2010-09-11 9 views
9

Ich versuche, was ist (im Wesentlichen) ein einfaches Pool-Spiel, und möchte in der Lage sein vorherzusagen, wo ein Schuss gehen wird, sobald es einen anderen Ball trifft.Berechne x/y-Punkt, dass 2 sich bewegende Bälle kollidieren

Der erste Teil ist, glaube ich, um zu berechnen, ob der Cueball irgendwas trifft, und wenn ja, wo er kollidiert. Ich kann Kollisionspunkte für eine Linie und einen Ball ausarbeiten, aber nicht 2 Bälle.

Also, wie berechnet man den Punkt, an dem sie kollidieren, angesichts der x/y-Positionen und Geschwindigkeiten von 2 Kugeln?

(PS: Im bewußt Ich kann dies tun, indem der Abstand zwischen den beiden Kugeln bei jedem Schritt auf dem Weg zu berechnen, aber ich hatte gehofft, für etwas mehr elegant und optimal.)

Beispiel für Setup: Der Versuch, der red dot

http://dl.dropbox.com/u/6202117/circle.PNG

Antwort

14

einige Dinge calcuate zur Kenntnis zu nehmen:

  • Wenn zwei Kugeln, die jeweils mit einem Radius r kollidieren ihre Zentren sind 2r auseinander.
  • Man kann annehmen, dass die erste Kugel in einer geraden Linie verläuft (naja, erste Annäherung, aber fange damit an), und du findest den Winkel alpha zwischen diesem Weg und der Richtung von der ersten Kugel zur zweiten.
  • Sie kennen das Zentrum der stationären Kugel, nein?

Jetzt haben Sie etwas Geometrie zu tun.

diese Konstruktion Do:

  1. Markieren Sie die aktuelle Mitte des ersten (bewegten) Ball als Punkt A.
  2. Markieren Sie die Mitte der stationären Kugel als Punkt B.
  3. Konstruieren Sie das Liniensegment AB.
  4. Konstruieren Sie den Strahl, R, von A in Bewegungsrichtung.
  5. Konstruieren Sie einen Kreis mit Radius 2r um B.
  6. Lassen Sie ein Segment von B senkrecht zu R den Schnittpunkt anrufen C.
  7. Sie kennen die Entfernung AB und Sie können den Winkel alpha zwischen AB und R finden, mit dem Gesetz von Sines finden Sie die Länge von BC.
  8. Von dieser Länge bestimmen, ob es 0, 1 oder 2 Lösungen gibt. Wenn es 0 oder 1 gibt, bist du fertig.
  9. Konstruieren Sie Punkt D, wo der Kreis R näher an A trifft, und verwenden Sie das Gesetz der Sines erneut, um den Abstand AD zu finden.
  10. Der Kollisionspunkt ist der Mittelpunkt der BD

und jetzt wissen Sie alles.

Das Konstruieren von effizientem Code wird als Übung überlassen.


BTW-- Diese Konstruktion wird nicht funktionieren, wenn beide Kugeln bewegen, aber Sie können in einen Rahmen verwandeln, wo man stationär ist, es auf diese Weise lösen, dann zurück verwandeln. Nur sicher sein, um zu überprüfen, dass die Lösung im erlaubten Bereich ist nach die Rücktransformation ...

/Physiker kann nicht nicht macht Kommentare wie diese. Ich habe versucht zu widerstehen. I wirklich tat.

+0

Gah, ich bin ein Idiot. Ich habe mir schon vorher von mehreren Leuten das erklären lassen, erst jetzt, wo ich es verstanden habe. Aus irgendeinem Grund war ich davon überzeugt, dass 2r zu einer Kollision führen würde. Schätzen Sie die Hilfe, ich sollte in der Lage sein, dies von hier aus zu arbeiten. – user352151

+1

Nachdem Sie ein paar Mal so etwas gemacht haben, greifen Sie automatisch nach einem Pad oder Whiteboard. Das ist der Punkt, an dem du für immer in der Welt der Männer verloren bist ... – dmckee

+1

Ist es schlimm, dass diese Antwort mir das Gefühl gab, dass ich wieder in der Highschool-Geometrie war ... und es irgendwie mochte? – userx

12

Zeichnung der Antwort des @ Dmckee

alt text

bearbeiten

Gerade in Reaktion Nekromant Antwort auf @ArtB könnten die Lösungen für Punkt D in der obigen Grafik geschrieben werden :

1/2 {(Ax+Bx+2 d Dx Cos[alpha]- Dx Cos[2 alpha]+ 2 Dy (Cos[alpha]-d) Sin[alpha]), 
    (Ay+By+2 d Dy Cos[alpha]- Dy Cos[2 alpha]- 2 Dx (Cos[alpha]-d) Sin[alpha]) 
    } 

Wo

