2010-09-11 6 views
9

Próbuję zrobić to, co jest (w zasadzie) prostą grą w bilard i chciałbym móc przewidzieć, gdzie trafi strzał, gdy uderzy w inną piłkę.Obliczyć punkt x/y, że 2 poruszające się piłki zderzają się z

Pierwsza część to, jak sądzę, obliczenie, czy cueball trafi cokolwiek, a jeśli tak, to gdzie się zderzy. Potrafię opracować punkty kolizji dla linii i piłki, ale nie dla 2 piłek.

Tak więc biorąc pod uwagę pozycje x/yi prędkości 2 kul, jak obliczyć punkt, w którym się zderzają?

(PS: Im świadomość, mogę to zrobić poprzez obliczenie odległości między dwoma kulkami na każdym kroku po drodze, ale miałem nadzieję na coś bardziej eleganckiego i optymalne.)

Przykład konfiguracji: stara do calcuate czerwoną kropką

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

Odpowiedz

14

Niektóre rzeczy biorą pod uwagę:

  • Gdy dwie kule, każda o promieniu r zderzają się ich centra są od siebie 2r.
  • Można założyć, że pierwsza piłka porusza się po linii prostej (dobrze, pierwsze przybliżenie, ale zacznij od tego), i możesz znaleźć kąt, alpha między tą ścieżką i kierunkiem od pierwszej piłki do drugiej.
  • Znasz centrum stacjonarnej piłki, nie?

Teraz masz trochę geometrii do zrobienia.

Wykonaj budowy:

  1. Mark obecny środek pierwszej piłki (w ruchu) jako punkt A.
  2. Oznaczyć środek kuli nieruchomej jako punkt B.
  3. Skonstruuj segment linii AB. Wygeneruj promień, R, od A w kierunku ruchu.
  4. Skonstruuj okrąg o promieniu 2r wokół B.
  5. Upuść segment z B prostopadle do R, wywołaj punkt przecięcia C.
  6. Znasz odległość AB i możesz znaleźć kąt alpha między AB a R, z ustawą Sines znaleźć długość BC.
  7. Od tej długości określ, czy istnieją rozwiązania 0, 1 lub 2. Jeśli masz 0 lub 1, to jesteś gotowy.
  8. Punkt konstrukcyjny D, gdzie koło spotyka się z R bliżej A, i ponownie użyj Prawa Sines, aby znaleźć odległość AD.
  9. Punktem uderzenia jest środkiem boku BD

i teraz wiesz wszystko.

Konstruowanie wydajnego kodu z tego jest pozostawione jako ćwiczenie.


BTW-- Konstrukcja ta nie będzie działać, jeśli obie kule są w ruchu, ale można przekształcić w klatce, w której jeden jest nieruchomy, rozwiązać to w ten sposób, a następnie przekształcić z powrotem. Tylko pamiętaj, aby sprawdzić, które rozwiązanie jest w dozwolonym obszarze po odwrotna transformacja ...

/Fizycy nie nie mogą dodawać komentarze jak ten. Próbowałem się oprzeć. I naprawde zrobiłem.

+0

Gah, jestem idiotą. Kilka osób wcześniej mi to wyjaśniło, tylko teraz, gdy je dostaję. Z jakiegoś powodu byłem przekonany, że zrobienie 2r spowoduje, że kolizje będą nieporęczne. Doceniam pomoc, powinienem móc to załatwić stąd. – user352151

+1

Po wykonaniu tego rodzaju czynności kilka razy automatycznie sięgniesz po podkładkę lub tablicę. To jest punkt, w którym jesteś wiecznie zagubiony w świecie ludzi ... – dmckee

+1

Czy to źle, że ta odpowiedź sprawiła, że ​​poczułem się, jakbym znowu był w licealnej geometrii ... i trochę jej się podobało? – userx

12

Rysunek odpowiedź @ dmckee za

alt text

Edit

Właśnie w odpowiedzi na @ArtB odpowiedź Nekromanty, rozwiązania dla punktu D w powyższym wykresie można zapisać :

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]) 
    } 

Gdzie

Dx = Ax - Bx 
Dy = Ay - By 

I

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

HTH!

1

