Example #1
0
def CreateLatticePopulateChildren(name, label, shapeObj, latticeObjFrom, latticeObjTo, refmode):
    '''utility function; sharing common code for all populate-Children commands'''
    FreeCADGui.addModule("lattice2PopulateChildren")
    FreeCADGui.addModule("lattice2Executer")
    
    #fill in properties
    FreeCADGui.doCommand("f = lattice2PopulateChildren.makeLatticePopulateChildren(name='"+name+"')")
    FreeCADGui.doCommand("f.Object = App.ActiveDocument."+shapeObj.Name)
    FreeCADGui.doCommand("f.PlacementsTo = App.ActiveDocument."+latticeObjTo.Name)
    if latticeObjFrom is not None:
        FreeCADGui.doCommand("f.PlacementsFrom = App.ActiveDocument."+latticeObjFrom.Name)        
    FreeCADGui.doCommand("f.Referencing = "+repr(refmode))
    FreeCADGui.doCommand("f.Label = " + repr(label))                         
    
    #execute
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    
    #hide something
    if (refmode != "Origin" and refmode != "Use PlacementsFrom") or lattice2BaseFeature.isObjectLattice(shapeObj):
        FreeCADGui.doCommand("f.Object.ViewObject.hide()")
    if lattice2BaseFeature.isObjectLattice(shapeObj):
        FreeCADGui.doCommand("f.PlacementsTo.ViewObject.hide()")
        if latticeObjFrom is not None:
            FreeCADGui.doCommand("f.PlacementsFrom.ViewObject.hide()")
        
    #finalize
    FreeCADGui.doCommand("Gui.Selection.addSelection(f)")
    FreeCADGui.doCommand("f = None")
def CreateLatticePopulateCopies(name, label, shapeObj, latticeObjFrom, latticeObjTo, refmode):
    '''utility function; sharing common code for all populate-copies commands'''
    FreeCADGui.addModule("lattice2PopulateCopies")
    FreeCADGui.addModule("lattice2Executer")
    
    #fill in properties
    FreeCADGui.doCommand("f = lattice2PopulateCopies.makeLatticePopulateCopies(name='"+name+"')")
    FreeCADGui.doCommand("f.Object = App.ActiveDocument."+shapeObj.Name)
    FreeCADGui.doCommand("f.PlacementsTo = App.ActiveDocument."+latticeObjTo.Name)
    if latticeObjFrom is not None:
        FreeCADGui.doCommand("f.PlacementsFrom = App.ActiveDocument."+latticeObjFrom.Name)        
    FreeCADGui.doCommand("f.Referencing = "+repr(refmode))
    FreeCADGui.doCommand("f.Label = " + repr(label))                         
    
    #execute
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    
    #hide something
    if (refmode != "Origin" and refmode != "Use PlacementsFrom") or lattice2BaseFeature.isObjectLattice(shapeObj):
        FreeCADGui.doCommand("f.Object.ViewObject.hide()")
    if lattice2BaseFeature.isObjectLattice(shapeObj):
        FreeCADGui.doCommand("f.PlacementsTo.ViewObject.hide()")
        if latticeObjFrom is not None:
            FreeCADGui.doCommand("f.PlacementsFrom.ViewObject.hide()")
        
    #finalize
    FreeCADGui.doCommand("Gui.Selection.addSelection(f)")
    FreeCADGui.doCommand("f = None")
Example #3
0
 def getIcon(self):
     obj = self.Object
     base_is_lattice = LBF.isObjectLattice(obj.Object)
     pivot_is_lattice = LBF.isObjectLattice(obj.Pivot[0]) if obj.Pivot else True
     whole = obj.ObjectTraversal == 'Use whole'
     key = 'Plm' if base_is_lattice else 'Sh'
     key += 's' if not whole and pivot_is_lattice else ''
     key += 'Plms' if pivot_is_lattice else 'Sh'
     return getIconPath("Lattice2_Mirror_{key}.svg".format(key= key))
Example #4
0
    def execute(self, obj):

        if self.clone(obj):
            return
        if not obj.LatticePlacement:
            return

        if lattice2BF.isObjectLattice(obj.LatticePlacement) is True:
            pls = lattice2BF.getPlacementsList(obj.LatticePlacement)
            obj.RebarPlacements = pls
            self.build_shape(obj)
            obj.Amount = len(obj.RebarPlacements)
            obj.TotalLength = obj.Amount * obj.BaseRebar.Length

            # set Visibility of BaseRebar
            # this should be done in the Gui Command,
            # but this dos not yet exist TODO
            # set view of base rebar to off
            # if reinforcement shape is not a null shape
            # TODO may be use another color for base rebar
            if FreeCAD.GuiUp:
                if obj.Shape.isNull() is not True:
                    obj.BaseRebar.ViewObject.Visibility = False
        else:
            FreeCAD.Console.PrintError(
                "The object provided: {} is not a Lattice2 object\n".format(
                    obj.Name))
Example #5
0
    def derivedExecute(self,obj):
        self.assureGenerator(obj)
        self.updateReadonlyness(obj)
        
        # Apply links
        if obj.AxisLink:
            if lattice2BaseFeature.isObjectLattice(obj.AxisLink):
                lattice2Executer.warning(obj,"For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape.")
                
            #resolve the link        
            if len(obj.AxisLinkSubelement) > 0:
                linkedShape = obj.AxisLink.Shape.getElement(obj.AxisLinkSubelement)
            else:
                linkedShape = obj.AxisLink.Shape

            #Type check
            if linkedShape.ShapeType != 'Edge':
                raise ValueError('Axis link must be an edge; it is '+linkedShape.ShapeType+' instead.')
            
            #prepare
            dir = App.Vector()
            point = App.Vector()
            if isinstance(linkedShape.Curve, Part.Line):
                dir = linkedShape.Curve.EndPoint - linkedShape.Curve.StartPoint
                point = linkedShape.Curve.StartPoint
            elif isinstance(linkedShape.Curve, Part.Circle):
                dir = linkedShape.Curve.Axis
                point = linkedShape.Curve.Center
            else:
                raise ValueError("Edge " + repr(linkedShape) + " can't be used to derive an axis. It must be either a line or a circle/arc.")
            
            #apply
            if obj.AxisDirIsDriven:
                obj.AxisDir = dir
            if obj.AxisPointIsDriven:
                obj.AxisPoint = point
        
        self.generator.execute()
        
        # cache properties into variables
        radius = float(obj.Radius)
        values = [float(strv) for strv in obj.Values]
        
        # compute initial vector. It is to be perpendicular to Axis
        rot_ini = lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= obj.AxisDir)
        overallPlacement = App.Placement(obj.AxisPoint, rot_ini)
        
        # Make the array
        output = [] # list of placements
        for ang in values:
            p = Part.Vertex()
            localrot = App.Rotation(App.Vector(0,0,1), ang)
            localtransl = localrot.multVec(App.Vector(radius,0,0))
            localplm = App.Placement(localtransl, localrot)
            resultplm = overallPlacement.multiply(localplm)
            if obj.OrientMode == 'None':
                resultplm.Rotation = App.Rotation()
            output.append(resultplm)

        return output
Example #6
0
def CreateLatticeArrayFilter(name, mode):
    sel = FreeCADGui.Selection.getSelectionEx()

    # selection order independence logic (lattice object and generic shape stencil can be told apart)
    iLtc = 0  #index of lattice object in selection
    iStc = 1  #index of stencil object in selection
    for i in range(0, len(sel)):
        if lattice2BaseFeature.isObjectLattice(sel[i]):
            iLtc = i
            iStc = i - 1  #this may give negative index, but python accepts negative indexes
            break
    FreeCAD.ActiveDocument.openTransaction("Create ArrayFilter")
    FreeCADGui.addModule("lattice2ArrayFilter")
    FreeCADGui.addModule("lattice2Executer")
    FreeCADGui.doCommand("sel = Gui.Selection.getSelectionEx()")
    FreeCADGui.doCommand("f = lattice2ArrayFilter.makeArrayFilter(name = '" +
                         name + "')")
    FreeCADGui.doCommand("f.Base = App.ActiveDocument." + sel[iLtc].ObjectName)
    FreeCADGui.doCommand("f.FilterType = '" + mode + "'")
    if mode == 'specific items':
        FreeCADGui.doCommand(
            "f.items = lattice2ArrayFilter.makeItemListFromSelection(sel[" +
            str(iLtc) + "])")
        if len(sel[0].SubElementNames) == 1:
            FreeCADGui.doCommand("f.ExposePlacement = True")
    else:
        FreeCADGui.doCommand("f.Stencil = App.ActiveDocument." +
                             sel[iStc].ObjectName)
    FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n" +
                         "    child.ViewObject.hide()")
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    FreeCADGui.doCommand("f = None")
    FreeCAD.ActiveDocument.commitTransaction()
Example #7
0
    def Activated(self):
        try:
            if len(FreeCADGui.Selection.getSelection()) == 0:
                infoMessage(
                    "Make compound",
                    "Make compound command. Combines several shapes into one. The shapes are kept as-is. They are not fused together, and can be extracted unchanged.\n\n"
                    +
                    "Compounds can contain combination of shapes of any topology: one can compound some edges with some solids. Compound is effectively another kind of group. But unlike normal FreeCAD group, compound only accepts OCC geometry. Compound cannot include meshes, dimensions, labels, or other objects that provide no Shape property.\n\n"
                    +
                    "Note that compounds that have objects that touch or intersect are considered invalid by Part CheckGeometry. Such invalid compounds cannot be used for Part Cut/Common/Fuse."
                )
                return

            oldVal = lattice2Executer.globalIsCreatingLatticeFeature
            lattice2Executer.globalIsCreatingLatticeFeature = True

            sel = FreeCADGui.Selection.getSelectionEx()
            for s in sel:
                if isObjectLattice(s.Object):
                    lattice2Executer.warning(
                        None,
                        "For making a compound, generic shapes are expected, but some of the selected objects are placements/arrays of placements. These will be treated as generic shapes; results may be unexpected."
                    )
                    break
            FreeCADGui.runCommand("Part_Compound")
        except Exception as err:
            msgError(err)
        finally:
            lattice2Executer.globalIsCreatingLatticeFeature = oldVal
Example #8
0
def CreateLatticeProjectArray(name):
    sel = FreeCADGui.Selection.getSelectionEx()

    # selection order independence logic (lattice object and generic shape stencil can be told apart)
    iLtc = 0  #index of lattice object in selection
    iStc = 1  #index of stencil object in selection
    for i in range(0, len(sel)):
        if lattice2BaseFeature.isObjectLattice(sel[i]):
            iLtc = i
            iStc = i - 1  #this may give negative index, but python accepts negative indexes
            break
    FreeCAD.ActiveDocument.openTransaction("Create ProjectArray")
    FreeCADGui.addModule("lattice2ProjectArray")
    FreeCADGui.addModule("lattice2Executer")
    FreeCADGui.doCommand("sel = Gui.Selection.getSelectionEx()")
    FreeCADGui.doCommand("f = lattice2ProjectArray.makeProjectArray(name = '" +
                         name + "')")
    FreeCADGui.doCommand("f.Base = App.ActiveDocument." + sel[iLtc].ObjectName)
    FreeCADGui.doCommand("f.Tool = App.ActiveDocument." + sel[iStc].ObjectName)

    FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n" +
                         "    child.ViewObject.hide()")
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    FreeCADGui.doCommand("f = None")
    FreeCAD.ActiveDocument.commitTransaction()
