采用 OpenCASCADE 提取布尔运算后平面图形的外轮廓

在 CAD 建模和几何处理中,经常需要从复杂形状中提取外轮廓。本文将深入探讨如何使用 OpenCASCADE 库在 C++ 中高效提取布尔运算后平面图形的外轮廓,并提供完整可运行的代码示例。

理论基础

平面图形的数学表示

在计算几何中,一个平面图形可以表示为:

S={(x,y)∈R2∣f(x,y)≥0}S = \{ (x,y) \in \mathbb{R}^2 | f(x,y) \geq 0 \}S={(x,y)R2f(x,y)0}

其中 f(x,y)f(x,y)f(x,y) 是定义图形边界的隐式函数。对于通过布尔运算获得的图形,其边界由多个分段曲线组成:

∂S=⋃i=1nCi(t),t∈[ai,bi]\partial S = \bigcup_{i=1}^{n} C_i(t), \quad t \in [a_i, b_i]S=i=1nCi(t),t[ai,bi]

其中 Ci(t)C_i(t)Ci(t) 是参数化的曲线段。

OpenCASCADE 拓扑结构

OpenCASCADE 使用 BREP(边界表示)模型表示几何形状,其拓扑结构包括:

  • 顶点 (Vertex):0维几何元素
  • 边 (Edge):1维几何元素,由曲线定义
  • 线框 (Wire):边的有序连接
  • 面 (Face):由线框界定的2维曲面
  • 壳 (Shell):面的集合
  • 实体 (Solid):封闭壳

对于平面图形,我们关注的是其外线框 (Outer Wire),即定义图形最外边界的线框。

完整代码实现

示例 1:基本外轮廓提取

#include <BRepTools.hxx>
  #include <TopExp_Explorer.hxx>
    #include <TopoDS.hxx>
      #include <TopoDS_Face.hxx>
        #include <TopoDS_Wire.hxx>
          #include <gp_Circ.hxx>
            #include <gp_Pln.hxx>
              #include <gp_Ax2.hxx>
                #include <gp_Dir.hxx>
                  #include <gp_Pnt.hxx>
                    #include <BRepBuilderAPI_MakeEdge.hxx>
                      #include <BRepBuilderAPI_MakeWire.hxx>
                        #include <BRepBuilderAPI_MakeFace.hxx>
                          #include <BRepAlgoAPI_Cut.hxx>
                            #include <iostream>
                              // 创建圆形平面
                              TopoDS_Shape CreateCircleFace(double radius) {
                              gp_Pln plane(gp::XOY());
                              gp_Circ circle(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), radius);
                              TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
                              TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edge);
                              return BRepBuilderAPI_MakeFace(wire);
                              }
                              // 创建矩形平面
                              TopoDS_Shape CreateRectangleFace(double width, double height) {
                              gp_Pnt p1(-width/2, -height/2, 0);
                              gp_Pnt p2(width/2, -height/2, 0);
                              gp_Pnt p3(width/2, height/2, 0);
                              gp_Pnt p4(-width/2, height/2, 0);
                              TopoDS_Edge e1 = BRepBuilderAPI_MakeEdge(p1, p2);
                              TopoDS_Edge e2 = BRepBuilderAPI_MakeEdge(p2, p3);
                              TopoDS_Edge e3 = BRepBuilderAPI_MakeEdge(p3, p4);
                              TopoDS_Edge e4 = BRepBuilderAPI_MakeEdge(p4, p1);
                              TopoDS_Wire wire = BRepBuilderAPI_MakeWire(e1, e2, e3, e4);
                              return BRepBuilderAPI_MakeFace(wire);
                              }
                              // 获取形状的外轮廓
                              TopoDS_Wire GetOuterWire(const TopoDS_Shape& shape) {
                              if (shape.IsNull()) {
                              throw std::runtime_error("输入形状为空");
                              }
                              TopExp_Explorer faceExplorer(shape, TopAbs_FACE);
                              if (!faceExplorer.More()) {
                              throw std::runtime_error("形状中未找到面");
                              }
                              const TopoDS_Face& face = TopoDS::Face(faceExplorer.Current());
                              TopoDS_Wire outerWire = BRepTools::OuterWire(face);
                              if (outerWire.IsNull()) {
                              throw std::runtime_error("提取外轮廓失败");
                              }
                              return outerWire;
                              }
                              int main() {
                              try {
                              // 创建几何图形
                              TopoDS_Shape circle = CreateCircleFace(50.0);
                              TopoDS_Shape rectangle = CreateRectangleFace(40.0, 40.0);
                              // 执行布尔运算
                              BRepAlgoAPI_Cut cutter(circle, rectangle);
                              cutter.Build();
                              if (!cutter.IsDone()) {
                              throw std::runtime_error("布尔运算失败");
                              }
                              // 获取结果形状
                              TopoDS_Shape resultShape = cutter.Shape();
                              // 提取外轮廓
                              TopoDS_Wire outerWire = GetOuterWire(resultShape);
                              // 输出结果
                              std::cout << "成功提取外轮廓" << std::endl;
                              std::cout << "轮廓包含 " << outerWire.NbChildren() << " 条边" << std::endl;
                              } catch (const std::exception& e) {
                              std::cerr << "错误: " << e.what() << std::endl;
                              return 1;
                              }
                              return 0;
                              }

示例 2:高级外轮廓处理

