Beispiel #1
0
def circleInversion(circle, circle2):
    """Circle inversion of a circle, inverting the center point.

    Returns the new circle created from the inverted center of circle2.
    """
    if geomType(circle) != "Circle" or geomType(circle2) != "Circle":
        print("debug: circleInversion bad parameters! Must be circles.")
        return None

    cen1 = circle.Curve.Center

    cen2 = circle2.Curve.Center
    rad2 = circle2.Curve.Radius

    if DraftVecUtils.equals(cen1, cen2):
        return None

    invCen2 = pointInversion(circle, cen2)

    pointOnCircle2 = App.Vector.add(cen2, App.Vector(rad2, 0, 0))
    invPointOnCircle2 = pointInversion(circle, pointOnCircle2)

    return Part.Circle(invCen2,
                       NORM,
                       DraftVecUtils.dist(invCen2, invPointOnCircle2))
Beispiel #2
0
def findRadicalCenter(circle1, circle2, circle3):
    """Calculate the radical center of three circles.

    It is also called the power center.
    It is the intersection point of the three radical axes of the pairs
    of circles.

    http://en.wikipedia.org/wiki/Power_center_(geometry)
    http://mathworld.wolfram.com/RadicalCenter.html

    See Also
    --------
    findRadicalAxis
    """
    if (geomType(circle1) != "Circle"
            or geomType(circle2) != "Circle"
            or geomType(circle3) != "Circle"):
        print("debug: findRadicalCenter bad parameters! Must be circles.")
        return None

    radicalAxis12 = findRadicalAxis(circle1, circle2)
    radicalAxis23 = findRadicalAxis(circle2, circle3)

    if not radicalAxis12 or not radicalAxis23:
        # No radical center could be calculated.
        return None

    intersect = findIntersection(radicalAxis12, radicalAxis23, True, True)

    if intersect:
        return intersect
    else:
        # No radical center could be calculated.
        return None
Beispiel #3
0
def circleFrom1tan2pt(tan1, p1, p2):
    if (geomType(tan1) == "Line") and isinstance(
            p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector):
        return circlefrom1Line2Points(tan1, p1, p2)
    if (geomType(tan1) == "Line") and isinstance(
            p1, FreeCAD.Vector) and isinstance(p2, FreeCAD.Vector):
        return circlefrom1Circle2Points(tan1, p1, p2)
Beispiel #4
0
def findRadicalCenter(circle1, circle2, circle3):
    """
    findRadicalCenter(circle1, circle2, circle3):
    Calculates the radical center (also called the power center) of three circles.
    It is the intersection point of the three radical axes of the pairs of circles.

    http://en.wikipedia.org/wiki/Power_center_(geometry)
    http://mathworld.wolfram.com/RadicalCenter.html

    @sa findRadicalAxis
    """
    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"):
        radicalAxis12 = findRadicalAxis(circle1, circle2)
        radicalAxis23 = findRadicalAxis(circle1, circle2)

        if not radicalAxis12 or not radicalAxis23:
            # No radical center could be calculated.
            return None

        int = findIntersection(radicalAxis12, radicalAxis23, True, True)

        if int:
            return int
        else:
            # No radical center could be calculated.
            return None
    else:
        FreeCAD.Console.PrintMessage(
            "debug: findRadicalCenter bad parameters!\n")
        return None
Beispiel #5
0
def invert(shape):
    """Return an inverted copy of the edge or wire contained in the shape."""
    if shape.ShapeType == "Wire":
        edges = [invert(edge) for edge in shape.OrderedEdges]
        edges.reverse()
        return Part.Wire(edges)
    elif shape.ShapeType == "Edge":
        if len(shape.Vertexes) == 1:
            return shape
        if geomType(shape) == "Line":
            return Part.LineSegment(shape.Vertexes[-1].Point,
                                    shape.Vertexes[0].Point).toShape()
        elif geomType(shape) == "Circle":
            mp = findMidpoint(shape)
            return Part.Arc(shape.Vertexes[-1].Point, mp,
                            shape.Vertexes[0].Point).toShape()
        elif geomType(shape) in ["BSplineCurve", "BezierCurve"]:
            if isLine(shape.Curve):
                return Part.LineSegment(shape.Vertexes[-1].Point,
                                        shape.Vertexes[0].Point).toShape()

        print("DraftGeomUtils.invert: unable to invert", shape.Curve)
        return shape
    else:
        print("DraftGeomUtils.invert: unable to handle", shape.ShapeType)
        return shape
