Ejemplo n.º 1
0
    def update_object_from_edit_points(self, obj, node_idx, v, alt_edit_mode=0):
        """Update the object from modified Draft_Edit point.
        No need to recompute at the end.

        Parameters:
        obj: the object
        node_idx: number of the edited node
        v: target vector of the node in object local coordinates system
        alt_edit_mode: alternative edit mode to perform different operations
                       (usually can be selected from the Draft_Edit context menu)
                       default = 0
        """
        if alt_edit_mode == 0:
            # trim/extend endpoint
            if node_idx == 0:
                obj.Proxy.set_first_point(obj, v, local=True)
            elif node_idx == 1:
                obj.Proxy.set_last_point(obj, v, local=True)

        elif alt_edit_mode == 1:
            # rotate wall on the opposite endpoint (context menu "align")
            import Draft
            global_v = obj.getGlobalPlacement().multVec(v)
            p1 = obj.Proxy.get_first_point(obj)
            p2 = obj.Proxy.get_last_point(obj)
            if node_idx == 0:
                current_angle = DraftVecUtils.angle(App.Vector(1,0,0), p1.sub(p2))
                new_angle = DraftVecUtils.angle(App.Vector(1,0,0), global_v.sub(p2))
                Draft.rotate(obj, math.degrees(new_angle - current_angle), p2)
                # obj.Proxy.set_first_point(obj, global_v) # this causes frequent hard crashes, probably to delay
            elif node_idx == 1:
                current_angle = DraftVecUtils.angle(App.Vector(1,0,0), p2.sub(p1))
                new_angle = DraftVecUtils.angle(App.Vector(1,0,0), global_v.sub(p1))
                Draft.rotate(obj, math.degrees(new_angle - current_angle), p1)
Ejemplo n.º 2
0
 def createObject(self):
     """Create the final object in the current document."""
     plane = App.DraftWorkingPlane
     p1 = self.node[0]
     p3 = self.node[-1]
     diagonal = p3.sub(p1)
     p2 = p1.add(DraftVecUtils.project(diagonal, plane.v))
     p4 = p1.add(DraftVecUtils.project(diagonal, plane.u))
     length = p4.sub(p1).Length
     if abs(DraftVecUtils.angle(p4.sub(p1), plane.u, plane.axis)) > 1:
         length = -length
     height = p2.sub(p1).Length
     if abs(DraftVecUtils.angle(p2.sub(p1), plane.v, plane.axis)) > 1:
         height = -height
     try:
         # The command to run is built as a series of text strings
         # to be committed through the `draftutils.todo.ToDo` class.
         rot, sup, pts, fil = self.getStrings()
         base = p1
         if length < 0:
             length = -length
             base = base.add((p1.sub(p4)).negative())
         if height < 0:
             height = -height
             base = base.add((p1.sub(p2)).negative())
         Gui.addModule("Draft")
         if utils.getParam("UsePartPrimitives", False):
             # Insert a Part::Primitive object
             _cmd = 'FreeCAD.ActiveDocument.'
             _cmd += 'addObject("Part::Plane", "Plane")'
             _cmd_list = [
                 'plane = ' + _cmd, 'plane.Length = ' + str(length),
                 'plane.Width = ' + str(height), 'pl = FreeCAD.Placement()',
                 'pl.Rotation.Q=' + rot,
                 'pl.Base = ' + DraftVecUtils.toString(base),
                 'plane.Placement = pl', 'Draft.autogroup(plane)',
                 'FreeCAD.ActiveDocument.recompute()'
             ]
             self.commit(translate("draft", "Create Plane"), _cmd_list)
         else:
             _cmd = 'Draft.makeRectangle'
             _cmd += '('
             _cmd += 'length=' + str(length) + ', '
             _cmd += 'height=' + str(height) + ', '
             _cmd += 'placement=pl, '
             _cmd += 'face=' + fil + ', '
             _cmd += 'support=' + sup
             _cmd += ')'
             _cmd_list = [
                 'pl = FreeCAD.Placement()', 'pl.Rotation.Q = ' + rot,
                 'pl.Base = ' + DraftVecUtils.toString(base),
                 'rec = ' + _cmd, 'Draft.autogroup(rec)',
                 'FreeCAD.ActiveDocument.recompute()'
             ]
             self.commit(translate("draft", "Create Rectangle"), _cmd_list)
     except Exception:
         _err("Draft: error delaying commit")
     self.finish(cont=True)
Ejemplo n.º 3
0
 def create(self):
     """Create the actual object."""
     if len(self.node) == 3:
         targetpoint = self.node[0]
         basepoint = self.node[2]
         v = self.node[2].sub(self.node[1])
         dist = v.Length
         if hasattr(App, "DraftWorkingPlane"):
             h = App.DraftWorkingPlane.u
             n = App.DraftWorkingPlane.axis
             r = App.DraftWorkingPlane.getRotation().Rotation
         else:
             h = App.Vector(1, 0, 0)
             n = App.Vector(0, 0, 1)
             r = App.Rotation()
         if abs(DraftVecUtils.angle(v, h, n)) <= math.pi / 4:
             direction = "Horizontal"
             dist = -dist
         elif abs(DraftVecUtils.angle(v, h, n)) >= math.pi * 3 / 4:
             direction = "Horizontal"
         elif DraftVecUtils.angle(v, h, n) > 0:
             direction = "Vertical"
         else:
             direction = "Vertical"
             dist = -dist
         tp = "targetpoint=FreeCAD." + str(targetpoint) + ", "
         sel = ""
         if self.sel:
             if self.sel.SubElementNames:
                 sub = "'" + self.sel.SubElementNames[0] + "'"
             else:
                 sub = "()"
             sel = "target="
             sel += "("
             sel += "FreeCAD.ActiveDocument." + self.sel.Object.Name + ", "
             sel += sub
             sel += "),"
         pl = "placement=FreeCAD.Placement"
         pl += "("
         pl += "FreeCAD." + str(basepoint) + ", "
         pl += "FreeCAD.Rotation" + str(r.Q)
         pl += ")"
         App.ActiveDocument.openTransaction("Create Label")
         Gui.addModule("Draft")
         _cmd = "Draft.makeLabel"
         _cmd += "("
         _cmd += tp
         _cmd += sel
         _cmd += "direction='" + direction + "', "
         _cmd += "distance=" + str(dist) + ", "
         _cmd += "labeltype='" + self.labeltype + "', "
         _cmd += pl
         _cmd += ")"
         Gui.doCommand("l = " + _cmd)
         Gui.doCommand("Draft.autogroup(l)")
         App.ActiveDocument.recompute()
         App.ActiveDocument.commitTransaction()
     self.finish()
Ejemplo n.º 4
0
def measure_two_obj_angles(link_sub_1, link_sub_2):
    """Measure two edges from two different objects to measure the angle.

    This function is a prototype because it does not determine all possible
    starting and ending angles that could be used to draw the dimension line,
    which is a circular arc.

    Parameters
    ----------
    link_sub_1: tuple
        A tuple containing one object and a list of subelement strings,
        which may be empty. Only the first subelement is considered, which
        must be an edge.
        ::
            link_sub_1 = (obj1, ['EdgeN', ...])

    link_sub_2: tuple
        Same.
    """
    start = 0
    end = 0

    obj1 = link_sub_1[0]
    lsub1 = link_sub_1[1]

    obj2 = link_sub_2[0]
    lsub2 = link_sub_2[1]

    # The subelement list may be empty so we test it first
    # and pick only the first item
    if lsub1 and lsub2:
        subelement1 = lsub1[0]
        subelement2 = lsub2[0]

        if "Edge" in subelement1 and "Edge" in subelement2:
            n1 = int(subelement1[4:]) - 1
            n2 = int(subelement2[4:]) - 1
            start = obj1.Shape.Edges[n1].Curve.Direction
            end = obj2.Shape.Edges[n2].Curve.Direction

            # We get the angle from the direction of the line to the U axis
            # of the working plane; we should be able to also use the V axis
            start_r = DraftVecUtils.angle(start, App.DraftWorkingPlane.u)
            end_r = DraftVecUtils.angle(end, App.DraftWorkingPlane.u)
            start = math.degrees(start_r)
            end = math.degrees(end_r)

            # We make the angle positive because when tested, some errors
            # were produced in the code that calculates the 'Angle'.
            # This code is actually inside the viewprovider.
            if start < 0:
                start = abs(start)
            if end < 0:
                end = abs(end)

    return start, end
Ejemplo n.º 5
0
    def getCurveSet(ent):
        result = []
        if ent.is_a() in ["IfcGeometricCurveSet", "IfcGeometricSet"]:
            elts = ent.Elements
        elif ent.is_a() in [
                "IfcLine", "IfcPolyline", "IfcCircle", "IfcTrimmedCurve"
        ]:
            elts = [ent]
        for el in elts:
            if el.is_a("IfcPolyline"):
                result.append(getPolyline(el))
            elif el.is_a("IfcLine"):
                result.append(getLine(el))
            elif el.is_a("IfcCircle"):
                result.append(getCircle(el))
            elif el.is_a("IfcTrimmedCurve"):
                base = el.BasisCurve
                t1 = el.Trim1[0].wrappedValue
                t2 = el.Trim2[0].wrappedValue
                if not el.SenseAgreement:
                    t1, t2 = t2, t1
                if base.is_a("IfcPolyline"):
                    bc = getPolyline(base)
                    result.append(bc)
                elif base.is_a("IfcCircle"):
                    bc = getCircle(base)
                    e = Part.ArcOfCircle(bc.Curve, math.radians(t1),
                                         math.radians(t2)).toShape()
                    d = base.Position.RefDirection.DirectionRatios
                    v = FreeCAD.Vector(d[0], d[1], d[2] if len(d) > 2 else 0)
                    a = -DraftVecUtils.angle(v)
                    e.rotate(bc.Curve.Center, FreeCAD.Vector(0, 0, 1),
                             math.degrees(a))
                    result.append(e)
            elif el.is_a("IfcCompositeCurve"):
                for base in el.Segments:
                    if base.ParentCurve.is_a("IfcPolyline"):
                        bc = getPolyline(base.ParentCurve)
                        result.append(bc)
                    elif base.ParentCurve.is_a("IfcCircle"):
                        bc = getCircle(base.ParentCurve)
                        e = Part.ArcOfCircle(bc.Curve, math.radians(t1),
                                             math.radians(t2)).toShape()
                        d = base.Position.RefDirection.DirectionRatios
                        v = FreeCAD.Vector(d[0], d[1],
                                           d[2] if len(d) > 2 else 0)
                        a = -DraftVecUtils.angle(v)
                        e.rotate(bc.Curve.Center, FreeCAD.Vector(0, 0, 1),
                                 math.degrees(a))
                        result.append(e)

        return result
Ejemplo n.º 6
0
def get_perpendicular_tuples(faces):
    listeCouple = []
    lenfaces = len(faces)
    faces.append(faces[0])
    for n in range(lenfaces):
        norm2 = faces[n + 1].normalAt(0, 0)
        norm1 = faces[n].normalAt(0, 0)
        norm0 = faces[n - 1].normalAt(0, 0)
        if abs(round(math.degrees(DraftVecUtils.angle(norm1, norm0)))) == 90.0:
            listeCouple.append([faces[n], faces[n - 1]])
        if abs(round(math.degrees(DraftVecUtils.angle(norm1, norm2)))) == 90.0:
            listeCouple.append([faces[n], faces[n + 1]])
    return listeCouple
Ejemplo n.º 7
0
 def getCoupleFacesEquerre(self, faces):
     listeCouple = []
     lenfaces = len(faces)
     faces.append(faces[0])
     for n in range(lenfaces):
         norm2 = faces[n+1].normalAt(0,0)
         norm1 = faces[n].normalAt(0,0)
         norm0 = faces[n-1].normalAt(0,0)
         if abs(round(math.degrees(DraftVecUtils.angle(norm1,norm0)))) == 90.:
             listeCouple.append([faces[n],faces[n-1]])
         if abs(round(math.degrees(DraftVecUtils.angle(norm1,norm2)))) == 90.:
             listeCouple.append([faces[n],faces[n+1]])
     return listeCouple
Ejemplo n.º 8
0
    def handle_mouse_move_event(self, arg):
        """Handle the mouse when moving."""
        plane = App.DraftWorkingPlane

        for ghost in self.ghosts:
            ghost.off()
        self.point, ctrlPoint, info = gui_tool_utils.getPoint(self, arg)
        # this is to make sure radius is what you see on screen
        if self.center and DraftVecUtils.dist(self.point, self.center):
            viewdelta = DraftVecUtils.project(self.point.sub(self.center),
                                              plane.axis)
            if not DraftVecUtils.isNull(viewdelta):
                self.point = self.point.add(viewdelta.negative())
        if self.extendedCopy:
            if not gui_tool_utils.hasMod(arg, gui_tool_utils.MODALT):
                self.step = 3
                self.finish()
        if self.step == 0:
            pass
        elif self.step == 1:
            currentrad = DraftVecUtils.dist(self.point, self.center)
            if currentrad != 0:
                angle = DraftVecUtils.angle(plane.u,
                                            self.point.sub(self.center),
                                            plane.axis)
            else:
                angle = 0
            self.ui.setRadiusValue(math.degrees(angle), unit="Angle")
            self.firstangle = angle
            self.ui.radiusValue.setFocus()
            self.ui.radiusValue.selectAll()
        elif self.step == 2:
            currentrad = DraftVecUtils.dist(self.point, self.center)
            if currentrad != 0:
                angle = DraftVecUtils.angle(plane.u,
                                            self.point.sub(self.center),
                                            plane.axis)
            else:
                angle = 0
            if angle < self.firstangle:
                sweep = (2 * math.pi - self.firstangle) + angle
            else:
                sweep = angle - self.firstangle
            self.arctrack.setApertureAngle(sweep)
            for ghost in self.ghosts:
                ghost.rotate(plane.axis, sweep)
                ghost.on()
            self.ui.setRadiusValue(math.degrees(sweep), 'Angle')
            self.ui.radiusValue.setFocus()
            self.ui.radiusValue.selectAll()
        gui_tool_utils.redraw3DView()
