转发并翻译一篇外国人写的关于利用 GeomFill_Pipe() 类构造管形结构的文章,这篇文章表现出来的技术、逻辑和对OpenCasCade的理解,都是非常值得学习的。文章原网址http://quaoar.su/blog/page/postroenie-trubki-po-dvum-sechenijam
需求:沿着给定轨迹通过入口、出口两个截面构造管道结构,如下图所示:
这个操作看起来很简单,开发人员可能会这样写代码:
// Construct path.
TColgp_Array1OfPnt pathPoles (1, 3);
pathPoles (1) = gp_Pnt (0, 0, 0);
pathPoles (2) = gp_Pnt (100, 0, 0);
pathPoles (3) = gp_Pnt (100, 100, 0);
//
Handle (Geom_BezierCurve) path = new Geom_BezierCurve (pathPoles);
// Construct sections.
Handle (Geom_Curve) c1 = new Geom_Circle (gp_Ax2 (gp_Pnt (0, 0, 0), gp :: DX ()), 10.0);
Handle (Geom_Curve) c2 = new Geom_Circle (gp_Ax2 (gp_Pnt (100, 100, 0), gp :: DY ()), 20.0);
// Make pipe.
GeomFill_Pipe Pipe (path, c1, c2);
Pipe.Perform ();
// Get the result.
const Handle (Geom_Surface) & result = Pipe.Surface ();
上述代码分别创建了 1. 中心线,2. 入口、出口,3. GeomFill_Pipe对象,并用 Pipe.Surface() 获取到生成的曲面。但是执行上述代码发生如下图所示的错误:
抛出的错误类型是:Standard_ConstructionError,表示构造失败,说明GeomFill_Pipe类构造函数中的参数不正确,为此将入口和出口截面曲线修改为非周期性的曲线(原文在这儿说明了一些原因,但感觉不是非常有说服力)
Handle(Geom_Curve)
c1 = new Geom_TrimmedCurve(new Geom_Circle(gp_Ax2(gp_Pnt(0,0,0),gp :: DX()),10.0),0,2 * M_PI);
//
Handle(Geom_Curve)
c2 = new Geom_TrimmedCurve(new Geom_Circle(gp_Ax2(gp_Pnt(100,100,0),gp :: DY()),20.0),0,2 * M_PI);
Geom_TrimmedCurve() 类对参数中的曲线按照参数进行修剪,消除曲线的周期性。通过这样的操作,Standard_ConstructionError消失了,获取到了“一些”结果,如下图所示:
可以看到,构造出来的管道在中间存在干涉。错误原因在于,入口、出口两条截面的位置和反向并不是随便放置的,每个截面的方向都需要与入口处中心线的切向平行,对于本例,这个方向是 (1,0,0),也就是 gp::DX()。修改原代码,重新绘制管道,获得的结果如下图所示:
仍然有点问题,管道的出口没有通过制定的出口截面。
原因在于,在上述将圆进行修剪之后,截面变得“不合理”,导致在构造管道的时候拟合出来的曲面没有通过截面。所以,需要将截面曲线重新转换为B样条曲线(原文的意思,还是有点不太明白),即:
Handle (Geom_Curve)
c1 = GeomConvert :: CurveToBSplineCurve (new Geom_TrimmedCurve (new Geom_Circle (gp_Ax2 (gp :: Origin (), gp :: DX ()), 10.0), 0, 2 * M_PI), Convert_Polynomial);
//
Handle (Geom_Curve)
c2 = GeomConvert :: CurveToBSplineCurve (new Geom_TrimmedCurve (new Geom_Circle (gp_Ax2 (gp :: Origin (), gp :: DX ()), 20.0), 0, 2 * M_PI), Convert_Polynomial);
最终,获取到了正确的管道曲面模型,如下图所示。
最终的“正确”代码如下图所示:
// Construct path.
TColgp_Array1OfPnt pathPoles (1, 3);
pathPoles (1) = gp_Pnt (0, 0, 0);
pathPoles (2) = gp_Pnt (100, 0, 0);
pathPoles (3) = gp_Pnt (100, 100, 0);
//
Handle (Geom_BezierCurve) path = new Geom_BezierCurve (pathPoles);
// Construct sections.
Handle (Geom_Curve)
c1 = GeomConvert :: CurveToBSplineCurve (new Geom_TrimmedCurve (new Geom_Circle (gp_Ax2 (gp :: Origin (), gp :: DX ()), 10.0), 0, 2 * M_PI), Convert_Polynomial);
//
Handle (Geom_Curve)
c2 = GeomConvert :: CurveToBSplineCurve (new Geom_TrimmedCurve (new Geom_Circle (gp_Ax2 (gp :: Origin (), gp :: DX ()), 20.0), 0, 2 * M_PI), Convert_Polynomial);
// Make pipe.
GeomFill_Pipe Pipe (path, c1, c2);
Pipe.Perform ();
// Get the result.
const Handle (Geom_Surface) & result = Pipe.Surface ();