| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| """Provides various functions for Apollonius and Soddy circle operations. |
| |
| The 'problem of Appollonius' consists of finding a circle that is |
| simultaneously tangent to three circles on a plane. |
| |
| - http://en.wikipedia.org/wiki/Problem_of_Apollonius#Inversive_methods |
| - http://mathworld.wolfram.com/ApolloniusCircle.html |
| - http://mathworld.wolfram.com/ApolloniusProblem.html |
| |
| If each circle only has one intersection with each other, the problem is that |
| of finding a 'Soddy circle', which has two solutions, and inner circle |
| and an outer circle. |
| |
| - 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 |
| """ |
| |
| |
| |
|
|
| import cmath |
| import math |
| import lazy_loader.lazy_loader as lz |
|
|
| import FreeCAD as App |
|
|
| from draftgeoutils.general import geomType, NORM |
| from draftgeoutils.intersections import findIntersection |
|
|
| |
| Part = lz.LazyLoader("Part", globals(), "Part") |
|
|
| |
| |
|
|
|
|
| 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 |
|
|
| |
| |
| 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 not z or not (1 / k4): |
| return None |
|
|
| X = -z.real |
| Y = -z.imag |
| print("Outer Soddy circle: " + str(X) + " " + str(Y) + "\n") |
|
|
| |
| |
| |
| circ = Part.Circle(App.Vector(X, Y, A.z), NORM, 1 / k4) |
|
|
| return circ |
|
|
|
|
| def innerSoddyCircle(circle1, circle2, circle3): |
| """Compute the inner 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/ |
| """ |
| if ( |
| geomType(circle1) != "Circle" |
| and geomType(circle2) != "Circle" |
| and geomType(circle3) != "Circle" |
| ): |
| print("debug: innerSoddyCircle 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 |
|
|
| |
| |
| 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 not z or not (1 / k4): |
| return None |
|
|
| X = z.real |
| Y = z.imag |
| print("Outer Soddy circle: " + str(X) + " " + str(Y) + "\n") |
|
|
| |
| |
| |
| circ = Part.Circle(App.Vector(X, Y, A.z), NORM, 1 / k4) |
|
|
| return circ |
|
|
|
|
| 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: |
| |
|
|
| |
| |
| |
| outerSoddy = outerSoddyCircle(circle1, circle2, circle3) |
| |
|
|
| innerSoddy = innerSoddyCircle(circle1, circle2, circle3) |
| |
|
|
| circles = [] |
| if outerSoddy: |
| circles.append(outerSoddy) |
| if innerSoddy: |
| circles.append(innerSoddy) |
| return circles |
|
|
| |
| |
| else: |
| |
| return None |
|
|
|
|
| |
|
|