Hide menu
Loading...
Searching...
No Matches
exploring/brep_topology/brep_topology.py

Refer to the B-Rep Topology Exploration Example.

1#!/usr/bin/env python3
2
3# $Id$
4
5# Copyright (C) 2008-2014, Roman Lygin. All rights reserved.
6# Copyright (C) 2014-2025, CADEX. All rights reserved.
7
8# This file is part of the Manufacturing Toolkit software.
9
10# You may use this file under the terms of the BSD license as follows:
11
12# Redistribution and use in source and binary forms, with or without
13# modification, are permitted provided that the following conditions are met:
14# * Redistributions of source code must retain the above copyright notice,
15# this list of conditions and the following disclaimer.
16# * Redistributions in binary form must reproduce the above copyright notice,
17# this list of conditions and the following disclaimer in the documentation
18# and/or other materials provided with the distribution.
19
20# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
24# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30# POSSIBILITY OF SUCH DAMAGE.
31
32import sys
33import os
34
35from pathlib import Path
36
37import manufacturingtoolkit.CadExMTK as mtk
38
39sys.path.append(os.path.abspath(os.path.dirname(Path(__file__).resolve()) + "/../../"))
40
41import mtk_license as license
42
43class UnorientedShapeKey:
44 def __init__(self, theShape: mtk.ModelData_Shape):
45 self.myShape = theShape
46
47 def __hash__(self):
48 aHasher = mtk.ModelData_UnorientedShapeHash()
49 return int(aHasher(self.myShape))
50
51 def __eq__(self, other):
52 if id(other) == id(self):
53 return True
54 if isinstance(other, UnorientedShapeKey):
55 anEqualityChecker = mtk.ModelData_UnorientedShapeEqual()
56 return anEqualityChecker(other.myShape, self.myShape)
57 return False
58
59class PartBRepVisitor(mtk.ModelData_ModelElementVoidVisitor):
60 def __init__(self):
61 super().__init__()
62 self.myNestingLevel = 0
63 self.myShapeSet = set()
64
65 def PrintUniqueShapesCount(self):
66 print();
67 print(f"Total unique shapes count: {len(self.myShapeSet)}")
68
69 def VisitPart(self, thePart: mtk.ModelData_Part):
70 aBodies = thePart.Bodies()
71 if thePart.NumberOfBodies() > 0:
72 self.ExploreBRep(aBodies)
73
74 def ExploreBRep(self, theBodies: mtk.Collections_BodyList):
75 for i, aBody in enumerate(theBodies):
76 print("Body ", i, ": type ", self.PrintBodyType(aBody))
77 aShapeIt = mtk.ModelData_ShapeIterator(aBody)
78 for aShape in aShapeIt:
79 self.ExploreShape(aShape)
80
81 # Recursive iterating over the Shape until reaching vertices
82 def ExploreShape(self, theShape: mtk.ModelData_Shape):
83 self.myShapeSet.add(UnorientedShapeKey(theShape))
84 self.myNestingLevel += 1
85 aShapeIt = mtk.ModelData_ShapeIterator(theShape)
86 while aShapeIt.HasNext():
87 aShape = aShapeIt.Next()
88 self.PrintShapeInfo(aShape)
89 self.ExploreShape(aShape)
90
91 self.myNestingLevel -= 1
92
93 # Returns body type name
94 def PrintBodyType(self, theBody: mtk.ModelData_Body) -> str:
95 if mtk.ModelData_SolidBody.CompareType(theBody):
96 return "Solid"
97 if mtk.ModelData_SheetBody.CompareType(theBody):
98 return "Sheet"
99 if mtk.ModelData_WireframeBody.CompareType(theBody):
100 return "Wireframe"
101 return "Undefined"
102
103 # Prints shape type name and prints shape info in some cases
104 def PrintShapeInfo(self, theShape: mtk.ModelData_Shape) -> str:
105 self.PrintTabulation()
106
107 aType = theShape.Type()
108 if aType == mtk.ShapeType_Solid:
109 print("Solid", end="")
110 elif aType == mtk.ShapeType_Shell:
111 print("Shell", end="")
112 elif aType == mtk.ShapeType_Wire:
113 print("Wire", end="")
114 self.PrintWireInfo(mtk.ModelData_Wire.Cast(theShape))
115 elif aType == mtk.ShapeType_Face:
116 print("Face", end="")
117 self.PrintFaceInfo(mtk.ModelData_Face.Cast(theShape))
118 elif aType == mtk.ShapeType_Edge:
119 print("Edge", end="")
120 self.PrintEdgeInfo(mtk.ModelData_Edge.Cast(theShape))
121 elif aType == mtk.ShapeType_Vertex:
122 print("Vertex", end="")
123 self.PrintVertexInfo(mtk.ModelData_Vertex.Cast(theShape))
124 else:
125 print("Undefined", end="")
126
127 print()
128
129 def PrintOrientationInfo(self, theShape: mtk.ModelData_Shape):
130 print(". Orientation: ", end="")
131 anOrientation = theShape.Orientation()
132 if anOrientation == mtk.ShapeOrientation_Forward:
133 print("Forward", end="")
134 elif anOrientation == mtk.ShapeOrientation_Reversed:
135 print("Reversed", end="")
136
137 def PrintWireInfo(self, theWire: mtk.ModelData_Wire):
138 self.myNestingLevel += 1
139 self.PrintOrientationInfo(theWire)
140 self.myNestingLevel -= 1
141
142 def PrintFaceInfo(self, theFace: mtk.ModelData_Face):
143 self.myNestingLevel += 1
144 self.PrintOrientationInfo(theFace)
145 print()
146 aSurface = theFace.Surface()
147 self.PrintTabulation()
148 print(f"Surface: {self.PrintSurfaceType(aSurface)}", end="")
149 self.myNestingLevel -= 1
150
151 def PrintSurfaceType(self, theSurface: mtk.Geom_Surface) -> str:
152 aType = theSurface.Type()
153 if aType == mtk.SurfaceType_Plane:
154 return "Plane"
155 if aType == mtk.SurfaceType_Cylinder:
156 return "Cylinder"
157 if aType == mtk.SurfaceType_Cone:
158 return "Cone"
159 if aType == mtk.SurfaceType_Sphere:
160 return "Sphere"
161 if aType == mtk.SurfaceType_Torus:
162 return "Torus"
163 if aType == mtk.SurfaceType_LinearExtrusion:
164 return "LinearExtrusion"
165 if aType == mtk.SurfaceType_Revolution:
166 return "Revolution"
167 if aType == mtk.SurfaceType_Bezier:
168 return "Bezier"
169 if aType == mtk.SurfaceType_BSpline:
170 return "BSpline"
171 if aType == mtk.SurfaceType_Offset:
172 return "Offset"
173 return "Undefined"
174
175 def PrintEdgeInfo(self, theEdge: mtk.ModelData_Edge):
176 self.myNestingLevel += 1
177 if theEdge.IsDegenerated():
178 print("(Degenerated)", end="")
179 self.PrintOrientationInfo(theEdge)
180 print(f". Tolerance {theEdge.Tolerance()}", end="")
181
182 if not theEdge.IsDegenerated():
183 print()
184 aCurve, aParamFirst, aParamLast = theEdge.Curve()
185 self.PrintTabulation()
186 print(f"Curve: {self.PrintCurveType(aCurve)}", end="")
187
188 self.myNestingLevel -= 1
189
190 def PrintCurveType(self, theCurve: mtk.Geom_Curve) -> str:
191 aType = theCurve.Type()
192 if aType == mtk.CurveType_Line:
193 return "Line"
194 if aType == mtk.CurveType_Circle:
195 return "Circle"
196 if aType == mtk.CurveType_Ellipse:
197 return "Ellipse"
198 if aType == mtk.CurveType_Hyperbola:
199 return "Hyperbola"
200 if aType == mtk.CurveType_Parabola:
201 return "Parabola"
202 if aType == mtk.CurveType_Bezier:
203 return "Bezier"
204 if aType == mtk.CurveType_BSpline:
205 return "BSpline"
206 if aType == mtk.CurveType_Offset:
207 return "Offset"
208 return "Undefined"
209
210 def PrintVertexInfo(self, theVertex: mtk.ModelData_Vertex):
211 self.PrintOrientationInfo(theVertex)
212 print(f". Tolerance {theVertex.Tolerance()}", end="")
213
214 def PrintTabulation(self):
215 print("- " * self.myNestingLevel, end="")
216
217import sys
218
219from os.path import abspath, dirname
220from pathlib import Path
221
222def main(theSource:str):
223 aKey = license.Value()
224
225 if not mtk.LicenseManager.Activate(aKey):
226 print("Failed to activate Manufacturing Toolkit license.")
227 return 1
228
229 aModel = mtk.ModelData_Model()
230
231 if not mtk.ModelData_ModelReader().Read(mtk.UTF16String(theSource), aModel):
232 print("Failed to read the file " + theSource)
233 return 1
234
235 # Explore B-Rep representation of model parts
236 aVisitor = PartBRepVisitor()
237 aModel.Accept(aVisitor)
238
239 aVisitor.PrintUniqueShapesCount()
240
241 print("Completed")
242 return 0
243
244if __name__ == "__main__":
245 if len(sys.argv) != 2:
246 print("Usage: " + os.path.abspath(Path(__file__).resolve()) + " <input_file>, where:")
247 print(" <input_file> is a name of the file to be read")
248 sys.exit(1)
249
250 aSource = os.path.abspath(sys.argv[1])
251 sys.exit(main(aSource))