Example #9
0
def CreateLatticeArrayFilter(name,mode):
    sel = FreeCADGui.Selection.getSelectionEx()
    
    # selection order independece logic (lattice object and generic shape stencil can be told apart)
    iLtc = 0 #index of lattice object in selection
    iStc = 1 #index of stencil object in selection
    for i in range(0,len(sel)):
        if lattice2BaseFeature.isObjectLattice(sel[i]):
            iLtc = i
            iStc = i-1 #this may give negative index, but python accepts negative indexes
            break
    FreeCAD.ActiveDocument.openTransaction("Create ArrayFilter")
    FreeCADGui.addModule("lattice2ArrayFilter")
    FreeCADGui.addModule("lattice2Executer")
    FreeCADGui.doCommand("sel = Gui.Selection.getSelectionEx()")    
    FreeCADGui.doCommand("f = lattice2ArrayFilter.makeArrayFilter(name = '"+name+"')")
    FreeCADGui.doCommand("f.Base = App.ActiveDocument."+sel[iLtc].ObjectName)
    FreeCADGui.doCommand("f.FilterType = '"+mode+"'")
    if mode == 'specific items':
        FreeCADGui.doCommand("f.items = lattice2ArrayFilter.makeItemListFromSelection(sel["+str(iLtc)+"])")
        if len(sel[0].SubElementNames) == 1:
            FreeCADGui.doCommand("f.ExposePlacement = True")
    else:
        FreeCADGui.doCommand("f.Stencil = App.ActiveDocument."+sel[iStc].ObjectName)
    FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n"+
                         "    child.ViewObject.hide()")
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    FreeCADGui.doCommand("f = None")
    FreeCAD.ActiveDocument.commitTransaction()
Example #10
0
    def derivedExecute(self,obj):
        #validity check
        if not lattice2BaseFeature.isObjectLattice(obj.Base):
            lattice2Executer.warning(obj,"A lattice object is expected as Base, but a generic shape was provided. It will be treated as a lattice object; results may be unexpected.")

        output = [] #variable to receive the final list of placements
        leaves = LCE.AllLeaves(obj.Base.Shape)
        input = [leaf.Placement for leaf in leaves]
        if obj.FilterType == 'bypass':
            output = input
        elif obj.FilterType == 'specific items':
            flags = [False] * len(input)
            ranges = obj.items.split(';')
            for r in ranges:
                r_v = r.split(':')
                if len(r_v) == 1:
                    i = int(r_v[0])
                    output.append(input[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])
                    output=output+input[ifrom:ito:istep]
                    for b in flags[ifrom:ito:istep]:
                        b = True
                else:
                    raise ValueError('index range cannot be parsed:'+r)
            if obj.Invert :
                output = []
                for i in xrange(0,len(input)):
                    if not flags[i]:
                        output.append(input[i])
        elif obj.FilterType == 'collision-pass':
            stencil = obj.Stencil.Shape
            for plm in input:
                pnt = Part.Vertex(plm.Base)
                d = pnt.distToShape(stencil)
                if bool(d[0] < DistConfusion) ^ bool(obj.Invert):
                    output.append(plm)
        elif obj.FilterType == 'window-distance':
            vals = [0.0] * len(input)
            for i in xrange(0,len(input)):
                if obj.FilterType == 'window-distance':
                    pnt = Part.Vertex(input[i].Base)
                    vals[i] = pnt.distToShape(obj.Stencil.Shape)[0]
            
            valFrom = obj.WindowFrom
            valTo = obj.WindowTo
            
            for i in xrange(0,len(input)):
                if bool(vals[i] >= valFrom and vals[i] <= valTo) ^ obj.Invert:
                    output.append(input[i])
        else:
            raise ValueError('Filter mode not implemented:'+obj.FilterType)
                            
        return output
    def derivedExecute(self,obj):
        self.assureProperties(obj)
        
        # cache stuff
        objectShape = obj.Object.Shape
        placements = lattice2BaseFeature.getPlacementsList(obj.PlacementsTo, obj)

        outputIsLattice = lattice2BaseFeature.isObjectLattice(obj.Object)

        # Pre-collect base placement list, if base is a lattice. For speed.
        if outputIsLattice:
            objectPlms = lattice2BaseFeature.getPlacementsList(obj.Object,obj)
        
        placements = DereferenceArray(obj, placements, obj.PlacementsFrom, obj.Referencing)
        
        # initialize output containers and loop variables
        outputShapes = [] #output list of shapes
        outputPlms = [] #list of placements
        copy_method_index = ShapeCopy.getCopyTypeIndex(obj.Copying)

        
        # the essence
        for plm in placements:

            if outputIsLattice:
                for objectPlm in objectPlms:
                    outputPlms.append(plm.multiply(objectPlm))
            else:
                outputShape = ShapeCopy.copyShape(objectShape, copy_method_index, plm)
                #outputShape.Placement = plm.multiply(outputShape.Placement) # now handled by copyShape
                outputShapes.append(outputShape)
            
        if outputIsLattice:
            return outputPlms
        else:
            # Output shape or compound (complex logic involving OutputCompounding property)
            #first, autosettle the OutputCompounding.
            if obj.OutputCompounding == "(autosettle)":
                if hasattr(obj.PlacementsTo,"ExposePlacement") and obj.PlacementsTo.ExposePlacement == False:
                    obj.OutputCompounding = "always"
                else:
                    obj.OutputCompounding = "only if many"
            #now, set the result shape
            if len(outputShapes) == 1 and obj.OutputCompounding == "only if many":
                sh = outputShapes[0]
                sh = ShapeCopy.transformCopy(sh)
                obj.Shape = sh
            else:
                obj.Shape = Part.makeCompound(outputShapes)
            return None
Example #12
0
    def derivedExecute(self,obj):
        self.assureProperties(obj)
        
        # cache stuff
        objectShape = screen(obj.Object).Shape
        placements = lattice2BaseFeature.getPlacementsList(screen(obj.PlacementsTo), obj)

        outputIsLattice = lattice2BaseFeature.isObjectLattice(screen(obj.Object))

        # Pre-collect base placement list, if base is a lattice. For speed.
        if outputIsLattice:
            objectPlms = lattice2BaseFeature.getPlacementsList(screen(obj.Object),obj)
        
        placements = DereferenceArray(obj, placements, screen(obj.PlacementsFrom), obj.Referencing)
        
        # initialize output containers and loop variables
        outputShapes = [] #output list of shapes
        outputPlms = [] #list of placements
        copy_method_index = ShapeCopy.getCopyTypeIndex(obj.Copying)

        
        # the essence
        for plm in placements:

            if outputIsLattice:
                for objectPlm in objectPlms:
                    outputPlms.append(plm.multiply(objectPlm))
            else:
                outputShape = ShapeCopy.copyShape(objectShape, copy_method_index, plm)
                #outputShape.Placement = plm.multiply(outputShape.Placement) # now handled by copyShape
                outputShapes.append(outputShape)
            
        if outputIsLattice:
            return outputPlms
        else:
            # Output shape or compound (complex logic involving OutputCompounding property)
            #first, autosettle the OutputCompounding.
            if obj.OutputCompounding == "(autosettle)":
                if hasattr(screen(obj.PlacementsTo),"ExposePlacement") and screen(obj.PlacementsTo).ExposePlacement == False:
                    obj.OutputCompounding = "always"
                else:
                    obj.OutputCompounding = "only if many"
            #now, set the result shape
            if len(outputShapes) == 1 and obj.OutputCompounding == "only if many":
                sh = outputShapes[0]
                sh = ShapeCopy.transformCopy(sh)
                obj.Shape = sh
            else:
                obj.Shape = Part.makeCompound(outputShapes)
            return None
 def getIcon(self):
     if lattice2BaseFeature.isObjectLattice(self.Object):
         return getIconPath(
             {"Origin":"Lattice2_PopulateCopies_Plms_Normal.svg",
              "First item":"Lattice2_PopulateCopies_Plms_Array.svg",
              "Last item":"Lattice2_PopulateCopies_Plms_Array.svg",
              "Use PlacementsFrom":"Lattice2_PopulateCopies_Plms_Move.svg",
             }[self.Object.Referencing]
             )  
     else:
         return getIconPath(
             {"Origin":"Lattice2_PopulateCopies_Normal.svg",
              "First item":"Lattice2_PopulateCopies_Array.svg",
              "Last item":"Lattice2_PopulateCopies_Array.svg",
              "Use PlacementsFrom":"Lattice2_PopulateCopies_Move.svg",
             }[self.Object.Referencing]
             )  
Example #14
0
 def getIcon(self):
     if lattice2BaseFeature.isObjectLattice(screen(self.Object)):
         return getIconPath(
             {"Origin":"Lattice2_PopulateChildren_Plms_Normal.svg",
              "First item":"Lattice2_PopulateChildren_Plms_Array.svg",
              "Last item":"Lattice2_PopulateChildren_Plms_Array.svg",
              "Use PlacementsFrom":"Lattice2_PopulateChildren_Plms_Move.svg",
             }[self.Object.Referencing]
             )  
     else:
         return getIconPath(
             {"Origin":"Lattice2_PopulateChildren_Normal.svg",
              "First item":"Lattice2_PopulateChildren_Array.svg",
              "Last item":"Lattice2_PopulateChildren_Array.svg",
              "Use PlacementsFrom":"Lattice2_PopulateChildren_Move.svg",
             }[self.Object.Referencing]
             )  
Example #15
0
 def Activated(self):
     try:
         sel = getSelectionAsListOfLinkSub()
         if len(sel) == 1 :
             #TODO: pop-up with options
             CreateLatticeMirror(name= "Mirror", extra_code=
                 "f.FlipX = True"
             )
         elif len(sel) == 2 :
             #TODO: pop-up with options instead of guessing
             lnk = sel[1]
             if LBF.isObjectLattice(lnk[0]):
                 extra_code = (
                     "f.FlipY = True"
                 )                    
             else:
                 sh = resolveSingleSublink(lnk)
                 if sh.ShapeType == 'Face':
                     extra_code = (
                         "f.FlipZ = True"
                     )
                 elif sh.ShapeType == 'Edge':
                     extra_code = (
                         "f.FlipX = True\n"
                         "f.FlipY = True"
                     )
                 elif sh.ShapeType == 'Vertex':
                     extra_code = (
                         "f.FlipX = True\n"
                         "f.FlipY = True\n"
                         "f.FlipZ = True"
                     )
             CreateLatticeMirror(name = "Mirror", extra_code= extra_code)
         else:
             infoMessage("Lattice Mirror","Lattice Mirror feature. Mirrors shapes and placements. Please select object to be mirrored, first,"
                                          " and then the mirror object (optional). Then invoke this tool.\n\n"
                                          "Object to be mirrored: any shape, or compound of shapes, or a placement, or an array of placements."
                                          " Note that when a placement is mirrored, its Y axis is switched, for the coordinate system to remain right-handed.\n\n"
                                          "Mirror object: either a placement, an array of placements, a vertex, a line, or a plane face. If an array of"
                                          " placements is used, the object is reflected using each placement as mirror, and the result is packed into a compound.\n\n"
                                          "You can adjust the mirroring direction in property editor by editing FlipX, FlipY, FlipZ properties."
                                          " The mirror object is used to establish the coordinate system to work in. If the mirror object is not"
                                          " specified, global coordinate system is used (and a custom one can be set up by editing PivotPlacement).")
     except Exception as err:
         msgError(err)