Beispiel #6
0
def offset(edge, vector, trim=False):
    """Return a copy of the edge at a certain vector offset.

    If the edge is an arc, the vector will be added at its first point
    and a complete circle will be returned.

    None if there is a problem.
    """
    if (not isinstance(edge, Part.Shape)
            or not isinstance(vector, App.Vector)):
        return None

    if geomType(edge) == "Line":
        v1 = App.Vector.add(edge.Vertexes[0].Point, vector)
        v2 = App.Vector.add(edge.Vertexes[-1].Point, vector)
        return Part.LineSegment(v1, v2).toShape()

    elif geomType(edge) == "Circle":
        rad = edge.Vertexes[0].Point.sub(edge.Curve.Center)
        curve = Part.Circle(edge.Curve)
        curve.Radius = App.Vector.add(rad, vector).Length
        if trim:
            return Part.ArcOfCircle(curve,
                                    edge.FirstParameter,
                                    edge.LastParameter).toShape()
        else:
            return curve.toShape()
    else:
        return None
Beispiel #7
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()
Beispiel #8
0
def circleInversion(circle, circle2):
    """
    pointInversion(Circle, Circle)

    Circle inversion of a circle.
    """
    if (geomType(circle) == "Circle") and (geomType(circle2) == "Circle"):
        cen1 = circle.Curve.Center
        rad1 = circle.Curve.Radius

        if DraftVecUtils.equals(cen1, point):
            return None

        invCen2 = Inversion(circle, circle2.Curve.Center)

        pointOnCircle2 = Vector.add(circle2.Curve.Center,
                                    Vector(circle2.Curve.Radius, 0, 0))
        invPointOnCircle2 = Inversion(circle, pointOnCircle2)

        return Part.Circle(invCen2, norm,
                           DraftVecUtils.dist(invCen2, invPointOnCircle2))

    else:
        FreeCAD.Console.PrintMessage(
            "debug: circleInversion bad parameters!\n")
        return None
Beispiel #9
0
def findMidpoint(edge):
    """Return the midpoint of a straight line or circular edge."""
    first = edge.Vertexes[0].Point
    last = edge.Vertexes[-1].Point

    if geomType(edge) == "Circle":
        center = edge.Curve.Center
        radius = edge.Curve.Radius
        if len(edge.Vertexes) == 1:
            # Circle
            dv = first.sub(center)
            dv = dv.negative()
            return center.add(dv)

        axis = edge.Curve.Axis
        chord = last.sub(first)
        perp = chord.cross(axis)
        perp.normalize()
        ray = first.sub(center)
        apothem = ray.dot(perp)
        sagitta = radius - apothem
        startpoint = FreeCAD.Vector.add(first, chord.multiply(0.5))
        endpoint = DraftVecUtils.scaleTo(perp, sagitta)
        return FreeCAD.Vector.add(startpoint, endpoint)

    elif geomType(edge) == "Line":
        halfedge = (last.sub(first)).multiply(0.5)
        return FreeCAD.Vector.add(first, halfedge)

    else:
        return None
