示例#1
0
    def setFromSelection(self):
        """Fill the nodes according to the selected geometry."""
        import DraftGeomUtils

        sel = Gui.Selection.getSelectionEx()
        if len(sel) == 1:
            if len(sel[0].SubElementNames) == 1:
                if "Edge" in sel[0].SubElementNames[0]:
                    edge = sel[0].SubObjects[0]
                    n = int(sel[0].SubElementNames[0].lstrip("Edge")) - 1
                    self.indices.append(n)
                    if DraftGeomUtils.geomType(edge) == "Line":
                        self.node.extend(
                            [edge.Vertexes[0].Point, edge.Vertexes[1].Point])
                        v1 = None
                        v2 = None
                        for i, v in enumerate(sel[0].Object.Shape.Vertexes):
                            if v.Point == edge.Vertexes[0].Point:
                                v1 = i
                            if v.Point == edge.Vertexes[1].Point:
                                v2 = i
                        if (v1 is not None) and (v2 is not None):
                            self.link = [sel[0].Object, v1, v2]
                    elif DraftGeomUtils.geomType(edge) == "Circle":
                        self.node.extend(
                            [edge.Curve.Center, edge.Vertexes[0].Point])
                        self.edges = [edge]
                        self.arcmode = "diameter"
                        self.link = [sel[0].Object, n]
示例#2
0
    def getPathData(self, w):
        """Returns a SVG path data string from a 2D wire
        The Y Axis in the SVG Coordinate system is reversed from the FreeCAD Coordinate System.
        So we change the y coordinates accordingly
        """
        def toCommand(command, x, y):
            return '%s %s %s ' % (command, toNumberString(x), toNumberString(-y))

        edges = Part.__sortEdges__(w.Edges)

        v = edges[0].Vertexes[0].Point
        svg = toCommand('M', v.x, v.y)

        for e in edges:
            if (DraftGeomUtils.geomType(e) == "Line") or (DraftGeomUtils.geomType(e) == "BSplineCurve"):
                v = e.Vertexes[-1].Point
                svg += toCommand('L', v.x, v.y)
            elif DraftGeomUtils.geomType(e) == "Circle":
                r = e.Curve.Radius
                v = e.Vertexes[-1].Point

                svg += 'A %s %s 0 0 1 %s %s ' % (toNumberString(r),
                                                 toNumberString(r), toNumberString(v.x), toNumberString(-v.y))

        if len(edges) > 1:
            svg += 'Z '

        return svg
示例#3
0
def export(exportList, filename):
    "called when freecad exports a file"
    faces = []
    edges = []

    # getting faces and edges
    for ob in exportList:
        if ob.Shape.Faces:
            for f in ob.Shape.Faces:
                faces.append(f)
        else:
            for e in ob.Shape.Edges:
                edges.append(e)
    if not (edges or faces):
        print "oca: found no data to export"
        return

    # writing file
    oca = pythonopen(filename, 'wb')
    oca.write("#oca file generated from FreeCAD\r\n")
    oca.write("# edges\r\n")
    count = 1
    for e in edges:
        if DraftGeomUtils.geomType(e) == "Line":
            oca.write("L" + str(count) + "=")
            oca.write(writepoint(e.Vertexes[0].Point))
            oca.write(" ")
            oca.write(writepoint(e.Vertexes[-1].Point))
            oca.write("\r\n")
        elif DraftGeomUtils.geomType(e) == "Circle":
            if (len(e.Vertexes) > 1):
                oca.write("C" + str(count) + "=ARC ")
                oca.write(writepoint(e.Vertexes[0].Point))
                oca.write(" ")
                oca.write(writepoint(DraftGeomUtils.findMidpoint(e)))
                oca.write(" ")
                oca.write(writepoint(e.Vertexes[-1].Point))
            else:
                oca.write("C" + str(count) + "= ")
                oca.write(writepoint(e.Curve.Center))
                oca.write(" ")
                oca.write(str(e.Curve.Radius))
            oca.write("\r\n")
        count += 1
    oca.write("# faces\r\n")
    for f in faces:
        oca.write("A" + str(count) + "=S(POL")
        for v in f.Vertexes:
            oca.write(" ")
            oca.write(writepoint(v.Point))
        oca.write(" ")
        oca.write(writepoint(f.Vertexes[0].Point))
        oca.write(")\r\n")
        count += 1

    # closing
    oca.close()
    FreeCAD.Console.PrintMessage("successfully exported " + filename)
def export(exportList,filename):
    "called when freecad exports a file"
    faces = []
    edges = []
    
    # getting faces and edges
    for ob in exportList:
        if ob.Shape.Faces:
            for f in ob.Shape.Faces:
                faces.append(f)
        else:
            for e in ob.Shape.Edges:
                edges.append(e)
    if not (edges or faces):
        print("oca: found no data to export")
        return
    
    # writing file
    oca = pythonopen(filename,'wb')
    oca.write("#oca file generated from FreeCAD\r\n")
    oca.write("# edges\r\n")
    count = 1
    for e in edges:
        if DraftGeomUtils.geomType(e) == "Line":
            oca.write("L"+str(count)+"=")
            oca.write(writepoint(e.Vertexes[0].Point))
            oca.write(" ")
            oca.write(writepoint(e.Vertexes[-1].Point))
            oca.write("\r\n")
        elif DraftGeomUtils.geomType(e) == "Circle":
            if (len(e.Vertexes) > 1):
                oca.write("C"+str(count)+"=ARC ")
                oca.write(writepoint(e.Vertexes[0].Point))
                oca.write(" ")
                oca.write(writepoint(DraftGeomUtils.findMidpoint(e)))
                oca.write(" ")
                oca.write(writepoint(e.Vertexes[-1].Point))
            else:
                oca.write("C"+str(count)+"= ")
                oca.write(writepoint(e.Curve.Center))
                oca.write(" ")
                oca.write(str(e.Curve.Radius))
            oca.write("\r\n")
        count += 1
    oca.write("# faces\r\n")
    for f in faces:
        oca.write("A"+str(count)+"=S(POL")
        for v in f.Vertexes:
            oca.write(" ")
            oca.write(writepoint(v.Point))
        oca.write(" ")
        oca.write(writepoint(f.Vertexes[0].Point))
        oca.write(")\r\n")
        count += 1

    # closing
    oca.close()
    FreeCAD.Console.PrintMessage("successfully exported "+filename)
示例#5
0
 def execute(self, obj):
     """ Set start point and end point according to the linked geometry"""
     if obj.LinkedGeometry:
         if len(obj.LinkedGeometry) == 1:
             lobj = obj.LinkedGeometry[0][0]
             lsub = obj.LinkedGeometry[0][1]
             if len(lsub) == 1:
                 if "Edge" in lsub[0]:
                     n = int(lsub[0][4:]) - 1
                     edge = lobj.Shape.Edges[n]
                     if DraftGeomUtils.geomType(edge) == "Line":
                         obj.Start = edge.Vertexes[0].Point
                         obj.End = edge.Vertexes[-1].Point
                     elif DraftGeomUtils.geomType(edge) == "Circle":
                         c = edge.Curve.Center
                         r = edge.Curve.Radius
                         a = edge.Curve.Axis
                         ray = obj.Dimline.sub(c).projectToPlane(
                             App.Vector(0, 0, 0), a)
                         if (ray.Length == 0):
                             ray = a.cross(App.Vector(1, 0, 0))
                             if (ray.Length == 0):
                                 ray = a.cross(App.Vector(0, 1, 0))
                         ray = DraftVecUtils.scaleTo(ray, r)
                         if hasattr(obj, "Diameter"):
                             if obj.Diameter:
                                 obj.Start = c.add(ray.negative())
                                 obj.End = c.add(ray)
                             else:
                                 obj.Start = c
                                 obj.End = c.add(ray)
             elif len(lsub) == 2:
                 if ("Vertex" in lsub[0]) and ("Vertex" in lsub[1]):
                     n1 = int(lsub[0][6:]) - 1
                     n2 = int(lsub[1][6:]) - 1
                     obj.Start = lobj.Shape.Vertexes[n1].Point
                     obj.End = lobj.Shape.Vertexes[n2].Point
         elif len(obj.LinkedGeometry) == 2:
             lobj1 = obj.LinkedGeometry[0][0]
             lobj2 = obj.LinkedGeometry[1][0]
             lsub1 = obj.LinkedGeometry[0][1]
             lsub2 = obj.LinkedGeometry[1][1]
             if (len(lsub1) == 1) and (len(lsub2) == 1):
                 if ("Vertex" in lsub1[0]) and ("Vertex" in lsub2[1]):
                     n1 = int(lsub1[0][6:]) - 1
                     n2 = int(lsub2[0][6:]) - 1
                     obj.Start = lobj1.Shape.Vertexes[n1].Point
                     obj.End = lobj2.Shape.Vertexes[n2].Point
     # set the distance property
     total_len = (obj.Start.sub(obj.End)).Length
     if round(obj.Distance.Value, utils.precision()) != round(
             total_len, utils.precision()):
         obj.Distance = total_len
     if App.GuiUp:
         if obj.ViewObject:
             obj.ViewObject.update()
示例#6
0
def measure_one_obj_edge(obj, subelement, dim_point, diameter=False):
    """Measure one object with one subelement, a straight or circular edge.

    Parameters
    ----------
    obj: Part::Feature
        The object that is measured.

    subelement: str
        The subelement that is measured, for example, `'Edge1'`.

    dim_line: Base::Vector3
        A point through which the dimension goes through.
    """
    start = App.Vector()
    end = App.Vector()

    if "Edge" in subelement:
        n = int(subelement[4:]) - 1
        edge = obj.Shape.Edges[n]

        if DraftGeomUtils.geomType(edge) == "Line":
            start = edge.Vertexes[0].Point
            end = edge.Vertexes[-1].Point
        elif DraftGeomUtils.geomType(edge) == "Circle":
            center = edge.Curve.Center
            radius = edge.Curve.Radius
            axis = edge.Curve.Axis
            dim_line = dim_point.sub(center)

            # The ray is projected to the plane on which the circle lies,
            # but if the projection is not successful, try in the other planes
            ray = dim_line.projectToPlane(App.Vector(0, 0, 0), axis)

            if ray.Length == 0:
                ray = axis.cross(App.Vector(1, 0, 0))
                if ray.Length == 0:
                    ray = axis.cross(App.Vector(0, 1, 0))

            # The ray is made as large as the arc's radius
            # and optionally the diameter
            ray = DraftVecUtils.scaleTo(ray, radius)

            if diameter:
                # The start and end points lie on the arc
                start = center.add(ray.negative())
                end = center.add(ray)
            else:
                # The start is th center and the end lies on the arc
                start = center
                end = center.add(ray)

    return start, end
示例#7
0
 def onChanged(self, obj, prop):
     if prop == "Length":
         if obj.Base and obj.Length.Value:
             if obj.Base.isDerivedFrom("Part::Feature"):
                 if len(obj.Base.Shape.Edges) == 1:
                     import DraftGeomUtils
                     e = obj.Base.Shape.Edges[0]
                     if DraftGeomUtils.geomType(e) == "Line":
                         if e.Length != obj.Length.Value:
                             v = e.Vertexes[-1].Point.sub(
                                 e.Vertexes[0].Point)
                             v.normalize()
                             v.multiply(obj.Length.Value)
                             p2 = e.Vertexes[0].Point.add(v)
                             if Draft.getType(obj.Base) == "Wire":
                                 obj.Base.End = p2
                             elif Draft.getType(obj.Base) == "Sketch":
                                 obj.Base.movePoint(0, 2, p2, 0)
                             else:
                                 FreeCAD.Console.PrintError(
                                     translate(
                                         "Arch",
                                         "Error: Unable to modify the base object of this wall"
                                     ) + "\n")
     self.hideSubobjects(obj, prop)
     ArchComponent.Component.onChanged(self, obj, prop)
示例#8
0
    def onChanged(self,obj,prop):

        if prop == "Length":
            if obj.Base and obj.Length.Value and hasattr(self,"oldLength") and (self.oldLength != None) and (self.oldLength != obj.Length.Value):
                if obj.Base.isDerivedFrom("Part::Feature"):
                    if len(obj.Base.Shape.Edges) == 1:
                        import DraftGeomUtils
                        e = obj.Base.Shape.Edges[0]
                        if DraftGeomUtils.geomType(e) == "Line":
                            if e.Length != obj.Length.Value:
                                v = e.Vertexes[-1].Point.sub(e.Vertexes[0].Point)
                                v.normalize()
                                v.multiply(obj.Length.Value)
                                p2 = e.Vertexes[0].Point.add(v)
                                if Draft.getType(obj.Base) == "Wire":
                                    #print "modifying p2"
                                    obj.Base.End = p2
                                elif Draft.getType(obj.Base) == "Sketch":
                                    try:
                                        obj.Base.movePoint(0,2,p2,0)
                                    except:
                                        print("Debug: The base sketch of this wall could not be changed, because the sketch has not been edited yet in this session (this is a bug in FreeCAD). Try entering and exiting edit mode in this sketch first, and then changing the wall length should work.")
                                else:
                                    FreeCAD.Console.PrintError(translate("Arch","Error: Unable to modify the base object of this wall")+"\n")
        self.hideSubobjects(obj,prop)
        ArchComponent.Component.onChanged(self,obj,prop)
示例#9
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    for v in shape.Vertexes:
        vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
    if not shape.Faces:
        for e in shape.Edges:
            if DraftGeomUtils.geomType(e) == "Line":
                ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                elist.append(ei)
    for f in shape.Faces:
        if len(f.Wires) > 1:
            # if we have holes, we triangulate
            tris = f.tessellate(1)
            for fdata in tris[1]:
                fi = ""
                for vi in fdata:
                    vdata = Part.Vertex(tris[0][vi])
                    fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                flist.append(fi)
        else:
            fi = ""
            # OCC vertices are unsorted. We need to sort in the right order...
            edges = DraftGeomUtils.sortEdges(f.Wire.Edges)
            #print edges
            for e in edges:
                #print e.Vertexes[0].Point,e.Vertexes[1].Point
                v = e.Vertexes[0]
                fi += " " + str(findVert(v,shape.Vertexes) + offset)
            flist.append(fi)
    return vlist,elist,flist
示例#10
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    if isinstance(shape,Part.Shape):
        for e in shape.Edges:
            try:
                if not isinstance(e.Curve,Part.LineSegment):
                    if not curves:
                        curves = shape.tessellate(1)
                        FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n").decode('utf8'))
                        break
            except: # unimplemented curve type
                curves = shape.tessellate(1)
                FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n").decode('utf8'))
                break
    elif isinstance(shape,Mesh.Mesh):
        curves = shape.Topology
    if curves:
        for v in curves[0]:
            vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                    ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                for e in f.OuterWire.OrderedEdges:
                    #print(e.Vertexes[0].Point,e.Vertexes[1].Point)
                    v = e.Vertexes[0]
                    ind = findVert(v,shape.Vertexes)
                    if ind == None:
                        return None,None,None
                    fi += " " + str(ind + offset)
                flist.append(fi)
    return vlist,elist,flist
示例#11
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    if isinstance(shape,Part.Shape):
        for e in shape.Edges:
            try:
                if not isinstance(e.Curve,Part.LineSegment):
                    if not curves:
                        curves = shape.tessellate(1)
                        FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
                        break
            except: # unimplemented curve type
                curves = shape.tessellate(1)
                FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating")+"\n")
                break
    elif isinstance(shape,Mesh.Mesh):
        curves = shape.Topology
    if curves:
        for v in curves[0]:
            vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                    ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                for e in f.OuterWire.OrderedEdges:
                    #print(e.Vertexes[0].Point,e.Vertexes[1].Point)
                    v = e.Vertexes[0]
                    ind = findVert(v,shape.Vertexes)
                    if ind == None:
                        return None,None,None
                    fi += " " + str(ind + offset)
                flist.append(fi)
    return vlist,elist,flist