Ejemplo n.º 9
0
    def T_join(self, wall, target, idx): 
        """ Compute wall angles according to given parameters """
        print("--------\n"+"T_Join "+wall.Name + " with " +target.Name+ "\n")

        if idx == 0:
            w1 = wall.Proxy.get_first_point(wall)
            w2 = wall.Proxy.get_last_point(wall)
        elif idx == 1:
            w1 = wall.Proxy.get_last_point(wall)
            w2 = wall.Proxy.get_first_point(wall)

        t1 = target.Proxy.get_first_point(target)
        t2 = target.Proxy.get_last_point(target)

        angle = math.degrees(DraftVecUtils.angle(w2-w1,t2-t1))
        # print(angle)

        # identify if the function have to join the first or the end of the wall
        if idx == 0:
            wall.FirstCoreInnerAngle = angle
            wall.FirstCoreOuterAngle = -angle
            wall.FirstCoreOffset = - abs(target.Width / 2 / math.cos(math.pi / 2 - math.radians(angle)))
        elif idx == 1:
            wall.LastCoreInnerAngle = -angle
            wall.LastCoreOuterAngle = angle
            wall.LastCoreOffset = - abs(target.Width / 2 / math.cos(math.pi / 2 - math.radians(angle)))

        if not wall.Name in target.IncomingTJoins:
            target_list = target.IncomingTJoins
            target_list.append(wall.Name)
            target.IncomingTJoins = target_list
Ejemplo n.º 10
0
    def getIncidentAngle(self, queue):
        global currLocation
        '''returns in the incident angle in radians between the current and previous moves'''
        # get the vector of the last move
        if queue[1].Name in arccommands:
            print queue
            print currLocation
            arcLoc = FreeCAD.Base.Vector(queue[2].X + queue[1].I, queue[2].Y + queue[1].J, currLocation['Z'])
            radvector = queue[1].Placement.Base.sub(arcLoc)  # vector of chord from center to point
            # vector of line perp to chord.
            v1 = radvector.cross(FreeCAD.Base.Vector(0, 0, 1))
        else:
            v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base)

        # get the vector of the current move
        if queue[0].Name in arccommands:
            arcLoc = FreeCAD.Base.Vector((queue[1].x + queue[0].I), (queue[1].y + queue[0].J), currLocation['Z'])
            radvector = queue[1].Placement.Base.sub(arcLoc)  # calculate arcangle

            v2 = radvector.cross(FreeCAD.Base.Vector(0, 0, 1))

            # if switching between G2 and G3, reverse orientation
            if queue[1].Name in arccommands:
                if queue[0].Name != queue[1].Name:
                    v2 = D.rotate2D(v2, math.radians(180))
        else:
            v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base)

        incident_angle = D.angle(v1, v2, FreeCAD.Base.Vector(0, 0, -1))
        return incident_angle
Ejemplo n.º 11
0
def orientEdge(edge, normal=None, make_arc=False):
    """Re-orient the edge such that it is in the XY plane.

    Re-orients `edge` such that it is in the XY plane.
    If `normal` is passed, this is used as the basis for the rotation,
    otherwise the placement of `edge` is used.
    """
    # This 'normalizes' the placement to the xy plane
    edge = edge.copy()
    xyDir = App.Vector(0, 0, 1)
    base = App.Vector(0, 0, 0)

    if normal:
        angle = DraftVecUtils.angle(normal, xyDir) * App.Units.Radian
        axis = normal.cross(xyDir)
    else:
        axis = edge.Placement.Rotation.Axis
        angle = -1 * edge.Placement.Rotation.Angle * App.Units.Radian
    if axis == App.Vector(0.0, 0.0, 0.0):
        axis = App.Vector(0.0, 0.0, 1.0)
    if angle:
        edge.rotate(base, axis, angle)
    if isinstance(edge.Curve, Part.Line):
        return Part.LineSegment(edge.Curve, edge.FirstParameter,
                                edge.LastParameter)
    elif make_arc and isinstance(edge.Curve, Part.Circle) and not edge.Closed:
        return Part.ArcOfCircle(edge.Curve, edge.FirstParameter,
                                edge.LastParameter, edge.Curve.Axis.z > 0)
    elif make_arc and isinstance(edge.Curve, Part.Ellipse) and not edge.Closed:
        return Part.ArcOfEllipse(edge.Curve, edge.FirstParameter,
                                 edge.LastParameter, edge.Curve.Axis.z > 0)
    return edge.Curve
Ejemplo n.º 12
0
 def getAngle(self, pt):
     "returns the angle of a given vector"
     c = self.trans.translation.getValue()
     center = Vector(c[0], c[1], c[2])
     base = FreeCAD.DraftWorkingPlane.u
     rad = pt.sub(center)
     return (DraftVecUtils.angle(rad, base, FreeCAD.DraftWorkingPlane.axis))
Ejemplo n.º 13
0
    def getDeviation(self):
        """Return the angle between the u axis and the horizontal plane.

        It defines a projection of `u` on the horizontal plane
        (without a Z component), and then measures the angle between
        this projection and `u`.

        It also considers the cross product of the projection
        and `u` to determine the sign of the angle.

        Returns
        -------
        float
            Angle between the `u` vector, and a projected vector
            on the global horizontal plane.

        See also
        --------
        DraftVecUtils.angle
        """
        proj = Vector(self.u.x, self.u.y, 0)
        if self.u.getAngle(proj) == 0:
            return 0
        else:
            norm = proj.cross(self.u)
            return DraftVecUtils.angle(self.u, proj, norm)
Ejemplo n.º 14
0
def makeWallFromPoints(p1,
                       p2,
                       width=None,
                       height=None,
                       align="Center",
                       name="Wall"):
    '''makeWall([obj],[length],[width],[height],[align],[face],[name]): creates a wall based on the
    given object, which can be a sketch, a draft object, a face or a solid, or no object at
    all, then you must provide length, width and height. Align can be "Center","Left" or "Right",
    face can be an index number of a face in the base object to base the wall on.'''

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

    # Add a Wall object to the docume
    # TODO: verify if it's necessary to split this in 2 to have the 'if App.GuiUp:'
    # guard for the viewprovider
    obj = App.ActiveDocument.addObject('Part::FeaturePython', 'Wall', Wall(),
                                       ViewProviderWall(), True)

    # Align the wall to the given point
    obj.Placement.Base = p1
    length = p1.distanceToPoint(p2)
    angle = DraftVecUtils.angle(p2 - p1, App.Vector(1, 0, 0))
    obj.Placement.Rotation.Angle = -angle
    obj.AxisLastPointX = length

    # Set the wall properties
    obj.Width = width
    obj.Height = height

    App.ActiveDocument.recompute()

    return obj
Ejemplo n.º 15
0
def getRoundEdgeSVG(edge, view_plane, stroke_width, stroke_color):
    """getRoundEdgeSVG(Edge, ViewPlane, StrokeWidth, StrokeColor):
    Returns round corner edge svg with given radius.
    """
    p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point, view_plane)
    p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point, view_plane)
    t1 = edge.tangentAt(edge.FirstParameter)
    t2 = edge.tangentAt(edge.FirstParameter +
                        (edge.LastParameter - edge.FirstParameter) / 10)
    flag_sweep = int(DraftVecUtils.angle(t1, t2, view_plane.axis) < 0)
    radius = edge.Curve.Radius
    svg = ElementTree.Element("path")
    svg.set("style", "stroke:{};fill:none".format(stroke_color))
    svg.set(
        "d",
        "M{x1} {y1} A{radius} {radius} 0 0 {flag_sweep} {x2} {y2}".format(
            x1=round(p1.x),
            y1=round(p1.y),
            x2=round(p2.x),
            y2=round(p2.y),
            radius=round(radius),
            flag_sweep=flag_sweep,
        ),
    )
    svg.set("stroke-width", str(stroke_width))
    svg.set("stroke", stroke_color)
    return svg
Ejemplo n.º 16
0
def isClockwise(edge, ref=None):
    """Return True if a circle-based edge has a clockwise direction."""
    if not geomType(edge) == "Circle":
        return True

    v1 = edge.Curve.tangent(edge.ParameterRange[0])[0]
    if DraftVecUtils.isNull(v1):
        return True

    # we take an arbitrary other point on the edge that has little chances
    # to be aligned with the first one
    v2 = edge.Curve.tangent(edge.ParameterRange[0] + 0.01)[0]
    n = edge.Curve.Axis
    # if that axis points "the wrong way" from the reference, we invert it
    if not ref:
        ref = FreeCAD.Vector(0, 0, 1)
    if n.getAngle(ref) > math.pi / 2:
        n = n.negative()

    if DraftVecUtils.angle(v1, v2, n) < 0:
        return False

    if n.z < 0:
        return False

    return True
Ejemplo n.º 17
0
 def getAngle(self,pt):
     "returns the angle of a given vector"
     c = self.trans.translation.getValue()
     center = Vector(c[0],c[1],c[2])
     base = FreeCAD.DraftWorkingPlane.u
     rad = pt.sub(center)
     return(DraftVecUtils.angle(rad,base,FreeCAD.DraftWorkingPlane.axis))
Ejemplo n.º 18
0
def angleBisection(edge1, edge2):
    """Return an edge that bisects the angle between the 2 straight edges."""
    if geomType(edge1) != "Line" or geomType(edge2) != "Line":
        return None

    p1 = edge1.Vertexes[0].Point
    p2 = edge1.Vertexes[-1].Point
    p3 = edge2.Vertexes[0].Point
    p4 = edge2.Vertexes[-1].Point
    intersect = findIntersection(edge1, edge2, True, True)

    if intersect:
        line1Dir = p2.sub(p1)
        angleDiff = DraftVecUtils.angle(line1Dir, p4.sub(p3))
        ang = angleDiff * 0.5
        origin = intersect[0]
        line1Dir.normalize()
        direction = DraftVecUtils.rotate(line1Dir, ang)
    else:
        diff = p3.sub(p1)
        origin = p1.add(diff.multiply(0.5))
        direction = p2.sub(p1)
        direction.normalize()

    return Part.LineSegment(origin, origin.add(direction)).toShape()
Ejemplo n.º 19
0
    def calcEdgeGeometry(self, edges, i):

        self.profilsDico[i]["edge"] = edges[i]
        vec = edges[i].Vertexes[-1].Point.sub(edges[i].Vertexes[0].Point)
        self.profilsDico[i]["vec"] = vec
        rot = math.degrees(DraftVecUtils.angle(vec))
        self.profilsDico[i]["rot"] = rot
Ejemplo n.º 20
0
def isRoundCornerInSVG(edge, radius, view_plane, svg):
    """isRoundCornerInSVG(Edge, Radius, ViewPlane. SVG):
    Returns True if svg corresponding to round corner edge is present in SVG
    element, False otherwise.
    """
    p1 = getProjectionToSVGPlane(edge.Vertexes[0].Point, view_plane)
    p2 = getProjectionToSVGPlane(edge.Vertexes[1].Point, view_plane)
    t1 = edge.tangentAt(edge.FirstParameter)
    t2 = edge.tangentAt(edge.FirstParameter +
                        (edge.LastParameter - edge.FirstParameter) / 10)
    flag_sweep = int(DraftVecUtils.angle(t1, t2, view_plane.axis) < 0)
    if (svg.find(
            './/path[@d="M{x1} {y1} A{radius} {radius} 0 0 {flag_sweep} {x2} '
            '{y2}"]'.format(
                x1=round(p1.x),
                y1=round(p1.y),
                x2=round(p2.x),
                y2=round(p2.y),
                radius=round(radius),
                flag_sweep=flag_sweep,
            )) is not None):
        return True
    elif (svg.find(
            './/path[@d="M{x1} {y1} A{radius} {radius} 0 0 {flag_sweep} {x2} '
            '{y2}"]'.format(
                x1=round(p2.x),
                y1=round(p2.y),
                x2=round(p1.x),
                y2=round(p1.y),
                radius=round(radius),
                flag_sweep=not flag_sweep,
            )) is not None):
        return True
    else:
        return False
