Пример #1
0
 def unlinkObject(self, featureToUnlink):
     '''Redirects all links to this object, to make it possible to recompute it individually. TODO: expressions!!'''
     doc = featureToUnlink.Document
     ListOfDependentObjects = featureToUnlink.InList #<rant> naming list of objects that are dependent on the feature as InList is bullshit. InList should have been list of inputs - that is, list of objects this feature depends on. But it's back-to-front. =<
     if len(self.actionList) > 0:
         raise ValueError("unlinker hasn't restored the changes it did previously. Can't unlink another object.")
     for obj in ListOfDependentObjects:
         for propname in obj.PropertiesList:
             try:
                 typ = obj.getTypeIdOfProperty(propname)
                 val = getattr(obj,propname)
                 bool_changed = True
                 if typ == 'App::PropertyLink':                    
                     setattr(obj,propname,None)
                 elif typ == 'App::PropertyLinkSub':
                     #val is (feature,["Edge1","Face2"])
                     setattr(obj,propname,None)
                 elif typ == 'App::PropertyLinkList':
                     setattr(obj,propname,[])
                 elif typ == 'App::PropertyLinkSubList':
                     setattr(obj,propname,[])
                 else:
                     bool_changed = False
                 
                 if bool_changed:
                     self.actionList.append((obj,propname,val))
             except Exception as err:
                 LE.error(None, "While temporarily removing all links to an object, an error occured.\n" +
                          "Error:"+err.message+"\n" +
                          "object = "+obj.Name+"\n" +
                          "property = "+propname+"\n" +
                          "value to be restored = "+repr(value))
Пример #2
0
 def restoreLinks(self):
     for (obj, propname, value) in self.actionList:
         try:
             setattr(obj,propname,value)
         except Exception as err:
             LE.error(None, "An error occured while restoring links.\n" +
                      "Error:"+err.message+"\n" +
                      "object = "+obj.Name+"\n" +
                      "property = "+propname+"\n" +
                      "value to be restored = "+repr(value))
     self.actionList = []
Пример #3
0
    def derivedExecute(self, selfobj):

        if selfobj.Recomputing == "Disabled":
            raise ValueError(
                selfobj.Name +
                ": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it."
            )
        try:

            # do the subsequencing in this document first, to verify stuff is set up correctly, and to obtain sequence length
            if self.isVerbose():
                print("In-place pre-subsequencing, for early check")
            n_seq, subs_linkdict = self.makeSubsequence(
                selfobj, screen(selfobj.ObjectToLoopOver))

            bGui = bool(
                App.GuiUp
            ) and Executer.globalIsCreatingLatticeFeature  #disabled for most recomputes, because it causes a crash if property edits are approved by hitting Enter
            if bGui:
                import PySide
                progress = PySide.QtGui.QProgressDialog(
                    u"Recomputing " + selfobj.Label, u"Abort", 0, n_seq + 1)
                progress.setModal(True)
                progress.show()

            doc1 = selfobj.Document
            doc2 = App.newDocument()
            object_to_take_in_doc2 = None  # define the variable, to prevent del() in finally block from raising another error
            object_to_loop_in_doc2 = None
            try:
                if self.isVerbose():
                    print(
                        "Copying object with dependencies to a temporary document..."
                    )

                doc2.copyObject(screen(selfobj.ObjectToTake), True)

                if self.isVerbose():
                    print("Enabling nested para/toposeries, if any...")
                #if there are nested para/toposeries in the dependencies, make sure to enable them
                for objd2 in doc2.Objects:
                    if hasattr(objd2, "Recomputing"):
                        try:
                            objd2.Recomputing = "Enabled"
                            objd2.purgeTouched()
                        except exception:
                            Executer.warning(
                                selfobj, "Failed to enable recomputing of " +
                                objd2.Name)

                object_to_take_in_doc2 = doc2.getObject(
                    screen(selfobj.ObjectToTake).Name)
                object_to_loop_in_doc2 = doc2.getObject(
                    screen(selfobj.ObjectToLoopOver).Name)
                if bGui:
                    progress.setValue(1)

                if self.isVerbose():
                    print("Repeating subsequencing in temporary document...")
                n_seq, subs_linkdict = self.makeSubsequence(
                    selfobj, object_to_loop_in_doc2)

                output_shapes = []
                for i in range(n_seq):
                    if self.isVerbose():
                        print("Computing {x}/{y}".format(x=i + 1, y=n_seq))

                    for key in subs_linkdict:
                        writeProperty(doc2, key[0], key[1],
                                      subs_linkdict[key][i])

                    #recompute
                    doc2.recompute()

                    #get shape
                    shape = None
                    for obj in doc2.Objects:
                        if 'Invalid' in obj.State:
                            Executer.error(
                                obj,
                                "Recomputing shape for subsequence index " +
                                repr(i) + " failed.")

                            scale = 1.0
                            try:
                                if not screen(
                                        selfobj.ObjectToTake).Shape.isNull():
                                    scale = screen(
                                        selfobj.ObjectToTake
                                    ).Shape.BoundBox.DiagonalLength / math.sqrt(
                                        3)
                            except Exception:
                                pass
                            if scale < DistConfusion * 100:
                                scale = 1.0
                            shape = markers.getNullShapeShape(scale)
                    if shape is None:
                        shape = object_to_take_in_doc2.Shape.copy()
                    output_shapes.append(shape)

                    #update progress
                    if bGui:
                        progress.setValue(progress.value() + 1)
                        if progress.wasCanceled():
                            raise Executer.CancelError()

            finally:
                #delete all references, before destroying the document. Probably not required, but to be sure...
                if self.isVerbose():
                    print("Cleanup...")

                del (object_to_take_in_doc2)
                del (object_to_loop_in_doc2)
                doc2_name = doc2.Name
                del (doc2)
                App.closeDocument(doc2_name)
                if bGui:
                    progress.setValue(n_seq + 1)

            selfobj.Shape = Part.makeCompound(output_shapes)

            output_is_lattice = lattice2BaseFeature.isObjectLattice(
                screen(selfobj.ObjectToTake))
            if 'Auto' in selfobj.isLattice:
                new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off'
                if selfobj.isLattice != new_isLattice:  #check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color)
                    selfobj.isLattice = new_isLattice
        finally:
            if selfobj.Recomputing == "Recompute Once":
                selfobj.Recomputing = "Disabled"
        return "suppress"  # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.