Example #16
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 #17
0
def CreateLatticeMirror(name, extra_code = ''):
    sel = FreeCADGui.Selection.getSelectionEx()
    if not LBF.isObjectLattice(sel[0].Object) and activeBody():
        raise SelectionError("PartDesign Mode", "You can only mirror placements while in body. Please deactivate the body to mirror shapes. PartDesign Feature mirroring is not supported yet.")
    FreeCAD.ActiveDocument.openTransaction("Create LatticeMirror")
    FreeCADGui.addModule("lattice2Mirror")
    FreeCADGui.addModule("lattice2Executer")
    FreeCADGui.addModule("lattice2Utils")
    FreeCADGui.doCommand("sel = lattice2Utils.getSelectionAsListOfLinkSub()")
    FreeCADGui.doCommand("f = lattice2Mirror.makeLatticeMirror(name = '"+name+"')")
    FreeCADGui.doCommand("f.Object = sel[0][0]")
    FreeCADGui.doCommand("if len(sel) == 2:\n"
                         "    f.Pivot = sel[1]")
    FreeCADGui.doCommand("f.Label = '{name} of {olabel}'.format(name= f.Name, olabel= f.Object.Label)")
    if extra_code:
        FreeCADGui.doCommand(extra_code)
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    FreeCAD.ActiveDocument.commitTransaction()
Example #18
0
    def derivedExecute(self, obj):
        # cache stuff
        base = screen(obj.Base).Shape
        if not lattice2BaseFeature.isObjectLattice(screen(obj.Base)):
            lattice2Executer.warning(
                obj,
                "Base is not a lattice, but lattice is expected. Results may be unexpected.\n"
            )
        baseChildren = LCE.AllLeaves(base)

        #cache mode comparisons, for speed
        posIsInvert = obj.TranslateMode == 'invert'
        posIsKeep = obj.TranslateMode == 'keep'
        posIsReset = obj.TranslateMode == 'reset'

        oriIsInvert = obj.OrientMode == 'invert'
        oriIsKeep = obj.OrientMode == 'keep'
        oriIsReset = obj.OrientMode == 'reset'

        # initialize output containers and loop variables
        outputPlms = []  #list of placements

        # the essence
        for child in baseChildren:
            pos = App.Vector()
            ori = App.Rotation()
            inverted = child.Placement.inverse()
            if posIsInvert:
                pos = inverted.Base
            elif posIsKeep:
                pos = child.Placement.Base
            elif posIsReset:
                pass

            if oriIsInvert:
                ori = inverted.Rotation
            elif oriIsKeep:
                ori = child.Placement.Rotation
            elif oriIsReset:
                pass

            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms
Example #19
0
    def derivedExecute(self, obj):
        # cache stuff
        base = obj.Base.Shape
        if not lattice2BaseFeature.isObjectLattice(obj.Base):
            lattice2Executer.warning(
                obj, "Base is not a lattice, but lattice is expected. Results may be unexpected.\n"
            )
        baseChildren = LCE.AllLeaves(base)

        # cache mode comparisons, for speed
        posIsInvert = obj.TranslateMode == "invert"
        posIsKeep = obj.TranslateMode == "keep"
        posIsReset = obj.TranslateMode == "reset"

        oriIsInvert = obj.OrientMode == "invert"
        oriIsKeep = obj.OrientMode == "keep"
        oriIsReset = obj.OrientMode == "reset"

        # initialize output containers and loop variables
        outputPlms = []  # list of placements

        # the essence
        for child in baseChildren:
            pos = App.Vector()
            ori = App.Rotation()
            inverted = child.Placement.inverse()
            if posIsInvert:
                pos = inverted.Base
            elif posIsKeep:
                pos = child.Placement.Base
            elif posIsReset:
                pass

            if oriIsInvert:
                ori = inverted.Rotation
            elif oriIsKeep:
                ori = child.Placement.Rotation
            elif oriIsReset:
                pass

            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms
Example #20
0
    def derivedExecute(self, obj):
        #validity check
        nonLattices = []
        for iArr in range(0, len(obj.Links)):
            link = obj.Links[iArr]
            if not lattice2BaseFeature.isObjectLattice(link):
                nonLattices.append(link.Label)
        if len(nonLattices) > 0:
            lattice2Executer.warning(
                obj,
                "Only lattice objects are expected to be linked as arrays in JoinArrays. There are "
                + len(nonLattices) +
                " objects which are not lattice objects. Results may me unexpected."
            )

        #extract placements
        listlistPlms = []
        lengths = []
        for link in obj.Links:
            leaves = LCE.AllLeaves(link.Shape)
            listlistPlms.append([child.Placement for child in leaves])
            lengths.append(len(leaves))

        #processing
        output = []  #list of placements
        if obj.Interleave:
            for l in lengths[1:]:
                if l != lengths[0]:
                    lattice2Executer.warning(
                        obj, "Array lengths are unequal: " + repr(lengths) +
                        ". Interleaving will be inconsistent.")
                    break

            for iItem in range(0, max(lengths)):
                for list in listlistPlms:
                    if iItem < len(list):
                        output.append(list[iItem])
        else:
            for list in listlistPlms:
                output.extend(list)
        return output
Example #21
0
    def derivedExecute(self, obj):
        # validity check
        nonLattices = []
        for iArr in range(0, len(obj.Links)):
            link = obj.Links[iArr]
            if not lattice2BaseFeature.isObjectLattice(link):
                nonLattices.append(link.Label)
        if len(nonLattices) > 0:
            lattice2Executer.warning(
                obj,
                "Only lattice objects are expected to be linked as arrays in JoinArrays. There are "
                + len(nonLattices)
                + " objects which are not lattice objects. Results may me unexpected.",
            )

        # extract placements
        listlistPlms = []
        lengths = []
        for link in obj.Links:
            leaves = LCE.AllLeaves(link.Shape)
            listlistPlms.append([child.Placement for child in leaves])
            lengths.append(len(leaves))

        # processing
        output = []  # list of placements
        if obj.Interleave:
            for l in lengths[1:]:
                if l != lengths[0]:
                    lattice2Executer.warning(
                        obj, "Array lengths are unequal: " + repr(lengths) + ". Interleaving will be inconsistent."
                    )
                    break

            for iItem in range(0, max(lengths)):
                for list in listlistPlms:
                    if iItem < len(list):
                        output.append(list[iItem])
        else:
            for list in listlistPlms:
                output.extend(list)
        return output
Example #22
0
 def Activated(self):
     try:
         if len(FreeCADGui.Selection.getSelection())==0:
             infoMessage("Make compound",
                 "Make compound command. Combines several shapes into one. The shapes are kept as-is. They are not fused together, and can be extracted unchanged.\n\n"+
                 "Compounds can contain combination of shapes of any topology: one can compound some edges with some solids. Compound is effectively another kind of group. But unlike normal FreeCAD group, compound only accepts OCC geometry. Compound cannot include meshes, dimensions, labels, or other objects that provide no Shape property.\n\n"+
                 "Note that compounds that have objects that touch or intersect are considered invalid by Part CheckGeometry. Such invalid compounds cannot be used for Part Cut/Common/Fuse.")
             return
         
         oldVal = lattice2Executer.globalIsCreatingLatticeFeature
         lattice2Executer.globalIsCreatingLatticeFeature = True
         
         sel = FreeCADGui.Selection.getSelectionEx()
         for s in sel:
             if isObjectLattice(s.Object):
                 lattice2Executer.warning(None,"For making a compound, generic shapes are expected, but some of the selected objects are placements/arrays of placements. These will be treated as generic shapes; results may be unexpected.")
                 break
         FreeCADGui.runCommand("Part_Compound")
     except Exception as err:
         msgError(err)
     finally:
         lattice2Executer.globalIsCreatingLatticeFeature = oldVal
def make_reinforcement_lattice(base_rebar,
                               latice_obj,
                               base_placement=FreeCAD.Placement(),
                               name="ReinforcementLattice"):
    """
    make_reinforcement_lattice(
        base_rebar,
        placements,
        [base_placement],
        [name]
    )
    Adds a lattice reinforcement object.
    """
    if lattice2BF.isObjectLattice(latice_obj) is not True:
        FreeCAD.Console.PrintError(
            "The object provided: {} is not a Lattice2 object\n".format(
                latice_obj.Name))
        return None

    if not FreeCAD.ActiveDocument:
        FreeCAD.Console.PrintError("No active document. Aborting\n")
        return
    obj = FreeCAD.ActiveDocument.addObject("Part::FeaturePython",
                                           "ReinforcementLattice")
    obj.Label = translate("Arch", name)

    ReinforcementLattice(obj)
    if FreeCAD.GuiUp:
        view_lattice.ViewProviderReinforcementLattice(obj.ViewObject)

    obj.BaseRebar = base_rebar
    obj.LatticePlacement = latice_obj
    obj.BasePlacement = base_placement

    # mark base_rebar obj to make it collect its new child
    base_rebar.touch()
    return obj
Example #24
0
def CreateLatticeProjectArray(name):
    sel = FreeCADGui.Selection.getSelectionEx()
    
    # selection order independece logic (lattice object and generic shape stencil can be told apart)
    iLtc = 0 #index of lattice object in selection
    iStc = 1 #index of stencil object in selection
    for i in range(0,len(sel)):
        if lattice2BaseFeature.isObjectLattice(sel[i]):
            iLtc = i
            iStc = i-1 #this may give negative index, but python accepts negative indexes
            break
    FreeCAD.ActiveDocument.openTransaction("Create ProjectArray")
    FreeCADGui.addModule("lattice2ProjectArray")
    FreeCADGui.addModule("lattice2Executer")
    FreeCADGui.doCommand("sel = Gui.Selection.getSelectionEx()")    
    FreeCADGui.doCommand("f = lattice2ProjectArray.makeProjectArray(name = '"+name+"')")
    FreeCADGui.doCommand("f.Base = App.ActiveDocument."+sel[iLtc].ObjectName)
    FreeCADGui.doCommand("f.Tool = App.ActiveDocument."+sel[iStc].ObjectName)

    FreeCADGui.doCommand("for child in f.ViewObject.Proxy.claimChildren():\n"+
                         "    child.ViewObject.hide()")
    FreeCADGui.doCommand("lattice2Executer.executeFeature(f)")
    FreeCADGui.doCommand("f = None")
    FreeCAD.ActiveDocument.commitTransaction()
Example #25
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
Example #26
0
    def derivedExecute(self, obj):
        base_is_lattice = LBF.isObjectLattice(obj.Object)
        pivot_is_lattice = LBF.isObjectLattice(
            obj.Pivot[0]) if obj.Pivot else True
        flipX = obj.FlipX
        flipY = obj.FlipY
        flipZ = obj.FlipZ

        # collect mirror pivot placements
        pivots = None
        em = 0  #editormode of PivotPlacement property. 0 = editable, 1 = read-only, 2 = hidden
        if obj.Pivot:
            em = 1  #read-only
            if pivot_is_lattice:
                pivots = LBF.getPlacementsList(obj.Pivot[0])
            else:
                pivot_shape = resolveSingleSublink(obj.Pivot)
                if pivot_shape.ShapeType == 'Edge' and type(
                        pivot_shape.Curve) is Part.Line:
                    dir = pivot_shape.Curve.Direction
                    base = pivot_shape.CenterOfMass
                    if flipX != flipY:
                        raise ValueError(
                            "Unsupported combination of flips for mirroring against line. FlipX and FlipY must either be both on or both off."
                        )
                    rot = makeOrientationFromLocalAxes(dir)
                    pivots = [App.Placement(base, rot)]
                elif pivot_shape.ShapeType == 'Face' and type(
                        pivot_shape.Surface) is Part.Plane:
                    dir = pivot_shape.Surface.Axis
                    base = pivot_shape.CenterOfMass
                    if flipX != flipY:
                        raise ValueError(
                            "Unsupported combination of flips for mirroring against line. FlipX and FlipY must either be both on or both off."
                        )
                    rot = makeOrientationFromLocalAxes(dir)
                    pivots = [App.Placement(base, rot)]
                elif pivot_shape.ShapeType == 'Vertex':
                    base = pivot_shape.Point
                    pivots = [App.Placement(base, obj.PivotPlacement.Rotation)]
                    em = 0  #editable
                else:
                    raise TypeError("Unsupported geometry for use as mirror")
            if len(pivots) == 1:
                obj.PivotPlacement = pivots[0]
            else:
                em = 2  #hidden
        else:
            pivots = [obj.PivotPlacement]
            em = 0
        obj.setEditorMode('PivotPlacement', em)

        # collect objects to be mirrored
        loop = False
        whole = obj.ObjectTraversal == 'Use whole'
        children = []
        if base_is_lattice:
            children = LBF.getPlacementsList(obj.Object)
        else:
            if obj.ObjectTraversal == 'Use whole':
                children = [obj.Object.Shape]
                loop = True
            elif obj.ObjectTraversal == 'Direct children only':
                children = obj.Object.Shape.childShapes()
            elif obj.ObjectTraversal == 'Use whole':
                children = LCE.AllLeaves(obj.Object.Shape)
            else:
                raise ValueError(
                    "Traversal mode not implemented: {mode}".format(
                        mode=obj.ObjectTraversal))

        if len(pivots) != len(children) and not loop and not whole:
            lattice2Executer.warning(
                obj,
                "{label}: Number of children ({nch}) doesn't match the number of pivot placements ({npiv})"
                .format(label=obj.Label, nch=len(children), npiv=len(pivots)))
            n = min(len(pivots), len(children))
        else:
            n = len(pivots)

        # actual mirroring!
        result = []
        for i in range(n):
            piv = pivots[i]
            ichild = i % len(children)
            if base_is_lattice:
                if whole:
                    for plm in children:
                        result.append(
                            mirrorPlacement(plm, piv, flipX, flipY, flipZ))
                else:
                    result.append(
                        mirrorPlacement(children[ichild], piv, flipX, flipY,
                                        flipZ))
            else:
                result.append(
                    mirrorShape(children[ichild], piv, flipX, flipY, flipZ))

        # write out the result
        if base_is_lattice:
            return result
        else:
            if n == 1:
                result = ShapeCopy.transformCopy(result[0])
            else:
                result = Part.Compound(result)
            obj.Shape = result
            return None