示例#12
0
def getIndices(shape, offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    for e in shape.Edges:
        if not isinstance(e.Curve, Part.Line):
            if not curves:
                curves = shape.tessellate(1)
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Arch",
                        "Found a shape containing curves, triangulating\n"))
    if curves:
        for v in curves[0]:
            vlist.append(" " + str(round(v.x, p)) + " " + str(round(v.y, p)) +
                         " " + str(round(v.z, p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" " + str(round(v.X, p)) + " " + str(round(v.Y, p)) +
                         " " + str(round(v.Z, p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(
                        findVert(e.Vertexes[0], shape.Vertexes) + offset)
                    ei += " " + str(
                        findVert(e.Vertexes[-1], shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(
                            findVert(vdata, shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                # OCC vertices are unsorted. We need to sort in the right order...
                edges = DraftGeomUtils.sortEdges(f.OuterWire.Edges)
                #print edges
                for e in edges:
                    #print e.Vertexes[0].Point,e.Vertexes[1].Point
                    v = e.Vertexes[0]
                    fi += " " + str(findVert(v, shape.Vertexes) + offset)
                flist.append(fi)
    return vlist, elist, flist
示例#13
0
 def snapToPerpendicular(self,shape,last):
     "returns a list of perpendicular snap locations"
     snaps = []
     if self.isEnabled("perpendicular"):
         if last:
             if isinstance(shape,Part.Edge):
                 if DraftGeomUtils.geomType(shape) == "Line":
                     np = self.getPerpendicular(shape,last)
                 elif DraftGeomUtils.geomType(shape) == "Circle":
                     dv = last.sub(shape.Curve.Center)
                     dv = DraftVecUtils.scaleTo(dv,shape.Curve.Radius)
                     np = (shape.Curve.Center).add(dv)
                 elif DraftGeomUtils.geomType(shape) == "BSplineCurve":
                     pr = shape.Curve.parameter(last)
                     np = shape.Curve.value(pr)
                 else:
                     return snaps
                 snaps.append([np,'perpendicular',np])
     return snaps
示例#14
0
 def snapToPerpendicular(self, shape, last):
     "returns a list of perpendicular snap locations"
     snaps = []
     if self.isEnabled("perpendicular"):
         if last:
             if isinstance(shape, Part.Edge):
                 if DraftGeomUtils.geomType(shape) == "Line":
                     np = self.getPerpendicular(shape, last)
                 elif DraftGeomUtils.geomType(shape) == "Circle":
                     dv = last.sub(shape.Curve.Center)
                     dv = DraftVecUtils.scaleTo(dv, shape.Curve.Radius)
                     np = (shape.Curve.Center).add(dv)
                 elif DraftGeomUtils.geomType(shape) == "BSplineCurve":
                     pr = shape.Curve.parameter(last)
                     np = shape.Curve.value(pr)
                 else:
                     return snaps
                 snaps.append([np, 'perpendicular', np])
     return snaps
示例#15
0
 def getPathData(self,w):
     "Returns a SVG path data string from a 2D wire"
     def tostr(val):
         return str(round(val,DraftVecUtils.precision()))
     edges = DraftGeomUtils.sortEdges(w.Edges)
     v = edges[0].Vertexes[0].Point
     svg = 'M '+ tostr(v.x) +' '+ tostr(v.y) + ' '
     for e in edges:
         if (DraftGeomUtils.geomType(e) == "Line") or (DraftGeomUtils.geomType(e) == "BSplineCurve"):
             v = e.Vertexes[-1].Point
             svg += 'L '+ tostr(v.x) +' '+ tostr(v.y) + ' '
         elif DraftGeomUtils.geomType(e) == "Circle":
             r = e.Curve.Radius
             v = e.Vertexes[-1].Point
             svg += 'A '+ tostr(r) + ' '+ tostr(r) +' 0 0 1 '+ tostr(v.x) +' '
             svg += tostr(v.y) + ' '
     if len(edges) > 1:
         svg += 'Z '
     return svg
示例#16
0
def getIndices(shape,offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    curves = None
    for e in shape.Edges:
        try:
            if not isinstance(e.Curve,Part.Line):
                if not curves:
                    curves = shape.tessellate(1)
                    FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n"))
                    break
        except: # unimplemented curve type
            curves = shape.tessellate(1)
            FreeCAD.Console.PrintWarning(translate("Arch","Found a shape containing curves, triangulating\n"))
            break
    if curves:
        for v in curves[0]:
            vlist.append(" "+str(round(v.x,p))+" "+str(round(v.y,p))+" "+str(round(v.z,p)))
        for f in curves[1]:
            fi = ""
            for vi in f:
                fi += " " + str(vi + offset)
            flist.append(fi)
    else:
        for v in shape.Vertexes:
            vlist.append(" "+str(round(v.X,p))+" "+str(round(v.Y,p))+" "+str(round(v.Z,p)))
        if not shape.Faces:
            for e in shape.Edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    ei = " " + str(findVert(e.Vertexes[0],shape.Vertexes) + offset)
                    ei += " " + str(findVert(e.Vertexes[-1],shape.Vertexes) + offset)
                    elist.append(ei)
        for f in shape.Faces:
            if len(f.Wires) > 1:
                # if we have holes, we triangulate
                tris = f.tessellate(1)
                for fdata in tris[1]:
                    fi = ""
                    for vi in fdata:
                        vdata = Part.Vertex(tris[0][vi])
                        fi += " " + str(findVert(vdata,shape.Vertexes) + offset)
                    flist.append(fi)
            else:
                fi = ""
                # OCC vertices are unsorted. We need to sort in the right order...
                edges = DraftGeomUtils.sortEdges(f.OuterWire.Edges)
                #print edges
                for e in edges:
                    #print e.Vertexes[0].Point,e.Vertexes[1].Point
                    v = e.Vertexes[0]
                    fi += " " + str(findVert(v,shape.Vertexes) + offset)
                flist.append(fi)
    return vlist,elist,flist
示例#17
0
def shapify(obj):
    """Transform a parametric object into a static, non-parametric shape.

    Parameters
    ----------
    obj : App::DocumentObject
        Any type of scripted object.

        This object will be removed, and a non-parametric object
        with the same topological shape (`Part::TopoShape`)
        will be created.

    Returns
    -------
    Part::Feature
        The new object that takes `obj.Shape` as its own.

        Depending on the contents of the Shape, the resulting object
        will be named `'Face'`, `'Solid'`, `'Compound'`,
        `'Shell'`, `'Wire'`, `'Line'`, `'Circle'`,
        or the name returned by `get_real_name(obj.Name)`.

        If there is a problem with `obj.Shape`, it will return `None`,
        and the original object will not be modified.
    """
    try:
        shape = obj.Shape
    except Exception:
        return None

    if len(shape.Faces) == 1:
        name = "Face"
    elif len(shape.Solids) == 1:
        name = "Solid"
    elif len(shape.Solids) > 1:
        name = "Compound"
    elif len(shape.Faces) > 1:
        name = "Shell"
    elif len(shape.Wires) == 1:
        name = "Wire"
    elif len(shape.Edges) == 1:
        import DraftGeomUtils
        if DraftGeomUtils.geomType(shape.Edges[0]) == "Line":
            name = "Line"
        else:
            name = "Circle"
    else:
        name = getRealName(obj.Name)

    App.ActiveDocument.removeObject(obj.Name)
    newobj = App.ActiveDocument.addObject("Part::Feature", name)
    newobj.Shape = shape

    return newobj
示例#18
0
 def is_linked_to_circle(self):
     _obj = self.Object
     if _obj.LinkedGeometry and len(_obj.LinkedGeometry) == 1:
         lobj = _obj.LinkedGeometry[0][0]
         lsub = _obj.LinkedGeometry[0][1]
         if len(lsub) == 1 and "Edge" in lsub[0]:
             n = int(lsub[0][4:]) - 1
             edge = lobj.Shape.Edges[n]
             if DraftGeomUtils.geomType(edge) == "Circle":
                 return True
     return False
示例#19
0
def draftify(objectslist, makeblock=False, delete=True):
    """draftify(objectslist,[makeblock],[delete])
    
    Turn each object of the given list (objectslist can also be a single 
    object) into a Draft parametric wire. 
    
    TODO: support more objects

    Parameters
    ----------
    objectslist :

    makeblock : bool
        If makeblock is True, multiple objects will be grouped in a block.
    
    delete : bool
        If delete = False, old objects are not deleted
    """
    import Part
    import DraftGeomUtils

    if not isinstance(objectslist, list):
        objectslist = [objectslist]
    newobjlist = []
    for obj in objectslist:
        if hasattr(obj, 'Shape'):
            for cluster in Part.getSortedClusters(obj.Shape.Edges):
                w = Part.Wire(cluster)
                if DraftGeomUtils.hasCurves(w):
                    if (len(w.Edges) == 1) and (DraftGeomUtils.geomType(
                            w.Edges[0]) == "Circle"):
                        nobj = makeCircle(w.Edges[0])
                    else:
                        nobj = App.ActiveDocument.addObject(
                            "Part::Feature", obj.Name)
                        nobj.Shape = w
                else:
                    nobj = makeWire(w)
                newobjlist.append(nobj)
                gui_utils.format_object(nobj, obj)
                # sketches are always in wireframe mode. In Draft we don't like that!
                if App.GuiUp:
                    nobj.ViewObject.DisplayMode = "Flat Lines"
            if delete:
                App.ActiveDocument.removeObject(obj.Name)

    if makeblock:
        return makeBlock(newobjlist)
    else:
        if len(newobjlist) == 1:
            return newobjlist[0]
        return newobjlist
示例#20
0
def addCircle(radius,
              placement=None,
              face=None,
              startangle=None,
              endangle=None,
              support=None):
    import Part, DraftGeomUtils
    if placement: typecheck([(placement, FreeCAD.Placement)], "makeCircle")
    if startangle != endangle:
        n = "Arc"
    else:
        n = "Circle"
    obj = FreeCAD.ActiveDocument.addObject("Part::Part2DObjectPython", n)
    _Circle(obj)
    if face != None:
        obj.MakeFace = face
    if isinstance(radius, Part.Edge):
        edge = radius
        if DraftGeomUtils.geomType(edge) == "Circle":
            obj.Radius = edge.Curve.Radius
            placement = FreeCAD.Placement(edge.Placement)
            delta = edge.Curve.Center.sub(placement.Base)
            placement.move(delta)
            if len(edge.Vertexes) > 1:
                ref = placement.multVec(FreeCAD.Vector(1, 0, 0))
                v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center)
                v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center)
                a1 = -math.degrees(DraftVecUtils.angle(v1, ref))
                a2 = -math.degrees(DraftVecUtils.angle(v2, ref))
                obj.FirstAngle = a1
                obj.LastAngle = a2
    else:
        obj.Radius = radius
        if (startangle != None) and (endangle != None):
            if startangle == -0: startangle = 0
            obj.FirstAngle = startangle
            obj.LastAngle = endangle
    obj.Support = support
    if placement: obj.Placement = placement
    if gui:
        _ViewProviderDraft(obj.ViewObject)
        formatObject(obj)
        select(obj)
    FreeCAD.ActiveDocument.recompute()
    return obj
示例#21
0
 def onChanged(self,obj,prop):
     if prop == "Length":
         if obj.Base and obj.Length.Value:
             if obj.Base.isDerivedFrom("Part::Feature"):
                 if len(obj.Base.Shape.Edges) == 1:
                     import DraftGeomUtils
                     e = obj.Base.Shape.Edges[0]
                     if DraftGeomUtils.geomType(e) == "Line":
                         if e.Length != obj.Length.Value:
                             v = e.Vertexes[-1].Point.sub(e.Vertexes[0].Point)
                             v.normalize()
                             v.multiply(obj.Length.Value)
                             p2 = e.Vertexes[0].Point.add(v)
                             if Draft.getType(obj.Base) == "Wire":
                                 obj.Base.End = p2
                             elif Draft.getType(obj.Base) == "Sketch":
                                 obj.Base.movePoint(0,2,p2,0)
                             else:
                                 FreeCAD.Console.PrintError(translate("Arch","Error: Unable to modify the base object of this wall")+"\n")
     self.hideSubobjects(obj,prop)
     ArchComponent.Component.onChanged(self,obj,prop)
示例#22
0
def getIndices(shape, offset):
    "returns a list with 2 lists: vertices and face indexes, offsetted with the given amount"
    vlist = []
    elist = []
    flist = []
    for v in shape.Vertexes:
        vlist.append(" " + str(round(v.X, p)) + " " + str(round(v.Y, p)) +
                     " " + str(round(v.Z, p)))
    if not shape.Faces:
        for e in shape.Edges:
            if DraftGeomUtils.geomType(e) == "Line":
                ei = " " + str(
                    findVert(e.Vertexes[0], shape.Vertexes) + offset)
                ei += " " + str(
                    findVert(e.Vertexes[-1], shape.Vertexes) + offset)
                elist.append(ei)
    for f in shape.Faces:
        if len(f.Wires) > 1:
            # if we have holes, we triangulate
            tris = f.tessellate(1)
            for fdata in tris[1]:
                fi = ""
                for vi in fdata:
                    vdata = Part.Vertex(tris[0][vi])
                    fi += " " + str(findVert(vdata, shape.Vertexes) + offset)
                flist.append(fi)
        else:
            fi = ""
            # OCC vertices are unsorted. We need to sort in the right order...
            edges = DraftGeomUtils.sortEdges(f.Wire.Edges)
            #print edges
            for e in edges:
                #print e.Vertexes[0].Point,e.Vertexes[1].Point
                v = e.Vertexes[0]
                fi += " " + str(findVert(v, shape.Vertexes) + offset)
            flist.append(fi)
    return vlist, elist, flist
示例#23
0
def getStirrupSVGData(rebar, view_plane, rebars_svg, rebars_stroke_width,
                      rebars_color_style):
    """getStirrupSVGData(StirrupRebar, ViewPlane, RebarsSVG, RebarsStrokeWidth,
    RebarsColorStyle):
    Returns dictionary containing stirrup svg data.

    rebars_color_style can be:
        - "shape color" to select color of rebar shape
        - color name or hex value of color

    Returns dictionary format:
    {
        "svg": stirrup_svg,
        "visibility": is_rebar_visible,
    }
    """
    rebars_color = getRebarColor(rebar, rebars_color_style)

    stirrup_svg = ElementTree.Element("g", attrib={"id": str(rebar.Name)})
    is_rebar_visible = False
    drawing_plane_normal = view_plane.axis
    stirrup_span_axis = getRebarsSpanAxis(rebar)
    if round(drawing_plane_normal.cross(stirrup_span_axis).Length) == 0:
        basewire = rebar.Base.Shape.Wires[0].copy()
        basewire.Placement = rebar.PlacementList[0].multiply(
            basewire.Placement)
        edges = Part.__sortEdges__(
            DraftGeomUtils.filletWire(
                basewire,
                rebar.Rounding * rebar.Diameter.Value,
            ).Edges)
        for edge in edges:
            if DraftGeomUtils.geomType(edge) == "Line":
                p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                             view_plane)
                p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                             view_plane)
                edge_svg = getLineSVG(p1, p2, rebars_stroke_width,
                                      rebars_color)
                if is_rebar_visible or not isLineInSVG(p1, p2, rebars_svg):
                    stirrup_svg.append(edge_svg)
                    is_rebar_visible = True
            elif DraftGeomUtils.geomType(edge) == "Circle":
                edge_svg = getRoundEdgeSVG(edge, view_plane,
                                           rebars_stroke_width, rebars_color)
                if is_rebar_visible or not isRoundCornerInSVG(
                        edge,
                        rebar.Rounding * rebar.Diameter.Value,
                        view_plane,
                        rebars_svg,
                ):
                    stirrup_svg.append(edge_svg)
                    is_rebar_visible = True

    else:
        if round(stirrup_span_axis.cross(view_plane.u).Length) == 0:
            stirrup_alignment = "V"
        else:
            stirrup_alignment = "H"
        basewire = DraftGeomUtils.filletWire(
            rebar.Base.Shape.Wires[0], rebar.Rounding * rebar.Diameter.Value)
        for placement in rebar.PlacementList:
            wire = basewire.copy()
            wire.Placement = placement.multiply(basewire.Placement)
            p1, p2 = getStirrupSVGPoints(wire, stirrup_alignment, view_plane)
            rebar_svg = getLineSVG(p1, p2, rebars_stroke_width, rebars_color)
            if not isLineInSVG(p1, p2, rebars_svg):
                is_rebar_visible = True
            if is_rebar_visible:
                stirrup_svg.append(rebar_svg)
    return {
        "svg": stirrup_svg,
        "visibility": is_rebar_visible,
    }
示例#24
0
 def convertBezier(edge):
     if DraftGeomUtils.geomType(edge) == "BezierCurve":
         return (edge.Curve.toBSpline(edge.FirstParameter,
                                      edge.LastParameter).toShape())
     else:
         return (edge)
示例#25
0
def make_circle(radius, placement=None, face=None, startangle=None, endangle=None, support=None):
    """make_circle(radius, [placement, face, startangle, endangle])
    or make_circle(edge,[face]):

    Creates a circle object with given parameters. 

    Parameters
    ----------
    radius : the radius of the circle.

    placement : 
        If placement is given, it is used. 
    
    face : Bool
        If face is False, the circle is shown as a wireframe, 
        otherwise as a face. 
    
    startangle : start angle of the arc (in degrees)

    endangle : end angle of the arc (in degrees)
        if startangle and endangle are equal, a circle is created, 
        if they are different an arc is created

    edge : edge.Curve must be a 'Part.Circle'
        the circle is created from the given edge

    support : 
        TODO: Describe
    """

    if not App.ActiveDocument:
        App.Console.PrintError("No active document. Aborting\n")
        return

    if placement: type_check([(placement,App.Placement)], "make_circle")

    if startangle != endangle:
        _name = "Arc"
    else:
        _name = "Circle"

    obj = App.ActiveDocument.addObject("Part::Part2DObjectPython", _name)

    Circle(obj)

    if face != None:
        obj.MakeFace = face

    if isinstance(radius,Part.Edge):
        edge = radius
        if DraftGeomUtils.geomType(edge) == "Circle":
            obj.Radius = edge.Curve.Radius
            placement = App.Placement(edge.Placement)
            delta = edge.Curve.Center.sub(placement.Base)
            placement.move(delta)
            # Rotation of the edge
            rotOk = App.Rotation(edge.Curve.XAxis, edge.Curve.YAxis, edge.Curve.Axis, "ZXY")
            placement.Rotation = rotOk
            if len(edge.Vertexes) > 1:
                v0 = edge.Curve.XAxis
                v1 = (edge.Vertexes[0].Point).sub(edge.Curve.Center)
                v2 = (edge.Vertexes[-1].Point).sub(edge.Curve.Center)
                # Angle between edge.Curve.XAxis and the vector from center to start of arc
                a0 = math.degrees(App.Vector.getAngle(v0, v1))
                # Angle between edge.Curve.XAxis and the vector from center to end of arc
                a1 = math.degrees(App.Vector.getAngle(v0, v2))
                obj.FirstAngle = a0
                obj.LastAngle = a1
    else:
        obj.Radius = radius
        if (startangle != None) and (endangle != None):
            if startangle == -0: startangle = 0
            obj.FirstAngle = startangle
            obj.LastAngle = endangle

    obj.Support = support

    if placement: 
        obj.Placement = placement

    if App.GuiUp:
        ViewProviderDraft(obj.ViewObject)
        format_object(obj)
        select(obj)

    return obj
def getRebarShapeSVG(
    rebar,
    view_direction: Union[FreeCAD.Vector,
                          WorkingPlane.Plane] = FreeCAD.Vector(0, 0, 0),
    include_mark: bool = True,
    stirrup_extended_edge_offset: float = 2,
    rebar_stroke_width: float = 0.35,
    rebar_color_style: str = "shape color",
    include_dimensions: bool = True,
    rebar_dimension_units: str = "mm",
    rebar_length_dimension_precision: int = 0,
    include_units_in_dimension_label: bool = False,
    bent_angle_dimension_exclude_list: Union[Tuple[float, ...],
                                             List[float]] = (
                                                 45,
                                                 90,
                                                 180,
                                             ),
    dimension_font_family: str = "DejaVu Sans",
    dimension_font_size: float = 2,
    helical_rebar_dimension_label_format: str = "%L,r=%R,pitch=%P",
    scale: float = 1,
    max_height: float = 0,
    max_width: float = 0,
    side_padding: float = 1,
    horizontal_shape: bool = False,
) -> ElementTree.Element:
    """Generate and return rebar shape svg.

    Parameters
    ----------
    rebar: <ArchRebar._Rebar> or <rebar2.BaseRebar>
        Rebar to generate its shape svg.
    view_direction: FreeCAD.Vector or WorkingPlane.Plane, optional
        The view point direction for rebar shape.
        Default is FreeCAD.Vector(0, 0, 0) to automatically choose
        view_direction.
    include_mark: bool, optional
        If True, then rebar.Mark will be included in rebar shape svg.
        Default is True.
    stirrup_extended_edge_offset: float, optional
        The offset of extended end edges of stirrup, so that end edges of
        stirrup with 90 degree bent angle do not overlap with stirrup edges.
        Default is 2.
    rebar_stroke_width: float, optional
        The stroke-width of rebar in svg.
        Default is 0.35
    rebar_color_style: {"shape color", "color_name", "hex_value_of_color"}
        The color style of rebar.
        "shape color" means select color of rebar shape.
    include_dimensions: bool, optional
        If True, then each rebar edge dimensions and bent angle dimensions will
        be included in rebar shape svg.
    rebar_dimension_units: str, optional
        The units to be used for rebar length dimensions.
        Default is "mm".
    rebar_length_dimension_precision: int, optional
        The number of decimals that should be shown for rebar length as
        dimension label. Set it to None to use user preferred unit precision
        from FreeCAD unit preferences.
        Default is 0
    include_units_in_dimension_label: bool, optional
        If it is True, then rebar length units will be shown in dimension label.
        Default is False.
    bent_angle_dimension_exclude_list: list or tuple of float, optional
        The list of bent angles to not include their dimensions.
        Default is (45, 90, 180).
    dimension_font_family: str, optional
        The font-family of dimension text.
        Default is "DejaVu Sans".
    dimension_font_size: float, optional
        The font-size of dimension text.
        Default is 2
    helical_rebar_dimension_label_format: str, optional
        The format of helical rebar dimension label.
            %L -> Length of helical rebar
            %R -> Helix radius of helical rebar
            %P -> Helix pitch of helical rebar
        Default is "%L,r=%R,pitch=%P".
    scale: float, optional
        The scale value to scale rebar svg. The scale parameter helps to
        scale down rebar_stroke_width and dimension_font_size to make them
        resolution independent.
        If max_height or max_width is set to non-zero value, then scale
        parameter will be ignored.
        Default is 1
    max_height: float, optional
        The maximum height of rebar shape svg.
        Default is 0 to set rebar shape svg height based on scale parameter.
    max_width: float, optional
        The maximum width of rebar shape svg.
        Default is 0 to set rebar shape svg width based on scale parameter.
    side_padding: float, optional
        The padding on each side of rebar shape.
        Default is 1.
    horizontal_shape: bool, optional
        If True, then rebar shape will be made horizontal by rotating max
        length edge of rebar shape.
        Default is False.

    Returns
    -------
    ElementTree.Element
        The generated rebar shape svg.
    """
    if isinstance(view_direction, FreeCAD.Vector):
        if DraftVecUtils.isNull(view_direction):
            if (hasattr(rebar, "RebarShape")
                    and rebar.RebarShape == "HelicalRebar"):
                view_direction = rebar.Base.Placement.Rotation.multVec(
                    FreeCAD.Vector(0, -1, 0))
                if hasattr(rebar, "Direction") and not DraftVecUtils.isNull(
                        rebar.Direction):
                    view_direction = FreeCAD.Vector(rebar.Direction)
                    view_direction.normalize()
            else:
                view_direction = getRebarsSpanAxis(rebar)
        view_plane = getSVGPlaneFromAxis(view_direction)
    elif isinstance(view_direction, WorkingPlane.Plane):
        view_plane = view_direction
    else:
        FreeCAD.Console.PrintError(
            "Invalid view_direction type. Supported view_direction types: "
            "FreeCAD.Vector, WorkingPlane.Plane\n")
        return ElementTree.Element("g")

    if rebar_length_dimension_precision is None:
        # Get user preferred unit precision
        precision: int = FreeCAD.ParamGet(
            "User parameter:BaseApp/Preferences/Units").GetInt("Decimals")
    else:
        precision = abs(int(rebar_length_dimension_precision))

    rebar_color = getRebarColor(rebar, rebar_color_style)

    # Create required svg elements
    svg = getSVGRootElement()
    rebar_shape_svg = ElementTree.Element("g", attrib={"id": str(rebar.Name)})
    svg.append(rebar_shape_svg)
    rebar_edges_svg = ElementTree.Element("g")
    edge_dimension_svg = ElementTree.Element("g")
    rebar_shape_svg.extend([rebar_edges_svg, edge_dimension_svg])

    # Get basewire and fillet_basewire (basewire with round edges)
    basewire = rebar.Base.Shape.Wires[0].copy()
    fillet_radius = rebar.Rounding * rebar.Diameter.Value
    if fillet_radius:
        fillet_basewire = DraftGeomUtils.filletWire(basewire, fillet_radius)
    else:
        fillet_basewire = basewire

    (
        rebar_shape_min_x,
        rebar_shape_min_y,
        rebar_shape_max_x,
        rebar_shape_max_y,
    ) = getVertexesMinMaxXY(fillet_basewire.Vertexes, view_plane)

    # If rebar shape should be horizontal and its width is less than its
    # height, then we should rotate basewire to make rebar shape horizontal
    rebar_shape_rotation_angle = 0
    if horizontal_shape:
        line_type_edges = [
            edge for edge in basewire.Edges
            if DraftGeomUtils.geomType(edge) == "Line"
        ]
        if line_type_edges:
            max_length_edge = max(line_type_edges, key=lambda x: x.Length)
            rebar_shape_rotation_angle = math.degrees(
                DraftVecUtils.angle(
                    max_length_edge.lastVertex().Point.sub(
                        max_length_edge.firstVertex().Point),
                    view_plane.u,
                    view_plane.axis,
                ))
        elif (rebar_shape_max_x - rebar_shape_min_x) < (rebar_shape_max_y -
                                                        rebar_shape_min_y):
            rebar_shape_rotation_angle = -90
        basewire.rotate(basewire.CenterOfMass, view_plane.axis,
                        rebar_shape_rotation_angle)

        fillet_radius = rebar.Rounding * rebar.Diameter.Value
        if fillet_radius:
            fillet_basewire = DraftGeomUtils.filletWire(
                basewire, fillet_radius)
        else:
            fillet_basewire = basewire

        (
            rebar_shape_min_x,
            rebar_shape_min_y,
            rebar_shape_max_x,
            rebar_shape_max_y,
        ) = getVertexesMinMaxXY(fillet_basewire.Vertexes, view_plane)

    # Check if stirrup will be having extended edges separated apart
    if (hasattr(rebar, "RebarShape") and rebar.RebarShape == "Stirrup"
            and hasattr(rebar, "BentAngle") and rebar.BentAngle == 90):
        apply_stirrup_extended_edge_offset = True
    else:
        apply_stirrup_extended_edge_offset = False

    # Apply max_height and max_width of rebar shape svg And calculate scaling
    # factor
    rebar_shape_height = (rebar_shape_max_y - rebar_shape_min_y) or 1
    rebar_shape_width = (rebar_shape_max_x - rebar_shape_min_x) or 1
    h_scaling_factor = v_scaling_factor = scale
    if max_height:
        v_scaling_factor = (
            max_height - dimension_font_size *
            ((2 if include_mark else 0) +
             (2 if include_dimensions else 0)) - 2 * side_padding -
            (stirrup_extended_edge_offset
             if apply_stirrup_extended_edge_offset and (round(
                 getProjectionToSVGPlane(
                     Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                     view_plane,
                 ).y) in (round(rebar_shape_min_y), round(rebar_shape_max_y)))
             else 0)) / rebar_shape_height
    if max_width:
        h_scaling_factor = (
            max_width - dimension_font_size *
            (2 if include_dimensions else 0) - 2 * side_padding -
            (stirrup_extended_edge_offset
             if apply_stirrup_extended_edge_offset and (round(
                 getProjectionToSVGPlane(
                     Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                     view_plane,
                 ).x) in (round(rebar_shape_min_x), round(rebar_shape_max_x)))
             else 0)) / rebar_shape_width
    scale = min(h_scaling_factor, v_scaling_factor)
    svg_height = (
        rebar_shape_height * scale + dimension_font_size *
        ((2 if include_mark else 0) +
         (2 if include_dimensions else 0)) + 2 * side_padding +
        (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and
         (round(
             getProjectionToSVGPlane(
                 Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                 view_plane,
             ).y) in (round(rebar_shape_min_y), round(rebar_shape_max_y))) else
         0))
    svg_width = (
        rebar_shape_width * scale + dimension_font_size *
        (2 if include_dimensions else 0) + 2 * side_padding +
        (stirrup_extended_edge_offset if apply_stirrup_extended_edge_offset and
         (round(
             getProjectionToSVGPlane(
                 Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                 view_plane,
             ).x) in (round(rebar_shape_min_x), round(rebar_shape_max_x))) else
         0))

    # Move (min_x, min_y) point in svg plane to (0, 0) so that entire basewire
    # should be visible in svg view box and apply required scaling
    translate_x = round(
        -(rebar_shape_min_x -
          (dimension_font_size if include_dimensions else 0) / scale -
          side_padding / scale -
          (stirrup_extended_edge_offset /
           scale if apply_stirrup_extended_edge_offset and (round(
               getProjectionToSVGPlane(
                   Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                   view_plane,
               ).x) == round(rebar_shape_min_x)) else 0)))
    translate_y = round(
        -(rebar_shape_min_y -
          ((2 if include_mark else 0) +
           (1 if include_dimensions else 0)) * dimension_font_size / scale -
          side_padding / scale -
          (stirrup_extended_edge_offset /
           scale if apply_stirrup_extended_edge_offset and (round(
               getProjectionToSVGPlane(
                   Part.__sortEdges__(basewire.Edges)[0].firstVertex().Point,
                   view_plane,
               ).y) == round(rebar_shape_min_y)) else 0)))
    rebar_shape_svg.set(
        "transform",
        "scale({}) translate({} {})".format(scale, translate_x, translate_y),
    )

    svg.set("width", "{}mm".format(round(svg_width)))
    svg.set("height", "{}mm".format(round(svg_height)))
    svg.set("viewBox", "0 0 {} {}".format(round(svg_width), round(svg_height)))

    # Scale down rebar_stroke_width and dimension_font_size to make them
    # resolution independent
    rebar_stroke_width /= scale
    dimension_font_size /= scale

    # Include rebar.Mark in rebar shape svg
    if include_mark:
        if hasattr(rebar, "Mark"):
            mark = rebar.Mark
        elif hasattr(rebar, "MarkNumber"):
            mark = rebar.MarkNumber
        else:
            mark = ""
        rebar_shape_svg.append(
            getSVGTextElement(
                mark,
                rebar_shape_min_x,
                rebar_shape_min_y -
                (0.5 + bool(include_dimensions)) * dimension_font_size,
                dimension_font_family,
                1.5 * dimension_font_size,
            ))

    if hasattr(rebar, "RebarShape") and rebar.RebarShape == "HelicalRebar":
        helical_rebar_shape_svg = Draft.getSVG(
            rebar,
            direction=view_plane,
            linewidth=rebar_stroke_width,
            fillstyle="none",
            color=rebar_color,
        )
        if helical_rebar_shape_svg:
            helical_rebar_shape_svg_element = ElementTree.fromstring(
                "<g>{}</g>".format(helical_rebar_shape_svg))
            rebar_edges_svg.append(helical_rebar_shape_svg_element)
            helical_rebar_center = getProjectionToSVGPlane(
                rebar.Base.Shape.CenterOfMass, view_plane)
            helical_rebar_shape_svg_element.set(
                "transform",
                "rotate({} {} {})".format(
                    rebar_shape_rotation_angle,
                    helical_rebar_center.x,
                    helical_rebar_center.y,
                ),
            )

        if include_dimensions:
            # Create rebar dimension svg
            top_mid_point = FreeCAD.Vector(
                (rebar_shape_min_x + rebar_shape_max_x) / 2, rebar_shape_min_y)
            helical_rebar_length = str(
                round(
                    FreeCAD.Units.Quantity("{}mm".format(
                        rebar.Base.Shape.Wires[0].Length)).getValueAs(
                            rebar_dimension_units).Value,
                    precision,
                ))
            helix_radius = str(
                round(
                    rebar.Base.Radius.getValueAs(rebar_dimension_units).Value,
                    precision,
                ))
            helix_pitch = str(
                round(
                    rebar.Base.Pitch.getValueAs(rebar_dimension_units).Value,
                    precision,
                ))
            if "." in helical_rebar_length:
                helical_rebar_length = helical_rebar_length.rstrip("0").rstrip(
                    ".")
            if "." in helix_radius:
                helix_radius = helix_radius.rstrip("0").rstrip(".")
            if "." in helix_pitch:
                helix_pitch = helix_pitch.rstrip("0").rstrip(".")
            if include_units_in_dimension_label:
                helical_rebar_length += rebar_dimension_units
                helix_radius += rebar_dimension_units
                helix_pitch += rebar_dimension_units
            edge_dimension_svg.append(
                getSVGTextElement(
                    helical_rebar_dimension_label_format.replace(
                        "%L", helical_rebar_length).replace(
                            "%R", helix_radius).replace("%P", helix_pitch),
                    top_mid_point.x,
                    top_mid_point.y - rebar_stroke_width * 2,
                    dimension_font_family,
                    dimension_font_size,
                    "middle",
                ))
    else:
        if stirrup_extended_edge_offset and apply_stirrup_extended_edge_offset:
            basewire = getBasewireOfStirrupWithExtendedEdges(
                rebar, view_plane, stirrup_extended_edge_offset / scale)
            basewire.rotate(
                basewire.CenterOfMass,
                view_plane.axis,
                rebar_shape_rotation_angle,
            )

            fillet_radius = rebar.Rounding * rebar.Diameter.Value
            if fillet_radius:
                fillet_basewire = DraftGeomUtils.filletWire(
                    basewire, fillet_radius)
            else:
                fillet_basewire = basewire

        edges = Part.__sortEdges__(fillet_basewire.Edges)
        straight_edges = Part.__sortEdges__(rebar.Base.Shape.Wires[0].Edges)
        for edge in list(straight_edges):
            if DraftGeomUtils.geomType(edge) != "Line":
                straight_edges.remove(edge)

        current_straight_edge_index = 0
        for edge_index, edge in enumerate(edges):
            if DraftGeomUtils.geomType(edge) == "Line":
                p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                             view_plane)
                p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                             view_plane)
                # Create Edge svg
                if round(p1.x) == round(p2.x) and round(p1.y) == round(p2.y):
                    edge_svg = getPointSVG(p1,
                                           radius=2 * rebar_stroke_width,
                                           fill=rebar_color)
                else:
                    edge_svg = getLineSVG(p1, p2, rebar_stroke_width,
                                          rebar_color)

                if include_dimensions:
                    # Create edge dimension svg
                    mid_point = FreeCAD.Vector((p1.x + p2.x) / 2,
                                               (p1.y + p2.y) / 2)
                    dimension_rotation = (math.degrees(
                        math.atan((p2.y - p1.y) / (p2.x - p1.x))) if
                                          round(p2.x) != round(p1.x) else -90)
                    edge_length = str(
                        round(
                            FreeCAD.Units.Quantity("{}mm".format(
                                straight_edges[current_straight_edge_index].
                                Length)).getValueAs(
                                    rebar_dimension_units).Value,
                            precision,
                        ))
                    if "." in edge_length:
                        edge_length = edge_length.rstrip("0").rstrip(".")
                    if include_units_in_dimension_label:
                        edge_length += rebar_dimension_units
                    edge_dimension_svg.append(
                        getSVGTextElement(
                            edge_length,
                            mid_point.x,
                            mid_point.y - rebar_stroke_width * 2,
                            dimension_font_family,
                            dimension_font_size,
                            "middle",
                        ))
                    edge_dimension_svg[-1].set(
                        "transform",
                        "rotate({} {} {})".format(
                            dimension_rotation,
                            round(mid_point.x),
                            round(mid_point.y),
                        ),
                    )
                    current_straight_edge_index += 1
                    if (0 <= edge_index - 1 and DraftGeomUtils.geomType(
                            edges[edge_index - 1]) == "Line"):
                        radius = max(fillet_radius, dimension_font_size * 0.8)
                        bent_angle_svg = getEdgesAngleSVG(
                            edges[edge_index - 1],
                            edge,
                            radius,
                            view_plane,
                            dimension_font_family,
                            dimension_font_size * 0.8,
                            bent_angle_dimension_exclude_list,
                            0.2 / scale,
                        )
                        edge_dimension_svg.append(bent_angle_svg)
            elif DraftGeomUtils.geomType(edge) == "Circle":
                p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                             view_plane)
                p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                             view_plane)
                if round(p1.x) == round(p2.x) or round(p1.y) == round(p2.y):
                    edge_svg = getLineSVG(p1, p2, rebar_stroke_width,
                                          rebar_color)
                else:
                    edge_svg = getRoundEdgeSVG(edge, view_plane,
                                               rebar_stroke_width, rebar_color)
                    if include_dimensions:
                        # Create bent angle svg
                        if 0 <= edge_index - 1 and edge_index + 1 < len(edges):
                            prev_edge = edges[edge_index - 1]
                            next_edge = edges[edge_index + 1]
                            if (DraftGeomUtils.geomType(prev_edge) ==
                                    DraftGeomUtils.geomType(next_edge) ==
                                    "Line"):
                                radius = max(fillet_radius,
                                             dimension_font_size * 0.8)
                                bent_angle_svg = getEdgesAngleSVG(
                                    prev_edge,
                                    next_edge,
                                    radius,
                                    view_plane,
                                    dimension_font_family,
                                    dimension_font_size * 0.8,
                                    bent_angle_dimension_exclude_list,
                                    0.2 / scale,
                                )
                                edge_dimension_svg.append(bent_angle_svg)
            else:
                edge_svg = ElementTree.Element("g")
            rebar_edges_svg.append(edge_svg)

    return svg
示例#27
0
def export(exportList, filename):
    """Export the OCA file with a given list of objects.

    The objects must be edges or faces, in order to be processed
    and exported.

    Parameters
    ----------
    exportList : list
        List of document objects to export.
    filename : str
        Path to the new file.

    Returns
    -------
    None
        If `exportList` doesn't have shapes to export.
    """
    faces = []
    edges = []

    # getting faces and edges
    for ob in exportList:
        if ob.Shape.Faces:
            for f in ob.Shape.Faces:
                faces.append(f)
        else:
            for e in ob.Shape.Edges:
                edges.append(e)
    if not (edges or faces):
        FCC.PrintMessage(
            translate("importOCA", "OCA: found no data to export") + "\n")
        return

    # writing file
    oca = pythonopen(filename, 'w')
    oca.write("#oca file generated from FreeCAD\r\n")
    oca.write("# edges\r\n")
    count = 1
    for e in edges:
        if DraftGeomUtils.geomType(e) == "Line":
            oca.write("L" + str(count) + "=")
            oca.write(writepoint(e.Vertexes[0].Point))
            oca.write(" ")
            oca.write(writepoint(e.Vertexes[-1].Point))
            oca.write("\r\n")
        elif DraftGeomUtils.geomType(e) == "Circle":
            if len(e.Vertexes) > 1:
                oca.write("C" + str(count) + "=ARC ")
                oca.write(writepoint(e.Vertexes[0].Point))
                oca.write(" ")
                oca.write(writepoint(DraftGeomUtils.findMidpoint(e)))
                oca.write(" ")
                oca.write(writepoint(e.Vertexes[-1].Point))
            else:
                oca.write("C" + str(count) + "= ")
                oca.write(writepoint(e.Curve.Center))
                oca.write(" ")
                oca.write(str(e.Curve.Radius))
            oca.write("\r\n")
        count += 1
    oca.write("# faces\r\n")
    for f in faces:
        oca.write("A" + str(count) + "=S(POL")
        for v in f.Vertexes:
            oca.write(" ")
            oca.write(writepoint(v.Point))
        oca.write(" ")
        oca.write(writepoint(f.Vertexes[0].Point))
        oca.write(")\r\n")
        count += 1

    # closing
    oca.close()
    FCC.PrintMessage(
        translate("importOCA", "successfully exported") + " " + filename +
        "\n")
示例#28
0
    def snap(self,screenpos,lastpoint=None,active=True,constrain=False,noTracker=False):
        """snap(screenpos,lastpoint=None,active=True,constrain=False,noTracker=False): returns a snapped
        point from the given (x,y) screenpos (the position of the mouse cursor), active is to
        activate active point snapping or not (passive), lastpoint is an optional
        other point used to draw an imaginary segment and get additional snap locations. Constrain can
        be True to constrain the point against the closest working plane axis.
        Screenpos can be a list, a tuple or a coin.SbVec2s object. If noTracker is True,
        the tracking line is not displayed."""

        global Part, DraftGeomUtils
        import Part, DraftGeomUtils

        if not hasattr(self,"toolbar"):
            self.makeSnapToolBar()
        mw = getMainWindow()
        bt = mw.findChild(QtGui.QToolBar,"Draft Snap")
        if not bt:
            mw.addToolBar(self.toolbar)
        else:
            if Draft.getParam("showSnapBar"):
                bt.show()

        def cstr(point):
            "constrains if needed"
            if constrain or self.mask:
                fpt = self.constrain(point,lastpoint)
            else:
                self.unconstrain()
                fpt = point
            if self.radiusTracker:
                self.radiusTracker.update(fpt)
            return fpt

        snaps = []
        self.snapInfo = None
        
        # type conversion if needed
        if isinstance(screenpos,list):
            screenpos = tuple(screenpos)
        elif isinstance(screenpos,coin.SbVec2s):
            screenpos = tuple(screenpos.getValue())
        elif  not isinstance(screenpos,tuple):
            print "snap needs valid screen position (list, tuple or sbvec2s)"
            return None

        # setup trackers if needed
        self.setTrackers()

        # getting current snap Radius
        self.radius =  self.getScreenDist(Draft.getParam("snapRange"),screenpos)
        if self.radiusTracker:
            self.radiusTracker.update(self.radius)
            self.radiusTracker.off()

        # activate snap
        oldActive = False
        if Draft.getParam("alwaysSnap"):
            oldActive = active
            active = True
        if not self.active:
            active = False

        self.setCursor('passive')
        if self.tracker:
            self.tracker.off()
        if self.extLine:
            self.extLine.off()
        if self.trackLine:
            self.trackLine.off()

        point = self.getApparentPoint(screenpos[0],screenpos[1])

        # setup a track line if we got a last point
        if lastpoint:
            if not self.trackLine:
                self.trackLine = DraftTrackers.lineTracker()
            self.trackLine.p1(lastpoint)
            
        # check if we snapped to something
        self.snapInfo = Draft.get3DView().getObjectInfo((screenpos[0],screenpos[1]))

        # checking if parallel to one of the edges of the last objects or to a polar direction
        if active:
            eline = None
            point,eline = self.snapToPolar(point,lastpoint)
            point,eline = self.snapToExtensions(point,lastpoint,constrain,eline)
            
        if not self.snapInfo:
            
            # nothing has been snapped, check fro grid snap
            if active:
                point = self.snapToGrid(point)
            fp = cstr(point)
            if self.trackLine and lastpoint and (not noTracker):
                self.trackLine.p2(fp)
                self.trackLine.on()
            return fp

        else:

            # we have an object to snap to

            obj = FreeCAD.ActiveDocument.getObject(self.snapInfo['Object'])
            if not obj:
                return cstr(point)

            self.lastSnappedObject = obj
                
            if hasattr(obj.ViewObject,"Selectable"):
                if not obj.ViewObject.Selectable:
                    return cstr(point)
                
            if not active:
                
                # passive snapping
                snaps = [self.snapToVertex(self.snapInfo)]

            else:

                # first stick to the snapped object
                s = self.snapToVertex(self.snapInfo)
                if s:
                    point = s[0]
                
                # active snapping
                comp = self.snapInfo['Component']

                if (Draft.getType(obj) == "Wall") and not oldActive:
                    edges = []
                    for o in [obj]+obj.Additions:
                        if Draft.getType(o) == "Wall":
                            if o.Base:
                                edges.extend(o.Base.Shape.Edges)
                    for edge in edges:
                        snaps.extend(self.snapToEndpoints(edge))
                        snaps.extend(self.snapToMidpoint(edge))
                        snaps.extend(self.snapToPerpendicular(edge,lastpoint))
                        snaps.extend(self.snapToIntersection(edge))
                        snaps.extend(self.snapToElines(edge,eline))
                            
                elif obj.isDerivedFrom("Part::Feature"):
                    if (not self.maxEdges) or (len(obj.Edges) <= self.maxEdges):
                        if "Edge" in comp:
                            # we are snapping to an edge
                            en = int(comp[4:])-1
                            if len(obj.Shape.Edges) > en:
                                edge = obj.Shape.Edges[en]
                                snaps.extend(self.snapToEndpoints(edge))
                                snaps.extend(self.snapToMidpoint(edge))
                                snaps.extend(self.snapToPerpendicular(edge,lastpoint))
                                #snaps.extend(self.snapToOrtho(edge,lastpoint,constrain)) # now part of snapToPolar
                                snaps.extend(self.snapToIntersection(edge))
                                snaps.extend(self.snapToElines(edge,eline))

                                if DraftGeomUtils.geomType(edge) == "Circle":
                                    # the edge is an arc, we have extra options
                                    snaps.extend(self.snapToAngles(edge))
                                    snaps.extend(self.snapToCenter(edge))

                        elif "Vertex" in comp:
                            # directly snapped to a vertex
                            snaps.append(self.snapToVertex(self.snapInfo,active=True))
                        elif comp == '':
                            # workaround for the new view provider
                            snaps.append(self.snapToVertex(self.snapInfo,active=True))
                        else:
                            # all other cases (face, etc...) default to passive snap
                            snapArray = [self.snapToVertex(self.snapInfo)]
                            
                elif Draft.getType(obj) == "Dimension":
                    # for dimensions we snap to their 3 points
                    for pt in [obj.Start,obj.End,obj.Dimline]:
                        snaps.append([pt,'endpoint',pt])
                        
                elif Draft.getType(obj) == "Mesh":
                    # for meshes we only snap to vertices
                    snaps.extend(self.snapToEndpoints(obj.Mesh))
                elif Draft.getType(obj) == "Points":
                    # for points we only snap to points
                    snaps.extend(self.snapToEndpoints(obj.Points))

            # updating last objects list
            if not self.lastObj[1]:
                self.lastObj[1] = obj.Name
            elif self.lastObj[1] != obj.Name:
                self.lastObj[0] = self.lastObj[1]
                self.lastObj[1] = obj.Name

            if not snaps:
                return cstr(point)

            # calculating the nearest snap point
            shortest = 1000000000000000000
            origin = Vector(self.snapInfo['x'],self.snapInfo['y'],self.snapInfo['z'])
            winner = [Vector(0,0,0),None,Vector(0,0,0)]
            for snap in snaps:
                if (not snap) or (snap[0] == None):
                    print "debug: Snapper: invalid snap point: ",snaps
                else:
                    delta = snap[0].sub(origin)
                    if delta.Length < shortest:
                        shortest = delta.Length
                        winner = snap

            # see if we are out of the max radius, if any
            if self.radius:
                dv = point.sub(winner[2])
                if (dv.Length > self.radius):
                    if (not oldActive) and self.isEnabled("passive"):
                        winner = self.snapToVertex(self.snapInfo)

            # setting the cursors
            if self.tracker:
                self.tracker.setCoords(winner[2])
                self.tracker.setMarker(self.mk[winner[1]])
                self.tracker.on()
            # setting the trackline
            fp = cstr(winner[2])
            if self.trackLine and lastpoint:
                self.trackLine.p2(fp)
                self.trackLine.on()
            # set the cursor
            self.setCursor(winner[1])

            # return the final point
            return fp
示例#29
0
    def execute(self,obj):
        if obj.Base:
            tool = PathUtils.getLastTool(obj)

            if tool:
                radius = tool.Diameter/2
                if radius < 0:# safe guard
                    radius -= radius
            else:
                # temporary value, to be taken from the properties later on
                radius = 1

            import Part, DraftGeomUtils
            if "Face" in obj.Base[1][0]:
                shape = getattr(obj.Base[0].Shape,obj.Base[1][0])
            else:
                edges = [getattr(obj.Base[0].Shape,sub) for sub in obj.Base[1]]
                shape = Part.Wire(edges)
                print len(edges)

            # absolute coords, millimeters, cancel offsets
            output = "G90\nG21\nG40\n"
            # save tool
            if obj.ToolNumber > 0 and tool.ToolNumber != obj.ToolNumber:
                output += "M06 T" + str(tool.ToolNumber) + "\n"
            
            # build offsets
            offsets = []
            nextradius = radius
            result = DraftGeomUtils.pocket2d(shape,nextradius)
            while result:
                #print "Adding " + str(len(result)) + " wires"
                offsets.extend(result)
                nextradius += radius
                result = DraftGeomUtils.pocket2d(shape,nextradius)
            
            # first move will be rapid, subsequent will be at feed rate
            first = True
            startPoint = None
            fastZPos = max(obj.StartDepth + 2, obj.RetractHeight)
            
            # revert the list so we start with the outer wires
            if obj.StartAt != 'Edge':
                offsets.reverse()

#            print "startDepth: " + str(obj.StartDepth)
#            print "finalDepth: " + str(obj.FinalDepth)
#            print "stepDown: " + str(obj.StepDown)
#            print "finishDepth" + str(obj.FinishDepth)
#            print "offsets:", len(offsets)

            def prnt(vlu): return str("%.4f" % round(vlu, 4))
            
            #Fraction of tool radius our plunge helix is to be
            #FIXME: This should be configurable
            plungeR = 0.75
            
            #(minimum) Fraction of tool DIAMETER to go back and forth while ramp-plunging
            #FIXME: This should be configurable
            #FIXME: The ramp plunging should maybe even be limited to this distance; I don't know what's best
            rampD = 0.75
            
            
            #Total offset from the desired pocket edge is tool radius plus the plunge helix radius
            #Any point on these curves could be the center of a plunge
            helixBounds = DraftGeomUtils.pocket2d(shape, tool.Diameter / 2. * (1 + plungeR))
            
            
            #Try to find a location to nicely plunge, starting with a helix, then ramp
            #Can't do it without knowledge of a tool
            plungePos = None
            rampEdge = None
            if not tool:
                    raise Error("Ramp plunge location-finding requires a tool")
                    return
            else:
                #Since we're going to start machining either the inner-most
                #edge or the outer (depending on StartAt setting), try to
                #plunge near that location
                
                if helixBounds:
                    #Edge is easy- pick a point on helixBounds and go with it
                    if obj.StartAt == 'Edge':
                        plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                    #Center is harder- use a point from the first offset, check if it works
                    else:
                        plungePos = offsets[0].Edges[0].Vertexes[0].Point
                        
                        #If it turns out this is invalid for some reason, nuke plungePos
                        [perp,idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges)
                        if not perp or perp.Length < tool.Diameter / 2. * (1 + plungeR):
                            plungePos = None
                        #FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
                        #Or some math to prove that it has to be (doubt that's true)
                        #Maybe reverse helixBounds and pick off that?
                
                
                #If we didn't find a place to helix, how about a ramp?
                if not plungePos:
                    #Check first edge of our offsets
                    if (offsets[0].Edges[0].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
                        rampEdge = offsets[0].Edges[0]
                    #The last edge also connects with the starting location- try that
                    elif (offsets[0].Edges[-1].Length >= tool.Diameter * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
                        rampEdge = offsets[0].Edges[-1]
                    else:
                        print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
                    #FIXME: There's got to be a smarter way to find a place to ramp
                
            
            #Returns gcode to perform a rapid move
            def rapid(x=None, y=None, z=None):
                retstr = "G00"
                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"
                
            #Returns gcode to perform a linear feed
            def feed(x=None, y=None, z=None):
                global feedxy
                retstr = "G01 F"
                if(x == None) and (y == None):
                    retstr += str("%.4f" % obj.HorizFeed)
                else:
                    retstr += str("%.4f" % obj.VertFeed)
                
                if (x != None) or (y != None) or (z != None):
                    if (x != None):
                        retstr += " X" + str("%.4f" % x)
                    if (y != None):
                        retstr += " Y" + str("%.4f" % y)
                    if (z != None):
                        retstr += " Z" + str("%.4f" % z)
                else:
                    return ""
                return retstr + "\n"
            
            #Returns gcode to perform an arc
            #Assumes XY plane or helix around Z
            #Don't worry about starting Z- assume that's dealt with elsewhere
            def arc(cx, cy, sx, sy, ex, ey, ez=None, ccw=False):
                #If start/end radii aren't within eps, abort
                eps = 0.01
                if (math.sqrt((cx - sx)**2 + (cy - sy)**2) - math.sqrt((cx - ex)**2 + (cy - ey)**2)) >= eps:
                    print "ERROR: Illegal arc: Stand and end radii not equal"
                    return ""
                
                #Set [C]CW and feed
                retstr = ""
                if ccw:
                    retstr += "G03 F"
                else:
                    retstr += "G02 F"
                retstr += str(obj.HorizFeed)
                
                #End location
                retstr += " X" + str("%.4f" % ex) + " Y" + str("%.4f" % ey)
                
                #Helix if requested
                if ez != None:
                    retstr += " Z" + str("%.4f" % ez)
                
                #Append center offsets
                retstr += " I" + str("%.4f" % (cx - sx)) + " J" + str("%.4f" % (cy - sy))
                
                return retstr + "\n"

            #Returns gcode to helically plunge
            #destZ is the milling level
            #startZ is the height we can safely feed down to before helix-ing
            def helicalPlunge(plungePos, rampangle, destZ, startZ):
                helixCmds = "(START HELICAL PLUNGE)\n"
                if(plungePos == None):
                    raise Error("Helical plunging requires a position!")
                    return None
                if(not tool):
                    raise Error("Helical plunging requires a tool!")
                    return None

                helixX = plungePos.x + tool.Diameter/2. * plungeR
                helixY = plungePos.y;
                
                helixCirc = math.pi * tool.Diameter * plungeR
                dzPerRev = math.sin(rampangle/180. * math.pi) * helixCirc

                #Go to the start of the helix position
                helixCmds += rapid(helixX, helixY)
                helixCmds += rapid(z=startZ)
                
                #Helix as required to get to the requested depth
                lastZ = startZ
                curZ = max(startZ-dzPerRev, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)
                    #NOTE: FreeCAD doesn't render this, but at least LinuxCNC considers it valid
                    #helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX, helixY, ez = curZ, ccw=True)
                    
                    #Use two half-helixes; FreeCAD renders that correctly,
                    #and it fits with the other code breaking up 360-degree arcs
                    helixCmds += arc(plungePos.x, plungePos.y, helixX, helixY, helixX - tool.Diameter * plungeR, helixY, ez = (curZ + lastZ)/2., ccw=True)
                    helixCmds += arc(plungePos.x, plungePos.y, helixX - tool.Diameter * plungeR, helixY, helixX, helixY, ez = curZ, ccw=True)
                    lastZ = curZ
                    curZ = max(curZ - dzPerRev, destZ)
                
                return helixCmds
                
                
            #Returns commands to linearly ramp into a cut
            #FIXME: This ramps along the first edge, assuming it's long
            #enough, NOT just wiggling back and forth by ~0.75 * toolD.
            #Not sure if that's any worse, but it's simpler
            #FIXME: This code is untested
            def rampPlunge(edge, rampangle, destZ, startZ):
                rampCmds = "(START RAMP PLUNGE)\n"
                if(edge == None):
                    raise Error("Ramp plunging requires an edge!")
                    return None
                if(not tool):
                    raise Error("Ramp plunging requires a tool!")
                
                
                sPoint = edge.Vertexes[0].Point
                ePoint = edge.Vertexes[1].Point
                #Evidently edges can get flipped- pick the right one in this case
                #FIXME: This is iffy code, based on what already existed in the "for vpos ..." loop below
                if ePoint == sPoint:
                    #print "FLIP"
                    ePoint = edge.Vertexes[-1].Point
                #print "Start: " + str(sPoint) + " End: " + str(ePoint) + " Zhigh: " + prnt(startZ) + " ZLow: " + prnt(destZ)
                
                rampDist = edge.Length
                rampDZ = math.sin(rampangle/180. * math.pi) * rampDist
                
                rampCmds += rapid(sPoint.x, sPoint.y)
                rampCmds += rapid(z=startZ)
                
                #Ramp down to the requested depth
                #FIXME: This might be an arc, so handle that as well
                lastZ = startZ
                curZ = max(startZ-rampDZ, destZ)
                done = False
                while not done:
                    done = (curZ == destZ)
                    
                    #If it's an arc, handle it!
                    if isinstance(edge.Curve,Part.Circle):
                        raise Error("rampPlunge: Screw it, not handling an arc.")
                    #Straight feed! Easy!
                    else:
                        rampCmds += feed(ePoint.x, ePoint.y, curZ)
                        rampCmds += feed(sPoint.x, sPoint.y)

                    lastZ = curZ
                    curZ = max(curZ - rampDZ, destZ)
                
                return rampCmds
                    
            
            
            
            #For helix-ing/ramping, know where we were last time
            #FIXME: Can probably get this from the "machine"?
            lastZ = fastZPos

            for vpos in frange(obj.StartDepth, obj.FinalDepth, obj.StepDown, obj.FinishDepth):
#                print "vpos: " + str(vpos)
                #Every for every depth we should helix down
                first = True
                # loop over successive wires
                for currentWire in offsets:
#                    print "new line (offset)"
                    last = None
                    for edge in currentWire.Edges:
#                        print "new edge"
                        if not last:
                            # we set the base GO to our fast move to our starting pos
                            if first:
                                #If we can helix, do so
                                if plungePos:
                                    output += helicalPlunge(plungePos, 3, vpos, lastZ)
                                    #print output
                                    lastZ = vpos
                                #Otherwise, see if we can ramp
                                #FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
                                elif rampEdge:
                                    output += rampPlunge(rampEdge, 3, vpos, lastZ)
                                    lastZ = vpos
                                #Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
                                #FIXME: At least not with the lazy ramp programming above...
                                else:
                                    print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
                                    startPoint = edge.Vertexes[0].Point
                                    output += "G0 X" + prnt(startPoint.x) + " Y" + prnt(startPoint.y) +\
                                              " Z" + prnt(fastZPos) + "\n"
                                first = False
                            #then move slow down to our starting point for our profile
                            last = edge.Vertexes[0].Point
                            output += "G1 X" + prnt(last.x) + " Y" + prnt(last.y) + " Z" + prnt(vpos) + "\n"
                        #if isinstance(edge.Curve,Part.Circle):
                        if DraftGeomUtils.geomType(edge) == "Circle":
                            point = edge.Vertexes[-1].Point
                            if point == last: # edges can come flipped
                                point = edge.Vertexes[0].Point
#                                print "flipped"
                            center = edge.Curve.Center
                            relcenter = center.sub(last)
                            v1 = last.sub(center)
                            v2 = point.sub(center)
                            if v1.cross(v2).z < 0:
                                output += "G2"
                            else:
                                output += "G3"
                            output += " X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos)
                            output += " I" + prnt(relcenter.x) + " J" +prnt(relcenter.y) + " K" + prnt(relcenter.z)
                            output += "\n"
                            last = point
                        else:
                            point = edge.Vertexes[-1].Point
                            if point == last: # edges can come flipped
                                point = edge.Vertexes[0].Point
                            output += "G1 X" + prnt(point.x) + " Y" + prnt(point.y) + " Z" + prnt(vpos) + "\n"
                            last = point

            #move back up
            output += "G0 Z" + prnt(fastZPos) + "\n"
#            print output
#            path = Path.Path(output)
#            obj.Path = path
            if obj.Active:
                path = Path.Path(output)
                obj.Path = path
                obj.ViewObject.Visibility = True
            else:
                path = Path.Path("(inactive operation)")
                obj.Path = path
                obj.ViewObject.Visibility = False
示例#30
0
文件: getSVG.py 项目: KimK/FreeCAD
 def getPath(edges=[],wires=[],pathname=None):
     import Part,DraftGeomUtils
     svg = "<path "
     if pathname is None:
         svg += 'id="%s" ' % obj.Name
     elif pathname != "":
         svg += 'id="%s" ' % pathname
     svg += ' d="'
     if not wires:
         egroups = Part.sortEdges(edges)
     else:
         egroups = []
         for w in wires:
             w1=w.copy()
             w1.fixWire()
             egroups.append(Part.__sortEdges__(w1.Edges))
     for egroupindex, edges in enumerate(egroups):
         edata = ""
         vs=() #skipped for the first edge
         for edgeindex,e in enumerate(edges):
             previousvs = vs
             # vertexes of an edge (reversed if needed)
             vs = e.Vertexes
             if previousvs:
                 if (vs[0].Point-previousvs[-1].Point).Length > 1e-6:
                     vs.reverse()
             if edgeindex == 0:
                 v = getProj(vs[0].Point, plane)
                 edata += 'M '+ str(v.x) +' '+ str(v.y) + ' '
             else:
                 if (vs[0].Point-previousvs[-1].Point).Length > 1e-6:
                     raise ValueError('edges not ordered')
             iscircle = DraftGeomUtils.geomType(e) == "Circle"
             isellipse = DraftGeomUtils.geomType(e) == "Ellipse"
             if iscircle or isellipse:
                 import math
                 if hasattr(FreeCAD,"DraftWorkingPlane"):
                     drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
                 else:
                     drawing_plane_normal = FreeCAD.Vector(0,0,1)
                 if plane: drawing_plane_normal = plane.axis
                 c = e.Curve
                 if round(c.Axis.getAngle(drawing_plane_normal),2) in [0,3.14]:
                     occversion = Part.OCC_VERSION.split(".")
                     done = False
                     if (int(occversion[0]) >= 7) and (int(occversion[1]) >= 1):
                         # if using occ >= 7.1, use HLR algorithm
                         import Drawing
                         snip = Drawing.projectToSVG(e,drawing_plane_normal)
                         if snip:
                             try:
                                 a = "A " + snip.split("path d=\"")[1].split("\"")[0].split("A")[1]
                             except:
                                 pass
                             else:
                                 edata += a
                                 done = True
                     if not done:
                         if len(e.Vertexes) == 1 and iscircle: #complete curve
                             svg = getCircle(e)
                             return svg
                         elif len(e.Vertexes) == 1 and isellipse:
                             #svg = getEllipse(e)
                             #return svg
                             endpoints = (getProj(c.value((c.LastParameter-\
                                     c.FirstParameter)/2.0), plane), \
                                     getProj(vs[-1].Point, plane))
                         else:
                             endpoints = (getProj(vs[-1].Point), plane)
                         # arc
                         if iscircle:
                             rx = ry = c.Radius
                             rot = 0
                         else: #ellipse
                             rx = c.MajorRadius
                             ry = c.MinorRadius
                             rot = math.degrees(c.AngleXU * (c.Axis * \
                                 FreeCAD.Vector(0,0,1)))
                             if rot > 90:
                                 rot -=180
                             if rot < -90:
                                 rot += 180
                             #be careful with the sweep flag
                         flag_large_arc = (((e.ParameterRange[1] - \
                                 e.ParameterRange[0]) / math.pi) % 2) > 1
                         #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \
                         #         == (e.LastParameter > e.FirstParameter)
                         #        == (e.Orientation == "Forward")
                         # other method: check the direction of the angle between tangents
                         t1 = e.tangentAt(e.FirstParameter)
                         t2 = e.tangentAt(e.FirstParameter + (e.LastParameter-e.FirstParameter)/10)
                         flag_sweep = (DraftVecUtils.angle(t1,t2,drawing_plane_normal) < 0)
                         for v in endpoints:
                             edata += 'A %s %s %s %s %s %s %s ' % \
                                     (str(rx),str(ry),str(rot),\
                                     str(int(flag_large_arc)),\
                                     str(int(flag_sweep)),str(v.x),str(v.y))
                 else:
                     edata += getDiscretized(e, plane)
             elif DraftGeomUtils.geomType(e) == "Line":
                 v = getProj(vs[-1].Point, plane)
                 edata += 'L '+ str(v.x) +' '+ str(v.y) + ' '
             else:
                 bspline=e.Curve.toBSpline(e.FirstParameter,e.LastParameter)
                 if bspline.Degree > 3 or bspline.isRational():
                     try:
                         bspline=bspline.approximateBSpline(0.05,50, 3,'C0')
                     except RuntimeError:
                         print("Debug: unable to approximate bspline")
                 if bspline.Degree <= 3 and not bspline.isRational():
                     for bezierseg in bspline.toBezier():
                         if bezierseg.Degree>3: #should not happen
                             raise AssertionError
                         elif bezierseg.Degree==1:
                             edata +='L '
                         elif bezierseg.Degree==2:
                             edata +='Q '
                         elif bezierseg.Degree==3:
                             edata +='C '
                         for pole in bezierseg.getPoles()[1:]:
                             v = getProj(pole, plane)
                             edata += str(v.x) +' '+ str(v.y) + ' '
                 else:
                     print("Debug: one edge (hash ",e.hashCode(),\
                             ") has been discretized with parameter 0.1")
                     for linepoint in bspline.discretize(0.1)[1:]:
                         v = getProj(linepoint, plane)
                         edata += 'L '+ str(v.x) +' '+ str(v.y) + ' '
         if fill != 'none':
             edata += 'Z '
         if edata in pathdata:
             # do not draw a path on another identical path
             return ""
         else:
             svg += edata
             pathdata.append(edata)
     svg += '" '
     svg += 'stroke="' + stroke + '" '
     svg += 'stroke-width="' + str(linewidth) + ' px" '
     svg += 'style="stroke-width:'+ str(linewidth)
     svg += ';stroke-miterlimit:4'
     svg += ';stroke-dasharray:' + lstyle
     svg += ';fill:' + fill
     try:
         svg += ';fill-opacity:' + str(fill_opacity)
     except NameError:
         pass
     svg += ';fill-rule: evenodd "'
     svg += '/>\n'
     return svg
示例#31
0
    def proceed(self):
        """Proceed with execution of the command after proper selection."""
        if self.call:
            self.view.removeEventCallback("SoEvent", self.call)
        sel = Gui.Selection.getSelection()
        if len(sel) == 2:
            self.trimObjects(sel)
            self.finish()
            return
        self.obj = sel[0]
        self.ui.trimUi()
        self.linetrack = trackers.lineTracker()

        import DraftGeomUtils
        import Part

        if "Shape" not in self.obj.PropertiesList:
            return
        if "Placement" in self.obj.PropertiesList:
            self.placement = self.obj.Placement
        if len(self.obj.Shape.Faces) == 1:
            # simple extrude mode, the object itself is extruded
            self.extrudeMode = True
            self.ghost = [trackers.ghostTracker([self.obj])]
            self.normal = self.obj.Shape.Faces[0].normalAt(0.5, 0.5)
            for v in self.obj.Shape.Vertexes:
                self.ghost.append(trackers.lineTracker())
        elif len(self.obj.Shape.Faces) > 1:
            # face extrude mode, a new object is created
            ss = Gui.Selection.getSelectionEx()[0]
            if len(ss.SubObjects) == 1:
                if ss.SubObjects[0].ShapeType == "Face":
                    self.obj = self.doc.addObject("Part::Feature", "Face")
                    self.obj.Shape = ss.SubObjects[0]
                    self.extrudeMode = True
                    self.ghost = [trackers.ghostTracker([self.obj])]
                    self.normal = self.obj.Shape.Faces[0].normalAt(0.5, 0.5)
                    for v in self.obj.Shape.Vertexes:
                        self.ghost.append(trackers.lineTracker())
        else:
            # normal wire trimex mode
            self.color = self.obj.ViewObject.LineColor
            self.width = self.obj.ViewObject.LineWidth
            # self.obj.ViewObject.Visibility = False
            self.obj.ViewObject.LineColor = (0.5, 0.5, 0.5)
            self.obj.ViewObject.LineWidth = 1
            self.extrudeMode = False
            if self.obj.Shape.Wires:
                self.edges = self.obj.Shape.Wires[0].Edges
                self.edges = Part.__sortEdges__(self.edges)
            else:
                self.edges = self.obj.Shape.Edges
            self.ghost = []
            lc = self.color
            sc = (lc[0], lc[1], lc[2])
            sw = self.width
            for e in self.edges:
                if DraftGeomUtils.geomType(e) == "Line":
                    self.ghost.append(
                        trackers.lineTracker(scolor=sc, swidth=sw))
                else:
                    self.ghost.append(trackers.arcTracker(scolor=sc,
                                                          swidth=sw))
        if not self.ghost:
            self.finish()
        for g in self.ghost:
            g.on()
        self.activePoint = 0
        self.nodes = []
        self.shift = False
        self.alt = False
        self.force = None
        self.cv = None
        self.call = self.view.addEventCallback("SoEvent", self.action)
        _msg(translate("draft", "Pick distance"))
示例#32
0
    def redraw(self, point, snapped=None, shift=False, alt=False, real=None):
        """Redraw the ghost normally."""
        # initializing
        reverse = False
        for g in self.ghost:
            g.off()
        if real:
            newedges = []

        import DraftGeomUtils
        import Part

        # finding the active point
        vlist = []
        for e in self.edges:
            vlist.append(e.Vertexes[0].Point)
        vlist.append(self.edges[-1].Vertexes[-1].Point)
        if shift:
            npoint = self.activePoint
        else:
            npoint = DraftGeomUtils.findClosest(point, vlist)
        if npoint > len(self.edges) / 2:
            reverse = True
        if alt:
            reverse = not reverse
        self.activePoint = npoint

        # sorting out directions
        if reverse and (npoint > 0):
            npoint = npoint - 1
        if (npoint > len(self.edges) - 1):
            edge = self.edges[-1]
            ghost = self.ghost[-1]
        else:
            edge = self.edges[npoint]
            ghost = self.ghost[npoint]
        if reverse:
            v1 = edge.Vertexes[-1].Point
            v2 = edge.Vertexes[0].Point
        else:
            v1 = edge.Vertexes[0].Point
            v2 = edge.Vertexes[-1].Point

        # snapping
        if snapped:
            snapped = self.doc.getObject(snapped['Object'])
            if hasattr(snapped, "Shape"):
                pts = []
                for e in snapped.Shape.Edges:
                    int = DraftGeomUtils.findIntersection(edge, e, True, True)
                    if int:
                        pts.extend(int)
                if pts:
                    point = pts[DraftGeomUtils.findClosest(point, pts)]

        # modifying active edge
        if DraftGeomUtils.geomType(edge) == "Line":
            ve = DraftGeomUtils.vec(edge)
            chord = v1.sub(point)
            n = ve.cross(chord)
            if n.Length == 0:
                self.newpoint = point
            else:
                perp = ve.cross(n)
                proj = DraftVecUtils.project(chord, perp)
                self.newpoint = App.Vector.add(point, proj)
            dist = v1.sub(self.newpoint).Length
            ghost.p1(self.newpoint)
            ghost.p2(v2)
            self.ui.labelRadius.setText(translate("draft", "Distance"))
            self.ui.radiusValue.setToolTip(
                translate("draft", "The offset distance"))
            if real:
                if self.force:
                    ray = self.newpoint.sub(v1)
                    ray.multiply(self.force / ray.Length)
                    self.newpoint = App.Vector.add(v1, ray)
                newedges.append(Part.LineSegment(self.newpoint, v2).toShape())
        else:
            center = edge.Curve.Center
            rad = edge.Curve.Radius
            ang1 = DraftVecUtils.angle(v2.sub(center))
            ang2 = DraftVecUtils.angle(point.sub(center))
            _rot_rad = DraftVecUtils.rotate(App.Vector(rad, 0, 0), -ang2)
            self.newpoint = App.Vector.add(center, _rot_rad)
            self.ui.labelRadius.setText(translate("draft", "Angle"))
            self.ui.radiusValue.setToolTip(
                translate("draft", "The offset angle"))
            dist = math.degrees(-ang2)
            # if ang1 > ang2:
            #     ang1, ang2 = ang2, ang1
            # print("last calculated:",
            #       math.degrees(-ang1),
            #       math.degrees(-ang2))
            ghost.setEndAngle(-ang2)
            ghost.setStartAngle(-ang1)
            ghost.setCenter(center)
            ghost.setRadius(rad)
            if real:
                if self.force:
                    angle = math.radians(self.force)
                    newray = DraftVecUtils.rotate(App.Vector(rad, 0, 0),
                                                  -angle)
                    self.newpoint = App.Vector.add(center, newray)
                chord = self.newpoint.sub(v2)
                perp = chord.cross(App.Vector(0, 0, 1))
                scaledperp = DraftVecUtils.scaleTo(perp, rad)
                midpoint = App.Vector.add(center, scaledperp)
                _sh = Part.Arc(self.newpoint, midpoint, v2).toShape()
                newedges.append(_sh)
        ghost.on()

        # resetting the visible edges
        if not reverse:
            li = list(range(npoint + 1, len(self.edges)))
        else:
            li = list(range(npoint - 1, -1, -1))
        for i in li:
            edge = self.edges[i]
            ghost = self.ghost[i]
            if DraftGeomUtils.geomType(edge) == "Line":
                ghost.p1(edge.Vertexes[0].Point)
                ghost.p2(edge.Vertexes[-1].Point)
            else:
                ang1 = DraftVecUtils.angle(edge.Vertexes[0].Point.sub(center))
                ang2 = DraftVecUtils.angle(edge.Vertexes[-1].Point.sub(center))
                # if ang1 > ang2:
                #     ang1, ang2 = ang2, ang1
                ghost.setEndAngle(-ang2)
                ghost.setStartAngle(-ang1)
                ghost.setCenter(edge.Curve.Center)
                ghost.setRadius(edge.Curve.Radius)
            if real:
                newedges.append(edge)
            ghost.on()

        # finishing
        if real:
            return newedges
        else:
            return dist
示例#33
0
def getUShapeRebarSVGData(
    rebar,
    view_plane,
    rebars_svg,
    rebars_stroke_width,
    rebars_color_style,
    longitudinal_line_dia=None,
):
    """getUShapeRebarSVGData(UShapeRebar, ViewPlane, RebarsSVG,
    RebarsStrokeWidth, RebarsColorStyle, longitudinal_line_dia):
    Returns dictionary containing UShape rebar svg data.

    rebars_color_style can be:
        - "shape color" to select color of rebar shape
        - color name or hex value of color

    Returns dictionary format:
    {
        "svg": u_rebar_svg,
        "visibility": is_rebar_visible,
    }
    """
    if longitudinal_line_dia is None:
        longitudinal_line_dia = 2 * 2 * rebars_stroke_width

    rebars_color = getRebarColor(rebar, rebars_color_style)

    u_rebar_svg = ElementTree.Element("g", attrib={"id": str(rebar.Name)})
    is_rebar_visible = False
    drawing_plane_normal = view_plane.axis
    if round(drawing_plane_normal.cross(getRebarsSpanAxis(rebar)).Length) == 0:
        basewire = rebar.Base.Shape.Wires[0].copy()
        basewire.Placement = rebar.PlacementList[0].multiply(
            basewire.Placement)
        edges = Part.__sortEdges__(
            DraftGeomUtils.filletWire(
                basewire,
                rebar.Rounding * rebar.Diameter.Value,
            ).Edges)
        for edge in edges:
            if DraftGeomUtils.geomType(edge) == "Line":
                p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                             view_plane)
                p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                             view_plane)
                if round(p1.x) == round(p2.x) and round(p1.y) == round(p2.y):
                    edge_svg = getPointSVG(p1,
                                           radius=longitudinal_line_dia / 2,
                                           fill=rebars_color)
                else:
                    edge_svg = getLineSVG(p1, p2, rebars_stroke_width,
                                          rebars_color)
                    if not isLineInSVG(p1, p2, rebars_svg):
                        is_rebar_visible = True
                if is_rebar_visible:
                    u_rebar_svg.append(edge_svg)
                    is_rebar_visible = True
            elif DraftGeomUtils.geomType(edge) == "Circle":
                p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                             view_plane)
                p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                             view_plane)
                if round(p1.x) == round(p2.x) or round(p1.y) == round(p2.y):
                    edge_svg = getLineSVG(p1, p2, rebars_stroke_width,
                                          rebars_color)
                    if not isLineInSVG(p1, p2, rebars_svg):
                        is_rebar_visible = True
                else:
                    edge_svg = getRoundEdgeSVG(edge, view_plane,
                                               rebars_stroke_width,
                                               rebars_color)
                    if not isRoundCornerInSVG(
                            edge,
                            rebar.Rounding * rebar.Diameter.Value,
                            view_plane,
                            rebars_svg,
                    ):
                        is_rebar_visible = True
                if is_rebar_visible:
                    u_rebar_svg.append(edge_svg)
    else:
        basewire = rebar.Base.Shape.Wires[0]
        for placement in rebar.PlacementList:
            wire = basewire.copy()
            wire.Placement = placement.multiply(basewire.Placement)

            edges = Part.__sortEdges__(
                DraftGeomUtils.filletWire(
                    wire,
                    rebar.Rounding * rebar.Diameter.Value,
                ).Edges)
            for edge in edges:
                if DraftGeomUtils.geomType(edge) == "Line":
                    p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                                 view_plane)
                    p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                                 view_plane)
                    if round(p1.x) == round(p2.x) and round(p1.y) == round(
                            p2.y):
                        edge_svg = getPointSVG(
                            p1,
                            radius=longitudinal_line_dia / 2,
                            fill=rebars_color,
                        )
                    else:
                        edge_svg = getLineSVG(p1, p2, rebars_stroke_width,
                                              rebars_color)
                        if not isLineInSVG(p1, p2, rebars_svg):
                            is_rebar_visible = True
                    if is_rebar_visible or not isLineInSVG(p1, p2, rebars_svg):
                        u_rebar_svg.append(edge_svg)
                        is_rebar_visible = True
                elif DraftGeomUtils.geomType(edge) == "Circle":
                    p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point,
                                                 view_plane)
                    p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point,
                                                 view_plane)
                    if round(p1.x) == round(p2.x) or round(p1.y) == round(
                            p2.y):
                        edge_svg = getLineSVG(p1, p2, rebars_stroke_width,
                                              rebars_color)
                        if not isLineInSVG(p1, p2, rebars_svg):
                            is_rebar_visible = True
                    else:
                        edge_svg = getRoundEdgeSVG(edge, view_plane,
                                                   rebars_stroke_width,
                                                   rebars_color)
                        if not isRoundCornerInSVG(
                                edge,
                                rebar.Rounding * rebar.Diameter.Value,
                                view_plane,
                                rebars_svg,
                        ):
                            is_rebar_visible = True
                    if is_rebar_visible:
                        u_rebar_svg.append(edge_svg)
    return {
        "svg": u_rebar_svg,
        "visibility": is_rebar_visible,
    }
