Геометрические примитивы
Вектор
В OpenCascade с понятием "вектор" связаны следующие классы:
- Класс gp_Vec описывает свободный вектор, характеризующихся только координатами.
- Класс gp_Dir описывает свободный единичный вектор, задающий направление в пространстве.
Вектор считается нулевым, если его длина (модуль) не превосходит значения Standard_Real gp::Resolution().
Рассмотрим несколько примеров использования объектов указанных классов. Основные операции с векторами, это их сложение
(вычитание) и вычисление скалярного и векторного произведений.
Создадим векторы $\mathbf{a}(1,2,3)$, $\mathbf{b}(2,1,0)$ и вычислим их сумму $\mathbf{c} = \mathbf{a} + \mathbf{b}$:
gp_Vec a, b, c;
a.SetCoord(1.,2.,3.);
b.SetCoord(2.,1.,0.);
c = a + b; // (3., 3., 3.)
Standard_Real cLen = c.Magnitude(); // 5.192
Вычислим векторное произведение векторов $\mathbf{a}$, $\mathbf{b}$: $\mathbf{d}=[\mathbf{a},\mathbf{b}]$ и проверим, что векторы $\mathbf{c}$ и $\mathbf{d}$ ортогональны:
gp_Vec d = a^b;
Standard_Boolean isNormal = c.IsNormal(d,1.e-5);
Направление (объект класса gp_Dir) — вектор единичной длины. Например
gp_Dir a_dir = gp_Dir(a); // (0.267, 0.534, 0.801 )
Разложим вектор $\mathbf{b}$ на две составляющие, одна из которых параллельна, а другая перпендикулярна вектору $\mathbf{a}$. Обратим внимание на то, что вместо направления в выражениях следует использовать едничный вектор, поскольку операции с направленем могут привести к нормированию результата:
gp_Vec a_unit = gp_Vec(a_dir);
gp_Vec b_par = (b*a_unit)*a_unit; // Компонента, параллельная вектору a
gp_Vec b_perp = a_unit^(b^a_unit); // Компонента, перпендикулярная вектору a
// Проверим, что в сумме они дают вектор b
Standard_Boolean isEqual = b.IsEqual(b_par+b_perp,1.e-5,1.e-5); // True
Координаты вектора зависят от системы координат, в которой они вычисляются. Система координат (в трехмерном пространстве) описывается объектом класса gp_Ax3. Система координат предполагается ортонормированной (декартовой), т.е. состоящей из трех векторов единичной длины, ортогональных друг другу. Она может быть правой (direct sense) или левой (indirect sense). Система координат определяется:
- точкой отсчета, началом системы координат (Location point)
- тремя единичным взаимно-ортогональным векторами, называемыми ось $x$ (X Direction), ось $y$ (Y Direction) и главная ось (ось $z$, main Direction)
Ось $z$ называется "главной" потому, что при изменении этого вектора оси $x$ и $y$ пересчитываются, а при изменении осей $x$ и $y$ ось $z$ остается неизменной. Ось $z$ всегда параллельна векторному произведению осей $x$ и $y$ (имеет то же или противоположное направление). Обозначая точку отсчета через $O$, базисные векторы через $\mathbf{e}_x$, $\mathbf{e}_y$, $\mathbf{e}_z$, систему координат можно записать как совокупность четырех элементов: $(O,\mathbf{e}_x, \mathbf{e}_y, \mathbf{e}_z)$. Предполагается, что есть некоторая основная система координат, относительно которой задаются все остальные.
Создадим систему координат, направив ось $x$ по вектору $\mathbf{a}$, а ось $z$ по векторному произведению векторов $\mathbf{a}$ и $\mathbf{b}$, т.е. по вектору $\mathbf{d}$:
gp_Ax3 frameNew = gp_Ax3(gp::Origin(),gp_Dir(d),gp_Dir(a));
gp_Dir axisX = frameNew.XDirection(); // ( 0.267, 0.534, 0.801)
gp_Dir axisY = frameNew.YDirection(); // ( 0.872, 0.218,-0.436)
gp_Dir axisZ = frameNew.Direction(); // (-0.408, 0.816,-0.408)
Чтобы вычислить координаты вектора в новой системе координат, нужно получить закон их преобраования. Это объект класса gp_Trsf.
gp_Trsf toNew;
toNew.SetTransformation(frameNew);
Вычислим теперь координаты векторов $\mathbf{a}$, $\mathbf{b}$ и $\mathbf{d}$. Ясно, что в новой системе координат вектор $\mathbf{a}$ должен иметь только x-компоненту, z-компонента у вектора $\mathbf{b}$ должна быть равна нулю, а вектор $\mathbf{d}$ должен иметь только z-компоненту:
gp_Vec a_new = a.Transformed(toNew); // ( 3.741, 0.000, 0.000 )
gp_Vec b_new = b.Transformed(toNew); // ( 1.069, 1.963, 0.000 )
gp_Vec d_new = d.Transformed(toNew); // ( 0.000, 0.000, 7.348 )
Рассмотрим две задачи о нахождении вектора по заданным произведениям его с другими векторами. Вектор определен, если заданы его скалярное и векторное произведения. Итак, пусть даны два взаимно-перпендикулярных вектора $\mathbf{a}$ и $\mathbf{b}$ и число $\alpha$. Требуется найти вектор $\mathbf{x}$, такой, что
(1)Решение дается выражением
(2)Вот соответствующий участок кода:
gp_Vec a, b, x;
Standard_Real alpha;
// Задаем параметры
a.SetCoord( ... )
b.SetCoord( ... )
alpha = ...
// Проверим ортогональность
if( ! a.IsNormal(b) )
... // Сообщение об ошибке в данных
Standard_Real sm = a.SquareMagnitude();
x = (a^b + alpha*a) / sm;
Вторая стуация. Вектор определен, если заданы его скалярные произведения с тремя некопланарными (не лежащими в одной плоскости) векторами. Итак, пусть даны три некомпланарных вектора $\mathbf{a}$, $\mathbf{b}$ и $\mathbf{c}$ и три числа $\alpha$, $\beta$, $\gamma$. Требуется найти вектор $\mathbf{x}$, такой, что
(3)Решение дается выражением
(4)Вот соответствующий участок кода:
gp_Vec a, b, c, x;
Standard_Real alpha, beta, gamma;
// Задаем параметры
a.SetCoord( ... )
b.SetCoord( ... )
c.SetCoord( ... )
alpha = ...
beta = ...
gamma = ...
// Проверим некомпланарность
Standard_Real abc = a.DotCross(b,c);
if( fabs(abc)<epsilon )
... // Сообщение об ошибке в данных
// Векторы взаимного базиса
gp_Vec a_rec, b_rec, c_rec;
a_rec = b^c / abc;
b_rec = c^a / abc;
c_rec = a^b / abc;
// Результат
x = alpha*a_rec + beta*b_rec + gamma*c_rec;
Чтобы нарисовать вектор, можно воспользоваться классом отображения отрезка прямой, у которого имеется свойство "стрелка".
// Строим отрезок прямой по двум точкам
gp_Pnt point1(0.,0.,0.);
gp_Pnt point2(100.,100.,100.);
Handle(Geom_CartesianPoint) geomPoint1 = new Geom_CartesianPoint(point1);
Handle(Geom_CartesianPoint) geomPoint2 = new Geom_CartesianPoint(point2);
Handle(AIS_Line) line = new AIS_Line(geomPoint1,geomPoint2);
//
// Устанавливаем атрибуты (стрелка, цвет)
if(!line->HasInteractiveContext())
line->SetContext(myAISContext);
Handle(Prs3d_Drawer) drawer = line->Attributes()->Link();
drawer->SetLineArrowDraw(Standard_True);
drawer->ArrowAspect()->SetLength(50);
drawer->LineAspect()->SetColor(Quantity_NOC_RED);
//
// Высвечваем
myAISContext->Display(line);