RU: Curve

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

Кривая

Мы дадим вначале краткий математический обзор свойств кривой, а затем поговорим о классах OpenCascade, связанных с этим понятием.

Математическое описание

Рассмотрим некоторые свойства векторной функции одного скалярного аргумента. Геометрическим образом такой функции служит кривая (линия) в пространстве. Пусть каждому значению скалярной величины $t$ из области допустимых значений $T$ поставлен в соответствие вектор ${\bf a}(t)$. В этом случае говорят, что задана векторная функция скалярного аргумента. В дальнейшем мы будем считать, что область допустимых значений $T$ представляет собой отрезок вещественной оси.

Зафиксируем в пространстве некоторую точку отсчета $O$ и будем откладывать все векторы ${\bf a}(t)$ от этой точки. Если функция непрерывная, то при изменении параметра $t$ конец вектора будет описывать некоторую кривую в пространстве, называемую годографом функции ${\bf a}(t)$.

Пусть в пространстве задана некоторая непрерывная кривая. При фиксированной точке отсчета $O$ каждую точку кривой можно характеризовать радиус-вектором ${\bf r}$, проведенным в эту точку из точки отсчета. Если кривая является годографом некоторой векторной функции ${\bf r}(t)$, то говорят, что задано параметрическое уравнение кривой. Запишем координатное представление вектор-функции: ${\bf r}(t) = x(t){\bf i}+y(t){\bf j}+z(t){\bf k}$, так что параметрическое задание кривой эквивалентно заданию трех функций $x(t)$, $y(t)$, $z(t)$.

Производной функции ${\bf a}(t)$ в точке $t_0$ называют предел

(1)
\begin{align} {\bf a}'(t_0) = \frac{d{\bf a}}{dt}(t_0)=\lim_{t\to t_0}\frac{{\bf a}(t)-{\bf a}(t_0)}{t-t_0} \end{align}

Если векторная функция имеет постоянную длину $|{\bf a}(t)|=\text{const}$ , то векторы ${\bf a}(t)$ и ${\bf a}'(t)$ ортогональны.

Пусть ${\bf e}(t)$ — единичный вектор в направлении ${\bf a}(t)$, так что ${\bf a}(t)=|{\bf a}(t)|{\bf e}(t)$. Дифференцируя это равенство, получаем

(2)
\begin{align} \frac{d{\bf a}}{dt}=\frac{d|{\bf a}|}{dt}{\bf e}+|{\bf a}|\frac{d{\bf e}}{dt} \end{align}

Поскольку ${\bf e}(t)$ единичный вектор, то ${\bf e}'\perp {\bf e}$, так что последнее равенство дает разложение вектора производной на вектор параллельный ${\bf a}(t)$ и перпендикулярный ему.

Длина дуги кривой определяется как предел длины вписанной в нее ломаной. Зафиксируем на линии некоторую точку $M_0$, отвечающую параметру $t_0$. Пусть точка $M$ отвечает значению параметра $t$. Длина дуги $M_0M$ равна

(3)
\begin{align} s(t) =\int\limits_{t_0}^{t} |{\bf r}'(t)|dt=\int\limits_{t_0}^{t} \sqrt{ \left[x'(t)\right]^2+\left[y'(t)\right]^2+\left[z'(t)\right]^2} dt \end{align}

При этом при $t>t_0$ длина дуги положительна, а при $t<t_0$ — отрицательна. Таким образом, зафиксировав точку $t_0$, мы можем поставить в соответствие каждой точке кривой параметр $s(t)$ — длину дуги, отсчитываемую от точки $M_0$. Дифференцируя последнее соотношение, получаем

(4)
\begin{align} \frac{ds}{dt} =|{\bf r}'(t)|=\left|\frac{d \mathbf{r}}{dt}\right| \end{align}

Если в качестве параметра в уравнении линии выбрана длина дуги, т.е. уравнение линии представлено в виде ${\bf r}={\bf r}(s)$, то говорят, что использована естественная параметризация. Удобство ее заключается в том, что

