Example #1
0
    def execute(self,selfobj):
        #validity check
        if isObjectLattice(selfobj.Object):
            import lattice2Executer
            lattice2Executer.warning(selfobj,"A generic shape is expected, but a placement/array was supplied. It will be treated as a generic shape.")

        rst = [] #variable to receive the final list of shapes
        lnkobj = selfobj.Object
        for subname in selfobj.SubNames:
            subname = subname.strip()
            if len(subname)==0:
                raise ValueError("Empty subname! Not allowed.")
            if 'Face' in subname:
                index = int(subname.replace('Face',''))-1
                rst.append(lnkobj.Shape.Faces[index])
            elif 'Edge' in subname:
                index = int(subname.replace('Edge',''))-1
                rst.append(lnkobj.Shape.Edges[index])
            elif 'Vertex' in subname:
                index = int(subname.replace('Vertex',''))-1
                rst.append(lnkobj.Shape.Vertexes[index])
            else:
                lattice2Executer.warning(selfobj,"Unexpected subelement name: "+subname+". Trying to extract it with .Shape.getElement()...")
                rst.append(linkobj.Shape.getElement(subname))
        if len(rst) == 0:
            scale = 1.0
            try:
                if selfobj.Object:
                    scale = selfobj.Object[0].Shape.BoundBox.DiagonalLength/math.sqrt(3)
            except Exception as err:
                App.Console.PrintError(selfobj.Name+": Failed to estimate size of marker shape")
            if scale < DistConfusion * 100:
                scale = 1.0
            selfobj.Shape = markers.getNullShapeShape(scale)
            raise ValueError('Nothing is linked, apparently!') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
        
        if len(rst) > 1:
            selfobj.Shape = Part.makeCompound(rst)
        else: # don't make compound of one shape, output it directly
            sh = rst[0]
            # absorb placement of original shape
            sh = ShapeCopy.transformCopy(sh)
            # apply Placement that is filled into feature's Placement property (not necessary)
            sh.Placement = selfobj.Placement
            selfobj.Shape = sh
Example #2
0
    def execute(self, selfobj):
        self.assureProperties(selfobj)

        #validity check
        if isObjectLattice(screen(selfobj.Object)):
            import lattice2Executer
            lattice2Executer.warning(
                selfobj,
                "A generic shape is expected, but a placement/array was supplied. It will be treated as a generic shape."
            )

        lnkobj = screen(selfobj.Object)
        sh = lnkobj.Shape

        # subsequencing
        full_link = (lnkobj, selfobj.SubNames)
        if selfobj.Looping == 'Single':
            lnkseq = [full_link]
        else:
            lnkseq = LSS.Subsequence_auto(full_link, selfobj.CompoundTraversal,
                                          selfobj.Looping)

        # main code
        seq_packs = [
        ]  #pack = single item of subsequence. Pack contains list of elements that were selected.
        shape_count = 0
        for lnk in lnkseq:  # loop over subsequence (if Looping == 'Single', this loop will only loop once)
            # extract the pack
            assert (
                lnk[0] is lnkobj
            )  # all links should point to elements of one object anyway
            subnames = lnk[1]
            pack = [
            ]  #acculumator, to eventually become a compound of shapes for this subsequence item
            for subname in subnames:
                subname = subname.strip()
                if len(subname) == 0:
                    raise ValueError("Empty subname! Not allowed.")
                if 'Face' in subname:  # manual handling of standard cases, because support for negative indexing is needed
                    index = int(subname.replace('Face', '')) - 1
                    pack.append(sh.Faces[index])
                elif 'Edge' in subname:
                    index = int(subname.replace('Edge', '')) - 1
                    pack.append(sh.Edges[index])
                elif 'Vertex' in subname:
                    index = int(subname.replace('Vertex', '')) - 1
                    pack.append(sh.Vertexes[index])
                else:  #fail-safe. non-standard sublink.
                    import lattice2Executer
                    lattice2Executer.warning(
                        selfobj, "Unexpected subelement name: " + subname +
                        ". Trying to extract it with .Shape.getElement()...")
                    pack.append(sh.getElement(subname))

            shape_count += len(pack)

            # convert list into compound
            if len(pack) == 1:
                pack = ShapeCopy.transformCopy(pack[0])
            else:
                pack = Part.makeCompound(pack)

            # accumulate
            seq_packs.append(pack)

        # convert list into compound
        if len(seq_packs) == 1:
            seq_packs = seq_packs[0]
        else:
            seq_packs = Part.makeCompound(seq_packs)

        if shape_count == 0:
            # no shapes collected, FAIL!
            scale = 1.0
            try:
                if screen(selfobj.Object):
                    scale = screen(
                        selfobj.Object
                    ).Shape.BoundBox.DiagonalLength / math.sqrt(3)
            except Exception as err:
                App.Console.PrintError(
                    selfobj.Name + ": Failed to estimate size of marker shape")
            if scale < DistConfusion * 100:
                scale = 1.0
            selfobj.Shape = markers.getNullShapeShape(scale)
            raise ValueError(
                'Nothing is linked, apparently!'
            )  #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.

        # done!
        selfobj.Shape = seq_packs
