RU: B-Spline Surface

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

B-сплайн поверхность

Напомним (см. B-сплайн}, что B-сплайн кривая, построенная с помощью B-сплайнов $n$-ой степени по опорным точкам $\{\mathbf{r}_i\}$, $0 \leq i \leq M$ на сетке $\{t_i\}$, $0 \leq i \leq n+M+1$ (число узлов сетки на $n+1$ больше, чем число опорных точек) имеет вид:

(1)
\begin{align} \mathbf{r}(t) = \sum_{i=0}^M N_{i}^{(n)}(t)\mathbf{r}_{i} \end{align}

где параметр $t$ лежит в диапазоне $t_n \leq t \leq t_{M+1}$. Рациональной $B$-кривой или NURBS (NonUniform Rational B-Spline) называется кривая вида

(2)
\begin{align} {\bf r}(t)=\frac{\sum_{i=0}^{M}w_{i}N_i^{(n)}(t){\bf r}_i} {\sum_{i=0}^{M}w_{i}N_i^{(n)}(t)} \end{align}

Рациональная кривая есть отношение двух обычных кривых B-кривых: числитель строится по опорным точкам $w_i\mathbf{r}_i$, а знаменатель по весовым коэффициентам $w_i$. В случае одинаковых весовых коэффициентов NURBS превращается в обычную B-кривую. Весовые коэффициенты дают дополнительные степени свободы для изменения поведения кривой: увеличивая вес вы приближаете кривую к опорной точке.

B-сплайн поверхность строится на прямоугольной сетке $(u_i,v_j)$ в области изменения параметров. Пусть $n_u$ и $n_v$ — степени B-сплайнов в соответствующих направлениях, $\mathbf{r}_{ij}$ — набор опорных точек, $0 \leq i \leq M_u$, $0 \leq j \leq M_v$. $w_{ij}$ — набор весовых коэффициентов. Уравнение поверхности имеет вид

(3)
\begin{align} \mathbf{r}(u,v) = \frac{\sum_{i=0}^{M_u}\sum_{j=0}^{M_v}w_{i}N_i^{(n_u)}(u)N_j^{(n_v)}(v){\bf r}_{ij}} {\sum_{i=0}^{M_u}\sum_{j=0}^{M_v}w_{i}N_i^{(n_u)}(u)N_j^{(n_v)}(v)} \end{align}

Класс Geom_BSplineSurface

Класс предназначен для описания B-сплайн поверхности на основе прямоугольной сетки в области параметров.
B-сплайн поверхность определяется

  • степенью B-сплайнов (UDegree, VDegree) по $u$ и $v$ направлениям. Эти значения ограничены числом 25 (MaxDegree);
  • одномерными массивами узлов (UKnots, VKnots) сетки параметров и их кратностей (UMults, VMults). Длины массивов узлов и кратностей должны совпадать;
  • Двумерным массивом опорных точек (poles). Рациональная поверхность определяется также массивом весов (weights).

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

Для непериодической в направлении $u$ B-сплайн поверхности число столбцов (первый индекс) двумерного массива опорных точек должно быть не меньше двух и равняться Sum(UMults) - UDegree - 1, где Sum(UMults) — сумма кратностей узлов $u$-направления. Для периодической в данном направлении поверхности кратности первого и последнего узлов должны совпадать, а число опорных точек равняться сумме кратностей (кратность последнего узла не учитывается). То же справедливо и для $v$-направления.

В качестве примера, построим B-сплайн поверхность, "сглаживающую" угол кубика (см. Поверхность Безье, где по этим же опорным точкам построена поверхность Безье). Двумерный массив опорных точек имеет размер $5 \times 3$, Степень B-сплайн в $u$-направлении возьмем равной трем. При этом сумма кратностей узлов должна равняться девяти. Чтобы B-сплайн проходил через крайние опорные точки, кратность крайних уздов должна равняться четырем. Поэтому в сетке возьмем три узла с кратностью внутреннего узла равной единице. Степень B-сплайна в $v$-направлении возьмем равной двум. При этом сумма кратностей узлов должна равняться шести. Чтобы B-сплайн проходил через крайние опорные точки, кратность крайних уздов должна равняться трем, так что сетка в $v$-направлении будет состоять из двух узлов (см. также пример в B-сплайн). Построенная таким образом поверхность представлена на рисунке, где для наглядности отображены также опорные точки и линии (пунктиром) их соединяющие.

// Двумерный массив опорных точек
   TColgp_Array2OfPnt points(1,5,1,3);
   points.SetValue(1,1,gp_Pnt(1.,-1.,0.));
   points.SetValue(1,2,gp_Pnt(1.,-1.,1.));
   points.SetValue(1,3,gp_Pnt(0.,-1.,1.));
   points.SetValue(2,1,gp_Pnt(1.,0.,0.));
   points.SetValue(2,2,gp_Pnt(1.,0.,1.));
   points.SetValue(2,3,gp_Pnt(0.,0.,1.));
   points.SetValue(3,1,gp_Pnt(1.,1.,0.));
   points.SetValue(3,2,gp_Pnt(1.,1.,1.));
   points.SetValue(3,3,gp_Pnt(0.,0.,1.));
   points.SetValue(3,3,gp_Pnt(0.,0.,1.));
   points.SetValue(4,1,gp_Pnt(0.,1.,0.));
   points.SetValue(4,2,gp_Pnt(0.,1.,1.));
   points.SetValue(4,3,gp_Pnt(0.,0.,1.));
   points.SetValue(5,1,gp_Pnt(-1.,1.,0.));
   points.SetValue(5,2,gp_Pnt(-1.,1.,1.));
   points.SetValue(5,3,gp_Pnt(-1.,0.,1.));