(5)
\begin{align} \left|\frac{d \mathbf{r}}{ds}\right|=1 \qquad \text{или} \qquad |d{\bf r}|=ds \end{align}

С пространственной кривой связаны такие понятия, как касательная, нормаль и бинормаль — тройка единичных векторов, образующих сопровождающий трехгранник кривой.

Пусть задана пространственная кривая и пусть $s$ — длина дуги этой кривой до точки $M$, отсчитываемая от некоторой фиксированной точки $M_0$ на линии. При этом уравнение кривой может быть записано как ${\bf r}={\bf r}(s)$. Вычислим производную $d{\bf r}/ds$ в точке $M$. Этот вектор направлен по касательной к кривой и имеет единичную длину. Вектор

(6)
\begin{align} {\bf t}=\frac{d{\bf r}}{ds}(M) \end{align}

называется вектором касательной к линии.

Плоскость, проходящая через заданную точку $M$ на кривой и перпендикулярная вектору касательной к линии в этой точке, называется нормальной плоскостью.

Построим плоскость, наиболее "пригнанную" к кривой. Рассмотрим произвольную плоскость, проходящую через заданную точку $M$. Положение плоскости будем характеризовать единичным вектором ${\bf N}$ нормали к ней. Дадим параметру $s$ приращение $\Delta s$, в результате чего мы сдвинемся по кривой из точки $M$ в точку $M'$. Вычислим расстояние $l=M'P$ от этой точки до плоскости. Поскольку расстояние до плоскости измеряется по перпендикуляру

(7)
\begin{align} l=\left({\bf r}(s+\Delta s)-{\bf r}(s),{\bf N}\right)= \left(\dot{{\bf r}}(s),{\bf N}\right)\Delta s + \frac12\left(\ddot{{\bf r}}(s),{\bf N}\right)\Delta s^2 + \dots \end{align}

где точкой обозначена производная по параметру $s$. Говорят, что кривая и плоскость имеют в точке касание $n$-го порядка, если $l=O(\Delta s^{n+1})$. В частности, если $\left(\dot{{\bf r}}(s),{\bf N}\right)\ne 0$, кривая "протыкает" плоскость — имеем касание нулевого порядка. Если $\left(\dot{{\bf r}}(s),{\bf N}\right)= 0$, то вектор касательной к линии лежит в плоскости, но плоскость может произвольно вращаться вокруг него. При этом осуществляется касание первого порядка. Наконец, среди таких плоскостей есть одна, для которой $\left({\bf r}''(s),{\bf N}\right)= 0$. Эта плоскость имеет касание второго порядка и называется соприкасающейся плоскостью. Нормаль к соприкасающейся плоскости перпендикулярна векторам $\dot{{\bf r}}$ и $\ddot{{\bf r}}$, так что она направлена по их векторному произведению.

Проведем через точку $M$ на кривой нормальную плоскость, т.е. плоскость, перпендикулярную касательной. Все единичные векторы, лежащие в этой плоскости, называются нормалями к кривой. Нормаль, лежащая в соприкасающейся плоскости, называется главной нормалью, а нормаль, перпендикулярная соприкасающейся плоскости — бинормалью. Если вектор касательной обозначить через ${\bf t}$, вектор главной нормали через ${\bf n}$, а вектор бинормали через ${\bf b}$, то тройка векторов $({\bf t}, {\bf n}, {\bf b})$ образует сопровождающий трехгранник линии в точке $M$. Найдем выражения для его векторов.

Вектор касательной равен ${\bf t}=\dot{{\bf r}}(s)$. Рассмотрим вектор $\dot{{\bf t}}(s)=\ddot{{\bf r}}(s)$. Поскольку ${\bf t}$ единичный вектор, его производная перпендикулярна ему, т.е. лежит в нормальной плоскости. Кроме того, как мы видели выше, она лежит в соприкасающейся плоскости, т.е. коллинеарна вектору главной нормали. Скорость поворота касательной как функции длины дуги называется кривизной линии, а обратная ей величина — радиусом кривизны:

