Simulación por computadora de colisión elástica

Estoy tratando de calcular la colisión de 2 bolas de igual masa, asumiendo que la colisión es perfectamente elástica, para una simulación de física por computadora. Dadas las coordenadas de ambas bolas y sus velocidades iniciales en el momento del choque, quiero calcular las velocidades finales. Busqué por un tiempo en línea y encontré algunos sitios web diferentes que dan una fórmula para hacer esto. El problema es que al ejecutar la simulación, parecía que la energía cinética no se conservaba correctamente (algunas colisiones donde se agregaba energía que no tenía ningún sentido, otras la perdían). Entonces mi pregunta es: ¿Hay algún problema con este método? Aquí está el pseudo código para el método:

function manage_bounce(ball, ball2) {
    dx = ball._x-ball2._x;
    dy = ball._y-ball2._y;
    collisionision_angle = Math.atan2(dy, dx);
    magnitude_1 = Math.sqrt(ball.xspeed*ball.xspeed+ball.yspeed*ball.yspeed);
    magnitude_2 = Math.sqrt(ball2.xspeed*ball2.xspeed+ball2.yspeed*ball2.yspeed);
    direction_1 = Math.atan2(ball.yspeed, ball.xspeed);
    direction_2 = Math.atan2(ball2.yspeed, ball2.xspeed);
    new_xspeed_1 = magnitude_1*Math.cos(direction_1-collisionision_angle);
    new_yspeed_1 = magnitude_1*Math.sin(direction_1-collisionision_angle);
    new_xspeed_2 = magnitude_2*Math.cos(direction_2-collisionision_angle);
    new_yspeed_2 = magnitude_2*Math.sin(direction_2-collisionision_angle);
    final_xspeed_1 = ((ball.mass-ball2.mass)*new_xspeed_1+(ball2.mass+ball2.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_xspeed_2 = ((ball.mass+ball.mass)*new_xspeed_1+(ball2.mass-ball.mass)*new_xspeed_2)/(ball.mass+ball2.mass);
    final_yspeed_1 = new_yspeed_1;
    final_yspeed_2 = new_yspeed_2;
    ball.xspeed = Math.cos(collisionision_angle)*final_xspeed_1+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball.yspeed = Math.sin(collisionision_angle)*final_xspeed_1+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_1;
    ball2.xspeed = Math.cos(collisionision_angle)*final_xspeed_2+Math.cos(collisionision_angle+Math.PI/2)*final_yspeed_2;
    ball2.yspeed = Math.sin(collisionision_angle)*final_xspeed_2+Math.sin(collisionision_angle+Math.PI/2)*final_yspeed_2;
}
¿ Sería la ciencia computacional un mejor hogar para esta pregunta?

Respuestas (1)

He simplificado tu código usando identidades trigonométricas y el hecho de que las masas de las bolas son iguales. También formateé el código para que parezca el resultado de una multiplicación de matriz de rotación y agregué comentarios que indican cuál creo que es el objetivo de cada sección.

function manage_bounce(ball, ball2) {
    // determine direction of balls with ball2 at origin
    dx = ball._x-ball2._x;
    dy = ball._y-ball2._y;
    collision_angle = Math.atan2(dy, dx);
    c = Math.cos(collision_angle);
    s = Math.sin(collision_angle);

    // Rotate coordinate system by -collision_angle so
    // x-axis aligns with line joining the balls' centers.
    // Recalculate velocity components in new coordinate system.
    new_xspeed_1 =  c*ball.xspeed + s*ball.yspeed;
    new_yspeed_1 = -s*ball.xspeed + c*ball.yspeed;
    new_xspeed_2 =  c*ball_2.xspeed + s*ball_2.yspeed;
    new_yspeed_2 = -s*ball_2.xspeed + c*ball_2.yspeed;

    // Exchange the velocities parallel to collision
    // direction (xspeed) and rotate (+collision_angle)
    // back to original coordinate system.
    ball.xspeed = c*new_xspeed_2 - s*new_yspeed_1;
    ball.yspeed = s*new_xspeed_2 + c*new_yspeed_1;
    ball2.xspeed = c*new_xspeed_1 - s*new_yspeed_2;
    ball2.yspeed = s*new_xspeed_1 + c*new_yspeed_2;
}

Esto parece correcto. Dado que las masas de las bolas son iguales, el resultado debería ser un intercambio de velocidades paralelo a la dirección de la colisión, ya que esto conserva la cantidad de movimiento. La energía cinética debe conservarse ya que

k = 1 2 metro v 1 2 + 1 2 metro v 2 2 = ( 1 2 metro v 1 X 2 + 1 2 metro v 1 y 2 ) + ( 1 2 metro v 2 X 2 + 1 2 metro v 2 y 2 ) = ( 1 2 metro v 2 X 2 + 1 2 metro v 1 y 2 ) + ( 1 2 metro v 1 X 2 + 1 2 metro v 2 y 2 )
de cambiar v 1 X y v 2 X .

Si se trata de un pseudocódigo, intente simplificar su código real de la misma manera que yo y vea si se revelan errores.

Editar: dos simplificaciones matemáticas más:

r = Math.sqrt(dx*dx + dy*dy) // or r = Math.hypot(dx, dy) if available
c = dx/r // cos(collision_angle)
s = dy/r // sin(collision_angle)
¡Gracias! Su simplificación me ayudó a detectar mi error.
@chessprogrammer Agregué un cambio más puramente por velocidad y precisión. Para referencia: fgiesen.wordpress.com/2010/10/21/finish-your-derivations-please