Пример #1
0
def isCubic(shape):
    """Return True if the shape is a parallelepiped (cuboid).

    A parallelepiped of cube-like shape has 8 vertices, 6 faces, 12 edges,
    and all angles are 90 degrees between its edges.
    """
    # first we try fast methods
    if (len(shape.Vertexes) != 8 or len(shape.Faces) != 6
            or len(shape.Edges) != 12):
        return False

    for e in shape.Edges:
        if geomType(e) != "Line":
            return False

    # if ok until now, let's do more advanced testing
    for f in shape.Faces:
        if len(f.Edges) != 4:
            return False

        for i in range(4):
            e1 = vec(f.Edges[i])
            if i < 3:
                e2 = vec(f.Edges[i + 1])
            else:
                e2 = vec(f.Edges[0])
            rpi = [0.0, round(math.pi / 2, precision())]
            if round(e1.getAngle(e2), precision()) not in rpi:
                return False

    return True
Пример #2
0
def isCubic(shape):
    """isCubic(shape): verifies if a shape is cubic, that is, has
    8 vertices, 6 faces, and all angles are 90 degrees."""
    # first we try fast methods
    if len(shape.Vertexes) != 8:
        return False
    if len(shape.Faces) != 6:
        return False
    if len(shape.Edges) != 12:
        return False
    for e in shape.Edges:
        if geomType(e) != "Line":
            return False
    # if ok until now, let's do more advanced testing
    for f in shape.Faces:
        if len(f.Edges) != 4: return False
        for i in range(4):
            e1 = vec(f.Edges[i])
            if i < 3:
                e2 = vec(f.Edges[i + 1])
            else:
                e2 = vec(f.Edges[0])
            rpi = [0.0, round(math.pi / 2, precision())]
            if not round(e1.getAngle(e2), precision()) in rpi:
                return False
    return True
Пример #3
0
def removeInterVertices(wire):
    """Remove middle vertices from a straight wire and return a new wire.

    Remove unneeded vertices, those that are in the middle of a straight line,
    from a wire, return a new wire.
    """
    _pre = precision()
    edges = Part.__sortEdges__(wire.Edges)
    nverts = []

    def getvec(v1, v2):
        if not abs(round(v1.getAngle(v2), _pre) in [0, round(math.pi, _pre)]):
            nverts.append(edges[i].Vertexes[-1].Point)

    for i in range(len(edges) - 1):
        vA = vec(edges[i])
        vB = vec(edges[i + 1])
        getvec(vA, vB)

    vA = vec(edges[-1])
    vB = vec(edges[0])
    getvec(vA, vB)

    if nverts:
        if wire.isClosed():
            nverts.append(nverts[0])
        w = Part.makePolygon(nverts)
        return w
    else:
        return wire
Пример #4
0
def isCoplanar(faces, tolerance=0):
    """Return True if all faces in the given list are coplanar.

    Tolerance is the maximum deviation to be considered coplanar.
    """
    if len(faces) < 2:
        return True

    base = faces[0].normalAt(0, 0)

    for i in range(1, len(faces)):
        for v in faces[i].Vertexes:
            chord = v.Point.sub(faces[0].Vertexes[0].Point)
            dist = DraftVecUtils.project(chord, base)
            if round(dist.Length, precision()) > tolerance:
                return False
    return True
Пример #5
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())
    ]
Пример #6
0
 def getvec(v1, v2):
     if not abs(
             round(v1.getAngle(v2), precision()) in
         [0, round(math.pi, precision())]):
         nverts.append(edges[i].Vertexes[-1].Point)
