2010-09-11 10 views
9

Estoy tratando de hacer lo que es (esencialmente) un simple juego de billar, y me gustaría poder predecir dónde irá un tiro una vez que golpea a otra bola.Calcule x/y apunte que 2 bolas en movimiento colisionarán

La primera parte es, creo, para calcular si la bola de cue llegará a algo, y si lo hace, donde colisiona. Puedo calcular puntos de colisión para una línea y una pelota, pero no 2 bolas.

Por lo tanto, dadas las posiciones x/y las velocidades de 2 bolas, ¿cómo calculo el punto en el que colisionan?

(PS: Im consciente de que puede hacer esto mediante el cálculo de la distancia entre las dos bolas en cada paso a lo largo del camino, pero me esperaba algo un poco más elegante y óptimo.)

Ejemplo de configuración: tratar a calcuate el punto rojo

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

Respuesta

14

Algunas cosas para tomar nota de:

  • Cuando dos bolas, cada una de radio r chocan sus centros son 2r aparte.
  • Se puede suponer que su primera bola viaja en línea recta (bueno, primera aproximación, pero comience con esto), y puede encontrar el ángulo alpha entre esta ruta y la dirección desde la primera bola hasta la segunda.
  • Conoces el centro de la bola estacionaria, ¿no?

Ahora tiene algo de geometría para hacer.

hacer esta construcción:

  1. Marque el centro actual de la primera bola (en movimiento) como punto de A.
  2. Marque el centro de la bola estacionaria como punto B.
  3. Construir segmento de línea AB.
  4. Construya el rayo, R, desde A en la dirección del movimiento.
  5. Construya un círculo de radio 2r alrededor de B.
  6. Coloque un segmento de B perpendicular a R llame al punto de intersección C.
  7. Conoces la distancia AB y puedes encontrar el ángulo alpha entre AB y R, con la Ley de Sines encuentra la longitud de BC.
  8. De esa longitud determine si hay 0, 1 o 2 soluciones. Si hay 0 o 1, ya terminaste.
  9. Construye el punto D donde el círculo se encuentra con R más cerca de A, y usa la Ley de Sines nuevamente para encontrar la distancia AD.
  10. El punto de colisión es el punto medio de BD

y ahora se sabe todo.

Construir código eficiente de esto se deja como un ejercicio.


BTW-- Esta construcción no funcionará si las dos bolas se mueven, pero se puede transformar en un marco donde uno está parado, resolver de esa manera, entonces se transformará de nuevo. Sólo asegúrese de comprobar que la solución está en la zona permitida después de la transformación inversa ...

/físicos no pueden no hacer comentarios como este. Traté de resistir. I realmente hizo.

+0

Gah, soy un idiota. He tenido varias personas que me explican esto anteriormente, es solo ahora que lo entiendo. Por alguna razón, estaba convencido de que hacer 2r causaría colisiones inseguras. Apreciar la ayuda, debería ser capaz de resolver esto desde aquí. – user352151

+1

Después de haber hecho este tipo de cosas varias veces, alcanzará automáticamente un bloc o una pizarra. Ese es el punto en el que estás perdido para siempre en el mundo de los hombres ... – dmckee

+1

¿Es malo que esta respuesta me hizo sentir como si estuviera en la geometría de la escuela secundaria otra vez ... y me gustó? – userx

12

Dibujo de respuesta de @ dmckee

alt text

Editar

Sólo en respuesta a @ArtB respuesta de nigromante, las soluciones para el punto D en el gráfico anterior se podría escribir :

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

Dónde

Dx = Ax - Bx 
Dy = Ay - By 

Y

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

HTH!

1

