RU: Line

Геометрические примитивы

Прямая линия

Уравнение прямой

Прямая задается точкой ${\bf r}_0$ на ней и вектором ${\bf a}$, направленным вдоль прямой: ${\bf r}(t) = {\bf r}_0 + {\bf a}t$. В координатной записи это выглядит так:

(1)
\begin{align} x(t) = x_0 + a_x t, \qquad y(t) = y_0 + a_y t, \qquad z(t) = z_0 +a_z t \end{align}

или

(2)
\begin{align} \frac{x - x_0}{a_x} = \frac{y - y_0}{a_y} =\frac{z - z_0}{a_z} \end{align}

Поскольку вектор ${\bf r}-{\bf r}_0$ коллинеарен вектору ${\bf a}$, их векторное прозведение равно нулю, так что уравнение прямой, проходящей через точку ${\bf r}_0$ и параллельной вектору ${\bf a}$, имеет вид $[{\bf r},{\bf a}]=[{\bf r}_0,{\bf a}]$.

Если прямая задана двумя точками ${\bf r}_A$, ${\bf r}_B$, то ее уравнение имеет вид ${\bf r}(t) = t\,{\bf r}_B + (1-t)\,{\bf r}_A$ — при увеличении параметра $t$ от $0$ до $1$ точка ${\bf r}(t)$ движется от ${\bf r}_A$ до ${\bf r}_B$.

Рассмотрим понятия, связанные с взаимным положением точки и прямой. В пространстве можно говорить о расстоянии точки от прямой и о перпендикуляре, опущенном з точки на прямую (вдоль него измеряется расстояние). На плоскости можно говорить о том, что точка находится слева, справа, или на самой прямой. Фактически, речь идет об ориентации обхода трех точек. Пусть $A$ и $B$ — точки на прямой, причем точка $B({\bf r}_B)$ отвечает большему значению параметра, а $M$ — произвольная точка плоскости. Вводя координаты точек, вычислим определитель

(3)
\begin{vmatrix} x_A & y_A & 1 \\ x_B & y_B & 1 \\ x_M & y_M & 1 \end{vmatrix}

равный удвоенной площади треугольника $ABM$. Если точка $M$ находится слева от прямой (обход $A\rightarrow B \rightarrow M$ выполняется против часовой стрелки), то значение определителя положительно. Если точка $M$ находится на прямой, определитель равен нулю, а его отрицательное значение указывает на то, что точка $M$ лежит справа от прямой.

При рассмотрении взаимного положения двух прямых можно говорить об угле между ними, об общем перпендикуляре (прямой, перпендкулярной как первой, так и второй линии) и о расстоянии между прямыми (которое измеряется по общему перпендикуляру). Если это расстояние равно нулю, то прямые пересекаются.

Классы, связанные с понятием "прямая"

В OpenCascade с понятием "прямая линия" связаны следующие классы:

  • класс gp_Lin — описание прямой в виде точки и направления;
  • класс gce_MakeLin — некоторые алгоритмы построения прямой;
  • класс Geom_Line — описание прямой как параметричкски заданной кривой;
  • класс AIS_Line — прямая как отображаемый объект.

Рассмотрим на примерах использование объектов указанных классов.

При описании прямой базовым классом служит класс gp_Lin. Прямая в нем рассматривается как совокупность точки и направления, т.е. как одномерная ось gp_Ax1. Обратим внимание на то, что в этом классе нет понятия параметра.

Создадим прямую, проходящую через точку gp_Pnt(0.,0.,1.) в направлении вектора gp_Dir(1.,1.,0.):

// Создание линии, проходящей через точку P и направленной по V
    gp_Lin gpLine(gp_Pnt(0.,0.,1.),gp_Dir(1.,1.,0.));

