Компьютерное моделирование упругого столкновения

Я пытаюсь рассчитать столкновение двух шаров одинаковой массы, предполагая, что столкновение абсолютно упругое, для моделирования компьютерной физики. Зная координаты обоих шаров и их начальные скорости в момент столкновения, я хочу рассчитать конечные скорости. Я некоторое время искал в Интернете и нашел несколько разных веб-сайтов, которые дают формулу для этого. Проблема в том, что при запуске симуляции казалось, что кинетическая энергия не сохраняется должным образом (некоторые столкновения прибавляют энергию, что вообще не имеет смысла, некоторые теряют ее). Итак, мой вопрос: что-то не так с этим методом? Вот псевдокод метода:

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;
}
Будет ли вычислительная наука лучшим местом для ответа на этот вопрос?

Ответы (1)

Я упростил ваш код, используя тождества триггеров и тот факт, что массы шаров равны. Я также отформатировал код так, чтобы он выглядел как результат умножения матрицы вращения, и добавил комментарии, указывающие на то, что, по моему мнению, является целью каждого раздела.

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;
}

Это выглядит правильно. Поскольку массы шаров равны, результатом должен быть обмен скоростями, параллельный направлению столкновения, поскольку при этом сохраняется импульс. Кинетическая энергия должна сохраняться, так как

К "=" 1 2 м в 1 2 + 1 2 м в 2 2 "=" ( 1 2 м в 1 Икс 2 + 1 2 м в 1 у 2 ) + ( 1 2 м в 2 Икс 2 + 1 2 м в 2 у 2 ) "=" ( 1 2 м в 2 Икс 2 + 1 2 м в 1 у 2 ) + ( 1 2 м в 1 Икс 2 + 1 2 м в 2 у 2 )
от переключения в 1 Икс и в 2 Икс .

Если это псевдокод, попробуйте упростить ваш реальный код так же, как это сделал я, и посмотрите, не обнаружатся ли какие-либо ошибки.

Изменить: еще два математических упрощения:

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)
Спасибо! Ваше упрощение помогло мне понять мою ошибку.
@chessprogrammer Я добавил еще одно изменение исключительно для скорости и точности. Для справки: fgiesen.wordpress.com/2010/10/21/finish-your-derivations-please