singlepost

Пара вопросов по столкновению тел << На главную или назад  

Здравствуйте!
Пишу проект на тему "Моделирование передачи импульса", и у меня возникли затруднения.
Итак, пользователь вводит скорости, массы, начальные и конечные координаты двух шаров. Затем заполняются структуры ball1 и ball2, объявленные как
struct ball
{
float m; //масса
float v; //скорость
float x; //——-
float y; //текущие координаты
float z; //——-
float angle_xy; //угол на плоскости xOy, по которому движется шар
float angle_xz; // -//- xOz -//-
} ball1,ball2;

и, с помощью OpenGL, выводятся эти шары.
Вопрос: как при нецентральном упругом столкновении шаров изменить углы angle_xy и angle_xz так, как это было бы на самом деле (система замкнутая)?

Заранее спасибо!
PS: пишу, используя WinAPI и OpenGL (glut), MS Visual Studio 2008

85 ответов в теме “Пара вопросов по столкновению тел”

  1. 26
    Миха Коробов ответил:

    Все, работает! Огромное спасибо!!!

  2. 25
    Павел Потапов ответил:

    Это ж тоже самое, только записано по-другому.

    Должно быть что-то вроде:

    Vc1 = E * (V1 * E);
    Vo1 = V1 – Vc1;
    Vc2 = E * (V2 * E);
    Vo2 = V2 – Vc2;

    Vc1n = (Vс1*(ball1.m-ball2.m)+Vс2*ball2.m*2)*(1./(ball1.m+ball2.m));
    Vc2n = …; // Аналогично предыдущей строчке/

    ball1.V = Vc1n + Vo1;
    ball2.V = Vc2n + Vo2;

  3. 24
    Миха Коробов ответил:

    А так правильно?

    vector E,Vc,Vo,V1(ball1.v),V2(ball2.v);

    //Для 1-ого шара
    E.i=ball2.x-ball1.x;
    E.j=ball2.y-ball1.y;
    E.k=ball2.z-ball1.z;
    E=E*(1./E.length());
    Vc=E*(V1*E);
    Vo=V1-Vc;
    Vc.i=(V1.i*(ball1.m-ball2.m)+V2.i*ball2.m*2)/(ball1.m+ball2.m);
    Vc.j=(V1.j*(ball1.m-ball2.m)+V2.j*ball2.m*2)/(ball1.m+ball2.m);
    Vc.k=(V1.k*(ball1.m-ball2.m)+V2.k*ball2.m*2)/(ball1.m+ball2.m);
    ball1.v=Vo+Vc;

    //Для 2-ого шара
    E.i=ball1.x-ball2.x;
    E.j=ball1.y-ball2.y;
    E.k=ball1.z-ball2.z;
    E=E*(1./E.length());
    Vc=E*(V2*E);
    Vo=V2-Vc;
    Vc.i=(V2.i*(ball2.m-ball1.m)+V1.i*ball1.m*2)/(ball1.m+ball2.m);
    Vc.j=(V2.j*(ball2.m-ball1.m)+V1.j*ball1.m*2)/(ball1.m+ball2.m);
    Vc.k=(V2.k*(ball2.m-ball1.m)+V1.k*ball1.m*2)/(ball1.m+ball2.m);
    ball2.v=Vo+Vc;

  4. 23
    Павел Потапов ответил:

    Да, нормированный вектор – единичный.

    E считаешь неправильно.

    E = ball1.C – ball2.C; // Где ball1.C и ball2.C – это центры шаров. После этого E еще надо нормировать, т.е. поделить на его длину.

    Vc считаешь неправильно. В выражении справа должны использоваться компоненты Vc обоих шаров, а не исходные скорости. За этим мы и раскладываем скорость на 2 компоненты.

    По поводу вектора:

    Все операции, кроме присваивания, должны возвращать vector (а не ссылку), и внутри не должно быть никаких new. Иначе у тебя течет память. И лучше операторы переписать так:

    vector operator+(const vector& v)const;

    Оператор присваивания должен выглядеть так:

    const vector& operator=(const vector& x);

    Также рекомендую определить конструкторы: по умолчанию, копирования и с 3мя параметрами (если используется создание вектора с известными координатам). Также можно добавить деструктор.

  5. 22
    Миха Коробов ответил:

    Павел Потапов, а нормированная разность векторов – это единичный вектор?
    Вот, кое-что написал для первого шара:
    vector E,Vc,Vo,V1=ball1.v,V2=ball2.v;
    E=V1-V2;//<—Вот тут сомневаюсь
    Vc=E*(V1*E);
    Vo=V1-Vc;
    Vc=(V1*(ball1.m-ball2.m)+V2*ball2.m*2)*(1./(ball1.m+ball2.m));
    ball1.v=Vo+Vc;

    А вот вектор: //codepad.org/DnBKzK5A – вроде бы правильный.
    А насчет скорости – то да, задержку таймера только поменять нужно :)

  6. 21
    Павел Потапов ответил:

    Это как? Если скорость постоянна, то шар двигается равномерно прямолинейно.

  7. 20
    Миха Коробов ответил:

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

  8. 19
    Павел Потапов ответил:

    Приращение координаты по времени в зависимости от скорости? Нет, оно будет

    ball.x += v.x * t;
    ball.y += v.y * t;
    ball.z += v.z * t;

  9. 18
    Миха Коробов ответил:

    Хм… А ведь действительно проще! Спасибо! То есть приращение координаты, например x, будет:
    ball1.x+=cos(arcctg(ball1.i/ball1.j));
    // i, j – координаты вектора
    ???

  10. 17
    Павел Потапов ответил:

    Да, и для векторов лучше завести отдельную структуру, а также пару-тройку методов, типа сложения/вычитания.

  11. 16
    Павел Потапов ответил:

    С углами мне как-то тяжело разобраться. Имхо, с векторами будет проще.

    Вроде алгоритм такой:

    1) Вычисляем единичный вектор, направленный по линии центров. Это просто нормированная разность центров (в векторном виде). Обозначим его E.

    2) Вычисляем проекцию скорости на этот вектор. Это некий вектор, параллельный E. Его длина равна скалярному произведению скорости на E. Итого: Vc = (V*E) E.
    Скалярное произведение: (V*E) = Vx * Ex + Vy * Ey (в случае с 3мя координатами, еще и Vz * Ez).

    3) Вторая часть скорости вычисляется тривиально: Vo = V – Vc.

    4) Вычисляем Vc(new) по закону сохранения импульса.

    5) Складываем Vo и Vc(new). Получаем новые скорости.

    И никаких проблем с углами. При желании можно перевести из координат в углы и модуль скорости.

    ЗЫ На счет векторного произведения я был неправ. Оно лежит в нужной плоскости, но не дает Vo.

  12. 15
    Миха Коробов ответил:

    Я вот так подумал, нужно сделать как-то так:
    if (<условие>) angle_х12+=PI;

    Только вот не могу <условие> понять какое? и как правильнее найти проекции на оси?

  13. 14
    Миха Коробов ответил:

    Павел Потапов, знаю, что мало. Я пока написал все это для плоскости, потом добавлю третье измерение. А в моем случае что нужно добавить в этот код? Просто переписывать весь проект будет трудновато :)

    Сергей Переславцев, спасибо, обязательно посмотрю!

  14. 13
    Сергей Переславцев ответил:

    раньше занимался физикой в 3Д играх, рекомендую посмотреть классический труд на эту тему :)
    //www.cs.cmu.edu/~baraff/pbm/rigid1.pdf
    //www.cs.cmu.edu/~baraff/pbm/rigid2.pdf
    там даны формулы расчетов крутящего момента по импульсу и тензору инерции (для шара тривиально).
    погугли есть кучи готовых демок на эту тему.

  15. 12
    Павел Потапов ответил:

    Ось а – прямая, соединяющая центры шаров.
    Ось b – прямая, ортогональная оси а.

    Мало. Если говорить о трехмерном пространстве, то должна еще быть третья ось, ортогональная первым двум.

    На мой взгляд в данном случае проще представлять скорость вектором, а не модулем и углами. Тогда проекция на ось, соединяющую центры шаров, будет вычисляться, как векторное произведение скорости на нормированный вектор, лежащий на этой прямой. (Компонента в векторном виде – это произведение проекции на нормированный вектор.) А проекция на ортогональную плоскость – как их векторное произведение.

    Новое значение будет просто суммой двух компонент (векторов).

  16. 11
    Миха Коробов ответил:

    И еще раз, здавствуйте!
    Вот написал несколько строчек, правда нужно что-то добавить, а чего – не знаю, так как работает не вполне правильно. Вот код:
    if (sqrt( (ball1.x-ball2.x)*(ball1.x-ball2.x) + (ball1.y-ball2.y)*(ball1.y-ball2.y) + (ball1.z-ball2.z)*(ball1.z-ball2.z) )<=51.) //Столкнулись
    {
    float angle_x12=(ball1.y<ball2.y)?
    arcctg((ball2.x-ball1.x)/(ball2.y-ball1.y)):
    arcctg((ball1.x-ball2.x)/(ball1.y-ball2.y)), /*угол между осью x и линией, соединяющей центры шаров. */
    v1a=ball1.v*cos(angle_x12-ball1.angle_xy), //проекция на ось a (1)
    v1b=ball1.v*sin(angle_x12-ball1.angle_xy), //проекция на ось b (1)
    v2a=ball2.v*cos(angle_x12-ball2.angle_xy), //проекция на ось a (2)
    v2b=ball2.v*sin(angle_x12-ball2.angle_xy); //проекция на ось b (2)

    //Дальше – все, вроде бы, правильно
    float _v1=v1a, _v2=v2a;

    v1a=((ball1.m-ball2.m)*_v1+2*ball2.m*_v2)/(ball1.m+ball2.m);
    v2a=((ball2.m-ball1.m)*_v2+2*ball1.m*_v1)/(ball1.m+ball2.m);

    ball1.angle_xy=arcctg(v1a/v1b);
    ball2.angle_xy=arcctg(v2a/v2b);

    ball1.v=sqrt(v1a*v1a+v1b*v1b);
    ball2.v=sqrt(v2a*v2a+v2b*v2b);

    KillTimer(hwnd,1);
    KillTimer(hwnd,2);
    SetTimer(hwnd,1,1000/ball1.v,0);
    SetTimer(hwnd,2,1000/ball2.v,0);
    }

    Ось а – прямая, соединяющая центры шаров.
    Ось b – прямая, ортогональная оси а.

    Посмотрите, пожалуйста, и посоветуйте, что нужно добавить.

  17. 10
    Павел Потапов ответил:

    Не совсем так. Скорость каждого шара состоит из 2х компонент. Модуль компоненты в плоскости ортгональной линии столкновения не меняется. Изменяется только компонента скорости в направлении линии столкновения.

    Т.е. если говорить о векторах, то V(new) = Vo + Vc(new).

    А вот уже Vc(new) расчитывается по закону сохранения импульса.

  18. 9
    Алексей Перепечко ответил:

    нет. не так.

    у вас речь идет о телах с разной массой. вы не можете суммировать вектора скоростей.

    //ru.wikibooks.org/wiki/%D0%97%D0%B0%D0%B4%D0%B...

    эадача 5, для 2-мерного пространства, вам достаточно добавить третье измерение.

    в двух словах, вам необходимо считать обмен импульсами, для получения конечных скоростей.

  19. 8
    Миха Коробов ответил:

    В смысле – модуль скорости? Если да, то
    ball1.v=((ball1.m-ball2.m)*v1+2*ball2.m*v2)/(ball1.m+ball2.m);
    ball2.v=((ball2.m-ball1.m)*v2+2*ball1.m*v1)/(ball1.m+ball2.m);

  20. 7
    Павел Потапов ответил:

    Ну… вроде да.

    Единственное, что я мог наврать на счет закона сохранения импульса :) Как вычислить правильное значение новой компоненты скорости надо посчитать.

  21. 6
    Миха Коробов ответил:

    Ага, всем спасибо!
    Павел Scavenger Потапов, то естьвектор Vo+Vc и будет искомый вектор скорости?

  22. 5
    Василий Some ответил:

    не изобретайте велосипед
    возьмите учебник физики и учебник по теормеху и прочитайте как это делается правильно

    если нужно чтобы это было правильно физически
    иначе – нормаль в точек касания и от нее угол падения равен углу отражения
    но это будет не упругое столкновение, и передачи импульса там не будет

  23. 4
    Сергей Канаев ответил:

    Можно даже немного иначе.
    Скорость представлять не как модуль и направление, а как вектор. Насколько я понял – вектор трех составляющих Vx, Vy, Vz.
    Учитывая упругость столкновения – Делаем следующее:
    Зная координаты центров шаров, мы можем составить уравнение прямой проходящей через оба центра. По этой линии они сталкиваются. Отталкиваться они будут по прямой касательной к обоим шарам в точке столкновения. Эта прямая есть не что иное, как перпендикулярная прямая к прямой центров

    Осталось только найти уравнение прямой в трех мерном пространстве (в объеме), а также уравнение прямой в объеме перпендикулярной к данной прямой.

  24. 3
    Павел Потапов ответил:

    Если я правильно понимаю, то надо разложить вектора скорости каждого из шаров на 2 составляющих:

    Vo – скорость шара в плоскости ортогональной линии центров в момент столкновения
    Vc – скорость шара по линии центров шаров

    Vo должна остаться неизменной для каждого шара, а Vc – измениться по закону сохранения импульса (наверно).

    складываем компоненты, получаем новые скорости.

  25. 2
    Миха Коробов ответил:

    Да, именно так :)

  26. 1
    Василий Some ответил:

    такое ощущение что вопрос задан чуть-чуть неправильно

    ball1.angle_xy = new_angle_xy;
    ball1.angle_xz = new_angle_xz;

    а new_angle_xy и new_angle_xz нужно посчитать, используя некоторое количество знаний по физике и механике…

Клуб программистов работает уже ой-ой-ой сколько, а если поточнее, то с 2007 года.