示例#34
0
    def getPath(edges=[], wires=[], pathname=None):

        svg = "<path "
        if pathname is None:
            svg += 'id="%s" ' % obj.Name
        elif pathname != "":
            svg += 'id="%s" ' % pathname
        svg += ' d="'
        if not wires:
            egroups = Part.sortEdges(edges)
        else:
            egroups = []
            first = True
            for w in wires:
                w1 = w.copy()
                if first:
                    first = False
                else:
                    # invert further wires to create holes
                    w1 = DraftGeomUtils.invert(w1)
                w1.fixWire()
                egroups.append(Part.__sortEdges__(w1.Edges))
        for egroupindex, edges in enumerate(egroups):
            edata = ""
            vs = ()  #skipped for the first edge
            for edgeindex, e in enumerate(edges):
                previousvs = vs
                # vertexes of an edge (reversed if needed)
                vs = e.Vertexes
                if previousvs:
                    if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
                        vs.reverse()
                if edgeindex == 0:
                    v = getProj(vs[0].Point, plane)
                    edata += 'M ' + str(v.x) + ' ' + str(v.y) + ' '
                else:
                    if (vs[0].Point - previousvs[-1].Point).Length > 1e-6:
                        raise ValueError('edges not ordered')
                iscircle = DraftGeomUtils.geomType(e) == "Circle"
                isellipse = DraftGeomUtils.geomType(e) == "Ellipse"
                if iscircle or isellipse:
                    import math
                    if hasattr(FreeCAD, "DraftWorkingPlane"):
                        drawing_plane_normal = FreeCAD.DraftWorkingPlane.axis
                    else:
                        drawing_plane_normal = FreeCAD.Vector(0, 0, 1)
                    if plane: drawing_plane_normal = plane.axis
                    c = e.Curve
                    if round(c.Axis.getAngle(drawing_plane_normal),
                             2) in [0, 3.14]:
                        occversion = Part.OCC_VERSION.split(".")
                        done = False
                        if (int(occversion[0]) >= 7) and (int(occversion[1]) >=
                                                          1):
                            # if using occ >= 7.1, use HLR algorithm
                            import Drawing
                            snip = Drawing.projectToSVG(
                                e, drawing_plane_normal)
                            if snip:
                                try:
                                    a = "A " + snip.split("path d=\"")[
                                        1].split("\"")[0].split("A")[1]
                                except:
                                    pass
                                else:
                                    edata += a
                                    done = True
                        if not done:
                            if len(e.Vertexes
                                   ) == 1 and iscircle:  #complete curve
                                svg = getCircle(e)
                                return svg
                            elif len(e.Vertexes) == 1 and isellipse:
                                #svg = getEllipse(e)
                                #return svg
                                endpoints = [
                                    getProj(
                                        c.value((c.LastParameter -
                                                 c.FirstParameter) / 2.0),
                                        plane),
                                    getProj(vs[-1].Point, plane)
                                ]
                            else:
                                endpoints = [getProj(vs[-1].Point, plane)]
                            # arc
                            if iscircle:
                                rx = ry = c.Radius
                                rot = 0
                            else:  #ellipse
                                rx = c.MajorRadius
                                ry = c.MinorRadius
                                rot = math.degrees(c.AngleXU * (c.Axis * \
                                    FreeCAD.Vector(0,0,1)))
                                if rot > 90:
                                    rot -= 180
                                if rot < -90:
                                    rot += 180
                                #be careful with the sweep flag
                            flag_large_arc = (((e.ParameterRange[1] - \
                                    e.ParameterRange[0]) / math.pi) % 2) > 1
                            #flag_sweep = (c.Axis * drawing_plane_normal >= 0) \
                            #         == (e.LastParameter > e.FirstParameter)
                            #        == (e.Orientation == "Forward")
                            # other method: check the direction of the angle between tangents
                            t1 = e.tangentAt(e.FirstParameter)
                            t2 = e.tangentAt(
                                e.FirstParameter +
                                (e.LastParameter - e.FirstParameter) / 10)
                            flag_sweep = (DraftVecUtils.angle(
                                t1, t2, drawing_plane_normal) < 0)
                            for v in endpoints:
                                edata += 'A %s %s %s %s %s %s %s ' % \
                                        (str(rx),str(ry),str(rot),\
                                        str(int(flag_large_arc)),\
                                        str(int(flag_sweep)),str(v.x),str(v.y))
                    else:
                        edata += getDiscretized(e, plane)
                elif DraftGeomUtils.geomType(e) == "Line":
                    v = getProj(vs[-1].Point, plane)
                    edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
                else:
                    bspline = e.Curve.toBSpline(e.FirstParameter,
                                                e.LastParameter)
                    if bspline.Degree > 3 or bspline.isRational():
                        try:
                            bspline = bspline.approximateBSpline(
                                0.05, 50, 3, 'C0')
                        except RuntimeError:
                            print("Debug: unable to approximate bspline")
                    if bspline.Degree <= 3 and not bspline.isRational():
                        for bezierseg in bspline.toBezier():
                            if bezierseg.Degree > 3:  #should not happen
                                raise AssertionError
                            elif bezierseg.Degree == 1:
                                edata += 'L '
                            elif bezierseg.Degree == 2:
                                edata += 'Q '
                            elif bezierseg.Degree == 3:
                                edata += 'C '
                            for pole in bezierseg.getPoles()[1:]:
                                v = getProj(pole, plane)
                                edata += str(v.x) + ' ' + str(v.y) + ' '
                    else:
                        print("Debug: one edge (hash ",e.hashCode(),\
                                ") has been discretized with parameter 0.1")
                        for linepoint in bspline.discretize(0.1)[1:]:
                            v = getProj(linepoint, plane)
                            edata += 'L ' + str(v.x) + ' ' + str(v.y) + ' '
            if fill != 'none':
                edata += 'Z '
            if edata in pathdata:
                # do not draw a path on another identical path
                return ""
            else:
                svg += edata
                pathdata.append(edata)
        svg += '" '
        svg += 'stroke="' + stroke + '" '
        svg += 'stroke-width="' + str(linewidth) + ' px" '
        svg += 'style="stroke-width:' + str(linewidth)
        svg += ';stroke-miterlimit:4'
        svg += ';stroke-dasharray:' + lstyle
        svg += ';fill:' + fill
        try:
            svg += ';fill-opacity:' + str(fill_opacity)
        except NameError:
            pass
        svg += ';fill-rule: evenodd "'
        svg += '/>\n'
        return svg
