理論介紹
在OpenCASCADE幾何建模內核中,BRepAlgoAPI_Splitter
是一個強大的工具,用于將一個形狀(Shape)用另一個形狀(Tool)進行分割。這種操作在CAD建模中非常常見,比如用平面切割實體、用曲線分割曲面等。
BRepAlgoAPI_Splitter
的工作原理是基于布爾運算的切割算法。它能夠處理各種拓撲形狀之間的分割操作,包括:
- 用邊分割面
- 用面分割體
- 用線分割邊
分割操作的結果取決于輸入形狀和工具的幾何關系。當工具完全穿過被分割形狀時,通常會產生多個子形狀;當工具只部分接觸時,則可能只修改原有形狀而不分割。
核心代碼分析
1. 創建被分割的面
TopoDS_Face makeFace(){gp_Pnt P1(-1.0/2.0, -1.0/2.0, 0);gp_Pnt P2(-1.0/2.0, 1.0/2.0, 0);gp_Pnt P3(1.0/2.0, 1.0/2.0, 0);gp_Pnt P4(極1.0/2.0, -1.0/2.0, 0);BRepBuilderAPI_MakePolygon mkPoly(P1,P2,P3,P4);mkPoly.Add(mkPoly.FirstVertex());TopoDS_Wire wire = mkPoly.Wire();BRepBuilderAPI_MakeFace face(wire);return face.Face();
}
這個函數創建一個正方形面,位于XY平面,邊長1個單位,中心在原點。我們使用BRepBuilderAPI_MakePolygon
創建多邊形,然后將其閉合為Wire,最后用Wire創建Face。
2. 創建分割工具
TopoDS_Face makeTool(){static constexpr double bigNumber {100};gp_Pnt P1(0, -bigNumber, -bigNumber);gp_Pnt P極2(0, -bigNumber, bigNumber);gp_Pnt P3(0, bigNumber, bigNumber);gp_Pnt P4(0, bigNumber, -bigNumber);BRepBuilderAPI_MakePoly極gon mkPoly(P1,P2,P3,P4);mkPoly.Add(mkPoly.FirstVertex());TopoDS_Wire wire = mkPoly.Wire();BRepBuilderAPI_MakeFace tool(wire);return tool.Face();}
這里創建一個無限大的YZ平面(實際用大數100近似),作為分割工具。這個平面將垂直于X軸,穿過原點。
3. 執行分割操作
TopoDS_Face face = makeFace();TopoDS_Face tool = makeTool();TopTools_ListOfShape originalArguments;originalArguments.Append (face);TopTools_ListOfShape firstSplitLine;firstSplitLine.Append(tool);auto squareSplitOnce = BRepAlgoAPI_Splitter();squareSplitOnce.SetArguments(originalArguments);squareSplitOnce.SetTools(firstSplitLine);squareSplitOnce.Build();
關鍵步驟:
- 創建被分割的面和分割工具
- 將面添加到參數列表(Arguments)
- 將工具添加到工具列表(Tools)
- 創建
BRepAlgoAPI_Splitter
對象并設置參數和工具 - 調用
Build()
方法執行分割
4. 分析結果
Handle(BRepTools_History) hist = squareSplitOnce.History();hist->Dump(std::cout);auto generated = squareSplitOnce.Generated(face);std::cout << "generated: " << generated.Size() << '\n';auto modified = squareSplitOnce.Modified(face);std::cout << "modified: " << modified.Size() << '\n';
History()
方法返回操作的歷史記錄,可以查詢哪些形狀被修改、生成或移除。Generated()
和Modified()
方法分別返回由輸入形狀生成的新形狀和被修改的形狀。
完整代碼
#include <BRepBuilderAPI_MakeFace.hxx>
#include <BRepBuilderAPI_MakePolygon.hxx>
#include <BRepAlgoAPI_Splitter.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Face.hxx>
#include <TopoDS_Wire.hxx>
#include <TopoDS_Iterator.hxx>
#include <TopExp_Explorer.hxx>
#include <TopTools_IndexedMapOfShape.hxx>
#include <iostream>TopoDS_Face makeFace()
{gp_Pnt P1(-1.0/2.0, -1.0/2.0, 0);gp_Pnt P2(-1.0/2.0, 1.0/2.0, 0);gp_Pnt P3(1.0/2.0, 1.0/2.0, 0);gp_Pnt P4(1.0/2.0, -1.0/2.0, 0);BRepBuilderAPI_MakePolygon mkPoly(P1,P2,P3,P4);mkPoly.Add(mkPoly.FirstVertex());TopoDS_Wire wire = mkPoly.Wire();BRepBuilderAPI_MakeFace face(wire);return face.Face();
}TopoDS_Face makeTool()
{static constexpr double bigNumber {100};gp_Pnt P1(0, -bigNumber, -bigNumber);gp_Pnt P2(0, -bigNumber, bigNumber);gp_Pnt P3(0, bigNumber, bigNumber);gp_Pnt P4(0, bigNumber, -bigNumber);BRepBuilderAPI_MakePolygon mkPoly(P1,P2,P3,P4);mkPoly.Add(mkPoly.FirstVertex());TopoDS_Wire wire = mkPoly.Wire();BRepBuilderAPI_MakeFace tool(wire);return tool.Face();
}void CountSubShape(const TopoDS_Face& face)
{TopTools_IndexedMapOfShape faces;TopTools_IndexedMapOfShape wires;TopTools_IndexedMapOfShape edges;TopTools_IndexedMapOfShape vertexes;for (TopExp_Explorer it(face, TopAbs_FACE); it.More(); it.Next()) {faces.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_WIRE); it.More(); it.Next()) {wires.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_EDGE); it.More(); it.Next()) {edges.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_VERTEX); it.More(); it.Next()) {vertexes.Add(it.Current());}std::cout << " faces=" << faces.Size()<< " wires=" << wires.Size()<< " edges=" << edges.Size()<< " vertexes=" << vertexes.Size()<< '\n';
}void PrintHistory(const TopTools_IndexedMapOfShape& map, Handle(BRepTools_History) hist)
{for (Standard_Integer i = 1; i <= map.Extent(); i++) {const TopoDS_Shape& shape = map(i);std::cout << " modified: " << hist->Modified(shape).Size() << '\n';std::cout << " generated: " << hist->Generated(shape).Size() << '\n';std::cout << " removed: " << hist->IsRemoved(shape) << '\n';}
}void PrintHistory(const TopoDS_Face& face, Handle(BRepTools_History) hist)
{TopTools_IndexedMapOfShape faces;TopTools_IndexedMapOfShape wires;TopTools_IndexedMapOfShape edges;TopTools_IndexedMapOfShape vertexes;for (TopExp_Explorer it(face, TopAbs_FACE); it.More(); it.Next()) {faces.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_WIRE); it.More(); it.Next()) {wires.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_EDGE); it.More(); it.Next()) {edges.Add(it.Current());}for (TopExp_Explorer it(face, TopAbs_VERTEX); it.More(); it.Next()) {vertexes.Add(it.Current());}std::cout << " faces:\n";PrintHistory(faces, hist);std::cout << " wires:\n";PrintHistory(wires, hist);std::cout << " edges:\n";PrintHistory(edges, hist);std::cout << " vertexes:\n";PrintHistory(vertexes, hist);
}int main()
{TopoDS_Face face = makeFace();//CountSubShape(face);TopoDS_Face tool = makeTool();//CountSubShape(tool);TopTools_ListOfShape originalArguments;originalArguments.Append (face);TopTools_ListOfShape firstSplitLine;firstSplitLine.Append(tool);auto squareSplitOnce = BRepAlgoAPI_Splitter();squareSplitOnce.SetArguments(originalArguments);squareSplitOnce.SetTools(firstSplitLine);squareSplitOnce.Build();Handle(BRepTools_History) hist = squareSplitOnce.History();hist->Dump(std::cout);auto generated = squareSplitOnce.Generated(face);std::cout << "generated: " << generated.Size() << '\n';auto modified = squareSplitOnce.Modified(face);std::cout << "modified: " << modified.Size() << '\n';
#if 0std::cout << "\nface:\n";PrintHistory(face, hist);std::cout << "\ntool:\n";PrintHistory(tool, hist);
#endif
}
結論
通過BRepAlgoAPI_Splitter
,我們可以方便地在OpenCASCADE中實現形狀的分割操作。本文展示了如何用一個大平面分割一個正方形面,實際應用中可以根據需要調整被分割形狀和分割工具的幾何參數。操作的歷史記錄功能對于理解分割過程和結果分析非常有幫助。
在實際項目中,分割操作常用于創建復雜幾何形狀、進行幾何分析或準備有限元網格劃分等場景。掌握這些基礎操作是使用OpenCASCADE進行高級幾何建模的重要一步。