예제 #1
0
 def execute(self,obj):
     rst = []
     pieces = LCE.AllLeaves(screen(obj.Base).Shape)
     cutters = LCE.AllLeaves(screen(obj.Tool).Shape)
     # prepare cutter shapes by converting them to solids
     cutters_solids = []
     for cutter in cutters:
         if cutter.ShapeType == "Face":
             cutter = Part.makeShell([cutter])
         if cutter.ShapeType == "Shell":
             cutter = Part.makeSolid(cutter)
         if cutter.ShapeType == "Solid":
             # all right, nothing to do
             cutters_solids.append(cutter)
         else:
             raise TypeError("Cannot slice with shape of type '{typ}'".format(typ= cutter.ShapeType))
     # cut everything successively with one cutter at a time
     for cutter in cutters_solids:
         pieces_old = pieces
         pieces = []
         for piece in pieces_old:
             pieces_1 = LCE.AllLeaves(piece.cut(cutter))
             pieces_2 = LCE.AllLeaves(piece.common(cutter))
             # when cutting with shells, and object doesn't intersect cutter, duplicates are sometimes produced. This is probably as occ bug. 
             # But we can filter the duplicates out. The trick is to test, if the result of a cut is the same as the original, which can be done by simply comparing masses.
             pieces_12 = pieces_1+pieces_2
             all_same = True
             for piece_test in pieces_12:
                 if float_fuzzy_equal(piece_test.Mass, piece.Mass, 1e-9):
                     # piece doesn't intersect cutter (probably).
                     # this test may fail, if the piece cut off by the cutter is very small.... So we discard cut result only if all masses are equal (no smaller objects are found)
                     pass
                 else:
                     all_same = False
                     break
             if all_same:
                 #the object doesn't intersect with cutter. Special processing, to remove duplicates if we are cutting with shells.
                 pieces += [piece]
             else:
                 pieces += pieces_1 + pieces_2
     if obj.Refine:
         pieces_old = pieces
         pieces = []
         for piece in pieces_old:
             pieces.append(piece.removeSplitter())
     obj.Shape = Part.makeCompound(pieces)
예제 #2
0
def resolveSingleSublink(lnk):
    if lnk is None:
        raise ValueError("resolveSingleSublink: link is empty")
    obj, sub = lnk
    if len(sub)>1:
        raise ValueError("Too many subelements linked: num. Maximum: 1".format(num= len(sub)))
    sh = obj.Shape if len(sub) == 0 or sub[0] == '' else obj.Shape.getElement(sub[0])
    shs = LCE.AllLeaves(sh) #if whole object is linked, it may be a compound containing the shape of interest. Explode it.
    if len(shs) != 1:
        raise ValueError("Linked is {num} shapes, but should be exactly one.".format(num= len(shs)))
    return shs[0]
예제 #3
0
def getPlacementsList(documentObject, context=None, suppressWarning=False):
    '''getPlacementsList(documentObject, context = None): extract list of placements 
    from an array object. Context is an object to report as context, when displaying 
    a warning if the documentObject happens to be a non-lattice.'''
    if not isObjectLattice(documentObject):
        if not suppressWarning:
            lattice2Executer.warning(
                context, documentObject.Name +
                " is not a placement or an array of placements. Results may be unexpected."
            )
    if documentObject.isDerivedFrom(
            'App::Placement') or documentObject.isDerivedFrom(
                'PartDesign::CoordinateSystem'):
        return [documentObject.Placement]
    leaves = LCE.AllLeaves(documentObject.Shape)
    return [leaf.Placement for leaf in leaves]
