Exemplo n.º 1
0
    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()
Exemplo n.º 2
0
def createUpdateFileList(
        importPath,
        parentAssemblyDir,
        filesToUpdate,
        recursive=False,
        selectedFiles=[]  #only update parts with these sourceFiles
):

    # do not update converted parts
    print("createUpdateFileList importPath = {}".format(importPath))
    if a2plib.to_bytes(importPath) == b'converted':
        return False, filesToUpdate

    fileNameInProject = a2plib.findSourceFileInProject(importPath,
                                                       parentAssemblyDir)
    workingDir, basicFileName = os.path.split(fileNameInProject)
    docReader1 = FCdocumentReader()

    docReader1.openDocument(fileNameInProject)
    needToUpdate = False
    subAsmNeedsUpdate = False
    for ob in docReader1.getA2pObjects():

        if a2plib.to_bytes(ob.getA2pSource()) == b'converted':
            print("Did not update converted part '{}'".format(ob.name))
            continue

        #Only update parts which are selected by the user...
        fDir, fName = os.path.split(ob.getA2pSource())
        if len(selectedFiles) > 0 and fName not in selectedFiles:
            continue

        if ob.isSubassembly() and recursive:
            subAsmNeedsUpdate, filesToUpdate = createUpdateFileList(
                ob.getA2pSource(), workingDir, filesToUpdate, recursive)
        if subAsmNeedsUpdate:
            needToUpdate = True

        objFileNameInProject = a2plib.findSourceFileInProject(
            ob.getA2pSource(), workingDir)
        mtime = os.path.getmtime(objFileNameInProject)
        if ob.getTimeLastImport() < mtime:
            needToUpdate = True

    if needToUpdate:
        if fileNameInProject not in filesToUpdate:
            filesToUpdate.append(fileNameInProject)

    return needToUpdate, filesToUpdate
Exemplo n.º 3
0
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
Exemplo n.º 4
0
 def Activated(self):
     doc = FreeCAD.activeDocument()
     if doc == None:
         QtGui.QMessageBox.information(  QtGui.QApplication.activeWindow(),
                                     u"No active document found!",
                                     u"You have to open a FCStd file first."
                                 )
         return
     completeFilePath = doc.FileName
     p,f = os.path.split(completeFilePath)
     
     flags = QtGui.QMessageBox.StandardButton.Yes | QtGui.QMessageBox.StandardButton.No
     msg = u"Please save before generating a parts list!\nSave now ?"
     response = QtGui.QMessageBox.information(QtGui.QApplication.activeWindow(), u"Save document?", msg, flags )
     if response == QtGui.QMessageBox.No:
         QtGui.QMessageBox.information(  QtGui.QApplication.activeWindow(),
                                     u"Parts list generation aborted!",
                                     u"You have to save the assembly file first."
                                 )
         return
     else:
         doc.save()
     
     flags = QtGui.QMessageBox.StandardButton.Yes | QtGui.QMessageBox.StandardButton.No
     msg = u"Do you want to iterate recursively over all included subassemblies?"
     response = QtGui.QMessageBox.information(QtGui.QApplication.activeWindow(), u"PARTSLIST", msg, flags )
     if response == QtGui.QMessageBox.Yes:
         subAssyRecursion = True
     else:
         subAssyRecursion = False
     
     partListEntries = createPartList(
         doc.FileName,
         p,
         {},
         recursive=subAssyRecursion
         )
     
     ss = None
     try:
         ss = doc.getObject(BOM_SHEET_NAME)
     except:
         pass
     if ss == None:
         ss = doc.addObject('Spreadsheet::Sheet',BOM_SHEET_NAME)
         ss.Label = BOM_SHEET_LABEL
     else:
         self.clearPartList()
     
     # Write Column headers to spreadsheet
     ss.set('A1',u'POS')
     ss.set('B1',u'QTY')
     idx1 = ord('C')
     idx2 = idx1 + len(PARTLIST_COLUMN_NAMES)
     i=0
     for c in range(idx1,idx2):
         ss.set(chr(c)+"1",PARTLIST_COLUMN_NAMES[i])
         i+=1
     # Set the background color of the column headers
     ss.setBackground('A1:'+chr(idx2-1)+'1', (0.000000,1.000000,0.000000,1.000000))
     # Set the columnwith to proper values
     ss.setColumnWidth('A',40)
     i=0
     for c in range(idx1,idx2):
         ss.setColumnWidth(chr(c),150)
         i+=1
     # fill entries for partsList...
     idx3 = ord('A')
     for idx, k in enumerate(partListEntries.keys()):
         ss.set('A'+str(idx+2),str(idx+1))
         ss.set('B'+str(idx+2),str(partListEntries[k][0]))
         values = partListEntries[k][1]
         for j,tx in enumerate(values): # all strings inside values are unicode!
             #ss.set needs 2. argument as unicode for py3 and utf-8 string for py2!!!
             if a2plib.PYVERSION > 2:
                 tx2 = tx # preserve unicode
             else:
                 tx2 = a2plib.to_bytes(tx) # convert to utf-8
             ss.set(chr(idx3+2+j)+str(idx+2),tx2)
     
     # recompute to finish..
     doc.recompute()
     print("#PARTSLIST# spreadsheet has been created")
Exemplo n.º 5
0
 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...