Przyglądałem się rozwiązaniu @ dmckee i zajęło mi to dużo pracy. Oto moje notatki dla tych, którzy szukają bardziej praktycznej odpowiedzi, jest ona pobierana bezpośrednio z jego postu, więc kredyt trafia do niego, ale wszelkie błędy są moje. Zwykle operatorem przypisania podobnym do Pascala (tj. :=) jest rozróżnianie pomiędzy wyświetlaniem mojej pracy a faktycznym potrzebnym kodem. Używam standardowego formatu Y = mX +b i notacji quasi-oop. Używam BC zarówno dla segmentu, jak i dla wynikowej linii. To powiedziawszy, powinno to "prawie" być "w stanie" skopiować kod Pythona (usunąć ";", zastąp "sqrt" i "sqr" odpowiednimi wersjami, itp.).

  1. A.x i A.y są x & pozycji y, A.R jest promień A, a A.v jest prędkość, z A.v.x czym x składnikiem się A.v.y jako składnik y tym.
  2. B jest takie samo, ale bez prędkości (lub dokładniej, odejmij prędkości B od A, więc B jest względnie stacjonarne).
  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. niekonieczne
  6. BC.m := -A.v.x/A.v.y; który jest standardem równanie na stoku prostopadłego, BC.b := B.y - BC.m * B.x; Teraz C gdzie AB spełnia BC więc wiemy, że są one równe więc pozwala zrównać C.y tak C.y == AB.m * C.x + AB.b == BC.m * C.x + BC.b;, więc C.x := (AB.m - BC.M)/(BC.b - AB.b); następnie wystarczy podłączyć C.x, aby uzyskać C.y := AB.m * C.x + AB.b;
  7. Można zignorować prawo sine ponieważ mamy AB i BC więc możemy po prostu użyć twierdzenie Pitagorasa, aby uzyskać długość BC, BC.l := sqrt(sqr(B.x-C.x) + sqr(B.y-C.y));
  8. If BC.l > A.r + B.r, są zerowe rozwiązania, a te koła nie dotykały od C jest Ścieżka As 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 'jest tym, którego chcemy.
    1. Teraz matematyka staje się brzydka, więc pokażę swoją pracę, na wypadek, gdy zrobię coś nie tak.
    2. D jest punktem na AC czyli A.r + B.r (aka 2r) od B tak: sqrt(sqr(D.x - B.x) + sqr(D.y - B.y)) == 2r
    3. Dlatego sqr(D.x - B.x) + sqr(D.y - B.y) == 4*r*r. Teraz 2 zmienne (tj. D.x i D.y) z jednym równaniem to kłopoty, ale wiemy też, że D to na linii AC, czyli D.y == AC.m*D.x + AC.b.
    4. Możemy zastąpić D.y, podając sqr(D.x - B.x) + sqr(AC.m*C.x + AC.b - B.y) == 4*r*r.
    5. ta rozwija się piękny: 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 (ten jest część, gdzie ja przeważnie prawdopodobnie pomylił jeśli ja w ogóle).
    6. te warunki możemy odebrać (Pamiętaj, że w tym momencie tylko D.x jest nieznany; reszta możemy traktować tak, jakby były stałymi), aby uzyskać 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. Przepisany do neater (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 które mogą być refactored do (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. To teraz pasuje do kwadratowego wzoru (tj x == (-bb +- sqrt(sqr(bb) - 4*aa*cc)/2*aa) (używając aa aby uniknąć nieporozumień z wcześniejszymi zmiennych), z aa := 1 + sqr(AC.m);, bb := 2*(1 + AC.b - AC.m*B.y); i cc := sqr(B.y) - sqr(B.x) + sqr(AC.b) - 2*AC.b*B.y - sqr(A.r+B.r);.
    9. Teraz możemy uzyskać dwa rozwiązania, więc zapiszmy części za pomocą -bb/2aa +- sqrt(sqr(bb)-4*aa*cc)/2*aa: first_term := -bb/(2*a); i second_term := sqrt(sqr(bb)-4*aa*cc)/2*aa;.
    10. Pierwsze rozwiązanie D1.x = first_term + second_term; z D1.y = AC.m * D1.x + AC.b i drugie rozwiązanie D2.x = first_term + second_term; z D2.y = AC.m * D2.x + AC.b.
    11. Znajdź odległości do A: D1.l := sqrt(sqr(D1.x-A.x) + sqr(D1.y-A.y)); i D2.l = sqrt(sqr(D2.x-A.x) + sqr(D2.y-A.y)); (w rzeczywistości skuteczniejsze jest pomijanie obu pierwiastków kwadratowych, ale nie ma to znaczenia).
    12. Im bliżej jest jeden, D := D1 if D1.l < D2. l else D2;.
    1. Środkowy punkt DB, pozwala nazwać E, jest kolizja (nie wiem jak to generalizowaniu jeśli promienie nie są równe).
    2. Więc utwórz linię DB.m := (B.y-D.y)/(B.x-D.x); i DB.b = B.y - DB.m*B.x;.
    3. Nie potrzebujemy długości, aby określić długość, ponieważ powinna być BD.l == A.r + B.r, czyli sqrt(sqr(E.x-B.x) + sqr(E.y-B.y)) == B.r.
    4. Znów możemy zastąpić E, ponieważ wiemy, że jest na BD, więc E.y == BD.m * E.x + BD.b, otrzymując sqrt(sqr(E.x-B.x) + sqr(BD.m * E.x + BD.b-B.y)) == B.r.
    5. Rozszerzenie do 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. który zbiera się

    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);, kwadratowa formuły, a następnie uzyskać dwa punkty i wybrać jeden bliżej B.

życzę Po prostu kręciłem się o karmę lub odznakę nekromanty, ale naprawdę musiałem to wyjaśnić i uznałem, że się podzielę. Ugh, myślę, że muszę się teraz położyć.

+0

Zobacz moją edycję proszę: D –

+0

To jest po prostu krępujące. Cóż, przynajmniej próbowałem. Dziękuję za prostszą alternatywę dla mojego bałaganu. – ArtB

+0

Nie ma za co. Pamiętaj, aby zacząć komentarze z @Username, aby Twoja strona otrzymała powiadomienie. Właśnie wróciłem tutaj sprawdzając moją odpowiedź! –

Powiązane problemy