Пример #4
0
    def derivedExecute(self,selfobj):
        # values generator should be functional even if recomputing is disabled, so do it first
        self.assureGenerator(selfobj)
        self.generator.updateReadonlyness()
        self.generator.execute()
        
        if selfobj.Recomputing == "Disabled":
            raise ValueError(selfobj.Name+": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it.")
        try:            
            #test parameter references and read out their current values
            refstr = selfobj.ParameterRef #dict(selfobj.ExpressionEngine)["ParameterRef"]
            refstrs = refstr.replace(";","\t").split("\t")
            defvalues = []
            for refstr in refstrs:
                refstr = refstr.strip();
                val = None;
                try:
                    val = getParameter(selfobj.Document,refstr)
                except Exception as err:
                    App.Console.PrintError("{obj}: failed to read out parameter '{param}': {err}\n"
                                            .format(obj= selfobj.Name,
                                                    param= refstr,
                                                    err= err.message))
                defvalues.append(val)
            N_params = len(defvalues)
            if N_params == 0:
                raise ValueError(selfobj.Name+": ParameterRef is not set. It is required.")
            
            #parse values
            values = []
            for strrow in selfobj.Values:
                if len(strrow) == 0:
                    break;
                row = strrow.split(";")
                row = [(strv.strip() if len(strv.strip())>0 else None) for strv in row] # clean out spaces and replace empty strings with None
                if len(row) < N_params:
                    row += [None]*(N_params - len(row))
                values.append(row)
            
            # convert values to type, filling in defaults where values are missing
            for row in values:
                for icol in range(N_params):
                    strv = row[icol]
                    val = None
                    if strv is None:
                        val = defvalues[icol]
                    elif selfobj.ParameterType == 'float' or selfobj.ParameterType == 'int':
                        val = float(strv.replace(",","."))
                        if selfobj.ParameterType == 'int':
                            val = int(round(val))
                    elif selfobj.ParameterType == 'string':
                        val = strv.strip()
                    else:
                        raise ValueError(selfobj.Name + ": ParameterType option not implemented: "+selfobj.ParameterType)
                    row[icol] = val
            
            if len(values) == 0:
                scale = 1.0
                try:
                    if not selfobj.Object.Shape.isNull():
                        scale = selfobj.Object.Shape.BoundBox.DiagonalLength/math.sqrt(3)
                except Exception:
                    pass
                if scale < DistConfusion * 100:
                    scale = 1.0
                selfobj.Shape = markers.getNullShapeShape(scale)
                raise ValueError(selfobj.Name + ": list of values is empty.") 
            
            bGui = False #bool(App.GuiUp) #disabled temporarily, because it causes a crash if property edits are approved by hitting Enter
            if bGui:
                import PySide
                progress = PySide.QtGui.QProgressDialog(u"Recomputing "+selfobj.Label, u"Abort", 0, len(values)+1)
                progress.setModal(True)
                progress.show()
            
            doc1 = selfobj.Document
            doc2 = App.newDocument()
            object_in_doc2 = None # define the variable, to prevent del() in finally block from raising another error
            try:
                doc2.copyObject(selfobj.Object, True)
                
                #if there are nested paraseries in the dependencies, make sure to enable them
                for objd2 in doc2.Objects:
                    if hasattr(objd2,"Recomputing"):
                        try:
                            objd2.Recomputing = "Enabled"
                            objd2.purgeTouched()
                        except exception:
                            lattice2Executer.warning(selfobj,"Failed to enable recomputing of "+objd2.Name)
                
                object_in_doc2 = doc2.getObject(selfobj.Object.Name)
                if bGui:
                    progress.setValue(1)
                output_shapes = []
                for row in values:
                    for icol in range(len(row)):
                        setParameter(doc2, refstrs[icol].strip(), row[icol])
                    
                    #recompute
                    doc2.recompute()
                    
                    #get shape
                    shape = None
                    for obj in doc2.Objects:
                        if 'Invalid' in obj.State:
                            lattice2Executer.error(obj,"Recomputing shape for parameter value of "+repr(row)+" failed.")
                            
                            scale = 1.0
                            try:
                                if not selfobj.Object.Shape.isNull():
                                    scale = selfobj.Object.Shape.BoundBox.DiagonalLength/math.sqrt(3)
                            except Exception:
                                pass
                            if scale < DistConfusion * 100:
                                scale = 1.0
                            shape = markers.getNullShapeShape(scale)
                    if shape is None:
                        shape = object_in_doc2.Shape.copy()
                    output_shapes.append(shape)
                    
                    #update progress
                    if bGui:
                        progress.setValue(progress.value()+1)
                        if progress.wasCanceled():
                            raise lattice2Executer.CancelError()
                    
            finally:
                #delete all references, before destroying the document. Probably not required, but to be sure...
                del(object_in_doc2)
                doc2_name = doc2.Name
                del(doc2)
                App.closeDocument(doc2_name)
                if bGui:
                    progress.setValue(len(values)+1)

                
            selfobj.Shape = Part.makeCompound(output_shapes)

            output_is_lattice = lattice2BaseFeature.isObjectLattice(selfobj.Object)
            if 'Auto' in selfobj.isLattice:
                new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off'
                if selfobj.isLattice != new_isLattice:#check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color)
                    selfobj.isLattice = new_isLattice                    
        finally:
            if selfobj.Recomputing == "Recompute Once":
                selfobj.Recomputing = "Disabled"
        return "suppress" # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.
