RU: Linear Transformation (1)

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

Линейное преобразование

Ортогональное линейное преобразование (класс gp_Trsf)

В OpenCascade ортогональное линейное преобразование описывается объектом класса gp_Trsf. Преобразование определяется следующими параметрами

    Standard_Real scale;    // Масштабный множитель
    gp_TrsfForm shape;      // Тип преобразования (перечисляемый, см. ниже)
    gp_Mat matrix;          // Матрица оператора размера 3 х 3
    gp_XYZ loc;             // Вектор переноса (3 компоненты)

Тип преобразования — перечисляемый тип, имеющий значения:
enum gp_TrsfForm {
    gp_Identity,        // Тождественное
    gp_Rotation,        // Поворот
    gp_Translation,     // Перенос
    gp_PntMirror,       // Отражение относительно точки
    gp_Ax1Mirror,       // Отражение относительно оси
    gp_Ax2Mirror,       // Отражение относительно плоскости
    gp_Scale,           // Масштабирование
    gp_CompoundTrsf,    // Комбинация преобразований
    gp_Other            // Другое
};

Обращаем внимание на то, что преобразование хранится не как матрица $4 \times 4$, а отдельно хранятся матрица $3 \times 3$ и вектор переноса. Масштабный множитель вычисляется таким образом, чтобы определитель матрицы равнялся единице, т.е. матрица описывала поворот.

Начнем с нескольких простых примеров. Преобразование переноса, т.е. перемещение точек пространства, описывается вектором сдвига $\mathbf{t}=(t_x, t_y, t_z)$: точка $A$ с радиус-вектором $\mathbf{r}_A=(x_A, y_A, z_A)$ переходит в точку $B$ с радиус-вектором $\mathbf{r}_B=\mathbf{r}_A+\mathbf{t}$:

    gp_Trsf trans;              // Создаем преобразование
    gp_Vec shift(1., 2, 3.);    // Вектор сдвига
    trans.SetTranslation(shift);// Преобразование сдвига
    gp_XYZ point(3., 2., 1.);   // Некоторая точка
    fprintf(fp,"before\t %f %f %f\n",point.X(),point.Y(),point.Z());
    trans.Transforms(point);    // Преобразуем ее
    fprintf(fp,"after\t %f %f %f\n",point.X(),point.Y(),point.Z());

Результат:

before   3.000000 2.000000 1.000000
after    4.000000 4.000000 4.000000

Преобразование поворота характеризуется тем, что точки пространства перемещаются как твердое тело: расстояния между точками не изменяются, а также не изменяются углы между отрезками, соединяющими точки. Впрочем, второе вытекает из первого.

    gp_Trsf transY;
// Поворот вокруг оси Y (0.,1.,0.) с неподвижной точкой (1.,0.,0.)
    transY.SetRotation(gp_Ax1(gp_Pnt(1.,0.,0.),gp_Dir(0.,1.,0.)),M_PI);
    fprintf(fp," Matrix:\n");
    for( int row=1; row<4; row++ ) {
        for( int col=1; col<5; col++ ) {
            fprintf(fp," %f ",transY.Value(row,col));
        }
        fprintf(fp,"\n");
    }
    gp_XYZ point(2., 0., 0.);   // Точка
    fprintf(fp,"before\t %f %f %f\n",point.X(),point.Y(),point.Z());
    transY.Transforms(point);
    fprintf(fp,"after\t %f %f %f\n",point.X(),point.Y(),point.Z());

Результат:

 Matrix:
 -1.000000  0.000000  0.000000  2.000000
  0.000000  1.000000  0.000000  0.000000
 -0.000000  0.000000 -1.000000  0.000000
before   2.000000 0.000000 0.000000
after    0.000000 0.000000 -0.000000

Результат двух последовательных поворотов зависит от порядка их выполнения.

    gp_Trsf transY, transZ;
