OCC构建Box实现过程解析:
TopoDS_Shape = BRepPrimAPI_MakeBox(5, 5, 5);
// BRepPrimAPI_MakeBox简单介绍
BRepPrimAPI_MakeBox : public BRepBuilderAPI_MakeShape
{
protected:
BRepPrim_Wedge myWedge;
};
// 第一步,BRepPrimAPI_MakeBox的构造函数
BRepPrimAPI_MakeBox(double dx, double dy, double dz)
: myWedge(gp_Ax2(pmin(gp_Pnt(0,0,0),dx,dy,dz), gp_Dir(0,0,1), gp_Dir(1,0,0)),
Abs(dx), Abs(dy), Abs(dz))
{
// 说明:pmin(gp_Pnt(0,0,0),dx,dy,dz) 如果dx/dy/dz小于0,则模型原点向小于0的对应方向偏移对应距离,否则,模型原点就是0,0,0
// 此步骤仅相当于提供了一个供用户方便使用的接口,实际建模是由 成员BRepPrim_Wedge完成的。
}
// 第二步,BRepPrim_Wedge的构造函数
// BRepPrim_Wedge简介
class BRepPrim_Wedge : public BRepPrim_GWedge
{
};
BRepPrim_Wedge(const gp_Ax2 &Axes, const double dx, const double dy, const double dz)
:BRepPrim_GWedge(BRepPrim_Builder(), Axes, dx, dy, dz)
{
// 也是仅提供便捷构造接口,实际建模内容由 BRepPrim_GWedge完成
}
// 第三步, BRepPrim_GWedge构造函数
// BRepPrim_GWedge简介:
class BRepPrim_GWedge
{
private:
BRepPrim_Builder myBuilder; // Topo关系及添加的处理类
gp_Ax2 myAxes;
double XMin, XMax, YMin, YMax, ZMin, ZMax;
double Z2Min, Z2Max, X2Min, X2Max;
TopoDS_Shell myShell; // Shell
bool ShellBuilt; // 整体的Shell是否已生成
TopoDS_Vertex myVertices[8]; // 8个顶点
bool VerticesBuilt[8]; // 8个顶点是否已生成
TopoDS_Edge myEdges[12]; // 12条边
bool EdgesBuilt[12]; // 12条边是否已生成
TopoDS_Wire myWires[6]; // 6个面的Wire
bool WiresBuilt[6]; // 6个面的Wire是否已生成
TopoDS_Face myFaces[6]; // 6个面
bool FacesBuilt[6]; // 6个面是否已生成
bool myInfinite[6]; // 6个面否是无限的。无限表示没有面
};
BRepPrim_GWedge(const BRepPrim_Builder &B, const gp_Ax2 &Axes, const double dx, const double dy, const double dz)
: myBuilder(B),
myAxes(Axes),
XMin(0), XMax(dx),
YMin(0), YMax(dy),
ZMin(0), ZMax(dz),
Z2Min(0), Z2Max(dz), // 此类不止能处理立方体,还可以处理楔体。所以,需要额外长度
X2Min(0), X2Max(dx)
{
for (int i=0; i<6;++i) myInfinite[i] = false;
BRepPrim_Wedge_Init(ShellBuilt, VerticesBuilt, EdgesBuilt, WiresBuilt, FacesBuilt);
}
BRepPrim_Wedge_Init(bool &S, bool V[], bool E[], bool W[], bool F[])
{
// 状态全部置为 false
}
完成
等等,不对呀,到目前为止,没有生成shape的代码呀?那最终的模型是怎么被构建出来的呢?
我们再回头看看,BRepPrimAPI_MakeBox 继承自 BRepBuilderAPI_MakeShape, BRepBuilderAPI_MakeShape重载了 TopoDS_Shape()转换,那么我们再看看转换过程中发生了什么吧。
BRepBuilderAPI_MakeShape::operator TopoDS_Shape()
{
return Shape();
}
const TopoDS_Shape &BRepBuilderAPI_MakeShape::Shape()
{
if (!IsDone())
{
((BRepBuilderAPI_MakeShape *)(void *) this)->Build();
Check();
}
return myShape;
}
// 此时我们应该清楚了,BRepPrimAPI_MakeBox也是通过Build()函数在类型转换时完成的建模,那么我们接着看。
void BRepPrimAPI_MakeBox::Build(const Message_ProgressRange &theRange = Message_ProgressRange())
{
Solid();
}
const TopoDS_Solid &BRepPrimAPI_MakeBox::Solid()
{
BRep_Builder B;
B.MakeSolid(TopoDS::Solid(myShape));
B.Add(myShape, myWedge.Shell());
Done();
return TopoDS::Solid(myShape);
}
// B.MakeSolid(TopoDS::Solid(myShape)); 创建 TopoDS_TSolid内存,并与myShape绑定
// B.Add(myShape, myWedge.Shell()); 判断myWedge.Shell()能否添加到myShape中,如果可以则添加,不可以则抛异常。
由此可见,真正执行建模任务的是 myWedge.Shell()。
const TopoDS_Shell &BRepPrim_GWedge::Shell()
{
// 判断x,y,z数值有效性
if (IsDegeneratedShape()) throw Standard_DomainError();
// 此变量在上方 Init函数中初始化为 false
if (!ShellBuilt)
{
// MakeShell 同上方的MakeSolid一样,创建TopoDS_TShell内存并与myShell绑定
myBuilder.MakeShell(myShell);
// BRepPrim_XMin表示朝向x轴负方向的面,其他同理
// HasFace:某个面需要生成
if (HasFace(BRepPrim_XMin))
myBuilder.AddShellFace(myShell, Face(BRepPrim_XMin));
if (HasFace(BRepPrim_XMax))
myBuilder.AddShellFace(myShell, Face(BRepPrim_XMax));
if (HasFace(BRepPrim_YMin))
myBuilder.AddShellFace(myShell,Face(BRepPrim_YMin));
if (HasFace(BRepPrim_YMax))
myBuilder.AddShellFace(myShell,Face(BRepPrim_YMax));
if (HasFace(BRepPrim_ZMin))
myBuilder.AddShellFace(myShell,Face(BRepPrim_ZMin));
if (HasFace(BRepPrim_ZMax))
myBuilder.AddShellFace(myShell,Face(BRepPrim_ZMax));
myShell.Closed(BRep_Tool::IsClosed(myShell));
myBuilder.CompleteShell(myShell);
ShellBuilt = true;
}
return myShell;
}
面、边、点的int值如下:
面的值 边的值 顶点的值
// param@d1: 某个面枚举值
const TopoDS_Face &BRepPrim_GWedge::Face(const BRepPrim_Direction d1)
{
// 把d1枚举值转换为本类对应的int值,为什么不能直接用枚举值?
int i = BRepPrim_Wedge_NumDir1(d1);
// 面没有创建才创建
if (FacesBuilt[i]) return myFaces[i];
gp_Pln P = Plane(d1);
myBuilder.MakeFace(myFaces[i], P);
// HasWire 同 HasFace
if (HasWire(d1)) myBuilder.AddFaceWire(myFaces[i], Wire(d1));
// 由上图可知,i为 0, 2, 4时分别代表 -x, -y, -z
if (i % 2 == 0) myBuilder.ReverseFace(myFaces[i]);
// 用于取某一个面上4条边,除d1外的另外一个面
BRepPrim_Direction dd1 = BRepPrim_ZMin,
dd2 = BRepPrim_YMax,
dd3 = BRepPrim_ZMax,
dd4 = BRepPrim_YMin;
switch(i / 2)
{
case 0: // XMin, XMax
dd1 = BRepPrim_ZMin; dd2 = BRepPrim_YMax;
dd3 = BRepPrim_ZMax; dd4 = BRepPrim_YMin; break;
case 1: // YMin, YMax
dd1 = BRepPrim_XMin; dd2 = BRepPrim_ZMax;
dd3 = BRepPrim_XMax; dd4 = BRepPrim_ZMin; break;
case 2: // ZMin, ZMax
dd1 = BRepPrim_YMin; dd2 = BRepPrim_XMax;
dd3 = BRepPrim_YMax; dd4 = BRepPrim_XMin; break;
}
gp_Line L;
gp_Dir DX = P.XAxis().Direction();
gp_Dir DY = P.YAxis().Direction();
double U, V, DU, DV;
// 源代码为4个if,此处简化为for
for (dd4, dd3, dd2, dd1)
{
if (HasEdge(d1, dd*))
{
L = Line(d1, dd*);
ElSLib::Parameters(P, L.Location(), U, V);
DU = L.Direction() * DX;
DV = L.Direction() * DY;
myBuilder.SetPCurve(myEdges[BRepPrim_Wedge_NumDir2(d1, dd*)],
myFaces[i],
gp_Line2d(gp_Pnt(U, V), gp_Dir2d(DU, DV)));
}
}
myBuilder.CompleteFace(myFaces[i]);
FacesBuilt[i] = true;
return myFaces[i];
}
// Wire
const TopoDS_Wire &BRepPrim_GWedge::Wire(const BRepPrim_Direction d1)
{
int i = BRepPrim_Wedge_NumDir1(d1);
BRepPrim_Direction dd1 = BRepPrim_XMin,
dd2 = BRepPrim_YMax,
dd3 = BRepPrim_XMax,
dd4 = BRepPrim_ZMin;
if (WiresBuilt[i]) return myWires[i];
switch(i / 2)
case 0: dd1 = BRepPrim_ZMin; dd2 = BRepPrim_YMax;
dd3 = BRepPrim_ZMax; dd4 = BRepPrim_YMin; break;
case 1: dd1 = BRepPrim_XMin; dd2 = BRepPrim_ZMax;
dd3 = BRepPrim_XMax; dd4 = BRepPrim_ZMin; break;
case 2: dd1 = BRepPrim_YMin; dd2 = BRepPrim_XMax;
dd3 = BRepPrim_YMax; dd4 = BRepPrim_XMin; break;
myBuilder.MakeWire(myWires[i]);
// AddWireEdge第3个参数为Edge是否需要逆序
if(HasEdge(d1,dd4))
myBulider.AddWireEdge(myWires[i], Edge(d1, dd4), false);
if (HasEdge(d1,dd3))
myBuilder.AddWireEdge(myWires[i], Edge(d1, dd3), false);
if (HasEdge(d1,dd2))
myBuilder.AddWireEdge(myWires[i], Edge(d1, dd2), true);
if (HasEdge(d1,dd1))
myBuilder.AddWireEdge(myWires[i], Edge(d1,dd1), true);
// CompleteWire { W.Closed(BRep_Tool::IsClosed(W)); BRepTools::Update(W); }
myBuilder.CompleteWire(myWires[i]);
WiresBuilt[i] = true;
return myWires[i];
}
const TopoDS_Edge &BRepPrim_GWedge::Edge(const BRepPrim_Direction d1,
const BRepPrim_Direction d2)
{
if (!HasEdge(d1,d2)) throw Standard_DomainError();
// 获取边的编号,见上图
int i = BRepPrim_Wedge_NumDir2(d1, d2);
if (EdgesBuilt[i]) return myEdges[i];
BRepPrim_Direction dd1 = BRepPrim_XMin, dd2 = BRepPrim_XMax;
switch(i / 4)
case 0: dd1 = BRepPrim_ZMin; dd2 = BRepPrim_ZMax; break;
case 1: dd1 = BRepPrim_XMin; dd2 = BRepPrim_XMax; break;
case 2: dd1 = BRepPrim_YMin; dd2 = BRepPrim_YMax; break;
// gp_Lin L是直线,所以,下面还要代码约束范围
gp_Lin L = Line(d1, d2);
myBuilder.MakeEdge(myEdges[i], L);
if (HasVertex(d1, d2, dd2)) {
myBuilder.AddEdgeVertex(myEdges[i], Vertex(d1,d2,dd2),
ElCLib::Parameter(L, Point(d1,d2,dd2)), false);
}
if (HasVertex(d1,d2,dd1)) {
myBuilder.AddEdgeVertex(myEdges[i], Vertex(d1,d2,dd1),
ElCLib::Parameter(L, Point(d1,d2,dd1)), true);
}
// 非立方体处理
if (Z2Max == Z2Min)
{
if (i == 6) {myEdges[7] = myEdges[6]; EdgesBuilt[7] = true;}
else if (i == 7) {myEdges[6] = myEdges[7]; EdgesBuilt[6] = true;}
}
if (X2Max == X2Min)
{
if (i == 1) {myEdges[3] = myEdges[61; EdgesBuilt[3] = true;}
else if (i == 3) {myEdges[1] = myEdges[3]; EdgesBuilt[1] = true;}
}
// CompleteEdge() { BRepTools::Update(E); }
myBuilder.CompleteEdge(myEdges[i]);
EdgesBuilt[i] = true;
return myEdges[i];
}
// Vertex
const TopoDS_Vertex &BRepPrim_GWedge::Vertex(const BRepPrim_Direction d1,
const BRepPrim_Direction d2, const BRepPrim_Direction d3)
{
if (!HasVertex(d1,d2,d3)) throw Standard_DomainError();
// 取顶点的int值,见上图
int i = BRepPrim_Wedge_NumDir3(d1,d2,d3);
if (VerticesBuilt[i]) return myVertices[i];
myBuilder.MakeVertex(myVertices[i], Point(d1,d2,d3));
if (Z2Max == Z2Min)
{
if (i == 2 || i == 6) {
myVertices[3] = myVertices[2]; myVertices[7] = myVertices[6];
VerticesBuilt[3] = true; VerticesBuilt[7] = true;
}
else if (i == 3 || i == 7) {
myVertices[2] = myVertices[3]; myVertices[6] = myVertices[7];
VerticesBuilt[2] = true; VerticesBuilt[6] = true;
}
}
if (X2Max == X2Min)
{
if (i == 2 || i == 3) {
myVertices[6] = myVertices[2]; myVertices[7] = myVertices[3];
VerticesBuilt[6] = true; VerticesBuilt[7] = true;
}
else if (i == 6 || i == 7) {
myVertices[2] = myVertices[6]; myVertices[3] = myVertices[7];
VerticesBuilt[2] = true; VerticesBuilt[3] = true;
}
}
VerticesBuilt[i] = true;
return myVertices[i];
}
gp_Pln BRepPrim_GWedge::Plane(const BRepPrim_Direction d1)
{
int i = BRepPrim_Wedge_NumDir1(d1); // 等价于 int i = (int)d1;
// XMin, XMax平面的法向量就是X轴
// YMin, YMax平面法向量为Y轴
// ZMin, ZMax平面法向量为Z轴
gp_Dir D;
switch(i / 2)
case 0: // XMin, XMax
D = myAxes.XDirection(); break;
case 1: // YMin, YMax
D = myAxes.YDirection(); break;
case 2: // ZMin, ZMax
D = myAxes.Direction(); break;
double X = 0, Y = 0, Z = 0;
switch(i) {
case 0: // XMin 不需要平移
X = XMin; Y = YMin; Z = ZMin;
if (X2Min != XMin) D = gp_Dir((YMax-YMin)*VX + (XMin-X2Min)*VY);
break;
case 1: // XMax x平移到XMax
X = XMax; Y = YMin; Z = ZMin;
if (X2Max != XMax) D = gp_Dir((YMax-YMin)*VX + (XMax-X2Max)*VY);
break;
case 2: // YMin 不需要平移
X = XMin; Y = YMin; Z = ZMin; break;
case 3: // YMax y平移到YMax
X = XMin; Y = YMax; Z = ZMin; break;
case 4: // ZMin 不需要平移
X = XMin; Y = YMin; Z = ZMin;
if (Z2Min != ZMin) D = gp_Dir((YMax-YMin)*VZ+(ZMin-Z2Min)*VY);
break;
case 5: // ZMax z平移到zMax
X = XMin; Y = YMin; Z = ZMax;
if (Z2Max != ZMax) D = gp_Dir((YMax-YMin)*VZ + (ZMax-Z2Max)*VY);
break;
}
gp_Pnt P = myAxes.Location();
P.Translate(X*gp_Vec(myAxes.XDirection()));
P.Translate(Y*gp_Vec(myAxes.YDirection()));
P.Translate(Z*gp_Vec(myAxes.Direction()));
gp_Pln plane(P, D);
return plane;
}
gp_Line BRepPrim_GWedge::Line(const BRepPrim_Direction d1, const BRepPrim_Direction d2)
{
if (!HasEdge(d1, d2)) throw Standard_DomainError();
// 根据面的int值 d1, d2获取边的int值。见上图
int i = BRepPrim_Wedge_NumDir2(d1, d2);
// 直线的向量
gp_Dir D;
switch(i / 4)
case 0: // 0, 1, 2, 3 见上图
D = myAxes.Direction(); break;
case 1: // 4, 5, 6, 7
D = myAxes.XDirection(); break;
case 2: // 8, 9, 10, 11
D = myAxes.YDirection(); break;
// 以下内容请对照上图理解
double X = 0, Y = 0, Z = 0;
switch(i)
case 0: X = XMin; Y = YMin; Z = ZMin; break;
case 1: X = X2Min; Y = YMax; Z = Z2Min; break; // 注意,X2Min和Z2Min表示可能不是立方体
case 2: X = XMax; Y = YMin; Z = ZMin; break;
case 3: X = X2Max; Y = YMax; Z = Z2Min; break;
case 4: X = XMin; Y = YMin; Z = ZMin; break;
case 5: X = XMin; Y = YMin; Z = ZMax; break;
case 6: X = X2Min; Y = YMax; Z = Z2Min; break;
case 7: X = X2Min; Y = YMax; Z = Z2Max; break;
case 8: X = XMin; Y = YMin; Z = ZMin;
if ((XMin != X2Min) || (ZMin != Z2Min))
D = gp_Vec((X2Min-XMin)*VX + (YMax-YMin)*VY + (Z2Min-ZMin)*VZ);
break;
case 9: X = XMin; Y = YMin; Z = ZMax;
if ((XMin != X2Min) || (ZMax != Z2Max))
D = gp_Vec((X2Min-XMin)*VX + (YMax-YMin)*VY + (Z2Max-ZMax)*VZ);
break;
case 10:X = XMax; Y = YMin; Z = ZMin;
if ((XMax != X2Max) || (ZMin != Z2Min))
D = gp_Vec((X2Max-XMax)*VX + (YMax-YMin)*VY + (Z2Min-ZMin)*VZ);
break;
case 11: X = XMax; Y = YMin; Z = ZMax;
if ((XMax != X2Max) || (ZMax != Z2Max))
D = gp_Vec((X2Max-XMax)*VX + (YMax-YMin)*VY + (Z2Max-ZMax)*VX);
break;
gp_Pnt P = myAxes.Location();
P.Translate(X * gp_Vec(myAxes.XDirection()));
P.Translate(Y * gp_Vec(myAxes.YDirection()));
P.Translate(Z * gp_Vec(myAxes.Direction()));
return gp_Lin(gp_Ax1(P, D));
}
gp_Pnt BRepPrim_GWedge::Point(const BRepPrim_Direction d1, const BRepPrim_Direction d2, const BRepPrim_Direction d3)
{
if (!HasVertex(d1,d2,d3)) throw Standard_DomainError();
// 取顶点int编号,见上图
int i = BRepPrim_Wedge_NumDir3(d1,d2,d3);
double X = 0, Y = 0, Z = 0;
// 根据顶点编号获取顶点坐标
switch(i)
case 0: X = XMin; Y = YMin; Z = ZMin; break;
case 1: X = XMin; Y = YMin; Z = ZMax; break;
case 2: X = X2Min; Y = YMax; Z = Z2Min; break;
case 3: X = X2Min; Y = YMax; Z = Z2Max; break;
case 4: X = XMax; Y = YMin; Z = ZMin; break;
case 5: X = XMax; Y = YMin; Z = ZMax; break;
case 6: X = X2Max; Y = YMax; Z = Z2Min; break;
case 7: X = X2Max; Y = YMax; Z = Z2Max; break;
gp_Pnt P = myAxes.Location();
P.Translate(X * gp_Vec(myAxes.XDirection()));
P.Translate(Y * gp_Vec(myAxes.YDirection()));
P.Translate(Z * gp_Vec(myAxes.Direction()));
return P;
}
结论
整体是按照Solid Shell Face Wire Edge Vertex一层层构造的
标签:case,gp,OCC,BRepPrim,break,MakeBox,YMin,BRepPrimAPI,d1 From: https://www.cnblogs.com/06NN08/p/16931595.html