Beispiel #10
0
def findRadicalAxis(circle1, circle2):
    """Calculate the radical axis of two circles.

    On the radical axis (also called power line) of two circles any
    tangents drawn from a point on the axis to both circles have
    the same length.

    http://en.wikipedia.org/wiki/Radical_axis
    http://mathworld.wolfram.com/RadicalLine.html

    See Also
    --------
    findRadicalCenter
    """
    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"):
        print("debug: findRadicalAxis bad parameters! Must be circles.")
        return None

    if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center):
        return None

    r1 = circle1.Curve.Radius
    r2 = circle1.Curve.Radius
    cen1 = circle1.Curve.Center
    # dist .. the distance from cen1 to cen2.
    dist = DraftVecUtils.dist(cen1, circle2.Curve.Center)
    cenDir = cen1.sub(circle2.Curve.Center)
    cenDir.normalize()

    # Get the perpedicular vector.
    perpCenDir = cenDir.cross(App.Vector(0, 0, 1))
    perpCenDir.normalize()

    # J ... The radical center.
    # K ... The point where the cadical axis crosses the line of cen1->cen2.
    # k1 ... Distance from cen1 to K.
    # k2 ... Distance from cen2 to K.
    # dist = k1 + k2

    k1 = (dist + (r1**2 - r2**2) / dist) / 2.0
    # k2 = dist - k1

    K = App.Vector.add(cen1, cenDir.multiply(k1))

    # K_ .. A point somewhere between K and J; actually with a distance
    # of 1 unit from K.
    K_ = App.Vector.add(K, perpCenDir)

    # Original code didn't specify the value of origin nor dir,
    # so this is a guess:
    # radicalAxis = Part.LineSegment(K, Vector.add(origin, dir))

    origin = App.Vector(0, 0, 0)
    radicalAxis = Part.LineSegment(K, App.Vector.add(origin, perpCenDir))

    if radicalAxis:
        return radicalAxis
    else:
        return None
Beispiel #11
0
def findHomotheticCenterOfCircles(circle1, circle2):
    """Calculate the homothetic center(s) of two circles.

    http://en.wikipedia.org/wiki/Homothetic_center
    http://mathworld.wolfram.com/HomotheticCenter.html
    """

    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"):
        if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center):
            return None

        cen1_cen2 = Part.LineSegment(circle1.Curve.Center,
                                     circle2.Curve.Center).toShape()
        cenDir = vec(cen1_cen2)
        cenDir.normalize()

        # Get the perpedicular vector.
        perpCenDir = cenDir.cross(Vector(0, 0, 1))
        perpCenDir.normalize()

        # Get point on first circle
        p1 = Vector.add(circle1.Curve.Center,
                        Vector(perpCenDir).multiply(circle1.Curve.Radius))

        centers = []
        # Calculate inner homothetic center
        # Get point on second circle
        p2_inner = Vector.add(
            circle1.Curve.Center,
            Vector(perpCenDir).multiply(-circle1.Curve.Radius))
        hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center,
                                               circle2.Curve.Center, p1,
                                               p2_inner, True, True)
        if hCenterInner:
            centers.append(hCenterInner)

        # Calculate outer homothetic center (only exists of the circles have different radii)
        if circle1.Curve.Radius != circle2.Curve.Radius:
            # Get point on second circle
            p2_outer = Vector.add(
                circle1.Curve.Center,
                Vector(perpCenDir).multiply(circle1.Curve.Radius))
            hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center,
                                                   circle2.Curve.Center, p1,
                                                   p2_outer, True, True)
            if hCenterOuter:
                centers.append(hCenterOuter)

        if len(centers):
            return centers
        else:
            return None

    else:
        FreeCAD.Console.PrintMessage(
            "debug: findHomotheticCenterOfCirclescleFrom3tan bad parameters!\n"
        )
        return None
Beispiel #12
0
def findHomotheticCenterOfCircles(circle1, circle2):
    """Calculate the homothetic centers from two circles.

    Return None if the objects are not circles, or if they are concentric.

    http://en.wikipedia.org/wiki/Homothetic_center
    http://mathworld.wolfram.com/HomotheticCenter.html
    """
    if (geomType(circle1) == "Circle" and geomType(circle2) == "Circle"):
        print("debug: findHomotheticCenterOfCircles bad parameters!")
        return None

    if DraftVecUtils.equals(circle1.Curve.Center,
                            circle2.Curve.Center):
        return None

    cen1_cen2 = Part.LineSegment(circle1.Curve.Center,
                                 circle2.Curve.Center).toShape()
    cenDir = vec(cen1_cen2)
    cenDir.normalize()

    # Get the perpedicular vector.
    perpCenDir = cenDir.cross(App.Vector(0, 0, 1))
    perpCenDir.normalize()

    # Get point on first circle
    p1 = App.Vector.add(circle1.Curve.Center,
                        App.Vector(perpCenDir).multiply(circle1.Curve.Radius))

    centers = []
    # Calculate inner homothetic center
    # Get point on second circle
    p2_inner = App.Vector.add(circle1.Curve.Center,
                              App.Vector(perpCenDir).multiply(-circle1.Curve.Radius))
    hCenterInner = DraftVecUtils.intersect(circle1.Curve.Center,
                                           circle2.Curve.Center,
                                           p1, p2_inner,
                                           True, True)
    if hCenterInner:
        centers.append(hCenterInner)

    # Calculate outer homothetic center; it only exists if the circles
    # have different radii
    if circle1.Curve.Radius != circle2.Curve.Radius:
        # Get point on second circle
        p2_outer = App.Vector.add(circle1.Curve.Center,
                                  App.Vector(perpCenDir).multiply(circle1.Curve.Radius))
        hCenterOuter = DraftVecUtils.intersect(circle1.Curve.Center,
                                               circle2.Curve.Center,
                                               p1, p2_outer,
                                               True, True)
        if hCenterOuter:
            centers.append(hCenterOuter)

    if centers:
        return centers
    else:
        return None