// Повороты вокруг осей Y и Z на 90 градусов
    transY.SetRotation(gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,1.,0.)),M_PI/2.);
    transZ.SetRotation(gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,0.,1.)),M_PI/2.);
    gp_XYZ point(0., 1., 0.);
    fprintf(fp,"before ZY\t %f %f %f\n",point.X(),point.Y(),point.Z());
    transY.Transforms(point);
    fprintf(fp,"after Y\t %f %f %f\n",point.X(),point.Y(),point.Z());
    transZ.Transforms(point);
    fprintf(fp,"after Z\t %f %f %f\n",point.X(),point.Y(),point.Z());
    point.SetCoord(0., 1., 0.);
    fprintf(fp,"before YZ\t %f %f %f\n",point.X(),point.Y(),point.Z());
    transZ.Transforms(point);
    fprintf(fp,"after Z\t %f %f %f\n",point.X(),point.Y(),point.Z());
    transY.Transforms(point);
    fprintf(fp,"after Y\t %f %f %f\n",point.X(),point.Y(),point.Z());

Результат:

before ZY    0.000000 1.000000 0.000000
after Y      0.000000 1.000000 0.000000
after Z     -1.000000 0.000000 0.000000

before YZ    0.000000 1.000000 0.000000
after Z     -1.000000 0.000000 0.000000
after Y     -0.000000 0.000000 1.000000

Два последовательных поворота представляют собой также поворот на некоторый угол вокруг некоторой оси.

// Повороты вокруг осей Y и Z на 90 градусов
    gp_Trsf transY, transZ, transZY;
    transY.SetRotation(gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,1.,0.)),M_PI/2.);
    transZ.SetRotation(gp_Ax1(gp_Pnt(0.,0.,0.),gp_Dir(0.,0.,1.)),M_PI/2.);
    transZY = transZ.Multiplied(transY);
    gp_XYZ theAxis;
    Standard_Real theAngle;
    bool isTrue = transZY.GetRotation(theAxis, theAngle);
    gp_XYZ point = transZY.TranslationPart();
    fprintf(fp,"Axis\t %f %f %f\n",theAxis.X(),theAxis.Y(),theAxis.Z());
    fprintf(fp,"Angle\t %f\n",theAngle);
    fprintf(fp,"Point\t %f %f %f\n",point.X(),point.Y(),point.Z());

Результат:

Axis     -0.577350 0.577350 0.577350
Angle    2.094395
Point    0.000000 0.000000 0.000000

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

// Создает тождественное преобразование
    gp_Trsf()

Для задания параметров преобразования предназначены процедуры:

// Задание коэффициентов преобразования, переводящего
// точку x,y,z в точку x',y',z'по закону:
//  x' = a11 x + a12 y + a13 z + a14 <br>
//  y' = a21 x + a22 y + a23 z + a24 <br>
//  z' = a31 x + a32 y + a43 z + a34 <br>
// Tolang и TolDist используются для проверке нулевых значений
// угла расстояния при определении типа преобразования
    void SetValues(
        const Standard_Real a11, const Standard_Real a12,
        const Standard_Real a13, const Standard_Real a14,
        const Standard_Real a21, const Standard_Real a22,
        const Standard_Real a23, const Standard_Real a24,
        const Standard_Real a31, const Standard_Real a32,
        const Standard_Real a33, const Standard_Real a34,
        const Standard_Real Tolang, const Standard_Real TolDist
    )

// Замена вектора переноса преобразования на вектор V
    void SetTranslationPart(const gp_Vec& V)
// Замена масштабного множителя преобразования на число S
    void SetScaleFactor(const Standard_Real S)

Следующие процедуры устанавливают параметры, отвечающие преобразованиям конкретного типа:

// Задание коэффициентов, отвечающих преобразованию
// переноса на вектор V
    void SetTranslation(const gp_Vec& V)
// Задание коэффициентов, отвечающих преобразованию
// переноса на вектор, проведенный из точки P1 в точку P2
    void SetTranslation(const gp_Pnt& P1,const gp_Pnt& P2)

// Задание коэффициентов, отвечающих преобразованию
// отражения относительно точки P.
    void SetMirror(const gp_Pnt& P)
// Задание коэффициентов, отвечающих преобразованию
// отражения относительно оси A1.
    void SetMirror(const gp_Ax1& A1)
// Задание коэффициентов, отвечающих преобразованию
// отражения относительно плоскости, задаваемой системой координат A2.
    void SetMirror(const gp_Ax2& A2)

