问题:
如果有这样的场景:已知一条B样条曲线,已知曲线上一个点,求过这个点的曲线的切线或法线,在OpenCasCade中如何解决?
局限性
实际上,上述求解是不存在的,或者说直接获得过这个点的曲线的法向或切向量的方法是没有的,原因之一可能是安全性考虑,比如所给点不在曲线上?虽然用户可能说我这个点就在曲线上,但是参数化的曲线可不管你怎么说。
在OpenCasCade中,要获得一条参数曲线的某个位置的法向或切向量,只能通过这个位置的参数u来实现。既然这样,那有没有什么办法可以先获得这个点的参数u,然后再将这个参数u作为自变量传递给曲线进行计算这个位置的法向或且想?
可行方法
OpenCasCade中有内置的功能是将某个点投射到曲线上,相关的类为
GeomAPI_ProjectPointOnCurve
实际上是找这个点到这条曲线上哪个点能获得最小距离或最大距离,能够获得投射点的坐标和其他变量,包括这个点的参数u。通过这个u就可以重新计算这个点的坐标(算是一种修正吧)和这个点的切向量。
实例
下图所示为一条分段Bezier曲线,白色点为各个控制点,需要在第三个控制点上画一条曲线的切线。虽然这个控制点一定在曲线上,但是参数型的曲线并不能确定某个点是否一定在曲线上或者有多大的误差。此时可以将该点投影到曲线上,获得曲线上最近的点和最远的点,如果添加一条判断语句,比如投影点与原点距离小于某个极小值,就可筛选出该点,同时可以获得该点对应的参数u。示意图如下所示:
AIS_ListOfInteractive aList; myAISContext->DisplayedObjects(aList); AIS_ListIteratorOfListOfInteractive aListIterator; for(aListIterator.Initialize(aList);aListIterator.More();aListIterator.Next()){ myAISContext->Remove (aListIterator.Value(), Standard_False); } TColgp_Array1OfPnt Poles(1,9); Poles.SetValue(1, gp_Pnt(0,-10,0)); Poles.SetValue(2, gp_Pnt(0,-10,5)); Poles.SetValue(3, gp_Pnt(0,-5,5)); Poles.SetValue(4, gp_Pnt(0,0,5)); Poles.SetValue(5, gp_Pnt(0,0,0)); Poles.SetValue(6, gp_Pnt(0,0,-5)); Poles.SetValue(7, gp_Pnt(0,5,-5)); Poles.SetValue(8, gp_Pnt(0,10,-5)); Poles.SetValue(9, gp_Pnt(0,10,0)); TColStd_Array1OfReal PolesWeight(1,9); PolesWeight.SetValue(1, 1.0); PolesWeight.SetValue(2, 0.707); PolesWeight.SetValue(3, 1.0); PolesWeight.SetValue(4, 0.707); PolesWeight.SetValue(5, 1.0); PolesWeight.SetValue(6, 0.707); PolesWeight.SetValue(7, 1.0); PolesWeight.SetValue(8, 0.707); PolesWeight.SetValue(9, 1.0); for(int i=0; i<9; ++i) { TopoDS_Vertex aVertex = BRepBuilderAPI_MakeVertex(Poles.Value(i+1)); Handle(AIS_Shape) vert = new AIS_Shape(aVertex); myAISContext->SetColor(vert,Quantity_NOC_WHITE,Standard_False); myAISContext->Display(vert,Standard_False); } Fit(); Standard_Integer curtype = 3; if(curtype == 1) { } else if(curtype == 2) { } else if(curtype == 3) { /// 分段Bezier曲线 Standard_Integer degree(2); Standard_Integer PNum = 9; Standard_Integer KNum = PNum - 4; TColStd_Array1OfReal knots(1,KNum); for(int i=0; i<KNum; ++i) { knots.SetValue(i+1, i); } TColStd_Array1OfInteger mults(1,KNum); for(int i=0; i<KNum; ++i) { if(i == 0 || i == KNum-1) { mults.SetValue(i+1, degree+1); } else { mults.SetValue(i+1, degree); } } Handle(Geom_BSplineCurve) curve = new Geom_BSplineCurve(Poles, knots, mults, degree); TopoDS_Edge ed1 = BRepBuilderAPI_MakeEdge(curve); TopoDS_Wire wr1 = BRepBuilderAPI_MakeWire(ed1); Handle(AIS_Shape) red = new AIS_Shape(wr1); myAISContext->SetColor(red,Quantity_NOC_RED,Standard_False); myAISContext->Display(red,Standard_False); Fit(); gp_Pnt N, Q, P(0, -5, 5); gp_Pnt PntOnCurve; Standard_Real distance; Standard_Real param_u; GeomAPI_ProjectPointOnCurve PPC(P, curve); N = PPC.NearestPoint(); Standard_Integer NbResults = PPC.NbPoints(); if(NbResults > 0) { for(Standard_Integer i=1; i<NbResults+1; ++i) { Q = PPC.Point(i); distance = PPC.Distance(i); Standard_Real u = PPC.Parameter(i); std::cout << "projected point:" << Q.X() << " " << Q.Y() << " " << Q.Z() << std::endl; std::cout << "distance:" << distance << std::endl; std::cout << "parameter:" << u << std::endl; if(distance < 1E-12) { PntOnCurve.SetCoord(Q.X(), Q.Y(), Q.Z()); param_u = u; } } } std::cout << "projected point:" << PntOnCurve.X() << " " << PntOnCurve.Y() << " " << PntOnCurve.Z() << std::endl; gp_Vec tang; curve->D1(param_u, P, tang); Handle(ISession_Direction) aDirection1 = new ISession_Direction(P,tang); myAISContext->Display(aDirection1, Standard_False); } else { }
————————————————
版权声明:本文为CSDN博主「求仁得仁AAA」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/DaGeYong/article/details/81483538