//
// Параметры в u-направлении
   Standard_Integer uDegree = 3;
   TColStd_Array1OfReal uKnots(1,3);
   TColStd_Array1OfInteger uMults(1,3);
   uKnots.SetValue(1,0.);
   uKnots.SetValue(2,1.);
   uKnots.SetValue(3,2.);
   uMults.SetValue(1,4);
   uMults.SetValue(2,1);
   uMults.SetValue(3,4);
//
// Параметры в v-направлении
   Standard_Integer vDegree = 2;
   TColStd_Array1OfReal vKnots(1,2);
   TColStd_Array1OfInteger vMults(1,2);
   vKnots.SetValue(1,0.);
   vKnots.SetValue(2,1.);
   vMults.SetValue(1,3);
   vMults.SetValue(2,3);
//
// Создаем поверхность
   Handle(Geom_BSplineSurface) surface = 
    new Geom_BSplineSurface(points, uKnots, vKnots, 
    uMults, vMults, uDegree, vDegree);
OCC_SurfBSpline.jpg

Построение участка поверхности по граничным кривым

Обсудим способы построения участка (patch) B-сплайн поверхности по граничным кривым. Начнем со следующей ситуации. Пусть заданы четыре кривые Безье $\mathbf{r}_1(t)$, $\mathbf{r}_2(t)$, $\mathbf{r}_3(t)$, $\mathbf{r}_4(t)$ с совпадающими конечным точками. Обратим внимание, что в данной ситуации фактически речь идет об интерполяции опорных точек с границы внутрь области параметров.

Для построения участка B-сплайн поверхности в OpenCascade предназначены процедуры класса GeomFill_BSplineCurves, конструктор которого имеет вид:

    GeomFill_BSplineCurves::GeomFill_BSplineCurves (
        const Handle(Geom_BSplineCurve)& C1, const Handle(Geom_BSplineCurve)& C2, 
        const Handle(Geom_BSplineCurve)& C3, const Handle(Geom_BSplineCurve)& C4, 
        const GeomFill_FillingStyle Type      )

Здесь параметр Type принадлежит перечисляемому типу GeomFill_FillingStyle и может прнимать значения:
GeomFill_StretchStyle, GeomFill_CoonsStyle, GeomFill_CurvedStyle. Эти значения определяют алгоритмы построения интерполяции (см. Интерполяционные поверхности и Поверхность Безье).
В качестве примера возьмем четыре граничные B-кривые из указанных выше опорных точек:
// Поверхность по четырем кривым
   Handle( Geom_BSplineCurve ) curve[4];
    TColgp_Array1OfPnt pointsVCurve(1,3);
    TColgp_Array1OfPnt pointsUCurve(1,5);
    for( i=1; i<=5; i++ )
        pointsUCurve.SetValue(i,points.Value(i,1));
   curve[0] = new Geom_BSplineCurve (pointsUCurve, uKnots, uMults, uDegree);
    for( i=1; i<=5; i++ )
        pointsUCurve.SetValue(i,points.Value(i,3));
   curve[1] = new Geom_BSplineCurve (pointsUCurve, uKnots, uMults, uDegree);
    for( i=1; i<=3; i++ )
        pointsVCurve.SetValue(i,points.Value(1,i));
   curve[2] = new Geom_BSplineCurve (pointsVCurve, vKnots, vMults, vDegree);
    for( i=1; i<=3; i++ )
        pointsVCurve.SetValue(i,points.Value(5,i));
   curve[3] = new Geom_BSplineCurve (pointsVCurve, vKnots, vMults, vDegree);

Построение интерполяционной поверхности выглядит так (во втором случае степень граничных кривых необходимо увеличить):
    GeomFill_BSplineCurves geomFill;
    geomFill.Init(curve[0], curve[1], curve[2], curve[3],GeomFill_StretchStyle);
//    curve[2]->IncreaseDegree(3);
//    curve[3]->IncreaseDegree(3);
//    geomFill.Init(curve[0], curve[1], curve[2], curve[3],GeomFill_CoonsStyle);
//    geomFill.Init(curve[0], curve[1], curve[2], curve[3],GeomFill_CurvedStyle);
     Handle(Geom_BSplineSurface) surface = geomFill.Surface();

На представленных ниже рисунках показаны результаты интерполяции в указанном порядке. Ради наглядности проведены линии, соединяющие опорные точки.
OCC_SurfBSpline01.jpg OCC_SurfBSpline02.jpg OCC_SurfBSpline03.jpg

У класса GeomFill_BSplineCurves имеются возможности построения интерполяционной поверхности по трем и двум граничным кривым:

    GeomFill_BSplineCurves::GeomFill_BSplineCurves (
        const Handle(Geom_BSplineCurve)& C1, const Handle(Geom_BSplineCurve)& C2, 
        const Handle(Geom_BSplineCurve)& C3, 
        const GeomFill_FillingStyle Type      )
    GeomFill_BSplineCurves::GeomFill_BSplineCurves (
        const Handle(Geom_BSplineCurve)& C1, const Handle(Geom_BSplineCurve)& C2, 
        const GeomFill_FillingStyle Type      )

но эти ситуации приводятся к случаю четырех кривых путем добавления линейных участков границы.