Dx = Ax - Bx 
Dy = Ay - By 

Und

d = Sqrt[4 r^2 - (Dx^2 + Dy^2) Sin[alpha]^2]/Sqrt[Dx^2 + Dy^2] 

HTH!

1

Ich habe @ dmckee's Lösung angeschaut und es hat ziemlich viel Arbeit gekostet. Das Folgende ist meine Notizen für diejenigen, die vielleicht eine praktischere Antwort suchen, es ist direkt von seinem Posten genommen, so dass der Kredit zu ihm/ihr geht, aber alle Fehler gehören mir. Normalerweise benutze ich einen Pascal-ähnlichen Assignment-Operator (zB :=), um zwischen der Anzeige meiner Arbeit und dem tatsächlich notwendigen Code zu unterscheiden. Ich verwende das Standardformat Y = mX +b und eine Quasi-Oop-Notation. Ich verwende BC sowohl für das Segment als auch für die resultierende Zeile. Das heißt, das sollte "fast" kopierfähig sein und Python-Code (entfernen Sie ";", ersetzen "sqrt" und "sqr" mit geeigneten Versionen, etc.).

  1. A.x und A.y die x & y-Positionen sind, ist A.R A Radius und A.v ist die Geschwindigkeit, mit A.v.x die x-Komponente davon zu sein und A.v.y die Y-Komponente davon zu sein.
  2. B ist das gleiche, aber ohne die Geschwindigkeit (oder genauer, subtrahieren Sie die Geschwindigkeiten von B von A, so dass B relativ stationär ist).
  3. AB.m := (b.y - a.y)/(b.x - a.x);AB.b := A.y - AB.m * A.x;
  4. R.m := A.v.y/A.v.x;R.b := A.y - R.m * A.x;
  5. nicht notwendig
  6. BC.m := -A.v.x/A.v.y;, die die Standard-Gleichung für die senkrechte Steigung ist, BC.b := B.y - BC.m * B.x; Jetzt C ist, wo AB trifft BC so wissen wir, dass sie gleich sind, so lässt C.y so gleichsetzen C.y == AB.m * C.x + AB.b == BC.m * C.x + BC.b; also C.x := (AB.m - BC.M)/(BC.b - AB.b); dann einfach C.x einstecken, um C.y := AB.m * C.x + AB.b;
  7. zu erhalten
  8. Sie können die Sinus-Gesetz ignorieren, da wir AB und BC haben, so können wir nur den Satz des Pythagoras verwenden, um die Länge von BC, BC.l := sqrt(sqr(B.x-C.x) + sqr(B.y-C.y));
  9. Wenn BC.l > A.r + B.r, gibt es Null-Lösungen, und diese Kreise berühren Sie nicht zu bekommen, da C ist A Weg s perigee with respect to B . If BC.l == Ar + Br , there is only one solution, and C == D . Otherwise, if BC.l < Ar + Br then there are two solutions. You can think of this as such, if there are zero solutions the bullet missed, if there is one the bullet grazed, and if there are two then there is both an entry and exit wound. The one closer to A ist die, die wir wollen.
    1. Jetzt wird die Mathematik hässlich, also werde ich meine Arbeit zeigen, nur für den Fall, dass ich etwas falsch mache.
    2. D ist ein Punkt auf die ACA.r + B.r (aka 2r) weg von B ist so: sqrt(sqr(D.x - B.x) + sqr(D.y - B.y)) == 2r
    3. Daher sqr(D.x - B.x) + sqr(D.y - B.y) == 4*r*r. Jetzt 2 Variablen (dh D.x und D.y) mit einer Gleichung ist ein Problem, aber wir wissen auch, dass ist auf der Linie AC so D.y == AC.m*D.x + AC.b.
    4. Wir ersetzen D.y geben sqr(D.x - B.x) + sqr(AC.m*C.x + AC.b - B.y) == 4*r*r. Diese
    5. expandiert in die schöne: sqr(D.x) + 2*D.x - sqr(B.x) + sqr(AC.m*D.x) + 2*AC.b*D.x - 2*AC.m*D.x*B.y + sqr(AC.b) - 2*AC.b*B.y + sqr(B.y) == 4*r*r (diese ist der Teil, wo ich meistens wahrscheinlich einen Fehler gemacht wenn ich überhaupt tat).
    6. Diese Begriffe wir (Sie erinnern sich, an dieser Stelle nur D.x ist unbekannt, der Rest wir behandeln können, als ob sie Konstanten waren) sammeln können sqr(D.x) + 2*D.x - sqr(B.x) + sqr(AC.m*D.x) + 2*AC.b*D.x - 2*AC.m*D.x*B.y + sqr(AC.b) - 2*AC.b*B.y + sqr(B.y) == 4*r*r
    7. in die sauberere (sqr(D.x) + sqr(AC.m*D.x)) + (2*D.x + 2*AC.b*D.x - 2*AC.m*B.y*D.x) + (- sqr(B.x) + sqr(AC.b) - 2*AC.b*B.y + sqr(B.y)) == 4*r*r Rewritten zu erhalten, die zu Refactoring werden kann (1 + sqr(AC.m)) * sqr(D.x) + 2*(1 + AC.b - AC.m*B.y) * D.x + (sqr(B.y) - sqr(B.x) + sqr(AC.b) - 2*AC.b*B.y - 4*r*r) == 0
    8. das passt jetzt gut in die quadratische Formel (dh x == (-bb +- sqrt(sqr(bb) - 4*aa*cc)/2*aa) (aa Verwirrung mit früheren Variablen zu vermeiden, verwenden), mit aa := 1 + sqr(AC.m);, bb := 2*(1 + AC.b - AC.m*B.y); und cc := sqr(B.y) - sqr(B.x) + sqr(AC.b) - 2*AC.b*B.y - sqr(A.r+B.r);.
    9. Jetzt können wir zwei Lösung erhalten, also können wir die Teile mit -bb/2aa +- sqrt(sqr(bb)-4*aa*cc)/2*aa speichern: first_term := -bb/(2*a); und second_term := sqrt(sqr(bb)-4*aa*cc)/2*aa;.
    10. Erste Lösung D1.x = first_term + second_term; mit D1.y = AC.m * D1.x + AC.b und eine zweite Lösung D2.x = first_term + second_term; mit D2.y = AC.m * D2.x + AC.b.
    11. Finden Sie die Abstände zu A: D1.l := sqrt(sqr(D1.x-A.x) + sqr(D1.y-A.y)); und D2.l = sqrt(sqr(D2.x-A.x) + sqr(D2.y-A.y)); (eigentlich ist es effizienter, beide Quadratwurzeln zu überspringen, aber es macht keinen Unterschied).
    12. Je näher man ist man wollen D := D1 if D1.l < D2. l else D2;.
    1. Der Mittelpunkt DB, lässt es E nennen, ist die Kollision (ich weiß nicht, wie dies verallgemeinert, wenn die Radien nicht gleich sind).
    2. So constuct die Linie DB.m := (B.y-D.y)/(B.x-D.x); und DB.b = B.y - DB.m*B.x;.
    3. Wir brauchen nicht die Länge, um die Länge zu bestimmen, da es BD.l == A.r + B.r sein sollte, also sqrt(sqr(E.x-B.x) + sqr(E.y-B.y)) == B.r.
    4. Wieder können wir E ersetzen, weil wir wissen, dass es auf BD so E.y == BD.m * E.x + BD.b ist, sqrt(sqr(E.x-B.x) + sqr(BD.m * E.x + BD.b-B.y)) == B.r bekommen.
    5. Expansion in sqr(E.x) - 2*E.x*B.x + sqr(B.x) + sqr(BD.m)*sqr(E.x) + 2*BD.m*E.x*BD.b - 2*BD.m*B.y + sqr(B.y) - 2*BD.b*B.y + sqr(B.y) == sqr(B.r)
    6. die in

    sqr(E.x) + sqr(BD.m)*sqr(E.x) + 2*BD.m*E.x*BD.b - 2*E.x*B.x + sqr(B.x) - 2*BD.m*B.y + sqr(B.y) - 2*BD.b*B.y + sqr(B.y) == sqr(B.r) (1 + sqr(BD.m)) * sqr(E.x) + 2*(BD.m*BD.b - B.x) * E.x + sqr(B.x) + sqr(B.y) - 2*BD.m*B.y + sqr(B.y) - 2*BD.b*B.y + sqr(B.y) - sqr(B.r) == 0 aa := (1 + sqr(BD.m)); bb := 2*(BD.m*BD.b - B.x); cc := sqr(B.y) - 2*BD.m*B.y + sqr(B.y) - 2*BD.b*B.y + sqr(B.y) - sqr(B.r);, quadratische Formel sammelt, und dann zwei Punkte bekommen und die näher an B.

Ich wünsche wählen Ich hurtete nur nach Karma oder dem Nekromanten-Abzeichen, aber ich musste es wirklich herausfinden und dachte mir, ich würde es teilen. Ugh, ich denke, ich muss mich jetzt hinlegen.

+0

Siehe meine Bearbeitung bitte: D –

+0

Das ist jetzt nur peinlich. Nun, zumindest habe ich es versucht. Danke für eine einfachere Alternative zu meinem Durcheinander. – ArtB

+0

Gern geschehen. Denken Sie daran, Ihre Kommentare mit @Username zu beginnen, damit Ihre Party benachrichtigt wird. Ich kam gerade hierher zurück, um meine Antwort zu überprüfen! –

Verwandte Themen