Ejemplo n.º 21
0
    def segmentAngleXY(self,
                       prevCommand,
                       currCommand,
                       endpos=False,
                       currentZ=0):
        '''returns in the starting angle in radians for a Path command.
        requires the previous command in order to calculate arcs correctly
        if endpos = True, return the angle at the end of the segment.'''

        global arccommands
        if currCommand.Name in arccommands:
            arcLoc = FreeCAD.Vector((prevCommand.x + currCommand.I),
                                    (prevCommand.y + currCommand.J), currentZ)
            if endpos is True:
                radvector = arcLoc.sub(currCommand.Placement.Base
                                       )  #Calculate vector at start of arc
            else:
                radvector = arcLoc.sub(prevCommand.Placement.Base
                                       )  #Calculate vector at end of arc

            v1 = radvector.cross(FreeCAD.Vector(0, 0, 1))
            if currCommand.Name in ["G2", "G02"]:
                v1 = D.rotate2D(v1, math.radians(180))
        else:
            v1 = currCommand.Placement.Base.sub(
                prevCommand.Placement.Base)  #Straight segments are easy

        myAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0),
                          FreeCAD.Base.Vector(0, 0, -1))
        return myAngle
Ejemplo n.º 22
0
 def rotateSel(sel, n):
     p = sel.Object.Placement
     loc = sel.Object.Placement.Base
     r = axis.cross(n) # rotation axis
     a = DraftVecUtils.angle(n, axis, r) * 180 / math.pi
     PathLog.debug("oh boy: (%.2f, %.2f, %.2f) -> %.2f" % (r.x, r.y, r.z, a))
     Draft.rotate(sel.Object, a, axis=r)
Ejemplo n.º 23
0
def circleFrom2LinesRadius(edge1, edge2, radius):
    """Retun a list of circles from two edges and one radius.

    It calculates 4 centers.
    """
    intsec = findIntersection(edge1, edge2, True, True)
    if not intsec:
        return None

    intsec = intsec[0]
    bis12 = angleBisection(edge1, edge2)
    bis21 = Part.LineSegment(bis12.Vertexes[0].Point,
                             DraftVecUtils.rotate(vec(bis12), math.pi/2.0))
    ang12 = abs(DraftVecUtils.angle(vec(edge1), vec(edge2)))
    ang21 = math.pi - ang12
    dist12 = radius / math.sin(ang12 * 0.5)
    dist21 = radius / math.sin(ang21 * 0.5)

    circles = []
    cen = App.Vector.add(intsec, vec(bis12).multiply(dist12))
    circles.append(Part.Circle(cen, NORM, radius))

    cen = App.Vector.add(intsec, vec(bis12).multiply(-dist12))
    circles.append(Part.Circle(cen, NORM, radius))

    cen = App.Vector.add(intsec, vec(bis21).multiply(dist21))
    circles.append(Part.Circle(cen, NORM, radius))

    cen = App.Vector.add(intsec, vec(bis21).multiply(-dist21))
    circles.append(Part.Circle(cen, NORM, radius))

    return circles
Ejemplo n.º 24
0
 def calcEdgeGeometry(self, i, edge):
     profilCurr = self.profilsDico[i]
     profilCurr["edge"] = edge
     vec = edge.Vertexes[1].Point.sub(edge.Vertexes[0].Point)
     profilCurr["vec"] = vec
     rot = math.degrees(DraftVecUtils.angle(vec))
     profilCurr["rot"] = rot
Ejemplo n.º 25
0
    def calcEdgeGeometry(self, edges, i):

        self.profilsDico[i]["edge"] = edges[i]
        vec = edges[i].Vertexes[-1].Point.sub(edges[i].Vertexes[0].Point)
        self.profilsDico[i]["vec"] = vec
        rot = math.degrees(DraftVecUtils.angle(vec))
        self.profilsDico[i]["rot"] = rot
Ejemplo n.º 26
0
    def lineExtension(self, obj, queue):
        '''returns gcode for line extension'''
        global currLocation

        offset = float(obj.offset)
        results = []

        v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base)

        # extend the current segment to comp for offset
        segAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0),
                           FreeCAD.Base.Vector(0, 0, -1))
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset

        newX = currLocation["X"] + xoffset
        newY = currLocation["Y"] + yoffset

        extendcommand = Path.Command('G1', {"X": newX, "Y": newY})
        results.append(extendcommand)

        currLocation.update(extendcommand.Parameters)

        replace = None
        return (results, replace)
Ejemplo n.º 27
0
def FSMoveToObject(ScrewObj_m, attachToObject, invert, offset):
    Pnt1 = None
    Axis1 = None
    Axis2 = None
    s = attachToObject
    if hasattr(s, "Curve"):
        if hasattr(s.Curve, "Center"):
            Pnt1 = s.Curve.Center
            Axis1 = s.Curve.Axis
    if hasattr(s, 'Surface'):
        #print 'the object is a face!'
        if hasattr(s.Surface, 'Axis'):
            Axis1 = s.Surface.Axis

    if hasattr(s, 'Point'):
        FreeCAD.Console.PrintLog("the object seems to be a vertex! " +
                                 str(s.Point) + "\n")
        Pnt1 = s.Point

    if (Axis1 != None):
        if invert:
            Axis1 = Base.Vector(0, 0, 0) - Axis1

        Pnt1 = Pnt1 + Axis1 * offset
        #FreeCAD.Console.PrintLog( "Got Axis1: " + str(Axis1) + "\n")
        Axis2 = Base.Vector(0.0, 0.0, 1.0)
        Axis2_minus = Base.Vector(0.0, 0.0, -1.0)

        # Calculate angle
        if Axis1 == Axis2:
            normvec = Base.Vector(1.0, 0.0, 0.0)
            result = 0.0
        else:
            if Axis1 == Axis2_minus:
                normvec = Base.Vector(1.0, 0.0, 0.0)
                result = math.pi
            else:
                normvec = Axis1.cross(
                    Axis2)  # Berechne Achse der Drehung = normvec
                normvec.normalize()  # Normalisieren fuer Quaternionenrechnung
                #normvec_rot = normvec
                result = DraftVecUtils.angle(Axis1, Axis2,
                                             normvec)  # Winkelberechnung
        sin_res = math.sin(result / 2.0)
        cos_res = math.cos(result / 2.0)
        normvec.multiply(-sin_res)  # Berechnung der Quaternionen-Elemente

        #FreeCAD.Console.PrintLog( "Winkel = "+ str(math.degrees(result)) + "\n")
        #FreeCAD.Console.PrintLog("Normalvektor: "+ str(normvec) + "\n")

        pl = FreeCAD.Placement()
        pl.Rotation = (normvec.x, normvec.y, normvec.z, cos_res
                       )  #Drehungs-Quaternion

        #FreeCAD.Console.PrintLog("pl mit Rot: "+ str(pl) + "\n")
        ScrewObj_m.Placement = FreeCAD.Placement()
        ScrewObj_m.Placement.Rotation = pl.Rotation.multiply(
            ScrewObj_m.Placement.Rotation)
        ScrewObj_m.Placement.move(Pnt1)
Ejemplo n.º 28
0
 def getDeviation(self):
     "returns the deviation angle between the u axis and the horizontal plane"
     proj = Vector(self.u.x,self.u.y,0)
     if self.u.getAngle(proj) == 0:
         return 0
     else:
         norm = proj.cross(self.u)
         return DraftVecUtils.angle(self.u,proj,norm)
Ejemplo n.º 29
0
 def rotateSel(sel, n):
     p = sel.Object.Placement
     loc = sel.Object.Placement.Base
     r = axis.cross(n)  # rotation axis
     a = DraftVecUtils.angle(n, axis, r) * 180 / math.pi
     PathLog.debug("oh boy: (%.2f, %.2f, %.2f) -> %.2f" %
                   (r.x, r.y, r.z, a))
     Draft.rotate(sel.Object, a, axis=r)
 def getAngle(self,pt):
     "returns the angle of a given vector"
     c = self.trans.translation.getValue()
     center = Vector(c[0],c[1],c[2])
     rad = pt.sub(center)
     a = DraftVecUtils.angle(rad,self.basevector,self.normal)
     #print(a)
     return(a)
Ejemplo n.º 31
0
 def getDeviation(self):
     "returns the deviation angle between the u axis and the horizontal plane"
     proj = Vector(self.u.x, self.u.y, 0)
     if self.u.getAngle(proj) == 0:
         return 0
     else:
         norm = proj.cross(self.u)
         return DraftVecUtils.angle(self.u, proj, norm)
Ejemplo n.º 32
0
 def getAngle(self,pt):
     "returns the angle of a given vector"
     c = self.trans.translation.getValue()
     center = Vector(c[0],c[1],c[2])
     rad = pt.sub(center)
     a = DraftVecUtils.angle(rad,self.basevector,self.normal)
     #print(a)
     return(a)
Ejemplo n.º 33
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
Ejemplo n.º 34
0
def getCubicDimensions(shape):
    """getCubicDimensions(shape): returns a list containing the placement,
    the length, the width and the height of a cubic shape. If not cubic, nothing
    is returned. The placement point is the lowest corner of the shape."""
    if not isCubic(shape): return None
    # determine lowest face, which will be our base
    z = [10, 1000000000000]
    for i in range(len(shape.Faces)):
        if shape.Faces[i].CenterOfMass.z < z[1]:
            z = [i, shape.Faces[i].CenterOfMass.z]
    if z[0] > 5: return None
    base = shape.Faces[z[0]]
    basepoint = base.Edges[0].Vertexes[0].Point
    plpoint = base.CenterOfMass
    basenorm = base.normalAt(0.5, 0.5)
    # getting length and width
    vx = vec(base.Edges[0])
    vy = vec(base.Edges[1])
    # getting rotations
    rotZ = DraftVecUtils.angle(vx)
    rotY = DraftVecUtils.angle(vx, FreeCAD.Vector(vx.x, vx.y, 0))
    rotX = DraftVecUtils.angle(vy, FreeCAD.Vector(vy.x, vy.y, 0))
    # getting height
    vz = None
    rpi = round(math.pi / 2, precision())
    for i in range(1, 6):
        for e in shape.Faces[i].Edges:
            if basepoint in [e.Vertexes[0].Point, e.Vertexes[1].Point]:
                vtemp = vec(e)
                # print(vtemp)
                if round(vtemp.getAngle(vx), precision()) == rpi:
                    if round(vtemp.getAngle(vy), precision()) == rpi:
                        vz = vtemp
    if not vz: return None
    mat = FreeCAD.Matrix()
    mat.move(plpoint)
    mat.rotateX(rotX)
    mat.rotateY(rotY)
    mat.rotateZ(rotZ)
    return [
        FreeCAD.Placement(mat),
        round(vx.Length, precision()),
        round(vy.Length, precision()),
        round(vz.Length, precision())
    ]
Ejemplo n.º 35
0
def FSMoveToObject(ScrewObj_m, attachToObject, invert, offset):
    Pnt1 = None
    Axis1 = None
    Axis2 = None
    s = attachToObject
    if hasattr(s,"Curve"):
      if hasattr(s.Curve,"Center"):
          Pnt1 = s.Curve.Center
          Axis1 = s.Curve.Axis
    if hasattr(s,'Surface'):
      #print 'the object is a face!'
      if hasattr(s.Surface,'Axis'):
          Axis1 = s.Surface.Axis

    if hasattr(s,'Point'):
      FreeCAD.Console.PrintLog( "the object seems to be a vertex! "+ str(s.Point) + "\n")
      Pnt1 = s.Point
          
    if (Axis1 != None):
      if invert:
        Axis1 = Base.Vector(0,0,0) - Axis1
      
      Pnt1 = Pnt1 + Axis1 * offset
      #FreeCAD.Console.PrintLog( "Got Axis1: " + str(Axis1) + "\n")
      Axis2 = Base.Vector(0.0,0.0,1.0)
      Axis2_minus = Base.Vector(0.0,0.0,-1.0)
        
      # Calculate angle
      if Axis1 == Axis2:
          normvec = Base.Vector(1.0,0.0,0.0)
          result = 0.0
      else:
          if Axis1 == Axis2_minus:
              normvec = Base.Vector(1.0,0.0,0.0)
              result = math.pi
          else:
              normvec = Axis1.cross(Axis2) # Berechne Achse der Drehung = normvec
              normvec.normalize() # Normalisieren fuer Quaternionenrechnung
              #normvec_rot = normvec
              result = DraftVecUtils.angle(Axis1, Axis2, normvec) # Winkelberechnung
      sin_res = math.sin(result/2.0)
      cos_res = math.cos(result/2.0)
      normvec.multiply(-sin_res) # Berechnung der Quaternionen-Elemente
      #FreeCAD.Console.PrintLog( "Winkel = "+ str(math.degrees(result)) + "\n")
      #FreeCAD.Console.PrintLog("Normalvektor: "+ str(normvec) + "\n")
        
      pl = FreeCAD.Placement()
      pl.Rotation = (normvec.x,normvec.y,normvec.z,cos_res) #Drehungs-Quaternion
      
      #FreeCAD.Console.PrintLog("pl mit Rot: "+ str(pl) + "\n")
      #neuPlatz = Part2.Object.Placement.multiply(pl)
      ScrewObj_m.Placement = FreeCAD.Placement()
      neuPlatz = ScrewObj_m.Placement
      #FreeCAD.Console.PrintLog("die Position     "+ str(neuPlatz) + "\n")
      neuPlatz.Rotation = pl.Rotation.multiply(ScrewObj_m.Placement.Rotation)
      neuPlatz.move(Pnt1)