Example #27
0
    def execute(self,obj):
        nOfStrings = len(obj.Strings)
        lattice = screen(obj.ArrayLink)
        if lattice is None:
            plms = [App.Placement() for i in range(0,nOfStrings)]
        else:
            if not lattice2BaseFeature.isObjectLattice(lattice):
                lattice2Executer.warning(obj,"ShapeString's link to array must point to a lattice. It points to a generic shape. Results may be unexpected.")
            leaves = LCE.AllLeaves(lattice.Shape)
            plms = [leaf.Placement for leaf in leaves]
        
        #update foolObj's properties
        self.makeFoolObj(obj) #make sure we have one - fixes defunct Lattice ShapeString after save-load
        for (proptype, propname, group, hint) in self.foolObj.properties:
            if propname != "String": #ignore "String", that will be taken care of in the following loop
                setattr(self.foolObj, propname, getattr(obj, propname))
        self.foolObj.FontFile = findFont(obj.FontFile)
        obj.FullPathToFont = self.foolObj.FontFile
        
        shapes = []
        for i in range(  0 ,  min(len(plms),len(obj.Strings))  ):
            if len(obj.Strings[i]) > 0:
                #generate shapestring using Draft
                self.foolObj.String = obj.Strings[i]
                self.foolObj.Shape = None
                self.draft_shape_string.execute(self.foolObj)
                shape = self.foolObj.Shape
                
                #calculate alignment point
                if obj.XAlign == 'None' and obj.YAlign == 'None':
                    pass #need not calculate boundbox
                else:
                    if obj.AlignPrecisionBoundBox:
                        bb = getPrecisionBoundBox(shape)
                    else:
                        bb = shape.BoundBox

                alignPnt = App.Vector()
                
                if obj.XAlign == 'Left':
                    alignPnt.x = bb.XMin
                elif obj.XAlign == 'Right':
                    alignPnt.x = bb.XMax
                elif obj.XAlign == 'Middle':
                    alignPnt.x = bb.Center.x

                if obj.YAlign == 'Bottom':
                    alignPnt.y = bb.YMin
                elif obj.YAlign == 'Top':
                    alignPnt.y = bb.YMax
                elif obj.YAlign == 'Middle':
                    alignPnt.y = bb.Center.y
                
                #Apply alignment
                shape.Placement = App.Placement(alignPnt*(-1.0), App.Rotation()).multiply(shape.Placement)
                
                #Apply placement from array
                shape.Placement = plms[i].multiply(shape.Placement)
                
                shapes.append(shape.copy())
        
        if len(shapes) == 0:
            scale = 1.0
            if lattice is not None:
                scale = lattice.Shape.BoundBox.DiagonalLength/math.sqrt(3)/math.sqrt(len(shps))
            if scale < DistConfusion * 100:
                scale = 1.0
            obj.Shape = markers.getNullShapeShape(scale)
            raise ValueError('No strings were converted into shapes') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
        result = Part.makeCompound(shapes)
        result.Placement = obj.Placement
        obj.Shape = result
