class TreeModel(): """XCAF Tree Model of hierarchical CAD assembly data""" def __init__(self, title): # Create the application and document doc = TDocStd_Document(TCollection_ExtendedString(title)) app = XCAFApp_Application_GetApplication() app.NewDocument(TCollection_ExtendedString("MDTV-XCAF"), doc) self.app = app self.doc = doc # Initialize tools self.shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) self.shape_tool.SetAutoNaming(True) self.color_tool = XCAFDoc_DocumentTool_ColorTool(doc.Main()) self.layer_tool = XCAFDoc_DocumentTool_LayerTool(doc.Main()) self.l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main()) self.allChildLabels = [] def getChildLabels(self, label): """Return list of child labels directly below label.""" itlbl = TDF_ChildIterator(label, True) childlabels = [] while itlbl.More(): childlabels.append(itlbl.Value()) itlbl.Next() return childlabels def getAllChildLabels(self, label, first=True): """Return list of all child labels (recursively) below label. This doesn't find anything at the second level down because the component labels of root do not have children, but rather they have references.""" print("Entering 'getAllChildLabels'") if first: self.allChildLabels = [] childLabels = self.getChildLabels(label) print(f"len(childLabels) = {len(childLabels)}") self.allChildLabels += childLabels print(f"len(allChildLabels) = {len(self.allChildLabels)}") for lbl in childLabels: self.getAllChildLabels(lbl, first=False) return self.allChildLabels def saveDoc(self, filename="foo.caf"): """Save doc to file (for educational purposes) (not working yet) https://www.opencascade.com/doc/occt-7.4.0/overview/html/occt_user_guides__ocaf.html#occt_ocaf_11 """ frmte = TCollection_ExtendedString("Xml-XCAF") #frmta = TCollection_AsciiString("MDTV-CAF") self.app.DefineFormat(TCollection_AsciiString("DocumentFormat"), TCollection_AsciiString("MDTV-CAF"), TCollection_AsciiString("caf"), XmlXCAFDrivers_DocumentRetrievalDriver(), XmlXCAFDrivers_DocumentStorageDriver(frmte)) logger.debug("Saving doc to file") savefilename = TCollection_ExtendedString(filename) self.app.SaveAs(self.doc, savefilename)
class TreeModel(): """XCAF Tree Model of heirarchical CAD assembly data.""" def __init__(self, title): # Create the application and document doc = TDocStd_Document(TCollection_ExtendedString(title)) app = XCAFApp_Application_GetApplication() app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), doc) self.app = app self.doc = doc # Initialize tools self.shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) self.shape_tool.SetAutoNaming(True) self.color_tool = XCAFDoc_DocumentTool_ColorTool(doc.Main()) self.layer_tool = XCAFDoc_DocumentTool_LayerTool(doc.Main()) self.l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main()) self.allChildLabels = [] def getChildLabels(self, label): """Return list of child labels directly below label.""" itlbl = TDF_ChildIterator(label, True) childlabels = [] while itlbl.More(): childlabels.append(itlbl.Value()) itlbl.Next() return childlabels def getAllChildLabels(self, label, first=True): """Return list of all child labels (recursively) below label. This doesn't find anything at the second level down because the component labels of root do not have children, but rather they have references.""" print("Entering 'getAllChildLabels'") if first: self.allChildLabels = [] childLabels = self.getChildLabels(label) print(f"len(childLabels) = {len(childLabels)}") self.allChildLabels += childLabels print(f"len(allChildLabels) = {len(self.allChildLabels)}") for lbl in childLabels: self.getAllChildLabels(lbl, first=False) return self.allChildLabels def saveDoc(self, filename): """Save doc to file (for educational purposes) (not working yet) """ logger.debug("Saving doc to file") savefilename = TCollection_ExtendedString(filename) self.app.SaveAs(self.doc, savefilename)
def read_step_file_with_names_colors(filename): """ Returns list of tuples (topods_shape, label, color) Use OCAF. """ # the list: output_shapes = [] # create an handle to a document doc = TDocStd_Document(TCollection_ExtendedString("pythonocc-doc")) # Get root assembly shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) color_tool = XCAFDoc_DocumentTool_ColorTool(doc.Main()) #layer_tool = XCAFDoc_DocumentTool_LayerTool(doc.Main()) #mat_tool = XCAFDoc_DocumentTool_MaterialTool(doc.Main()) step_reader = STEPCAFControl_Reader() step_reader.SetColorMode(True) step_reader.SetLayerMode(True) step_reader.SetNameMode(True) step_reader.SetMatMode(True) status = step_reader.ReadFile(filename) if status == IFSelect_RetDone: step_reader.Transfer(doc) shape_tool.SetAutoNaming(True) #lvl = 0 locs = [] #cnt = 0 def _get_label_name(lab): entry = TCollection_AsciiString() TDF_Tool.Entry(lab, entry) n = TDataStd_Name() lab.FindAttribute(TDataStd_Name_GetID(), n) if n: return n.Get().PrintToString() return "No Name" def _get_sub_shapes(lab, loc): #global cnt, lvl #cnt += 1 #print("\n[%d] level %d, handling LABEL %s\n" % (cnt, lvl, _get_label_name(lab))) #print() #print(lab.DumpToString()) #print() #print("Is Assembly :", shape_tool.IsAssembly(lab)) #print("Is Free :", shape_tool.IsFree(lab)) #print("Is Shape :", shape_tool.IsShape(lab)) #print("Is Compound :", shape_tool.IsCompound(lab)) #print("Is Component :", shape_tool.IsComponent(lab)) #print("Is SimpleShape :", shape_tool.IsSimpleShape(lab)) #print("Is Reference :", shape_tool.IsReference(lab)) #users = TDF_LabelSequence() #users_cnt = shape_tool.GetUsers(lab, users) #print("Nr Users :", users_cnt) l_subss = TDF_LabelSequence() shape_tool.GetSubShapes(lab, l_subss) #print("Nb subshapes :", l_subss.Length()) l_comps = TDF_LabelSequence() shape_tool.GetComponents(lab, l_comps) #print("Nb components :", l_comps.Length()) #print() if shape_tool.IsAssembly(lab): l_c = TDF_LabelSequence() shape_tool.GetComponents(lab, l_c) for i in range(l_c.Length()): label = l_c.Value(i + 1) if shape_tool.IsReference(label): #print("\n######## reference label :", label) label_reference = TDF_Label() shape_tool.GetReferredShape(label, label_reference) loc = shape_tool.GetLocation(label) #print(" loc :", loc) #trans = loc.Transformation() #print(" tran form :", trans.Form()) #rot = trans.GetRotation() #print(" rotation :", rot) #print(" X :", rot.X()) #print(" Y :", rot.Y()) #print(" Z :", rot.Z()) #print(" W :", rot.W()) #tran = trans.TranslationPart() #print(" translation :", tran) #print(" X :", tran.X()) #print(" Y :", tran.Y()) #print(" Z :", tran.Z()) locs.append(loc) #print(">>>>") #lvl += 1 _get_sub_shapes(label_reference, loc) #lvl -= 1 #print("<<<<") locs.pop() elif shape_tool.IsSimpleShape(lab): #print("\n######## simpleshape label :", lab) shape = shape_tool.GetShape(lab) #print(" all ass locs :", locs) loc = TopLoc_Location() for i in range(len(locs)): #print(" take loc :", locs[i]) loc = loc.Multiplied(locs[i]) #trans = loc.Transformation() #print(" FINAL loc :") #print(" tran form :", trans.Form()) #rot = trans.GetRotation() #print(" rotation :", rot) #print(" X :", rot.X()) #print(" Y :", rot.Y()) #print(" Z :", rot.Z()) #print(" W :", rot.W()) #tran = trans.TranslationPart() #print(" translation :", tran) #print(" X :", tran.X()) #print(" Y :", tran.Y()) #print(" Z :", tran.Z()) shape = BRepBuilderAPI_Transform(shape, loc.Transformation()).Shape() c = Quantity_Color() # colorSet = False # if (color_tool.GetInstanceColor(shape, 0, c) or # color_tool.GetInstanceColor(shape, 1, c) or # color_tool.GetInstanceColor(shape, 2, c)): # for i in (0, 1, 2): # color_tool.SetInstanceColor(shape, i, c) # colorSet = True # n = c.Name(c.Red(), c.Green(), c.Blue()) # #print(' instance color Name & RGB: ', c, n, c.Red(), c.Green(), c.Blue()) # if not colorSet: color_tool.GetColor(lab, 0, c) color_tool.GetColor(lab, 1, c) color_tool.GetColor(lab, 2, c) #for i in (0, 1, 2): # color_tool.SetInstanceColor(shape, i, c) #n = c.Name(c.Red(), c.Green(), c.Blue()) #print(' shape color Name & RGB: ', c, n, c.Red(), c.Green(), c.Blue()) # for i in range(l_subss.Length()): # lab = l_subss.Value(i+1) # print("\n######## simpleshape subshape label :", lab) # shape_sub = shape_tool.GetShape(lab) # c = Quantity_Color() # colorSet = False # if (color_tool.GetInstanceColor(shape_sub, 0, c) or # color_tool.GetInstanceColor(shape_sub, 1, c) or # color_tool.GetInstanceColor(shape_sub, 2, c)): # for i in (0, 1, 2): # color_tool.SetInstanceColor(shape_sub, i, c) # colorSet = True # n = c.Name(c.Red(), c.Green(), c.Blue()) # #print(' instance color Name & RGB: ', c, n, c.Red(), c.Green(), c.Blue()) # if not colorSet: # if (color_tool.GetColor(lab, 0, c) or # color_tool.GetColor(lab, 1, c) or # color_tool.GetColor(lab, 2, c)): # for i in (0, 1, 2): # color_tool.SetInstanceColor(shape, i, c) # n = c.Name(c.Red(), c.Green(), c.Blue()) # #print(' shape color Name & RGB: ', c, n, c.Red(), c.Green(), c.Blue()) output_shapes.append([shape, _get_label_name(lab), c]) def _get_shapes(): labels = TDF_LabelSequence() shape_tool.GetFreeShapes(labels) #global cnt #cnt += 1 print() print("Number of shapes at root :", labels.Length()) print() root = labels.Value(1) _get_sub_shapes(root, None) _get_shapes() return output_shapes
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
def externalGeometryAssembly(self): # Create a TDoc holding the assembly of structure parts with external geometry. When assembled, write the STEP file # Initialize the writer shapes = [] step_writer = STEPCAFControl_Writer() step_writer.SetNameMode(True) step_writer.SetPropsMode(True) # create the handle to a document doc = TDocStd_Document(TCollection_ExtendedString("ocx-doc")) # Get root assembly shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) shape_tool.SetAutoNaming(False) l_colors = XCAFDoc_DocumentTool_ColorTool(doc.Main()) l_layers = XCAFDoc_DocumentTool_LayerTool(doc.Main()) l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main()) aBuilder = BRep_Builder() # Loop over all Panels panelchildren = [] for panel in self.model.panels: OCXCommon.LogMessage(panel, self.logging) guid = self.model.getGUID(panel) children = self.model.getPanelChildren(guid) panelchildren = panelchildren + children # Build the Panel compound compound = TopoDS_Compound() aBuilder.MakeCompound(compound) label = shape_tool.AddShape(compound) pname = panel.get('name') tname = TDataStd_Name() tname.Set(TCollection_ExtendedString(pname)) label.AddAttribute(tname) for child in children: object = self.model.getObject(child) name = object.get('name') extg = ExternalGeometry(self.model, object, self.dict, self.logging) # Init the creator extg.readExtGeometry() # Read the Brep if extg.IsDone(): aBuilder.Add(compound, extg.Shape()) tname = TDataStd_Name() label = shape_tool.AddShape(extg.Shape()) tname.Set(TCollection_ExtendedString(name)) label.AddAttribute(tname) # Root brackets compound = TopoDS_Compound() aBuilder.MakeCompound(compound) label = shape_tool.AddShape(compound) tname = TDataStd_Name() tname.Set(TCollection_ExtendedString('Brackets')) label.AddAttribute(tname) for br in self.model.brackets: guid = self.model.getGUID(br) name = br.get('name') if guid not in panelchildren: extg = ExternalGeometry(self.model, br, self.dict, self.logging) # Init the creator extg.readExtGeometry() # Read the Brep if extg.IsDone(): aBuilder.Add(compound, extg.Shape()) tname = TDataStd_Name() label = shape_tool.AddShape(extg.Shape()) tname.Set(TCollection_ExtendedString(name)) label.AddAttribute(tname) # Root plates compound = TopoDS_Compound() aBuilder.MakeCompound(compound) label = shape_tool.AddShape(compound) tname = TDataStd_Name() tname.Set(TCollection_ExtendedString('Plates')) label.AddAttribute(tname) for pl in self.model.plates: guid = self.model.getGUID(pl) name = pl.get('name') if guid not in panelchildren: extg = ExternalGeometry(self.model, pl, self.dict, self.logging) # Init the creator extg.readExtGeometry() # Read the Brep if extg.IsDone(): aBuilder.Add(compound, extg.Shape()) tname = TDataStd_Name() label = shape_tool.AddShape(extg.Shape()) tname.Set(TCollection_ExtendedString(name)) label.AddAttribute(tname) # Root pillars compound = TopoDS_Compound() aBuilder.MakeCompound(compound) label = shape_tool.AddShape(compound) tname = TDataStd_Name() tname.Set(TCollection_ExtendedString('Pillars')) label.AddAttribute(tname) for pil in self.model.pillars: guid = self.model.getGUID(pil) name = pil.get('name') if guid not in panelchildren: extg = ExternalGeometry(self.model, pil, self.dict, self.logging) # Init the creator extg.readExtGeometry() # Read the Brep if extg.IsDone(): aBuilder.Add(compound, extg.Shape()) tname = TDataStd_Name() label = shape_tool.AddShape(extg.Shape()) tname.Set(TCollection_ExtendedString(name)) label.AddAttribute(tname) step_writer.Perform( doc, TCollection_AsciiString(self.model.ocxfile.stem + '.stp')) return
def read_file(self): """Build self.tree (treelib.Tree()) containing CAD data read from a step file. Each node of self.tree contains the following: (Name, UID, ParentUID, {Data}) where the Data keys are: 'a' (isAssy?), 'l' (TopLoc_Location), 'c' (Quantity_Color), 's' (TopoDS_Shape) """ logger.info("Reading STEP file") doc = TDocStd_Document(TCollection_ExtendedString("STEP")) # Create the application app = XCAFApp_Application_GetApplication() app.NewDocument(TCollection_ExtendedString("MDTV-CAF"), doc) # Get root shapes shape_tool = XCAFDoc_DocumentTool_ShapeTool(doc.Main()) shape_tool.SetAutoNaming(True) self.color_tool = XCAFDoc_DocumentTool_ColorTool(doc.Main()) layer_tool = XCAFDoc_DocumentTool_LayerTool(doc.Main()) l_materials = XCAFDoc_DocumentTool_MaterialTool(doc.Main()) step_reader = STEPCAFControl_Reader() step_reader.SetColorMode(True) step_reader.SetLayerMode(True) step_reader.SetNameMode(True) step_reader.SetMatMode(True) status = step_reader.ReadFile(self.filename) if status == IFSelect_RetDone: logger.info("Transfer doc to STEPCAFControl_Reader") step_reader.Transfer(doc) # Test round trip by writing doc back to another file. logger.info("Doing a 'short-circuit' Round Trip test") doctype = type(doc) # <class 'OCC.Core.TDocStd.TDocStd_Document'> logger.info(f"Writing {doctype} back to another STEP file") self.testRTStep(doc) # Save doc to file (for educational purposes) (not working yet) logger.debug("Saving doc to file") savefilename = TCollection_ExtendedString('../doc.txt') app.SaveAs(doc, savefilename) labels = TDF_LabelSequence() color_labels = TDF_LabelSequence() shape_tool.GetShapes(labels) self.shape_tool = shape_tool logger.info('Number of labels at root : %i' % labels.Length()) try: label = labels.Value(1) # First label at root except RuntimeError: return name = self.getName(label) logger.info('Name of root label: %s' % name) isAssy = shape_tool.IsAssembly(label) logger.info("First label at root holds an assembly? %s" % isAssy) if isAssy: # If first label at root holds an assembly, it is the Top Assembly. # Through this label, the entire assembly is accessible. # No need to examine other labels at root explicitly. topLoc = TopLoc_Location() topLoc = shape_tool.GetLocation(label) self.assyLocStack.append(topLoc) entry = label.EntryDumpToString() logger.debug("Entry: %s" % entry) logger.debug("Top assy name: %s" % name) # Create root node for top assy newAssyUID = self.getNewUID() self.tree.create_node(name, newAssyUID, None, { 'a': True, 'l': None, 'c': None, 's': None }) self.assyUidStack.append(newAssyUID) topComps = TDF_LabelSequence() # Components of Top Assy subchilds = False isAssy = shape_tool.GetComponents(label, topComps, subchilds) logger.debug("Is Assembly? %s" % isAssy) logger.debug("Number of components: %s" % topComps.Length()) logger.debug("Is Reference? %s" % shape_tool.IsReference(label)) if topComps.Length(): self.findComponents(label, topComps) else: # Labels at root can hold solids or compounds (which are 'crude' assemblies) # Either way, we will need to create a root node in self.tree newAssyUID = self.getNewUID() self.tree.create_node(os.path.basename(self.filename), newAssyUID, None, { 'a': True, 'l': None, 'c': None, 's': None }) self.assyUidStack = [newAssyUID] for j in range(labels.Length()): label = labels.Value(j + 1) name = self.getName(label) isAssy = shape_tool.IsAssembly(label) logger.debug("Label %i is assembly?: %s" % (j + 1, isAssy)) shape = shape_tool.GetShape(label) color = self.getColor(shape) isSimpleShape = self.shape_tool.IsSimpleShape(label) logger.debug("Is Simple Shape? %s" % isSimpleShape) shapeType = shape.ShapeType() logger.debug("The shape type is: %i" % shapeType) if shapeType == 0: logger.debug( "The shape type is OCC.Core.TopAbs.TopAbs_COMPOUND") topo = TopologyExplorer(shape) #topo = aocutils.topology.Topo(shape) logger.debug("Nb of compounds : %i" % topo.number_of_compounds()) logger.debug("Nb of solids : %i" % topo.number_of_solids()) logger.debug("Nb of shells : %i" % topo.number_of_shells()) newAssyUID = self.getNewUID() for i, solid in enumerate(topo.solids()): name = "P%s" % str(i + 1) self.tree.create_node(name, self.getNewUID(), self.assyUidStack[-1], { 'a': False, 'l': None, 'c': color, 's': solid }) elif shapeType == 2: logger.debug( "The shape type is OCC.Core.TopAbs.TopAbs_SOLID") self.tree.create_node(name, self.getNewUID(), self.assyUidStack[-1], { 'a': False, 'l': None, 'c': color, 's': shape }) elif shapeType == 3: logger.debug( "The shape type is OCC.Core.TopAbs.TopAbs_SHELL") self.tree.create_node(name, self.getNewUID(), self.assyUidStack[-1], { 'a': False, 'l': None, 'c': color, 's': shape }) return True