Пример. Вращение колец
Постановка задачи
Мы хотим отобразить систему из трех вложенных лруг в друга вращающихся колец, как показано на рисунке.
Внешнее (красное) кольцо первоначально лежит плоскости $(x, y)$ и вращается вокруг оси $x$.
Второе (зеленое) кольцо первоначально лежит в плоскости $(y, z)$ и вращается относительно оси $y$ в системе координат первого кольца, т.е. ось вращения второго кольца прикреплена к первому.
Третье кольцо (синее) первоначально лежит в плоскости $(x, z)$, его ось вращения связана со вторым кольцом и в системе координат второго кольца третье кольцо вращается относительно оси $z$.
Геометрия системы задается двумя параметрами: радиусом внешнего кольца $r$ и толщиной колец $a$ (мы считаем, что кольца имеют квадратное сечение). Радиус второго кольца равен $r-a$, а третьего $r-2a$. Будем считать, что угловая скорость вращения у колец одинаковая и равна $\omega$.
Кроме движения колец мы построим траекторию точки, лежащей на внутреннем кольце.
Структура программы
Программа реализована в рамках MFC и подхода "документ-представление". Аналогично примерам Opencascade, в документе определен интерактивный контекст. Будем также считать, что документ имеет доступ к виду.
Handle(V3d_View) myView;
Handle(AIS_InteractiveContext) myAISContext;
При инициализации документа
- Задаем параметры колец и вида
//
// Задаем параметры
m_side = 0.1; // Длина стороны квадрата кольца
m_radius = 1.; // Радиус внешнего кольца
m_time = 0; // Текущее время
m_timeStep = 0.1; // Шаг по времени
m_omega = 1.; // Угловая скорость
m_bPause = true; // Признак паузы
myView->SetSize(5.);// Размер вида
m_pointCount = 0; // Число положений точки
//
// Оси координат
Handle(AIS_Trihedron) aisTrihedron;
Handle(Geom_Axis2Placement) axis = new Geom_Axis2Placement(gp::XOY());
aisTrihedron = new AIS_Trihedron(axis);
aisTrihedron->SetSize(1.);
myAISContext->Display(aisTrihedron);
- Строим кольца
gp_Pnt point[4];
TopoDS_Vertex vertex[4];
TopoDS_Edge edge[4];
TopoDS_Wire wire;
TopoDS_Shape shape;
//
// ----- Первое кольцо
radius = m_radius;
// Вершины (квадрат в плоскости xz)
point[0].SetCoord(radius+0.5*m_side,0.0,-0.5*m_side);
point[1].SetCoord(radius-0.5*m_side,0.0,-0.5*m_side);
point[2].SetCoord(radius-0.5*m_side,0.0,+0.5*m_side);
point[3].SetCoord(radius+0.5*m_side,0.0,+0.5*m_side);
//
for( i=0; i<4; i++ )
vertex[i] = BRepBuilderAPI_MakeVertex(point[i]);
//
// Ребра
for( i=0;i<4; i++ ) {
ip = (i+1)%4;
edge[i] = BRepBuilderAPI_MakeEdge(vertex[i],vertex[ip]);
}
// Контур
wire = BRepBuilderAPI_MakeWire(edge[0],edge[1],edge[2],edge[3]);
// Тело вращения
gp_Ax1 axis = gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,0.,1.));
shape = BRepPrimAPI_MakeRevol(wire,axis, 360.*M_PI/180.);
m_aisShape[0] = new AIS_Shape(shape);
myAISContext->SetColor(m_aisShape[0],Quantity_NOC_RED,Standard_False);
//
// ----- Второе кольцо
// Вершины
radius -= m_side; // Уменьшаем радиус
// Координаты точек заменяются циклически
point[0].SetCoord(-0.5*m_side,radius+0.5*m_side,0.0);
point[1].SetCoord(-0.5*m_side,radius-0.5*m_side,0.0);
point[2].SetCoord(+0.5*m_side,radius-0.5*m_side,0.0);
point[3].SetCoord(+0.5*m_side,radius+0.5*m_side,0.0);
//
for( i=0; i<4; i++ )
vertex[i] = BRepBuilderAPI_MakeVertex(point[i]);
//
// Ребра
for( i=0;i<4; i++ ) {
ip = (i+1)%4;
edge[i] = BRepBuilderAPI_MakeEdge(vertex[i],vertex[ip]);
}
// Контур
wire = BRepBuilderAPI_MakeWire(edge[0],edge[1],edge[2],edge[3]);
// Тело вращения
axis = gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(1.,0.,0.));
shape = BRepPrimAPI_MakeRevol(wire,axis, 360.*M_PI/180);
m_aisShape[1] = new AIS_Shape(shape);
myAISContext->SetColor(m_aisShape[1],Quantity_NOC_GREEN,Standard_False);
//
// ----- Третье кольцо
// Вершины
radius -= m_side; // Уменьшаем радиус
// Координаты точек заменяются циклически
point[0].SetCoord(0.0,-0.5*m_side,radius+0.5*m_side);
point[1].SetCoord(0.0,-0.5*m_side,radius-0.5*m_side);
point[2].SetCoord(0.0,+0.5*m_side,radius-0.5*m_side);
point[3].SetCoord(0.0,+0.5*m_side,radius+0.5*m_side);
//
for( i=0; i<4; i++ )
vertex[i] = BRepBuilderAPI_MakeVertex(point[i]);
//
// Ребра
for( i=0;i<4; i++ ) {
ip = (i+1)%4;
edge[i] = BRepBuilderAPI_MakeEdge(vertex[i],vertex[ip]);
}
// Контур
wire = BRepBuilderAPI_MakeWire(edge[0],edge[1],edge[2],edge[3]);
// Тело вращения
axis = gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,1.,0.));
shape = BRepPrimAPI_MakeRevol(wire,axis, 360.*M_PI/180);
m_aisShape[2] = new AIS_Shape(shape);
myAISContext->SetColor(m_aisShape[2],Quantity_NOC_BLUE1,Standard_False);
//
- Задаем точку на третьем кольце, траекторию которой будем отображать
//
// Задаем точку на третьем кольце
m_point.SetCoord(0.0,0.0,radius+0.5*m_side);
Handle(Geom_CartesianPoint) geomPoint = new Geom_CartesianPoint(m_point);
Handle(AIS_Point) aisPoint = new AIS_Point(geomPoint);
aisPoint->SetMarker (Aspect_TOM_BALL ); // Тип маркера
myAISContext->SetColor(aisPoint,Quantity_NOC_YELLOW); // Цвет
myAISContext->Display(aisPoint);
В программе имеется таймер, который через определенные промежутки времени вызывает процедуру документа. В этой процедуре выполняется преобразование фигур, а именно:
//
if( m_bPause ) // Если пауза -- выходим
return;
//
m_time += m_timeStep; // Сдвигаем время
//
// Вращение
gp_Trsf trsf[3];
// Первое (красное) кольцо вращаем относительно оси X
trsf[0].SetRotation (gp::OX(), m_omega*m_time);
// Второе (зеленое) кольцо вращаем относительно оси Y
trsf[1].SetRotation (gp::OY(), m_omega*m_time);
trsf[1].PreMultiply(trsf[0]); // В координатах кольца 0
// Третье (синее) кольцо вращаем относительно оси Z
trsf[2].SetRotation (gp::OZ(), m_omega*m_time);
trsf[2].PreMultiply(trsf[1]); // В координатах кольца 1
//
myAISContext->SetLocation(m_aisShape[0],TopLoc_Location(trsf[0]));
myAISContext->Redisplay(m_aisShape[0],Standard_True);
myAISContext->SetLocation(m_aisShape[1],TopLoc_Location(trsf[1]));
myAISContext->Redisplay(m_aisShape[1],Standard_True);
myAISContext->SetLocation(m_aisShape[2],TopLoc_Location(trsf[2]));
myAISContext->Redisplay(m_aisShape[2],Standard_True);
//
// Положение точки
Handle(Geom_CartesianPoint) geomPoint = new Geom_CartesianPoint(m_point);
Handle(AIS_Point) aisPoint;
if( m_pointCount<100 ) { // Отображаем только первые 100 положений
aisPoint = new AIS_Point(geomPoint);
aisPoint->SetMarker (Aspect_TOM_BALL ); // Тип маркера
myAISContext->SetColor(aisPoint,Quantity_NOC_YELLOW); // Цвет
myAISContext->Display(aisPoint);
myAISContext->SetLocation(aisPoint,TopLoc_Location(trsf[2]));
m_pointCount++;
}
На рисунке справа представлено положение колец на некоторый момент времени. Маркеры показывают траекторию точки, лежащей на третьем кольце. Обратим внимание на то, что при формировании сложного преобразования (внутреннее кольцо вращается в системе координат внешнего) матрица внешнего преобразования должна стоять слева.