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-2026, 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 mtk.MTKCore as mtk
38
39sys.path.append(os.path.abspath(os.path.dirname(Path(__file__).resolve()) + "/../../"))
40sys.path.append(os.path.abspath(os.path.dirname(Path(__file__).resolve()) + "/../../helpers/"))
41
42import LicenseHelper
43
44import mtk_license as license
45
46class UnorientedShapeKey:
47 def __init__(self, theShape: mtk.ModelData_Shape):
48 self.myShape = theShape
49
50 def __hash__(self):
51 aHasher = mtk.ModelData_UnorientedShapeHash()
52 return int(aHasher(self.myShape))
53
54 def __eq__(self, other):
55 if id(other) == id(self):
56 return True
57 if isinstance(other, UnorientedShapeKey):
58 anEqualityChecker = mtk.ModelData_UnorientedShapeEqual()
59 return anEqualityChecker(other.myShape, self.myShape)
60 return False
61
62class PartBRepVisitor(mtk.ModelData_ModelElementVoidVisitor):
63 def __init__(self):
64 super().__init__()
65 self.myNestingLevel = 0
66 self.myShapeSet = set()
67
68 def PrintUniqueShapesCount(self):
69 print();
70 print(f"Total unique shapes count: {len(self.myShapeSet)}")
71
72 def VisitPart(self, thePart: mtk.ModelData_Part):
73 aBodies = thePart.Bodies()
74 if thePart.NumberOfBodies() > 0:
75 self.ExploreBRep(aBodies)
76
77 def ExploreBRep(self, theBodies: mtk.Collections_BodyList):
78 for i, aBody in enumerate(theBodies):
79 print("Body ", i, ": type ", self.PrintBodyType(aBody))
80 aShapeIt = mtk.ModelData_ShapeIterator(aBody)
81 for aShape in aShapeIt:
82 self.ExploreShape(aShape)
83
84 # Recursive iterating over the Shape until reaching vertices
85 def ExploreShape(self, theShape: mtk.ModelData_Shape):
86 self.myShapeSet.add(UnorientedShapeKey(theShape))
87 self.myNestingLevel += 1
88 aShapeIt = mtk.ModelData_ShapeIterator(theShape)
89 while aShapeIt.HasNext():
90 aShape = aShapeIt.Next()
91 self.PrintShapeInfo(aShape)
92 self.ExploreShape(aShape)
93
94 self.myNestingLevel -= 1
95
96 # Returns body type name
97 def PrintBodyType(self, theBody: mtk.ModelData_Body) -> str:
98 if mtk.ModelData_SolidBody.CompareType(theBody):
99 return "Solid"
100 if mtk.ModelData_SheetBody.CompareType(theBody):
101 return "Sheet"
102 if mtk.ModelData_WireframeBody.CompareType(theBody):
103 return "Wireframe"
104 return "Undefined"
105
106 # Prints shape type name and prints shape info in some cases
107 def PrintShapeInfo(self, theShape: mtk.ModelData_Shape) -> str:
108 self.PrintTabulation()
109
110 aType = theShape.Type()
111 if aType == mtk.ShapeType_Solid:
112 print("Solid", end="")
113 elif aType == mtk.ShapeType_Shell:
114 print("Shell", end="")
115 elif aType == mtk.ShapeType_Wire:
116 print("Wire", end="")
117 self.PrintWireInfo(mtk.ModelData_Wire.Cast(theShape))
118 elif aType == mtk.ShapeType_Face:
119 print("Face", end="")
120 self.PrintFaceInfo(mtk.ModelData_Face.Cast(theShape))
121 elif aType == mtk.ShapeType_Edge:
122 print("Edge", end="")
123 self.PrintEdgeInfo(mtk.ModelData_Edge.Cast(theShape))
124 elif aType == mtk.ShapeType_Vertex:
125 print("Vertex", end="")
126 self.PrintVertexInfo(mtk.ModelData_Vertex.Cast(theShape))
127 else:
128 print("Undefined", end="")
129
130 print()
131
132 def PrintOrientationInfo(self, theShape: mtk.ModelData_Shape):
133 print(". Orientation: ", end="")
134 anOrientation = theShape.Orientation()
135 if anOrientation == mtk.ShapeOrientation_Forward:
136 print("Forward", end="")
137 elif anOrientation == mtk.ShapeOrientation_Reversed:
138 print("Reversed", end="")
139
140 def PrintWireInfo(self, theWire: mtk.ModelData_Wire):
141 self.myNestingLevel += 1
142 self.PrintOrientationInfo(theWire)
143 self.myNestingLevel -= 1
144
145 def PrintFaceInfo(self, theFace: mtk.ModelData_Face):
146 self.myNestingLevel += 1
147 self.PrintOrientationInfo(theFace)
148 print()
149 aSurface = theFace.Surface()
150 self.PrintTabulation()
151 print(f"Surface: {self.PrintSurfaceType(aSurface)}", end="")
152 self.myNestingLevel -= 1
153
154 def PrintSurfaceType(self, theSurface: mtk.Geom_Surface) -> str:
155 aType = theSurface.Type()
156 if aType == mtk.SurfaceType_Plane:
157 return "Plane"
158 if aType == mtk.SurfaceType_Cylinder:
159 return "Cylinder"
160 if aType == mtk.SurfaceType_Cone:
161 return "Cone"
162 if aType == mtk.SurfaceType_Sphere:
163 return "Sphere"
164 if aType == mtk.SurfaceType_Torus:
165 return "Torus"
166 if aType == mtk.SurfaceType_LinearExtrusion:
167 return "LinearExtrusion"
168 if aType == mtk.SurfaceType_Revolution:
169 return "Revolution"
170 if aType == mtk.SurfaceType_Bezier:
171 return "Bezier"
172 if aType == mtk.SurfaceType_BSpline:
173 return "BSpline"
174 if aType == mtk.SurfaceType_Offset:
175 return "Offset"
176 return "Undefined"
177
178 def PrintEdgeInfo(self, theEdge: mtk.ModelData_Edge):
179 self.myNestingLevel += 1
180 if theEdge.IsDegenerated():
181 print("(Degenerated)", end="")
182 self.PrintOrientationInfo(theEdge)
183 print(f". Tolerance {theEdge.Tolerance()}", end="")
184
185 if not theEdge.IsDegenerated():
186 print()
187 aCurve, aParamFirst, aParamLast = theEdge.Curve()
188 self.PrintTabulation()
189 print(f"Curve: {self.PrintCurveType(aCurve)}", end="")
190
191 self.myNestingLevel -= 1
192
193 def PrintCurveType(self, theCurve: mtk.Geom_Curve) -> str:
194 aType = theCurve.Type()
195 if aType == mtk.CurveType_Line:
196 return "Line"
197 if aType == mtk.CurveType_Circle:
198 return "Circle"
199 if aType == mtk.CurveType_Ellipse:
200 return "Ellipse"
201 if aType == mtk.CurveType_Hyperbola:
202 return "Hyperbola"
203 if aType == mtk.CurveType_Parabola:
204 return "Parabola"
205 if aType == mtk.CurveType_Bezier:
206 return "Bezier"
207 if aType == mtk.CurveType_BSpline:
208 return "BSpline"
209 if aType == mtk.CurveType_Offset:
210 return "Offset"
211 return "Undefined"
212
213 def PrintVertexInfo(self, theVertex: mtk.ModelData_Vertex):
214 self.PrintOrientationInfo(theVertex)
215 print(f". Tolerance {theVertex.Tolerance()}", end="")
216
217 def PrintTabulation(self):
218 print("- " * self.myNestingLevel, end="")
219
220import sys
221
222from os.path import abspath, dirname
223from pathlib import Path
224
225def main(theSource:str):
226 aKey = license.Value()
227
228 if not LicenseHelper.SetupRuntimeKey() :
229 return 1
230
231 try:
232 mtk.LicenseManager.Activate(aKey)
233 except mtk.LicenseError as anException:
234 mtk.LicenseManager.Deactivate()
235 print("Failed to activate Manufacturing Toolkit license: " + anException.what())
236 return 1
237
238 aModel = mtk.ModelData_Model()
239
240 if not mtk.ModelData_ModelReader().Read(mtk.UTF16String(theSource), aModel):
241 mtk.LicenseManager.Deactivate()
242 print("Failed to read the file " + theSource)
243 return 1
244
245 # Explore B-Rep representation of model parts
246 aVisitor = PartBRepVisitor()
247 aModel.Accept(aVisitor)
248
249 aVisitor.PrintUniqueShapesCount()
250
251 print("Completed")
252
253 mtk.LicenseManager.Deactivate()
254
255 return 0
256
257if __name__ == "__main__":
258 if len(sys.argv) != 2:
259 print("Usage: " + os.path.abspath(Path(__file__).resolve()) + " <input_file>, where:")
260 print(" <input_file> is a name of the file to be read")
261 sys.exit(1)
262
263 aSource = os.path.abspath(sys.argv[1])
264 sys.exit(main(aSource))