Beispiel #13
0
def cleanProjection(shape, tessellate=True, seglength=0.05):
    """Return a valid compound of edges, by recreating them.

    This is because the projection algorithm somehow creates wrong shapes.
    They display fine, but on loading the file the shape is invalid.

    Now with tanderson's fix to `ProjectionAlgos`, that isn't the case,
    but this function can be used for tessellating ellipses and splines
    for DXF output-DF.
    """
    oldedges = shape.Edges
    newedges = []
    for e in oldedges:
        try:
            if geomType(e) == "Line":
                newedges.append(e.Curve.toShape())

            elif geomType(e) == "Circle":
                if len(e.Vertexes) > 1:
                    mp = findMidpoint(e)
                    a = Part.Arc(e.Vertexes[0].Point,
                                 mp,
                                 e.Vertexes[-1].Point).toShape()
                    newedges.append(a)
                else:
                    newedges.append(e.Curve.toShape())

            elif geomType(e) == "Ellipse":
                if tessellate:
                    newedges.append(Part.Wire(curvetowire(e, seglength)))
                else:
                    if len(e.Vertexes) > 1:
                        a = Part.Arc(e.Curve,
                                     e.FirstParameter,
                                     e.LastParameter).toShape()
                        newedges.append(a)
                    else:
                        newedges.append(e.Curve.toShape())

            elif (geomType(e) == "BSplineCurve"
                  or geomType(e) == "BezierCurve"):
                if tessellate:
                    newedges.append(Part.Wire(curvetowire(e, seglength)))
                else:
                    if isLine(e.Curve):
                        line = Part.LineSegment(e.Vertexes[0].Point,
                                                e.Vertexes[-1].Point).toShape()
                        newedges.append(line)
                    else:
                        newedges.append(e.Curve.toShape(e.FirstParameter,
                                                        e.LastParameter))
            else:
                newedges.append(e)
        except Part.OCCError:
            print("Debug: error cleaning edge ", e)

    return Part.makeCompound(newedges)
Beispiel #14
0
def circleFrom1tan1pt1rad(tan1, p1, rad):
    """Circle from one tangent, one point, and radius.

    The tangents should be edges, and they may be either straight line edges
    or circular edges, so two combinations are possible.
    """
    if geomType(tan1) == "Line" and isinstance(p1, FreeCAD.Vector):
        return circleFromPointLineRadius(p1, tan1, rad)

    elif geomType(tan1) == "Circle" and isinstance(p1, FreeCAD.Vector):
        return circleFromPointCircleRadius(p1, tan1, rad)