Example #3
0
 def execute(self,obj):
     rst = [] #variable to receive the final list of shapes
     shp = screen(obj.Base).Shape
     if obj.Mode == 'bypass':
         rst = [shp]
     elif obj.Mode == 'Leaves':
         rst = LCE.AllLeaves(shp)
     elif obj.Mode == 'CompSolids':
         rst = shp.CompSolids
     elif obj.Mode == 'Solids':
         rst = shp.Solids
     elif obj.Mode == 'Shells':
         rst = shp.Shells
     elif obj.Mode == 'OpenWires':
         openWires = []
         shells = shp.Shells
         for shell in shells:
             openEdges = shell.getFreeEdges().childShapes()
             if len(openEdges) > 1: # edges need to be fused into wires
                 clusters = Part.getSortedClusters(openEdges)
                 wires = [Part.Wire(cluster) for cluster in clusters]
             else: 
                 wires = openEdges
             openWires.extend(wires)
         rst = openWires
     elif obj.Mode == 'Faces':
         rst = shp.Faces
     elif obj.Mode == 'Wires':
         rst = shp.Wires
     elif obj.Mode == 'Edges':
         rst = shp.Edges
     elif obj.Mode == 'Seam edges':
         rst = getAllSeams(shp)
     elif obj.Mode == 'Non-seam edges':
         seams = getAllSeams(shp)
         edges = shp.Edges
         rst = []
         for e in edges:
             bIsSeam = False
             for s in seams:
                 if e.isSame(s):
                     bIsSeam = True
                     break
             if not bIsSeam:
                 rst.append(e)
     elif obj.Mode == 'Vertices':
         rst = shp.Vertexes
     else:
         raise ValueError('Downgrade mode not implemented:'+obj.Mode)
     
     if len(rst) == 0:
         scale = 1.0
         if not screen(obj.Base).Shape.isNull():
             scale = screen(obj.Base).Shape.BoundBox.DiagonalLength/math.sqrt(3)
         if scale < DistConfusion * 100:
             scale = 1.0
         obj.Shape = markers.getNullShapeShape(scale)
         raise ValueError('Downgrade output is null') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
     
     obj.Shape = Part.makeCompound(rst)
     return
Example #4
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.
Example #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= 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.
Example #6
0
    def execute(self, obj):
        # please, don't override. Override derivedExecute instead.

        plms = self.derivedExecute(obj)

        if plms is not None:
            if plms == "suppress":
                return
            obj.NumElements = len(plms)
            shapes = []
            markerSize = obj.MarkerSize
            if markerSize < DistConfusion:
                markerSize = getMarkerSizeEstimate(plms, obj)
            marker = lattice2Markers.getPlacementMarker(
                scale=markerSize, markerID=obj.MarkerShape)

            bExposing = False
            if obj.ExposePlacement:
                if len(plms) == 1:
                    bExposing = True
                else:
                    lattice2Executer.warning(
                        obj,
                        "Multiple placements are being fed, can't expose placements. Placement property will be forced to zero."
                    )
                    obj.Placement = App.Placement()

            if bExposing:
                obj.Shape = shallowCopy(marker)
                obj.Placement = plms[0]
            else:
                for plm in plms:
                    sh = shallowCopy(marker)
                    sh.Placement = plm
                    shapes.append(sh)

                if len(shapes) == 0:
                    obj.Shape = lattice2Markers.getNullShapeShape(markerSize)
                    raise ValueError('Lattice object is null')

                sh = Part.makeCompound(shapes)
                sh.Placement = obj.Placement
                obj.Shape = sh

            if obj.isLattice == 'Auto-Off':
                obj.isLattice = 'Auto-On'

        else:
            # DerivedExecute didn't return anything. Thus we assume it
            # has assigned the shape, and thus we don't do anything.
            # Moreover, we assume that it is no longer a lattice object, so:
            if obj.isLattice == 'Auto-On':
                obj.isLattice = 'Auto-Off'

            if obj.ExposePlacement:
                if obj.Shape.ShapeType == "Compound":
                    children = obj.Shape.childShapes()
                    if len(children) == 1:
                        obj.Placement = children[0].Placement
                        obj.Shape = children[0]
                    else:
                        obj.Placement = App.Placement()
                else:
                    #nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized.
                    pass
        return