Example #28
0
    def derivedExecute(self, obj):
        #validity check
        if not lattice2BaseFeature.isObjectLattice(screen(obj.Base)):
            lattice2Executer.warning(
                obj,
                "A lattice object is expected as Base, but a generic shape was provided. It will be treated as a lattice object; results may be unexpected."
            )

        toolShape = screen(obj.Tool).Shape
        if lattice2BaseFeature.isObjectLattice(screen(obj.Tool)):
            lattice2Executer.warning(
                obj,
                "A lattice object was provided as Tool. It will be converted into points; orientations will be ignored."
            )
            leaves = LCE.AllLeaves(toolShape)
            points = [Part.Vertex(leaf.Placement.Base) for leaf in leaves]
            toolShape = Part.makeCompound(points)

        leaves = LCE.AllLeaves(screen(obj.Base).Shape)
        input = [leaf.Placement for leaf in leaves]

        output = []  #variable to receive the final list of placements

        #cache settings
        elev = float(obj.PosElevation)
        posIsKeep = obj.TranslateMode == 'keep'
        posIsProjected = obj.TranslateMode == 'projected'
        posIsMixed = obj.TranslateMode == 'mixed'
        mixF = float(obj.PosMixFraction)
        oriIsKeep = obj.OrientMode == 'keep'
        oriIsAlongGap = obj.OrientMode == 'along gap'
        oriIsTangentPlane = obj.OrientMode == 'tangent plane'
        oriIsAlongU = obj.OrientMode == 'along u'
        oriIsAlongV = obj.OrientMode == 'along v'

        isMultiSol = obj.Multisolution == 'use all'

        for plm in input:
            v = Part.Vertex(plm.Base)
            projection = v.distToShape(toolShape)
            (dist, gaps, infos) = projection
            for iSol in range(0, len(gaps)):
                (posKeep, posPrj) = gaps[iSol]
                (dummy, dummy, dummy, el_topo, el_index,
                 el_params) = infos[iSol]

                # Fetch all possible parameters (some may not be required, depending on modes)
                normal = posKeep - posPrj
                if normal.Length < DistConfusion:
                    normal = None

                tangU = None
                tangV = None
                if el_topo == 'Face':
                    face = toolShape.Faces[el_index]
                    if normal is None:
                        normal = face.normalAt(*el_params)
                    (tangU, tangV) = face.tangentAt(*el_params)
                elif el_topo == "Edge":
                    edge = toolShape.Edges[el_index]
                    tangU = edge.tangentAt(el_params)

                if normal is not None:
                    normal.normalize()

                #mode logic - compute new placement
                if posIsKeep:
                    pos = plm.Base
                elif posIsProjected:
                    pos = posPrj
                elif posIsMixed:
                    pos = posKeep * mixF + posPrj * (1 - mixF)
                else:
                    raise ValueError("Positioning mode not implemented: " +
                                     obj.TranslateMode)

                if abs(elev) > DistConfusion:
                    if normal is None:
                        raise ValueError(
                            "Normal vector not available for a placement resting on "
                            + el_topo +
                            ". Normal vector is required for nonzero position elevation."
                        )
                    pos += normal * elev

                if oriIsKeep:
                    ori = plm.Rotation
                elif oriIsAlongGap:
                    if normal is None:
                        raise ValueError(
                            "Normal vector not available for a placement resting on "
                            + el_topo +
                            ". Normal vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    ori = Utils.makeOrientationFromLocalAxesUni("X",
                                                                XAx=normal *
                                                                (-1.0))
                elif oriIsTangentPlane:
                    if normal is None:
                        raise ValueError(
                            "Normal vector not available for a placement resting on "
                            + el_topo +
                            ". Normal vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    ori = Utils.makeOrientationFromLocalAxesUni("Z",
                                                                ZAx=normal)
                elif oriIsAlongU:
                    if normal is None:
                        raise ValueError(
                            "Normal vector not available for a placement resting on "
                            + el_topo +
                            ". Normal vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    if tangU is None:
                        raise ValueError(
                            "TangentU vector not available for point on " +
                            el_topo +
                            ". TangentU vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    ori = Utils.makeOrientationFromLocalAxesUni("ZX",
                                                                ZAx=normal,
                                                                XAx=tangU)
                elif oriIsAlongV:
                    if normal is None:
                        raise ValueError(
                            "Normal vector not available for a placement resting on "
                            + el_topo +
                            ". Normal vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    if tangV is None:
                        raise ValueError(
                            "TangentV vector not available for point on " +
                            el_topo +
                            ". TangentV vector is required for orientation mode '"
                            + obj.OrientMode + "'")
                    ori = Utils.makeOrientationFromLocalAxesUni("ZX",
                                                                ZAx=normal,
                                                                XAx=tangV)
                else:
                    raise ValueError("Orientation mode not implemented: " +
                                     obj.OrientMode)

                output.append(App.Placement(pos, ori))

                if not isMultiSol:
                    break

        return output
Example #29
0
    def derivedExecute(self, obj):
        self.assureGenerator(obj)
        self.assureProperties(obj)
        self.updateReadonlyness(obj)

        # Apply links
        if screen(obj.Link):
            if lattice2BaseFeature.isObjectLattice(screen(obj.Link)):
                lattice2Executer.warning(
                    obj,
                    "For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape."
                )

            #resolve the link
            if len(obj.LinkSubelement) > 0:
                linkedShape = screen(obj.Link).Shape.getElement(
                    obj.LinkSubelement)
            else:
                linkedShape = screen(obj.Link).Shape

            #Type check
            if linkedShape.ShapeType != 'Edge':
                raise ValueError('Axis link must be an edge; it is ' +
                                 linkedShape.ShapeType + ' instead.')
            if type(linkedShape.Curve) is not Part.Line:
                raise ValueError('Axis link must be a line; it is ' +
                                 type(linkedShape.Curve) + ' instead.')

            #obtain
            start_point = linkedShape.valueAt(linkedShape.FirstParameter)
            end_point = linkedShape.valueAt(linkedShape.LastParameter)
            dir = end_point - start_point
            point = start_point if not obj.Reverse else end_point

            if obj.DirIsDriven:
                obj.Dir = dir
            if obj.PointIsDriven:
                obj.Point = point
            if obj.DrivenProperty != 'None':
                if obj.DrivenProperty == 'Span':
                    propname = "SpanEnd"
                    obj.SpanEnd = obj.SpanStart + App.Units.Quantity(
                        'mm') * dir.Length
                else:
                    propname = obj.DrivenProperty
                    setattr(obj, propname, dir.Length)
                if self.generator.isPropertyControlledByGenerator(propname):
                    lattice2Executer.warning(
                        obj, "Property " + propname +
                        " is driven by both generator and link. Generator has priority."
                    )

        # Generate series of values
        self.generator.execute()
        values = [float(strv) for strv in obj.Values]

        #Apply reversal
        if obj.Reverse:
            obj.Dir = obj.Dir * (-1.0)
            if not (obj.DirIsDriven and screen(obj.Link)):
                obj.Reverse = False

        # precompute orientation
        if obj.OrientMode == 'Along axis':
            ori = lattice2GeomUtils.makeOrientationFromLocalAxes(
                ZAx=obj.Dir).multiply(
                    lattice2GeomUtils.makeOrientationFromLocalAxes(
                        ZAx=App.Vector(1, 0, 0), XAx=App.Vector(0, 0, 1)))
        else:
            ori = App.Rotation()

        dir = obj.Dir
        dir.normalize()

        # Make the array
        output = []  # list of placements
        for v in values:
            output.append(App.Placement(obj.Point + obj.Dir * v, ori))

        return output
    def derivedExecute(self,obj):
        
        self.initNewProperties(obj)
        
        outputIsLattice = lattice2BaseFeature.isObjectLattice(obj.Object)
        
        if not lattice2BaseFeature.isObjectLattice(obj.Object):
            if obj.ObjectTraversal == "Direct children only":
                objectShapes = obj.Object.Shape.childShapes()
                if obj.Object.Shape.ShapeType != "Compound":
                    lattice2Executer.warning(obj,"shape supplied as object is not a compound. It is going to be downgraded one level down (e.g, if it is a wire, the edges are going to be enumerated as children).")
            elif obj.ObjectTraversal == "Recursive":
                objectShapes = LCE.AllLeaves(obj.Object.Shape)
            else:
                raise ValueError("Traversal mode not implemented: "+obj.ObjectTraversal)
        else:
            objectPlms = lattice2BaseFeature.getPlacementsList(obj.Object, obj)
        placements = lattice2BaseFeature.getPlacementsList(obj.PlacementsTo, obj)

        
        # Precompute referencing
        placements = DereferenceArray(obj, placements, obj.PlacementsFrom, obj.Referencing)
                
        # initialize output containers and loop variables
        outputShapes = [] #output list of shapes
        outputPlms = [] #list of placements
        iChild = 0
        numChildren = len(objectPlms) if outputIsLattice else len(objectShapes) 
        copy_method_index = ShapeCopy.getCopyTypeIndex(obj.Copying)
        
        # the essence
        for iPlm in range(len(placements)):
            if iChild == numChildren:
                if obj.LoopObjectSequence:
                    iChild = 0
                else:
                    break
            
            plm = placements[iPlm]
             
            if outputIsLattice:
                objectPlm = objectPlms[iChild]
                outputPlms.append(plm.multiply(objectPlm))
            else:
                outputShape = ShapeCopy.copyShape(objectShapes[iChild], copy_method_index, plm)
                # outputShape.Placement = plm.multiply(outputShape.Placement) #now done by shape copy routine
                outputShapes.append(outputShape)
            
            iChild += 1
            
        if len(placements) > numChildren and not obj.LoopObjectSequence:
            lattice2Executer.warning(obj,"There are fewer children to populate, than placements to be populated (%1, %2). Extra placements will be dropped.".replace("%1", str(numChildren)).replace("%2",str(len(placements))))
            
        if len(placements) < numChildren:
            lattice2Executer.warning(obj,"There are more children to populate, than placements to be populated (%1, %2). Extra children will be dropped.".replace("%1", str(numChildren)).replace("%2",str(len(placements))))
            
        if outputIsLattice:
            return outputPlms
        else:
            obj.Shape = Part.makeCompound(outputShapes)
            return None
Example #31
0
 def Activated(self):
     sel = FreeCADGui.Selection.getSelectionEx()[0]
     isLattice = lattice2BaseFeature.isObjectLattice(sel.Object)
     
     strStructure = []
     if not hasattr(sel.Object,"Shape"):
         strStructure = ["<object has no shape!>"]
     else:
         if sel.Object.Shape.isNull():
             strStructure.append(unicode("<NULL SHAPE!>"))
         else:
             for (child, msg, it) in LCE.CompoundExplorer(sel.Object.Shape):
                 #child is a shape. 
                 #msg is int equal to one of three constants:
                 #    CompoundExplorer.MSG_LEAF  - child is a leaf (non-compound)
                 #    CompoundExplorer.MSG_DIVEDOWN  - child is a compound that is about to be traversed
                 #    CompoundExplorer.MSG_BUBBLEUP  - child is a compound that was just finished traversing        
                 #it is reference to iterator class (can be useful to extract current depth, or index stack)
                 if msg == LCE.CompoundExplorer.MSG_LEAF or msg == LCE.CompoundExplorer.MSG_DIVEDOWN:
                     try:
                         strMsg =  '    ' * it.curDepth() + shapeInfoString(child)
                         if msg == LCE.CompoundExplorer.MSG_DIVEDOWN:
                             strMsg += ":"
                     except Exception as err:
                         strMsg = "ERROR: " + err.message
                     strStructure.append(unicode(strMsg))
         
     strSubInfo = []
     if sel.HasSubObjects:
         subNames = sel.SubElementNames
         subObjects = sel.SubObjects
         for i in range(0,len(subNames)):
             strMsg = subNames[i] + ": "
             child = subObjects[i]
             
             try:
                 strMsg += shapeInfoString(child)
             except Exception as err:
                 strMsg += "ERROR: " + err.message
             strSubInfo.append(unicode(strMsg))
     
     allText = u''
     if sel.HasSubObjects:
         allText += u"Selected " + str(len(sel.SubElementNames)) + u" subelements:\n"
         allText += u'\n'.join(strSubInfo) + u'\n\n'
     
     allText += u'Selected document object:\n'
     allText += u'  Name = ' + unicode(sel.Object.Name) + u'\n'
     allText += u'  Label = ' + sel.Object.Label + u'\n'
     allText += u'  Is placement/array = ' + unicode(repr(isLattice)) + u'\n'
     allText += u'Structure: \n'
     allText += u'\n'.join(strStructure)
     mb = QtGui.QMessageBox()
     mb.setIcon(mb.Icon.Information)
     lines = allText.split(u"\n") 
     if len(lines)>30:
         lines = lines[0:30]
         lines.append(u"...")
     mb.setText(u"\n".join(lines))
     mb.setWindowTitle(translate("Lattice2_Inspect","Selection info", None))
     
     btnClose = mb.addButton(QtGui.QMessageBox.StandardButton.Close)
     btnCopy = mb.addButton("Copy to clipboard",QtGui.QMessageBox.ButtonRole.ActionRole)
     mb.setDefaultButton(btnClose)
     mb.exec_()
     
     if mb.clickedButton() is btnCopy:
         cb = QtGui.QClipboard()
         cb.setText(allText)
Example #32
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 #33
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 #34
0
    def derivedExecute(self, obj):
        self.assureGenerator(obj)
        self.assureProperties(obj)
        self.updateReadonlyness(obj)

        # Apply links
        if screen(obj.AxisLink):
            if lattice2BaseFeature.isObjectLattice(screen(obj.AxisLink)):
                lattice2Executer.warning(
                    obj,
                    "For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape."
                )

            #resolve the link
            if len(obj.AxisLinkSubelement) > 0:
                linkedShape = screen(obj.AxisLink).Shape.getElement(
                    obj.AxisLinkSubelement)
            else:
                linkedShape = screen(obj.AxisLink).Shape

            #Type check
            if linkedShape.ShapeType != 'Edge':
                raise ValueError('Axis link must be an edge; it is ' +
                                 linkedShape.ShapeType + ' instead.')

            #prepare
            dir = App.Vector()
            point = App.Vector()
            if isinstance(linkedShape.Curve, Part.Line):
                start_point = linkedShape.valueAt(linkedShape.FirstParameter)
                end_point = linkedShape.valueAt(linkedShape.LastParameter)
                dir = end_point - start_point
                point = start_point
            elif isinstance(linkedShape.Curve, Part.Circle):
                dir = linkedShape.Curve.Axis
                point = linkedShape.Curve.Center
            else:
                raise ValueError(
                    "Edge " + repr(linkedShape) +
                    " can't be used to derive an axis. It must be either a line or a circle/arc."
                )

            #apply
            if obj.AxisDirIsDriven:
                obj.AxisDir = dir
            if obj.AxisPointIsDriven:
                obj.AxisPoint = point

        self.generator.execute()

        # cache properties into variables
        radius = float(obj.Radius)
        values = [float(strv) for strv in obj.Values]

        # compute initial vector. It is to be perpendicular to Axis
        rot_ini = lattice2GeomUtils.makeOrientationFromLocalAxes(
            ZAx=obj.AxisDir)
        overallPlacement = App.Placement(obj.AxisPoint, rot_ini)

        # Make the array
        output = []  # list of placements
        for ang in values:
            p = Part.Vertex()
            localrot = App.Rotation(App.Vector(0, 0, 1), ang)
            localtransl = localrot.multVec(App.Vector(radius, 0, 0))
            localplm = App.Placement(localtransl, localrot)
            resultplm = overallPlacement.multiply(localplm)
            if obj.OrientMode == 'None':
                resultplm.Rotation = App.Rotation()
            output.append(resultplm)

        return output
Example #35
0
    def derivedExecute(self,obj):
        # cache stuff
        base = obj.Base.Shape
        if not lattice2BaseFeature.isObjectLattice(obj.Base):
            lattice2Executer.warning(obj, "Base is not a lattice, but lattice is expected. Results may be unexpected.\n")
        input = [leaf.Placement for leaf in LCE.AllLeaves(base)]
        
        if len(input) < 2:
            raise ValueError("At least 2 placements ar needed to interpolate; there are just "+str(len(input))+" in base array.")
        if obj.NumberSamples < 2:
            raise ValueError("Can output no less than 2 samples; "+str(obj.NumberSamples)+" was requested.")
                        
        #cache mode comparisons, for speed
        posIsInterpolate = obj.TranslateMode == 'interpolate'
        posIsReset = obj.TranslateMode == 'reset'
        
        oriIsInterpolate = obj.OrientMode == 'interpolate'
        oriIsReset = obj.OrientMode == 'reset'        
        
        # construct interpolation functions
        #  prepare lists of input samples
        IArray = [float(i) for i in range(0,len(input))]
        XArray = [plm.Base.x for plm in input]
        YArray = [plm.Base.y for plm in input]
        ZArray = [plm.Base.z for plm in input]
        QArrays = [[],[],[],[]]
        prevQ = [0.0]*4
        for plm in input:
            Q = plm.Rotation.Q
            #test if quaernion has changed sign compared to previous one. 
            # Quaternions of opposite sign are equivalent in terms of rotation, 
            # but sign changes confuse interpolation, so we are detecting sign 
            # changes and discarding them
            if dotProduct(Q,prevQ) < -ParaConfusion: 
                Q = [-v for v in Q] 
            for iQ in [0,1,2,3]:
                QArrays[iQ].append( Q[iQ] ) 
            prevQ = Q
        
        #  constuct function objects
        if posIsInterpolate:
            FX = LIU.InterpolateF(IArray,XArray)
            FY = LIU.InterpolateF(IArray,YArray)
            FZ = LIU.InterpolateF(IArray,ZArray)
        if oriIsInterpolate:
            FQs = []
            for iQ in [0,1,2,3]:
                FQs.append(LIU.InterpolateF(IArray,QArrays[iQ]))
                
        # initialize output containers and loop variables
        outputPlms = [] #list of placements

        for i_output in range(0,math.trunc(obj.NumberSamples+ParaConfusion)):
            i_input = float(i_output) / (obj.NumberSamples-1) * (len(input)-1)
            pos = App.Vector()
            ori = App.Rotation()
            if posIsInterpolate:
                pos = App.Vector(FX.value(i_input), FY.value(i_input), FZ.value(i_input))
            
            if oriIsInterpolate:
                ori = App.Rotation(FQs[0].value(i_input),
                                   FQs[1].value(i_input),
                                   FQs[2].value(i_input),
                                   FQs[3].value(i_input))                
            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms
    def execute(self, selfobj):

        self.updatedProperties = set()
        try:
            if LBF.isObjectLattice(selfobj.Object):
                plms = LBF.getPlacementsList(selfobj.Object)
                self.assignProp(selfobj, "App::PropertyInteger", "NumberOfPlacements", len(plms))
                for i in range(min(len(plms), 10)):
                    self.assignProp(selfobj, "App::PropertyPlacement", "Placement" + str(i), plms[i])
            else:
                sh = selfobj.Object.Shape

                self.assignProp(selfobj, "App::PropertyString", "ShapeType", sh.ShapeType)

                if (
                    sh.ShapeType == "Compound"
                    or sh.ShapeType == "CompSolid"
                    or sh.ShapeType == "Shell"
                    or sh.ShapeType == "Wire"
                ):
                    self.assignProp(
                        selfobj, "App::PropertyInteger", sh.ShapeType + "NumChildren", len(sh.childShapes(False, False))
                    )
                if sh.ShapeType == "Compound":
                    max_depth = 0
                    num_leaves = 0
                    last_leaf = None
                    for (child, msg, it) in LCE.CompoundExplorer(sh):
                        if it.curDepth() > max_depth:
                            max_depth = it.curDepth()
                        if msg == LCE.CompoundExplorer.MSG_LEAF:
                            last_leaf = child
                            num_leaves += 1
                    self.assignProp(selfobj, "App::PropertyInteger", "CompoundNestingDepth", max_depth)
                    self.assignProp(selfobj, "App::PropertyInteger", "CompoundNumLeaves", num_leaves)
                    if num_leaves == 1:
                        self.assignProp(
                            selfobj, "App::PropertyString", "ShapeType", sh.ShapeType + "(" + last_leaf.ShapeType + ")"
                        )
                        sh = last_leaf

                self.transplant_all_attributes(
                    selfobj, sh, "Shape", withdraw_set=set(["ShapeType", "Content", "Module", "TypeId"])
                )

                if sh.ShapeType == "Face":
                    typelist = [
                        "BSplineSurface",
                        "BezierSurface",
                        "Cone",
                        "Cylinder",
                        "OffsetSurface",
                        "Plane",
                        "PlateSurface",
                        "RectangularTrimmedSurface",
                        "Sphere",
                        "SurfaceOfExtrusion",
                        "SurfaceOfRevolution",
                        "Toroid",
                    ]
                    surf = sh.Surface
                    for typename in typelist:
                        if type(surf) is getattr(Part, typename):
                            break
                        typename = None
                    self.assignProp(selfobj, "App::PropertyString", "FaceType", typename)

                    self.transplant_all_attributes(selfobj, surf, "Face")
                elif sh.ShapeType == "Edge":
                    typelist = [
                        "Arc",
                        "ArcOfCircle",
                        "ArcOfEllipse",
                        "ArcOfHyperbola",
                        "ArcOfParabola",
                        "BSplineCurve",
                        "BezierCurve",
                        "Circle",
                        "Ellipse",
                        "Hyperbola",
                        "Line",
                        "OffsetCurve",
                        "Parabola",
                    ]
                    crv = sh.Curve
                    for typename in typelist:
                        if type(crv) is getattr(Part, typename):
                            break
                        typename = None
                    self.assignProp(selfobj, "App::PropertyString", "EdgeType", typename)

                    self.transplant_all_attributes(selfobj, crv, "Edge")

                elif sh.ShapeType == "Vertex":
                    self.assignProp(selfobj, "App::PropertyVector", "VertexPosition", sh.Point)
        finally:
            # remove properties that haven't been updated
            for propname in selfobj.PropertiesList:
                if selfobj.getGroupOfProperty(propname) == "info":
                    if not (propname in self.updatedProperties):
                        selfobj.removeProperty(propname)
Example #37
0
    def derivedExecute(self,obj):
        self.assureGenerator(obj)
        self.updateReadonlyness(obj)

        # Apply links
        if obj.Link:
            if lattice2BaseFeature.isObjectLattice(obj.Link):
                lattice2Executer.warning(obj,"For polar array, axis link is expected to be a regular shape. Lattice objct was supplied instead, it's going to be treated as a generic shape.")
            
            #resolve the link
            if len(obj.LinkSubelement) > 0:
                linkedShape = obj.Link.Shape.getElement(obj.LinkSubelement)
            else:
                linkedShape = obj.Link.Shape
            
            #Type check
            if linkedShape.ShapeType != 'Edge':
                raise ValueError('Axis link must be an edge; it is '+linkedShape.ShapeType+' instead.')
            if type(linkedShape.Curve) is not Part.Line:
                raise ValueError('Axis link must be a line; it is '+type(linkedShape.Curve)+' instead.')
            
            #obtain
            dir = linkedShape.Curve.EndPoint - linkedShape.Curve.StartPoint
            point = linkedShape.Curve.StartPoint if not obj.Reverse else linkedShape.Curve.EndPoint
            
            if obj.DirIsDriven:
                obj.Dir = dir
            if obj.PointIsDriven:
                obj.Point = point
            if obj.DrivenProperty != 'None':
                if obj.DrivenProperty == 'Span':
                    propname = "SpanEnd"
                    obj.SpanEnd = obj.SpanStart + App.Units.Quantity('mm')*dir.Length
                else:
                    propname = obj.DrivenProperty
                    setattr(obj, propname, dir.Length)
                if self.generator.isPropertyControlledByGenerator(propname):
                    lattice2Executer.warning(obj, "Property "+propname+" is driven by both generator and link. Generator has priority.")

        
        # Generate series of values
        self.generator.execute()
        values = [float(strv) for strv in obj.Values]
        
        #Apply reversal
        if obj.Reverse:
            obj.Dir = obj.Dir*(-1.0)
            if not(obj.DirIsDriven and obj.Link):
                obj.Reverse = False

        # precompute orientation
        if obj.OrientMode == 'Along axis':
            ori = lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= obj.Dir).multiply(
                    lattice2GeomUtils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0), XAx= App.Vector(0,0,1)) )
        else:
            ori = App.Rotation()
        
        dir = obj.Dir
        dir.normalize()
        
        # Make the array
        output = [] # list of placements
        for v in values:
            output.append( App.Placement(obj.Point + obj.Dir*v, ori) )
            
        return output