Beispiel #15
0
def circleFrom3CircleTangents(circle1, circle2, circle3):
    """Return the circle that is tangent to three other circles.

    This problem is called the 'Problem of Appollonius'.

    A special case is that of 'Soddy circles'.

    To Do
    -----
    Currently not all possible solutions are found, only the Soddy circles.

    * Calc all 6 homothetic centers.
    * Create 3 lines from the inner and 4 from the outer h. center.
    * Calc. the 4 inversion poles of these lines for each circle.
    * Calc. the radical center of the 3 circles.
    * Calc. the intersection points (max. 8) of 4 lines (through each
      inversion pole and the radical center) with the circle.
    * This gives us all the tangent points.
    """
    if (geomType(circle1) != "Circle" and geomType(circle2) != "Circle"
            and geomType(circle3) == "Circle"):
        print("debug: circleFrom3CircleTangents bad input! Must be circles")
        return None

    int12 = findIntersection(circle1, circle2, True, True)
    int23 = findIntersection(circle2, circle3, True, True)
    int31 = findIntersection(circle3, circle1, True, True)

    if int12 and int23 and int31:
        if len(int12) == 1 and len(int23) == 1 and len(int31) == 1:
            # If only one intersection with each circle, Soddy circle

            # r1 = circle1.Curve.Radius
            # r2 = circle2.Curve.Radius
            # r3 = circle3.Curve.Radius
            outerSoddy = outerSoddyCircle(circle1, circle2, circle3)
            # print(str(outerSoddy))  # Debug

            innerSoddy = innerSoddyCircle(circle1, circle2, circle3)
            # print(str(innerSoddy))  # Debug

            circles = []
            if outerSoddy:
                circles.append(outerSoddy)
            if innerSoddy:
                circles.append(innerSoddy)
            return circles

        # Here the rest of the circles should be calculated
        # ...
    else:
        # Some circles are inside each other or an error has occurred.
        return None
Beispiel #16
0
def circleFrom3CircleTangents(circle1, circle2, circle3):
    """
    http://en.wikipedia.org/wiki/Problem_of_Apollonius#Inversive_methods
    http://mathworld.wolfram.com/ApolloniusCircle.html
    http://mathworld.wolfram.com/ApolloniusProblem.html
    """

    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle") \
    and (geomType(circle3) == "Circle"):
        int12 = findIntersection(circle1, circle2, True, True)
        int23 = findIntersection(circle2, circle3, True, True)
        int31 = findIntersection(circle3, circle1, True, True)

        if int12 and int23 and int31:
            if len(int12) == 1 and len(int23) == 1 and len(int31) == 1:
                # Only one intersection with each circle.
                # => "Soddy Circle" - 2 solutions.
                # http://en.wikipedia.org/wiki/Problem_of_Apollonius#Mutually_tangent_given_circles:_Soddy.27s_circles_and_Descartes.27_theorem
                # http://mathworld.wolfram.com/SoddyCircles.html
                # http://mathworld.wolfram.com/InnerSoddyCenter.html
                # http://mathworld.wolfram.com/OuterSoddyCenter.html

                r1 = circle1.Curve.Radius
                r2 = circle2.Curve.Radius
                r3 = circle3.Curve.Radius
                outerSoddy = outerSoddyCircle(circle1, circle2, circle3)
                #               print(str(outerSoddy) + "\n") # Debug

                innerSoddy = innerSoddyCircle(circle1, circle2, circle3)
                #               print(str(innerSoddy) + "\n") # Debug

                circles = []
                if outerSoddy:
                    circles.append(outerSoddy)
                if innerSoddy:
                    circles.append(innerSoddy)
                return circles

            # @todo Calc all 6 homothetic centers.
            # @todo Create 3 lines from the inner and 4 from the outer h. center.
            # @todo Calc. the 4 inversion poles of these lines for each circle.
            # @todo Calc. the radical center of the 3 circles.
            # @todo Calc. the intersection points (max. 8) of 4 lines (through each inversion pole and the radical center) with the circle.
            #       This gives us all the tangent points.
        else:
            # Some circles are inside each other or an error has occurred.
            return None

    else:
        print("debug: circleFrom3CircleTangents bad parameters!\n")
        # FreeCAD.Console.PrintMessage("debug: circleFrom3CircleTangents bad parameters!\n")
        return None
