首页 > 其他分享 >OCC BRepPrimAPI_MakeBox实现步骤记录

OCC BRepPrimAPI_MakeBox实现步骤记录

时间:2022-11-29 09:55:43浏览次数:41  
标签:case gp OCC BRepPrim break MakeBox YMin BRepPrimAPI d1

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

相关文章