Ru: Sample. Rotating rings

Пример. Вращение колец

Постановка задачи

Мы хотим отобразить систему из трех вложенных лруг в друга вращающихся колец, как показано на рисунке.
Внешнее (красное) кольцо первоначально лежит плоскости $(x, y)$ и вращается вокруг оси $x$.
Второе (зеленое) кольцо первоначально лежит в плоскости $(y, z)$ и вращается относительно оси $y$ в системе координат первого кольца, т.е. ось вращения второго кольца прикреплена к первому.
Третье кольцо (синее) первоначально лежит в плоскости $(x, z)$, его ось вращения связана со вторым кольцом и в системе координат второго кольца третье кольцо вращается относительно оси $z$.
Геометрия системы задается двумя параметрами: радиусом внешнего кольца $r$ и толщиной колец $a$ (мы считаем, что кольца имеют квадратное сечение). Радиус второго кольца равен $r-a$, а третьего $r-2a$. Будем считать, что угловая скорость вращения у колец одинаковая и равна $\omega$.

OCC_ring01.JPG


Кроме движения колец мы построим траекторию точки, лежащей на внутреннем кольце.

Структура программы

Программа реализована в рамках 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++;
   }

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

OCC_ring02.JPG