def onItemClicked( self, item ): for selected in self.partList.selectedIndexes(): # get the selected part part = self.allParts[ selected.row() ] doc = self.partsDoc[ selected.row() ] # by default, the link shall have the same name as the original part proposedLinkName = part.Label+'_var' # if it's a sub-assembly if part.Name == 'Model' or part.Name == 'Assembly': # if it has been renamed, we take the name given by the user if part.Name == part.Label: proposedLinkName = part.Document.Name+'_var' # if not, we take the document else: proposedLinkName = part.Label+'_var' # set the proposed name into the text field, unless it's a broken link if not self.brokenLink: # if the last character is a number, we increment this number lastChar = proposedLinkName[-1] if lastChar.isnumeric(): (rootName,sep,num) = proposedLinkName.rpartition('_') proposedLinkName = Asm4.nextInstance(rootName) # if that name is already taken if self.activeDoc.getObject(proposedLinkName): proposedLinkName = Asm4.nextInstance(proposedLinkName) self.linkNameInput.setText( proposedLinkName )
def Restore(self): selectedItems = self.configList.selectedItems() if len(selectedItems) != 1: Asm4.warningBox('Please select a configuration in the list') return confName = self.configList.currentItem().name restoreConfiguration(confName)
def onParentSelected(self): # clear the selection in the GUI window Gui.Selection.clearSelection() # build the LCS table self.attLCStable = [] # the current text in the combo-box is the link's name... if self.parentList.currentIndex() > 0: parentName = self.parentTable[self.parentList.currentIndex()].Name parentPart = self.activeDoc.getObject(parentName) if parentPart: # we get the LCS from the linked part self.attLCStable = Asm4.getPartLCS(parentPart.LinkedObject) # linked part & doc dText = parentPart.LinkedObject.Document.Name + '#' # if the linked part has been renamed by the user pText = Asm4.nameLabel(parentPart.LinkedObject) self.parentDoc.setText(dText + pText) # highlight the selected part: Gui.Selection.addSelection(parentPart.Document.Name, 'Model', parentPart.Name + '.') # something wrong else: return # build the list self.attLCSlist.clear() for lcs in self.attLCStable: newItem = QtGui.QListWidgetItem() newItem.setText(Asm4.nameLabel(lcs)) newItem.setIcon(lcs.ViewObject.Icon) self.attLCSlist.addItem(newItem) #self.attLCStable.append(lcs) return
def initUI(self): # clear the parent name (if any) self.parentDoc.clear() self.partLCSlist.clear() self.attLCSlist.clear() # the selected link's name self.linkName.setText( Asm4.labelName(self.selectedObj) ) # linked part & doc dText = '' if self.selectedObj.LinkedObject.Document != self.activeDoc : dText = self.selectedObj.LinkedObject.Document.Name +'#' # if the linked part has been renamed by the user, keep the label and add (.Name) pText = Asm4.labelName(self.selectedObj.LinkedObject) self.linkedDoc.setText( dText + pText ) # Initialize the assembly tree with the Parent Assembly as first element # clear the available parents combo box self.parentTable = [] self.parentList.clear() self.parentTable.append( [] ) self.parentList.addItem('Please select') self.parentTable.append( self.rootAssembly ) parentIcon = self.rootAssembly.ViewObject.Icon self.parentList.addItem( parentIcon, 'Parent Assembly', self.rootAssembly ) # set the old position values self.XtranslSpinBox.setValue(self.old_LinkPosition[0]) self.YtranslSpinBox.setValue(self.old_LinkPosition[1]) self.ZtranslSpinBox.setValue(self.old_LinkPosition[2])
def getSelectedAxes(self): holeAxes = [] fstnr = None selection = Gui.Selection.getSelectionEx('', 0) if selection: for s in selection: for seNames in s.SubElementNames: seObj = s.Object for se in seNames.split('.'): if se and (len(se) > 0): seObj = seObj.getObject(se) if Asm4.isAppLink(seObj): seObj = seObj.getLinkedObject() if Asm4.isHoleAxis(seObj): holeAxes.append( Asm4.getSelectionPath( s.Document.Name, s.ObjectName, seNames)) break elif isFastener(seObj): if fstnr is None: fstnr = seObj break else: # only 1 fastener can be selected return (None) else: break # if a fastener and at least 1 HoleAxis have been selected if fstnr and (len(holeAxes) > 0): return (fstnr, holeAxes) else: return (None)
def Activated(self): (fstnr, axes) = self.selection if fstnr.Document: for axisData in axes: if len(axisData) > 3: # DocName/ModelName/AppLinkName/AxisName docName = axisData[0] doc = App.getDocument(docName) if doc: model = doc.getObject(axisData[1]) if model: objLink = model.getObject(axisData[2]) if objLink: obj = objLink.getLinkedObject() axis = obj.getObject(axisData[3]) if axis and axis.Document: newFstnr = Asm4.cloneObject(fstnr) Asm4.placeObjectToLCS( newFstnr, axisData[2], axis.Document.Name, axisData[3]) Gui.Selection.clearSelection() self.rootAssembly = Asm4.getAssembly() if rootAssembly: Gui.Selection.addSelection(fstnr.Document.Name, self.rootAssembly.Name, fstnr.Name + '.')
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: # not yet implemented for variant links pass ''' 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 variant link with the user-provided name # variantLink = self.rootAssembly.newObject( 'App::Link', linkName ) variantLink = App.ActiveDocument.addObject("Part::FeaturePython", linkName, VariantLink(), None, True ) self.rootAssembly.addObject(variantLink) # assign the user-selected selectedPart to it variantLink.SourceObject = selectedPart # update the link to actually make all things inside variantLink.recompute() # If the name was already chosen, and a UID was generated: if variantLink.Name != linkName: # we try to set the label to the chosen name variantLink.Label = linkName # add the Asm4 properties Asm4.makeAsmProperties(variantLink) variantLink.Type = 'Asm4::VariantLink' variantLink.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, variantLink.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 IsActive(self): # we only insert variant links into assemblies and root parts if Asm4.getAssembly() or Asm4.getSelectedRootPart(): return True # if an existing variant link is selected, we duplicate it if Asm4.getSelectedVarLink(): return True return False
def Activated(self): selectedDatum = Asm4.getSelectedDatum() # check if the datum object is already mapped to something if selectedDatum.MapMode == 'Deactivated' and Asm4.checkModel(): Gui.Control.showDialog(placeDatumUI()) else: Gui.runCommand('Part_EditAttachment') '''
def IsActive(self): # if an App::Link is selected, even a broken one if Gui.Selection.getSelection() and Gui.Selection.getSelection()[0].isDerivedFrom('App::Link'): return True # there is an assembly or a root App::Part is selected elif Asm4.getAssembly() or Asm4.getSelectedRootPart(): return True return False
def Activated(self): # retrieve the Variables object self.Variables = App.ActiveDocument.getObject('Variables') # if it doesn't exist then create it (for older Asm4 documents) if not self.Variables: Asm4.messageBox('There are no variables here') return # (re-)initialise the UI self.UI.show() self.initUI()
def restoreConfiguration(confName): FCC.PrintMessage('Restoring configuration "' + confName + '"\n') #doc = getConfig(confName, 'Configurations') conf = getConfig(confName) assy = Asm4.getAssembly() link = Asm4.getSelectedLink() if link: restoreObject(conf, link) else: restoreSubObjects(conf, assy) App.ActiveDocument.recompute()
def onOK(self): confName = self.configName.text().strip() confDescr = self.configDescription.toPlainText().strip() if confName == '': Asm4.warningBox('Please specify configuration name!') self.configName.setFocus() return # if no description provided, give a single space to avoid errors if confDescr == '': confDescr = ' ' SaveConfiguration(confName, confDescr) self.UI.close()
def checkSelection(self): selectedObj = None # check that there is an App::Part called 'Model' # a standard App::Part would also do, but then more error checks are necessary # if App.ActiveDocument.getObject('Model') and App.ActiveDocument.getObject('Model').TypeId=='App::Part' : if Asm4.getAssembly() and len(Gui.Selection.getSelection()) == 1: # set the (first) selected object as global variable selection = Gui.Selection.getSelection()[0] if Asm4.isAsm4EE(selection) and selection.SolverId != '': selectedObj = selection # now we should be safe return selectedObj
def onExport(self): self.onStop() # check for OpenCV module installed (cv2) try: import cv2 if not self.exporter: # Only import the export-lib if requested. Helps to keep WB loading times in check. import AnimationExportLib self.exporter = AnimationExportLib.animationExporter(self) self.exporter.openUI() except: Asm4.warningBox('The Python module \"OpenCV\" is not installed')
def checkModel(self): if self.activeDoc.getObject('Model'): if self.activeDoc.Model.TypeId == 'App::Part' and self.activeDoc.Model.Type == 'Assembly4 Model': Asm4.warningBox( "This document already contains an Assembly4 Model.") else: Asm4.warningBox( "This document already contains another FreeCAD object called \"Model\". I cannot create an Assembly4 Model." ) return (True) else: return (False)
def addSelection(self, doc, obj, sub, pnt): parentFound = False # selected object selObj = Gui.Selection.getSelection()[0] selPath = Asm4.getSelectionPath(doc, obj, sub) # check that a datum object is selected if selObj.TypeId in Asm4.datumTypes and len(selPath) > 2: selLink = self.activeDoc.getObject(selPath[2]) # if it's the selected link to be placed: if selLink == self.selectedObj: # try to find the selected LCS in the partLCS list found = self.partLCSlist.findItems(Asm4.labelName(selObj), QtCore.Qt.MatchExactly) if len(found) > 0: self.partLCSlist.clearSelection() self.partLCSlist.scrollToItem(found[0]) self.partLCSlist.setCurrentItem(found[0]) # show and highlight LCS selObj.Visibility=True # highlight the entire object if selected in the 3D window if pnt != (0,0,0): pass # preview the part's placement self.Apply() # if it's a child in the assembly: elif selLink in self.parentTable: # find the parent idx = self.parentList.findText(Asm4.labelName(selLink), QtCore.Qt.MatchExactly) if idx >= 0: self.parentList.setCurrentIndex(idx) # this has triggered to fill in the attachment LCS list parentFound = True # if it's the object itself, then it belongs to the root assembly elif selLink == selObj and obj == self.rootAssembly.Name: self.parentList.setCurrentIndex(1) # this has triggered to fill in the attachment LCS list parentFound = True # if a parent was found if parentFound: # now lets try to find the selected LCS in this list found = self.attLCSlist.findItems(Asm4.labelName(selObj), QtCore.Qt.MatchExactly) if len(found) > 0: self.attLCSlist.clearSelection() self.attLCSlist.scrollToItem(found[0]) self.attLCSlist.setCurrentItem(found[0]) # show and highlight LCS selObj.Visibility=True # highlight the entire object if selected in the 3D window if pnt != (0,0,0): pass # preview the part's placement self.Apply()
def onParentList(self): # clear the LCS list self.attLCSlist.clear() self.attLCStable = [] # clear the selection in the GUI window Gui.Selection.clearSelection() # keep the fastener selected Gui.Selection.addSelection(self.activeDoc.Name, self.rootAssembly.Name, self.selectedFastener.Name + '.') # the current text in the combo-box is the link's name... # ... or it's 'Parent Assembly' then the parent is the 'Model' root App::Part if self.parentList.currentText() == 'Parent Assembly': parentName = 'Parent Assembly' # parentPart = self.activeDoc.getObject( 'Model' ) parentPart = self.rootAssembly # we get the LCS directly in the root App::Part self.attLCStable = Asm4.getPartLCS(parentPart) self.parentDoc.setText(parentPart.Document.Name + '#' + Asm4.labelName(parentPart)) # if something is selected elif self.parentList.currentIndex() > 1: parentName = self.parentTable[self.parentList.currentIndex()].Name parentPart = self.activeDoc.getObject(parentName) if parentPart: # we get the LCS from the linked part self.attLCStable = Asm4.getPartLCS(parentPart.LinkedObject) # linked part & doc dText = parentPart.LinkedObject.Document.Name + '#' # if the linked part has been renamed by the user pText = Asm4.labelName(parentPart.LinkedObject) self.parentDoc.setText(dText + pText) # highlight the selected part: Gui.Selection.addSelection( \ parentPart.Document.Name, self.rootAssembly.Name, parentPart.Name+'.' ) QtCore.QTimer.singleShot(1500, lambda:Gui.Selection.removeSelection( \ parentPart.Document.Name, self.rootAssembly.Name, parentPart.Name+'.' ) ) # something wrong else: return # build the list self.attLCSlist.clear() for lcs in self.attLCStable: newItem = QtGui.QListWidgetItem() newItem.setText(Asm4.labelName(lcs)) newItem.setIcon(lcs.ViewObject.Icon) self.attLCSlist.addItem(newItem) #self.attLCStable.append(lcs) return
def Activated(self): self.selObj = None # get the selected object if Asm4.getSelectedContainer(): self.selObj = Asm4.getSelectedContainer() elif Asm4.getSelectedLink(): self.selObj = Asm4.getSelectedLink() # should be unnecessary, but who knows if self.selObj: # initialise the UI self.selectedPart.setText(self.selObj.Name) proposedName = self.selObj.Label + '_sym' self.mirroredPartName.setText(proposedName) self.UI.show()
def checkSelection(self): # if something is selected ... if Gui.Selection.getSelection(): selectedObj = Gui.Selection.getSelection()[0] # ... and it's an App::Part or an datum object selType = selectedObj.TypeId if selType in self.containers or selType in Asm4.datumTypes or selType == 'Sketcher::SketchObject': return (selectedObj) # or of nothing is selected ... elif Asm4.getAssembly(): # ... but there is as assembly: return Asm4.getAssembly() # if we're here it's because we didn't find a good reason to not be here return None
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 IsActive(self): # if a spreadsheet in a Group called "Configuration" is selected if Asm4.getAssembly() and len(Gui.Selection.getSelection()) == 1: config = Gui.Selection.getSelection()[0] if getConfGroup() and isAsm4Config(config): return True return False
def lookForParts( self, doc=None ): self.allParts = [] self.partsDoc = [] self.partList.clear() if doc is None: docList = App.listDocuments().values() else: docList = [doc] for doc in docList: # don't consider temporary documents if not doc.Temporary: for obj in doc.findObjects("App::Part"): # we don't want to link to itself to the 'Model' object # other App::Part in the same document are OK # but only those at top level (not nested inside other containers) if obj != self.rootAssembly and obj.getParentGeoFeatureGroup() is None: self.allParts.append( obj ) self.partsDoc.append( doc ) for obj in doc.findObjects("PartDesign::Body"): # but only those at top level (not nested inside other containers) if obj.getParentGeoFeatureGroup() is None: self.allParts.append( obj ) self.partsDoc.append( doc ) # build the list for part in self.allParts: newItem = QtGui.QListWidgetItem() newItem.setText( part.Document.Name +"#"+ Asm4.labelName(part) ) newItem.setIcon(part.ViewObject.Icon) self.partList.addItem(newItem)
def Activated(self): rootAssembly = Asm4.getAssembly() # get the selected objects selEx = Gui.Selection.getSelectionEx("", 0)[0].SubElementNames (objName, dot, shape) = selEx[0].partition('.') # the first element should be the name of a child in the assembly if objName + '.' in rootAssembly.getSubObjects(): # get the object where the selected shapes are obj = App.ActiveDocument.getObject(objName) # this is a double-check, should always be true at this point if obj: shape = (shape, ) # we must remove the first name in each selEx element if len(selEx) > 1: # the first one (shape) has already been done for sel in selEx[1:]: (objName, dot, shp) = sel.partition('.') shape += (shp, ) # now create the SubShapeBinder binder = rootAssembly.newObject('PartDesign::SubShapeBinder', 'ShapeBinder') binder.Support = [(obj, shape)] binder.MakeFace = False binder.ViewObject.LineColor = (0., 1., 0.) binder.recompute()
def createConfig(name, description): group = getConfGroup() if not group: # create a group Configurations to store various config tables assy = Asm4.getAssembly() if assy: group = assy.newObject('App::DocumentObjectGroup', 'Configurations') else: FCC.PrintWarnin('No assembly container here, quitting\n') return # Create the document conf = group.newObject('Spreadsheet::Sheet', name) headerRow = str(int(OBJECTS_START_ROW) - 1) #conf.set(HEADER_CELL, 'Assembly4 configuration table') conf.set(HEADER_CELL, ASM4_CONFIG_TYPE) conf.set(DESCRIPTION_CELL, str(description)) conf.set(OBJECT_NAME_COL + headerRow, 'ObjectName') conf.set(OBJECT_VISIBLE_COL + headerRow, 'Visible') conf.set(OBJECT_ASM_TYPE_COL + headerRow, 'Assembly Type') conf.set(OFFSET_POS_X_COL + headerRow, 'Pos. X') conf.set(OFFSET_POS_Y_COL + headerRow, 'Pos. Y') conf.set(OFFSET_POS_Z_COL + headerRow, 'Pos. Z') conf.set(OFFSET_ROT_YAW_COL + headerRow, 'Rot. Yaw') conf.set(OFFSET_ROT_PITCH_COL + headerRow, 'Rot. Pitch') conf.set(OFFSET_ROT_ROLL_COL + headerRow, 'Rot. Roll') return conf
def Activated(self): # get the current active document to avoid errors if user changes tab self.activeDoc = App.activeDocument() # check whether there is already Model in the document if not self.checkModel(): # create a group 'Parts' to hold all parts in the assembly document (if any) # must be done before creating the Asm4 Model partsGroup = self.activeDoc.getObject('Parts') if partsGroup is None: partsGroup = self.activeDoc.addObject( 'App::DocumentObjectGroup', 'Parts') # create a new App::Part called 'Model' assembly = self.activeDoc.addObject('App::Part', 'Model') # set the type as a "proof" that it's an Assembly4 Model assembly.Type = 'Assembly' assembly.addProperty('App::PropertyString', 'AssemblyType', 'Assembly') assembly.AssemblyType = 'Part::Link' # add an LCS at the root of the Model, and attach it to the 'Origin' lcs0 = assembly.newObject('PartDesign::CoordinateSystem', 'LCS_Origin') lcs0.Support = [(assembly.Origin.OriginFeatures[0], '')] lcs0.MapMode = 'ObjectXY' lcs0.MapReversed = False # create a group Constraints to store future solver constraints there assembly.newObject('App::DocumentObjectGroup', 'Constraints') # create an object Variables to hold variables to be used in this document assembly.addObject(Asm4.createVariables()) # create a group Configurations to store future solver constraints there assembly.newObject('App::DocumentObjectGroup', 'Configurations') # move existing parts and bodies at the document root to the Parts group # not nested inside other parts, to keep hierarchy if partsGroup.TypeId == 'App::DocumentObjectGroup': for obj in self.activeDoc.Objects: if obj.TypeId in Asm4.containerTypes and obj.Name != 'Model' and obj.getParentGeoFeatureGroup( ) is None: partsGroup.addObject(obj) else: Asm4.warningBox( 'There seems to already be a Parts object, you might get unexpected behaviour' ) # recompute to get rid of the small overlays assembly.recompute() self.activeDoc.recompute()
def showHide(show): # reset processed links cache processedLinks = [] # if something is selected if Gui.Selection.hasSelection(): for sel in Gui.Selection.getSelection(): if sel.isDerivedFrom('App::Link'): showChildLCSs(sel, show, processedLinks) elif sel.TypeId in Asm4.containerTypes: for objName in sel.getSubObjects(1): showChildLCSs(sel.getSubObject(objName, 1), show, processedLinks) # if not, apply it to the assembly elif Asm4.getAssembly(): asm = Asm4.getAssembly() for objName in asm.getSubObjects(1): showChildLCSs(asm.getSubObject(objName, 1), show, processedLinks)
def Activated(self): # retrieve the Variables object self.Variables = App.ActiveDocument.getObject('Variables') # if it doesn't exist then create it (for older Asm4 documents) if not self.Variables: self.Variables = Asm4.createVariables() part = None # if an App::Part is selected: if checkPart(): part = checkPart() # if an Asm4 Model is present: elif Asm4.getAssembly(): part = Asm4.getAssembly() if part: part.addObject(self.Variables) #self.Variables = part.newObject('App::FeaturePython','Variables') #self.Variables.ViewObject.Proxy = Asm4.setCustomIcon(object,'Asm4_Variables.svg') # create the Variables in the document #else: #self.Variables = App.ActiveDocument.addObject('App::FeaturePython','Variables') #self.Variables.ViewObject.Proxy = Asm4.setCustomIcon(object,'Asm4_Variables.svg') # (re-)initialise the UI self.typeList.clear() self.varName.clear() self.varValue.setValue( 10.0 ) self.description.clear() self.UI.show() # get all supported Property types for prop in self.Variables.supportedProperties(): if prop in self.allowedProperties: # remove the leading 'App::Property' for clarity self.typeList.addItem(prop[13:]) # find the Float property # propFloat = self.typeList.findText( 'App::PropertyFloat' ) propFloat = self.typeList.findText( 'Float' ) # if not found if propFloat == -1: self.typeList.setCurrentIndex( 0 ) else: self.typeList.setCurrentIndex( propFloat ) # set focus on the variable name self.varName.setFocus()
def clicked(self, bt): if bt == QtGui.QDialogButtonBox.Ignore: # ask for confirmation before resetting everything msgName = Asm4.nameLabel(self.selectedDatum) # see whether the ExpressionEngine field is filled if self.selectedDatum.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: self.selectedDatum.setExpression('Placement', None) self.finish()
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