RU: Vector

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

Вектор

В 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)
\begin{align} (\mathbf{x},\mathbf{a}) &=\alpha, & [\mathbf{x},\mathbf{a}] &=\mathbf{b}. \end{align}

Решение дается выражением

(2)
\begin{align} \mathbf{x} = \frac{1}{|\mathbf{a}|^2}[\mathbf{a},\mathbf{b}] +\frac{\alpha}{|\mathbf{a}|^2}\mathbf{a} \end{align}

Вот соответствующий участок кода:

    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)
\begin{align} (\mathbf{x},\mathbf{a}) &=\alpha, & (\mathbf{x},\mathbf{b}) &=\beta, & (\mathbf{x},\mathbf{c}) &=\gamma. \end{align}

Решение дается выражением

(4)
\begin{align} \mathbf{x} = \alpha\frac{[\mathbf{b},\mathbf{c}]}{(\mathbf{a}, \mathbf{b},\mathbf{c})}+ \beta\frac{[\mathbf{c},\mathbf{a}]}{(\mathbf{a}, \mathbf{b},\mathbf{c})}+ \gamma\frac{[\mathbf{a},\mathbf{b}]}{(\mathbf{a}, \mathbf{b},\mathbf{c})} \end{align}

Вот соответствующий участок кода:

    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);