Пример #7
0
def getCubicDimensions(shape):
    """Return a list containing the placement, and dimensions of the shape.

    The dimensios are length, width and height of a the parallelepiped,
    rounded to the value indicated by `precision`.
    The placement point is the lowest corner of the shape.

    If it is not a parallelepiped (cuboid), return None.
    """
    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, App.Vector(vx.x, vx.y, 0))
    rotX = DraftVecUtils.angle(vy, App.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 = App.Matrix()
    mat.move(plpoint)
    mat.rotateX(rotX)
    mat.rotateY(rotY)
    mat.rotateZ(rotZ)

    return [
        App.Placement(mat),
        round(vx.Length, precision()),
        round(vy.Length, precision()),
        round(vz.Length, precision())
    ]
Пример #8
0
def findIntersection(edge1,
                     edge2,
                     infinite1=False,
                     infinite2=False,
                     ex1=False,
                     ex2=False,
                     dts=True,
                     findAll=False):
    """Return a list containing the intersection points of 2 edges.

    You can also feed 4 points instead of `edge1` and `edge2`.
    If `dts` is used, `Shape.distToShape()` is used, which can be buggy.
    """
    def getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2):
        if pt1:
            # first check if we don't already have coincident endpoints
            if pt1 in [pt3, pt4]:
                return [pt1]
            elif (pt2 in [pt3, pt4]):
                return [pt2]
        norm1 = pt2.sub(pt1).cross(pt3.sub(pt1))
        norm2 = pt2.sub(pt4).cross(pt3.sub(pt4))

        if not DraftVecUtils.isNull(norm1):
            try:
                norm1.normalize()
            except Part.OCCError:
                return []

        if not DraftVecUtils.isNull(norm2):
            try:
                norm2.normalize()
            except Part.OCCError:
                return []

        if DraftVecUtils.isNull(norm1.cross(norm2)):
            vec1 = pt2.sub(pt1)
            vec2 = pt4.sub(pt3)
            if DraftVecUtils.isNull(vec1) or DraftVecUtils.isNull(vec2):
                return []  # One of the lines has zero-length
            try:
                vec1.normalize()
                vec2.normalize()
            except Part.OCCError:
                return []
            norm3 = vec1.cross(vec2)
            denom = norm3.x + norm3.y + norm3.z
            if not DraftVecUtils.isNull(norm3) and denom != 0:
                k = ((pt3.z - pt1.z) * (vec2.x - vec2.y) + (pt3.y - pt1.y) *
                     (vec2.z - vec2.x) + (pt3.x - pt1.x) *
                     (vec2.y - vec2.z)) / denom
                vec1.scale(k, k, k)
                intp = pt1.add(vec1)

                if infinite1 is False and not isPtOnEdge(intp, edge1):
                    return []

                if infinite2 is False and not isPtOnEdge(intp, edge2):
                    return []

                return [intp]
            else:
                return []  # Lines have same direction
        else:
            return []  # Lines aren't on same plane

    # First, check bound boxes
    if (isinstance(edge1, Part.Edge) and isinstance(edge2, Part.Edge)
            and (not infinite1) and (not infinite2)):
        if not edge1.BoundBox.intersect(edge2.BoundBox):
            return []  # bound boxes don't intersect

    # First, try to use distToShape if possible
    if (dts and isinstance(edge1, Part.Edge) and isinstance(edge2, Part.Edge)
            and (not infinite1) and (not infinite2)):
        dist, pts, geom = edge1.distToShape(edge2)
        sol = []
        if round(dist, precision()) == 0:
            for p in pts:
                if p not in sol:
                    sol.append(p[0])
        return sol

    pt1 = None

    if isinstance(edge1, FreeCAD.Vector) and isinstance(edge2, FreeCAD.Vector):
        # we got points directly
        pt1 = edge1
        pt2 = edge2
        pt3 = infinite1
        pt4 = infinite2
        infinite1 = ex1
        infinite2 = ex2
        return getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2)

    elif (geomType(edge1) == "Line") and (geomType(edge2) == "Line"):
        # we have 2 straight lines
        pt1, pt2, pt3, pt4 = [
            edge1.Vertexes[0].Point, edge1.Vertexes[1].Point,
            edge2.Vertexes[0].Point, edge2.Vertexes[1].Point
        ]
        return getLineIntersections(pt1, pt2, pt3, pt4, infinite1, infinite2)

    elif ((geomType(edge1) == "Circle") and (geomType(edge2) == "Line")
          or (geomType(edge1) == "Line") and (geomType(edge2) == "Circle")):

        # deals with an arc or circle and a line
        edges = [edge1, edge2]
        for edge in edges:
            if geomType(edge) == "Line":
                line = edge
            else:
                arc = edge

        dirVec = vec(line)
        dirVec.normalize()
        pt1 = line.Vertexes[0].Point
        pt2 = line.Vertexes[1].Point
        pt3 = arc.Vertexes[0].Point
        pt4 = arc.Vertexes[-1].Point
        center = arc.Curve.Center

        int = []
        # first check for coincident endpoints
        if DraftVecUtils.equals(pt1, pt3) or DraftVecUtils.equals(pt1, pt4):
            if findAll:
                int.append(pt1)
            else:
                return [pt1]
        elif pt2 in [pt3, pt4]:
            if findAll:
                int.append(pt2)
            else:
                return [pt2]

        if DraftVecUtils.isNull(
                pt1.sub(center).cross(pt2.sub(center)).cross(arc.Curve.Axis)):
            # Line and Arc are on same plane

            dOnLine = center.sub(pt1).dot(dirVec)
            onLine = FreeCAD.Vector(dirVec)
            onLine.scale(dOnLine, dOnLine, dOnLine)
            toLine = pt1.sub(center).add(onLine)

            if toLine.Length < arc.Curve.Radius:
                dOnLine = (arc.Curve.Radius**2 - toLine.Length**2)**(0.5)
                onLine = FreeCAD.Vector(dirVec)
                onLine.scale(dOnLine, dOnLine, dOnLine)
                int += [center.add(toLine).add(onLine)]
                onLine = FreeCAD.Vector(dirVec)
                onLine.scale(-dOnLine, -dOnLine, -dOnLine)
                int += [center.add(toLine).add(onLine)]
            elif round(toLine.Length - arc.Curve.Radius, precision()) == 0:
                int = [center.add(toLine)]
            else:
                return []

        else:
            # Line isn't on Arc's plane
            if dirVec.dot(arc.Curve.Axis) != 0:
                toPlane = FreeCAD.Vector(arc.Curve.Axis)
                toPlane.normalize()
                d = pt1.dot(toPlane)
                if not d:
                    return []
                dToPlane = center.sub(pt1).dot(toPlane)
                toPlane = FreeCAD.Vector(pt1)
                toPlane.scale(dToPlane / d, dToPlane / d, dToPlane / d)
                ptOnPlane = toPlane.add(pt1)
                if round(
                        ptOnPlane.sub(center).Length - arc.Curve.Radius,
                        precision()) == 0:
                    int = [ptOnPlane]
                else:
                    return []
            else:
                return []

        if infinite1 is False:
            for i in range(len(int) - 1, -1, -1):
                if not isPtOnEdge(int[i], edge1):
                    del int[i]
        if infinite2 is False:
            for i in range(len(int) - 1, -1, -1):
                if not isPtOnEdge(int[i], edge2):
                    del int[i]
        return int

    elif (geomType(edge1) == "Circle") and (geomType(edge2) == "Circle"):
        # deals with 2 arcs or circles
        cent1, cent2 = edge1.Curve.Center, edge2.Curve.Center
        rad1, rad2 = edge1.Curve.Radius, edge2.Curve.Radius
        axis1, axis2 = edge1.Curve.Axis, edge2.Curve.Axis
        c2c = cent2.sub(cent1)

        if cent1.sub(cent2).Length == 0:
            # circles are concentric
            return []

        if DraftVecUtils.isNull(axis1.cross(axis2)):
            if round(c2c.dot(axis1), precision()) == 0:
                # circles are on same plane
                dc2c = c2c.Length
                if not DraftVecUtils.isNull(c2c):
                    c2c.normalize()
                if (round(rad1 + rad2 - dc2c, precision()) < 0
                        or round(rad1 - dc2c - rad2, precision()) > 0
                        or round(rad2 - dc2c - rad1, precision()) > 0):
                    return []
                else:
                    norm = c2c.cross(axis1)
                    if not DraftVecUtils.isNull(norm):
                        norm.normalize()
                    if DraftVecUtils.isNull(norm):
                        x = 0
                    else:
                        x = (dc2c**2 + rad1**2 - rad2**2) / (2 * dc2c)
                    y = abs(rad1**2 - x**2)**(0.5)
                    c2c.scale(x, x, x)
                    if round(y, precision()) != 0:
                        norm.scale(y, y, y)
                        int = [cent1.add(c2c).add(norm)]
                        int += [cent1.add(c2c).sub(norm)]
                    else:
                        int = [cent1.add(c2c)]
            else:
                return []  # circles are on parallel planes
        else:
            # circles aren't on same plane
            axis1.normalize()
            axis2.normalize()
            U = axis1.cross(axis2)
            V = axis1.cross(U)
            dToPlane = c2c.dot(axis2)
            d = V.add(cent1).dot(axis2)
            V.scale(dToPlane / d, dToPlane / d, dToPlane / d)
            PtOn2Planes = V.add(cent1)
            planeIntersectionVector = U.add(PtOn2Planes)
            intTemp = findIntersection(planeIntersectionVector, edge1, True,
                                       True)
            int = []
            for pt in intTemp:
                if round(pt.sub(cent2).Length - rad2, precision()) == 0:
                    int += [pt]

        if infinite1 is False:
            for i in range(len(int) - 1, -1, -1):
                if not isPtOnEdge(int[i], edge1):
                    del int[i]
        if infinite2 is False:
            for i in range(len(int) - 1, -1, -1):
                if not isPtOnEdge(int[i], edge2):
                    del int[i]

        return int
    else:
        print("DraftGeomUtils: Unsupported curve type: "
              "(" + str(edge1.Curve) + ", " + str(edge2.Curve) + ")")
        return []