Ejemplo n.º 36
0
    def lineTwist(self, obj, queue, lastXY, twistCW=False):
        '''returns gcode to do an arc move toward a line to perform
        a corner action twist. Includes lifting and plungeing the knife'''
        global currLocation
        pivotheight = obj.pivotheight
        offset = obj.offset

        results = []

        # set the correct twist command
        if twistCW is False:
            arcdir = "G3"
        else:
            arcdir = "G2"

        # move to pivot height
        zdepth = currLocation["Z"]
        retract = Path.Command("G0", {"Z": pivotheight})
        results.append(retract)
        currLocation.update(retract.Parameters)

        C = queue[1].Placement.Base

        # get the vectors between endpoints to calculate twist
        v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base)

        # calc arc endpoints to twist to
        segAngle = D.angle(v2, FreeCAD.Base.Vector(1, 0, 0),
                           FreeCAD.Base.Vector(0, 0, -1))
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset
        newX = queue[1].x + xoffset
        newY = queue[1].y + yoffset

        offsetvector = C.sub(lastXY)
        I = offsetvector.x
        J = offsetvector.y

        # add the arc move
        arcmove = Path.Command(arcdir, {
            "X": newX,
            "Y": newY,
            "I": I,
            "J": J
        })  # add G2/G3 move
        results.append(arcmove)

        currLocation.update(arcmove.Parameters)

        # plunge back to depth
        plunge = Path.Command("G1", {"Z": zdepth})
        results.append(plunge)
        currLocation.update(plunge.Parameters)

        replace = None
        return (results, replace)
Ejemplo n.º 37
0
def getRotation(v1, v2=App.Vector(0, 0, 1)):
    """Get the rotation Quaternion between 2 vectors."""
    if (v1.dot(v2) > 0.999999) or (v1.dot(v2) < -0.999999):
        # vectors are opposite
        return None

    axis = v1.cross(v2)
    axis.normalize()
    # angle = math.degrees(math.sqrt(v1.Length^2 * v2.Length^2) + v1.dot(v2))
    angle = math.degrees(DraftVecUtils.angle(v1, v2, axis))
    return App.Rotation(axis, angle)
Ejemplo n.º 38
0
 def shapeAnalyse(self, name, shape):
     ## Create a new object with the shape of the current arch object
     ## His placment is set to 0,0,0
     obj = FreeCAD.ActiveDocument.addObject('Part::Feature', name)
     obj.Shape = shape
     obj.Placement.Base = FreeCAD.Vector(0.0, 0.0, 0.0)
     obj.Placement.Rotation = FreeCAD.Rotation(
         FreeCAD.Vector(0.0, 0.0, 1.0), 0.0)
     FreeCAD.ActiveDocument.recompute()
     ## Get the face to align with XY plane
     faces = obj.Shape.Faces
     facesMax = self.getFacesMax(faces)
     coupleEquerre = self.getCoupleFacesEquerre(facesMax)
     ## Get the normal of this face
     nv1 = coupleEquerre[0][0].normalAt(0, 0)
     ## Get the goal normal vector
     zv = Vector(0, 0, 1)
     ## Find and apply a rotation to the object to align face
     pla = obj.Placement
     rot = pla.Rotation
     rot1 = Rotation(nv1, zv)
     newrot = rot.multiply(rot1)
     pla.Rotation = newrot
     ## Get the face to align with XY plane
     faces = obj.Shape.Faces
     facesMax = self.getFacesMax(faces)
     coupleEquerre = self.getCoupleFacesEquerre(facesMax)
     ## Get the longest edge from aligned face
     maxLength = 0.
     for e in coupleEquerre[0][0].Edges:
         if e.Length > maxLength:
             maxLength = e.Length
             edgeMax = e
     ## Get the angle between edge and X axis and rotate object
     vec = DraftGeomUtils.vec(edgeMax)
     vecZ = FreeCAD.Vector(vec[0], vec[1], 0.0)
     pos2 = obj.Placement.Base
     rotZ = math.degrees(
         DraftVecUtils.angle(vecZ, FreeCAD.Vector(1.0, 0.0, 0.0), zv))
     Draft.rotate([obj], rotZ, pos2, axis=zv, copy=False)
     bb = obj.Shape.BoundBox
     movex = bb.XMin * -1
     movey = bb.YMin * -1
     movez = bb.ZMin * -1
     Draft.move([obj], FreeCAD.Vector(movex, movey, movez))
     FreeCAD.ActiveDocument.recompute()
     ## Get the boundbox
     analyse = [
         obj.Shape.BoundBox.YLength, obj.Shape.BoundBox.ZLength,
         obj.Shape.BoundBox.XLength
     ]
     if not "Shape" in self.export:
         FreeCAD.ActiveDocument.removeObject(name)
     return analyse
Ejemplo n.º 39
0
    def lineTwist(self, obj, queue, lastXY, twistCW=False):
        '''returns gcode to do an arc move toward a line to perform
        a corner action twist. Includes lifting and plungeing the knife'''
        global currLocation
        pivotheight = obj.pivotheight
        offset = obj.offset

        results = []

        # set the correct twist command
        if twistCW is False:
            arcdir = "G3"
        else:
            arcdir = "G2"

        # move to pivot height
        zdepth = currLocation["Z"]
        retract = Path.Command("G0", {"Z": pivotheight})
        results.append(retract)
        currLocation.update(retract.Parameters)

        C = queue[1].Placement.Base

        # get the vectors between endpoints to calculate twist
        v2 = queue[0].Placement.Base.sub(queue[1].Placement.Base)

        # calc arc endpoints to twist to
        segAngle = D.angle(v2, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1))
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset
        newX = queue[1].x + xoffset
        newY = queue[1].y + yoffset

        offsetvector = C.sub(lastXY)
        I = offsetvector.x
        J = offsetvector.y

        # add the arc move
        arcmove = Path.Command(
            arcdir, {"X": newX, "Y": newY, "I": I, "J": J})  # add G2/G3 move
        results.append(arcmove)

        currLocation.update(arcmove.Parameters)

        # plunge back to depth
        plunge = Path.Command("G1", {"Z": zdepth})
        results.append(plunge)
        currLocation.update(plunge.Parameters)

        replace = None
        return (results, replace)
Ejemplo n.º 40
0
 def shapeAnalyse(self, name, shape):
     ## Create a new object with the shape of the current arch object
     ## His placment is set to 0,0,0
     obj = FreeCAD.ActiveDocument.addObject('Part::Feature',name)
     obj.Shape=shape
     obj.Placement.Base = FreeCAD.Vector(0.0,0.0,0.0)
     obj.Placement.Rotation = FreeCAD.Rotation(FreeCAD.Vector(0.0,0.0,1.0),0.0)
     FreeCAD.ActiveDocument.recompute()
     ## Get the face to align with XY plane
     faces = obj.Shape.Faces
     facesMax = self.getFacesMax(faces)
     coupleEquerre = self.getCoupleFacesEquerre(facesMax)
     ## Get the normal of this face
     nv1 = coupleEquerre[0][0].normalAt(0,0)
     ## Get the goal normal vector
     zv = Vector(0,0,1)
     ## Find and apply a rotation to the object to align face
     pla = obj.Placement
     rot = pla.Rotation
     rot1 = Rotation(nv1, zv)
     newrot = rot.multiply(rot1)
     pla.Rotation = newrot
     ## Get the face to align with XY plane
     faces = obj.Shape.Faces
     facesMax = self.getFacesMax(faces)
     coupleEquerre = self.getCoupleFacesEquerre(facesMax)
     ## Get the longest edge from aligned face
     maxLength = 0.
     for e in coupleEquerre[0][0].Edges:
         if e.Length > maxLength:
             maxLength = e.Length
             edgeMax = e
     ## Get the angle between edge and X axis and rotate object
     vec = DraftGeomUtils.vec(edgeMax)
     vecZ = FreeCAD.Vector(vec[0],vec[1],0.0)
     pos2 = obj.Placement.Base
     rotZ = math.degrees(DraftVecUtils.angle(vecZ,FreeCAD.Vector(1.0,0.0,0.0),zv))
     Draft.rotate([obj],rotZ,pos2,axis=zv,copy=False)
     bb = obj.Shape.BoundBox
     movex = bb.XMin*-1
     movey = bb.YMin*-1
     movez = bb.ZMin*-1
     Draft.move([obj], FreeCAD.Vector(movex, movey, movez))
     FreeCAD.ActiveDocument.recompute()
     ## Get the boundbox
     analyse = [obj.Shape.BoundBox.YLength, obj.Shape.BoundBox.ZLength, obj.Shape.BoundBox.XLength]
     if not "Shape" in self.export :
         FreeCAD.ActiveDocument.removeObject(name)
     return analyse
Ejemplo n.º 41
0
    def accept(self):
        self.recupererDonnees()
        distancesListe = []
        if self.objetDebut:
            distancesListe.append(self.decalageDebut)
        if self.plEspaceRestant == 0:
            distancesListe.append(self.espaceRestant)
        if self.plEspaceRestant == 1:
            distancesListe.append(self.ecartementRegulier-self.decalageDebut)
        if self.plEspaceRestant == 2:
            distancesListe.append(self.espaceRestant/2-self.decalageDebut)
        for i in range(self.qteEcartement-2):
            distancesListe.append(self.ecartementRegulier)
        if self.objetFin:
            if self.plEspaceRestant == 0:
                distancesListe.append(self.ecartementRegulier-self.decalageFin-self.decalageDebut)
            if self.plEspaceRestant == 1:
                distancesListe.append(self.espaceRestant-self.decalageFin)
            if self.plEspaceRestant == 2:
                distancesListe.append(self.ecartementRegulier)
                distancesListe.append((self.espaceRestant/2)-self.decalageFin)
        repartition = Arch.makeAxis(num=len(distancesListe), name="Repartition")
        repartition.Length = 1000.00
        repartition.Distances= distancesListe

        self.sel = FreeCADGui.Selection.getSelection()
        if self.sel:
            edges = DraftGeomUtils.sortEdges(self.sel[0].Shape.Wires[0].Edges)
            vec1 = edges[0].Vertexes[-1].Point.sub(edges[0].Vertexes[0].Point)
            point1 = edges[0].Vertexes[0].Point
            rot = math.degrees(DraftVecUtils.angle(vec1))*-1
            repartition.Placement = FreeCAD.Placement(FreeCAD.Vector(point1),FreeCAD.Rotation(FreeCAD.Vector(0.0,0.0,1.0),rot))
            FreeCAD.ActiveDocument.recompute()
        else:
            repartition.Placement = FreeCAD.Placement(FreeCAD.Vector(0.0,0.0,0.0),FreeCAD.Rotation(FreeCAD.Vector(0.0,0.0,1.0),0))

        m = FreeCADGui.getMainWindow()
        w = m.findChild(QtGui.QDockWidget,"PartsLibrary")
        if w:
            if w.isVisible():
                index = w.folder_view.selectedIndexes()[0]
                path = w.dirmodel.filePath(index)
                if path.lower().endswith(".stp") or path.lower().endswith(".step") or path.lower().endswith(".brep"):
                    objetRepartit = Part.show(Part.read(path))
                else:
                    objetRepartit = FreeCADGui.ActiveDocument.mergeProject(path)
                repartitionStructurel = Arch.makeStructuralSystem([FreeCAD.ActiveDocument.Objects[-1],],[repartition,], name="RepartitionStructurelle")
        return True
Ejemplo n.º 42
0
def setRepresentation(representation):
    """Returns a shape from a 2D IfcShapeRepresentation"""
    
    def getPolyline(ent):
        pts = []
        for p in ent.Points:
            c = p.Coordinates
            pts.append(FreeCAD.Vector(c[0],c[1],c[2] if len(c) > 2 else 0))
        return Part.makePolygon(pts)
            
    def getCircle(ent):
        c = ent.Position.Location.Coordinates
        c = FreeCAD.Vector(c[0],c[1],c[2] if len(c) > 2 else 0)
        r = ent.Radius
        return Part.makeCircle(r,c)
    
    result = []
    if representation.is_a("IfcShapeRepresentation"):
        for item in representation.Items:
            if item.is_a("IfcGeometricCurveSet"):
                for el in item.Elements:
                    if el.is_a("IfcPolyline"):
                        result.append(getPolyline(el))
                    elif el.is_a("IfcCircle"):
                        result.append(getCircle(el))
                    elif el.is_a("IfcTrimmedCurve"):
                        base = el.BasisCurve
                        t1 = el.Trim1[0].wrappedValue
                        t2 = el.Trim2[0].wrappedValue
                        if not el.SenseAgreement:
                            t1,t2 = t2,t1
                        if base.is_a("IfcPolyline"):
                            bc = getPolyline(base)
                            result.append(bc)
                        elif base.is_a("IfcCircle"):
                            bc = getCircle(base)
                            e = Part.ArcOfCircle(bc.Curve,math.radians(t1),math.radians(t2)).toShape()
                            d = base.Position.RefDirection.DirectionRatios
                            v = FreeCAD.Vector(d[0],d[1],d[2] if len(d) > 2 else 0)
                            a = -DraftVecUtils.angle(v)
                            e.rotate(bc.Curve.Center,FreeCAD.Vector(0,0,1),math.degrees(a))
                            result.append(e)
    return result