示例#35
0
    def action(self, arg):
        """Handle the 3D scene events.

        This is installed as an EventCallback in the Inventor view.

        Parameters
        ----------
        arg: dict
            Dictionary with strings that indicates the type of event received
            from the 3D view.
        """
        if arg["Type"] == "SoKeyboardEvent":
            if arg["Key"] == "ESCAPE":
                self.finish()
        elif arg["Type"] == "SoLocation2Event":  # mouse movement detection
            import DraftGeomUtils
            shift = gui_tool_utils.hasMod(arg, gui_tool_utils.MODCONSTRAIN)
            if self.arcmode or self.point2:
                gui_tool_utils.setMod(arg, gui_tool_utils.MODCONSTRAIN, False)
            (self.point, ctrlPoint, self.info) = gui_tool_utils.getPoint(
                self, arg, noTracker=(len(self.node) > 0))
            if (gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT)
                    or self.selectmode) and (len(self.node) < 3):
                self.dimtrack.off()
                if not self.altdown:
                    self.altdown = True
                    self.ui.switchUi(True)
                    if hasattr(Gui, "Snapper"):
                        Gui.Snapper.setSelectMode(True)
                snapped = self.view.getObjectInfo(
                    (arg["Position"][0], arg["Position"][1]))
                if snapped:
                    ob = self.doc.getObject(snapped['Object'])
                    if "Edge" in snapped['Component']:
                        num = int(snapped['Component'].lstrip('Edge')) - 1
                        ed = ob.Shape.Edges[num]
                        v1 = ed.Vertexes[0].Point
                        v2 = ed.Vertexes[-1].Point
                        self.dimtrack.update([v1, v2, self.cont])
            else:
                if self.node and (len(self.edges) < 2):
                    self.dimtrack.on()
                if len(self.edges) == 2:
                    # angular dimension
                    self.dimtrack.off()
                    r = self.point.sub(self.center)
                    self.arctrack.setRadius(r.Length)
                    a = self.arctrack.getAngle(self.point)
                    pair = DraftGeomUtils.getBoundaryAngles(a, self.pts)
                    if not (pair[0] < a < pair[1]):
                        self.angledata = [
                            4 * math.pi - pair[0], 2 * math.pi - pair[1]
                        ]
                    else:
                        self.angledata = [
                            2 * math.pi - pair[0], 2 * math.pi - pair[1]
                        ]
                    self.arctrack.setStartAngle(self.angledata[0])
                    self.arctrack.setEndAngle(self.angledata[1])
                if self.altdown:
                    self.altdown = False
                    self.ui.switchUi(False)
                    if hasattr(Gui, "Snapper"):
                        Gui.Snapper.setSelectMode(False)
                if self.dir:
                    _p = DraftVecUtils.project(self.point.sub(self.node[0]),
                                               self.dir)
                    self.point = self.node[0].add(_p)
                if len(self.node) == 2:
                    if self.arcmode and self.edges:
                        cen = self.edges[0].Curve.Center
                        rad = self.edges[0].Curve.Radius
                        baseray = self.point.sub(cen)
                        v2 = DraftVecUtils.scaleTo(baseray, rad)
                        v1 = v2.negative()
                        if shift:
                            self.node = [cen, cen.add(v2)]
                            self.arcmode = "radius"
                        else:
                            self.node = [cen.add(v1), cen.add(v2)]
                            self.arcmode = "diameter"
                        self.dimtrack.update(self.node)
                # Draw constraint tracker line.
                if shift and (not self.arcmode):
                    if len(self.node) == 2:
                        if not self.point2:
                            self.point2 = self.node[1]
                        else:
                            self.node[1] = self.point2
                        if not self.force:
                            _p = self.point.sub(self.node[0])
                            a = abs(_p.getAngle(App.DraftWorkingPlane.u))
                            if (a > math.pi / 4) and (a <= 0.75 * math.pi):
                                self.force = 1
                            else:
                                self.force = 2
                        if self.force == 1:
                            self.node[1] = App.Vector(self.node[0].x,
                                                      self.node[1].y,
                                                      self.node[0].z)
                        elif self.force == 2:
                            self.node[1] = App.Vector(self.node[1].x,
                                                      self.node[0].y,
                                                      self.node[0].z)
                else:
                    self.force = None
                    if self.point2 and (len(self.node) > 1):
                        self.node[1] = self.point2
                        self.point2 = None
                # update the dimline
                if self.node and not self.arcmode:
                    self.dimtrack.update(self.node + [self.point] +
                                         [self.cont])
            gui_tool_utils.redraw3DView()
        elif arg["Type"] == "SoMouseButtonEvent":
            if (arg["State"] == "DOWN") and (arg["Button"] == "BUTTON1"):
                import DraftGeomUtils
                if self.point:
                    self.ui.redraw()
                    if (not self.node) and (not self.support):
                        gui_tool_utils.getSupport(arg)
                    if (gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT)
                            or self.selectmode) and (len(self.node) < 3):
                        # print("snapped: ",self.info)
                        if self.info:
                            ob = self.doc.getObject(self.info['Object'])
                            if 'Edge' in self.info['Component']:
                                num = int(
                                    self.info['Component'].lstrip('Edge')) - 1
                                ed = ob.Shape.Edges[num]
                                v1 = ed.Vertexes[0].Point
                                v2 = ed.Vertexes[-1].Point
                                i1 = i2 = None
                                for i in range(len(ob.Shape.Vertexes)):
                                    if v1 == ob.Shape.Vertexes[i].Point:
                                        i1 = i
                                    if v2 == ob.Shape.Vertexes[i].Point:
                                        i2 = i
                                if (i1 is not None) and (i2 is not None):
                                    self.indices.append(num)
                                    if not self.edges:
                                        # nothing snapped yet, we treat it
                                        # as a normal edge-snapped dimension
                                        self.node = [v1, v2]
                                        self.link = [ob, i1, i2]
                                        self.edges.append(ed)
                                        if DraftGeomUtils.geomType(
                                                ed) == "Circle":
                                            # snapped edge is an arc
                                            self.arcmode = "diameter"
                                            self.link = [ob, num]
                                    else:
                                        # there is already a snapped edge,
                                        # so we start angular dimension
                                        self.edges.append(ed)
                                        # self.node now has the 4 endpoints
                                        self.node.extend([v1, v2])
                                        c = DraftGeomUtils.findIntersection(
                                            self.node[0], self.node[1],
                                            self.node[2], self.node[3], True,
                                            True)
                                        if c:
                                            # print("centers:",c)
                                            self.center = c[0]
                                            self.arctrack.setCenter(
                                                self.center)
                                            self.arctrack.on()
                                            for e in self.edges:
                                                for v in e.Vertexes:
                                                    self.pts.append(
                                                        self.arctrack.getAngle(
                                                            v.Point))
                                            self.link = [self.link[0], ob]
                                        else:
                                            _msg(
                                                translate(
                                                    "draft",
                                                    "Edges don't intersect!"))
                                            self.finish()
                                            return
                                self.dimtrack.on()
                    else:
                        self.node.append(self.point)
                    self.selectmode = False
                    # print("node", self.node)
                    self.dimtrack.update(self.node)
                    if len(self.node) == 2:
                        self.point2 = self.node[1]
                    if len(self.node) == 1:
                        self.dimtrack.on()
                        if self.planetrack:
                            self.planetrack.set(self.node[0])
                    elif len(self.node) == 2 and self.cont:
                        self.node.append(self.cont)
                        self.createObject()
                        if not self.cont:
                            self.finish()
                    elif len(self.node) == 3:
                        # for unlinked arc mode:
                        # if self.arcmode:
                        #     v = self.node[1].sub(self.node[0])
                        #     v.multiply(0.5)
                        #     cen = self.node[0].add(v)
                        #     self.node = [self.node[0], self.node[1], cen]
                        self.createObject()
                        if not self.cont:
                            self.finish()
                    elif self.angledata:
                        self.node.append(self.point)
                        self.createObject()
                        self.finish()