Beispiel #17
0
def outerSoddyCircle(circle1, circle2, circle3):
    """Compute the outer soddy circle for three tightly packed circles.

    Original Java code Copyright (rc) 2008 Werner Randelshofer
    Converted to python by Martin Buerbaum 2009
    http://www.randelshofer.ch/treeviz/
    Either Creative Commons Attribution 3.0, the MIT license,
    or the GNU Lesser General License LGPL.
    """
    if (geomType(circle1) != "Circle" or geomType(circle2) != "Circle"
            or geomType(circle3) != "Circle"):
        print("debug: outerSoddyCircle bad parameters! Must be circles.")
        return None

    A = circle1.Curve.Center
    B = circle2.Curve.Center
    C = circle3.Curve.Center

    ra = circle1.Curve.Radius
    rb = circle2.Curve.Radius
    rc = circle3.Curve.Radius

    # Solution using Descartes' theorem, as described here:
    # http://en.wikipedia.org/wiki/Descartes%27_theorem
    k1 = 1 / ra
    k2 = 1 / rb
    k3 = 1 / rc
    k4 = abs(k1 + k2 + k3 - 2 * math.sqrt(k1 * k2 + k2 * k3 + k3 * k1))

    q1 = (k1 + 0j) * (A.x + A.y * 1j)
    q2 = (k2 + 0j) * (B.x + B.y * 1j)
    q3 = (k3 + 0j) * (C.x + C.y * 1j)

    temp = ((q1 * q2) + (q2 * q3) + (q3 * q1))
    q4 = q1 + q2 + q3 - ((2 + 0j) * cmath.sqrt(temp))

    z = q4 / (k4 + 0j)

    # If the formula is not solvable, we return no circle.
    if not z or not (1 / k4):
        return None

    X = -z.real
    Y = -z.imag
    print("Outer Soddy circle: " + str(X) + " " + str(Y) + "\n")  # Debug

    # The Radius of the outer soddy circle can also be calculated
    # with the following formula:
    # radiusOuter = abs(r1*r2*r3 / (r1*r2 + r1*r3 + r2*r3 - 2 * math.sqrt(r1*r2*r3 * (r1+r2+r3))))
    circ = Part.Circle(App.Vector(X, Y, A.z), NORM, 1 / k4)

    return circ
Beispiel #18
0
def circleFrom1tan2pt(tan1, p1, p2):
    """Circle from one tangent and two points.

    The tangents should be edges, and they may be either straight line edges
    or circular edges, so two combinations are possible.
    """
    if (geomType(tan1) == "Line" and isinstance(p1, FreeCAD.Vector)
            and isinstance(p2, FreeCAD.Vector)):
        return circlefrom1Line2Points(tan1, p1, p2)

    elif (geomType(tan1) == "Circle" and isinstance(p1, FreeCAD.Vector)
          and isinstance(p2, FreeCAD.Vector)):
        return circlefrom1Circle2Points(tan1, p1, p2)
Beispiel #19
0
def findRadicalAxis(circle1, circle2):
    """Calculate the radical axis of two circles.

    On the radical axis (also called power line) of two circles any
    tangents drawn from a point on the axis to both circles have the same length.

    http://en.wikipedia.org/wiki/Radical_axis
    http://mathworld.wolfram.com/RadicalLine.html

    @sa findRadicalCenter
    """
    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle"):
        if DraftVecUtils.equals(circle1.Curve.Center, circle2.Curve.Center):
            return None
        r1 = circle1.Curve.Radius
        r2 = circle1.Curve.Radius
        cen1 = circle1.Curve.Center
        # dist .. the distance from cen1 to cen2.
        dist = DraftVecUtils.dist(cen1, circle2.Curve.Center)
        cenDir = cen1.sub(circle2.Curve.Center)
        cenDir.normalize()

        # Get the perpedicular vector.
        perpCenDir = cenDir.cross(Vector(0, 0, 1))
        perpCenDir.normalize()

        # J ... The radical center.
        # K ... The point where the cadical axis crosses the line of cen1->cen2.
        # k1 ... Distance from cen1 to K.
        # k2 ... Distance from cen2 to K.
        # dist = k1 + k2

        k1 = (dist + (r1 ^ 2 - r2 ^ 2) / dist) / 2.0
        #k2 = dist - k1

        K = Vector.add(cen1, cenDir.multiply(k1))

        # K_ .. A point somewhere between K and J (actually with a distance of 1 unit from K).
        K_ = Vector, add(K, perpCenDir)

        radicalAxis = Part.LineSegment(K, Vector.add(origin, dir))

        if radicalAxis:
            return radicalAxis
        else:
            return None
    else:
        FreeCAD.Console.PrintMessage(
            "debug: findRadicalAxis bad parameters!\n")
        return None
