示例#1
0
 def callSolveConstraints(self):
     from assembly2solver import solveConstraints
     preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Assembly2")
     if preferences.GetBool('useCache', False):
         import cache_assembly2
         solverCache = cache_assembly2.defaultCache
     else:
         solverCache = None
     solveConstraints( FreeCAD.ActiveDocument, cache = solverCache )
 def callSolveConstraints(self):
     from assembly2solver import solveConstraints
     preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Assembly2")
     if preferences.GetBool('useCache', False):
         import cache_assembly2
         solverCache = cache_assembly2.defaultCache
     else:
         solverCache = None
     solveConstraints( FreeCAD.ActiveDocument, cache = solverCache )
 def Activated(self):
     #disable proxies solving the system as their objects are updated
     parms = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Assembly2")
     org_setting = parms.GetBool('autoSolveConstraintAttributesChanged', True)
     parms.SetBool('autoSolveConstraintAttributesChanged', False)
     solve_assembly_constraints = False
     for obj in FreeCAD.ActiveDocument.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 os.path.exists( obj.sourceFile ):
                 debugPrint( 3, '%s.sourceFile %s is missing, attempting to repair it' % (obj.Name,  obj.sourceFile) )
                 replacement = None
                 aFolder, aFilename = posixpath.split( FreeCAD.ActiveDocument.FileName )
                 sParts = path_split( posixpath, obj.sourceFile)
                 debugPrint( 3, '  obj.sourceFile parts %s' % sParts )
                 replacement = None
                 previousRejects = []
                 while replacement == None and aFilename <> '':
                     for i in reversed(range(len(sParts))):
                         newFn = aFolder
                         for j in range(i,len(sParts)):
                             newFn = posixpath.join( newFn,sParts[j] )
                         debugPrint( 4, '    checking %s' % newFn )
                         if os.path.exists( newFn ) and not newFn in previousRejects :
                             reply = QtGui.QMessageBox.question(
                                 QtGui.qApp.activeWindow(), "%s source file not found" % obj.Name,
                                 "Unable to find\n  %s \nUse \n  %s\n instead?" % (obj.sourceFile, newFn) , 
                                 QtGui.QMessageBox.Yes | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
                             if reply == QtGui.QMessageBox.Yes:
                                 replacement = newFn
                                 break
                             else:
                                 previousRejects.append( newFn )
                     aFolder, aFilename = posixpath.split( aFolder )
                 if replacement <> None:
                     obj.sourceFile = replacement
                 else:
                     QtGui.QMessageBox.critical(  QtGui.qApp.activeWindow(), "Source file not found", "update of %s aborted!\nUnable to find %s" % (obj.Name, obj.sourceFile) )
                     obj.timeLastImport = 0 #force update if users repairs link
             if os.path.exists( obj.sourceFile ):
                 if os.path.getmtime( obj.sourceFile ) > obj.timeLastImport:
                     importPart( obj.sourceFile, obj.Name )
                     solve_assembly_constraints = True
     if solve_assembly_constraints:
         solveConstraints( FreeCAD.ActiveDocument )
     FreeCAD.ActiveDocument.recompute()
     parms.SetBool('autoSolveConstraintAttributesChanged', org_setting )
 def Activated(self):
     from assembly2solver import solveConstraints
     constraintSystem = solveConstraints(FreeCAD.ActiveDocument)
     if len(constraintSystem.degreesOfFreedom) > 0:
         moduleVars['animation'] = AnimateDOF(constraintSystem)#required to protect the QTimer from the garbage collector
     else:
         FreeCAD.Console.PrintError('Aborting Animation! Constraint system has no degrees of freedom.')
def boltSelection():
    doc = FreeCAD.ActiveDocument
    doc.openTransaction('Bolt Multiple Circular Edges')
    selection = FreeCADGui.Selection.getSelectionEx()
    bolt = selection[0].Object
    bolt_se_name = selection[0].SubElementNames[0]
    S = []  #edgesToConstrainTo
    for s in selection[1:]:
        for se_name in s.SubElementNames:
            S.append(SelectionExObject(doc, s.Object, se_name))
    for s2 in S:
        newBolt = duplicateImportedPart(bolt)
        s1 = SelectionExObject(doc, newBolt, bolt_se_name)
        debugPrint(3, 's1 %s' % [s1, s2])
        parseSelection([s1, s2], callSolveConstraints=False, lockRotation=True)
    solveConstraints(doc)
    FreeCAD.ActiveDocument.commitTransaction()
    repair_tree_view()
def boltSelection():
    doc = FreeCAD.ActiveDocument
    doc.openTransaction('Bolt Multiple Circular Edges')
    selection = FreeCADGui.Selection.getSelectionEx()
    bolt = selection[0].Object
    bolt_se_name = selection[0].SubElementNames[0]
    S = [] #edgesToConstrainTo 
    for s in selection[1:]:
        for se_name in s.SubElementNames:
            S.append( SelectionExObject(doc, s.Object, se_name) )
    for s2 in S:
        newBolt = duplicateImportedPart(bolt)
        s1 = SelectionExObject(doc, newBolt, bolt_se_name)
        debugPrint(3,'s1 %s' % [s1, s2])
        parseSelection(
            [s1, s2 ], 
            callSolveConstraints= False, lockRotation = True 
            )
    solveConstraints( doc )
    FreeCAD.ActiveDocument.commitTransaction()
示例#7
0
 def Activated(self):
     from assembly2solver import solveConstraints
     constraintSystem = solveConstraints(FreeCAD.ActiveDocument)
     if len(constraintSystem.degreesOfFreedom) > 0:
         moduleVars['animation'] = AnimateDOF(
             constraintSystem
         )  #required to protect the QTimer from the garbage collector
     else:
         FreeCAD.Console.PrintError(
             'Aborting Animation! Constraint system has no degrees of freedom.'
         )
示例#8
0
 def step(self, now):
     try:
         # https://github.com/hamish2014/FreeCAD_assembly2/issues/73
         import assembly2lib
         assembly2lib.debugPrint.level = 0  #the default is 2
         assembly2lib.debugPrint.level = self.obj2.debugLevel
         import assembly2solver
         try:
             constraintSystem = assembly2solver.solveConstraints(
                 FreeCAD.ActiveDocument,
                 showFailureErrorDialog=False,
                 printErrors=self.obj2.printErrors)
             if constraintSystem == None:
                 sayErr('Solver failed to satisfy specified constraints')
             else:
                 say("Solver step done " + str(now))
         except:
             sayErr(
                 "problem assembly2solver.solveConstraints(App.ActiveDocument)"
             )
     except:
         sayErr("problem no assembly2 available")
         pass
示例#9
0
 def Activated(self):
     from assembly2solver import solveConstraints
     constraintSystem = solveConstraints(FreeCAD.ActiveDocument)
     self.taskPanel = manualDOFadjPanel( constraintSystem )
     FreeCADGui.Control.showDialog( self.taskPanel )
示例#10
0
 def reject(self):  #or more correctly close, given the button settings
     if hasattr(self.form, 'constraintAnimator'):
         self.form.constraintAnimator.stop()
         from assembly2solver import solveConstraints
         solveConstraints(FreeCAD.ActiveDocument)
     FreeCADGui.Control.closeDialog()
示例#11
0
    def generate_animation(self):
        preferences = FreeCAD.ParamGet(
            "User parameter:BaseApp/Preferences/Mod/Assembly2")
        org_auto_solve = preferences.GetBool(
            'autoSolveConstraintAttributesChanged', True)
        preferences.SetBool('autoSolveConstraintAttributesChanged', False)
        try:
            if hasattr(self, 'constraintAnimator'):
                self.constraintAnimator.stop()
            from assembly2solver import solveConstraints
            P = {}
            for p in animation_parameters:
                if hasattr(p, 'getValue'):
                    p.add_property_to_freecad_object()
                    P[p.name] = p.getValue()
            debugPrint(3, 'generate_animation parms %s' % P)
            constraint_to_animate = self.taskDialog.constraint_to_animate
            self.original_expressions = constraint_to_animate.ExpressionEngine  #[('angle', '12')]
            self.X = []
            if not hasattr(constraint_to_animate, 'a'):
                constraint_to_animate.addProperty({
                    'angle_between_planes':
                    'App::PropertyAngle',
                    'plane':
                    'App::PropertyDistance',
                    'circularEdge':
                    'App::PropertyDistance'
                }[constraint_to_animate.Type], 'a', "animationParameters")
                constraint_to_animate.setEditorMode('a', 2)
            attr_to_animate = {
                'angle_between_planes': 'angle',
                'plane': 'offset',
                'circularEdge': 'offset'
            }[constraint_to_animate.Type]
            attr_org_value = getattr(constraint_to_animate, attr_to_animate)
            constraint_to_animate.setExpression(attr_to_animate,
                                                P['animation_exp'])

            moduleVars['progressDialog'] = QtGui.QProgressDialog(
                "Generating Animation", "Cancel", 0, P['a_n'])
            p = moduleVars['progressDialog']
            p.setWindowModality(QtCore.Qt.WindowModal)
            p.forceShow()
            A = numpy.linspace(P['a_0'], P['a_1'], P['a_n'])
            for count, a in enumerate(A):
                if not p.wasCanceled():
                    p.setLabelText('solving %i/%i' % (count + 1, P['a_n']))
                    p.setValue(count)
                    debugPrint(3, 'solving constraint system for a=%1.1f' % a)
                    constraint_to_animate.a = a
                    FreeCAD.ActiveDocument.recompute(
                    )  #update other expersions
                    constraint_sys = solveConstraints(FreeCAD.ActiveDocument)
                    self.X.append(constraint_sys.variableManager.X.copy())
                    #variableManager.updateFreeCADValues( constraintSystem.variableManager.X )
            set_exp_to_none = True
            for ent in self.original_expressions:
                if ent[0] == attr_to_animate:
                    constraint_to_animate.setExpression(
                        attr_to_animate, ent[1])
                    set_exp_to_none = False
            if set_exp_to_none:
                constraint_to_animate.setExpression(attr_to_animate, None)
            setattr(constraint_to_animate, attr_to_animate, attr_org_value)
            if not p.wasCanceled():
                p.setValue(
                    P['a_n'])  #hopefully this will close the progress dialog
                if P['interp_method'] == 'none':
                    pass
                elif P['interp_method'] == 'linear':
                    self.X = linear_interp(self.X, A, P['n_interp'])
                elif P['interp_method'] == 'Cubic_Hermite_spline':
                    self.X = spline_interp(self.X, A, P['n_interp'])
                else:
                    raise NotImplemented

                self.playStopButton.setEnabled(True)
                self.constraintAnimator = ConstraintAnimator(
                    self.X, constraint_sys.variableManager)
                if P['play_after_generate']:
                    self.playStopButton_clicked()
        except:
            FreeCAD.Console.PrintError(traceback.format_exc())
        preferences.SetBool('autoSolveConstraintAttributesChanged',
                            org_auto_solve)
        debugPrint(3, 'done generating constraint animation')
 def callSolveConstraints(self):
     from assembly2solver import solveConstraints
     solveConstraints( FreeCAD.ActiveDocument )
示例#13
0
 def callSolveConstraints(self):
     from assembly2solver import solveConstraints
     solveConstraints(FreeCAD.ActiveDocument)
    def generate_animation( self ):
        preferences = FreeCAD.ParamGet("User parameter:BaseApp/Preferences/Mod/Assembly2")
        org_auto_solve = preferences.GetBool('autoSolveConstraintAttributesChanged', True)
        preferences.SetBool('autoSolveConstraintAttributesChanged', False)
        try:
            if hasattr( self, 'constraintAnimator' ):
                 self.constraintAnimator.stop()
            from assembly2solver import solveConstraints
            P = {}
            for p in animation_parameters:
                if hasattr(p,'getValue'):
                    p.add_property_to_freecad_object()
                    P[p.name] = p.getValue()
            debugPrint(3, 'generate_animation parms %s' % P )
            constraint_to_animate = self.taskDialog.constraint_to_animate
            self.original_expressions = constraint_to_animate.ExpressionEngine #[('angle', '12')]
            self.X = []
            if not hasattr(constraint_to_animate, 'a'):
                constraint_to_animate.addProperty(
                    {'angle_between_planes':'App::PropertyAngle', 'plane':'App::PropertyDistance', 'circularEdge':'App::PropertyDistance'}[ constraint_to_animate.Type ], 
                    'a', 
                    "animationParameters"
                    )
                constraint_to_animate.setEditorMode( 'a', 2)
            attr_to_animate = {'angle_between_planes':'angle', 'plane':'offset', 'circularEdge':'offset'}[ constraint_to_animate.Type ]
            attr_org_value = getattr( constraint_to_animate, attr_to_animate)
            constraint_to_animate.setExpression( attr_to_animate, P['animation_exp'] )

            moduleVars['progressDialog'] = QtGui.QProgressDialog("Generating Animation", "Cancel", 0, P['a_n'])
            p = moduleVars['progressDialog']
            p.setWindowModality(QtCore.Qt.WindowModal)
            p.forceShow()
            A = numpy.linspace(P['a_0'],P['a_1'],P['a_n'])
            for count, a in enumerate(A):
                if not p.wasCanceled():
                    p.setLabelText( 'solving %i/%i' % (count+1, P['a_n']) )
                    p.setValue(count)
                    debugPrint(3, 'solving constraint system for a=%1.1f' % a )
                    constraint_to_animate.a = a
                    FreeCAD.ActiveDocument.recompute() #update other expersions
                    constraint_sys = solveConstraints( FreeCAD.ActiveDocument )
                    self.X.append( constraint_sys.variableManager.X.copy() )
                    #variableManager.updateFreeCADValues( constraintSystem.variableManager.X )
            set_exp_to_none = True
            for ent in self.original_expressions:
                if ent[0] == attr_to_animate:
                    constraint_to_animate.setExpression( attr_to_animate,ent[1] )
                    set_exp_to_none = False
            if set_exp_to_none:
                constraint_to_animate.setExpression( attr_to_animate, None )
            setattr( constraint_to_animate, attr_to_animate, attr_org_value )
            if not p.wasCanceled():
                p.setValue(P['a_n']) #hopefully this will close the progress dialog
                if P['interp_method'] == 'none':
                    pass
                elif P['interp_method'] == 'linear':
                    self.X = linear_interp( self.X, A , P['n_interp'] )
                elif P['interp_method'] == 'Cubic_Hermite_spline':
                    self.X = spline_interp( self.X, A , P['n_interp'] )
                else:
                    raise NotImplemented

                self.playStopButton.setEnabled( True )
                self.constraintAnimator = ConstraintAnimator( self.X, constraint_sys.variableManager)
                if P['play_after_generate']:
                    self.playStopButton_clicked()
        except:
            FreeCAD.Console.PrintError( traceback.format_exc() )
        preferences.SetBool('autoSolveConstraintAttributesChanged',org_auto_solve)
        debugPrint(3, 'done generating constraint animation' )
示例#15
0
 def reconstraints(self):
 	solveConstraints(App.ActiveDocument)
 def reject(self): #or more correctly close, given the button settings
     if hasattr( self.form, 'constraintAnimator' ):
         self.form.constraintAnimator.stop()
         from assembly2solver import solveConstraints
         solveConstraints( FreeCAD.ActiveDocument )
     FreeCADGui.Control.closeDialog()
示例#17
0
    def Activated(self):
        #disable proxies solving the system as their objects are updated
        doc_assembly = FreeCAD.ActiveDocument
        solve_assembly_constraints = False
        YesToAll_clicked = False
        for obj in doc_assembly.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 os.path.exists( obj.sourceFile ):
                    debugPrint( 3, '%s.sourceFile %s is missing, attempting to repair it' % (obj.Name,  obj.sourceFile) )
                    replacement = None
                    aFolder, aFilename = posixpath.split( doc_assembly.FileName )
                    sParts = path_split( posixpath, obj.sourceFile)
                    debugPrint( 3, '  obj.sourceFile parts %s' % sParts )
                    replacement = None
                    previousRejects = []
                    while replacement == None and aFilename <> '':
                        for i in reversed(range(len(sParts))):
                            newFn = aFolder
                            for j in range(i,len(sParts)):
                                newFn = posixpath.join( newFn,sParts[j] )
                            debugPrint( 4, '    checking %s' % newFn )
                            if os.path.exists( newFn ) and not newFn in previousRejects :
                                if YesToAll_clicked:
                                    replacement = newFn
                                    break
                                reply = QtGui.QMessageBox.question(
                                    QtGui.qApp.activeWindow(), "%s source file not found" % obj.Name,
                                    "Unable to find\n  %s \nUse \n  %s\n instead?" % (obj.sourceFile, newFn) , 
                                    QtGui.QMessageBox.Yes | QtGui.QMessageBox.YesToAll | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
                                if reply == QtGui.QMessageBox.Yes:
                                    replacement = newFn
                                    break
                                if reply == QtGui.QMessageBox.YesToAll:
                                    replacement = newFn
                                    YesToAll_clicked = True
                                    break
                                else:
                                    previousRejects.append( newFn )
                        aFolder, aFilename = posixpath.split( aFolder )
                    if replacement <> None:
                        obj.sourceFile = replacement
                    else:
                        QtGui.QMessageBox.critical(  QtGui.qApp.activeWindow(), "Source file not found", "update of %s aborted!\nUnable to find %s" % (obj.Name, obj.sourceFile) )
                        obj.timeLastImport = 0 #force update if users repairs link
                if os.path.exists( obj.sourceFile ):
                    if os.path.getmtime( obj.sourceFile ) > obj.timeLastImport:
                        importPart( obj.sourceFile, obj.Name,  doc_assembly )
                        solve_assembly_constraints = True
        if solve_assembly_constraints:
            solveConstraints( doc_assembly )
        # constraint mirror house keeping

        for obj in doc_assembly.Objects: #for adding creating mirrored constraints in old files
            if 'ConstraintInfo' in obj.Content:
                if doc_assembly.getObject( obj.Object1 ) == None or doc_assembly.getObject( obj.Object2 ) == None: 
                    debugPrint(2, 'removing %s which refers to non-existent objects' % obj.Name)
                    doc_assembly.removeObject( obj.Name ) #required for FreeCAD 0.15 which does not support the on-delete method
                if group_constraints_under_parts():
                    if not hasattr( obj.ViewObject.Proxy, 'mirror_name'):
                        if isinstance( doc_assembly.getObject( obj.Object1 ).Proxy, Proxy_importPart) \
                                or isinstance( doc_assembly.getObject( obj.Object2 ).Proxy, Proxy_importPart):
                            debugPrint(2, 'creating mirror of %s' % obj.Name)
                            doc_assembly.getObject( obj.Object2 ).touch()
                            obj.ViewObject.Proxy.mirror_name = create_constraint_mirror(  obj, obj.ViewObject.Proxy.iconPath )
            elif 'ConstraintNfo' in obj.Content: #constraint mirror
                if  doc_assembly.getObject( obj.ViewObject.Proxy.constraintObj_name ) == None:
                    debugPrint(2, 'removing %s which mirrors/links to a non-existent constraint' % obj.Name)
                    doc_assembly.removeObject( obj.Name ) #clean up for FreeCAD 0.15 which does not support the on-delete method
                elif not group_constraints_under_parts():
                     debugPrint(2, 'removing %s since group_constraints_under_parts=False' % obj.Name)
                     delattr( doc_assembly.getObject( obj.ViewObject.Proxy.constraintObj_name ),  'mirror_name' )
                     doc_assembly.removeObject( obj.Name ) 
            elif hasattr(obj,'Proxy') and isinstance( obj.Proxy, Proxy_importPart) and not isinstance( obj.ViewObject.Proxy, ImportedPartViewProviderProxy):
                obj.ViewObject.Proxy = ImportedPartViewProviderProxy()
                debugPrint(2, '%s.ViewObject.Proxy = ImportedPartViewProviderProxy()'%obj.Name)
        doc_assembly.recompute()
	def Activated(self):
		from assembly2solver import solveConstraints
		constraintSystem = solveConstraints(FreeCAD.ActiveDocument)
		self.taskPanel = AnimateDegreesOfFreedomTaskPanel( constraintSystem )
		FreeCADGui.Control.showDialog( self.taskPanel )
示例#19
0
 def Activated(self):
     from assembly2solver import solveConstraints
     constraintSystem = solveConstraints(FreeCAD.ActiveDocument)
     self.taskPanel = AnimateDegreesOfFreedomTaskPanel(constraintSystem)
     FreeCADGui.Control.showDialog(self.taskPanel)
示例#20
0
    def Activated(self):
        #disable proxies solving the system as their objects are updated
        doc_assembly = FreeCAD.ActiveDocument
        solve_assembly_constraints = False
        YesToAll_clicked = False
        for obj in doc_assembly.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 os.path.exists( obj.sourceFile ) and  path_rel_to_abs( obj.sourceFile ) is None:
                    debugPrint( 3, '%s.sourceFile %s is missing, attempting to repair it' % (obj.Name,  obj.sourceFile) )
                    replacement = None
                    aFolder, aFilename = posixpath.split( doc_assembly.FileName )
                    sParts = path_split( posixpath, obj.sourceFile)
                    debugPrint( 3, '  obj.sourceFile parts %s' % sParts )
                    replacement = None
                    previousRejects = []
                    while replacement == None and aFilename <> '':
                        for i in reversed(range(len(sParts))):
                            newFn = aFolder
                            for j in range(i,len(sParts)):
                                newFn = posixpath.join( newFn,sParts[j] )
                            debugPrint( 4, '    checking %s' % newFn )
                            if os.path.exists( newFn ) and not newFn in previousRejects :
                                if YesToAll_clicked:
                                    replacement = newFn
                                    break
                                reply = QtGui.QMessageBox.question(
                                    QtGui.qApp.activeWindow(), "%s source file not found" % obj.Name,
                                    "Unable to find\n  %s \nUse \n  %s\n instead?" % (obj.sourceFile, newFn) ,
                                    QtGui.QMessageBox.Yes | QtGui.QMessageBox.YesToAll | QtGui.QMessageBox.No, QtGui.QMessageBox.Yes)
                                if reply == QtGui.QMessageBox.Yes:
                                    replacement = newFn
                                    break
                                if reply == QtGui.QMessageBox.YesToAll:
                                    replacement = newFn
                                    YesToAll_clicked = True
                                    break
                                else:
                                    previousRejects.append( newFn )
                        aFolder, aFilename = posixpath.split( aFolder )
                    if replacement <> None:
                        obj.sourceFile = replacement
                    else:
                        QtGui.QMessageBox.critical(  QtGui.qApp.activeWindow(), "Source file not found", "update of %s aborted!\nUnable to find %s" % (obj.Name, obj.sourceFile) )
                        obj.timeLastImport = 0 #force update if users repairs link
                if path_rel_to_abs( obj.sourceFile ) is not None:
                    absolutePath = path_rel_to_abs( obj.sourceFile )
                    if os.path.getmtime( absolutePath ) > obj.timeLastImport:
                        importPart( absolutePath, obj.Name,  doc_assembly )
                        solve_assembly_constraints = True
                if os.path.exists( obj.sourceFile ):
                    if os.path.getmtime( obj.sourceFile ) > obj.timeLastImport:
                        importPart( obj.sourceFile, obj.Name,  doc_assembly )
                        solve_assembly_constraints = True

        if solve_assembly_constraints:
            solveConstraints( doc_assembly )
        # constraint mirror house keeping

        for obj in doc_assembly.Objects: #for adding creating mirrored constraints in old files
            if 'ConstraintInfo' in obj.Content:
                if doc_assembly.getObject( obj.Object1 ) == None or doc_assembly.getObject( obj.Object2 ) == None:
                    debugPrint(2, 'removing %s which refers to non-existent objects' % obj.Name)
                    doc_assembly.removeObject( obj.Name ) #required for FreeCAD 0.15 which does not support the on-delete method
                if group_constraints_under_parts():
                    if not hasattr( obj.ViewObject.Proxy, 'mirror_name'):
                        if isinstance( doc_assembly.getObject( obj.Object1 ).Proxy, Proxy_importPart) \
                                or isinstance( doc_assembly.getObject( obj.Object2 ).Proxy, Proxy_importPart):
                            debugPrint(2, 'creating mirror of %s' % obj.Name)
                            doc_assembly.getObject( obj.Object2 ).touch()
                            obj.ViewObject.Proxy.mirror_name = create_constraint_mirror(  obj, obj.ViewObject.Proxy.iconPath )
            elif 'ConstraintNfo' in obj.Content: #constraint mirror
                if  doc_assembly.getObject( obj.ViewObject.Proxy.constraintObj_name ) == None:
                    debugPrint(2, 'removing %s which mirrors/links to a non-existent constraint' % obj.Name)
                    doc_assembly.removeObject( obj.Name ) #clean up for FreeCAD 0.15 which does not support the on-delete method
                elif not group_constraints_under_parts():
                     debugPrint(2, 'removing %s since group_constraints_under_parts=False' % obj.Name)
                     delattr( doc_assembly.getObject( obj.ViewObject.Proxy.constraintObj_name ),  'mirror_name' )
                     doc_assembly.removeObject( obj.Name )
            elif hasattr(obj,'Proxy') and isinstance( obj.Proxy, Proxy_importPart) and not isinstance( obj.ViewObject.Proxy, ImportedPartViewProviderProxy):
                obj.ViewObject.Proxy = ImportedPartViewProviderProxy()
                debugPrint(2, '%s.ViewObject.Proxy = ImportedPartViewProviderProxy()'%obj.Name)
        doc_assembly.recompute()