Example #38
0
    def derivedExecute(self,obj):
        
        self.initNewProperties(obj)
        
        outputIsLattice = lattice2BaseFeature.isObjectLattice(screen(obj.Object))
        
        if not lattice2BaseFeature.isObjectLattice(screen(obj.Object)):
            if obj.ObjectTraversal == "Direct children only":
                objectShapes = screen(obj.Object).Shape.childShapes()
                if screen(obj.Object).Shape.ShapeType != "Compound":
                    lattice2Executer.warning(obj,"shape supplied as object is not a compound. It is going to be downgraded one level down (e.g, if it is a wire, the edges are going to be enumerated as children).")
            elif obj.ObjectTraversal == "Recursive":
                objectShapes = LCE.AllLeaves(screen(obj.Object).Shape)
            else:
                raise ValueError("Traversal mode not implemented: "+obj.ObjectTraversal)
        else:
            objectPlms = lattice2BaseFeature.getPlacementsList(screen(obj.Object), obj)
        placements = lattice2BaseFeature.getPlacementsList(screen(obj.PlacementsTo), obj)

        
        # Precompute referencing
        placements = DereferenceArray(obj, placements, screen(obj.PlacementsFrom), obj.Referencing)
                
        # initialize output containers and loop variables
        outputShapes = [] #output list of shapes
        outputPlms = [] #list of placements
        iChild = 0
        numChildren = len(objectPlms) if outputIsLattice else len(objectShapes) 
        copy_method_index = ShapeCopy.getCopyTypeIndex(obj.Copying)
        
        # the essence
        for iPlm in range(len(placements)):
            if iChild == numChildren:
                if obj.LoopObjectSequence:
                    iChild = 0
                else:
                    break
            
            plm = placements[iPlm]
             
            if outputIsLattice:
                objectPlm = objectPlms[iChild]
                outputPlms.append(plm.multiply(objectPlm))
            else:
                outputShape = ShapeCopy.copyShape(objectShapes[iChild], copy_method_index, plm)
                # outputShape.Placement = plm.multiply(outputShape.Placement) #now done by shape copy routine
                outputShapes.append(outputShape)
            
            iChild += 1
            
        if len(placements) > numChildren and not obj.LoopObjectSequence:
            lattice2Executer.warning(obj,"There are fewer children to populate, than placements to be populated (%1, %2). Extra placements will be dropped.".replace("%1", str(numChildren)).replace("%2",str(len(placements))))
            
        if len(placements) < numChildren:
            lattice2Executer.warning(obj,"There are more children to populate, than placements to be populated (%1, %2). Extra children will be dropped.".replace("%1", str(numChildren)).replace("%2",str(len(placements))))
            
        if outputIsLattice:
            return outputPlms
        else:
            obj.Shape = Part.makeCompound(outputShapes)
            return None
Example #39
0
    def execute(self,obj):
        nOfStrings = len(obj.Strings)
        lattice = obj.ArrayLink
        if lattice is None:
            plms = [App.Placement() for i in range(0,nOfStrings)]
        else:
            if not lattice2BaseFeature.isObjectLattice(lattice):
                lattice2Executer.warning(obj,"ShapeString's link to array must point to a lattice. It points to a generic shape. Results may be unexpected.")
            leaves = LCE.AllLeaves(lattice.Shape)
            plms = [leaf.Placement for leaf in leaves]
        
        #update foolObj's properties
        self.makeFoolObj(obj) #make sure we have one - fixes defunct Lattice ShapeString after save-load
        for (proptype, propname, group, hint) in self.foolObj.properties:
            if propname != "String": #ignore "String", that will be taken care of in the following loop
                setattr(self.foolObj, propname, getattr(obj, propname))
        self.foolObj.FontFile = findFont(obj.FontFile)
        obj.FullPathToFont = self.foolObj.FontFile
        
        shapes = []
        for i in range(  0 ,  min(len(plms),len(obj.Strings))  ):
            if len(obj.Strings[i]) > 0:
                #generate shapestring using Draft
                self.foolObj.String = obj.Strings[i]
                self.foolObj.Shape = None
                self.draft_shape_string.execute(self.foolObj)
                shape = self.foolObj.Shape
                
                #calculate alignment point
                if obj.XAlign == 'None' and obj.YAlign == 'None':
                    pass #need not calculate boundbox
                else:
                    if obj.AlignPrecisionBoundBox:
                        bb = getPrecisionBoundBox(shape)
                    else:
                        bb = shape.BoundBox

                alignPnt = App.Vector()
                
                if obj.XAlign == 'Left':
                    alignPnt.x = bb.XMin
                elif obj.XAlign == 'Right':
                    alignPnt.x = bb.XMax
                elif obj.XAlign == 'Middle':
                    alignPnt.x = bb.Center.x

                if obj.YAlign == 'Bottom':
                    alignPnt.y = bb.YMin
                elif obj.YAlign == 'Top':
                    alignPnt.y = bb.YMax
                elif obj.YAlign == 'Middle':
                    alignPnt.y = bb.Center.y
                
                #Apply alignment
                shape.Placement = App.Placement(alignPnt*(-1.0), App.Rotation()).multiply(shape.Placement)
                
                #Apply placement from array
                shape.Placement = plms[i].multiply(shape.Placement)
                
                shapes.append(shape.copy())
        
        if len(shapes) == 0:
            scale = 1.0
            if lattice is not None:
                scale = lattice.Shape.BoundBox.DiagonalLength/math.sqrt(3)/math.sqrt(len(shps))
            if scale < DistConfusion * 100:
                scale = 1.0
            obj.Shape = markers.getNullShapeShape(scale)
            raise ValueError('No strings were converted into shapes') #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(shapes)
