def muxAssemblyWithTopoNames(doc, desiredShapeLabel=None): ''' Mux an a2p assenbly combines all the a2p objects in the doc into one shape and populates muxinfo with a description of an edge or face. these descriptions are used later to retrieve the edges or faces... ''' faces = [] faceColors = [] muxInfo = [] # List of keys, not used at moment... visibleObjects = [ obj for obj in doc.Objects if hasattr(obj, 'ViewObject') and obj.ViewObject.isVisible() and hasattr(obj, 'Shape') and len(obj.Shape.Faces) > 0 and hasattr(obj, 'muxInfo') ] if desiredShapeLabel: # is not None.. tmp = [] for ob in visibleObjects: if ob.Label == desiredShapeLabel: tmp.append(ob) break visibleObjects = tmp transparency = 0 shape_list = [] for obj in visibleObjects: extendNames = False if a2plib.getUseTopoNaming() and len( obj.muxInfo) > 0: # Subelement-Strings existieren schon... extendNames = True # vertexNames = [] edgeNames = [] faceNames = [] # for item in obj.muxInfo: if item[0] == 'V': vertexNames.append(item) if item[0] == 'E': edgeNames.append(item) if item[0] == 'F': faceNames.append(item) if a2plib.getUseTopoNaming(): for i in range(0, len(obj.Shape.Vertexes)): if extendNames: newName = "".join((vertexNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('V;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) for i in range(0, len(obj.Shape.Edges)): if extendNames: newName = "".join((edgeNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('E;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) # Save Computing time, store this before the for..enumerate loop later... needDiffuseColorExtension = (len(obj.ViewObject.DiffuseColor) < len( obj.Shape.Faces)) shapeCol = obj.ViewObject.ShapeColor diffuseCol = obj.ViewObject.DiffuseColor tempShape = makePlacedShape(obj) transparency = obj.ViewObject.Transparency shape_list.append(obj.Shape) # now start the loop with use of the stored values..(much faster) topoNaming = a2plib.getUseTopoNaming() diffuseElement = makeDiffuseElement(shapeCol, transparency) for i in range(0, len(tempShape.Faces)): if topoNaming: if extendNames: newName = "".join((faceNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('F;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) if needDiffuseColorExtension: faceColors.append(diffuseElement) if not needDiffuseColorExtension: faceColors.extend(diffuseCol) faces.extend(tempShape.Faces) #if len(faces) == 1: # shell = Part.makeShell([faces]) #else: # shell = Part.makeShell(faces) shell = Part.makeShell(faces) try: if a2plib.getUseSolidUnion(): if len(shape_list) > 1: shape_base = shape_list[0] shapes = shape_list[1:] solid = shape_base.fuse(shapes) else: solid = Part.Solid(shape_list[0]) else: solid = Part.Solid( shell ) # This does not work if shell includes spherical faces. FC-Bug ?? # Fall back to shell if some faces are missing.. if len(shell.Faces) != len(solid.Faces): solid = shell except: # keeping a shell if solid is failing FreeCAD.Console.PrintWarning('Union of Shapes FAILED\n') solid = shell # transparency could change to different values depending # on the order of imported objects # now set it to a default value # faceColors still contains the per face transparency values transparency = 0 return muxInfo, solid, faceColors, transparency
def createTopoNames(self, desiredShapeLabel = None): ''' creates a combined shell of all toplevel objects and assigns toponames to its geometry if toponaming is enabled. ''' self.detectPartDesignDocument() self.getTopLevelObjects() # filter topLevelShapes if there is a desiredShapeLabel # means: extract only one desired shape out of whole file... if desiredShapeLabel: #is not None tmp = [] for objName in self.topLevelShapes: o = self.doc.getObject(objName) if o.Label == desiredShapeLabel: tmp.append(o.Name) self.topLevelShapes = tmp #------------------------------------------- # analyse the toplevel shapes #------------------------------------------- if a2plib.getUseTopoNaming(): for n in self.topLevelShapes: self.totalNumVertexes = 0 self.totalNumEdges = 0 self.totalNumFaces = 0 self.processTopoData(n) # analyse each toplevel object... # #------------------------------------------- # MUX the toplevel shapes #------------------------------------------- faces = [] faceColors = [] transparency = 0 shape_list = [] for objName in self.topLevelShapes: ob = self.doc.getObject(objName) needDiffuseExtension = ( len(ob.ViewObject.DiffuseColor) < len(ob.Shape.Faces) ) shapeCol = ob.ViewObject.ShapeColor diffuseCol = ob.ViewObject.DiffuseColor tempShape = self.makePlacedShape(ob) transparency = ob.ViewObject.Transparency shape_list.append(ob.Shape) if needDiffuseExtension: diffuseElement = a2plib.makeDiffuseElement(shapeCol,transparency) for i in range(0,len(tempShape.Faces)): faceColors.append(diffuseElement) else: faceColors.extend(diffuseCol) #let python libs extend faceColors, much faster faces.extend(tempShape.Faces) #let python libs extend faces, much faster shell = Part.makeShell(faces) try: if a2plib.getUseSolidUnion(): if len(shape_list) > 1: shape_base=shape_list[0] shapes=shape_list[1:] solid = shape_base.fuse(shapes) else: #one shape only solid = Part.Solid(shape_list[0]) else: solid = Part.Solid(shell) # fails with missing faces if shell contains spheres if len(shell.Faces) != len(solid.Faces): solid = shell # fall back to shell if faces are missing except: # keeping a shell if solid is failing FreeCAD.Console.PrintWarning('Union of Shapes FAILED\n') solid = shell #------------------------------------------- # if toponaming is used, assign toponames to # shells geometry #------------------------------------------- muxInfo = [] if a2plib.getUseTopoNaming(): #------------------------------------------- # map vertexnames to the MUX #------------------------------------------- muxInfo.append("[VERTEXES]") for i,v in enumerate(solid.Vertexes): k = self.calcVertexKey(v) name = self.shapeDict.get(k,"None") muxInfo.append(name) #------------------------------------------- # map edgenames to the MUX #------------------------------------------- muxInfo.append("[EDGES]") pl = FreeCAD.Placement() for i,edge in enumerate(solid.Edges): keys = self.calcEdgeKeys(edge, pl) name = self.shapeDict.get(keys[0],"None") muxInfo.append(name) #------------------------------------------- # map facenames to the MUX #------------------------------------------- muxInfo.append("[FACES]") pl = FreeCAD.Placement() for i,face in enumerate(solid.Faces): keys = self.calcFaceKeys(face, pl) name = self.shapeDict.get(keys[0],"None") muxInfo.append(name) return muxInfo, solid, faceColors, transparency
def createTopoNames(self, withColor=False): ''' creates a combined shell of all toplevel objects and assigns toponames to its geometry if toponaming is enabled. ''' self.getTopLevelObjects() #------------------------------------------- # analyse the toplevel shapes #------------------------------------------- if a2plib.getUseTopoNaming(): for n in self.topLevelShapes: self.totalNumVertexes = 0 self.totalNumEdges = 0 self.totalNumFaces = 0 self.processTopoData(n) # analyse each toplevel object... # #------------------------------------------- # MUX the toplevel shapes #------------------------------------------- faces = [] faceColors = [] for objName in self.topLevelShapes: ob = self.doc.getObject(objName) colorFlag = (len(ob.ViewObject.DiffuseColor) < len(ob.Shape.Faces)) shapeCol = ob.ViewObject.ShapeColor diffuseCol = ob.ViewObject.DiffuseColor tempShape = self.makePlacedShape(ob) # now start the loop with use of the stored values..(much faster) for i, face in enumerate(tempShape.Faces): faces.append(face) if withColor: if colorFlag: faceColors.append(shapeCol) else: faceColors.append(diffuseCol[i]) shell = Part.makeShell(faces) #------------------------------------------- # if toponaming is used, assign toponames to # shells geometry #------------------------------------------- muxInfo = [] if a2plib.getUseTopoNaming(): #------------------------------------------- # map vertexnames to the MUX #------------------------------------------- muxInfo.append("[VERTEXES]") for i, v in enumerate(shell.Vertexes): k = self.calcVertexKey(v) name = self.shapeDict.get(k, "None") muxInfo.append(name) #------------------------------------------- # map edgenames to the MUX #------------------------------------------- muxInfo.append("[EDGES]") pl = FreeCAD.Placement() for i, edge in enumerate(shell.Edges): keys = self.calcEdgeKeys(edge, pl) name = self.shapeDict.get(keys[0], "None") muxInfo.append(name) #------------------------------------------- # map facenames to the MUX #------------------------------------------- muxInfo.append("[FACES]") pl = FreeCAD.Placement() for i, face in enumerate(shell.Faces): keys = self.calcFaceKeys(face, pl) name = self.shapeDict.get(keys[0], "None") muxInfo.append(name) if withColor: return muxInfo, shell, faceColors else: return muxInfo, shell
def createTopoNames(self, desiredShapeLabel=None): ''' creates a combined shell of all toplevel objects and assigns toponames to its geometry if toponaming is enabled. ''' if desiredShapeLabel is not None: allowSketches = True else: allowSketches = False self.detectPartDesignDocument() self.getTopLevelObjects(allowSketches) # filter topLevelShapes if there is a desiredShapeLabel # means: extract only one desired shape out of whole file... if desiredShapeLabel: #is not None tmp = [] for objName in self.topLevelShapes: o = self.doc.getObject(objName) if o.Label == desiredShapeLabel: tmp.append(o.Name) self.topLevelShapes = tmp #------------------------------------------- # analyse the toplevel shapes #------------------------------------------- if a2plib.getUseTopoNaming(): for n in self.topLevelShapes: self.totalNumVertexes = 0 self.totalNumEdges = 0 self.totalNumFaces = 0 self.processTopoData(n) # analyse each toplevel object... # #------------------------------------------- # MUX the toplevel shapes #------------------------------------------- faces = [] faceColors = [] transparency = 0 shape_list = [] if len(self.topLevelShapes) == 1 and self.topLevelShapes[0].startswith( "Sketch"): importingSketch = True else: importingSketch = False if importingSketch == True: # We are importing a sketch object objName = self.topLevelShapes[0] sketchOb = self.doc.getObject(objName) solid = sketchOb.Shape else: # We are importing no sketch object for objName in self.topLevelShapes: ob = self.doc.getObject(objName) tempShape = self.makePlacedShape(ob) faces.extend(tempShape.Faces ) #let python libs extend faces, much faster #manage colors of faces if ob.ViewObject.TypeId == "Gui::ViewProviderLinkPython": # a link is involved... linkedObject = self.getLinkedObjectRecursive(ob) needDiffuseExtension = (len( linkedObject.ViewObject.DiffuseColor) < len( linkedObject.Shape.Faces)) shapeCol = linkedObject.ViewObject.ShapeColor diffuseCol = linkedObject.ViewObject.DiffuseColor transparency = linkedObject.ViewObject.Transparency shape_list.append(ob.Shape) if needDiffuseExtension: diffuseElement = a2plib.makeDiffuseElement( shapeCol, transparency) for i in range(0, len(tempShape.Faces)): faceColors.append(diffuseElement) else: count = len(ob.Shape.Faces) // len( linkedObject.Shape.Faces) for c in range( 0, count ): # add colors to multiple representations of linkedObject faceColors.extend(diffuseCol) else: # no link is involved... needDiffuseExtension = (len(ob.ViewObject.DiffuseColor) < len(ob.Shape.Faces)) shapeCol = ob.ViewObject.ShapeColor diffuseCol = ob.ViewObject.DiffuseColor transparency = ob.ViewObject.Transparency shape_list.append(ob.Shape) if needDiffuseExtension: diffuseElement = a2plib.makeDiffuseElement( shapeCol, transparency) for i in range(0, len(tempShape.Faces)): faceColors.append(diffuseElement) else: faceColors.extend( diffuseCol ) #let python libs extend faceColors, much faster shell = Part.makeShell(faces) try: if a2plib.getUseSolidUnion(): if len(shape_list) > 1: shape_base = shape_list[0] shapes = shape_list[1:] solid = shape_base.fuse(shapes) else: #one shape only solid = Part.Solid(shape_list[0]) else: solid = Part.Solid( shell ) # fails with missing faces if shell contains spheres if len(shell.Faces) != len(solid.Faces): solid = shell # fall back to shell if faces are missing except: # keeping a shell if solid is failing FreeCAD.Console.PrintWarning('Union of Shapes FAILED\n') solid = shell #------------------------------------------- # if toponaming is used, assign toponames to # shells geometry #------------------------------------------- muxInfo = [] if a2plib.getUseTopoNaming(): #------------------------------------------- # map vertexnames to the MUX #------------------------------------------- muxInfo.append("[VERTEXES]") for i, v in enumerate(solid.Vertexes): k = self.calcVertexKey(v) defaultVal = "V;NONAME;{};".format(i) name = self.shapeDict.get(k, defaultVal) muxInfo.append(name) #------------------------------------------- # map edgenames to the MUX #------------------------------------------- muxInfo.append("[EDGES]") pl = FreeCAD.Placement() for i, edge in enumerate(solid.Edges): keys = self.calcEdgeKeys(edge, pl) defaultVal = "E;NONAME;{};".format(i) name = self.shapeDict.get(keys[0], defaultVal) muxInfo.append(name) #------------------------------------------- # map facenames to the MUX #------------------------------------------- muxInfo.append("[FACES]") pl = FreeCAD.Placement() for i, face in enumerate(solid.Faces): keys = self.calcFaceKeys(face, pl) defaultVal = "F;NONAME;{};".format(i) name = self.shapeDict.get(keys[0], defaultVal) muxInfo.append(name) return muxInfo, solid, faceColors, transparency
def muxAssemblyWithTopoNames(doc, withColor=False): ''' Mux an a2p assenbly combines all the a2p objects in the doc into one shape and populates muxinfo with a description of an edge or face. these descriptions are used later to retrieve the edges or faces... ''' faces = [] faceColors = [] muxInfo = [] # List of keys, not used at moment... visibleObjects = [ obj for obj in doc.Objects if hasattr(obj, 'ViewObject') and obj.ViewObject.isVisible() and hasattr(obj, 'Shape') and len(obj.Shape.Faces) > 0 and hasattr(obj, 'muxInfo') ] for obj in visibleObjects: # extendNames = False if a2plib.getUseTopoNaming() and len( obj.muxInfo) > 0: # Subelement-Strings existieren schon... extendNames = True # vertexNames = [] edgeNames = [] faceNames = [] # for item in obj.muxInfo: if item[0] == 'V': vertexNames.append(item) if item[0] == 'E': edgeNames.append(item) if item[0] == 'F': faceNames.append(item) if a2plib.getUseTopoNaming(): for i in range(0, len(obj.Shape.Vertexes)): if extendNames: newName = "".join((vertexNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('V;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) for i in range(0, len(obj.Shape.Edges)): if extendNames: newName = "".join((edgeNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('E;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) # Save Computing time, store this before the for..enumerate loop later... colorFlag = (len(obj.ViewObject.DiffuseColor) < len(obj.Shape.Faces)) shapeCol = obj.ViewObject.ShapeColor diffuseCol = obj.ViewObject.DiffuseColor tempShape = makePlacedShape(obj) # now start the loop with use of the stored values..(much faster) topoNaming = a2plib.getUseTopoNaming() for i, face in enumerate(tempShape.Faces): faces.append(face) if topoNaming: if extendNames: newName = "".join((faceNames[i], obj.Name, ';')) muxInfo.append(newName) else: newName = "".join(('F;', str(i + 1), ';', obj.Name, ';')) muxInfo.append(newName) if withColor: if colorFlag: faceColors.append(shapeCol) else: faceColors.append(diffuseCol[i]) shell = Part.makeShell(faces) if withColor: return muxInfo, shell, faceColors else: return muxInfo, shell
def updateImportedParts(doc): if doc == None: QtGui.QMessageBox.information( QtGui.QApplication.activeWindow(), "No active document found!", "Before updating parts, you have to open an assembly file.") return # modififying object's subelements causes solving of the assembly, disable autosolve here autoSolveState = a2plib.getAutoSolveState() a2plib.setAutoSolve(False) doc.openTransaction("updateImportParts") objectCache.cleanUp(doc) for obj in doc.Objects: if hasattr(obj, 'sourceFile'): if not hasattr(obj, 'timeLastImport'): obj.addProperty( "App::PropertyFloat", "timeLastImport", "importPart" ) #should default to zero which will force update. obj.setEditorMode("timeLastImport", 1) if not hasattr(obj, 'a2p_Version'): obj.addProperty("App::PropertyString", "a2p_Version", "importPart").a2p_Version = 'V0.0' obj.setEditorMode("a2p_Version", 1) if not hasattr(obj, 'muxInfo'): obj.addProperty("App::PropertyStringList", "muxInfo", "importPart").muxInfo = [] assemblyPath = os.path.normpath(os.path.split(doc.FileName)[0]) absPath = a2plib.findSourceFileInProject(obj.sourceFile, assemblyPath) if absPath == None: QtGui.QMessageBox.critical( QtGui.QApplication.activeWindow(), u"Source file not found", u"Unable to find {}".format(obj.sourceFile)) if absPath != None and os.path.exists(absPath): newPartCreationTime = os.path.getmtime(absPath) if (newPartCreationTime > obj.timeLastImport or obj.a2p_Version != A2P_VERSION): if not objectCache.isCached( absPath ): # Load every changed object one time to cache importPartFromFile(doc, absPath, importToCache=True ) # the version is now in the cache newObject = objectCache.get(absPath) obj.timeLastImport = newPartCreationTime if hasattr(newObject, 'a2p_Version'): obj.a2p_Version = A2P_VERSION importUpdateConstraintSubobjects( doc, obj, newObject) # do this before changing shape and mux if hasattr(newObject, 'muxInfo'): obj.muxInfo = newObject.muxInfo # save Placement because following newObject.Shape.copy() isn't resetting it to zeroes... savedPlacement = obj.Placement obj.Shape = newObject.Shape.copy() obj.ViewObject.DiffuseColor = copy.copy( newObject.ViewObject.DiffuseColor) obj.ViewObject.Transparency = newObject.ViewObject.Transparency obj.Placement = savedPlacement # restore the old placement mw = FreeCADGui.getMainWindow() mdi = mw.findChild(QtGui.QMdiArea) sub = mdi.activeSubWindow() if sub != None: sub.showMaximized() objectCache.cleanUp(doc) a2plib.setAutoSolve(autoSolveState) if not a2plib.getUseTopoNaming(): # This is only needed when not using toponames. # Otherwise updating constraints.subelements triggers this. a2p_solversystem.autoSolveConstraints( doc, useTransaction=False, callingFuncName="updateImportedParts" ) #transaction is already open... doc.recompute() doc.commitTransaction()
def importUpdateConstraintSubobjects(doc, oldObject, newObject): if not a2plib.getUseTopoNaming(): return # return if there are no constraints linked to the object if len([ c for c in doc.Objects if 'ConstraintInfo' in c.Content and oldObject.Name in [c.Object1, c.Object2] ]) == 0: return # check, whether object is an assembly with muxInformations. # Then find edgenames with mapping in muxinfo... deletionList = [] #for broken constraints if hasattr(oldObject, 'muxInfo'): if hasattr(newObject, 'muxInfo'): # oldVertexNames = [] oldEdgeNames = [] oldFaceNames = [] for item in oldObject.muxInfo: if item[:1] == 'V': oldVertexNames.append(item) if item[:1] == 'E': oldEdgeNames.append(item) if item[:1] == 'F': oldFaceNames.append(item) # newVertexNames = [] newEdgeNames = [] newFaceNames = [] for item in newObject.muxInfo: if item[:1] == 'V': newVertexNames.append(item) if item[:1] == 'E': newEdgeNames.append(item) if item[:1] == 'F': newFaceNames.append(item) # partName = oldObject.Name for c in doc.Objects: if 'ConstraintInfo' in c.Content: if partName == c.Object1: SubElement = "SubElement1" elif partName == c.Object2: SubElement = "SubElement2" else: SubElement = None if SubElement: #same as subElement <> None subElementName = getattr(c, SubElement) if subElementName[:4] == 'Face': try: oldIndex = int(subElementName[4:]) - 1 oldConstraintString = oldFaceNames[oldIndex] newIndex = newFaceNames.index( oldConstraintString) newSubElementName = 'Face' + str(newIndex + 1) except: newIndex = -1 newSubElementName = 'INVALID' elif subElementName[:4] == 'Edge': try: oldIndex = int(subElementName[4:]) - 1 oldConstraintString = oldEdgeNames[oldIndex] newIndex = newEdgeNames.index( oldConstraintString) newSubElementName = 'Edge' + str(newIndex + 1) except: newIndex = -1 newSubElementName = 'INVALID' elif subElementName[:6] == 'Vertex': try: oldIndex = int(subElementName[6:]) - 1 oldConstraintString = oldVertexNames[oldIndex] newIndex = newVertexNames.index( oldConstraintString) newSubElementName = 'Vertex' + str(newIndex + 1) except: newIndex = -1 newSubElementName = 'INVALID' else: newIndex = -1 newSubElementName = 'INVALID' if newIndex >= 0: setattr(c, SubElement, newSubElementName) print("oldConstraintString (KEY) : {}".format( oldConstraintString)) print( "Updating by SubElement-Map: {} => {} ".format( subElementName, newSubElementName)) continue # # if code coming here, constraint is broken if c.Name not in deletionList: deletionList.append(c.Name) if len(deletionList) > 0: # there are broken constraints.. for cName in deletionList: flags = QtGui.QMessageBox.StandardButton.Yes | QtGui.QMessageBox.StandardButton.Abort message = "constraint %s is broken. Delete constraint? otherwise check for wrong linkage." % cName #response = QtGui.QMessageBox.critical(QtGui.qApp.activeWindow(), "Broken Constraint", message, flags ) response = QtGui.QMessageBox.critical(None, "Broken Constraint", message, flags) if response == QtGui.QMessageBox.Yes: FreeCAD.Console.PrintError("removing constraint %s" % cName) c = doc.getObject(cName) a2plib.removeConstraint(c)