示例#36
0
def getIndices(obj, shape, offsetv, offsetvn):
    "returns a list with 2 lists: vertices and face indexes, offset with the given amount"
    vlist = []
    vnlist = []
    elist = []
    flist = []
    curves = None

    if isinstance(shape, Part.Shape):
        for e in shape.Edges:
            try:
                if not isinstance(e.Curve, Part.LineSegment):
                    if not curves:
                        if obj.isDerivedFrom("App::Link"):
                            myshape = obj.LinkedObject.Shape.copy(False)
                            myshape.Placement = obj.LinkPlacement
                        else:
                            myshape = obj.Shape.copy(False)
                            myshape.Placement = obj.getGlobalPlacement()
                        mesh = MeshPart.meshFromShape(Shape=myshape,
                                                      LinearDeflection=0.1,
                                                      AngularDeflection=0.7,
                                                      Relative=True)
                        FreeCAD.Console.PrintWarning(
                            translate(
                                "Arch",
                                "Found a shape containing curves, triangulating"
                            ) + "\n")
                        break
            except:  # unimplemented curve type
                if obj.isDerivedFrom("App::Link"):
                    if obj.Shape:
                        myshape = obj.Shape.copy(False)
                        myshape.Placement = obj.LinkPlacement
                    else:
                        myshape = obj.Shape.copy(False)
                        myshape.Placement = obj.getGlobalPlacement()
                mesh = MeshPart.meshFromShape(Shape=myshape,
                                              LinearDeflection=0.1,
                                              AngularDeflection=0.7,
                                              Relative=True)
                FreeCAD.Console.PrintWarning(
                    translate(
                        "Arch",
                        "Found a shape containing curves, triangulating") +
                    "\n")
                break
    elif isinstance(shape, Mesh.Mesh):
        curves = shape.Topology
    if mesh:
        for v in mesh.Topology[0]:
            vlist.append(" " + str(round(v[0], p)) + " " +
                         str(round(v[1], p)) + " " + str(round(v[2], p)))

        for vn in mesh.Facets:
            vnlist.append(" " + str(vn.Normal[0]) + " " + str(vn.Normal[1]) +
                          " " + str(vn.Normal[2]))

        for i, vn in enumerate(mesh.Topology[1]):
            flist.append(" " + str(vn[0] + offsetv) + "//" +
                         str(i + offsetvn) + " " + str(vn[1] + offsetv) +
                         "//" + str(i + offsetvn) + " " +
                         str(vn[2] + offsetv) + "//" + str(i + offsetvn) + " ")
    else:
        if curves:
            for v in curves[0]:
                vlist.append(" " + str(round(v.x, p)) + " " +
                             str(round(v.y, p)) + " " + str(round(v.z, p)))
            for f in curves[1]:
                fi = ""
                for vi in f:
                    fi += " " + str(vi + offsetv)
                flist.append(fi)
        else:
            for v in shape.Vertexes:
                vlist.append(" " + str(round(v.X, p)) + " " +
                             str(round(v.Y, p)) + " " + str(round(v.Z, p)))
            if not shape.Faces:
                for e in shape.Edges:
                    if DraftGeomUtils.geomType(e) == "Line":
                        ei = " " + str(
                            findVert(e.Vertexes[0], shape.Vertexes) + offsetv)
                        ei += " " + str(
                            findVert(e.Vertexes[-1], shape.Vertexes) + offsetv)
                        elist.append(ei)
            for f in shape.Faces:
                if len(f.Wires) > 1:
                    # if we have holes, we triangulate
                    tris = f.tessellate(1)
                    for fdata in tris[1]:
                        fi = ""
                        for vi in fdata:
                            vdata = Part.Vertex(tris[0][vi])
                            fi += " " + str(
                                findVert(vdata, shape.Vertexes) + offsetv)
                        flist.append(fi)
                else:
                    fi = ""
                    for e in f.OuterWire.OrderedEdges:
                        #print(e.Vertexes[0].Point,e.Vertexes[1].Point)
                        v = e.Vertexes[0]
                        ind = findVert(v, shape.Vertexes)
                        if ind is None:
                            return None, None, None
                        fi += " " + str(ind + offsetv)
                    flist.append(fi)
    return vlist, vnlist, elist, flist
