def onCreateLink(self): # parse the selected items selectedPart = [] for selected in self.partList.selectedIndexes(): # get the selected part selectedPart = self.allParts[selected.row()] # get the name of the link (as it should appear in the tree) linkName = self.linkNameInput.text() # repair broken link if self.brokenLink and selectedPart: self.origLink.LinkedObject = selectedPart self.origLink.recompute() self.UI.close() # ... and launch the placement of the inserted part Gui.Selection.clearSelection() Gui.Selection.addSelection(self.activeDoc.Name, self.rootAssembly.Name, self.origLink.Name + '.') # ... but only if we're in an Asm4 Model if self.rootAssembly == Asm4.getAssembly(): Gui.runCommand('Asm4_placeLink') # only create link if there is a Part object and a name elif self.rootAssembly and selectedPart and linkName: # check that the current document had been saved # or that it's the same document as that of the selected part if App.ActiveDocument.FileName != '' or App.ActiveDocument == selectedPart.Document: # create the App::Link with the user-provided name #createdLink = self.activeDoc.getObject('Model').newObject( 'App::Link', linkName ) createdLink = self.rootAssembly.newObject( 'App::Link', linkName) # assign the user-selected selectedPart to it createdLink.LinkedObject = selectedPart # If the name was already chosen, and a UID was generated: if createdLink.Name != linkName: # we try to set the label to the chosen name createdLink.Label = linkName # add the Asm4 properties Asm4.makeAsmProperties(createdLink) createdLink.AssemblyType = "Part::Link" # update the link createdLink.recompute() # close the dialog UI... self.UI.close() # ... and launch the placement of the inserted part Gui.Selection.clearSelection() Gui.Selection.addSelection(self.activeDoc.Name, self.rootAssembly.Name, createdLink.Name + '.') # ... but only if we're in an Asm4 Model if self.rootAssembly == Asm4.getAssembly(): Gui.runCommand('Asm4_placeLink') else: Asm4.warningBox( 'The current document must be saved before inserting an external part' ) return # if still open, close the dialog UI self.UI.close()
def setupTargetDatum(self, targetDatum, expression): # unset Attachment targetDatum.MapMode = 'Deactivated' targetDatum.Support = None # Set Asm4 properties Asm4.makeAsmProperties(targetDatum, reset=True) targetDatum.AttachedBy = 'Origin' targetDatum.SolverId = 'Placement::ExpressionEngine' # set the Placement's ExpressionEngine targetDatum.setExpression('Placement', expression) targetDatum.Visibility = True # recompute the object to apply the placement: targetDatum.recompute()
def onApply(self): # get the name of the part to attach to: # it's either the top level part name ('Model') # or the provided link's name. if self.parentList.currentText() == 'Parent Assembly': a_Link = 'Parent Assembly' a_Part = None elif self.parentList.currentIndex() > 1: parent = self.parentTable[self.parentList.currentIndex()] a_Link = parent.Name a_Part = parent.LinkedObject.Document.Name else: a_Link = None a_Part = None # the attachment LCS's name in the parent # check that something is selected in the QlistWidget if self.attLCSlist.selectedItems(): a_LCS = self.attLCStable[self.attLCSlist.currentRow()].Name else: a_LCS = None # check that all of them have something in if a_Link and a_LCS: # add Asm4 properties if necessary Asm4.makeAsmProperties(self.selectedFastener, reset=True) # hide "offset" and "invert" properties to avoid confusion as they are not used in Asm4 if hasattr(self.selectedFastener, 'offset'): self.selectedFastener.setPropertyStatus('offset', 'Hidden') if hasattr(self.selectedFastener, 'invert'): self.selectedFastener.setPropertyStatus('invert', 'Hidden') # <<LinkName>>.Placement.multiply( <<LinkName>>.<<LCS.>>.Placement ) # expr = '<<'+ a_Part +'>>.Placement.multiply( <<'+ a_Part +'>>.<<'+ a_LCS +'.>>.Placement )' Asm4.placeObjectToLCS(self.selectedFastener, a_Link, a_Part, a_LCS) # highlight the selected fastener in its new position Gui.Selection.clearSelection() Gui.Selection.addSelection(self.activeDoc.Name, self.rootAssembly.Name, self.selectedFastener.Name + '.') else: FCC.PrintWarning("Problem in selections\n") return
def Activated(self): # check what we have selected selectedObj = self.checkSelection() if not selectedObj: return objName = selectedObj.Name objLabel = selectedObj.Label objType = selectedObj.TypeId # ask for confirmation before resetting everything confirmText = 'This command will release all attachments on '+Asm4.labelName(selectedObj) \ +' and set it to manual positioning in its current location.' if not Asm4.confirmBox(confirmText): # don't do anything return # the root Assembly4 Model # model = App.ActiveDocument.getObject('Model') model = Asm4.getAssembly() # handle object types differently # an App::Link if objType == 'App::Link': # unset the ExpressionEngine for the Placement selectedObj.setExpression('Placement', None) # reset Asm4 properties Asm4.makeAsmProperties(selectedObj, reset=True) # a datum object else: # reset Asm4 properties Asm4.makeAsmProperties(selectedObj, reset=True) # unset both Placements (who knows what confusion the user has done) selectedObj.setExpression('Placement', None) selectedObj.setExpression('AttachmentOffset', None) # if it's a datum object if objType == 'PartDesign::CoordinateSystem' or objType == 'PartDesign::Plane' or objType == 'PartDesign::Line' or objType == 'PartDesign::Point': # unset the MapMode; this actually keeps the MapMode parameters intact, # so it's easy for the user to re-enable it selectedObj.MapMode = 'Deactivated' # recompute the assembly model model.recompute(True)
def clicked(self, bt): if bt == QtGui.QDialogButtonBox.Ignore: # ask for confirmation before resetting everything msgName = Asm4.labelName(self.selectedFastener) # see whether the ExpressionEngine field is filled if self.old_EE: # if yes, then ask for confirmation confirmed = Asm4.confirmBox( 'This command will release all attachments on ' + msgName + ' and set it to manual positioning in its current location.' ) else: # if not, then it's useless to bother the user confirmed = True if confirmed: # unset the ExpressionEngine in the Placement self.selectedFastener.setExpression('Placement', None) # reset Asm4 properties Asm4.makeAsmProperties(self.selectedFastener, reset=True) self.finish()
def Activated(self): # check that we have selected a Fastener from the Fastener WB selection = getSelectionFS() if selection is None: return # check that the fastener is an Asm4 fastener if not hasattr(selection, 'SolverId'): Asm4.makeAsmProperties(selection) # we only deal with Asm4 or empty types asmType = selection.SolverId if asmType == 'Placement::ExpressionEngine' or asmType == '': # now we should be safe, call the UI Gui.Control.showDialog(placeFastenerUI()) else: convert = Asm4.confirmBox( "This doesn't seem to be an Assembly4 Fastener, but I can convert it." ) if convert: Asm4.makeAsmProperties(selection, reset=True) # selection.AssemblyType = 'Part::Link' selection.SolverId = 'Placement::ExpressionEngine' Gui.Control.showDialog(placeFastenerUI()) return
def clicked(self, button): if button == QtGui.QDialogButtonBox.Apply: self.Apply() elif button == QtGui.QDialogButtonBox.Ignore: # ask for confirmation before resetting everything msgName = Asm4.labelName(self.selectedObj) # see whether the ExpressionEngine field is filled if self.selectedObj.ExpressionEngine : # if yes, then ask for confirmation confirmed = Asm4.confirmBox('This command will release all attachments on '+msgName+' and set it to manual positioning in its current location.') # if not, then it's useless to bother the user else: confirmed = True if confirmed: # unset the ExpressionEngine for the Placement self.selectedObj.setExpression('Placement', None) # reset the assembly properties Asm4.makeAsmProperties( self.selectedObj, reset=True ) # finish FCC.PrintMessage("Part is now manually placed\n") self.finish() else: FCC.PrintMessage("Part untouched\n") self.finish()
def __init__(self): # remove selectionFilter self.selectionFilterStatus = selectionFilter.observerStatus() selectionFilter.observerDisable() # get the current active document to avoid errors if user changes tab self.activeDoc = App.ActiveDocument # we have checked before that all this is correct selection = Asm4.getSelectedLink() if selection is None: selection = Asm4.getSelectedVarLink() self.selectedObj = selection #self.rootAssembly = self.selectedObj.getParentGeoFeatureGroup() self.rootAssembly = Asm4.getAssembly() # has been checked before, this is for security only if Asm4.isAsm4EE(self.selectedObj): # get the old values self.old_AO = self.selectedObj.AttachmentOffset self.old_linkLCS = self.selectedObj.AttachedBy[1:] else: # this shouldn't happen FCC.PrintWarning("WARNING : unsupported Assembly/Solver/Part combination, you shouldn't be seeing this\n") Asm4.makeAsmProperties(self.selectedObj) self.old_AO = [] self.old_linkLCS = '' # define the GUI # draw the GUI, objects are defined later down # self.UI = QtGui.QWidget() # self.form = self.UI self.form = QtGui.QWidget() iconFile = os.path.join( Asm4.iconPath , 'Place_Link.svg') self.form.setWindowIcon(QtGui.QIcon( iconFile )) self.form.setWindowTitle('Place linked Part') self.drawUI(self.form) #save original AttachmentOffset of linked part self.old_LinkAttachmentOffset = self.selectedObj.AttachmentOffset self.old_LinkRotation = self.selectedObj.AttachmentOffset.Rotation self.old_LinkPosition = self.selectedObj.AttachmentOffset.Base # default values correspond to original AttachmentOffset of linked part self.Xtranslation = self.old_LinkPosition[0] self.Ytranslation = self.old_LinkPosition[1] self.Ztranslation = self.old_LinkPosition[2] self.XrotationAngle = self.old_LinkRotation.toEuler()[0] self.YrotationAngle = self.old_LinkRotation.toEuler()[1] self.ZrotationAngle = self.old_LinkRotation.toEuler()[2] # save previous view properties self.old_OverrideMaterial = self.selectedObj.ViewObject.OverrideMaterial self.old_DrawStyle = self.selectedObj.ViewObject.DrawStyle self.old_LineWidth = self.selectedObj.ViewObject.LineWidth self.old_DiffuseColor = self.selectedObj.ViewObject.ShapeMaterial.DiffuseColor self.old_Transparency = self.selectedObj.ViewObject.ShapeMaterial.Transparency # set new view properties self.selectedObj.ViewObject.OverrideMaterial = True self.selectedObj.ViewObject.DrawStyle = DrawStyle self.selectedObj.ViewObject.LineWidth = LineWidth self.selectedObj.ViewObject.ShapeMaterial.DiffuseColor = DiffuseColor self.selectedObj.ViewObject.ShapeMaterial.Transparency = Transparency # get the old values self.old_EE = '' old_Parent = '' old_ParentPart = '' old_attLCS = '' constrName = '' linkedDoc = '' old_linkLCS = '' # get and store the current expression engine: self.old_EE = Asm4.placementEE(self.selectedObj.ExpressionEngine) # decode the old ExpressionEngine # if the decode is unsuccessful, old_Expression is set to False and the other things are set to 'None' (self.old_Parent, separator, self.old_parentLCS) = self.selectedObj.AttachedTo.partition('#') ( old_Parent, old_attLCS, old_linkLCS ) = self.splitExpressionLink( self.old_EE, self.old_Parent ) # sometimes, the object is in << >> which is an error by FreeCAD, # because that's reserved for labels, but we still look for it if len(old_attLCS)>4 and old_attLCS[:2]=='<<' and old_attLCS[-2:]=='>>': old_attLCS = old_attLCS[2:-2] if len(old_linkLCS)>4 and old_linkLCS[:2]=='<<' and old_linkLCS[-2:]=='>>': old_linkLCS = old_linkLCS[2:-2] # initialize the UI with the current data self.attLCStable = [] self.initUI() # now self.parentList and self.parentTable are available # find all the linked parts in the assembly for obj in self.activeDoc.findObjects("App::Link"): if self.rootAssembly.getObject(obj.Name) is not None and hasattr(obj.LinkedObject,'isDerivedFrom'): linkedObj = obj.LinkedObject if linkedObj.isDerivedFrom('App::Part') or linkedObj.isDerivedFrom('PartDesign::Body'): # ... except if it's the selected link itself if obj != self.selectedObj: self.parentTable.append( obj ) # add to the drop-down combo box with the assembly tree's parts objIcon = linkedObj.ViewObject.Icon objText = Asm4.labelName(obj) self.parentList.addItem( objIcon, objText, obj) # find all the LCS in the selected link self.partLCStable = Asm4.getPartLCS( self.selectedObj.LinkedObject ) # build the list self.partLCSlist.clear() for lcs in self.partLCStable: newItem = QtGui.QListWidgetItem() newItem.setText(Asm4.labelName(lcs)) newItem.setIcon( lcs.ViewObject.Icon ) self.partLCSlist.addItem(newItem) # find the old LCS in the list of LCS of the linked part... # MatchExactly, MatchContains, MatchEndsWith ... # find with Name ... lcs_found = self.partLCSlist.findItems( old_linkLCS, QtCore.Qt.MatchExactly ) # ... or with (Name) if not lcs_found: lcs_found = self.partLCSlist.findItems( '('+old_linkLCS+')', QtCore.Qt.MatchEndsWith ) if lcs_found: # ... and select it self.partLCSlist.setCurrentItem( lcs_found[0] ) # find the oldPart in the part list... if old_Parent == 'Parent Assembly': parent_found = True parent_index = 1 else: parent_found = False parent_index = 1 for item in self.parentTable[1:]: if item.Name == old_Parent: parent_found = True break else: parent_index = parent_index +1 if not parent_found: parent_index = 0 self.parentList.setCurrentIndex( parent_index ) # this should have triggered self.getPartLCS() to fill the LCS list # find the old attachment Datum in the list of the Datums in the linked part... lcs_found = self.attLCSlist.findItems( old_attLCS, QtCore.Qt.MatchExactly ) if not lcs_found: lcs_found = self.attLCSlist.findItems( '('+old_attLCS+')', QtCore.Qt.MatchEndsWith ) if lcs_found: # ... and select it self.attLCSlist.setCurrentItem( lcs_found[0] ) # selection observer to detect selection of LCS in the 3D window and tree Gui.Selection.addObserver(self, 0)
def Apply( self ): # get the instance to attach to: # it's either the top level assembly or a sister App::Link if self.parentList.currentText() == 'Parent Assembly': a_Link = 'Parent Assembly' a_Part = None elif self.parentList.currentIndex() > 1: parent = self.parentTable[ self.parentList.currentIndex() ] a_Link = parent.Name a_Part = parent.LinkedObject.Document.Name else: a_Link = None a_Part = None # the attachment LCS's name in the parent # check that something is selected in the QlistWidget if self.attLCSlist.selectedItems(): a_LCS = self.attLCStable[ self.attLCSlist.currentRow() ].Name else: a_LCS = None # the linked App::Part's name l_Part = self.selectedObj.LinkedObject.Document.Name # the LCS's name in the linked part to be used for its attachment # check that something is selected in the QlistWidget if self.partLCSlist.selectedItems(): #l_LCS = self.partLCSlist.selectedItems()[0].text() l_LCS = self.partLCStable[ self.partLCSlist.currentRow() ].Name else: l_LCS = None # check that all of them have something in # constrName has been checked at the beginning if a_Link and a_LCS and l_Part and l_LCS : # add the Asm4 properties if it's a pure App::Link Asm4.makeAsmProperties(self.selectedObj) # self.selectedObj.AssemblyType = 'Part::Link' self.selectedObj.AttachedBy = '#'+l_LCS self.selectedObj.AttachedTo = a_Link+'#'+a_LCS self.selectedObj.SolverId = 'Placement::ExpressionEngine' # build the expression for the ExpressionEngine # this is where all the magic is, see: # # https://forum.freecadweb.org/viewtopic.php?p=278124#p278124 # # as of FreeCAD v0.19 the syntax is different: # https://forum.freecadweb.org/viewtopic.php?f=17&t=38974&p=337784#p337784 # # expr = ParentLink.Placement * ParentPart#LCS.Placement * constr_LinkName.AttachmentOffset * LinkedPart#LCS.Placement ^ -1' # expr = LCS_in_the_assembly.Placement * constr_LinkName.AttachmentOffset * LinkedPart#LCS.Placement ^ -1' expr = Asm4.makeExpressionPart( a_Link, a_Part, a_LCS, l_Part, l_LCS ) # load the expression into the link's Expression Engine self.selectedObj.setExpression('Placement', expr ) # recompute the object to apply the placement: self.selectedObj.recompute() self.rootAssembly.recompute(True) return True else: FCC.PrintWarning("Problem in selections\n") return False
def Activated(self): # try with a regular App::Link selection = Asm4.getSelectedLink() # may-be an Asm4::VariantLink ? if selection is None: selection = Asm4.getSelectedVarLink() # if we found a valid link if selection is not None: # check that it's in the root assembly parent = selection.getParentGeoFeatureGroup() if parent and parent == Asm4.getAssembly(): # if it's a valid assembly and part if Asm4.isAsm4EE(selection): # BUGFIX: if the part was corrupted by Assembly4 v0.11.5: if hasattr(selection, 'MapMode'): Asm4.warningBox( "This Part has the Attachment extension, it can only be placed manually" ) else: # launch the UI in the task panel ui = placeLinkUI() Gui.Control.showDialog(ui) # else try to convert it else: convert = Asm4.confirmBox( "This Part wasn't assembled with this Assembly4 WorkBench, but I can convert it." ) if convert: Asm4.makeAsmProperties(selection, reset=True) # launch the UI in the task panel ui = placeLinkUI() Gui.Control.showDialog(ui) else: Asm4.warningBox('Please select a link in the assembly Model.') else: # or any part that has a Placement ? if len(Gui.Selection.getSelection()) == 1: selection = Gui.Selection.getSelection()[0] # object has a Placement property if hasattr(selection, 'Placement') and selection.getTypeIdOfProperty( 'Placement') == 'App::PropertyPlacement': # we don't want to mess with obects that are attached with the Attacher (MapMode) if hasattr(selection, 'MapMode'): FCC.PrintMessage( 'Object has MapMode property, you should use that\n' ) else: # check that it's in the root assembly parent = selection.getParentGeoFeatureGroup() if parent and parent == Asm4.getAssembly(): # is it's a virgin object, give it Asm4 properties if not hasattr(selection, 'SolverId'): Asm4.makeAsmProperties(selection) # if it's a valid assembly and part if Asm4.isAsm4EE(selection): # launch the UI in the task panel ui = placePartUI() Gui.Control.showDialog(ui) # else try to convert it else: convert = Asm4.confirmBox( "This Part wasn't assembled with this Assembly4 WorkBench, but I can convert it." ) if convert: Asm4.makeAsmProperties(selection, reset=True) # launch the UI in the task panel ui = placePartUI() Gui.Control.showDialog(ui) # the selected object doesn't belong to the root assembly else: Asm4.warningBox( 'Please select an object in the assembly Model.' ) return