Example #7
0
    def execute(self, obj):
        # please, don't override. Override derivedExecute instead.

        plms = self.derivedExecute(obj)

        if plms is not None:
            if plms == "suppress":
                return
            obj.NumElements = len(plms)
            shapes = []
            markerSize = obj.MarkerSize
            if markerSize < DistConfusion:
                markerSize = getMarkerSizeEstimate(plms)
            marker = lattice2Markers.getPlacementMarker(scale=markerSize, markerID=obj.MarkerShape)

            bExposing = False
            if obj.ExposePlacement:
                if len(plms) == 1:
                    bExposing = True
                else:
                    lattice2Executer.warning(
                        obj,
                        "Multiple placements are being fed, can't expose placements. Placement property will be forced to zero.",
                    )
                    obj.Placement = App.Placement()

            if bExposing:
                obj.Shape = shallowCopy(marker)
                obj.Placement = plms[0]
            else:
                for plm in plms:
                    sh = shallowCopy(marker)
                    sh.Placement = plm
                    shapes.append(sh)

                if len(shapes) == 0:
                    obj.Shape = lattice2Markers.getNullShapeShape(markerSize)
                    raise ValueError("Lattice object is null")

                sh = Part.makeCompound(shapes)
                obj.Shape = sh

            if obj.isLattice == "Auto-Off":
                obj.isLattice = "Auto-On"

        else:
            # DerivedExecute didn't return anything. Thus we assume it
            # has assigned the shape, and thus we don't do anything.
            # Moreover, we assume that it is no longer a lattice object, so:
            if obj.isLattice == "Auto-On":
                obj.isLattice = "Auto-Off"

            if obj.ExposePlacement:
                if obj.Shape.ShapeType == "Compound":
                    children = obj.Shape.childShapes()
                    if len(children) == 1:
                        obj.Placement = children[0].Placement
                        obj.Shape = children[0]
                    else:
                        obj.Placement = App.Placement()
                else:
                    # nothing to do - FreeCAD will take care to make obj.Placement and obj.Shape.Placement synchronized.
                    pass
        return
