예제 #1
0
    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()
예제 #2
0
    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()
예제 #3
0
    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
예제 #4
0
    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)
예제 #5
0
 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()
예제 #6
0
 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
예제 #7
0
 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()
예제 #8
0
    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)
예제 #9
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
예제 #10
0
 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