Геометрические примитивы
Прямая линия
Уравнение прямой
Прямая задается точкой ${\bf r}_0$ на ней и вектором ${\bf a}$, направленным вдоль прямой: ${\bf r}(t) = {\bf r}_0 + {\bf a}t$. В координатной записи это выглядит так:
(1)или
(2)Поскольку вектор ${\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)равный удвоенной площади треугольника $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)$. Для наглядности нарисуем оси координат, а белым пунктирными линиям отобразим ребра куба.
//
// Рисуем оси координат (для наглядности)
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);
}