예제 #4
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
예제 #5
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
예제 #6
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
예제 #7
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
예제 #8
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
예제 #9
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
예제 #10
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
예제 #11
0
 def execute(self,obj):
     rst = [] #variable to receive the final list of shapes
     shp = screen(obj.Base).Shape
     if obj.Mode == 'bypass':
         rst = [shp]
     elif obj.Mode == 'Leaves':
         rst = LCE.AllLeaves(shp)
     elif obj.Mode == 'CompSolids':
         rst = shp.CompSolids
     elif obj.Mode == 'Solids':
         rst = shp.Solids
     elif obj.Mode == 'Shells':
         rst = shp.Shells
     elif obj.Mode == 'OpenWires':
         openWires = []
         shells = shp.Shells
         for shell in shells:
             openEdges = shell.getFreeEdges().childShapes()
             if len(openEdges) > 1: # edges need to be fused into wires
                 clusters = Part.getSortedClusters(openEdges)
                 wires = [Part.Wire(cluster) for cluster in clusters]
             else: 
                 wires = openEdges
             openWires.extend(wires)
         rst = openWires
     elif obj.Mode == 'Faces':
         rst = shp.Faces
     elif obj.Mode == 'Wires':
         rst = shp.Wires
     elif obj.Mode == 'Edges':
         rst = shp.Edges
     elif obj.Mode == 'Seam edges':
         rst = getAllSeams(shp)
     elif obj.Mode == 'Non-seam edges':
         seams = getAllSeams(shp)
         edges = shp.Edges
         rst = []
         for e in edges:
             bIsSeam = False
             for s in seams:
                 if e.isSame(s):
                     bIsSeam = True
                     break
             if not bIsSeam:
                 rst.append(e)
     elif obj.Mode == 'Vertices':
         rst = shp.Vertexes
     else:
         raise ValueError('Downgrade mode not implemented:'+obj.Mode)
     
     if len(rst) == 0:
         scale = 1.0
         if not screen(obj.Base).Shape.isNull():
             scale = screen(obj.Base).Shape.BoundBox.DiagonalLength/math.sqrt(3)
         if scale < DistConfusion * 100:
             scale = 1.0
         obj.Shape = markers.getNullShapeShape(scale)
         raise ValueError('Downgrade output is null') #Feeding empty compounds to FreeCAD seems to cause rendering issues, otherwise it would have been a good idea to output nothing.
     
     obj.Shape = Part.makeCompound(rst)
     return
예제 #12
0
    def execute(self, obj):
        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()

        N = len(baseChildren)

        orients = []
        if obj.OrientMode == "global":
            orients = [App.Placement()] * N
        elif obj.OrientMode == "local of compound":
            orients = [screen(obj.ShapeLink).Placement] * N
        elif obj.OrientMode == "local of child":
            orients = [child.Placement for child in baseChildren]
        elif obj.OrientMode == "use OrientLink":
            orients = LBF.getPlacementsList(screen(obj.OrientLink),
                                            context=obj)
            if len(orients) == N:
                pass
            elif len(orients) > N:
                Executer.warning(
                    obj,
                    "Array of placements linked in OrientLink has more placements ("
                    + str(len(orients)) +
                    ") than bounding boxes to be constructed (" +
                    str(len(baseChildren)) +
                    "). Extra placements will be dropped.")
            elif len(orients) == 1:
                orients = [orients[0]] * N
            else:
                raise ValueError(
                    obj.Name +
                    ": Array of placements linked in OrientLink has not enough placements ("
                    + str(len(orients)) +
                    ") than bounding boxes to be constructed (" +
                    str(len(baseChildren)) + ").")
        else:
            raise ValueError(obj.Name + ": OrientMode " + obj.OrientMode +
                             " not implemented =(")

        # mark placements with no rotation
        for i in range(N):
            Q = orients[i].Rotation.Q
            # Quaternions for zero rotation are either (0,0,0,1) or (0,0,0,-1). For non-zero
            # rotations, some of first three values will be nonzero, and fourth value will
            # not be equal to 1. While it's enough to compare absolute value of fourth value
            # to 1, precision is seriously lost in such comparison, so we are checking if
            # first three values are zero instead.
            if abs(Q[0]) + abs(Q[1]) + abs(Q[2]) < ParaConfusion:
                orients[i] = None

        from lattice2ShapeCopy import shallowCopy
        boxes_shapes = []
        for i in range(N):
            child = baseChildren[i]
            if orients[i] is not None:
                child = shallowCopy(child)
                child.Placement = orients[i].inverse().multiply(
                    child.Placement)

            if obj.Precision:
                bb = getPrecisionBoundBox(child)
            else:
                bb = child.BoundBox

            bb = scaledBoundBox(bb, obj.ScaleFactor)
            bb.enlarge(obj.Padding)

            bb_shape = boundBox2RealBox(bb)
            if orients[i] is not None:
                bb_shape.transformShape(orients[i].toMatrix(), True)
            boxes_shapes.append(bb_shape)

        #Fill in read-only properties
        if N == 1:
            obj.Size = App.Vector(bb.XLength, bb.YLength, bb.ZLength)

            cnt = bb.Center
            if orients[0] is not None:
                cnt = orients[0].multVec(cnt)
            obj.Center = cnt
        else:
            obj.Size = App.Vector()
            obj.Center = App.Vector()

        if obj.CompoundTraversal == "Use as a whole":
            assert (N == 1)
            obj.Shape = boxes_shapes[0]
        else:
            obj.Shape = Part.makeCompound(boxes_shapes)
예제 #13
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
예제 #14
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