Estaba viendo la solución de @dmckee y me tomó bastante trabajo trabajar en ella. Las siguientes son mis notas para aquellos que tal vez buscan una respuesta más práctica, se toma directamente de su publicación por lo que el crédito es para él/ella, pero cualquier error es mío. Por lo general, soy un operador de asignación tipo Pascal (es decir, :=) para distinguir entre mostrar mi trabajo y el código necesario real. Estoy usando el formato estándar Y = mX +b y una notación cuasi-oop. Utilizo BC tanto para el segmento como para la línea resultante. Dicho esto, esto debería ser "casi" copiar el código de Python (eliminar ";", reemplazar "sqrt" y "sqr" con las versiones adecuadas, etc.).

  1. A.x y A.y son los x & Y posiciones, A.R. es el radio de A, y A.v es la velocidad con A.v.x siendo la componente x de la misma y A.v.y siendo la componente y de la misma.
  2. B es lo mismo, pero sin la velocidad (o más exactamente, reste las velocidades de B de A, por lo que B es relativamente estacionario).
  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. no es necesario
  6. BC.m := -A.v.x/A.v.y; que es la ecuación estándar para la pendiente perpendicular, BC.b := B.y - BC.m * B.x; Ahora C es donde AB cumple BC así que sabemos que son iguales por lo que permite equiparar C.y por lo C.y == AB.m * C.x + AB.b == BC.m * C.x + BC.b; así que C.x := (AB.m - BC.M)/(BC.b - AB.b); entonces simplemente enchufe C.x para obtener C.y := AB.m * C.x + AB.b;
  7. puede ignorar la ley de los senos ya que tenemos AB y BC por lo que sólo puede usar el teorema de Pitágoras para obtener la longitud de BC, BC.l := sqrt(sqr(B.x-C.x) + sqr(B.y-C.y));
  8. Si BC.l > A.r + B.r, hay cero soluciones, y estos círculos no toque desde C es Ruta 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` es lo que queremos.
    1. Ahora, las matemáticas se ponen feas así que mostraré mi trabajo en caso de que haga algo mal.
    2. D es un punto en AC que es A.r + B.r (también conocido como 2r) de distancia de B así: sqrt(sqr(D.x - B.x) + sqr(D.y - B.y)) == 2r
    3. Por lo tanto sqr(D.x - B.x) + sqr(D.y - B.y) == 4*r*r. Ahora 2 variables (es decir, D.x y D.y) con una ecuación es un problema, pero también sabemos que D es en la línea AC así que D.y == AC.m*D.x + AC.b.
    4. Podemos sustituir D.y dando sqr(D.x - B.x) + sqr(AC.m*C.x + AC.b - B.y) == 4*r*r.
    5. Esto se expande en la hermosa: 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 (este es la parte en la que en su mayoría probablemente cometido un error si lo hice en absoluto).
    6. Estos términos podemos recoger (recuerda, en este momento sólo D.x es desconocida; el resto podemos tratar como si fueran constantes) para obtener 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. vuelto a escribir en el más ordenado (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 que puede ser readaptado a (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. Esto ahora encaja muy bien en la fórmula cuadrática (es decir x == (-bb +- sqrt(sqr(bb) - 4*aa*cc)/2*aa) (usando aa para evitar confusiones con las variables anteriores), con aa := 1 + sqr(AC.m);, bb := 2*(1 + AC.b - AC.m*B.y);, y cc := sqr(B.y) - sqr(B.x) + sqr(AC.b) - 2*AC.b*B.y - sqr(A.r+B.r);.
    9. Ahora podemos obtener dos soluciones, así que permite guardar las piezas usando -bb/2aa +- sqrt(sqr(bb)-4*aa*cc)/2*aa: first_term := -bb/(2*a); y second_term := sqrt(sqr(bb)-4*aa*cc)/2*aa;.
    10. Primera solución D1.x = first_term + second_term; con D1.y = AC.m * D1.x + AC.b, y una segunda solución D2.x = first_term + second_term; con D2.y = AC.m * D2.x + AC.b.
    11. Encuentra las distancias a A: D1.l := sqrt(sqr(D1.x-A.x) + sqr(D1.y-A.y)); y D2.l = sqrt(sqr(D2.x-A.x) + sqr(D2.y-A.y)); (en realidad es más eficiente omitir ambas raíces cuadradas, pero no importa).
    12. Cuanto más cerca esté uno que desee D := D1 if D1.l < D2. l else D2;.
    1. El punto medio de DB, vamos a llamarlo E, es la colisión (no sé cómo esto se generaliza si los radios no son iguales).
    2. Constucte la línea DB.m := (B.y-D.y)/(B.x-D.x); y DB.b = B.y - DB.m*B.x;.
    3. No necesitamos la longitud para determinar la longitud ya que debe ser BD.l == A.r + B.r, entonces sqrt(sqr(E.x-B.x) + sqr(E.y-B.y)) == B.r.
    4. De nuevo, podemos sustituir E porque sabemos que está en BD así que E.y == BD.m * E.x + BD.b, obteniendo sqrt(sqr(E.x-B.x) + sqr(BD.m * E.x + BD.b-B.y)) == B.r.
    5. Expansión en 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. que recoge en

    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);, fórmula cuadrática, y luego conseguir sus dos puntos y elegir el que más cerca de B.

Deseo Solo putaba por el karma o la insignia de nigromante, pero realmente necesitaba resolver esto y pensé que lo compartiría. Uf, creo que tengo que acostarme ahora.

+0

Ver mi edición por favor: D –

+0

Ahora que es embarazoso. Bueno, al menos lo intenté. Gracias por una alternativa más simple a mi desastre. – ArtB

+0

De nada. Recuerde comenzar sus comentarios con @Username, para que su fiesta sea notificada. ¡Acabo de volver aquí para verificar mi respuesta! –

Cuestiones relacionadas