Elastische Stösse zwischen Kugeln
Im folgenden wird die Berechnung von nicht-zentralen, elastischen Stössen bei Kugeln in 2D anhand eines Codegerüstes vorgestellt. Die Wandkollision ist ebenfalls implementiert. Die Kugeln können beliebig gross sein und beliebige Massen besitzen. Die Berechnung ist physikalisch korrekt; nicht berücksichtigt werden Reibung, Deformationsverluste und die Kugelrotation.
Source
Der Code dient zur Illustration und ist nicht sonderlich optimiert. Die Kernberechnung findet in
Timer1Timer statt. Details zur Berechnung siehe Kommentare und Erklärung unten.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127: 128: 129: 130: 131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141: 142: 143: 144: 145: 146: 147: 148: 149: 150: 151: 152: 153: 154: 155: 156: 157: 158: 159: 160: 161: 162: 163: 164: 165: 166: 167: 168: 169: 170: 171: 172: 173: 174: 175: 176: 177: 178: 179: 180: 181: 182: 183: 184: 185: 186: 187: 188: 189: 190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200: 201: 202: 203:
| unit Unit1;
interface
uses SysUtils, Forms, StdCtrls, ExtCtrls, Classes;
const dt = 20; SubIterations = 10; KugelCount = 10;
type TKugel = class;
TForm1 = class(TForm) Timer1: TTimer; procedure FormCreate(Sender: TObject); procedure Timer1Timer(Sender: TObject); private public Kugeln: array[0..KugelCount-1] of TKugel; end;
Borders = (boLeft, boTop, boBottom, boRight); BordersSet = set of Borders; TKugel = class(TShape) private FX, FY: Extended; FR: Extended; FM: Extended; FVx, FVy: Extended; procedure setR(const Value: Extended); public property X: Extended read FX write FX; property Y: Extended read FY write FY; property R: Extended read FR write setR; property M: Extended read FM write FM; property Vx: Extended read FVx write FVx; property Vy: Extended read FVy write FVy; procedure Move; procedure Apply; function CollidesWith(const Kugel2: TKugel): Boolean; function WallCollisions: BordersSet; constructor Create(AOwner: TComponent); override; end;
var Form1: TForm1;
implementation
{$R *.dfm}
function TKugel.CollidesWith(const Kugel2: TKugel): Boolean; begin Result := sqr(FX-Kugel2.FX)+sqr(FY-Kugel2.FY) < sqr(FR+Kugel2.FR); end;
constructor TKugel.Create(AOwner: TComponent); begin inherited; Shape := stCircle; end;
procedure TKugel.Move; begin X := X + (dt/1000)/SubIterations*FVx; Y := Y + (dt/1000)/SubIterations*FVy; end;
function TKugel.WallCollisions: BordersSet; const Border = 10; begin Result := []; if X-Border < R then Result := Result + [boLeft]; if Y-Border < R then Result := Result + [boTop]; if X+Border >= Parent.ClientWidth-R then Result := Result + [boRight]; if Y+Border >= Parent.ClientHeight-R then Result := Result + [boBottom]; end;
procedure TKugel.setR(const Value: Extended); begin FR := Value; Width := Round(FR*2); Height := Round(FR*2); end;
procedure TKugel.Apply; begin Left := round(X-FR); Top := round(Y-FR); end;
procedure TForm1.FormCreate(Sender: TObject); const Border = 10; var I: Integer; begin with Timer1 do begin Interval := dt; OnTimer := Timer1Timer; end;
for I := 0 to Length(Kugeln)-1 do begin Kugeln[I] := TKugel.Create(Form1); with Kugeln[I] do begin Parent := self; R := 20+Random(8); X := Random(self.ClientWidth-2*Round(R+Border))+Round(R+Border); Y := Random(self.ClientHeight-2*Round(R+Border))+Round(R+Border); Vx := Random(400); Vy := Random(400); M := 4/3*R*R*R*pi; Brush.Color := Random(256*256*256); end; end; end;
procedure TForm1.Timer1Timer(Sender: TObject); var DX, DY, M11, M21, M12, M22, L, Vp1, Vp2, Vs1, Vs2, MTot, Vp1_, Vp2_: Extended; I, J, K: Integer; B: BordersSet; begin for K := 0 to SubIterations-1 do begin for I := 0 to Length(Kugeln)-1 do Kugeln[I].Move;
for I := 0 to Length(Kugeln)-1 do for J := I+1 to Length(Kugeln)-1 do if Kugeln[I].CollidesWith(Kugeln[J]) then begin DX := Kugeln[j].X-Kugeln[i].X; DY := Kugeln[j].Y-Kugeln[i].Y; L := sqrt(sqr(DX)+sqr(DY)); M11 := DX/L; M12 := -DY/L; M21 := DY/L; M22 := DX/L;
Vp1 := Kugeln[i].Vx*M11+Kugeln[i].Vy*-M12; Vs1 := Kugeln[i].Vx*-M21+Kugeln[i].Vy*M22; Vp2 := Kugeln[j].Vx*M11+Kugeln[j].Vy*-M12; Vs2 := Kugeln[j].Vx*-M21+Kugeln[j].Vy*M22;
if Vp1-Vp2<0 then Continue; MTot := Kugeln[i].M+Kugeln[j].M; Vp1_ := (Kugeln[i].M-Kugeln[j].M)/MTot*Vp1+2*Kugeln[j].M/MTot*Vp2; Vp2_ := (Kugeln[j].M-Kugeln[i].M)/MTot*Vp2+2*Kugeln[i].M/MTot*Vp1;
Kugeln[i].Vx := Vp1_*M11+Vs1*M12; Kugeln[i].Vy := Vp1_*M21+Vs1*M22; Kugeln[j].Vx := Vp2_*M11+Vs2*M12; Kugeln[j].Vy := Vp2_*M21+Vs2*M22; end;
for I := 0 to Length(Kugeln)-1 do with Kugeln[I] do begin B := WallCollisions; if ((boLeft in B) and (Vx < 0)) or ((boRight in B) and (Vx > 0)) then Vx := -Vx; if ((boTop in B) and (Vy < 0)) or ((boBottom in B) and (Vy > 0)) then Vy := -Vy; end; end; for I := 0 to Length(Kugeln)-1 do Kugeln[I].Apply; end;
end. |
Vollständigkeitshalber noch die Form-Daten (in Form Alt+F12):
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| object Form1: TForm1 Left = 192 Top = 114 Width = 800 Height = 600 Caption = 'Form1' Color = clBtnFace OnCreate = FormCreate object Timer1: TTimer OnTimer = Timer1Timer end end |
Physikalischer Hintergrund
Die Berechnung des nicht-zentralen Stosses geht indirekt: Bei einer Kollision wird ein neues, gedrehtes Koordinatensystem definiert: Eine Koordinatenachse senkrecht und die andere parallel zum Stosspunkt (ausgehend vom Kugelmittelpunkt). Die senkrechten Geschwindigkeiten der Kugeln bleiben erhalten und die parallelen verhalten sich wie beim zentralen Stoss. Somit ist Energieerhaltung und Impulserhaltung garantiert. Die Umrechnung ins gedrehte Koordinatensystem und zurück geht einfach mittels Matrizenrechnung.
Kugel 1
_____
/ \
| --> |_____ * Stosspunkt
\_____* \
| <-- |
\_____/
Kugel 2
[meta]Billard Billiard Kugel Kugeln nicht zentraler elastischer dezentraler Stoss Stoß Kollision[/meta]
Moderiert von jasocul: Beitrag geprüft am 06.04.2006