Beispiel #20
0
def innerSoddyCircle(circle1, circle2, circle3):
    """Compute the inner soddy circle for three tightly packed circles."""
    if (geomType(circle1) == "Circle") and (geomType(circle2) == "Circle") \
    and (geomType(circle3) == "Circle"):
        # Original Java code Copyright (rc) 2008 Werner Randelshofer
        # Converted to python by Martin Buerbaum 2009
        # http://www.randelshofer.ch/treeviz/

        A = circle1.Curve.Center
        B = circle2.Curve.Center
        C = circle3.Curve.Center

        ra = circle1.Curve.Radius
        rb = circle2.Curve.Radius
        rc = circle3.Curve.Radius

        # Solution using Descartes' theorem, as described here:
        # http://en.wikipedia.org/wiki/Descartes%27_theorem
        k1 = 1 / ra
        k2 = 1 / rb
        k3 = 1 / rc
        k4 = abs(k1 + k2 + k3 + 2 * math.sqrt(k1 * k2 + k2 * k3 + k3 * k1))

        q1 = (k1 + 0j) * (A.x + A.y * 1j)
        q2 = (k2 + 0j) * (B.x + B.y * 1j)
        q3 = (k3 + 0j) * (C.x + C.y * 1j)

        temp = ((q1 * q2) + (q2 * q3) + (q3 * q1))
        q4 = q1 + q2 + q3 + ((2 + 0j) * cmath.sqrt(temp))

        z = q4 / (k4 + 0j)

        # If the formula is not solvable, we return no circle.
        if (not z or not (1 / k4)):
            return None

        X = z.real
        Y = z.imag
        print("Outer Soddy circle: " + str(X) + " " + str(Y) + "\n")  # Debug

        # The Radius of the inner soddy circle can also be calculated with the following formula:
        # radiusInner = abs(r1*r2*r3 / (r1*r2 + r1*r3 + r2*r3 + 2 * math.sqrt(r1*r2*r3 * (r1+r2+r3))))
        circ = Part.Circle(Vector(X, Y, A.z), norm, 1 / k4)
        return circ

    else:
        print("debug: innerSoddyCircle bad parameters!\n")
        # FreeCAD.Console.PrintMessage("debug: innerSoddyCircle bad parameters!\n")
        return None
Beispiel #21
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
Beispiel #22
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
Beispiel #23
0
def pointInversion(circle, point):
    """Return the circle inversion of a point.

    It will return `None` if the given point is equal to the center
    of the circle.
    """
    if geomType(circle) != "Circle" or isinstance(point, App.Vector):
        print("debug: pointInversion bad parameters!")
        return None

    cen = circle.Curve.Center
    rad = circle.Curve.Radius

    if DraftVecUtils.equals(cen, point):
        return None

    # Inverse the distance of the point
    # dist(cen -> P) = r^2 / dist(cen -> invP)

    dist = DraftVecUtils.dist(point, cen)
    invDist = rad**2 / dist

    invPoint = App.Vector(0, 0, point.z)
    invPoint.x = cen.x + (point.x - cen.x) * invDist / dist
    invPoint.y = cen.y + (point.y - cen.y) * invDist / dist

    return invPoint
Beispiel #24
0
def pointInversion(circle, point):
    """Circle inversion of a point.

    pointInversion(Circle, Vector)

    Will calculate the inversed point an return it.
    If the given point is equal to the center of the circle "None" will be returned.

    See also:
    http://en.wikipedia.org/wiki/Inversive_geometry
    """
    if (geomType(circle) == "Circle") and isinstance(point, FreeCAD.Vector):
        cen = circle.Curve.Center
        rad = circle.Curve.Radius

        if DraftVecUtils.equals(cen, point):
            return None

        # Inverse the distance of the point
        # dist(cen -> P) = r^2 / dist(cen -> invP)

        dist = DraftVecUtils.dist(point, cen)
        invDist = rad**2 / d

        invPoint = Vector(0, 0, point.z)
        invPoint.x = cen.x + (point.x - cen.x) * invDist / dist
        invPoint.y = cen.y + (point.y - cen.y) * invDist / dist

        return invPoint

    else:
        FreeCAD.Console.PrintMessage("debug: pointInversion bad parameters!\n")
        return None