Ejemplo n.º 43
0
    def segmentAngleXY(self, prevCommand, currCommand, endpos=False, currentZ=0):
        '''returns in the starting angle in radians for a Path command.
        requires the previous command in order to calculate arcs correctly
        if endpos = True, return the angle at the end of the segment.'''

        global arccommands
        if currCommand.Name in arccommands:
            arcLoc = FreeCAD.Vector((prevCommand.x + currCommand.I), (prevCommand.y + currCommand.J), currentZ)
            if endpos is True:
                radvector = arcLoc.sub(currCommand.Placement.Base)  # Calculate vector at start of arc
            else:
                radvector = arcLoc.sub(prevCommand.Placement.Base)  # Calculate vector at end of arc

            v1 = radvector.cross(FreeCAD.Vector(0, 0, 1))
            if currCommand.Name in ["G2", "G02"]:
                v1 = D.rotate2D(v1, math.radians(180))
        else:
            v1 = currCommand.Placement.Base.sub(prevCommand.Placement.Base)  # Straight segments are easy

        myAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1))
        return myAngle
Ejemplo n.º 44
0
def getTuples(data,scale=1,placement=None,normal=None,close=True):
    """getTuples(data,[scale,placement,normal,close]): returns a tuple or a list of tuples from a vector
    or from the vertices of a shape. Scale can indicate a scale factor"""
    import Part
    if isinstance(data,FreeCAD.Vector):
        if placement:
            data = placement.multVec(data)
            data = DraftVecUtils.rounded(data)
        return (data.x*scale,data.y*scale,data.z*scale)
    elif isinstance(data,Part.Shape):
        t = []
        if len(data.Wires) == 1:
            import Part,DraftGeomUtils
            data = Part.Wire(DraftGeomUtils.sortEdges(data.Wires[0].Edges))
            verts = data.Vertexes
            try:
                c = data.CenterOfMass
                v1 = verts[0].Point.sub(c)
                v2 = verts[1].Point.sub(c)
                if DraftVecUtils.angle(v2,v1,normal) >= 0:
                    # inverting verts order if the direction is couterclockwise
                    verts.reverse()
            except:
                pass
            for v in verts:
                pt = v.Point
                if placement:
                    if not placement.isNull():
                        pt = placement.multVec(pt)
                        pt = DraftVecUtils.rounded(pt)
                t.append((pt.x*scale,pt.y*scale,pt.z*scale))

            if close: # faceloops must not be closed, but ifc profiles must.
                t.append(t[0])
        else:
            print "Arch.getTuples(): Wrong profile data"
        return t
Ejemplo n.º 45
0
    def lineExtension(self, obj, queue):
        '''returns gcode for line extension'''
        global currLocation

        offset = float(obj.offset)
        results = []

        v1 = queue[1].Placement.Base.sub(queue[2].Placement.Base)

        # extend the current segment to comp for offset
        segAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1))
        xoffset = math.cos(segAngle) * offset
        yoffset = math.sin(segAngle) * offset

        newX = currLocation["X"] + xoffset
        newY = currLocation["Y"] + yoffset

        extendcommand = Path.Command('G1', {"X": newX, "Y": newY})
        results.append(extendcommand)

        currLocation.update(extendcommand.Parameters)

        replace = None
        return (results, replace)
