def openDocument(self, _fileName): fileName = _fileName if a2plib.PYVERSION == 3: fileName = a2plib.to_str(fileName) self.clear() # got a fileName != None ? if fileName is None: print(u"fcDocumentReader: failed to open file with None name!") return # check whether file exists or not... if not os.path.exists(fileName): print( u"fcDocumentReader: file {} does not exist!".format(fileName)) return # check for fcstd file if not fileName.lower().endswith(a2plib.to_str('.fcstd')): print(u"fcDocumentReader: file {} is no FCStd file!".format( fileName)) return # decompress the file f = zipfile.ZipFile(fileName, 'r') xml = f.read('Document.xml') f.close() self.successfulOpened = True # #self.xmlLines = xml.split("\r\n") #Windows self.xmlLines = xml.split(b'\r\n') #Windows if len(self.xmlLines) <= 1: self.xmlLines = xml.split(b"\n") #Linux del (xml) # remove not needed data above first section <objects name=... idx = 0 for line in self.xmlLines: if line.lstrip(b' ').startswith(b'<Object name'): break else: idx += 1 self.xmlLines = self.xmlLines[idx:] #reduce list size instantly while len(self.xmlLines) > 0: if not self.xmlLines[0].strip(b' ').startswith(b'<Object name'): break ob = simpleXMLObject() self.xmlLines = ob.initialize(self.xmlLines) self.objects.append(ob) # remove not needed objects tmp = [] for ob in self.objects: if ob.isA2pObject() or ob.isSpreadSheet(): tmp.append(ob) self.objects = tmp
def visualizeHierarchy(self): ''' generate a html file with constraints structure. The html file is in the same folder with the same filename of the assembly ''' out_file = os.path.splitext(self.doc.FileName)[0] + '_asm_hierarchy.html' Msg("Writing visual hierarchy to: {}\n".format(out_file)) f = open(out_file, "w") f.write("<!DOCTYPE html>\n") f.write("<html>\n") f.write("<head>\n") f.write(' <meta charset="utf-8">\n') f.write(' <meta http-equiv="X-UA-Compatible" content="IE=edge">\n') f.write(' <title>A2P assembly hierarchy visualization</title>\n') f.write("</head>\n") f.write("<body>\n") f.write('<div class="mermaid">\n') f.write("graph TD\n") for rig in self.rigids: rigLabel = a2plib.to_str(rig.label).replace(u' ',u'_') # No children, add current rogod as a leaf entry if len(rig.childRigids) == 0: message = u"{}\n".format(rigLabel) if a2plib.PYVERSION < 3: f.write(a2plib.to_bytes(message)) else: f.write(message) else: # Rigid have children, add them based on the dependency list for d in rig.dependencies: if d.dependedRigid in rig.childRigids: dependedRigLabel = a2plib.to_str(d.dependedRigid.label).replace(u' ',u'_') if rig.fixed: message = u"{}({}<br>*FIXED*) -- {} --> {}\n".format(rigLabel, rigLabel, d.Type, dependedRigLabel) if a2plib.PYVERSION < 3: f.write(a2plib.to_bytes(message)) else: f.write(message) else: message = u"{} -- {} --> {}\n".format(rigLabel, d.Type, dependedRigLabel) if a2plib.PYVERSION < 3: f.write(a2plib.to_bytes(message)) else: f.write(message) f.write("</div>\n") f.write(' <script src="https://unpkg.com/[email protected]/dist/mermaid.js"></script>\n') f.write(" <script>\n") f.write(' mermaid.initialize({startOnLoad: true});\n') f.write(" </script>\n") f.write("</body>") f.write("</html>") f.close()
def createPartList( importPath, parentAssemblyDir, partListEntries, recursive=False ): ''' Extract quantities and descriptions of assembled parts from document.xml Is able to analyse subassemblies by recursion It works with a dict. Structure of an entry is: filename: [Quantity,[information,information,....] ] ''' fileNameInProject = a2plib.findSourceFileInProject( importPath, parentAssemblyDir ) workingDir,basicFileName = os.path.split(fileNameInProject) docReader1 = FCdocumentReader() docReader1.openDocument(fileNameInProject) for ob in docReader1.getA2pObjects(): # skip converted parts... if a2plib.to_str(ob.getA2pSource()) == a2plib.to_str('converted'): continue if ob.isSubassembly() and recursive: partListEntries = createPartList( ob.getA2pSource(), workingDir, partListEntries, recursive ) # Process information of this a2p object if not ob.isSubassembly() or not recursive: # Try to get spreadsheetdata _PARTINFO_ from linked source linkedSource1 = ob.getA2pSource() linkedSource = a2plib.findSourceFileInProject( #this returns unicode on py2 systems! linkedSource1, workingDir ) if linkedSource == None: print(u"BOM ERROR: Could not open sourcefile {}".format(linkedSource1)) continue # Is it already processed minimum one time ? entry = partListEntries.get(linkedSource,None) if entry != None: partListEntries.get(linkedSource)[0]+=1 #count sourcefile usage continue # only needed to count imports of this file, information exists yet # There is no entry in dict, need to read out information from importFile... docReader2 = FCdocumentReader() docReader2.openDocument(linkedSource) # Initialize a default parts information... partInformation = [] for i in range(0,len(PARTLIST_COLUMN_NAMES)): partInformation.append("*") # if there is a proper spreadsheet, then read it... for ob in docReader2.getSpreadsheetObjects(): sheetName = PARTINFORMATION_SHEET_NAME if a2plib.PYVERSION > 2: sheetName = a2plib.to_bytes(PARTINFORMATION_SHEET_NAME) if ob.name == sheetName: cells = ob.getCells() for addr in cells.keys(): if addr[:1] == b'B': #column B contains the data, A only the titles idx = int(addr[1:])-1 if idx < len(PARTLIST_COLUMN_NAMES): # don't read further! partInformation[idx] = cells[addr] # last entry of partinformations is reserved for filename partInformation[-1] = os.path.split(linkedSource)[1] #without complete path... # put information to dict and count usage of sourcefiles.. entry = partListEntries.get(linkedSource,None) if entry == None: partListEntries[linkedSource] = [ 1, partInformation ] else: partListEntries.get(linkedSource)[0]+=1 #count sourcefile usage return partListEntries
def scanForProperties(self): sourceFileFound = False a2pVersionFound = False subAssemblyImportFound = False timeLastImportFound = False spreadSheetCellsFound = False a2pObjectTypeFound = False numLines = len(self.xmlDefs) # Readout object's name and save it (1rst line) if numLines > 0: line = self.xmlDefs[0] segments = line.split(b'"') self.name = segments[1] idx = 0 while idx<numLines: line = self.xmlDefs[idx] if not sourceFileFound and line.startswith(b'<Property name="sourceFile"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') fileName = segments[1] self.propertyDict[b'sourceFile'] = a2plib.to_str(fileName) sourceFileFound = True elif not a2pVersionFound and line.startswith(b'<Property name="a2p_Version"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') a2pVersion = segments[1] self.propertyDict[b'a2p_Version'] = a2plib.to_str(a2pVersion) a2pVersionFound = True elif not a2pVersionFound and line.startswith(b'<Property name="assembly2Version"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') a2pVersion = segments[1] self.propertyDict[b'a2p_Version'] = a2plib.to_str(a2pVersion) a2pVersionFound = True # for very old a2p versions do additionally... elif not subAssemblyImportFound and line.startswith(b'<Property name="subassemblyImport"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') tmp = segments[1] val = True if tmp == b"false": val = False self.propertyDict[b'subassemblyImport'] = val subAssemblyImportFound = True elif not timeLastImportFound and line.startswith(b'<Property name="timeLastImport"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') tmp = segments[1] floatVal = float(tmp) self.propertyDict[b'timeLastImport'] = floatVal timeLastImportFound = True elif not spreadSheetCellsFound and line.startswith(b'<Property name="cells" type="Spreadsheet::PropertySheet"'): spreadSheetCellsFound = True idx += 2 cellDict = {} while True: line = self.xmlDefs[idx] if line.startswith(b'</Cells>'): break if line.startswith(b'<Cell address="'): cellAdress,cellContent = self.parseCellLine(line) cellDict[cellAdress] = a2plib.to_str(cellContent) idx += 1 self.propertyDict[b'cells'] = cellDict elif not a2pObjectTypeFound and line.startswith(b'<Property name="objectType"'): idx+=1 line = self.xmlDefs[idx] segments = line.split(b'"') objectType = segments[1] self.propertyDict[b'objectType'] = a2plib.to_bytes(objectType) a2pObjectTypeFound = True idx+=1 self.xmlDefs = [] # we are done, free memory...