天天看点

【第三回】使用OCCT做类似AutoCAD的拉伸功能(Extrude)

        这几周真心把我给累到了,突如其来一下子要接收消化那么多新的知识,工作上面要用到的还有我自己感兴趣研究的,基本上周末都没得休息

【第三回】使用OCCT做类似AutoCAD的拉伸功能(Extrude)

。不过努力就有收获,这几周没白忙活,工作上面对OCCT的使用已经摸出了点门道。

        AutoCAD中的拉伸功能有这几个限制:待拉伸的模型不可以是自相交的(self-intersecting),拉伸出来的模型也不可是自相交的。AutoCAD在基于这两个限制上可对线段,多段线以及面进行拉伸。拉伸可以沿方向(Direction),路径(Path)和锥角(Taper Angle)进行。而在OCCT中它并没有针对拉伸等这些业务层级别的功能进行封装实现,要实现沿方向,路径和锥角进行拉伸,需要用到BRepPrimAPI_MakePrism(沿方向拉伸),BRepOffsetAPI_MakePipe(沿路径拉伸)和BRepOffsetAPI_DraftAngle(根据锥角使模型产生形变)。由于OCCT所有实现的功能都是功能级别上的,这几个类所实现的拉伸的效果是没有AutoCAD中的这几个限制的。下面贴出这几个类的使用示例:

BRepPrimAPI_MakePrism(沿方向拉伸):

TopoDS_Shape makeExtrude(const TopoDS_Shape& oriShape, const gp_Vec& dir)
{
	TopoDS_Shape rstShape;
	try
	{
		TopoDS_Shape oriShape1 = oriShape;
		if (oriShape1.ShapeType() == TopAbs_WIRE)
			oriShape1 = BRepBuilderAPI_MakeFace(TopoDS::Wire(oriShape1));

		rstShape = BRepPrimAPI_MakePrism(oriShape1, dir);
	}
	catch (const Standard_Failure& err)
	{
		std::cout<<"\nStandard_Failure: "<<err.GetMessageString();
	}
	catch (...)
	{
		std::cout<<"\nBRepPrimAPI_MakePrism some unknown errors occur";
	}

	return rstShape;
}
           

BRepOffsetAPI_MakePipe(沿路径拉伸):

TopoDS_Shape makeExtrude(const TopoDS_Shape& oriShape)
{
	Handle(Geom_TrimmedCurve) arc = GC_MakeArcOfCircle(gp_Pnt(0, 0, 0), gp_Pnt(10, 10, 0), gp_Pnt(0, 20, 0));
	Handle(Geom_TrimmedCurve) arc2 = GC_MakeArcOfCircle(gp_Pnt(0, 20, 0), gp_Pnt(-10, 30, 0), gp_Pnt(0, 40, 0));
	Handle(Geom_TrimmedCurve) seg = GC_MakeSegment(gp_Pnt(0, 40, 0), gp_Pnt(20, 40, 0));
	Handle(Geom_TrimmedCurve) seg1 = GC_MakeSegment(gp_Pnt(20, 40, 0), gp_Pnt(20, 60, 0));
	TopoDS_Edge arcEdge = BRepBuilderAPI_MakeEdge(arc);
	TopoDS_Edge arcEdge1 = BRepBuilderAPI_MakeEdge(arc2);
	TopoDS_Edge segEdge = BRepBuilderAPI_MakeEdge(seg);
	TopoDS_Edge segEdge1 = BRepBuilderAPI_MakeEdge(seg1);
	TopoDS_Wire arcWire = BRepBuilderAPI_MakeWire(arcEdge, arcEdge1, segEdge/*, segEdge1*/); //return arcWire;

	TopoDS_Shape rstShape;
	try
	{
		rstShape = BRepOffsetAPI_MakePipe(arcWire, oriShape);
	}
	catch (const Standard_Failure& err)
	{
		std::cout<<"\nStandard_Failure: "<<err.GetMessageString();
	}
	catch (...)
	{
		std::cout<<"\nBRepOffsetAPI_MakePipe some unknown error occur";
	}

	return rstShape;
}
           

其中这两个类的拉伸规则如下:

【第三回】使用OCCT做类似AutoCAD的拉伸功能(Extrude)

还有一个类BRepOffsetAPI_MakePipeShell只能对线框以下的模型进行拉伸,即它最高只能拉伸出shell,而它相对于BRepOffsetAPI_MakePipe有一个较灵活的地方是:它提供了几个方法:

BRepOffsetAPI_MakePipeShell::Add

BRepOffsetAPI_MakePipeShell::SetMode

void BRepOffsetAPI_MakePipeShell::Add	(	const TopoDS_Shape & 	Profile,
const Standard_Boolean 	WithContact = Standard_False,
const Standard_Boolean 	WithCorrection = Standard_False 
)	
           
void BRepOffsetAPI_MakePipeShell::SetMode  ( const gp_Dir &  BiNormal ) 
           

第一个方法里面有一个参数WithCorrection,当为true时,那么它在做拉伸时,拉伸的面的法向会校正为拉伸路径曲线的切线方向,当为false时,拉伸的面的法向会保持原有的法向不变;第二个方法是设置拉伸面的固定法向,也就是说在拉伸的过程中拉伸面的法向始终保持BiNormal不变。这两个方法不能同时使用!

而BRepOffsetAPI_MakePipe在拉伸的过程是是保持原有的拉伸面的法向不变,这个特征满足AutoCAD中拉伸功能的特征!

还有一个BRepOffsetAPI_DraftAngle(根据锥角使模型产生形变)的示例:

TopoDS_Shape S = BRepPrimAPI_MakeBox(200.,300.,150.);
	BRepOffsetAPI_DraftAngle adraft(S);
	TopExp_Explorer Ex;
	for (Ex.Init(S,TopAbs_FACE); Ex.More(); Ex.Next()) {
		TopoDS_Face F = TopoDS::Face(Ex.Current());
		Handle(Geom_Plane) surf = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(F));
		gp_Pln apln = surf->Pln();
		gp_Dir dirF = apln.Axis().Direction();
		if (dirF.IsNormal(gp_Dir(0.,0.,1.),Precision::Angular()))
			adraft.Add(F, gp_Dir(0.,0.,1.), 15.*M_PI/180, gp_Pln(gp::XOY()));
	}
	TopoDS_Shape resultShape = adraft.Shape();
           

       我接下来还要做的一件事就是将它们进行封装,封装成业务层的拉伸功能,下周又是攻坚的一站

【第三回】使用OCCT做类似AutoCAD的拉伸功能(Extrude)

,不过这周是真的得好好休息了。。

       在执行拉伸功能的时候检测待拉伸的模型是否合法,拉伸后的模型是否合法可使用BRepAlgoAPI_Check,这个类可以检测自干涉(self-interference),也就是自相交(self-intersection)检测。

       有了这些类,那么封装拉伸功能基本上可以完成的了!

继续阅读