Пример #9
0
def get_extended_wire(wire, offset_start, offset_end):
    """Return a wire trimmed (negative offset) or extended (positive offset) at its first vertex, last vertex or both ends. 
    
    get_extended_wire(wire, -100.0, 0.0) -> returns a copy of the wire with its first 100 mm removed
    get_extended_wire(wire, 0.0, 100.0) -> returns a copy of the wire extended by 100 mm after it's last vertex
    """
    if min(offset_start, offset_end,
           offset_start + offset_end) <= -wire.Length:
        App.Console.PrintError(
            "debug: get_extended_wire error, wire's length insufficient for trimming.\n"
        )
        return wire
    if offset_start < 0:  # Trim the wire from the first vertex
        offset_start = -offset_start
        out_edges = []
        for edge in wire.OrderedEdges:
            if offset_start >= edge.Length:  # Remove entire edge
                offset_start -= edge.Length
            elif round(offset_start, precision()
                       ) > 0:  # Split edge, to remove the required length
                if edge.Orientation == "Forward":
                    new_edge = edge.split(
                        edge.getParameterByLength(
                            offset_start)).OrderedEdges[1]
                else:
                    new_edge = edge.split(
                        edge.getParameterByLength(
                            edge.Length - offset_start)).OrderedEdges[0]
                new_edge.Placement = edge.Placement  # Strangely, edge.split discards the placement and orientation
                new_edge.Orientation = edge.Orientation
                out_edges.append(new_edge)
                offset_start = 0
            else:  # Keep the remaining entire edges
                out_edges.append(edge)
        wire = Part.Wire(out_edges)
    elif offset_start > 0:  # Extend the first edge along its normal
        first_edge = wire.OrderedEdges[0]
        if first_edge.Orientation == "Forward":
            start, end = first_edge.FirstParameter, first_edge.LastParameter
            vec = first_edge.tangentAt(start).multiply(offset_start)
        else:
            start, end = first_edge.LastParameter, first_edge.FirstParameter
            vec = -first_edge.tangentAt(start).multiply(offset_start)
        if geomType(
                first_edge
        ) == "Line":  # Replace first edge with the extended new edge
            new_edge = Part.LineSegment(
                first_edge.valueAt(start).sub(vec),
                first_edge.valueAt(end)).toShape()
            wire = Part.Wire([new_edge] + wire.OrderedEdges[1:])
        else:  # Add a straight edge before the first vertex
            new_edge = Part.LineSegment(
                first_edge.valueAt(start).sub(vec),
                first_edge.valueAt(start)).toShape()
            wire = Part.Wire([new_edge] + wire.OrderedEdges)
    if offset_end < 0:  # Trim the wire from the last vertex
        offset_end = -offset_end
        out_edges = []
        for edge in reversed(wire.OrderedEdges):
            if offset_end >= edge.Length:  # Remove entire edge
                offset_end -= edge.Length
            elif round(offset_end, precision()
                       ) > 0:  # Split edge, to remove the required length
                if edge.Orientation == "Forward":
                    new_edge = edge.split(
                        edge.getParameterByLength(edge.Length -
                                                  offset_end)).OrderedEdges[0]
                else:
                    new_edge = edge.split(
                        edge.getParameterByLength(offset_end)).OrderedEdges[1]
                new_edge.Placement = edge.Placement  # Strangely, edge.split discards the placement and orientation
                new_edge.Orientation = edge.Orientation
                out_edges.insert(0, new_edge)
                offset_end = 0
            else:  # Keep the remaining entire edges
                out_edges.insert(0, edge)
        wire = Part.Wire(out_edges)
    elif offset_end > 0:  # Extend the last edge along its normal
        last_edge = wire.OrderedEdges[-1]
        if last_edge.Orientation == "Forward":
            start, end = last_edge.FirstParameter, last_edge.LastParameter
            vec = last_edge.tangentAt(end).multiply(offset_end)
        else:
            start, end = last_edge.LastParameter, last_edge.FirstParameter
            vec = -last_edge.tangentAt(end).multiply(offset_end)
        if geomType(
                last_edge
        ) == "Line":  # Replace last edge with the extended new edge
            new_edge = Part.LineSegment(
                last_edge.valueAt(start),
                last_edge.valueAt(end).add(vec)).toShape()
            wire = Part.Wire(wire.OrderedEdges[:-1] + [new_edge])
        else:  # Add a straight edge after the last vertex
            new_edge = Part.LineSegment(
                last_edge.valueAt(end),
                last_edge.valueAt(end).add(vec)).toShape()
            wire = Part.Wire(wire.OrderedEdges + [new_edge])
    return wire