// Задание коэффициентов, отвечающих преобразованию
// поворота вокруг оси A1 на угол Ang (радианы). Поворот выполняется
// с неподвижной точкой "начала" оси вокруг "направления" оси
    void SetRotation(const gp_Ax1& A1,const Standard_Real Ang)

// Задание коэффициентов, отвечающих преобразованию
// масштабирования с множителем S относительно точки P
    void SetScale(const gp_Pnt& P,const Standard_Real S)

// Задание коэффициентов, отвечающих преобразованию,
// переводящему систему координат (начало и тройку векторов)FromSystem1
// в систему координат ToSystem2
    void SetDisplacement(const gp_Ax3& FromSystem1,const gp_Ax3& ToSystem2)

// Задание коэффициентов, отвечающих преобразованию,
// переводящему координаты вектора, заданного в системе координат FromSystem1,
// в координаты этого вектора в системе координат ToSystem2.
// Например:
//  Real x1, y1, z1;  // координаты точки в системе координат FromSystem1
//  Real x2, y2, z2;  // координаты точки в системе координат ToSystem2
//  gp_Pnt P1 (x1, y1, z1);
//  Trsf T;
//  T.SetTransformation (FromSystem1, ToSystem2);
//  gp_Pnt P2 = P1.Transformed (T);
//  P2.Coord (x2, y2, z2);
    void SetTransformation(const gp_Ax3& FromSystem1,const gp_Ax3& ToSystem2)
// Задание коэффициентов, отвечающих преобразованию,
// переводящему координаты вектора, заданного в системе координат по умолчанию
//  {P(0.,0.,0.), VX (1.,0.,0.), VY (0.,1.,0.), VZ (0., 0. ,1.) }
// в координаты этого вектора в системе координат ToSystem.
    void SetTransformation(const gp_Ax3& ToSystem)

Следующие процедуры позволяют опросить параметры преобразования:

// Опрос масштабного множителя преобразования
    Standard_Real ScaleFactor()
// Опрос вектора переноса преобразования
    gp_XYZ& TranslationPart()
// Опрос матрицы преобразования
// Это матрица 3*3 с учетом масштабного множителя
    gp_Mat VectorialPart()
// Опрос матрицы преобразования без учета масштабного множителя.
// Коэффициенты матрицы должны быть умножены на масштабный множитель,
// чтобы получились элементы истинной матрицы.
    gp_Mat& HVectorialPart()
// Опрос коэффицента преобразованияс индексами (Row, Col).
// Должны выполняться условия 1 <= Row <= 3, 1<= Col <= 4
    Standard_Real Value( const Standard_Integer Row,
        const Standard_Integer Col)
// Опрос оси theAxis и угла поворота theAngle преобразования
    Standard_Boolean GetRotation(gp_XYZ& theAxis,Standard_Real& theAngle)
// Процедура возвращает значение "истина", если
// определитель матрицы 3х3 преобразования отрицателен
    Standard_Boolean IsNegative()
// Опрос типа преобразования (см. выше)
    gp_TrsfForm Form()

Процедуры выполнения комбинации преобразований:

// Замена преобразования на обратное
    void Invert()
// Получение обратного преобразования
    gp_Trsf Inverted() const;

// Умножение данного преобразования справа на T
    void Multiply(const gp_Trsf& T)
// Оператор умножения справа
    void operator *=(const gp_Trsf& T)
// Вычисление преобразования  <me> * T
    gp_Trsf Multiplied(const gp_Trsf& T)
// Оператор вычисление преобразования  <me> * T
    gp_Trsf operator *(const gp_Trsf& T)

// Умножение преобразования T на данное слева,
// т.е.  <me> = T * <me>
    void PreMultiply(const gp_Trsf& T)

// Замена преобразования на его N-ую степень
// Если N = 0 <me> = Identity -- тождественное преобразование
// Если N < 0 -- степень обратного преобразования
    void Power(const Standard_Integer N)
// Вычисление N-ой степени преобразования
    gp_Trsf Powered(const Standard_Integer N)

// Применение преобразования к компонентам вектора
    void Transforms(Standard_Real& X,Standard_Real& Y,Standard_Real& Z)
// Применение преобразования к тройке чисел
    void Transforms(gp_XYZ& Coord)