NURBS样条曲线学习

搞3D几何内核算法研究,必须学习NURBS样条曲线曲面。

看《非均匀有理B样条  第2版》这本书,学习起来,事半功倍。

在《插件化算法研究平台》上,做了一个样条曲线研究功能,可以分析Bezier曲线、BSpline、NURBS曲线的各种性质,有直观的体验,能更好地理解。

一、基函数

参考示例代码:

// 计算基函数值
    double basis(int i, int k, double u) {
        if (k == 0) {
            if (u >= knots[i] && u < knots[i + 1]) {
                return 1.0;
            }
            return 0.0;
        }
        double a = 0.0, b = 0.0;
        if (knots[i + k] - knots[i] != 0.0) {
            a = (u - knots[i]) / (knots[i + k] - knots[i]);
        }
        if (knots[i + k + 1] - knots[i + 1] != 0.0) {
            b = (knots[i + k + 1] - u) / (knots[i + k + 1] - knots[i + 1]);
        }
        return a * basis(i, k - 1, u) + b * basis(i + 1, k - 1, u);
    }

二、B样条曲线

参考示例代码:

// 计算样条曲线上的点
   virtual Point3  calculatePoint(double u) {
        auto size = controlPoints3d.size();
        Point3 result;
        for (size_t i = 0; i < size; i++) {
            double factor = basis(i, degree, u) ;
            result.x += factor * controlPoints3d[i].x;
            result.y += factor * controlPoints3d[i].y;
            result.z += factor * controlPoints3d[i].z;
        }
        return result;
    }

三、NURBS曲线

参考示例代码:

 // 计算样条曲线上的点
    Point3  calculatePoint(double u)override
    {
        auto size = controlPoints3d.size();
        Point3 result;
        double denominator = 0.0;
        for (size_t i = 0; i < size; i++) {
            double factor = basis(i, degree, u) * weights[i];
            denominator += factor;
            result.x += factor * controlPoints3d[i].x;
            result.y += factor * controlPoints3d[i].y;
            result.z += factor * controlPoints3d[i].z;
        }
        result.x /= denominator;
        result.y /= denominator;
        result.z /= denominator;
        return result;
    }

四、程序效果

Bezier曲线

BSpline曲线

其中,Degree对曲线的影响,当Degree=1时,就成了线性插值。

NURBS曲线

     

权重对曲线的影响。

四、基于OCCT几何内核生成的样条曲线示例

参考示例代码:

//BSpline Bezier  Curve
void makeCurve(OccView* view)
{
    myObject3d.Clear();
    // Define points.
    gp_Pnt aPnt1(0.0, 0.0, 0.0);
    gp_Pnt aPnt2(5.0, 5.0, 0.0);
    gp_Pnt aPnt3(10.0, 5.0, 0.0);
    gp_Pnt aPnt4(15.0, 0.0, 5.0);

    // Add points to the curve poles array.
    TColgp_Array1OfPnt aPoles(1, 4);
    aPoles.SetValue(1, aPnt1);
    aPoles.SetValue(2, aPnt2);
    aPoles.SetValue(3, aPnt3);
    aPoles.SetValue(4, aPnt4);

    // Define BSpline weights.
    TColStd_Array1OfReal aBSplineWeights(1, 4);
    aBSplineWeights.SetValue(1, 1.0);
    aBSplineWeights.SetValue(2, 0.5);
    aBSplineWeights.SetValue(3, 0.5);
    aBSplineWeights.SetValue(4, 1.0);

    // Define knots.
    TColStd_Array1OfReal aKnots(1, 2);
    aKnots.SetValue(1, 0.0);
    aKnots.SetValue(2, 1.0);

    // Define multiplicities.
    TColStd_Array1OfInteger aMults(1, 2);
    aMults.SetValue(1, 4);
    aMults.SetValue(2, 4);

    // Define BSpline degree and periodicity.
    Standard_Integer aDegree = 3;
    Standard_Boolean aPeriodic = Standard_False;

    // Create a BSpline curve.
    Handle(Geom_BSplineCurve) aBSplineCurve = new Geom_BSplineCurve(
        aPoles, aBSplineWeights, aKnots, aMults, aDegree, aPeriodic);

    Handle(AIS_ColoredShape) anAisBSplineCurve = new AIS_ColoredShape(
        BRepBuilderAPI_MakeEdge(aBSplineCurve).Shape());
    anAisBSplineCurve->SetColor(Quantity_Color(Quantity_NOC_IVORY));

    // Compute BSpline surface bounding box.
    Bnd_Box aBndBox;
    BndLib_Add3dCurve::AddOptimal(GeomAdaptor_Curve(aBSplineCurve), Precision::Confusion(), aBndBox);
    Handle(AIS_ColoredShape) anAisBndBox = new AIS_ColoredShape(
        BRepPrimAPI_MakeBox(aBndBox.CornerMin(), aBndBox.CornerMax()).Shell());
    view->aisInterContext->SetDisplayMode(anAisBndBox, 0, false);
    myObject3d.Append(anAisBndBox);

    NCollection_List<Standard_Real> aParams;
    aParams.Append(0.75 * aBSplineCurve->FirstParameter() + 0.25 * aBSplineCurve->LastParameter());
    aParams.Append(0.50 * aBSplineCurve->FirstParameter() + 0.50 * aBSplineCurve->LastParameter());
    aParams.Append(0.25 * aBSplineCurve->FirstParameter() + 0.75 * aBSplineCurve->LastParameter());
    for (NCollection_List<Standard_Real>::Iterator anIt(aParams); anIt.More(); anIt.Next())
    {
        Standard_Real aParam = anIt.Value();
        gp_Pnt aPnt;
        gp_Vec aVec;
        aBSplineCurve->D1(aParam, aPnt, aVec);
        myObject3d.Append(new AIS_Point(new Geom_CartesianPoint(aPnt)));
        Handle(AIS_TextLabel) aisLabel = new AIS_TextLabel();
        Standard_SStream aSS;
        aSS << "P [" << aPnt.X() << ", " << aPnt.Y() << ", " << aPnt.Z() << "]" << std::endl;
        aSS << "D [" << aVec.X() << ", " << aVec.Y() << ", " << aVec.Z() << "]" << std::endl;
        aisLabel->SetHeight(fontHeight);
        aisLabel->SetText(aSS.str().c_str());
        aisLabel->SetPosition(aPnt);
        myObject3d.Append(aisLabel);
        Handle(AIS_Axis) anAisD = new AIS_Axis(new Geom_Axis1Placement(gp_Ax1(aPnt, aVec)));
        myObject3d.Append(anAisD);
    }


    // Define Bezier weights.
    TColStd_Array1OfReal aBezierWeights(1, 4);
    aBezierWeights.SetValue(1, 0.5);
    aBezierWeights.SetValue(2, 1.5);
    aBezierWeights.SetValue(3, 1.5);
    aBezierWeights.SetValue(4, 0.5);

    // Create Bezier curve.
    Handle(Geom_BezierCurve) aBezierCurve = new Geom_BezierCurve(aPoles, aBezierWeights);
    Handle(AIS_ColoredShape) anAisBezierCurve = new AIS_ColoredShape(BRepBuilderAPI_MakeEdge(aBezierCurve).Shape());
    anAisBezierCurve->SetColor(Quantity_Color(Quantity_NOC_BLUE));


    myObject3d.Append(anAisBSplineCurve);
    myObject3d.Append(anAisBezierCurve);
    myObject3d.Append(new AIS_Point(new Geom_CartesianPoint(aPnt1)));
    myObject3d.Append(new AIS_Point(new Geom_CartesianPoint(aPnt2)));
    myObject3d.Append(new AIS_Point(new Geom_CartesianPoint(aPnt3)));
    myObject3d.Append(new AIS_Point(new Geom_CartesianPoint(aPnt4)));

    Handle(AIS_TextLabel) aisBSplineLabel = new AIS_TextLabel();
    aisBSplineLabel->SetHeight(fontHeight);
    aisBSplineLabel->SetText("BSpline edge");
    aisBSplineLabel->SetPosition(aPnt4);
    aisBSplineLabel->SetColor(Quantity_Color(Quantity_NOC_IVORY));
    myObject3d.Append(aisBSplineLabel);

    Handle(AIS_TextLabel) aisLabel = new AIS_TextLabel();
    aisLabel->SetHeight(fontHeight);
    aisLabel->SetText("Bezier edge");
    aisLabel->SetPosition(aPnt3);
    aisLabel->SetColor(Quantity_Color(Quantity_NOC_BLUE));
    myObject3d.Append(aisLabel);

    gp_Ax2 anAxis2(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0));
    // Describes a parabola 抛物线 in 3D space. A parabola is defined by its focal length
  // (that is, the distance between its focus and apex) and positioned in space with
  // a coordinate system (a gp_Ax2 object)
    gp_Parab aParab(anAxis2.Translated(gp_Vec(0.0, 0.0, 20.0)), 2.0);
    Handle(Geom_Parabola) aGeomParabola = new Geom_Parabola(aParab);
    Handle(Geom_TrimmedCurve) aTrimmedParabola = new Geom_TrimmedCurve(aGeomParabola, 20.0, -20.0);
    Handle(AIS_ColoredShape) anAisParabola = new AIS_ColoredShape(BRepBuilderAPI_MakeEdge(aTrimmedParabola));
    myObject3d.Append(anAisParabola);

    // Describes a branch of a hyperbola 双曲线 in 3D space. A hyperbola is defined by its major
    // and minor radii and positioned in space with a coordinate system (a gp_Ax2 object)
    gp_Hypr aHypr(anAxis2.Translated(gp_Vec(0.0, 0.0, 30.0)), 20.0, 10.0);
    Handle(Geom_Hyperbola) aGeomHyperbola = new Geom_Hyperbola(aHypr);
    Handle(Geom_TrimmedCurve) aTrimmedHyperbola = new Geom_TrimmedCurve(aGeomHyperbola, 2.0, -2.0);
    Handle(AIS_ColoredShape) anAisHyperbola = new AIS_ColoredShape(BRepBuilderAPI_MakeEdge(aTrimmedHyperbola));
    myObject3d.Append(anAisHyperbola);

    auto context = view->getContext();
    NCollection_Vector<Handle(AIS_InteractiveObject)>::iterator it = myObject3d.begin();
    for (; it != myObject3d.end(); it++)
    {
        context->Display(*it, Standard_False);
    }
    view->fitAll();
}

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值