Пример #10
0
def fillet(lEdges, r, chamfer=False):
    """Return a list of sorted edges describing a round corner.

    Author: Jacques-Antoine Gaudin
    """
    def getCurveType(edge, existingCurveType=None):
        """Build or complete a dictionary containing edges.

        The dictionary contains edges with keys 'Arc' and 'Line'.
        """
        if not existingCurveType:
            existingCurveType = {'Line': [], 'Arc': []}
        if issubclass(type(edge.Curve), Part.LineSegment):
            existingCurveType['Line'] += [edge]
        elif issubclass(type(edge.Curve), Part.Line):
            existingCurveType['Line'] += [edge]
        elif issubclass(type(edge.Curve), Part.Circle):
            existingCurveType['Arc'] += [edge]
        else:
            raise ValueError("Edge's curve must be either Line or Arc")
        return existingCurveType

    rndEdges = lEdges[0:2]
    rndEdges = Part.__sortEdges__(rndEdges)

    if len(rndEdges) < 2:
        return rndEdges

    if r <= 0:
        print("DraftGeomUtils.fillet: Error: radius is negative.")
        return rndEdges

    curveType = getCurveType(rndEdges[0])
    curveType = getCurveType(rndEdges[1], curveType)

    lVertexes = rndEdges[0].Vertexes + [rndEdges[1].Vertexes[-1]]

    if len(curveType['Line']) == 2:
        # Deals with 2-line-edges lists
        U1 = lVertexes[0].Point.sub(lVertexes[1].Point)
        U1.normalize()

        U2 = lVertexes[2].Point.sub(lVertexes[1].Point)
        U2.normalize()

        alpha = U1.getAngle(U2)

        if chamfer:
            # correcting r value so the size of the chamfer = r
            beta = math.pi - alpha / 2
            r = (r / 2) / math.cos(beta)

        # Edges have same direction
        if (round(alpha, precision()) == 0
                or round(alpha - math.pi, precision()) == 0):
            print("DraftGeomUtils.fillet: Warning: "
                  "edges have same direction. Did nothing")
            return rndEdges

        dToCenter = r / math.sin(alpha / 2.0)
        dToTangent = (dToCenter**2 - r**2)**(0.5)
        dirVect = App.Vector(U1)
        dirVect.scale(dToTangent, dToTangent, dToTangent)
        arcPt1 = lVertexes[1].Point.add(dirVect)

        dirVect = U2.add(U1)
        dirVect.normalize()
        dirVect.scale(dToCenter - r, dToCenter - r, dToCenter - r)
        arcPt2 = lVertexes[1].Point.add(dirVect)

        dirVect = App.Vector(U2)
        dirVect.scale(dToTangent, dToTangent, dToTangent)
        arcPt3 = lVertexes[1].Point.add(dirVect)

        if (dToTangent > lEdges[0].Length) or (dToTangent > lEdges[1].Length):
            print("DraftGeomUtils.fillet: Error: radius value ", r,
                  " is too high")
            return rndEdges

        if chamfer:
            rndEdges[1] = Part.Edge(Part.LineSegment(arcPt1, arcPt3))
        else:
            rndEdges[1] = Part.Edge(Part.Arc(arcPt1, arcPt2, arcPt3))

        if lVertexes[0].Point == arcPt1:
            # fillet consumes entire first edge
            rndEdges.pop(0)
        else:
            rndEdges[0] = Part.Edge(
                Part.LineSegment(lVertexes[0].Point, arcPt1))

        if lVertexes[2].Point != arcPt3:
            # fillet does not consume entire second edge
            rndEdges += [
                Part.Edge(Part.LineSegment(arcPt3, lVertexes[2].Point))
            ]

        return rndEdges

    elif len(curveType['Arc']) == 1:
        # Deals with lists containing an arc and a line
        if lEdges[0] in curveType['Arc']:
            lineEnd = lVertexes[2]
            arcEnd = lVertexes[0]
            arcFirst = True
        else:
            lineEnd = lVertexes[0]
            arcEnd = lVertexes[2]
            arcFirst = False
        arcCenter = curveType['Arc'][0].Curve.Center
        arcRadius = curveType['Arc'][0].Curve.Radius
        arcAxis = curveType['Arc'][0].Curve.Axis
        arcLength = curveType['Arc'][0].Length

        U1 = lineEnd.Point.sub(lVertexes[1].Point)
        U1.normalize()
        toCenter = arcCenter.sub(lVertexes[1].Point)
        if arcFirst:  # make sure the tangent points towards the arc
            T = arcAxis.cross(toCenter)
        else:
            T = toCenter.cross(arcAxis)

        projCenter = toCenter.dot(U1)
        if round(abs(projCenter), precision()) > 0:
            normToLine = U1.cross(T).cross(U1)
        else:
            normToLine = App.Vector(toCenter)
        normToLine.normalize()

        dCenterToLine = toCenter.dot(normToLine) - r

        if round(projCenter, precision()) > 0:
            newRadius = arcRadius - r
        elif (round(projCenter, precision()) < 0
              or (round(projCenter, precision()) == 0 and U1.dot(T) > 0)):
            newRadius = arcRadius + r
        else:
            print("DraftGeomUtils.fillet: Warning: "
                  "edges are already tangent. Did nothing")
            return rndEdges

        toNewCent = newRadius**2 - dCenterToLine**2
        if toNewCent > 0:
            toNewCent = abs(abs(projCenter) - toNewCent**(0.5))
        else:
            print("DraftGeomUtils.fillet: Error: radius value ", r,
                  " is too high")
            return rndEdges

        U1.scale(toNewCent, toNewCent, toNewCent)
        normToLine.scale(r, r, r)
        newCent = lVertexes[1].Point.add(U1).add(normToLine)

        arcPt1 = lVertexes[1].Point.add(U1)
        arcPt2 = lVertexes[1].Point.sub(newCent)
        arcPt2.normalize()
        arcPt2.scale(r, r, r)
        arcPt2 = arcPt2.add(newCent)

        if newRadius == arcRadius - r:
            arcPt3 = newCent.sub(arcCenter)
        else:
            arcPt3 = arcCenter.sub(newCent)
        arcPt3.normalize()
        arcPt3.scale(r, r, r)
        arcPt3 = arcPt3.add(newCent)
        arcPt = [arcPt1, arcPt2, arcPt3]

        # Warning: In the following I used a trick for calling
        # the right element in arcPt or V:
        # arcFirst is a boolean so - not arcFirst is -0 or -1
        # list[-1] is the last element of a list and list[0] the first
        # this way I don't have to proceed tests to know the position
        # of the arc
        myTrick = not arcFirst

        V = [arcPt3]
        V += [arcEnd.Point]

        toCenter.scale(-1, -1, -1)

        delLength = arcRadius * V[0].sub(arcCenter).getAngle(toCenter)
        if delLength > arcLength or toNewCent > curveType['Line'][0].Length:
            print("DraftGeomUtils.fillet: Error: radius value ", r,
                  " is too high")
            return rndEdges

        arcAsEdge = arcFrom2Pts(V[-arcFirst], V[-myTrick], arcCenter, arcAxis)

        V = [lineEnd.Point, arcPt1]
        lineAsEdge = Part.Edge(Part.LineSegment(V[-arcFirst], V[myTrick]))

        rndEdges[not arcFirst] = arcAsEdge
        rndEdges[arcFirst] = lineAsEdge
        if chamfer:
            rndEdges[1:1] = [
                Part.Edge(Part.LineSegment(arcPt[-arcFirst], arcPt[-myTrick]))
            ]
        else:
            rndEdges[1:1] = [
                Part.Edge(Part.Arc(arcPt[-arcFirst], arcPt[1],
                                   arcPt[-myTrick]))
            ]

        return rndEdges

    elif len(curveType['Arc']) == 2:
        # Deals with lists of 2 arc-edges
        (arcCenter, arcRadius, arcAxis, arcLength, toCenter, T,
         newRadius) = [], [], [], [], [], [], []

        for i in range(2):
            arcCenter += [curveType['Arc'][i].Curve.Center]
            arcRadius += [curveType['Arc'][i].Curve.Radius]
            arcAxis += [curveType['Arc'][i].Curve.Axis]
            arcLength += [curveType['Arc'][i].Length]
            toCenter += [arcCenter[i].sub(lVertexes[1].Point)]

        T += [arcAxis[0].cross(toCenter[0])]
        T += [toCenter[1].cross(arcAxis[1])]
        CentToCent = toCenter[1].sub(toCenter[0])
        dCentToCent = CentToCent.Length

        sameDirection = (arcAxis[0].dot(arcAxis[1]) > 0)
        TcrossT = T[0].cross(T[1])

        if sameDirection:
            if round(TcrossT.dot(arcAxis[0]), precision()) > 0:
                newRadius += [arcRadius[0] + r]
                newRadius += [arcRadius[1] + r]
            elif round(TcrossT.dot(arcAxis[0]), precision()) < 0:
                newRadius += [arcRadius[0] - r]
                newRadius += [arcRadius[1] - r]
            elif T[0].dot(T[1]) > 0:
                newRadius += [arcRadius[0] + r]
                newRadius += [arcRadius[1] + r]
            else:
                print("DraftGeomUtils.fillet: Warning: "
                      "edges are already tangent. Did nothing")
                return rndEdges

        elif not sameDirection:
            if round(TcrossT.dot(arcAxis[0]), precision()) > 0:
                newRadius += [arcRadius[0] + r]
                newRadius += [arcRadius[1] - r]
            elif round(TcrossT.dot(arcAxis[0]), precision()) < 0:
                newRadius += [arcRadius[0] - r]
                newRadius += [arcRadius[1] + r]
            elif T[0].dot(T[1]) > 0:
                if arcRadius[0] > arcRadius[1]:
                    newRadius += [arcRadius[0] - r]
                    newRadius += [arcRadius[1] + r]
                elif arcRadius[1] > arcRadius[0]:
                    newRadius += [arcRadius[0] + r]
                    newRadius += [arcRadius[1] - r]
                else:
                    print("DraftGeomUtils.fillet: Warning: "
                          "arcs are coincident. Did nothing")
                    return rndEdges
            else:
                print("DraftGeomUtils.fillet: Warning: "
                      "edges are already tangent. Did nothing")
                return rndEdges

        if (newRadius[0] + newRadius[1] < dCentToCent
                or newRadius[0] - newRadius[1] > dCentToCent
                or newRadius[1] - newRadius[0] > dCentToCent):
            print("DraftGeomUtils.fillet: Error: radius value ", r,
                  " is too high")
            return rndEdges

        x = ((dCentToCent**2 + newRadius[0]**2 - newRadius[1]**2) /
             (2 * dCentToCent))
        y = (newRadius[0]**2 - x**2)**(0.5)

        CentToCent.normalize()
        toCenter[0].normalize()
        toCenter[1].normalize()
        if abs(toCenter[0].dot(toCenter[1])) != 1:
            normVect = CentToCent.cross(CentToCent.cross(toCenter[0]))
        else:
            normVect = T[0]

        normVect.normalize()
        CentToCent.scale(x, x, x)
        normVect.scale(y, y, y)
        newCent = arcCenter[0].add(CentToCent.add(normVect))
        CentToNewCent = [newCent.sub(arcCenter[0]), newCent.sub(arcCenter[1])]

        for i in range(2):
            CentToNewCent[i].normalize()
            if newRadius[i] == arcRadius[i] + r:
                CentToNewCent[i].scale(-r, -r, -r)
            else:
                CentToNewCent[i].scale(r, r, r)

        toThirdPt = lVertexes[1].Point.sub(newCent)
        toThirdPt.normalize()
        toThirdPt.scale(r, r, r)
        arcPt1 = newCent.add(CentToNewCent[0])
        arcPt2 = newCent.add(toThirdPt)
        arcPt3 = newCent.add(CentToNewCent[1])
        arcPt = [arcPt1, arcPt2, arcPt3]

        arcAsEdge = []
        for i in range(2):
            toCenter[i].scale(-1, -1, -1)
            delLength = (arcRadius[i] *
                         arcPt[-i].sub(arcCenter[i]).getAngle(toCenter[i]))
            if delLength > arcLength[i]:
                print("DraftGeomUtils.fillet: Error: radius value ", r,
                      " is too high")
                return rndEdges
            V = [arcPt[-i], lVertexes[-i].Point]
            arcAsEdge += [
                arcFrom2Pts(V[i - 1], V[-i], arcCenter[i], arcAxis[i])
            ]

        rndEdges[0] = arcAsEdge[0]
        rndEdges[1] = arcAsEdge[1]
        if chamfer:
            rndEdges[1:1] = [Part.Edge(Part.LineSegment(arcPt[0], arcPt[2]))]
        else:
            rndEdges[1:1] = [Part.Edge(Part.Arc(arcPt[0], arcPt[1], arcPt[2]))]

        return rndEdges