示例#37
0
def upgrade(objects, delete=False, force=None):
    """upgrade(objects,delete=False,force=None)
    
    Upgrade the given object(s).
    
    Parameters
    ----------
    objects :

    delete : bool
        If delete is True, old objects are deleted.

    force : string
        The force attribute can be used to force a certain way of upgrading.
        Accepted values: makeCompound, closeGroupWires, makeSolid, closeWire,
        turnToParts, makeFusion, makeShell, makeFaces, draftify, joinFaces,
        makeSketchFace, makeWires.
    
    Return
    ----------
    Returns a dictionary containing two lists, a list of new objects and a list
    of objects to be deleted
    """

    import Part
    import DraftGeomUtils

    if not isinstance(objects,list):
        objects = [objects]

    global deleteList, newList
    deleteList = []
    addList = []

    # definitions of actions to perform

    def turnToLine(obj):
        """turns an edge into a Draft line"""
        p1 = obj.Shape.Vertexes[0].Point
        p2 = obj.Shape.Vertexes[-1].Point
        newobj = makeLine(p1,p2)
        addList.append(newobj)
        deleteList.append(obj)
        return newobj

    def makeCompound(objectslist):
        """returns a compound object made from the given objects"""
        newobj = makeBlock(objectslist)
        addList.append(newobj)
        return newobj

    def closeGroupWires(groupslist):
        """closes every open wire in the given groups"""
        result = False
        for grp in groupslist:
            for obj in grp.Group:
                    newobj = closeWire(obj)
                    # add new objects to their respective groups
                    if newobj:
                        result = True
                        grp.addObject(newobj)
        return result

    def makeSolid(obj):
        """turns an object into a solid, if possible"""
        if obj.Shape.Solids:
            return None
        sol = None
        try:
            sol = Part.makeSolid(obj.Shape)
        except Part.OCCError:
            return None
        else:
            if sol:
                if sol.isClosed():
                    newobj = App.ActiveDocument.addObject("Part::Feature","Solid")
                    newobj.Shape = sol
                    addList.append(newobj)
                    deleteList.append(obj)
            return newobj

    def closeWire(obj):
        """closes a wire object, if possible"""
        if obj.Shape.Faces:
            return None
        if len(obj.Shape.Wires) != 1:
            return None
        if len(obj.Shape.Edges) == 1:
            return None
        if utils.get_type(obj) == "Wire":
            obj.Closed = True
            return True
        else:
            w = obj.Shape.Wires[0]
            if not w.isClosed():
                edges = w.Edges
                p0 = w.Vertexes[0].Point
                p1 = w.Vertexes[-1].Point
                if p0 == p1:
                    # sometimes an open wire can have its start and end points identical (OCC bug)
                    # in that case, although it is not closed, face works...
                    f = Part.Face(w)
                    newobj = App.ActiveDocument.addObject("Part::Feature","Face")
                    newobj.Shape = f
                else:
                    edges.append(Part.LineSegment(p1,p0).toShape())
                    w = Part.Wire(Part.__sortEdges__(edges))
                    newobj = App.ActiveDocument.addObject("Part::Feature","Wire")
                    newobj.Shape = w
                addList.append(newobj)
                deleteList.append(obj)
                return newobj
            else:
                return None

    def turnToParts(meshes):
        """turn given meshes to parts"""
        result = False
        import Arch
        for mesh in meshes:
            sh = Arch.getShapeFromMesh(mesh.Mesh)
            if sh:
                newobj = App.ActiveDocument.addObject("Part::Feature","Shell")
                newobj.Shape = sh
                addList.append(newobj)
                deleteList.append(mesh)
                result = True
        return result

    def makeFusion(obj1,obj2):
        """makes a Draft or Part fusion between 2 given objects"""
        newobj = fuse(obj1,obj2)
        if newobj:
            addList.append(newobj)
            return newobj
        return None

    def makeShell(objectslist):
        """makes a shell with the given objects"""
        params = App.ParamGet("User parameter:BaseApp/Preferences/Mod/Draft")
        preserveFaceColor = params.GetBool("preserveFaceColor") # True
        preserveFaceNames = params.GetBool("preserveFaceNames") # True
        faces = []
        facecolors = [[], []] if (preserveFaceColor) else None
        for obj in objectslist:
            faces.extend(obj.Shape.Faces)
            if (preserveFaceColor):
                """ at this point, obj.Shape.Faces are not in same order as the
                original faces we might have gotten as a result of downgrade, nor do they
                have the same hashCode(); but they still keep reference to their original
                colors - capture that in facecolors.
                Also, cannot w/ .ShapeColor here, need a whole array matching the colors
                of the array of faces per object, only DiffuseColor has that """
                facecolors[0].extend(obj.ViewObject.DiffuseColor)
                facecolors[1] = faces
        sh = Part.makeShell(faces)
        if sh:
            if sh.Faces:
                newobj = App.ActiveDocument.addObject("Part::Feature","Shell")
                newobj.Shape = sh
                if (preserveFaceNames):
                    import re
                    firstName = objectslist[0].Label
                    nameNoTrailNumbers = re.sub("\d+$", "", firstName)
                    newobj.Label = "{} {}".format(newobj.Label, nameNoTrailNumbers)
                if (preserveFaceColor):
                    """ At this point, sh.Faces are completely new, with different hashCodes
                    and different ordering from obj.Shape.Faces; since we cannot compare
                    via hashCode(), we have to iterate and use a different criteria to find
                    the original matching color """
                    colarray = []
                    for ind, face in enumerate(newobj.Shape.Faces):
                        for fcind, fcface in enumerate(facecolors[1]):
                            if ((face.Area == fcface.Area) and (face.CenterOfMass == fcface.CenterOfMass)):
                                colarray.append(facecolors[0][fcind])
                                break
                    newobj.ViewObject.DiffuseColor = colarray;
                addList.append(newobj)
                deleteList.extend(objectslist)
                return newobj
        return None

    def joinFaces(objectslist):
        """makes one big face from selected objects, if possible"""
        faces = []
        for obj in objectslist:
            faces.extend(obj.Shape.Faces)
        u = faces.pop(0)
        for f in faces:
            u = u.fuse(f)
        if DraftGeomUtils.isCoplanar(faces):
            u = DraftGeomUtils.concatenate(u)
            if not DraftGeomUtils.hasCurves(u):
                # several coplanar and non-curved faces: they can become a Draft wire
                newobj = makeWire(u.Wires[0],closed=True,face=True)
            else:
                # if not possible, we do a non-parametric union
                newobj = App.ActiveDocument.addObject("Part::Feature","Union")
                newobj.Shape = u
            addList.append(newobj)
            deleteList.extend(objectslist)
            return newobj
        return None

    def makeSketchFace(obj):
        """Makes a Draft face out of a sketch"""
        newobj = makeWire(obj.Shape,closed=True)
        if newobj:
            newobj.Base = obj
            obj.ViewObject.Visibility = False
            addList.append(newobj)
            return newobj
        return None

    def makeFaces(objectslist):
        """make a face from every closed wire in the list"""
        result = False
        for o in objectslist:
            for w in o.Shape.Wires:
                try:
                    f = Part.Face(w)
                except Part.OCCError:
                    pass
                else:
                    newobj = App.ActiveDocument.addObject("Part::Feature","Face")
                    newobj.Shape = f
                    addList.append(newobj)
                    result = True
                    if not o in deleteList:
                        deleteList.append(o)
        return result

    def makeWires(objectslist):
        """joins edges in the given objects list into wires"""
        edges = []
        for o in objectslist:
            for e in o.Shape.Edges:
                edges.append(e)
        try:
            nedges = Part.__sortEdges__(edges[:])
            # for e in nedges: print("debug: ",e.Curve,e.Vertexes[0].Point,e.Vertexes[-1].Point)
            w = Part.Wire(nedges)
        except Part.OCCError:
            return None
        else:
            if len(w.Edges) == len(edges):
                newobj = App.ActiveDocument.addObject("Part::Feature","Wire")
                newobj.Shape = w
                addList.append(newobj)
                deleteList.extend(objectslist)
                return True
        return None

    # analyzing what we have in our selection

    edges = []
    wires = []
    openwires = []
    faces = []
    groups = []
    parts = []
    curves = []
    facewires = []
    loneedges = []
    meshes = []
    for ob in objects:
        if ob.TypeId == "App::DocumentObjectGroup":
            groups.append(ob)
        elif hasattr(ob,'Shape'):
            parts.append(ob)
            faces.extend(ob.Shape.Faces)
            wires.extend(ob.Shape.Wires)
            edges.extend(ob.Shape.Edges)
            for f in ob.Shape.Faces:
                facewires.extend(f.Wires)
            wirededges = []
            for w in ob.Shape.Wires:
                if len(w.Edges) > 1:
                    for e in w.Edges:
                        wirededges.append(e.hashCode())
                if not w.isClosed():
                    openwires.append(w)
            for e in ob.Shape.Edges:
                if DraftGeomUtils.geomType(e) != "Line":
                    curves.append(e)
                if not e.hashCode() in wirededges:
                    loneedges.append(e)
        elif ob.isDerivedFrom("Mesh::Feature"):
            meshes.append(ob)
    objects = parts

    #print("objects:",objects," edges:",edges," wires:",wires," openwires:",openwires," faces:",faces)
    #print("groups:",groups," curves:",curves," facewires:",facewires, "loneedges:", loneedges)

    if force:
        if force in ["makeCompound","closeGroupWires","makeSolid","closeWire","turnToParts","makeFusion",
                     "makeShell","makeFaces","draftify","joinFaces","makeSketchFace","makeWires","turnToLine"]:
            result = eval(force)(objects)
        else:
            App.Console.PrintMessage(_tr("Upgrade: Unknown force method:")+" "+force)
            result = None

    else:

        # applying transformations automatically

        result = None

        # if we have a group: turn each closed wire inside into a face
        if groups:
            result = closeGroupWires(groups)
            if result:
                App.Console.PrintMessage(_tr("Found groups: closing each open object inside")+"\n")

        # if we have meshes, we try to turn them into shapes
        elif meshes:
            result = turnToParts(meshes)
            if result:
                App.Console.PrintMessage(_tr("Found mesh(es): turning into Part shapes")+"\n")

        # we have only faces here, no lone edges
        elif faces and (len(wires) + len(openwires) == len(facewires)):

            # we have one shell: we try to make a solid
            if (len(objects) == 1) and (len(faces) > 3):
                result = makeSolid(objects[0])
                if result:
                    App.Console.PrintMessage(_tr("Found 1 solidifiable object: solidifying it")+"\n")

            # we have exactly 2 objects: we fuse them
            elif (len(objects) == 2) and (not curves):
                result = makeFusion(objects[0],objects[1])
                if result:
                    App.Console.PrintMessage(_tr("Found 2 objects: fusing them")+"\n")

            # we have many separate faces: we try to make a shell
            elif (len(objects) > 2) and (len(faces) > 1) and (not loneedges):
                result = makeShell(objects)
                if result:
                    App.Console.PrintMessage(_tr("Found several objects: creating a shell")+"\n")

            # we have faces: we try to join them if they are coplanar
            elif len(faces) > 1:
                result = joinFaces(objects)
                if result:
                    App.Console.PrintMessage(_tr("Found several coplanar objects or faces: creating one face")+"\n")

            # only one object: if not parametric, we "draftify" it
            elif len(objects) == 1 and (not objects[0].isDerivedFrom("Part::Part2DObjectPython")):
                result = draftify(objects[0])
                if result:
                    App.Console.PrintMessage(_tr("Found 1 non-parametric objects: draftifying it")+"\n")

        # we have only one object that contains one edge
        elif (not faces) and (len(objects) == 1) and (len(edges) == 1):
            # we have a closed sketch: Extract a face
            if objects[0].isDerivedFrom("Sketcher::SketchObject") and (len(edges[0].Vertexes) == 1):
                result = makeSketchFace(objects[0])
                if result:
                    App.Console.PrintMessage(_tr("Found 1 closed sketch object: creating a face from it")+"\n")
            else:
                # turn to Draft line
                e = objects[0].Shape.Edges[0]
                if isinstance(e.Curve,(Part.LineSegment,Part.Line)):
                    result = turnToLine(objects[0])
                    if result:
                        App.Console.PrintMessage(_tr("Found 1 linear object: converting to line")+"\n")

        # we have only closed wires, no faces
        elif wires and (not faces) and (not openwires):

            # we have a sketch: Extract a face
            if (len(objects) == 1) and objects[0].isDerivedFrom("Sketcher::SketchObject"):
                result = makeSketchFace(objects[0])
                if result:
                    App.Console.PrintMessage(_tr("Found 1 closed sketch object: creating a face from it")+"\n")

            # only closed wires
            else:
                result = makeFaces(objects)
                if result:
                    App.Console.PrintMessage(_tr("Found closed wires: creating faces")+"\n")

        # special case, we have only one open wire. We close it, unless it has only 1 edge!"
        elif (len(openwires) == 1) and (not faces) and (not loneedges):
            result = closeWire(objects[0])
            if result:
                App.Console.PrintMessage(_tr("Found 1 open wire: closing it")+"\n")

        # only open wires and edges: we try to join their edges
        elif openwires and (not wires) and (not faces):
            result = makeWires(objects)
            if result:
                App.Console.PrintMessage(_tr("Found several open wires: joining them")+"\n")

        # only loneedges: we try to join them
        elif loneedges and (not facewires):
            result = makeWires(objects)
            if result:
                App.Console.PrintMessage(_tr("Found several edges: wiring them")+"\n")

        # all other cases, if more than 1 object, make a compound
        elif (len(objects) > 1):
            result = makeCompound(objects)
            if result:
                App.Console.PrintMessage(_tr("Found several non-treatable objects: creating compound")+"\n")

        # no result has been obtained
        if not result:
            App.Console.PrintMessage(_tr("Unable to upgrade these objects.")+"\n")

    if delete:
        names = []
        for o in deleteList:
            names.append(o.Name)
        deleteList = []
        for n in names:
            App.ActiveDocument.removeObject(n)
    gui_utils.select(addList)
    return [addList,deleteList]