Example #40
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
    def execute(self,selfobj):
        
        self.updatedProperties = set()
        try:
            if LBF.isObjectLattice(screen(selfobj.Object)):
                plms = LBF.getPlacementsList(screen(selfobj.Object))
                self.assignProp(selfobj,"App::PropertyInteger","NumberOfPlacements",len(plms))
                for i in range(    min(  len(plms), 10  )    ):
                    self.assignProp(selfobj,"App::PropertyPlacement","Placement"+str(i),plms[i])
            else:
                sh = screen(selfobj.Object).Shape
                
                self.assignProp(selfobj,"App::PropertyString","ShapeType", sh.ShapeType)
                
                if sh.ShapeType == "Compound" or sh.ShapeType == "CompSolid" or sh.ShapeType == "Shell" or sh.ShapeType == "Wire":
                    self.assignProp(selfobj,"App::PropertyInteger",sh.ShapeType+"NumChildren",len(sh.childShapes(False,False)))
                if sh.ShapeType == "Compound":
                    max_depth = 0
                    num_leaves = 0
                    last_leaf = None
                    for (child, msg, it) in LCE.CompoundExplorer(sh):
                        if it.curDepth() > max_depth:
                            max_depth = it.curDepth()
                        if msg == LCE.CompoundExplorer.MSG_LEAF:
                            last_leaf = child
                            num_leaves += 1
                    self.assignProp(selfobj,"App::PropertyInteger","CompoundNestingDepth", max_depth)
                    self.assignProp(selfobj,"App::PropertyInteger","CompoundNumLeaves", num_leaves)
                    if num_leaves == 1:
                        self.assignProp(selfobj,"App::PropertyString","ShapeType", sh.ShapeType + "(" + last_leaf.ShapeType + ")")
                        sh = last_leaf

                self.transplant_all_attributes(selfobj,sh,"Shape", withdraw_set= set(["ShapeType", "Content", "Module", "TypeId"]))
                        
                if sh.ShapeType == "Face":
                    typelist = ["BSplineSurface",
                                "BezierSurface",
                                "Cone",
                                "Cylinder",
                                "OffsetSurface",
                                "Plane",
                                "PlateSurface",
                                "RectangularTrimmedSurface",
                                "Sphere",
                                "SurfaceOfExtrusion",
                                "SurfaceOfRevolution",
                                "Toroid",
                                ]
                    surf = sh.Surface
                    for typename in typelist:
                        if type(surf) is getattr(Part, typename):
                            break
                        typename = None
                    self.assignProp(selfobj,"App::PropertyString","FaceType",typename)
                    
                    self.transplant_all_attributes(selfobj,surf,"Face")
                elif sh.ShapeType == "Edge":
                    typelist = ["Arc",
                                "ArcOfCircle",
                                "ArcOfEllipse",
                                "ArcOfHyperbola",
                                "ArcOfParabola",
                                "BSplineCurve",
                                "BezierCurve",
                                "Circle",
                                "Ellipse",
                                "Hyperbola",
                                "Line",
                                "OffsetCurve",
                                "Parabola",
                                ]
                    crv = sh.Curve
                    for typename in typelist:
                        if type(crv) is getattr(Part, typename):
                            break
                        typename = None
                    self.assignProp(selfobj,"App::PropertyString","EdgeType",typename)
                    
                    self.transplant_all_attributes(selfobj,crv,"Edge")
                        
                elif sh.ShapeType == "Vertex":
                    self.assignProp(selfobj,"App::PropertyVector","VertexPosition",sh.Point)
        finally:
            #remove properties that haven't been updated
            for propname in selfobj.PropertiesList:
                if selfobj.getGroupOfProperty(propname) == "info":
                    if not (propname in self.updatedProperties):
                        selfobj.removeProperty(propname)
Example #42
0
    def derivedExecute(self,obj):
        # cache stuff
        base = screen(obj.Base).Shape
        if not lattice2BaseFeature.isObjectLattice(screen(obj.Base)):
            lattice2Executer.warning(obj, "Base is not a lattice, but lattice is expected. Results may be unexpected.\n")
        input = [leaf.Placement for leaf in LCE.AllLeaves(base)]
        
        if len(input) < 2:
            raise ValueError("At least 2 placements ar needed to interpolate; there are just "+str(len(input))+" in base array.")
        if obj.NumberSamples < 2:
            raise ValueError("Can output no less than 2 samples; "+str(obj.NumberSamples)+" was requested.")
                        
        #cache mode comparisons, for speed
        posIsInterpolate = obj.TranslateMode == 'interpolate'
        posIsReset = obj.TranslateMode == 'reset'
        
        oriIsInterpolate = obj.OrientMode == 'interpolate'
        oriIsReset = obj.OrientMode == 'reset'        
        
        # construct interpolation functions
        #  prepare lists of input samples
        IArray = [float(i) for i in range(0,len(input))]
        XArray = [plm.Base.x for plm in input]
        YArray = [plm.Base.y for plm in input]
        ZArray = [plm.Base.z for plm in input]
        QArrays = [[],[],[],[]]
        prevQ = [0.0]*4
        for plm in input:
            Q = plm.Rotation.Q
            #test if quaernion has changed sign compared to previous one. 
            # Quaternions of opposite sign are equivalent in terms of rotation, 
            # but sign changes confuse interpolation, so we are detecting sign 
            # changes and discarding them
            if dotProduct(Q,prevQ) < -ParaConfusion: 
                Q = [-v for v in Q] 
            for iQ in [0,1,2,3]:
                QArrays[iQ].append( Q[iQ] ) 
            prevQ = Q
        
        #  construct function objects
        if posIsInterpolate:
            FX = LIU.InterpolateF(IArray,XArray)
            FY = LIU.InterpolateF(IArray,YArray)
            FZ = LIU.InterpolateF(IArray,ZArray)
        if oriIsInterpolate:
            FQs = []
            for iQ in [0,1,2,3]:
                FQs.append(LIU.InterpolateF(IArray,QArrays[iQ]))
                
        # initialize output containers and loop variables
        outputPlms = [] #list of placements

        for i_output in range(0,math.trunc(obj.NumberSamples+ParaConfusion)):
            i_input = float(i_output) / (obj.NumberSamples-1) * (len(input)-1)
            pos = App.Vector()
            ori = App.Rotation()
            if posIsInterpolate:
                pos = App.Vector(FX.value(i_input), FY.value(i_input), FZ.value(i_input))
            
            if oriIsInterpolate:
                ori = App.Rotation(FQs[0].value(i_input),
                                   FQs[1].value(i_input),
                                   FQs[2].value(i_input),
                                   FQs[3].value(i_input))                
            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms
Example #43
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
    def derivedExecute(self,obj):
        # cache stuff
        if lattice2BaseFeature.isObjectLattice(obj.ShapeLink):
            lattice2Executer.warning(obj,"ShapeLink points to a placement/array of placements. The placement/array will be reinterpreted as a generic shape; the results may be unexpected.")

        base = obj.ShapeLink.Shape
        if obj.CompoundTraversal == "Use as a whole":
            baseChildren = [base]
        else:
            if base.ShapeType != 'Compound':
                base = Part.makeCompound([base])
            if obj.CompoundTraversal == "Recursive":
                baseChildren = LCE.AllLeaves(base)
            else:
                baseChildren = base.childShapes()
        
                        
        #cache mode comparisons, for speed
        posIsNone = obj.TranslateMode == '(none)'
        posIsParent = obj.TranslateMode == 'parent'
        posIsChild = obj.TranslateMode == 'child'
        posIsCenterM = obj.TranslateMode == 'child.CenterOfMass'
        posIsCenterBB = obj.TranslateMode == 'child.CenterOfBoundBox'
        posIsVertex = obj.TranslateMode == 'child.Vertex'
        
        oriIsNone = obj.OrientMode == '(none)'
        oriIsParent = obj.OrientMode == 'parent'
        oriIsChild = obj.OrientMode == 'child'
        oriIsInertial = obj.OrientMode == 'child.InertiaAxes'
        oriIsEdge = obj.OrientMode == 'child.Edge'
        oriIsFace = obj.OrientMode == 'child.FaceAxis'
        
        # initialize output containers and loop variables
        outputPlms = [] #list of placements
        
        # the essence
        for child in baseChildren:
            pos = App.Vector()
            ori = App.Rotation()
            if posIsNone:
                pass
            elif posIsParent:
                pos = base.Placement.Base
            elif posIsChild:
                pos = child.Placement.Base
            elif posIsCenterM:
                leaves = LCE.AllLeaves(child)
                totalW = 0
                weightAttrib = {"Vertex":"",
                             "Edge":"Length",
                             "Wire":"Length",
                             "Face":"Area",
                             "Shell":"Area",
                             "Solid":"Volume",
                             "CompSolid":""}[leaves[0].ShapeType]
                #Center of mass of a compound is a weghted average of centers
                # of mass of individual objects.
                for leaf in leaves:
                    w = 1.0 if not weightAttrib else (getattr(leaf, weightAttrib))
                    if leaf.ShapeType == 'Vertex':
                        leafCM = leaf.Point
                    #elif child.ShapeType == 'CompSolid':
                        #todo
                    else: 
                        leafCM = leaf.CenterOfMass
                    pos += leafCM * w
                    totalW += w
                pos = pos * (1.0/totalW)
            elif posIsCenterBB:
                import lattice2BoundBox
                bb = lattice2BoundBox.getPrecisionBoundBox(child)
                pos = bb.Center
            elif posIsVertex:
                v = child.Vertexes[obj.TranslateElementIndex - 1]
                pos = v.Point
            else:
                raise ValueError(obj.Name + ": translation mode not implemented: "+obj.TranslateMode)
            
            if oriIsNone:
                pass
            elif oriIsParent:
                ori = base.Placement.Rotation
            elif oriIsChild:
                ori = child.Placement.Rotation
            elif oriIsInertial:
                leaves = LCE.AllLeaves(child)
                if len(leaves)>1:
                    raise ValueError(obj.Name + ": calculation of principal axes of compounds is not supported yet")
                props = leaves[0].PrincipalProperties
                XAx = props['FirstAxisOfInertia']
                ZAx = props['ThirdAxisOfInertia']
                ori = Utils.makeOrientationFromLocalAxes(ZAx, XAx)
            elif oriIsEdge:
                edge = child.Edges[obj.OrientElementIndex - 1]
                XAx = edge.Curve.tangent(edge.Curve.FirstParameter)[0]
                ori1 = Utils.makeOrientationFromLocalAxes(ZAx= XAx)
                ori2 = Utils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0),XAx= App.Vector(0,0,1))
                ori = ori1.multiply(ori2)
            elif oriIsFace:
                face = child.Faces[obj.OrientElementIndex - 1]
                ZAx = face.Surface.Axis
            else:
                raise ValueError(obj.Name + ": orientation mode not implemented: "+obj.OrientMode)

            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms
