Здравствуйте!
Пишу проект на тему "Моделирование передачи импульса", и у меня возникли затруднения.
Итак, пользователь вводит скорости, массы, начальные и конечные координаты двух шаров. Затем заполняются структуры 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
2 марта 2010 в 18:03
Все, работает! Огромное спасибо!!!
2 марта 2010 в 15:02
Это ж тоже самое, только записано по-другому.
Должно быть что-то вроде:
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;
2 марта 2010 в 14:04
А так правильно?
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;
2 марта 2010 в 13:04
Да, нормированный вектор – единичный.
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мя параметрами (если используется создание вектора с известными координатам). Также можно добавить деструктор.
1 марта 2010 в 21:03
Павел Потапов, а нормированная разность векторов – это единичный вектор?
Вот, кое-что написал для первого шара:
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 – вроде бы правильный.
А насчет скорости – то да, задержку таймера только поменять нужно
1 марта 2010 в 16:00
Это как? Если скорость постоянна, то шар двигается равномерно прямолинейно.
1 марта 2010 в 15:04
Если так, то при большой скорости шар будет рывками двигаться.
1 марта 2010 в 0:05
Приращение координаты по времени в зависимости от скорости? Нет, оно будет
ball.x += v.x * t;
ball.y += v.y * t;
ball.z += v.z * t;
28 февраля 2010 в 21:04
Хм… А ведь действительно проще! Спасибо! То есть приращение координаты, например x, будет:
ball1.x+=cos(arcctg(ball1.i/ball1.j));
// i, j – координаты вектора
???
28 февраля 2010 в 21:00
Да, и для векторов лучше завести отдельную структуру, а также пару-тройку методов, типа сложения/вычитания.
28 февраля 2010 в 20:04
С углами мне как-то тяжело разобраться. Имхо, с векторами будет проще.
Вроде алгоритм такой:
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.
28 февраля 2010 в 17:05
Я вот так подумал, нужно сделать как-то так:
if (<условие>) angle_х12+=PI;
Только вот не могу <условие> понять какое? и как правильнее найти проекции на оси?
28 февраля 2010 в 15:03
Павел Потапов, знаю, что мало. Я пока написал все это для плоскости, потом добавлю третье измерение. А в моем случае что нужно добавить в этот код? Просто переписывать весь проект будет трудновато
Сергей Переславцев, спасибо, обязательно посмотрю!
28 февраля 2010 в 10:02
раньше занимался физикой в 3Д играх, рекомендую посмотреть классический труд на эту тему
//www.cs.cmu.edu/~baraff/pbm/rigid1.pdf
//www.cs.cmu.edu/~baraff/pbm/rigid2.pdf
там даны формулы расчетов крутящего момента по импульсу и тензору инерции (для шара тривиально).
погугли есть кучи готовых демок на эту тему.
28 февраля 2010 в 3:02
Ось а – прямая, соединяющая центры шаров.
Ось b – прямая, ортогональная оси а.
Мало. Если говорить о трехмерном пространстве, то должна еще быть третья ось, ортогональная первым двум.
На мой взгляд в данном случае проще представлять скорость вектором, а не модулем и углами. Тогда проекция на ось, соединяющую центры шаров, будет вычисляться, как векторное произведение скорости на нормированный вектор, лежащий на этой прямой. (Компонента в векторном виде – это произведение проекции на нормированный вектор.) А проекция на ортогональную плоскость – как их векторное произведение.
Новое значение будет просто суммой двух компонент (векторов).
27 февраля 2010 в 19:01
И еще раз, здавствуйте!
Вот написал несколько строчек, правда нужно что-то добавить, а чего – не знаю, так как работает не вполне правильно. Вот код:
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 февраля 2010 в 12:03
Не совсем так. Скорость каждого шара состоит из 2х компонент. Модуль компоненты в плоскости ортгональной линии столкновения не меняется. Изменяется только компонента скорости в направлении линии столкновения.
Т.е. если говорить о векторах, то V(new) = Vo + Vc(new).
А вот уже Vc(new) расчитывается по закону сохранения импульса.
16 февраля 2010 в 19:03
нет. не так.
у вас речь идет о телах с разной массой. вы не можете суммировать вектора скоростей.
//ru.wikibooks.org/wiki/%D0%97%D0%B0%D0%B4%D0%B...
эадача 5, для 2-мерного пространства, вам достаточно добавить третье измерение.
в двух словах, вам необходимо считать обмен импульсами, для получения конечных скоростей.
16 февраля 2010 в 19:02
В смысле – модуль скорости? Если да, то
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);
16 февраля 2010 в 18:05
Ну… вроде да.
Единственное, что я мог наврать на счет закона сохранения импульса Как вычислить правильное значение новой компоненты скорости надо посчитать.
16 февраля 2010 в 18:02
Ага, всем спасибо!
Павел Scavenger Потапов, то естьвектор Vo+Vc и будет искомый вектор скорости?
16 февраля 2010 в 17:05
не изобретайте велосипед
возьмите учебник физики и учебник по теормеху и прочитайте как это делается правильно
если нужно чтобы это было правильно физически
иначе – нормаль в точек касания и от нее угол падения равен углу отражения
но это будет не упругое столкновение, и передачи импульса там не будет
16 февраля 2010 в 17:00
Можно даже немного иначе.
Скорость представлять не как модуль и направление, а как вектор. Насколько я понял – вектор трех составляющих Vx, Vy, Vz.
Учитывая упругость столкновения – Делаем следующее:
Зная координаты центров шаров, мы можем составить уравнение прямой проходящей через оба центра. По этой линии они сталкиваются. Отталкиваться они будут по прямой касательной к обоим шарам в точке столкновения. Эта прямая есть не что иное, как перпендикулярная прямая к прямой центров
Осталось только найти уравнение прямой в трех мерном пространстве (в объеме), а также уравнение прямой в объеме перпендикулярной к данной прямой.
16 февраля 2010 в 16:03
Если я правильно понимаю, то надо разложить вектора скорости каждого из шаров на 2 составляющих:
Vo – скорость шара в плоскости ортогональной линии центров в момент столкновения
Vc – скорость шара по линии центров шаров
Vo должна остаться неизменной для каждого шара, а Vc – измениться по закону сохранения импульса (наверно).
складываем компоненты, получаем новые скорости.
16 февраля 2010 в 15:03
Да, именно так
16 февраля 2010 в 15:02
такое ощущение что вопрос задан чуть-чуть неправильно
ball1.angle_xy = new_angle_xy;
ball1.angle_xz = new_angle_xz;
а new_angle_xy и new_angle_xz нужно посчитать, используя некоторое количество знаний по физике и механике…