Ejemplo n.º 46
0
def getRepresentation(ifcfile,context,obj,forcebrep=False,subtraction=False,tessellation=1):
    """returns an IfcShapeRepresentation object or None"""
    
    import Part,math,DraftGeomUtils,DraftVecUtils
    shapes = []
    placement = None
    productdef = None
    shapetype = "no shape"
        
    if not forcebrep:
        profile = None
        if hasattr(obj,"Proxy"):
            if hasattr(obj.Proxy,"getProfiles"):
                p = obj.Proxy.getProfiles(obj,noplacement=True)
                extrusionv = obj.Proxy.getExtrusionVector(obj,noplacement=True)
                if (len(p) == 1) and extrusionv:
                    p = p[0]
                    r = obj.Proxy.getPlacement(obj)
                    
                    if len(p.Edges) == 1:
                        
                        pxvc = ifcfile.createIfcDirection((1.0,0.0))
                        povc = ifcfile.createIfcCartesianPoint((0.0,0.0))
                        pt = ifcfile.createIfcAxis2Placement2D(povc,pxvc)
                        
                        # extruded circle
                        if isinstance(p.Edges[0].Curve,Part.Circle):
                            profile = ifcfile.createIfcCircleProfileDef("AREA",None,pt, p.Edges[0].Curve.Radius)
                            
                        # extruded ellipse
                        elif isinstance(p.Edges[0].Curve,Part.Ellipse):
                            profile = ifcfile.createIfcEllipseProfileDef("AREA",None,pt, p.Edges[0].Curve.MajorRadius, p.Edges[0].Curve.MinorRadius)     
                            
                    else:
                        curves = False
                        for e in p.Edges:
                            if isinstance(e.Curve,Part.Circle):
                                curves = True
                                
                        # extruded polyline
                        if not curves:
                            w = Part.Wire(DraftGeomUtils.sortEdges(p.Edges))
                            pts = [ifcfile.createIfcCartesianPoint(tuple(v.Point)[:2]) for v in w.Vertexes+[w.Vertexes[0]]]
                            pol = ifcfile.createIfcPolyline(pts)
                            
                        # extruded composite curve
                        else:
                            segments = []
                            last = None
                            edges = DraftGeomUtils.sortEdges(p.Edges)
                            for e in edges:
                                if isinstance(e.Curve,Part.Circle):
                                    follow = True
                                    if last:
                                        if not DraftVecUtils.equals(last,e.Vertexes[0].Point):
                                            follow = False
                                            last = e.Vertexes[0].Point
                                        else:
                                            last = e.Vertexes[-1].Point
                                    else:
                                        last = e.Vertexes[-1].Point
                                    p1 = math.degrees(-DraftVecUtils.angle(e.Vertexes[0].Point.sub(e.Curve.Center)))
                                    p2 = math.degrees(-DraftVecUtils.angle(e.Vertexes[-1].Point.sub(e.Curve.Center)))
                                    da = DraftVecUtils.angle(e.valueAt(e.FirstParameter+0.1).sub(e.Curve.Center),e.Vertexes[0].Point.sub(e.Curve.Center))
                                    if p1 < 0: 
                                        p1 = 360 + p1
                                    if p2 < 0:
                                        p2 = 360 + p2
                                    if da > 0:
                                        follow = not(follow)
                                    xvc =       ifcfile.createIfcDirection((1.0,0.0))
                                    ovc =       ifcfile.createIfcCartesianPoint(tuple(e.Curve.Center)[:2])
                                    plc =       ifcfile.createIfcAxis2Placement2D(ovc,xvc)
                                    cir =       ifcfile.createIfcCircle(plc,e.Curve.Radius)
                                    curve =     ifcfile.createIfcTrimmedCurve(cir,[ifcfile.create_entity("IfcParameterValue",p1)],[ifcfile.create_entity("IfcParameterValue",p2)],follow,"PARAMETER")
                                    
                                else:
                                    verts = [vertex.Point for vertex in e.Vertexes]
                                    if last:
                                        if not DraftVecUtils.equals(last,verts[0]):
                                            verts.reverse()
                                            last = e.Vertexes[0].Point
                                        else:
                                            last = e.Vertexes[-1].Point
                                    else:
                                        last = e.Vertexes[-1].Point
                                    pts =     [ifcfile.createIfcCartesianPoint(tuple(v)[:2]) for v in verts]
                                    curve =   ifcfile.createIfcPolyline(pts)
                                segment = ifcfile.createIfcCompositeCurveSegment("CONTINUOUS",True,curve)
                                segments.append(segment)
                                
                            pol = ifcfile.createIfcCompositeCurve(segments,False)
                        profile = ifcfile.createIfcArbitraryClosedProfileDef("AREA",None,pol)
                        
        if profile:
            xvc =       ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(1,0,0))))
            zvc =       ifcfile.createIfcDirection(tuple(r.Rotation.multVec(FreeCAD.Vector(0,0,1))))
            ovc =       ifcfile.createIfcCartesianPoint(tuple(r.Base))
            lpl =       ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
            edir =      ifcfile.createIfcDirection(tuple(FreeCAD.Vector(extrusionv).normalize()))
            shape =     ifcfile.createIfcExtrudedAreaSolid(profile,lpl,edir,extrusionv.Length)
            shapes.append(shape)
            solidType = "SweptSolid"
            shapetype = "extrusion"
                
    if not shapes:
        
        # brep representation
        fcshape = None
        solidType = "Brep"
        if subtraction:
            if hasattr(obj,"Proxy"):
                if hasattr(obj.Proxy,"getSubVolume"):
                    fcshape = obj.Proxy.getSubVolume(obj)
        if not fcshape:
            if hasattr(obj,"Shape"):
                if obj.Shape:
                    if not obj.Shape.isNull():
                        fcshape = obj.Shape
            elif hasattr(obj,"Terrain"):
                if obj.Terrain:
                    if hasattr(obj.Terrain,"Shape"):
                        if obj.Terrain.Shape:
                            if not obj.Terrain.Shape.isNull():
                                    fcshape = obj.Terrain.Shape
        if fcshape:
            solids = []
            if fcshape.Solids:
                dataset = fcshape.Solids
            else:
                dataset = fcshape.Shells
                print "Warning! object contains no solids"
            for fcsolid in dataset:
                faces = []
                curves = False
                for fcface in fcsolid.Faces:
                    for e in fcface.Edges:
                        if not isinstance(e.Curve,Part.Line):
                            curves = True
                if curves:
                    tris = fcsolid.tessellate(tessellation)
                    for tri in tris[1]:
                        pts =   [ifcfile.createIfcCartesianPoint(tuple(tris[0][i])) for i in tri]
                        loop =  ifcfile.createIfcPolyLoop(pts)
                        bound = ifcfile.createIfcFaceOuterBound(loop,True)
                        face =  ifcfile.createIfcFace([bound])
                        faces.append(face)
                else:
                    for fcface in fcsolid.Faces:
                        loops = []
                        verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(fcface.OuterWire.Edges)).Vertexes]
                        c = fcface.CenterOfMass
                        v1 = verts[0].sub(c)
                        v2 = verts[1].sub(c)
                        n = fcface.normalAt(0,0)
                        if DraftVecUtils.angle(v2,v1,n) >= 0:
                            verts.reverse() # inverting verts order if the direction is couterclockwise
                        pts =   [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
                        loop =  ifcfile.createIfcPolyLoop(pts)
                        bound = ifcfile.createIfcFaceOuterBound(loop,True)
                        loops.append(bound)
                        for wire in fcface.Wires:
                            if wire.hashCode() != fcface.OuterWire.hashCode():
                                verts = [v.Point for v in Part.Wire(DraftGeomUtils.sortEdges(wire.Edges)).Vertexes]
                                v1 = verts[0].sub(c)
                                v2 = verts[1].sub(c)
                                if DraftVecUtils.angle(v2,v1,DraftVecUtils.neg(n)) >= 0:
                                    verts.reverse()
                                pts =   [ifcfile.createIfcCartesianPoint(tuple(v)) for v in verts]
                                loop =  ifcfile.createIfcPolyLoop(pts)
                                bound = ifcfile.createIfcFaceBound(loop,True)
                                loops.append(bound)
                        face =  ifcfile.createIfcFace(loops)
                        faces.append(face)
                shell = ifcfile.createIfcClosedShell(faces)
                shape = ifcfile.createIfcFacetedBrep(shell)
                shapes.append(shape)
                shapetype = "brep"

    if shapes:
        
        if FreeCAD.GuiUp and (not subtraction) and hasattr(obj.ViewObject,"ShapeColor"):
            rgb = obj.ViewObject.ShapeColor
            col = ifcfile.createIfcColourRgb(None,rgb[0],rgb[1],rgb[2])
            ssr = ifcfile.createIfcSurfaceStyleRendering(col,None,None,None,None,None,None,None,"FLAT")
            iss = ifcfile.createIfcSurfaceStyle(None,"BOTH",[ssr])
            psa = ifcfile.createIfcPresentationStyleAssignment([iss])
            for shape in shapes:
                isi = ifcfile.createIfcStyledItem(shape,[psa],None)
                
                
        xvc = ifcfile.createIfcDirection((1.0,0.0,0.0))
        zvc = ifcfile.createIfcDirection((0.0,0.0,1.0))
        ovc = ifcfile.createIfcCartesianPoint((0.0,0.0,0.0))
        gpl = ifcfile.createIfcAxis2Placement3D(ovc,zvc,xvc)
        placement = ifcfile.createIfcLocalPlacement(None,gpl)
        representation = ifcfile.createIfcShapeRepresentation(context,'Body',solidType,shapes)
        productdef = ifcfile.createIfcProductDefinitionShape(None,None,[representation])
        
    return productdef,placement,shapetype
Ejemplo n.º 47
0
    def arcTwist(self, obj, queue, lastXY, twistCW=False):
        '''returns gcode to do an arc move toward an arc to perform
        a corner action twist. Includes lifting and plungeing the knife'''

        global currLocation
        pivotheight = obj.pivotheight
        offset = obj.offset
        results = []

        # set the correct twist command
        if twistCW is False:
            arcdir = "G3"
        else:
            arcdir = "G2"

        # move to the pivot height
        zdepth = currLocation["Z"]
        retract = Path.Command("G0", {"Z": pivotheight})
        results.append(retract)
        currLocation.update(retract.Parameters)

        # get the center of the destination arc
        arccenter = FreeCAD.Base.Vector(queue[1].x + queue[0].I, queue[1].y + queue[0].J, currLocation["Z"])

        # The center of the twist arc is the old line end point.
        C = queue[1].Placement.Base

        # Find radius of old arc
        R = math.hypot(queue[0].I, queue[0].J)

        # find angle of original center to startpoint
        v1 = queue[1].Placement.Base.sub(arccenter)
        segAngle = D.angle(v1, FreeCAD.Base.Vector(1, 0, 0), FreeCAD.Base.Vector(0, 0, -1))

        # Find angle subtended by the offset
        theta = offset / R

        # add or subtract theta depending on direction
        if queue[1].Name in ["G2", "G02"]:
            newangle = segAngle + theta
        else:
            newangle = segAngle - theta

        # calculate endpoints
        Bx = arccenter.x + R * math.cos(newangle)
        By = arccenter.y + R * math.sin(newangle)
        endpointvector = FreeCAD.Base.Vector(Bx, By, currLocation['Z'])

        # calculate IJ offsets of twist arc from current position.
        offsetvector = C.sub(lastXY)

        # add G2/G3 move
        arcmove = Path.Command(
            arcdir, {"X": endpointvector.x, "Y": endpointvector.y, "I": offsetvector.x, "J": offsetvector.y})
        results.append(arcmove)
        currLocation.update(arcmove.Parameters)

        # plunge back to depth
        plunge = Path.Command("G1", {"Z": zdepth})
        results.append(plunge)
        currLocation.update(plunge.Parameters)

        # The old arc move won't work so calculate a replacement command
        offsetv = arccenter.sub(endpointvector)

        replace = Path.Command(
            queue[0].Name, {"X": queue[0].X, "Y": queue[0].Y, "I": offsetv.x, "J": offsetv.y})
        return (results, replace)
Ejemplo n.º 48
0
def getSVG(obj,scale=1,linewidth=0.35,fontsize=12,fillstyle="shape color",direction=None,linestyle=None,color=None,linespacing=None,techdraw=False,rotation=0):
    '''getSVG(object,[scale], [linewidth],[fontsize],[fillstyle],[direction],[linestyle],[color],[linespacing]):
    returns a string containing a SVG representation of the given object,
    with the given linewidth and fontsize (used if the given object contains
    any text). You can also supply an arbitrary projection vector. the
    scale parameter allows to scale linewidths down, so they are resolution-independant.'''

    # if this is a group, gather all the svg views of its children
    if hasattr(obj,"isDerivedFrom"):
        if obj.isDerivedFrom("App::DocumentObjectGroup"):
            svg = ""
            for child in obj.Group:
                svg += getSVG(child,scale,linewidth,fontsize,fillstyle,direction,linestyle,color,linespacing,techdraw)
            return svg

    pathdata = []
    svg = ""
    linewidth = float(linewidth)/scale
    fontsize = (float(fontsize)/scale)/2
    if linespacing:
        linespacing = float(linespacing)/scale
    else:
        linespacing = 0.5
    #print obj.Label," line spacing ",linespacing,"scale ",scale
    pointratio = .75 # the number of times the dots are smaller than the arrow size
    plane = None
    if direction:
        if isinstance(direction,FreeCAD.Vector):
            if direction != Vector(0,0,0):
                plane = WorkingPlane.plane()
                plane.alignToPointAndAxis_SVG(Vector(0,0,0),direction.negative().negative(),0)
        elif isinstance(direction,WorkingPlane.plane):
            plane = direction
    stroke = "#000000"
    if color:
        if "#" in color:
            stroke = color
        else:
            stroke = getrgb(color)
    elif gui:
        if hasattr(obj,"ViewObject"):
            if hasattr(obj.ViewObject,"LineColor"):
                stroke = getrgb(obj.ViewObject.LineColor)


    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

    def getCircle(edge):
        cen = getProj(edge.Curve.Center, plane)
        rad = edge.Curve.Radius
        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
        if round(edge.Curve.Axis.getAngle(drawing_plane_normal),2) == 0:
            # perpendicular projection: circle
            svg = '<circle cx="' + str(cen.x)
            svg += '" cy="' + str(cen.y)
            svg += '" r="' + str(rad)+'" '
        else:
            # any other projection: ellipse
            svg = '<path d="'
            svg += getDiscretized(edge, plane)
            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 + '"'
        svg += '/>\n'
        return svg

    def getEllipse(edge):
        cen = getProj(edge.Curve.Center, plane)
        mir = edge.Curve.MinorRadius
        mar = edge.Curve.MajorRadius
        svg = '<ellipse cx="' + str(cen.x)
        svg += '" cy="' + str(cen.y)
        svg += '" rx="' + str(mar)
        svg += '" ry="' + str(mir)+'" '
        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 + '"'
        svg += '/>\n'
        return svg

    def getArrow(arrowtype,point,arrowsize,color,linewidth,angle=0):
        svg = ""
        if gui:
            if not obj.ViewObject:
                return svg
            if obj.ViewObject.ArrowType == "Circle":
                svg += '<circle cx="'+str(point.x)+'" cy="'+str(point.y)
                svg += '" r="'+str(arrowsize)+'" '
                svg += 'fill="none" stroke="'+ color + '" '
                svg += 'style="stroke-width:'+ str(linewidth) + ';stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'freecad:skip="1"'
                svg += '/>\n'
            elif obj.ViewObject.ArrowType == "Dot":
                svg += '<circle cx="'+str(point.x)+'" cy="'+str(point.y)
                svg += '" r="'+str(arrowsize)+'" '
                svg += 'fill="'+ color +'" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'freecad:skip="1"'
                svg += '/>\n'
            elif obj.ViewObject.ArrowType == "Arrow":
                svg += '<path transform="rotate('+str(math.degrees(angle))
                svg += ','+ str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'scale('+str(arrowsize)+','+str(arrowsize)+')" freecad:skip="1" '
                svg += 'fill="'+ color +'" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'd="M 0 0 L 4 1 L 4 -1 Z"/>\n'
            elif obj.ViewObject.ArrowType == "Tick":
                svg += '<path transform="rotate('+str(math.degrees(angle))
                svg += ','+ str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += 'scale('+str(arrowsize)+','+str(arrowsize)+')" freecad:skip="1" '
                svg += 'fill="'+ color +'" stroke="none" '
                svg += 'style="stroke-miterlimit:4;stroke-dasharray:none" '
                svg += 'd="M -1 -2 L 0 2 L 1 2 L 0 -2 Z"/>\n'
            elif obj.ViewObject.ArrowType == "Tick-2":
                svg += '<line transform="rotate('+str(math.degrees(angle)+45)
                svg += ','+ str(point.x) + ',' + str(point.y) + ') '
                svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
                svg += '" freecad:skip="1" '
                svg += 'fill="none" stroke="'+ color +'" '
                svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
                svg += 'stroke-width:'+ str(linewidth) +'" '
                svg += 'x1="-'+ str(arrowsize*2) +'" y1="0" '
                svg += 'x2="' + str(arrowsize*2) +'" y2="0" />\n'
            else:
                print("getSVG: arrow type not implemented")
        return svg

    def getOvershoot(point,shootsize,color,linewidth,angle=0):
        svg = '<line transform="rotate('+str(math.degrees(angle))
        svg += ','+ str(point.x) + ',' + str(point.y) + ') '
        svg += 'translate(' + str(point.x) + ',' + str(point.y) + ') '
        svg += '" freecad:skip="1" '
        svg += 'fill="none" stroke="'+ color +'" '
        svg += 'style="stroke-dasharray:none;stroke-linecap:square;'
        svg += 'stroke-width:'+ str(linewidth) +'" '
        svg += 'x1="0" y1="0" '
        svg += 'x2="'+ str(shootsize*-1) +'" y2="0" />\n'
        return svg

    def getText(color,fontsize,fontname,angle,base,text,linespacing=0.5,align="center",flip=True):
        if isinstance(angle,FreeCAD.Rotation):
            if not plane:
                angle = angle.Angle
            else:
                if plane.axis.getAngle(angle.Axis) < 0.001:
                    angle = angle.Angle
                elif abs(plane.axis.getAngle(angle.Axis)-math.pi) < 0.001:
                    return "" # text is perpendicular to view, so it shouldn't appear
                else:
                    angle = 0 #TODO maybe there is something better to do here?
        if not isinstance(text,list):
            text = text.split("\n")
        if align.lower() == "center":
            anchor = "middle"
        elif align.lower() == "left":
            anchor = "start"
        else:
            anchor = "end"
        if techdraw:
            svg = ""
            for i in range(len(text)):
                t = text[i]
                if sys.version_info.major < 3 and (not isinstance(t,unicode)):
                    t = t.decode("utf8")
                # possible workaround if UTF8 is unsupported
                #    import unicodedata
                #    t = u"".join([c for c in unicodedata.normalize("NFKD",t) if not unicodedata.combining(c)]).encode("utf8")
                svg += '<text fill="' + color +'" font-size="' + str(fontsize) + '" '
                svg += 'style="text-anchor:'+anchor+';text-align:'+align.lower()+';'
                svg += 'font-family:'+ fontname +'" '
                svg += 'transform="rotate('+str(math.degrees(angle))
                svg += ','+ str(base.x) + ',' + str(base.y-linespacing*i) + ') '
                svg += 'translate(' + str(base.x) + ',' + str(base.y-linespacing*i) + ') '
                svg += 'scale(1,-1)" '
                #svg += '" freecad:skip="1"'
                svg += '>\n' + t + '</text>\n'
        else:
            svg = '<text fill="'
            svg += color +'" font-size="'
            svg += str(fontsize) + '" '
            svg += 'style="text-anchor:'+anchor+';text-align:'+align.lower()+';'
            svg += 'font-family:'+ fontname +'" '
            svg += 'transform="rotate('+str(math.degrees(angle))
            svg += ','+ str(base.x) + ',' + str(base.y) + ') '
            if flip:
                svg += 'translate(' + str(base.x) + ',' + str(base.y) + ')'
            else:
                svg += 'translate(' + str(base.x) + ',' + str(-base.y) + ')'
            #svg += 'scale('+str(tmod/2000)+',-'+str(tmod/2000)+') '
            if flip:
                svg += ' scale(1,-1) '
            else:
                svg += ' scale(1,1) '
            svg += '" freecad:skip="1"'
            svg += '>\n'
            if len(text) == 1:
                try:
                    svg += text[0]
                except:
                    svg += text[0].decode("utf8")
            else:
                for i in range(len(text)):
                    if i == 0:
                        svg += '<tspan>'
                    else:
                        svg += '<tspan x="0" dy="'+str(linespacing)+'">'
                    try:
                        svg += text[i]
                    except:
                        svg += text[i].decode("utf8")
                    svg += '</tspan>\n'
            svg += '</text>\n'
        return svg


    if not obj:
        pass

    elif isinstance(obj,Part.Shape):
        if "#" in fillstyle:
            fill = fillstyle
        elif fillstyle == "shape color":
            fill = "#888888"
        else:
            fill = 'url(#'+fillstyle+')'
        lstyle = getLineStyle(linestyle, scale)
        svg += getPath(obj.Edges,pathname="")


    elif getType(obj) == "Dimension":
        if gui:
            if not obj.ViewObject:
                print ("export of dimensions to SVG is only available in GUI mode")
            elif obj.ViewObject.Proxy:
                if hasattr(obj.ViewObject.Proxy,"p1"):
                    prx = obj.ViewObject.Proxy
                    ts = (len(prx.string)*obj.ViewObject.FontSize.Value)/4.0
                    rm = ((prx.p3.sub(prx.p2)).Length/2.0)-ts
                    p2a = getProj(prx.p2.add(DraftVecUtils.scaleTo(prx.p3.sub(prx.p2),rm)), plane)
                    p2b = getProj(prx.p3.add(DraftVecUtils.scaleTo(prx.p2.sub(prx.p3),rm)), plane)
                    p1 = getProj(prx.p1, plane)
                    p2 = getProj(prx.p2, plane)
                    p3 = getProj(prx.p3, plane)
                    p4 = getProj(prx.p4, plane)
                    tbase = getProj(prx.tbase, plane)
                    r = prx.textpos.rotation.getValue().getValue()
                    rv = FreeCAD.Rotation(r[0],r[1],r[2],r[3]).multVec(FreeCAD.Vector(1,0,0))
                    angle = -DraftVecUtils.angle(getProj(rv, plane))
                    #angle = -DraftVecUtils.angle(p3.sub(p2))

                    # drawing lines
                    svg = '<path '
                    if obj.ViewObject.DisplayMode == "2D":
                        tangle = angle
                        if tangle > math.pi/2:
                            tangle = tangle-math.pi
                        #elif (tangle <= -math.pi/2) or (tangle > math.pi/2):
                        #    tangle = tangle+math.pi
                        #tbase = tbase.add(DraftVecUtils.rotate(Vector(0,2/scale,0),tangle))
                        if rotation != 0:
                            #print "dim: tangle:",tangle," rot: ",rotation," text: ",prx.string
                            if abs(tangle+math.radians(rotation)) < 0.0001:
                                tangle += math.pi
                                tbase = tbase.add(DraftVecUtils.rotate(Vector(0,2/scale,0),tangle))
                        svg += 'd="M '+str(p1.x)+' '+str(p1.y)+' '
                        svg += 'L '+str(p2.x)+' '+str(p2.y)+' '
                        svg += 'L '+str(p3.x)+' '+str(p3.y)+' '
                        svg += 'L '+str(p4.x)+' '+str(p4.y)+'" '
                    else:
                        tangle = 0
                        if rotation != 0:
                            tangle = -math.radians(rotation)
                        tbase = tbase.add(Vector(0,-2.0/scale,0))
                        svg += 'd="M '+str(p1.x)+' '+str(p1.y)+' '
                        svg += 'L '+str(p2.x)+' '+str(p2.y)+' '
                        svg += 'L '+str(p2a.x)+' '+str(p2a.y)+' '
                        svg += 'M '+str(p2b.x)+' '+str(p2b.y)+' '
                        svg += 'L '+str(p3.x)+' '+str(p3.y)+' '
                        svg += 'L '+str(p4.x)+' '+str(p4.y)+'" '

                    svg += 'fill="none" stroke="'
                    svg += stroke + '" '
                    svg += 'stroke-width="' + str(linewidth) + ' px" '
                    svg += 'style="stroke-width:'+ str(linewidth)
                    svg += ';stroke-miterlimit:4;stroke-dasharray:none" '
                    svg += 'freecad:basepoint1="'+str(p1.x)+' '+str(p1.y)+'" '
                    svg += 'freecad:basepoint2="'+str(p4.x)+' '+str(p4.y)+'" '
                    svg += 'freecad:dimpoint="'+str(p2.x)+' '+str(p2.y)+'"'
                    svg += '/>\n'

                    # drawing dimension and extension lines overshoots
                    if hasattr(obj.ViewObject,"DimOvershoot") and obj.ViewObject.DimOvershoot.Value:
                        shootsize = obj.ViewObject.DimOvershoot.Value/pointratio
                        svg += getOvershoot(p2,shootsize,stroke,linewidth,angle)
                        svg += getOvershoot(p3,shootsize,stroke,linewidth,angle+math.pi)
                    if hasattr(obj.ViewObject,"ExtOvershoot") and obj.ViewObject.ExtOvershoot.Value:
                        shootsize = obj.ViewObject.ExtOvershoot.Value/pointratio
                        shootangle = -DraftVecUtils.angle(p1.sub(p2))
                        svg += getOvershoot(p2,shootsize,stroke,linewidth,shootangle)
                        svg += getOvershoot(p3,shootsize,stroke,linewidth,shootangle)

                    # drawing arrows
                    if hasattr(obj.ViewObject,"ArrowType"):
                        arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
                        if hasattr(obj.ViewObject,"FlipArrows"):
                            if obj.ViewObject.FlipArrows:
                                angle = angle+math.pi
                        svg += getArrow(obj.ViewObject.ArrowType,p2,arrowsize,stroke,linewidth,angle)
                        svg += getArrow(obj.ViewObject.ArrowType,p3,arrowsize,stroke,linewidth,angle+math.pi)

                    # drawing text
                    svg += getText(stroke,fontsize,obj.ViewObject.FontName,tangle,tbase,prx.string)

    elif getType(obj) == "AngularDimension":
        if gui:
            if not obj.ViewObject:
                print ("export of dimensions to SVG is only available in GUI mode")
            elif obj.ViewObject.Proxy:
                if hasattr(obj.ViewObject.Proxy,"circle"):
                    prx = obj.ViewObject.Proxy

                    # drawing arc
                    fill= "none"
                    lstyle = getLineStyle(linestyle, scale)
                    if obj.ViewObject.DisplayMode == "2D":
                        svg += getPath([prx.circle])
                    else:
                        if hasattr(prx,"circle1"):
                            svg += getPath([prx.circle1])
                            svg += getPath([prx.circle2])
                        else:
                            svg += getPath([prx.circle])

                    # drawing arrows
                    if hasattr(obj.ViewObject,"ArrowType"):
                        p2 = getProj(prx.p2, plane)
                        p3 = getProj(prx.p3, plane)
                        arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
                        arrowlength = 4*obj.ViewObject.ArrowSize.Value
                        u1 = getProj((prx.circle.valueAt(prx.circle.FirstParameter+arrowlength)).sub(prx.circle.valueAt(prx.circle.FirstParameter)), plane)
                        u2 = getProj((prx.circle.valueAt(prx.circle.LastParameter-arrowlength)).sub(prx.circle.valueAt(prx.circle.LastParameter)), plane)
                        angle1 = -DraftVecUtils.angle(u1)
                        angle2 = -DraftVecUtils.angle(u2)
                        if hasattr(obj.ViewObject,"FlipArrows"):
                            if obj.ViewObject.FlipArrows:
                                angle1 = angle1+math.pi
                                angle2 = angle2+math.pi
                        svg += getArrow(obj.ViewObject.ArrowType,p2,arrowsize,stroke,linewidth,angle1)
                        svg += getArrow(obj.ViewObject.ArrowType,p3,arrowsize,stroke,linewidth,angle2)

                    # drawing text
                    if obj.ViewObject.DisplayMode == "2D":
                        t = prx.circle.tangentAt(prx.circle.FirstParameter+(prx.circle.LastParameter-prx.circle.FirstParameter)/2.0)
                        t = getProj(t, plane)
                        tangle = DraftVecUtils.angle(t)
                        if (tangle <= -math.pi/2) or (tangle > math.pi/2):
                            tangle = tangle + math.pi
                        tbase = getProj(prx.circle.valueAt(prx.circle.FirstParameter+(prx.circle.LastParameter-prx.circle.FirstParameter)/2.0), plane)
                        tbase = tbase.add(DraftVecUtils.rotate(Vector(0,2.0/scale,0),tangle))
                        #print(tbase)
                    else:
                        tangle = 0
                        tbase = getProj(prx.tbase, plane)
                    svg += getText(stroke,fontsize,obj.ViewObject.FontName,tangle,tbase,prx.string)

    elif getType(obj) == "Label":
        if getattr(obj.ViewObject, "Line", True):  # some Labels may have no Line property
            def format_point(coords, action='L'):
                return "{action}{x},{y}".format(
                    x=coords.x, y=coords.y, action=action
                )

            # Draw multisegment line
            proj_points = list(map(lambda x: getProj(x, plane), obj.Points))
            path_dir_list = [format_point(proj_points[0], action='M')]
            path_dir_list += map(format_point, proj_points[1:])
            path_dir_str = " ".join(path_dir_list)
            svg_path = '<path fill="none" stroke="{stroke}" stroke-width="{linewidth}" d="{directions}"/>'.format(
                stroke=stroke,
                linewidth=linewidth,
                directions=path_dir_str
            )
            svg += svg_path

            # Draw arrow.
            # We are different here from 3D view
            # if Line is set to 'off', no arrow is drawn
            if hasattr(obj.ViewObject, "ArrowType") and len(obj.Points) >= 2:
                last_segment = FreeCAD.Vector(obj.Points[-1] - obj.Points[-2])
                angle = -DraftVecUtils.angle(getProj(last_segment, plane)) + math.pi
                svg += getArrow(
                    arrowtype=obj.ViewObject.ArrowType,
                    point=proj_points[-1],
                    arrowsize=obj.ViewObject.ArrowSize.Value/pointratio,
                    color=stroke,
                    linewidth=linewidth,
                    angle=angle
                )

        # print text
        if gui:
            if not obj.ViewObject:
                print("export of texts to SVG is only available in GUI mode")
            else:
                fontname = obj.ViewObject.TextFont
                position = getProj(obj.Placement.Base, plane)
                rotation = obj.Placement.Rotation
                justification = obj.ViewObject.TextAlignment
                text = obj.Text
                svg += getText(stroke, fontsize, fontname, rotation, position,
                               text, linespacing, justification)

    elif getType(obj) in ["Annotation","DraftText"]:
        "returns an svg representation of a document annotation"
        if gui:
            if not obj.ViewObject:
                print ("export of texts to SVG is only available in GUI mode")
            else:
                n = obj.ViewObject.FontName
                if getType(obj) == "Annotation":
                    p = getProj(obj.Position, plane)
                    r = obj.ViewObject.Rotation.getValueAs("rad")
                    t = obj.LabelText
                else: # DraftText
                    p = getProj(obj.Placement.Base, plane)
                    r = obj.Placement.Rotation
                    t = obj.Text
                j = obj.ViewObject.Justification
                svg += getText(stroke,fontsize,n,r,p,t,linespacing,j)

    elif getType(obj) == "Axis":
        "returns the SVG representation of an Arch Axis system"
        if gui:
            if not obj.ViewObject:
                print ("export of axes to SVG is only available in GUI mode")
            else:
                vobj = obj.ViewObject
                lorig = getLineStyle(linestyle, scale)
                fill = 'none'
                rad = vobj.BubbleSize.Value/2
                n = 0
                for e in obj.Shape.Edges:
                    lstyle = lorig
                    svg += getPath([e])
                    lstyle = "none"
                    pos = ["Start"]
                    if hasattr(vobj,"BubblePosition"):
                        if vobj.BubblePosition == "Both":
                            pos = ["Start","End"]
                        else:
                            pos = [vobj.BubblePosition]
                    for p in pos:
                        if p == "Start":
                            p1 = e.Vertexes[0].Point
                            p2 = e.Vertexes[1].Point
                        else:
                            p1 = e.Vertexes[1].Point
                            p2 = e.Vertexes[0].Point
                        dv = p2.sub(p1)
                        dv.normalize()
                        center = p2.add(dv.scale(rad,rad,rad))
                        svg += getCircle(Part.makeCircle(rad,center))
                        if hasattr(vobj.Proxy,"bubbletexts"):
                            if len (vobj.Proxy.bubbletexts) >= n:
                                svg += '<text fill="' + stroke + '" '
                                svg += 'font-size="' + str(rad) + '" '
                                svg += 'style="text-anchor:middle;'
                                svg += 'text-align:center;'
                                svg += 'font-family: sans;" '
                                svg += 'transform="translate(' + str(center.x+rad/4.0) + ',' + str(center.y-rad/3.0) + ') '
                                svg += 'scale(1,-1)"> '
                                svg += '<tspan>' + obj.ViewObject.Proxy.bubbletexts[n].string.getValues()[0] + '</tspan>\n'
                                svg += '</text>\n'
                                n += 1

    elif getType(obj) == "Pipe":
        fill = stroke
        lstyle = getLineStyle(linestyle, scale)
        if obj.Base and obj.Diameter:
            svg += getPath(obj.Base.Shape.Edges)
        for f in obj.Shape.Faces:
            if len(f.Edges) == 1:
                if isinstance(f.Edges[0].Curve,Part.Circle):
                    svg += getCircle(f.Edges[0])

    elif getType(obj) == "Rebar":
        fill = "none"
        lstyle = getLineStyle(linestyle, scale)
        if obj.Proxy:
            if not hasattr(obj.Proxy,"wires"):
                obj.Proxy.execute(obj)
            if hasattr(obj.Proxy,"wires"):
                svg += getPath(wires=obj.Proxy.wires)

    elif getType(obj) == "PipeConnector":
        pass

    elif getType(obj) == "Space":
        "returns an SVG fragment for the text of a space"
        if gui:
            if not obj.ViewObject:
                print ("export of spaces to SVG is only available in GUI mode")
            else:
                c = getrgb(obj.ViewObject.TextColor)
                n = obj.ViewObject.FontName
                a = 0
                if rotation != 0:
                    a = math.radians(rotation)
                t1 = obj.ViewObject.Proxy.text1.string.getValues()
                t2 = obj.ViewObject.Proxy.text2.string.getValues()
                scale = obj.ViewObject.FirstLine.Value/obj.ViewObject.FontSize.Value
                f1 = fontsize*scale
                p2 = FreeCAD.Vector(obj.ViewObject.Proxy.coords.translation.getValue().getValue())
                lspc = FreeCAD.Vector(obj.ViewObject.Proxy.header.translation.getValue().getValue())
                p1 = p2.add(lspc)
                j = obj.ViewObject.TextAlign
                svg += getText(c,f1,n,a,getProj(p1, plane),t1,linespacing,j,flip=True)
                if t2:
                    ofs = FreeCAD.Vector(0,lspc.Length,0)
                    if a:
                        ofs = FreeCAD.Rotation(FreeCAD.Vector(0,0,1),-rotation).multVec(ofs)
                    svg += getText(c,fontsize,n,a,getProj(p1, plane).add(ofs),t2,linespacing,j,flip=True)

    elif obj.isDerivedFrom('Part::Feature'):
        if obj.Shape.isNull():
            return ''
        # setting fill
        if obj.Shape.Faces:
            if gui:
                try:
                    m = obj.ViewObject.DisplayMode
                except AttributeError:
                    m = None
                if (m != "Wireframe"):
                    if fillstyle == "shape color":
                        fill = getrgb(obj.ViewObject.ShapeColor,testbw=False)
                        fill_opacity = 1 - (obj.ViewObject.Transparency / 100.0)
                    else:
                        fill = 'url(#'+fillstyle+')'
                        svg += getPattern(fillstyle)
                else:
                    fill = "none"
            else:
                fill = "#888888"
        else:
            fill = 'none'
        lstyle = getLineStyle(linestyle, scale)

        if len(obj.Shape.Vertexes) > 1:
            wiredEdges = []
            if obj.Shape.Faces:
                for i,f in enumerate(obj.Shape.Faces):
                    svg += getPath(wires=f.Wires,pathname='%s_f%04d' % \
                            (obj.Name,i))
                    wiredEdges.extend(f.Edges)
            else:
                for i,w in enumerate(obj.Shape.Wires):
                    svg += getPath(w.Edges,pathname='%s_w%04d' % \
                            (obj.Name,i))
                    wiredEdges.extend(w.Edges)
            if len(wiredEdges) != len(obj.Shape.Edges):
                for i,e in enumerate(obj.Shape.Edges):
                    if (DraftGeomUtils.findEdge(e,wiredEdges) == None):
                        svg += getPath([e],pathname='%s_nwe%04d' % \
                                (obj.Name,i))
        else:
            # closed circle or spline
            if obj.Shape.Edges:
                if isinstance(obj.Shape.Edges[0].Curve,Part.Circle):
                    svg = getCircle(obj.Shape.Edges[0])
                else:
                    svg = getPath(obj.Shape.Edges)
        if FreeCAD.GuiUp:
            if hasattr(obj.ViewObject,"EndArrow") and hasattr(obj.ViewObject,"ArrowType") and (len(obj.Shape.Vertexes) > 1):
                if obj.ViewObject.EndArrow:
                    p1 = getProj(obj.Shape.Vertexes[-2].Point, plane)
                    p2 = getProj(obj.Shape.Vertexes[-1].Point, plane)
                    angle = -DraftVecUtils.angle(p2.sub(p1))
                    arrowsize = obj.ViewObject.ArrowSize.Value/pointratio
                    svg += getArrow(obj.ViewObject.ArrowType,p2,arrowsize,stroke,linewidth,angle)

    # techdraw expects bottom-to-top coordinates
    if techdraw:
        svg = '<g transform ="scale(1,-1)">'+svg+'</g>'
    return svg
Ejemplo n.º 49
0
    def execute(self,obj):
        import Part, math, DraftGeomUtils
        pl = obj.Placement
        self.baseface = None

        base = None
        if obj.Base and obj.Angles:
            w = None
            if obj.Base.isDerivedFrom("Part::Feature"):
                if (obj.Base.Shape.Faces and obj.Face):
                    w = obj.Base.Shape.Faces[obj.Face-1].Wires[0]
                elif obj.Base.Shape.Wires:
                    w = obj.Base.Shape.Wires[0]
            if w:
                if w.isClosed():
                    self.profilsDico = []
                    self.shps = []
                    self.subVolshps = []
                    heights = []
                    edges = DraftGeomUtils.sortEdges(w.Edges)
                    l = len(edges)
                    print("le contour contient "+str(l)+" aretes")
                    for i in range(l):
                        self.makeRoofProfilsDic(i, obj.Angles[i], obj.Runs[i], obj.IdRel[i], obj.Overhang[i], obj.Thickness[i])
                    for i in range(l):
                        self.calcMissingData(i)
                    for p in self.profilsDico:
                        heights.append(p["height"])
                    obj.Heights = heights
                    for i in range(l):
                        edgesForward = edges[:]
                        edgesForward.append(edges[0])
                        ptsPaneProject=[]
                        profil0 =self.profilsDico[i-1]
                        profil1 =self.profilsDico[i]
                        if i == l-1:
                            profil2 =self.profilsDico[0]
                        else:
                            profil2 =self.profilsDico[i+1]
                        vec0 = edges[i-1].Vertexes[-1].Point.sub(edges[i-1].Vertexes[0].Point)
                        vec1 = edges[i].Vertexes[-1].Point.sub(edges[i].Vertexes[0].Point)
                        vec2 = edgesForward[i+1].Vertexes[-1].Point.sub(edgesForward[i+1].Vertexes[0].Point)
                        rotEdge0 = math.degrees(DraftVecUtils.angle(vec0))
                        rotEdge1 = math.degrees(DraftVecUtils.angle(vec1))
                        rotEdge2 = math.degrees(DraftVecUtils.angle(vec2))
                        edgeEave0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["overhang"]).negative())
                        edgeEave1 = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,profil1["overhang"]).negative())
                        edgeEave2 = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,profil2["overhang"]).negative())
                        pt0Eave1 = DraftGeomUtils.findIntersection(edgeEave0,edgeEave1,infinite1=True,infinite2=True,)
                        pt1Eave1 = DraftGeomUtils.findIntersection(edgeEave1,edgeEave2,infinite1=True,infinite2=True,)
                        edgeEave1 = DraftGeomUtils.edg(FreeCAD.Vector(pt0Eave1[0]),FreeCAD.Vector(pt1Eave1[0]))
                        edgeRidge0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["run"]))
                        edgeRidge1 = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,profil1["run"]))
                        edgeRidge2 = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,profil2["run"]))
                        midpoint = DraftGeomUtils.findMidpoint(edges[i])
                        pt0Edge1 = edges[i].Vertexes[0].Point
                        pt1Edge1 = edges[i].Vertexes[-1].Point
                        print("Analyse profil " + str(i))
                        if profil1["angle"] != 90.:
                            if profil2["angle"] == 90. :
                                print("situation a droite : pignon")
                                ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0]))
                                point = DraftGeomUtils.findIntersection(edgeRidge1,edgeEave2,infinite1=True,infinite2=True,)
                                ptsPaneProject.append(FreeCAD.Vector(point[0]))
                            elif profil1["height"] == profil2["height"] :
                                print("situation a droite : ht1 = ht2")
                                ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2,infinite1=True,infinite2=True,)
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt1Edge1)
                                ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave1:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0]))
                                else:
                                    ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0]))
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
                            elif profil1["height"] > profil2["height"]:
                                print("situation a droite : ht1 > ht2")
                                dec = profil2["height"]/math.tan(math.radians(profil1["angle"]))
                                edgeRidge2OnPane = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,dec))
                                ptInter1 = DraftGeomUtils.findIntersection(edgeRidge2,edgeRidge2OnPane,infinite1=True,infinite2=True,)
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt1Edge1)
                                ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave1:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0]))
                                else:
                                    ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0]))
                                ptsPaneProject.append(FreeCAD.Vector(ptInter1[0]))
                                ptInter2 = edgeHip.Vertexes[0].Point
                                vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter2, [edgeRidge1.Edges[0],], force=0)
                                ptInterRidges = ptInter2.add(vecInterRidges[0])
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges))
                            elif profil1["height"] < profil2["height"]:
                                print("situation a droite : ht1 < ht2")
                                dec = profil1["height"]/math.tan(math.radians(profil2["angle"]))
                                edgeRidge2OnPane = DraftGeomUtils.offset(edgesForward[i+1],self.getPerpendicular(vec2,rotEdge2,dec))
                                ptInter1 = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2OnPane,infinite1=True,infinite2=True,)
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt1Edge1)
                                ptInterHipEave1 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave1:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave1[0]))
                                else:
                                    ptInterHipEave2 = DraftGeomUtils.findIntersection(edgeHip,edgeEave2,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(pt1Eave1[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave2[0]))
                                ptsPaneProject.append(FreeCAD.Vector(ptInter1[0]))
                                ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge2,infinite1=True,infinite2=True,)
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
                            else:
                                print("Cas de figure non pris en charge")
                            if profil0["angle"] == 90. :
                                print("situation a gauche : pignon")
                                point = DraftGeomUtils.findIntersection(edgeRidge1,edgeEave0,infinite1=True,infinite2=True,)
                                ptsPaneProject.append(FreeCAD.Vector(point[0]))
                                ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0]))
                            elif profil0["height"] == profil1["height"]:
                                print("situation a gauche : ht1 = ht0")
                                edgeRidge0 = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,profil0["run"]))
                                ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge1,edgeRidge0,infinite1=True,infinite2=True,)
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt0Edge1)
                                ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave3:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0]))
                                else:
                                    ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0]))
                            elif profil1["height"] > profil0["height"]:
                                print("situation a gauche : ht1 > ht0")
                                dec = profil0["height"]/math.tan(math.radians(profil1["angle"]))
                                edgeRidge0OnPane = DraftGeomUtils.offset(edges[i],self.getPerpendicular(vec1,rotEdge1,dec))
                                ptInter1 = DraftGeomUtils.findIntersection(edgeRidge0OnPane,edgeRidge0,infinite1=True,infinite2=True,)
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInter1[0]),pt0Edge1)
                                ptInter2 = edgeHip.Vertexes[0].Point
                                vecInterRidges = DraftGeomUtils.findPerpendicular(ptInter2, [edgeRidge1.Edges[0],], force=0)
                                ptInterRidges = ptInter2.add(vecInterRidges[0])
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges))
                                ptsPaneProject.append(FreeCAD.Vector(ptInter1[0]))
                                ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave3:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0]))
                                else:
                                    ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0]))
                            elif profil1["height"] < profil0["height"]:
                                print("situation a gauche : ht1 < ht0")
                                dec = profil1["height"]/math.tan(math.radians(profil0["angle"]))
                                edgeRidge0OnPane = DraftGeomUtils.offset(edges[i-1],self.getPerpendicular(vec0,rotEdge0,dec))
                                ptInterRidges = DraftGeomUtils.findIntersection(edgeRidge0OnPane,edgeRidge1,infinite1=True,infinite2=True,)
                                ptsPaneProject.append(FreeCAD.Vector(ptInterRidges[0]))
                                edgeHip = DraftGeomUtils.edg(FreeCAD.Vector(ptInterRidges[0]),pt0Edge1)
                                ptInterHipEave3 = DraftGeomUtils.findIntersection(edgeHip,edgeEave1,infinite1=True,infinite2=False,)
                                if ptInterHipEave3:
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave3[0]))
                                else:
                                    ptInterHipEave4 = DraftGeomUtils.findIntersection(edgeHip,edgeEave0,infinite1=True,infinite2=True,)
                                    ptsPaneProject.append(FreeCAD.Vector(ptInterHipEave4[0]))
                                    ptsPaneProject.append(FreeCAD.Vector(pt0Eave1[0]))
                            else:
                                print("Cas de figure non pris en charge")
                            ptsPaneProject = DraftVecUtils.removeDoubles(ptsPaneProject)
                            print("ptsPaneProject",ptsPaneProject)
                            print("Fin Analyse profil " + str(i))
                            self.profilsDico[i]["points"] = ptsPaneProject
                            lp = len(ptsPaneProject)
                            ptsPaneProject.append(ptsPaneProject[0])
                            edgesWire = []
                            for i in range(lp):
                                edge = Part.makeLine(ptsPaneProject[i],ptsPaneProject[i+1])
                                edgesWire.append(edge)
                            wire = Part.Wire(edgesWire)
                            d = wire.BoundBox.DiagonalLength
                            thicknessV = profil1["thickness"]/(math.cos(math.radians(profil1["angle"])))
                            overhangV = profil1["overhang"]*math.tan(math.radians(profil1["angle"]))
                            if wire.isClosed():
                                f = Part.Face(wire)
                                f = f.extrude(FreeCAD.Vector(0,0,profil1["height"]+2*thicknessV+2*overhangV))
                                f.translate(FreeCAD.Vector(0.0,0.0,-2*overhangV))
                            ptsPaneProfil=[FreeCAD.Vector(-profil1["overhang"],-overhangV,0.0),FreeCAD.Vector(profil1["run"],profil1["height"],0.0),FreeCAD.Vector(profil1["run"],profil1["height"]+thicknessV,0.0),FreeCAD.Vector(-profil1["overhang"],-overhangV+thicknessV,0.0)]
                            self.createProfilShape (ptsPaneProfil, midpoint, rotEdge1, vec1, profil1["run"], d, self.shps, f)
                            ## subVolume shape
                            ptsSubVolumeProfil=[FreeCAD.Vector(-profil1["overhang"],-overhangV,0.0),FreeCAD.Vector(profil1["run"],profil1["height"],0.0),FreeCAD.Vector(profil1["run"],profil1["height"]+10000,0.0),FreeCAD.Vector(0.0,profil1["height"]+10000,0.0)]
                            self.createProfilShape (ptsSubVolumeProfil, midpoint, rotEdge1, vec1, profil1["run"], d, self.subVolshps, f)
                        else:
                            #TODO PIGNON
                            pass

                    ## SubVolume
                    self.sub = self.subVolshps.pop()
                    for s in self.subVolshps:
                        self.sub = self.sub.fuse(s)
                    self.sub = self.sub.removeSplitter()
                    if not self.sub.isNull():
                        if not DraftGeomUtils.isNull(pl):
                            self.sub.Placement = pl
                    ## BaseVolume
                    base = Part.makeCompound(self.shps)
                    if not base.isNull():
                        if not DraftGeomUtils.isNull(pl):
                            base.Placement = pl
        base = self.processSubShapes(obj,base)
        if base:
            if not base.isNull():
                obj.Shape = base
Ejemplo n.º 50
0
 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