Example #45
0
    def derivedExecute(self,obj):
        #validity check
        if not lattice2BaseFeature.isObjectLattice(obj.Base):
            lattice2Executer.warning(obj,"A lattice object is expected as Base, but a generic shape was provided. It will be treated as a lattice object; results may be unexpected.")
        
        toolShape = obj.Tool.Shape
        if lattice2BaseFeature.isObjectLattice(obj.Tool):
            lattice2Executer.warning(obj,"A lattice object was provided as Tool. It will be converted into points; orientations will be ignored.")
            leaves = LCE.AllLeaves(toolShape)
            points = [Part.Vertex(leaf.Placement.Base) for leaf in leaves]
            toolShape = Part.makeCompound(points)

        leaves = LCE.AllLeaves(obj.Base.Shape)
        input = [leaf.Placement for leaf in leaves]

        output = [] #variable to receive the final list of placements
        
        #cache settings
        elev = float(obj.PosElevation)
        posIsKeep = obj.TranslateMode == 'keep'
        posIsProjected = obj.TranslateMode == 'projected'
        posIsMixed = obj.TranslateMode == 'mixed'
        mixF = float(obj.PosMixFraction)
        oriIsKeep = obj.OrientMode == 'keep'
        oriIsAlongGap = obj.OrientMode == 'along gap'
        oriIsTangentPlane = obj.OrientMode == 'tangent plane'
        oriIsAlongU = obj.OrientMode == 'along u'
        oriIsAlongV = obj.OrientMode == 'along v'
        
        isMultiSol = obj.Multisolution == 'use all'
        
        for plm in input:
            v = Part.Vertex(plm.Base)
            projection = v.distToShape(toolShape)
            (dist, gaps, infos) = projection
            for iSol in range(0,len(gaps)):
                (posKeep, posPrj) = gaps[iSol]
                (dummy, dummy, dummy, el_topo, el_index, el_params) = infos[iSol]

                # Fetch all possible parameters (some may not be required, depending on modes)
                normal = posKeep - posPrj
                if normal.Length < DistConfusion:
                    normal = None
                
                tangU = None
                tangV = None
                if el_topo == 'Face':
                    face = toolShape.Faces[el_index]
                    if normal is None:
                        normal = face.normalAt(*el_params)
                    (tangU, tangV) = face.tangentAt(*el_params)
                elif el_topo == "Edge":
                    edge = toolShape.Edges[el_index]
                    tangU = edge.tangentAt(el_params)
                
                if normal is not None:
                    normal.normalize()
                
                #mode logic - compute new placement
                if posIsKeep:
                    pos = plm.Base
                elif posIsProjected:
                    pos = posPrj
                elif posIsMixed:
                    pos = posKeep*mixF + posPrj*(1-mixF)
                else:
                    raise ValueError("Positioning mode not implemented: " + obj.TranslateMode )
                
                if abs(elev) > DistConfusion:
                    if normal is None:
                        raise ValueError("Normal vector not available for a placement resting on " + el_topo +". Normal vector is required for nonzero position elevation.")
                    pos += normal * elev
                    
                    
                if oriIsKeep:
                    ori = plm.Rotation
                elif oriIsAlongGap:
                    if normal is None:
                        raise ValueError("Normal vector not available for a placement resting on " + el_topo +". Normal vector is required for orientation mode '"+obj.OrientMode+"'")
                    ori = Utils.makeOrientationFromLocalAxesUni("X",XAx= normal*(-1.0))
                elif oriIsTangentPlane:
                    if normal is None:
                        raise ValueError("Normal vector not available for a placement resting on " + el_topo +". Normal vector is required for orientation mode '"+obj.OrientMode+"'")
                    ori = Utils.makeOrientationFromLocalAxesUni("Z",ZAx= normal)
                elif oriIsAlongU:
                    if normal is None:
                        raise ValueError("Normal vector not available for a placement resting on " + el_topo +". Normal vector is required for orientation mode '"+obj.OrientMode+"'")
                    if tangU is None:
                        raise ValueError("TangentU vector not available for point on " + el_topo +". TangentU vector is required for orientation mode '"+obj.OrientMode+"'")
                    ori = Utils.makeOrientationFromLocalAxesUni("ZX",ZAx= normal, XAx= tangU)
                elif oriIsAlongV:
                    if normal is None:
                        raise ValueError("Normal vector not available for a placement resting on " + el_topo +". Normal vector is required for orientation mode '"+obj.OrientMode+"'")
                    if tangV is None:
                        raise ValueError("TangentV vector not available for point on " + el_topo +". TangentV vector is required for orientation mode '"+obj.OrientMode+"'")
                    ori = Utils.makeOrientationFromLocalAxesUni("ZX",ZAx= normal, XAx= tangV)
                else:
                    raise ValueError("Orientation mode not implemented: " + obj.OrientMode )
                
                output.append(App.Placement(pos,ori))
                
                if not isMultiSol:
                    break
        
        return output
Example #46
0
    def Activated(self):
        sel = FreeCADGui.Selection.getSelectionEx()[0]
        isLattice = lattice2BaseFeature.isObjectLattice(sel.Object)

        strStructure = []
        if not hasattr(sel.Object, "Shape"):
            strStructure = ["<object has no shape!>"]
        else:
            if sel.Object.Shape.isNull():
                strStructure.append("<NULL SHAPE!>")
            else:
                for (child, msg, it) in LCE.CompoundExplorer(sel.Object.Shape):
                    #child is a shape.
                    #msg is int equal to one of three constants:
                    #    CompoundExplorer.MSG_LEAF  - child is a leaf (non-compound)
                    #    CompoundExplorer.MSG_DIVEDOWN  - child is a compound that is about to be traversed
                    #    CompoundExplorer.MSG_BUBBLEUP  - child is a compound that was just finished traversing
                    #it is reference to iterator class (can be useful to extract current depth, or index stack)
                    if msg == LCE.CompoundExplorer.MSG_LEAF or msg == LCE.CompoundExplorer.MSG_DIVEDOWN:
                        try:
                            strMsg = '    ' * it.curDepth() + shapeInfoString(
                                child)
                            if msg == LCE.CompoundExplorer.MSG_DIVEDOWN:
                                strMsg += ":"
                        except Exception as err:
                            strMsg = "ERROR: " + str(err)
                        strStructure.append(strMsg)

        strSubInfo = []
        if sel.HasSubObjects:
            subNames = sel.SubElementNames
            subObjects = sel.SubObjects
            for i in range(0, len(subNames)):
                strMsg = subNames[i] + ": "
                child = subObjects[i]

                try:
                    strMsg += shapeInfoString(child)
                except Exception as err:
                    strMsg += "ERROR: " + str(err)
                strSubInfo.append(strMsg)

        allText = u''
        if sel.HasSubObjects:
            allText += u"Selected " + str(len(
                sel.SubElementNames)) + u" subelements:\n"
            allText += u'\n'.join(strSubInfo) + u'\n\n'

        allText += u'Selected document object:\n'
        allText += u'  Name = ' + sel.Object.Name + u'\n'
        allText += u'  Label = ' + sel.Object.Label + u'\n'
        allText += u'  Is placement/array = ' + repr(isLattice) + u'\n'
        allText += u'Structure: \n'
        allText += u'\n'.join(strStructure)
        mb = QtGui.QMessageBox()
        mb.setIcon(mb.Icon.Information)
        lines = allText.split(u"\n")
        if len(lines) > 30:
            lines = lines[0:30]
            lines.append(u"...")
        mb.setText(u"\n".join(lines))
        mb.setWindowTitle(translate("Lattice2_Inspect", "Selection info",
                                    None))

        btnClose = mb.addButton(QtGui.QMessageBox.StandardButton.Close)
        btnCopy = mb.addButton("Copy to clipboard",
                               QtGui.QMessageBox.ButtonRole.ActionRole)
        mb.setDefaultButton(btnClose)
        mb.exec_()

        if mb.clickedButton() is btnCopy:
            cb = QtGui.QClipboard()
            cb.setText(allText)
Example #47
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 #48
0
    def derivedExecute(self, obj):
        #validity check
        if not lattice2BaseFeature.isObjectLattice(screen(obj.Base)):
            lattice2Executer.warning(
                obj,
                "A lattice object is expected as Base, but a generic shape was provided. It will be treated as a lattice object; results may be unexpected."
            )

        output = []  #variable to receive the final list of placements
        leaves = LCE.AllLeaves(screen(obj.Base).Shape)
        input = [leaf.Placement for leaf in leaves]
        if obj.FilterType == 'bypass':
            output = input
        elif obj.FilterType == 'specific items':
            flags = [False] * len(input)
            ranges = obj.items.split(';')
            for r in ranges:
                r_v = r.split(':')
                if len(r_v) == 1:
                    i = int(r_v[0])
                    output.append(input[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])
                    output = output + input[ifrom:ito:istep]
                    for b in flags[ifrom:ito:istep]:
                        b = True
                else:
                    raise ValueError('index range cannot be parsed:' + r)
            if obj.Invert:
                output = []
                for i in range(0, len(input)):
                    if not flags[i]:
                        output.append(input[i])
        elif obj.FilterType == 'collision-pass':
            stencil = screen(obj.Stencil).Shape
            for plm in input:
                pnt = Part.Vertex(plm.Base)
                d = pnt.distToShape(stencil)
                if bool(d[0] < DistConfusion) ^ bool(obj.Invert):
                    output.append(plm)
        elif obj.FilterType == 'window-distance':
            vals = [0.0] * len(input)
            for i in range(0, len(input)):
                if obj.FilterType == 'window-distance':
                    pnt = Part.Vertex(input[i].Base)
                    vals[i] = pnt.distToShape(screen(obj.Stencil).Shape)[0]

            valFrom = obj.WindowFrom
            valTo = obj.WindowTo

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

        return output
Example #49
0
    def derivedExecute(self,obj):
        # cache stuff
        if lattice2BaseFeature.isObjectLattice(screen(obj.ShapeLink)):
            lattice2Executer.warning(obj,"ShapeLink points to a placement/array of placements. The placement/array will be reinterpreted as a generic shape; the results may be unexpected.")

        base = screen(obj.ShapeLink).Shape
        if obj.CompoundTraversal == "Use as a whole":
            baseChildren = [base]
        else:
            if base.ShapeType != 'Compound':
                base = Part.makeCompound([base])
            if obj.CompoundTraversal == "Recursive":
                baseChildren = LCE.AllLeaves(base)
            else:
                baseChildren = base.childShapes()
        
                        
        #cache mode comparisons, for speed
        posIsNone = obj.TranslateMode == '(none)'
        posIsParent = obj.TranslateMode == 'parent'
        posIsChild = obj.TranslateMode == 'child'
        posIsCenterM = obj.TranslateMode == 'child.CenterOfMass'
        posIsCenterBB = obj.TranslateMode == 'child.CenterOfBoundBox'
        posIsVertex = obj.TranslateMode == 'child.Vertex'
        
        oriIsNone = obj.OrientMode == '(none)'
        oriIsParent = obj.OrientMode == 'parent'
        oriIsChild = obj.OrientMode == 'child'
        oriIsInertial = obj.OrientMode == 'child.InertiaAxes'
        oriIsEdge = obj.OrientMode == 'child.Edge'
        oriIsFace = obj.OrientMode == 'child.FaceAxis'
        
        # initialize output containers and loop variables
        outputPlms = [] #list of placements
        
        # the essence
        for child in baseChildren:
            pos = App.Vector()
            ori = App.Rotation()
            if posIsNone:
                pass
            elif posIsParent:
                pos = base.Placement.Base
            elif posIsChild:
                pos = child.Placement.Base
            elif posIsCenterM:
                leaves = LCE.AllLeaves(child)
                totalW = 0
                weightAttrib = {"Vertex":"",
                             "Edge":"Length",
                             "Wire":"Length",
                             "Face":"Area",
                             "Shell":"Area",
                             "Solid":"Volume",
                             "CompSolid":""}[leaves[0].ShapeType]
                #Center of mass of a compound is a weghted average of centers
                # of mass of individual objects.
                for leaf in leaves:
                    w = 1.0 if not weightAttrib else (getattr(leaf, weightAttrib))
                    if leaf.ShapeType == 'Vertex':
                        leafCM = leaf.Point
                    #elif child.ShapeType == 'CompSolid':
                        #todo
                    else: 
                        leafCM = leaf.CenterOfMass
                    pos += leafCM * w
                    totalW += w
                pos = pos * (1.0/totalW)
            elif posIsCenterBB:
                import lattice2BoundBox
                bb = lattice2BoundBox.getPrecisionBoundBox(child)
                pos = bb.Center
            elif posIsVertex:
                v = child.Vertexes[obj.TranslateElementIndex - 1]
                pos = v.Point
            else:
                raise ValueError(obj.Name + ": translation mode not implemented: "+obj.TranslateMode)
            
            if oriIsNone:
                pass
            elif oriIsParent:
                ori = base.Placement.Rotation
            elif oriIsChild:
                ori = child.Placement.Rotation
            elif oriIsInertial:
                leaves = LCE.AllLeaves(child)
                if len(leaves)>1:
                    raise ValueError(obj.Name + ": calculation of principal axes of compounds is not supported yet")
                props = leaves[0].PrincipalProperties
                XAx = props['FirstAxisOfInertia']
                ZAx = props['ThirdAxisOfInertia']
                ori = Utils.makeOrientationFromLocalAxes(ZAx, XAx)
            elif oriIsEdge:
                edge = child.Edges[obj.OrientElementIndex - 1]
                XAx = edge.Curve.tangent(edge.Curve.FirstParameter)[0]
                ori1 = Utils.makeOrientationFromLocalAxes(ZAx= XAx)
                ori2 = Utils.makeOrientationFromLocalAxes(ZAx= App.Vector(1,0,0),XAx= App.Vector(0,0,1))
                ori = ori1.multiply(ori2)
            elif oriIsFace:
                face = child.Faces[obj.OrientElementIndex - 1]
                ZAx = face.Surface.Axis
            else:
                raise ValueError(obj.Name + ": orientation mode not implemented: "+obj.OrientMode)

            plm = App.Placement(pos, ori)
            outputPlms.append(plm)
        return outputPlms