Example #8
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.
Example #9
0
    def execute(self, obj):
        #validity check
        if isObjectLattice(screen(obj.Base)):
            import lattice2Executer
            lattice2Executer.warning(
                obj,
                "A generic shape is expected, but an array of placements was supplied. It will be treated as a generic shape."
            )

        rst = []  #variable to receive the final list of shapes
        shps = screen(obj.Base).Shape.childShapes()
        if obj.FilterType == 'bypass':
            rst = shps
        elif obj.FilterType == 'specific items':
            rst = []
            flags = [False] * len(shps)
            ranges = obj.items.split(';')
            for r in ranges:
                r_v = r.split(':')
                if len(r_v) == 1:
                    i = int(r_v[0])
                    rst.append(shps[i])
                    flags[i] = True
                elif len(r_v) == 2 or len(r_v) == 3:
                    if len(r_v) == 2:
                        r_v.append(
                            ""
                        )  # fix issue #1: instead of checking length here and there, simply add the missing field =)
                    ifrom = None if len(r_v[0].strip()) == 0 else int(r_v[0])
                    ito = None if len(r_v[1].strip()) == 0 else int(r_v[1])
                    istep = None if len(r_v[2].strip()) == 0 else int(r_v[2])
                    rst = rst + shps[ifrom:ito:istep]
                    for b in flags[ifrom:ito:istep]:
                        b = True
                else:
                    raise ValueError('index range cannot be parsed:' + r)
            if obj.Invert:
                rst = []
                for i in range(0, len(shps)):
                    if not flags[i]:
                        rst.append(shps[i])
        elif obj.FilterType == 'collision-pass':
            stencil = screen(obj.Stencil).Shape
            for s in shps:
                d = s.distToShape(stencil)
                if bool(d[0] < DistConfusion) ^ bool(obj.Invert):
                    rst.append(s)
        elif obj.FilterType == 'window-volume' or obj.FilterType == 'window-area' or obj.FilterType == 'window-length' or obj.FilterType == 'window-distance':
            vals = [0.0] * len(shps)
            for i in range(0, len(shps)):
                if obj.FilterType == 'window-volume':
                    vals[i] = shps[i].Volume
                elif obj.FilterType == 'window-area':
                    vals[i] = shps[i].Area
                elif obj.FilterType == 'window-length':
                    vals[i] = shps[i].Length
                elif obj.FilterType == 'window-distance':
                    vals[i] = shps[i].distToShape(obj.Stencil.Shape)[0]

            maxval = max(vals)
            if obj.Stencil:
                if obj.FilterType == 'window-volume':
                    maxval = obj.Stencil.Shape.Volume
                elif obj.FilterType == 'window-area':
                    maxval = obj.Stencil.Shape.Area
                elif obj.FilterType == 'window-length':
                    maxval = obj.Stencil.Shape.Length
            if obj.OverrideMaxVal:
                maxval = obj.OverrideMaxVal

            valFrom = obj.WindowFrom / 100.0 * maxval
            valTo = obj.WindowTo / 100.0 * maxval

            for i in range(0, len(shps)):
                if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert:
                    rst.append(shps[i])
        else:
            raise ValueError('Filter mode not implemented:' + obj.FilterType)

        if len(rst) == 0:
            scale = 1.0
            if not screen(obj.Base).Shape.isNull():
                scale = screen(
                    obj.Base).Shape.BoundBox.DiagonalLength / math.sqrt(
                        3) / math.sqrt(len(shps))
            if scale < DistConfusion * 100:
                scale = 1.0
            obj.Shape = markers.getNullShapeShape(scale)
            raise ValueError(
                'Nothing passes through the filter'
            )  #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.

        if len(rst) > 1:
            obj.Shape = Part.makeCompound(rst)
        else:  # don't make compound of one shape, output it directly
            sh = rst[0]
            sh = ShapeCopy.transformCopy(sh)
            sh.Placement = obj.Placement
            obj.Shape = sh

        return
Example #10
0
 def execute(self,obj):
     rst = [] #variable to receive the final list of shapes
     shp = obj.Base.Shape
     if obj.Mode == 'bypass':
         rst = [shp]
     elif obj.Mode == 'Leaves':
         rst = LCE.AllLeaves(shp)
     elif obj.Mode == 'CompSolids':
         rst = shp.CompSolids
     elif obj.Mode == 'Solids':
         rst = shp.Solids
     elif obj.Mode == 'Shells':
         rst = shp.Shells
     elif obj.Mode == 'OpenWires':
         openWires = []
         shells = shp.Shells
         for shell in shells:
             openEdges = shell.getFreeEdges().childShapes()
             if len(openEdges) > 1: # edges need to be fused into wires
                 clusters = Part.getSortedClusters(openEdges)
                 wires = [Part.Wire(cluster) for cluster in clusters]
             else: 
                 wires = openEdges
             openWires.extend(wires)
         rst = openWires
     elif obj.Mode == 'Faces':
         rst = shp.Faces
     elif obj.Mode == 'Wires':
         rst = shp.Wires
     elif obj.Mode == 'Edges':
         rst = shp.Edges
     elif obj.Mode == 'Seam edges':
         rst = getAllSeams(shp)
     elif obj.Mode == 'Non-seam edges':
         seams = getAllSeams(shp)
         edges = shp.Edges
         rst = []
         for e in edges:
             bIsSeam = False
             for s in seams:
                 if e.isSame(s):
                     bIsSeam = True
                     break
             if not bIsSeam:
                 rst.append(e)
     elif obj.Mode == 'Vertices':
         rst = shp.Vertexes
     else:
         raise ValueError('Downgrade mode not implemented:'+obj.Mode)
     
     if len(rst) == 0:
         scale = 1.0
         if not obj.Base.Shape.isNull():
             scale = obj.Base.Shape.BoundBox.DiagonalLength/math.sqrt(3)
         if scale < DistConfusion * 100:
             scale = 1.0
         obj.Shape = markers.getNullShapeShape(scale)
         raise ValueError('Downgrade output is null') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
     
     obj.Shape = Part.makeCompound(rst)
     return