Пример #5
0
    def derivedExecute(self, selfobj):
        # values generator should be functional even if recomputing is disabled, so do it first
        self.assureGenerator(selfobj)
        self.generator.updateReadonlyness()
        self.generator.execute()

        if selfobj.Recomputing == "Disabled":
            raise ValueError(
                selfobj.Name +
                ": recomputing of this object is currently disabled. Modify 'Recomputing' property to enable it."
            )
        try:
            #test parameter references and read out their current values
            refstr = selfobj.ParameterRef  #dict(selfobj.ExpressionEngine)["ParameterRef"]
            refstrs = refstr.replace(";", "\t").split("\t")
            defvalues = []
            for refstr in refstrs:
                refstr = refstr.strip()
                val = None
                try:
                    val = getParameter(selfobj.Document, refstr)
                except Exception as err:
                    App.Console.PrintError(
                        "{obj}: failed to read out parameter '{param}': {err}\n"
                        .format(obj=selfobj.Name, param=refstr, err=str(err)))
                defvalues.append(val)
            N_params = len(defvalues)
            if N_params == 0:
                raise ValueError(selfobj.Name +
                                 ": ParameterRef is not set. It is required.")

            #parse values
            values = []
            for strrow in selfobj.Values:
                if len(strrow) == 0:
                    break
                row = strrow.split(";")
                row = [
                    (strv.strip() if len(strv.strip()) > 0 else None)
                    for strv in row
                ]  # clean out spaces and replace empty strings with None
                if len(row) < N_params:
                    row += [None] * (N_params - len(row))
                values.append(row)

            # convert values to type, filling in defaults where values are missing
            for row in values:
                for icol in range(N_params):
                    strv = row[icol]
                    val = None
                    if strv is None:
                        val = defvalues[icol]
                    elif selfobj.ParameterType == 'float' or selfobj.ParameterType == 'int':
                        val = float(strv.replace(",", "."))
                        if selfobj.ParameterType == 'int':
                            val = int(round(val))
                    elif selfobj.ParameterType == 'string':
                        val = strv.strip()
                    else:
                        raise ValueError(
                            selfobj.Name +
                            ": ParameterType option not implemented: " +
                            selfobj.ParameterType)
                    row[icol] = val

            if len(values) == 0:
                scale = 1.0
                try:
                    if not screen(selfobj.Object).Shape.isNull():
                        scale = screen(
                            selfobj.Object
                        ).Shape.BoundBox.DiagonalLength / math.sqrt(3)
                except Exception:
                    pass
                if scale < DistConfusion * 100:
                    scale = 1.0
                selfobj.Shape = markers.getNullShapeShape(scale)
                raise ValueError(selfobj.Name + ": list of values is empty.")

            bGui = False  #bool(App.GuiUp) #disabled temporarily, because it causes a crash if property edits are approved by hitting Enter
            if bGui:
                import PySide
                progress = PySide.QtGui.QProgressDialog(
                    u"Recomputing " + selfobj.Label, u"Abort", 0,
                    len(values) + 1)
                progress.setModal(True)
                progress.show()

            doc1 = selfobj.Document
            doc2 = App.newDocument(
            )  #create temporary doc to do the computations

            # assign doc's filename before copying objects, otherwise we get errors with xlinks
            try:
                doc2.FileName = doc1.FileName
            except Exception as err:
                pass  #in old FreeCADs, FileName property is read-only, we can safely ignore that

            object_in_doc2 = None  # define the variable, to prevent del() in finally block from raising another error
            try:
                doc2.copyObject(screen(selfobj.Object), True)

                #if there are nested paraseries in the dependencies, make sure to enable them
                for objd2 in doc2.Objects:
                    if hasattr(objd2, "Recomputing"):
                        try:
                            objd2.Recomputing = "Enabled"
                            objd2.purgeTouched()
                        except exception:
                            lattice2Executer.warning(
                                selfobj, "Failed to enable recomputing of " +
                                objd2.Name)

                object_in_doc2 = doc2.getObject(screen(selfobj.Object).Name)
                if bGui:
                    progress.setValue(1)
                output_shapes = []
                for row in values:
                    for icol in range(len(row)):
                        setParameter(doc2, refstrs[icol].strip(), row[icol])

                    #recompute
                    doc2.recompute()

                    #get shape
                    shape = None
                    for obj in doc2.Objects:
                        if 'Invalid' in obj.State:
                            lattice2Executer.error(
                                obj,
                                "Recomputing shape for parameter value of " +
                                repr(row) + " failed.")

                            scale = 1.0
                            try:
                                if not screen(selfobj.Object).Shape.isNull():
                                    scale = screen(
                                        selfobj.Object
                                    ).Shape.BoundBox.DiagonalLength / math.sqrt(
                                        3)
                            except Exception:
                                pass
                            if scale < DistConfusion * 100:
                                scale = 1.0
                            shape = markers.getNullShapeShape(scale)
                    if shape is None:
                        shape = object_in_doc2.Shape.copy()
                    output_shapes.append(shape)

                    #update progress
                    if bGui:
                        progress.setValue(progress.value() + 1)
                        if progress.wasCanceled():
                            raise lattice2Executer.CancelError()

            finally:
                #delete all references, before destroying the document. Probably not required, but to be sure...
                del (object_in_doc2)
                doc2_name = doc2.Name
                del (doc2)
                App.closeDocument(doc2_name)
                if bGui:
                    progress.setValue(len(values) + 1)

            selfobj.Shape = Part.makeCompound(output_shapes)

            output_is_lattice = lattice2BaseFeature.isObjectLattice(
                screen(selfobj.Object))
            if 'Auto' in selfobj.isLattice:
                new_isLattice = 'Auto-On' if output_is_lattice else 'Auto-Off'
                if selfobj.isLattice != new_isLattice:  #check, to not cause onChanged without necessity (onChange messes with colors, it's better to keep user color)
                    selfobj.isLattice = new_isLattice
        finally:
            if selfobj.Recomputing == "Recompute Once":
                selfobj.Recomputing = "Disabled"
        return "suppress"  # "suppress" disables most convenience code of lattice2BaseFeature. We do it because we build a nested array, which are not yet supported by lattice WB.