在这里插入图片描述

#include <BRepTools.hxx>
  #include <TopExp_Explorer.hxx>
    #include <TopoDS.hxx>
      #include <TopoDS_Face.hxx>
        #include <TopoDS_Wire.hxx>
          #include <TopTools_ListOfShape.hxx>
            #include <gp_Circ.hxx>
              #include <gp_Pln.hxx>
                #include <gp_Ax2.hxx>
                  #include <gp_Dir.hxx>
                    #include <gp_Pnt.hxx>
                      #include <BRepBuilderAPI_MakeEdge.hxx>
                        #include <BRepBuilderAPI_MakeWire.hxx>
                          #include <BRepBuilderAPI_MakeFace.hxx>
                            #include <BRepAlgoAPI_Cut.hxx>
                              #include <BRepAlgoAPI_Fuse.hxx>
                                #include <BRepCheck_Analyzer.hxx>
                                  #include <iostream>
                                    #include <vector>
                                      // 创建圆形平面
                                      TopoDS_Shape CreateCircleFace(double radius) {
                                      gp_Pln plane(gp::XOY());
                                      gp_Circ circle(gp_Ax2(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), radius);
                                      TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(circle);
                                      TopoDS_Wire wire = BRepBuilderAPI_MakeWire(edge);
                                      return BRepBuilderAPI_MakeFace(wire);
                                      }
                                      // 创建多边形平面
                                      TopoDS_Shape CreatePolygonFace(const std::vector<gp_Pnt>& points) {
                                        if (points.size() < 3) {
                                        throw std::runtime_error("多边形至少需要3个点");
                                        }
                                        BRepBuilderAPI_MakeWire wireMaker;
                                        for (size_t i = 0; i < points.size(); i++) {
                                        size_t next = (i + 1) % points.size();
                                        TopoDS_Edge edge = BRepBuilderAPI_MakeEdge(points[i], points[next]);
                                        wireMaker.Add(edge);
                                        }
                                        if (!wireMaker.IsDone()) {
                                        throw std::runtime_error("创建线框失败");
                                        }
                                        return BRepBuilderAPI_MakeFace(wireMaker.Wire());
                                        }
                                        // 获取所有外轮廓
                                        TopTools_ListOfShape GetAllOuterWires(const TopoDS_Shape& shape) {
                                        TopTools_ListOfShape resultWires;
                                        // 验证形状有效性
                                        BRepCheck_Analyzer analyzer(shape);
                                        if (!analyzer.IsValid()) {
                                        throw std::runtime_error("形状拓扑结构无效");
                                        }
                                        // 遍历所有面
                                        for (TopExp_Explorer exp(shape, TopAbs_FACE); exp.More(); exp.Next()) {
                                        TopoDS_Face face = TopoDS::Face(exp.Current());
                                        // 获取面的外轮廓
                                        TopoDS_Wire outerWire = BRepTools::OuterWire(face);
                                        if (!outerWire.IsNull()) {
                                        resultWires.Append(outerWire);
                                        }
                                        // 可选:获取内轮廓(孔洞)
                                        /*
                                        TopExp_Explorer wireExp(face, TopAbs_WIRE);
                                        for (; wireExp.More(); wireExp.Next()) {
                                        TopoDS_Wire wire = TopoDS::Wire(wireExp.Current());
                                        if (!wire.IsSame(outerWire)) {
                                        // 处理内轮廓
                                        }
                                        }
                                        */
                                        }
                                        return resultWires;
                                        }
                                        int main() {
                                        try {
                                        // 创建复杂几何图形
                                        std::vector<gp_Pnt> hexPoints = {
                                          gp_Pnt(0, 0, 0),
                                          gp_Pnt(30, 0, 0),
                                          gp_Pnt(45, 25, 0),
                                          gp_Pnt(30, 50, 0),
                                          gp_Pnt(0, 50, 0),
                                          gp_Pnt(-15, 25, 0)
                                          };
                                          TopoDS_Shape hexagon = CreatePolygonFace(hexPoints);
                                          TopoDS_Shape circle = CreateCircleFace(25.0);
                                          // 执行布尔并集运算
                                          BRepAlgoAPI_Fuse fuser(hexagon, circle);
                                          fuser.Build();
                                          if (!fuser.IsDone()) {
                                          throw std::runtime_error("布尔并集运算失败");
                                          }
                                          // 获取结果形状
                                          TopoDS_Shape fusedShape = fuser.Shape();
                                          // 提取所有外轮廓
                                          TopTools_ListOfShape outerWires = GetAllOuterWires(fusedShape);
                                          // 输出结果
                                          std::cout << "找到 " << outerWires.Extent() << " 个外轮廓" << std::endl;
                                          // 遍历所有外轮廓
                                          int wireCount = 1;
                                          for (TopTools_ListIteratorOfListOfShape it(outerWires); it.More(); it.Next()) {
                                          TopoDS_Wire wire = TopoDS::Wire(it.Value());
                                          std::cout << "轮廓 " << wireCount++ << " 包含 "
                                          << wire.NbChildren() << " 条边" << std::endl;
                                          }
                                          } catch (const std::exception& e) {
                                          std::cerr << "错误: " << e.what() << std::endl;
                                          return 1;
                                          }
                                          return 0;
                                          }

posted on 2025-11-14 21:32  slgkaifa  阅读(0)  评论(0)    收藏  举报

导航