Example #11
0
    def execute(self,obj):
        #validity check
        if isObjectLattice(obj.Base):
            import lattice2Executer
            lattice2Executer.warning(obj,"A generic shape is expected, but an array of placements was supplied. It will be treated as a generic shape.")

        rst = [] #variable to receive the final list of shapes
        shps = obj.Base.Shape.childShapes()
        if obj.FilterType == 'bypass':
            rst = shps
        elif obj.FilterType == 'specific items':
            rst = []
            flags = [False] * len(shps)
            ranges = obj.items.split(';')
            for r in ranges:
                r_v = r.split(':')
                if len(r_v) == 1:
                    i = int(r_v[0])
                    rst.append(shps[i])
                    flags[i] = True
                elif len(r_v) == 2 or len(r_v) == 3:
                    if len(r_v) == 2:
                        r_v.append("") # fix issue #1: instead of checking length here and there, simply add the missing field =)
                    ifrom = None   if len(r_v[0].strip()) == 0 else   int(r_v[0])                    
                    ito = None     if len(r_v[1].strip()) == 0 else   int(r_v[1])
                    istep = None   if len(r_v[2].strip()) == 0 else   int(r_v[2])
                    rst=rst+shps[ifrom:ito:istep]
                    for b in flags[ifrom:ito:istep]:
                        b = True
                else:
                    raise ValueError('index range cannot be parsed:'+r)
            if obj.Invert :
                rst = []
                for i in xrange(0,len(shps)):
                    if not flags[i]:
                        rst.append(shps[i])
        elif obj.FilterType == 'collision-pass':
            stencil = obj.Stencil.Shape
            for s in shps:
                d = s.distToShape(stencil)
                if bool(d[0] < DistConfusion) ^ bool(obj.Invert):
                    rst.append(s)
        elif obj.FilterType == 'window-volume' or obj.FilterType == 'window-area' or obj.FilterType == 'window-length' or obj.FilterType == 'window-distance':
            vals = [0.0] * len(shps)
            for i in xrange(0,len(shps)):
                if obj.FilterType == 'window-volume':
                    vals[i] = shps[i].Volume
                elif obj.FilterType == 'window-area':
                    vals[i] = shps[i].Area
                elif obj.FilterType == 'window-length':
                    vals[i] = shps[i].Length
                elif obj.FilterType == 'window-distance':
                    vals[i] = shps[i].distToShape(obj.Stencil.Shape)[0]
            
            maxval = max(vals)
            if obj.Stencil:
                if obj.FilterType == 'window-volume':
                    maxval = obj.Stencil.Shape.Volume
                elif obj.FilterType == 'window-area':
                    maxval = obj.Stencil.Shape.Area
                elif obj.FilterType == 'window-length':
                    maxval = obj.Stencil.Shape.Length
            if obj.OverrideMaxVal:
                maxval = obj.OverrideMaxVal
            
            valFrom = obj.WindowFrom / 100.0 * maxval
            valTo = obj.WindowTo / 100.0 * maxval
            
            for i in xrange(0,len(shps)):
                if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert:
                    rst.append(shps[i])
        else:
            raise ValueError('Filter mode not implemented:'+obj.FilterType)
        
        if len(rst) == 0:
            scale = 1.0
            if not obj.Base.Shape.isNull():
                scale = obj.Base.Shape.BoundBox.DiagonalLength/math.sqrt(3)/math.sqrt(len(shps))
            if scale < DistConfusion * 100:
                scale = 1.0
            print scale
            obj.Shape = markers.getNullShapeShape(scale)
            raise ValueError('Nothing passes through the filter') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
        
        if len(rst) > 1:
            obj.Shape = Part.makeCompound(rst)
        else: # don't make compound of one shape, output it directly
            sh = rst[0]
            sh = ShapeCopy.transformCopy(sh)
            sh.Placement = obj.Placement
            obj.Shape = sh
            
        return