示例#38
0
    def buildpathocc(self, obj, shape):
        """Build pocket Path using Native OCC algorithm."""
        import Part
        import DraftGeomUtils
        from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge, depth_params

        FreeCAD.Console.PrintMessage(translate("PathPocket", "Generating toolpath with OCC native offsets.\n"))
        extraoffset = obj.MaterialAllowance.Value

        # Build up the offset loops
        output = ""
        if obj.Comment != "":
            output += '(' + str(obj.Comment)+')\n'
        output += 'G0 Z' + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"

        offsets = []
        nextradius = self.radius + extraoffset
        result = DraftGeomUtils.pocket2d(shape, nextradius)
        while result:
            offsets.extend(result)
            nextradius += (self.radius * 2) * (float(obj.StepOver)/100)
            result = DraftGeomUtils.pocket2d(shape, nextradius)

        # revert the list so we start with the outer wires
        if obj.StartAt != 'Edge':
            offsets.reverse()

        plungePos = None
        rampEdge = None
        if obj.UseEntry:
            # Try to find an entry location
            toold = self.radius*2
            helixBounds = DraftGeomUtils.pocket2d(shape, self.radius * (1 + obj.HelixSize))

            if helixBounds:
                rampD = obj.RampSize

                if obj.StartAt == 'Edge':
                    plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                else:
                    plungePos = offsets[0].Edges[0].Vertexes[0].Point

                    # If it turns out this is invalid for some reason, nuke plungePos
                    [perp, idx] = DraftGeomUtils.findPerpendicular(plungePos, shape.Edges)
                    if not perp or perp.Length < self.radius * (1 + obj.HelixSize):
                        plungePos = None
                        FreeCAD.Console.PrintError(translate("PathPocket", "Helical Entry location not found.\n"))
                    # FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
                    # Or some math to prove that it has to be (doubt that's true)
                    # Maybe reverse helixBounds and pick off that?

            if plungePos is None:  # If we didn't find a place to helix, how about a ramp?
                FreeCAD.Console.PrintMessage(translate("PathPocket", "Attempting ramp entry.\n"))
                if (offsets[0].Edges[0].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[0]
                # The last edge also connects with the starting location- try that
                elif (offsets[0].Edges[-1].Length >= toold * rampD) and not (isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[-1]
                else:
                    FreeCAD.Console.PrintError(translate("PathPocket", "Ramp Entry location not found.\n"))
                    # print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
                    # FIXME: There's got to be a smarter way to find a place to ramp

        # For helix-ing/ramping, know where we were last time
        # FIXME: Can probably get this from the "machine"?
        lastZ = obj.ClearanceHeight.Value

        startPoint = None

        depthparams = depth_params(
                obj.ClearanceHeight.Value,
                obj.SafeHeight.Value,
                obj.StartDepth.Value,
                obj.StepDown,
                obj.FinishDepth.Value,
                obj.FinalDepth.Value)

        for vpos in depthparams.get_depths():

            first = True
            # loop over successive wires
            for currentWire in offsets:
                last = None
                for edge in currentWire.Edges:
                    if not last:
                        # we set the base GO to our fast move to our starting pos
                        if first:
                            # If we can helix, do so
                            if plungePos:
                                output += helicalPlunge(plungePos, obj.RampAngle, vpos, lastZ, self.radius*2, obj.HelixSize, self.horizFeed)
                                lastZ = vpos
                            # Otherwise, see if we can ramp
                            # FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
                            elif rampEdge:
                                output += rampPlunge(rampEdge, obj.RampAngle, vpos, lastZ)
                                lastZ = vpos
                            # Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
                            # FIXME: At least not with the lazy ramp programming above...
                            else:
                                print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
                                startPoint = edge.Vertexes[0].Point
                                output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
                                output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\
                                          " Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.horizRapid) + "\n"
                            first = False
                        # then move slow down to our starting point for our profile
                        last = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(last.x) + " Y" + fmt(last.y) + " Z" + fmt(vpos) + " F" + fmt(self.vertFeed) + "\n"
                    if DraftGeomUtils.geomType(edge) == "Circle":
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        center = edge.Curve.Center
                        relcenter = center.sub(last)
                        v1 = last.sub(center)
                        v2 = point.sub(center)
                        if v1.cross(v2).z < 0:
                            output += "G2"
                        else:
                            output += "G3"
                        output += " X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos)
                        output += " I" + fmt(relcenter.x) + " J" + fmt(relcenter.y) + " K" + fmt(relcenter.z)  + " F" + fmt(self.horizFeed) 
                        output += "\n"
                        last = point
                    else:
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(point.x) + " Y" + fmt(point.y) + " Z" + fmt(vpos) + " F" + fmt(self.horizFeed)  + "\n"
                        last = point

        # move back up
        output += "G0 Z" + fmt(obj.ClearanceHeight.Value) + "F " + PathUtils.fmt(self.vertRapid) + "\n"
        return output
示例#39
0
    def buildpathocc(self, obj, shape):
        """Build pocket Path using Native OCC algorithm."""
        import Part
        import DraftGeomUtils
        from PathScripts.PathUtils import fmt, helicalPlunge, rampPlunge

        FreeCAD.Console.PrintMessage(
            translate("PathPocket",
                      "Generating toolpath with OCC native offsets.\n"))

        # Build up the offset loops
        output = ""
        offsets = []
        nextradius = (self.radius * 2) * (float(obj.StepOver) / 100)
        result = DraftGeomUtils.pocket2d(shape, nextradius)
        print "did we get something: " + str(result)
        while result:
            print "Adding " + str(len(result)) + " wires"
            offsets.extend(result)
            nextradius += (self.radius * 2) * (float(obj.StepOver) / 100)
            result = DraftGeomUtils.pocket2d(shape, nextradius)

        # revert the list so we start with the outer wires
        if obj.StartAt != 'Edge':
            offsets.reverse()

        plungePos = None
        rampEdge = None
        if obj.UseEntry:
            # Try to find an entry location
            toold = self.radius * 2
            helixBounds = DraftGeomUtils.pocket2d(
                shape, self.radius * (1 + obj.HelixSize))

            if helixBounds:
                rampD = obj.RampSize

                if obj.StartAt == 'Edge':
                    plungePos = helixBounds[0].Edges[0].Vertexes[0].Point
                else:
                    plungePos = offsets[0].Edges[0].Vertexes[0].Point

                    # If it turns out this is invalid for some reason, nuke plungePos
                    [perp, idx] = DraftGeomUtils.findPerpendicular(
                        plungePos, shape.Edges)
                    if not perp or perp.Length < self.radius * (1 +
                                                                obj.HelixSize):
                        plungePos = None
                        FreeCAD.Console.PrintError(
                            translate("PathPocket",
                                      "Helical Entry location not found.\n"))
                    # FIXME: Really need to do a point-in-polygon operation to make sure this is within helixBounds
                    # Or some math to prove that it has to be (doubt that's true)
                    # Maybe reverse helixBounds and pick off that?

            if plungePos is None:  # If we didn't find a place to helix, how about a ramp?
                FreeCAD.Console.PrintMessage(
                    translate("PathPocket", "Attempting ramp entry.\n"))
                if (offsets[0].Edges[0].Length >= toold * rampD) and not (
                        isinstance(offsets[0].Edges[0].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[0]
                # The last edge also connects with the starting location- try that
                elif (offsets[0].Edges[-1].Length >= toold * rampD) and not (
                        isinstance(offsets[0].Edges[-1].Curve, Part.Circle)):
                    rampEdge = offsets[0].Edges[-1]
                else:
                    FreeCAD.Console.PrintError(
                        translate("PathPocket",
                                  "Ramp Entry location not found.\n"))
                    # print "Neither edge works: " + str(offsets[0].Edges[0]) + ", " + str(offsets[0].Edges[-1])
                    # FIXME: There's got to be a smarter way to find a place to ramp

        fastZPos = obj.ClearanceHeight.Value

        # For helix-ing/ramping, know where we were last time
        # FIXME: Can probably get this from the "machine"?
        lastZ = fastZPos

        startPoint = None

        for vpos in PathUtils.frange(obj.StartDepth.Value,
                                     obj.FinalDepth.Value, obj.StepDown,
                                     obj.FinishDepth.Value):
            first = True
            # loop over successive wires
            for currentWire in offsets:
                #output += PathUtils.convert(currentWire.Edges, "on", 1)
                last = None
                for edge in currentWire.Edges:
                    if not last:
                        # we set the base GO to our fast move to our starting pos
                        if first:
                            # If we can helix, do so
                            if plungePos:
                                output += helicalPlunge(
                                    plungePos, obj.RampAngle, vpos, lastZ,
                                    self.radius * 2, obj.HelixSize,
                                    self.horizFeed)
                                # print output
                                lastZ = vpos
                            # Otherwise, see if we can ramp
                            # FIXME: This could be a LOT smarter (eg, searching for a longer leg of the edge to ramp along)
                            elif rampEdge:
                                output += rampPlunge(rampEdge, obj.RampAngle,
                                                     vpos, lastZ)
                                lastZ = vpos
                            # Otherwise, straight plunge... Don't want to, but sometimes you might not have a choice.
                            # FIXME: At least not with the lazy ramp programming above...
                            else:
                                print "WARNING: Straight-plunging... probably not good, but we didn't find a place to helix or ramp"
                                startPoint = edge.Vertexes[0].Point
                                output += "G0 X" + fmt(startPoint.x) + " Y" + fmt(startPoint.y) +\
                                          " Z" + fmt(fastZPos) + "\n"
                            first = False
                        # then move slow down to our starting point for our profile
                        last = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(last.x) + " Y" + fmt(
                            last.y) + " Z" + fmt(vpos) + "\n"
                    # if isinstance(edge.Curve,Part.Circle):
                    if DraftGeomUtils.geomType(edge) == "Circle":
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        center = edge.Curve.Center
                        relcenter = center.sub(last)
                        v1 = last.sub(center)
                        v2 = point.sub(center)
                        if v1.cross(v2).z < 0:
                            output += "G2"
                        else:
                            output += "G3"
                        output += " X" + fmt(point.x) + " Y" + fmt(
                            point.y) + " Z" + fmt(vpos)
                        output += " I" + fmt(relcenter.x) + " J" + fmt(
                            relcenter.y) + " K" + fmt(relcenter.z)
                        output += "\n"
                        last = point
                    else:
                        point = edge.Vertexes[-1].Point
                        if point == last:  # edges can come flipped
                            point = edge.Vertexes[0].Point
                        output += "G1 X" + fmt(point.x) + " Y" + fmt(
                            point.y) + " Z" + fmt(vpos) + "\n"
                        last = point

        # move back up
        output += "G1 Z" + fmt(fastZPos) + "\n"
        return output
示例#40
0
    def snapToExtensions(self,point,last,constrain,eline):
        "returns a point snapped to extension or parallel line to last object, if any"

        if self.isEnabled("extension"):
            tsnap = self.snapToExtOrtho(last,constrain,eline)
            if tsnap:
                if (tsnap[0].sub(point)).Length < self.radius:
                    if self.tracker:
                        self.tracker.setCoords(tsnap[2])
                        self.tracker.setMarker(self.mk[tsnap[1]])
                        self.tracker.on()
                    if self.extLine:
                        self.extLine.p2(tsnap[2])
                        self.extLine.on()
                    self.setCursor(tsnap[1])
                    return tsnap[2],eline
            else:
                tsnap = self.snapToExtPerpendicular(last)
                if tsnap:
                    if (tsnap[0].sub(point)).Length < self.radius:
                        if self.tracker:
                            self.tracker.setCoords(tsnap[2])
                            self.tracker.setMarker(self.mk[tsnap[1]])
                            self.tracker.on()
                        if self.extLine:
                            self.extLine.p2(tsnap[2])
                            self.extLine.on()
                        self.setCursor(tsnap[1])
                        return tsnap[2],eline
                
        for o in [self.lastObj[1],self.lastObj[0]]:
            if o:
                ob = FreeCAD.ActiveDocument.getObject(o)
                if ob:
                    if ob.isDerivedFrom("Part::Feature"):
                        edges = ob.Shape.Edges
                        if (not self.maxEdges) or (len(edges) <= self.maxEdges):
                            for e in edges:
                                if DraftGeomUtils.geomType(e) == "Line":
                                    np = self.getPerpendicular(e,point)
                                    if not DraftGeomUtils.isPtOnEdge(np,e):
                                        if (np.sub(point)).Length < self.radius:
                                            if self.isEnabled('extension'):
                                                if np != e.Vertexes[0].Point:
                                                    if self.tracker:
                                                        self.tracker.setCoords(np)
                                                        self.tracker.setMarker(self.mk['extension'])
                                                        self.tracker.on()
                                                    if self.extLine:
                                                        self.extLine.p1(e.Vertexes[0].Point)
                                                        self.extLine.p2(np)
                                                        self.extLine.on()
                                                    self.setCursor('extension')
                                                    return np,Part.Line(e.Vertexes[0].Point,np).toShape()
                                        else:
                                            if self.isEnabled('parallel'):
                                                if last:
                                                    ve = DraftGeomUtils.vec(e)
                                                    if not DraftVecUtils.isNull(ve):
                                                        de = Part.Line(last,last.add(ve)).toShape()  
                                                        np = self.getPerpendicular(de,point)
                                                        if (np.sub(point)).Length < self.radius:
                                                            if self.tracker:
                                                                self.tracker.setCoords(np)
                                                                self.tracker.setMarker(self.mk['parallel'])
                                                                self.tracker.on()
                                                            self.setCursor('parallel')
                                                            return np,de
        return point,eline