(8)
\begin{align} \left|\frac{d{\bf t}}{ds}\right|=\left|\frac{d^2{\bf r}}{ds^2}\right|=\frac1R \end{align}

Отсюда вытекает определение вектора главной нормали: \nopagebreak

(9)
\begin{align} {\bf n}=R\frac{d{\bf t}}{ds} \end{align}

Вектор бинормали перпендикулярен ${\bf t}$ и ${\bf n}$ и по определению равен ${\bf b} = [{\bf t},{\bf n}]$. Производная бинормали направлена по вектору нормали:

(10)
\begin{align} \frac{d{\bf b}}{ds} = -\frac1T{\bf n} \end{align}

Величину $1/T$, характеризующую скорость поворота бинормали при движении вдоль кривой, называют кручением кривой, а $T$радиусом кручения.

Скорости изменения касательной, нормали и бинормали при движении вдоль кривой даются выражениями:

(11)
\begin{align} \frac{d{\bf t}}{ds} = \frac1R{\bf n}, \qquad \frac{d{\bf n}}{ds} =\frac1T{\bf b}-\frac1R{\bf t}, \qquad \frac{d{\bf b}}{ds} = -\frac1T{\bf n} \end{align}

Эти три обыкновенных дифференциальных уравнения называются уравнениями Френе. Они показывают, что пространственная кривая определяется зависимостями кривизны и кручения от расстояния вдоль кривой.

Описание кривой в OpenCascade

В OpenCascade описание кривой основывается на абстрактном классе Geom_Curve. Классы описания прямой, конических сечений, кривой Безье, B-сплайна и другие наследуют свойства и методы этого класса. К ним относятся:

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

Метод Value(const Standard_Real U) возвращает значение точки на кривой для заданного значения параметра. Например, построим прямую, проходящую через точку gp_Pnt(0.,0.,1.) в направлении вектора gp_Dir(1.,1.,0.) и вычислим точки на ней для значений параметра 0 и 1:

    Geom_Line geomLine(gp_Pnt(0.,0.,1.), gp_Dir(1.,1.,0.));
    gp_Pnt point;
    point = geomLine.Value(0.); // ( 0.0000, 0.0000, 1.0000 )
    point = geomLine.Value(1.); // ( 0.7071, 0.7071, 1.0000 )

Диапазон изменения параметра опрашивается процедурами FirstParameter() и LastParameter(). Прямая — бесконечная линия так что возвращаемые значения для прямой есть RealFirst() ($-\infty$) и RealLast() ($+\infty$). Но для окружности параметр изменяется от $0$ до $2\pi$:
    double parMin = geomLine.FirstParameter();  //  -2.0000000000000e+100
    double parMax = geomLine.LastParameter();   //   2.0000000000000e+100
    Geom_Circle circle(gp::XOY(), sqrt(2.));  // окружность в плоскости (X,Y)
    parMin = circle.FirstParameter();   // 0.0000
    parMax = circle.LastParameter();    // 6.2831

Методы D0, D1 … позволяют узнать значения точки и производных различного порядка для данного значения параметра. Например
    gp_Pnt point;
    gp_Vec deriv;
    double par = 3.14159/4.;
    circle.D0(par,point);       // point = ( 1.0000, 1.0000, 0.0000 )
    circle.D1(par,point,deriv); // deriv = (-1.0000, 1.0000, 0.0000 )

Для вычисления таких характеристик кривой как касательная, нормаль, кривизна нужно воспользоваться процедурами класса GeomLProp_CLProps. При создании объекта даного класса нужно указать кривую, для которой вычисляются характеристики, значение параметра, порядок производных, участвующих в вычислении характеристики и точность вычисления (чтобы избежать, например, деления на ноль). Выполним вычисления для окружности:

    Handle(Geom_Circle) circle = new Geom_Circle(gp::XOY(), 1.); // окружность в плоскости (X,Y)
    double phi = 3.14159/4.;                            // значене параметра: 45 градусов
    GeomLProp_CLProps curveProps(circle, phi, 2, 1.e-8);
    gp_Dir tang, normal;
    curveProps.Tangent(tang);      // tang = (-0.7071, 0.7071, 0.0000 )
    curveProps.Normal(normal);     // normal = (-0.7071,-0.7071, 0.0000 )
    Standard_Real curv = curveProps.Curvature();   // curv = 1.0000
    gp_Pnt center;
    curveProps.CentreOfCurvature(center);   // center = ( 0.0000, 0.0000, 0.0000 )