Вычислим расстояние от точки gp_Pnt(1.,1.,0.) до этой прямой, а также проведем перпендикуляр
// Вычисление расстояния точки P до прямой
    gp_Pnt point((1.,1.,0.);
    Standard_Real dist = gpLine.Distance(point);    //  1.0000
// Нахождение прямой, перпендикулярной данной и проходящей через точку P.
    gp_Lin gpLine2 = gpLine. Normal(point);
// Ее параметры: точка и направление
    gp_Pnt point2 = gpLine2.Location(); //  ( 1.0000, 1.0000, 0.0000 )
    gp_Dir dir2 = gpLine2.Direction();  //  ( 0.0000, 0.0000,-1.0000 )

Проверим, что прямые gpLine и gpLine2 ортогональны
// Вычисление угла (в радианах) между двумя прямыми
    Standard_Real angle = gpLine.Angle(gpLine2);    //  1.5707

Класс gp_Lin содержит также методы преобразования прямой: сдвиг, отражения относительно точки, направления и плоскости.

Класс gce_MakeLin реализует некоторые алгоритмы построения прямой линии, а именно:

  • создание прямой, параллельной данной, и проходящей через заданную точку;
  • создание прямой по двум точкам;
  • создание прямой по оси;
  • создание прямой по точке и направлению.

хотя последние два метода есть и в классе gp_Lin.

Построим прямую, проходящую через начало координат, параллельно прямой gpLine

// Создание линии, параллельной Lin и проходящей через точку Point
    gp_Lin gpLine3 = gce_MakeLin(gpLine, gp::Origin());

Построим прямую, проходящую через начало координат и точку $(1, 1, 1)$. При этом мы проверим, выполнено ли построение (ошибка возникает при совпадении точек)
// Создание линии, проходящей через две точки
    gce_MakeLin makeLin(gp::Origin(),gp_Pnt(1.,1.,1.));
    if( makeLin.IsDone() ) {
        gpLine3 = makeLin.Value();
    }

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

Построим параметрическую прямую, проходящую через начало координат и точку $(1, 1, 1)$. Вычислим точки на прямой при различных значениях параметра:

// Создание линии, проходящей через две точки
   gp_Lin gpLine = gce_MakeLin(gp::Origin(),gp_Pnt(1.,1.,1.));
   Geom_Line geomLine(gpLine);    
//
   gp_Pnt point;
   point = geomLine.Value(0.0); // ( 0.0000, 0.0000, 1.0000 )
   point = geomLine.Value(0.5); // ( 0.2886, 0.2886, 0.2886 )
   point = geomLine.Value(1.0); // ( 0.5773, 0.5773, 0.5773 )

Класс AIS_Line предназначен для отображения (рисования) прямой. Отображаемый объект создается на основе прямой, либо двух точек:

// Конструктор на основе прямой
    AIS_Line(const Handle(Geom_Line)& aLine)
//
// Конструктор на основе двух точек
    AIS_Line(const Handle(Geom_Point)& aStartPoint,const Handle(Geom_Point)& aEndPoint);

В первом случае создается бесконечная прямая, во втором — отрезок. Прямую можно нарисовать различным цветом и разной толщины
// Задание цвета линии
    void SetColor(const Quantity_NameOfColor aColor)
    void SetColor(const Quantity_Color& aColor)
//
// Задание толщины линии
    void SetWidth(const Standard_Real aValue)

Приведенные выше методы предоставляются самим классом AIS_Line. Но надо иметь в виду, что прямая, как интерактивный объект, имеет гораздо более полный набор атрибутов. Для доступа к ним нужно обратиться к "средствам рисования" (Drawer) интерактивного объекта. У "рисовальщика" (Drawer) есть атрибуты, указывающие как отображать каждый элемент. В частности, для линии эти атрибуты находятся в классе Prs3d_LineAspect и их три:
  • цвет линии;
  • толщина линии;
  • тип линии (сплошная, пунктрная и т.д.).

Все сказанное проиллюстрируем следующим примером (см. рисунок справа). Нарисуем (красным цветом) бесконечную прямую, проходящую через начало координат и точку $(1,1,1)$. Зеленым нарисуем отрезок, соединяющий две другие верщины единичного куба: $(1,0,0)$ и $(0,1,1)$. Для наглядности нарисуем оси координат, а белым пунктирными линиям отобразим ребра куба.

OCC_line01.JPG
//
// Рисуем оси координат (для наглядности)
   Handle(Geom_Axis2Placement) axes;
   axes = new Geom_Axis2Placement(gp::XOY());
   Handle(AIS_Trihedron) aisTrihedron;
   aisTrihedron = new AIS_Trihedron(axes);
   aisTrihedron->SetSize(1.0);
   myAISContext->Display(aisTrihedron);
//
// Прямая (бесконечная), проходящая по главной диагонали единичного куба
   gp_Lin gpLine = gce_MakeLin(gp::Origin(),gp_Pnt(1.,1.,1.));
   Geom_Line geomLine(gpLine);
   Handle(AIS_Line) aisLine = new AIS_Line(&geomLine);
   aisLine->SetColor(Quantity_NOC_RED);   // ее цвет -- синий
   aisLine->SetWidth(2.);   // ее толщина
// Отобразить объект на экране.
   myAISContext->Display(aisLine);
//
// Отрезок,
   Handle(Geom_CartesianPoint) start, end;
   start = new Geom_CartesianPoint(gp_Pnt(1.,0.,0.));    // Начало
   end = new Geom_CartesianPoint(gp_Pnt(0.,1.,1.));      // Конец
    Handle(AIS_Line) aisSegment = new AIS_Line(start, end);
   aisSegment->SetColor(Quantity_NOC_GREEN);  // Цвет
   aisSegment->SetWidth(2.);                  // Толщина
// Отобразить объект на экране.
   myAISContext->Display(aisSegment);
//
   Handle(AIS_Line) aisSide;
   Handle(AIS_Drawer) drawer;
   Handle(Prs3d_LineAspect) lineAspect;
// Точки: начала и концы ребер куба
   gp_Pnt ends[9][2];
   ends[0][0].SetCoord(1.,0.,0.);   ends[0][1].SetCoord(1.,0.,1.);
   ends[1][0].SetCoord(1.,1.,0.);   ends[1][1].SetCoord(1.,1.,1.);
   ends[2][0].SetCoord(0.,1.,0.);   ends[2][1].SetCoord(0.,1.,1.);
   ends[3][0].SetCoord(1.,0.,0.);   ends[3][1].SetCoord(1.,1.,0.);
   ends[4][0].SetCoord(1.,1.,0.);   ends[4][1].SetCoord(0.,1.,0.);
   ends[5][0].SetCoord(0.,0.,1.);   ends[5][1].SetCoord(1.,0.,1.);
   ends[6][0].SetCoord(1.,0.,1.);   ends[6][1].SetCoord(1.,1.,1.);
   ends[7][0].SetCoord(1.,1.,1.);   ends[7][1].SetCoord(0.,1.,1.);
   ends[8][0].SetCoord(0.,1.,1.);   ends[8][1].SetCoord(0.,0.,1.);
//
// Цикл по ребрам
   for( int i=0; i<9; i++ ) {
   // Начальная и конечная точки
      start = new Geom_CartesianPoint(ends[i][0]);
      end = new Geom_CartesianPoint(ends[i][1]);
   // Сторона
      aisSide = new AIS_Line(start,end);
      if(!aisSide->HasInteractiveContext())
         aisSide->SetContext(myAISContext);
   // Рисовальщик линии
      drawer = aisSide->Attributes();
   // Свойства линии
      lineAspect = drawer->LineAspect();
      lineAspect->SetColor(Quantity_NOC_WHITE);    // Цвет белый
      lineAspect->SetTypeOfLine(Aspect_TOL_DOT);   // Тип пунктир
   // Отобразить объект на экране.
      myAISContext->Display(aisSide);
   }