Beispiel #25
0
def getCircleFromSpline(edge):
    """Return a circle-based edge from a bspline-based edge."""
    if geomType(edge) != "BSplineCurve":
        return None
    if len(edge.Vertexes) != 1:
        return None
    # get 2 points
    p1 = edge.Curve.value(0)
    p2 = edge.Curve.value(math.pi / 2)
    # get 2 tangents
    t1 = edge.Curve.tangent(0)[0]
    t2 = edge.Curve.tangent(math.pi / 2)[0]
    # get normal
    n = p1.cross(p2)
    if DraftVecUtils.isNull(n):
        return None
    # get rays
    r1 = DraftVecUtils.rotate(t1, math.pi / 2, n)
    r2 = DraftVecUtils.rotate(t2, math.pi / 2, n)
    # get center (intersection of rays)
    i = findIntersection(p1, p1.add(r1), p2, p2.add(r2), True, True)
    if not i:
        return None
    c = i[0]
    r = (p1.sub(c)).Length
    circle = Part.makeCircle(r, c, n)
    #print(circle.Curve)
    return circle
Beispiel #26
0
def arcFromSpline(edge):
    """arcFromSpline(edge): turns the given edge into an arc, by taking
        its first point, midpoint and endpoint. Works best with bspline
        segments such as those from imported svg files. Use this only
        if you are sure your edge is really an arc..."""
    if geomType(edge) == "Line":
        print("This edge is straight, cannot build an arc on it")
        return None
    if len(edge.Vertexes) > 1:
        # 2-point arc
        p1 = edge.Vertexes[0].Point
        p2 = edge.Vertexes[-1].Point
        ml = edge.Length / 2
        p3 = edge.valueAt(ml)
        try:
            return Part.Arc(p1, p3, p2).toShape()
        except:
            print("Couldn't make an arc out of this edge")
            return None
    else:
        # circle
        p1 = edge.Vertexes[0].Point
        ml = edge.Length / 2
        p2 = edge.valueAt(ml)
        ray = p2.sub(p1)
        ray.scale(.5, .5, .5)
        center = p1.add(ray)
        radius = ray.Length
        try:
            return Part.makeCircle(radius, center)
        except:
            print("couldn't make a circle out of this edge")
Beispiel #27
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
Beispiel #28
0
def circleFrom2tan1rad(tan1, tan2, rad):
    """circleFrom2tan1rad(edge, edge, float)"""
    if (geomType(tan1) == "Line") and (geomType(tan2) == "Line"):
        return circleFrom2LinesRadius(tan1, tan2, rad)
    elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Line"):
        return circleFromCircleLineRadius(tan1, tan2, rad)
    elif (geomType(tan1) == "Line") and (geomType(tan2) == "Circle"):
        return circleFromCircleLineRadius(tan2, tan1, rad)
    elif (geomType(tan1) == "Circle") and (geomType(tan2) == "Circle"):
        return circleFrom2CirclesRadius(tan1, tan2, rad)
Beispiel #29
0
def polarInversion(circle, edge):
    """Return the inversion pole of a line. The edge is the polar.

    The nearest point on the line is inversed.

    http://mathworld.wolfram.com/InversionPole.html
    """
    if geomType(circle) != "Circle" or geomType(edge) != "Line":
        print("debug: circleInversionPole bad parameters! Must be a circle.")
        return None

    nearest = circle.Curve.Center.add(
        findDistance(circle.Curve.Center, edge, False))
    if nearest:
        inversionPole = pointInversion(circle, nearest)
        if inversionPole:
            return inversionPole

    return None
Beispiel #30
0
def tessellateProjection(shape, seglen):
    """Returns projection with BSplines and Ellipses broken into line segments.
        Useful for exporting projected views to *dxf files."""
    oldedges = shape.Edges
    newedges = []
    for e in oldedges:
        try:
            if geomType(e) == "Line":
                newedges.append(e.Curve.toShape())
            elif geomType(e) == "Circle":
                newedges.append(e.Curve.toShape())
            elif geomType(e) == "Ellipse":
                newedges.append(Part.Wire(curvetosegment(e, seglen)))
            elif geomType(e) == "BSplineCurve":
                newedges.append(Part.Wire(curvetosegment(e, seglen)))
            else:
                newedges.append(e)
        except:
            print("Debug: error cleaning edge ", e)
    return Part.makeCompound(newedges)