Класс GCPnts_AbscissaPoint предоставляет алгоритмы для вычисления точки (значения параметра) на кривой по длине дуги от заданной точки, а также для вычисления длины дуги в зависимости от параметра. Иначе говоря, методы этого класса устанавливают соответствие между параметризацией кривой и ее естественной параметризацией: $t(s)$ и $s(t)$.

Первый пример: вычисление параметра по длине дуги (для окружности)

// Окружность радиуса 5 в плоскости (x,y)
   Standard_Real radius = 5;
   Handle(Geom_Circle) cicle = new Geom_Circle(gp::XOY(),radius);
// startParam - параметр начальной тоски на кривой
   Standard_Real startParam = 0.;
   gp_Pnt point;
   cicle->D0(startParam,point);   // point = ( 5.0000, 0.0000, 0.0000 )
// abscissa - длина дуги от начальной тоски до искомой
//   Standard_Real abscissa = radius*3.14159;
   Standard_Real abscissa = radius*PI;
// abscissa is the distance along the curve from startparam
   GeomAdaptor_Curve adaptorCicle(cicle);
   GCPnts_AbscissaPoint abscissaPoint(adaptorCicle, abscissa, startParam);
   if( ! abscissaPoint.IsDone() ) {
   // Обработка ошибки
   }
   Standard_Real endParam = abscissaPoint.Parameter();
   cicle->D0(endParam,point);   // point = ( -5.0000, 0.0000, 0.0000 )

Второй пример: вычисление длины дуги по параметру (для окружности)

   startParam = 0.;
   endParam = PI;
   Standard_Real length = GCPnts_AbscissaPoint::Length(adaptorCicle, startParam, endParam);    
// length =     15.7079

Для вычисления проекции точки на кривую общего вида предназначен класс GeomAPI_ProjectPointOnCurve.
Его конструкторы выглядят так:

// Нахождение проекции точки <P> на кривую <Curve>
   GeomAPI_ProjectPointOnCurve( const gp_Pnt& P,const Handle(Geom_Curve)& Curve)

// Нахождение проекции точки <P> на участок кривой <Curve>,
// ограниченный параметрами Umin и Usup
   GeomAPI_ProjectPointOnCurve( const gp_Pnt& P, const Handle(Geom_Curve)& Curve,
      const Quantity_Parameter Umin, const Quantity_Parameter Usup)

Создав объект класса GeomAPI_ProjectPointOnCurve, можно опросить:
  • число проекций
// Процедура возвращает число найденных проекций.
// Если проекции не найдены, возвращается 0
   Standard_Integer NbPoints()
  • точку проекции или параметр на кривой, соответствующий этой точке, а также расстояние до проекции
// Процедура возвращает точку проекции номер Index
// Значение Index должно лежать в диапазоне от 1 до NbPoints
   gp_Pnt Point(const Standard_Integer Index)

// Процедура возвращает параметр на кривой, отвечающий точке проекции номер Index
   Quantity_Parameter Parameter(const Standard_Integer Index)

// Процедура возвращает расстояние от проектируемой точки до точки проекции номер Index
   Quantity_Length Distance(const Standard_Integer Index)
  • ближайшую точку проекции, т.е. точку с минимальным расстоянием
// Процедура возвращает ближайшую точку проекции
   gp_Pnt NearestPoint()

// Процедура возвращает параметр на кривой, отвечающий ближайшей точке проекции
   Quantity_Parameter LowerDistanceParameter()

// Процедура возвращает минимальное расстояние от проектируемой точки до кривой
   Quantity_Length LowerDistance()

Класс ElCLib provides functions for basic geometric computations on elementary curves such as conics and lines in 2D and 3D space.