-
Notifications
You must be signed in to change notification settings - Fork 2
/
stepanalyzer.py
150 lines (132 loc) · 6.18 KB
/
stepanalyzer.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#!/usr/bin/env python
#
# Copyright 2020 Doug Blanding ([email protected])
#
# The latest version of this file can be found at:
# //https://github.com/dblanding/step-analyzer
#
# stepanalyzer is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# stepanalyzer is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# if not, write to the Free Software Foundation, Inc.
# 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
"""A tool which examines the hierarchical structure of a TDocStd_Document
containing CAD data in OCAF format, either loaded directly or read from a
STEP file. The structure is presented as an indented text outline."""
from OCC.Core.IFSelect import IFSelect_RetDone
from OCC.Core.STEPCAFControl import STEPCAFControl_Reader
from OCC.Core.TDF import TDF_Label, TDF_LabelSequence
from OCC.Core.TCollection import TCollection_ExtendedString
from OCC.Core.TDocStd import TDocStd_Document
from OCC.Core.XCAFApp import XCAFApp_Application_GetApplication
from OCC.Core.XCAFDoc import XCAFDoc_DocumentTool_ShapeTool
class StepAnalyzer():
"""A class that analyzes the structure of an OCAF document."""
def __init__(self, document=None, filename=None):
"""Supply one or the other: document or STEP filename."""
self.uid = 1
self.indent = 0
self.output = ""
self.fname = filename
if filename:
self.doc = self.read_file(filename)
elif document:
self.doc = document
self.shape_tool = XCAFDoc_DocumentTool_ShapeTool(self.doc.Main())
else:
print("Supply one or the other: document or STEP filename.")
def read_file(self, fname):
"""Read STEP file and return <TDocStd_Document>."""
# Create the application, empty document and shape_tool
doc = TDocStd_Document(TCollection_ExtendedString("STEP"))
app = XCAFApp_Application_GetApplication()
app.NewDocument(TCollection_ExtendedString("MDTV-XCAF"), doc)
self.shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main())
self.shape_tool.SetAutoNaming(True)
# Read file and return populated doc
step_reader = STEPCAFControl_Reader()
step_reader.SetColorMode(True)
step_reader.SetLayerMode(True)
step_reader.SetNameMode(True)
step_reader.SetMatMode(True)
status = step_reader.ReadFile(fname)
if status == IFSelect_RetDone:
step_reader.Transfer(doc)
return doc
def dump(self):
"""Return assembly structure in indented outline form.
Format of lines:
Component Name [entry] => Referred Label Name [entry]
Components are shown indented w/r/t line above."""
if self.fname:
self.output += f"Assembly structure of file: {self.fname}\n\n"
else:
self.output += "Assembly structure of doc:\n\n"
self.indent = 0
# Find root label of step doc
labels = TDF_LabelSequence()
self.shape_tool.GetShapes(labels)
nbr = labels.Length()
rootlabel = labels.Value(1) # First label at root
# Get information from root label
name = rootlabel.GetLabelName()
entry = rootlabel.EntryDumpToString()
is_assy = self.shape_tool.IsAssembly(rootlabel)
if is_assy:
# If 1st label at root holds an assembly, it is the Top Assy.
# Through this label, the entire assembly is accessible.
# There is no need to explicitly examine other labels at root.
self.output += f"{self.uid}\t[{entry}] {name}\t"
self.uid += 1
self.indent += 2
top_comps = TDF_LabelSequence() # Components of Top Assy
subchilds = False
is_assy = self.shape_tool.GetComponents(rootlabel, top_comps,
subchilds)
self.output += f"Number of labels at root = {nbr}\n"
if top_comps.Length():
self.find_components(top_comps)
return self.output
def find_components(self, comps):
"""Discover components from comps (LabelSequence) of an assembly.
Components of an assembly are, by definition, references which refer
to either a shape or another assembly. Components are essentially
'instances' of the referred shape or assembly, and carry a location
vector specifing the location of the referred shape or assembly.
"""
for j in range(comps.Length()):
c_label = comps.Value(j+1) # component label <class 'TDF_Label'>
c_name = c_label.GetLabelName()
c_entry = c_label.EntryDumpToString()
ref_label = TDF_Label() # label of referred shape (or assembly)
is_ref = self.shape_tool.GetReferredShape(c_label, ref_label)
if is_ref: # just in case all components are not references
ref_entry = ref_label.EntryDumpToString()
ref_name = ref_label.GetLabelName()
indent = "\t" * self.indent
self.output += f"{self.uid}{indent}[{c_entry}] {c_name}"
self.output += f" => [{ref_entry}] {ref_name}\n"
self.uid += 1
if self.shape_tool.IsAssembly(ref_label):
self.indent += 1
ref_comps = TDF_LabelSequence() # Components of Assy
subchilds = False
_ = self.shape_tool.GetComponents(ref_label, ref_comps,
subchilds)
if ref_comps.Length():
self.find_components(ref_comps)
self.indent -= 1
if __name__ == "__main__":
SA = StepAnalyzer(filename="step/as1-oc-214.stp")
print(SA.dump())
SA2 = StepAnalyzer(filename="step/as1_pe_203.stp")
print(SA2.dump())