# # Copyright (c) 2003, 2004 Art Haas # # This file is part of PythonCAD. # # PythonCAD is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # PythonCAD is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with PythonCAD; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # # # functions for handling tangent circles on multiple objects # import math from PythonCAD.Generic import hcline from PythonCAD.Generic import vcline from PythonCAD.Generic import acline from PythonCAD.Generic import cline from PythonCAD.Generic import ccircle # # common constants # _dtr = math.pi/180.0 _piover2 = math.pi/2.0 # # find the projection point of point (x, y) on a line # from (x1, y1) to (x2, y2) # def _get_two_point_projection(x1, y1, x2, y2, x, y): _sqlen = pow((x2 - x1), 2) + pow((y2 - y1), 2) _rn = ((x - x1) * (x2 - x1)) + ((y - y1) * (y2 - y1)) _r = _rn/_sqlen _px = x1 + _r * (x2 - x1) _py = y1 + _r * (y2 - y1) return _px, _py # # find the projection point of point (x, y) on a line # defined by an angle and y intercept # def _get_angled_projection(angle, yint, x, y): _x1 = 0.0 _y1 = yint _x2 = _x1 + math.cos(angle) _y2 = _y1 + math.sin(angle) return _get_two_point_projection(_x1, _y1, _x2, _y2, x, y) def _two_line_tangent(x1, y1, x2, y2, x3, y3, x4, y4, x, y): # # this function calculates the apprpriate tangent circle # for two lines (x1, y1)->(x2, y2) and (x3, y3)->(x4, y4) # using a point (x, y) to determine which tangent circle # should be defined # # test if lines are parallel # _cx = _cy = _radius = None _denom = ((x2 - x1) * (y4 - y3)) - ((y2 - y1) * (x4 - x3)) # print "denom: %g" % _denom if abs(_denom) < 1e-10: # print "parallel ..." if abs(x2 - x1) < 1e-10: # both vertical if x < min(x1, x3) or x > max(x1, x3): return None _cx = (x3 + x1)/2.0 _cy = y _radius = abs(x3 - x1)/2.0 elif abs(y2 - y1) < 1e-10: # both horizontal if y < min(y1, y3) or y > max(y1, y3): return None _cx = x _cy = (y3 + y1)/2.0 _radius = abs(y3 - y1)/2.0 else: # both at equal angles _ax1, _ay1 = _get_two_point_projection(x1, y1, x2, y2, x, y) # print "ax1: %g; ay1: %g" % (_ax1, _ay1) _ax2, _ay2 = _get_two_point_projection(x3, y3, x4, y4, x, y) # print "ax2: %g; ay2: %g" % (_ax2, _ay2) if (x < min(_ax1, _ax2) or x > max(_ax1, _ax2) or y < min(_ay1, _ay2) or y > max(_ay1, _ay2)): return None _cx = (_ax1 + _ax2)/2.0 _cy = (_ay1 + _ay2)/2.0 _radius = math.hypot((_ax1 - _cx), (_ay1 - _cy)) return _cx, _cy, _radius # # the lines are not parallel, so we have to test for the # different combinations of horizontal/vertical/sloped lines ... # if abs(y2 - y1) < 1e-10: # horizontal line 1 # print "horizontal line 1 ..." if abs(y4 - y3) < 1e-10: # this should be handled above ... # print "horizontal line 2 ..." if y < min(y1, y3) or y > max(y1, y3): return None _cx = x _cy = (y1 + y3)/2.0 _radius = abs(_cy - y1) elif abs(x4 - x3) < 1e-10: # vertical line 2 # print "vertical line 2 ..." _a1 = math.pi/4.0 _a2 = -_a1 else: _angle = math.atan2((y4 - y3), (x4 - x3)) _a1 = _angle/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 elif abs(x2 - x1) < 1e-10: # vertical line 1 # print "vertical line 1 ..." if abs(y4 - y3) < 1e-10: # horizontal line2 # print "horizontal line 2 ..." _a1 = math.pi/4.0 _a2 = -_a1 elif abs(x4 - x3) < 1e-10: # this should be handled above ... if x < min(x1, x3) or x > max(x1, x3): return None _cx = (x1 + x3)/2.0 _cy = y _radius = abs(_cx - x1) else: _angle = math.atan2((y4 - y3), (x4 - x3)) if _angle > 0.0: _a1 = (_angle + _piover2)/2.0 _a2 = _a1 - _piover2 else: _a1 = (_angle - _piover2)/2.0 _a2 = _a1 + _piover2 else: _angle1 = math.atan2((y2 - y1), (x2 - x1)) if abs(y4 - y3) < 1e-10: # horizontal line2 _a1 = _angle1/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 elif abs(x4 - x3) < 1e-10: # vertical line2 if _angle1 > 0.0: _a1 = (_angle1 + _piover2)/2.0 _a2 = _a1 - _piover2 else: _a1 = (_angle1 - _piover2)/2.0 _a2 = _a1 + _piover2 else: _angle2 = math.atan2((y4 - y3), (x4 - x3)) _a1 = (_angle1 + _angle2)/2.0 if _a1 > 0.0: _a2 = _a1 - _piover2 else: _a2 = _a1 + _piover2 if _cx is not None and _cy is not None and _radius is not None: return _cx, _cy, _radius # # handle the general case of two lines at arbitrary angles # # print "arbitrary angles ..." # print "a1: %g" % (_a1/_dtr) # print "a2: %g" % (_a2/_dtr) _rn = ((y1 - y3) * (x4 - x3)) - ((x1 - x3) * (y4 - y3)) # print "rn: %g" % _rn _r = _rn/_denom # print "r: %g" % _r _ix = x1 + _r * (x2 - x1) _iy = y1 + _r * (y2 - y1) # print "ix: %g; iy: %g" % (_ix, _iy) _m1 = math.tan(_a1) _b1 = _iy - (_m1 * _ix) # print "line1: m: %g; b: %g" % (_m1, _b1) _m2 = math.tan(_a2) _b2 = _iy - (_m2 * _ix) # print "line2: m: %g; b: %g" % (_m2, _b2) _px1, _py1 = _get_angled_projection(_a1, _b1, x, y) # print "px1: %g; py1: %g" % (_px1, _py1) _sep1 = math.hypot((_px1 - x), (_py1 - y)) _px2, _py2 = _get_angled_projection(_a2, _b2, x, y) # print "px2: %g; py2: %g" % (_px2, _py2) _sep2 = math.hypot((_px2 - x), (_py2 - y)) if _sep1 < _sep2: _cx = _px1 _cy = _py1 else: _cx = _px2 _cy = _py2 _px, _py = _get_two_point_projection(x1, y1, x2, y2, _cx, _cy) _radius = math.hypot((_px - _cx), (_py - _cy)) return _cx, _cy, _radius # # horizontal construction line tangents # def _hcl_hcl_tangent(hcla, hclb, x, y): _hx1, _hy1 = hcla.getLocation().getCoords() _hx2, _hy2 = hclb.getLocation().getCoords() if y < min(_hy1, _hy2) or y > max(_hy1, _hy2): return None _cx = x _cy = (_hy1 + _hy2)/2.0 _radius = abs(_cy - _hy1) return _cx, _cy, _radius def _hcl_vcl_tangent(hcl, vcl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _vx, _vy = vcl.getLocation().getCoords() _vy2 = _vy + 1.0 return _two_line_tangent(_hx, _hy, _hx2, _hy, _vx, _vy, _vx, _vy2, x, y) def _hcl_acl_tangent(hcl, acl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _ax, _ay = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax + math.cos(_angle) _ay2 = _ay + math.sin(_angle) return _two_line_tangent(_hx, _hy, _hx2, _hy, _ax, _ay, _ax2, _ay2, x, y) def _hcl_cl_tangent(hcl, cl, x, y): _hx, _hy = hcl.getLocation().getCoords() _hx2 = _hx + 1.0 _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_hx, _hy, _hx2, _hy, _x1, _y1, _x2, _y2, x, y) # # the HCLine-CCircle tangent circle problem has been generalized # to solve the {VCLine/ACLine/CLine}-CCircle tangent calculation # def _gen_cline_ccircle_tangent(radius, hy, x): # # center of ccircle : (0,0) # radius of ccircle : r # distance between ccircle and hcl: hy # x-coordinate of mouse: x # # center of tangent circle : (px, py) # # projection point on hcl: (px, hy) # # Projection point outside the radius of the circle gives: # # math.hypot((px - cx), (py - cy)) == math.hypot((px - px), (py - hy)) + r # # Projection point inside the radius of the circle gives: # # math.hypot((px - cx), (py - cy)) + rt = r # # rt == radius of tangent circle # # Distance from projection point to tangent circle center # # math.hypot((px - px), (py - hy)) = rt # # lots of algebra reduces to the following two cases # _cx = x if hy > 0.0: _num = pow(x, 2) - pow(hy, 2) - (2.0 * hy * radius) - pow(radius, 2) _den = (-2.0 * hy) - (2.0 * radius) else: _num = pow(x, 2) - pow(hy, 2) + (2.0 * hy * radius) - pow(radius, 2) _den = (2.0 * radius) - (2.0 * hy) # print "num: %g" % _num # print "den: %g" % _den _cy = _num/_den _radius = abs(_cy - hy) return _cx, _cy, _radius def _hcl_cc_tangent(hcl, cc, x, y): _hx, _hy = hcl.getLocation().getCoords() # print "hy: %g" % _hy _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into system where circle center is (0,0) # _sep = _hy - _ccy _xproj = x - _ccx _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _xproj) # # transform result back into real coordinates # _cx = _tcx + _ccx _cy = _tcy + _ccy return _cx, _cy, _tcrad # # vertical construction line # def _vcl_vcl_tangent(vcl1, vcl2, x, y): _vx1, _vy1 = vcl1.getLocation().getCoords() _vx2, _vy2 = vcl2.getLocation().getCoords() if x < min(_vx1, _vx2) or x > max(_vx1, _vx2): return None _cx = (_vx1 + _vx2)/2.0 _cy = y _radius = abs(_cx - _vx1) return _cx, _cy, _radius def _vcl_acl_tangent(vcl, acl, x, y): _vx, _vy = vcl.getLocation().getCoords() _vy2 = _vy + 1.0 _ax, _ay = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax + math.cos(_angle) _ay2 = _ay + math.sin(_angle) return _two_line_tangent(_vx, _vy, _vx, _vy2, _ax, _ay, _ax2, _ay2, x, y) def _vcl_cl_tangent(hcl, cl, x, y): _vx, _vy = hcl.getLocation().getCoords() _vy2 = _vy + 1.0 _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_vx, _vy, _vx, _vy2, _x1, _y1, _x2, _y2, x, y) def _vcl_cc_tangent(vcl, cc, x, y): _vx, _vy = vcl.getLocation().getCoords() # print "vx: %g" % _vx _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into system where circle center is (0,0) and # rotate 90 degrees # _sep = _vx - _ccx _xproj = y - _ccy _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _xproj) # # transform result back into real coordinates # _cx = _tcy + _ccx _cy = _tcx + _ccy return _cx, _cy, _tcrad # # angular construction line # def _acl_acl_tangent(acl1, acl2, x, y): _ax1, _ay1 = acl1.getLocation().getCoords() _angle1 = acl1.getAngle() * _dtr _ax2 = _ax1 + math.cos(_angle1) _ay2 = _ay1 + math.sin(_angle1) _ax3, _ay3 = acl2.getLocation().getCoords() _angle2 = acl2.getAngle() * _dtr _ax4 = _ax3 + math.cos(_angle2) _ay4 = _ay3 + math.sin(_angle2) return _two_line_tangent(_ax1, _ay1, _ax2, _ay2, _ax3, _ay3, _ax4, _ay4, x, y) def _acl_cl_tangent(acl, cl, x, y): _ax1, _ay1 = acl.getLocation().getCoords() _angle = acl.getAngle() * _dtr _ax2 = _ax1 + math.cos(_angle) _ay2 = _ay1 + math.sin(_angle) _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() return _two_line_tangent(_ax1, _ay1, _ax2, _ay2, _x1, _y1, _x2, _y2, x, y) def _acl_cc_tangent(acl, cc, x, y): _ax, _ay = acl.getLocation().getCoords() # print "ax: %g; ay: %g" % (_ax, _ay) _angle = acl.getAngle() _ccx, _ccy = cc.getCenter().getCoords() _rad = cc.getRadius() # # transform the coords into the system where the circle center is (0,0) # and rotate so the ACLine is horizontal # _apx, _apy = acl.getProjection(_ccx, _ccy) _sep = math.hypot((_apx - _ccx), (_apy - _ccy)) if abs(_angle) < 1e-10: # horizontal _sine = 0.0 if _apy > _ccy: # system rotated 0.0 _cosine = 1.0 else: # system rotated 180.0 _cosine = -1.0 elif abs(abs(_angle) - 90.0) < 1e-10: # vertical _cosine = 0.0 if _apx > _ccx: # system rotated 90.0 _sine = 1.0 else: # system rotated -90.0 _sine = -1.0 else: _angle = _piover2 - math.atan2((_apy - _ccy), (_apx - _ccx)) _sine = math.sin(_angle) _cosine = math.cos(_angle) # # transform (x, y) # _tx1 = x - _ccx _ty1 = y - _ccy # # transform by rotating through _negative_ angle to # map to horizontal line # _tx = (_tx1 * _cosine) - (_ty1 * _sine) _ty = (_tx1 * _sine) + (_ty1 * _cosine) _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _tx) # # transform result back into real coordinates # _cx = ((_tcx * _cosine) + (_tcy * _sine)) + _ccx _cy = (-(_tcx * _sine) + (_tcy * _cosine)) + _ccy return _cx, _cy, _tcrad # # two-point construction line # def _cl_cl_tangent(cl1, cl2, x, y): _p1, _p2 = cl1.getKeypoints() _x1, _y1 = _p1.getCoords() _x2, _y2 = _p2.getCoords() _p3, _p4 = cl2.getKeypoints() _x3, _y3 = _p3.getCoords() _x4, _y4 = _p4.getCoords() return _two_line_tangent(_x1, _y1, _x2, _y2, _x3, _y3, _x4, _y4, x, y) def _cl_cc_tangent(cl, cc, x, y): _p1, _p2 = cl.getKeypoints() _x1, _y1 = _p1.getCoords() # print "x1: %g; y1: %g" % (_x1, _y1) _x2, _y2 = _p2.getCoords() # print "x2: %g; y2: %g" % (_x2, _y2) _ccx, _ccy = cc.getCenter().getCoords() # print "ccx: %g; ccy: %g" % (_ccx, _ccy) _rad = cc.getRadius() # # transform the coords into the system where the circle center is (0,0) # and rotate so the CLine is horizontal # _apx, _apy = cl.getProjection(_ccx, _ccy) # print "apx: %g; apy: %g" % (_apx, _apy) _sep = math.hypot((_apx - _ccx), (_apy - _ccy)) # print "sep: %g" % _sep # # use the line (ccx, ccy) to (apx, apy) to determine the # angular rotation # if abs(_apx - _ccx) < 1e-10: # cline is horizontal _sine = 0.0 if _apy > _ccy: # system rotated 0.0 _cosine = 1.0 else: # system rotated 180.0 _cosine = -1.0 elif abs(_apy - _ccy) < 1e-10: # cline is vertical; system rotated -90.0 _cosine = 0.0 if _apx > _ccx: # system rotated 90.0 _sine = 1.0 else: # system rotated -90.0 _sine = -1.0 else: _angle = _piover2 - math.atan2((_apy - _ccy), (_apx - _ccx)) # print "angle: %g" % _angle _sine = math.sin(_angle) _cosine = math.cos(_angle) # print "sin(angle): %g" % _sine # print "cos(angle): %g" % _cosine # # transform (x, y) into _tx1 = x - _ccx _ty1 = y - _ccy # print "tx1: %g; ty1: %g" % (_tx1, _ty1) # # transform by rotating through angle to # map to horizontal line # _tx = (_tx1 * _cosine) - (_ty1 * _sine) _ty = (_tx1 * _sine) + (_ty1 * _cosine) # print "tx: %g; ty: %g" % (_tx, _ty) _tcx, _tcy, _tcrad = _gen_cline_ccircle_tangent(_rad, _sep, _tx) # # transform result back into real coordinates # # print "tcx: %g: tcy: %g" % (_tcx, _tcy) _cx = ((_tcx * _cosine) + (_tcy * _sine)) + _ccx _cy = (-(_tcx * _sine) + (_tcy * _cosine)) + _ccy # print "cx: %g; cy %g" % (_cx, _cy) return _cx, _cy, _tcrad def calc_tangent_circle(obja, objb, x, y): _x = x if not isinstance(_x, float): _x = float(x) _y = y if not isinstance(_y, float): _y = float(y) _tandata = None if isinstance(obja, hcline.HCLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_hcl_tangent(obja, objb, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _hcl_vcl_tangent(obja, objb, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _hcl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _hcl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _hcl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, vcline.VCLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_vcl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_vcl_tangent(obja, objb, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _vcl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _vcl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _vcl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, acline.ACLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_acl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_acl_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_acl_tangent(obja, objb, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _acl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _tandata = _acl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, cline.CLine): if isinstance(objb, hcline.HCLine): _tandata = _hcl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_cl_tangent(objb, obja, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _cl_cl_tangent(obja, objb, _x, _y) elif isinstance(objb, ccircle.CCircle): _cl_cc_tangent(obja, objb, _x, _y) elif isinstance(obja, ccircle.CCircle): if isinstance(objb, hcline.HCLine): _tandata = _hcl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, vcline.VCLine): _tandata = _vcl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, acline.ACLine): _tandata = _acl_cc_tangent(objb, obja, _x, _y) elif isinstance(objb, cline.CLine): _tandata = _cl_cc_tangent(objb, obja, _x, _y) else: pass # CCircle/CCircle tangent circles to do later ... return _tandata # # calculate the possible tangent lines between two circles # def _calc_values(ax, ay, bx, by, cx, cy): """This function was used for debugging""" _den = pow((bx - ax), 2) + pow((by - ay), 2) _num = ((cx - ax) * (bx - ax)) + ((cy - ay) * (by - ay)) _r = _num/_den # print "r: %g" % _r _num = ((ay - cy) * (bx - ax)) - ((ax - cx) * (by - ay)) _s = _num/_den # print "s: %g" % _s _sep = abs(_s) * math.sqrt(_den) # print "sep: %g" % _sep # return _r, _s, _sep def _calc_tangent_triangle(r1, r2, sep, ip): _sine = r1/abs(ip) # print "sin: %g" % _sine _angle = math.asin(_sine) # print "angle: %g" % (_angle * (180.0/math.pi)) _tan = math.tan(_angle) # print "tan(angle): %g" % _tan _cosine = math.cos(_angle) # print "cos(angle): %g" % _cosine _tanlen = r1/_tan # print "tanlen: %g" % _tanlen if ip < 0.0: # r1 < r2 and intersection point left of r1 assert abs(ip) > r1, "Expected ip beyond radius: %g < %g" % (ip, r1) _tx1 = ip + (_tanlen * _cosine) else: _tx1 = ip - (_tanlen * _cosine) # print "tx1: %g" % _tx1 _ty1 = _tanlen * _sine # print "ty1: %g" % _ty1 _dist = math.hypot(_tx1, _ty1) # print "dist: %g" % _dist assert abs(_dist - r1) < 1e-10, "Invalid tangent point for circle 1" _tanlen = r2/_tan # print "tanlen: %g" % _tanlen if ip < 0.0: # see above _tx2 = ip + (_tanlen * _cosine) _ty2 = _tanlen * _sine elif ip > (sep + r2): # only possible if r1 > r2 _tx2 = ip - (_tanlen * _cosine) _ty2 = _tanlen * _sine else: _tx2 = ip + (_tanlen * _cosine) _ty2 = -1.0 * _tanlen * _sine # print "tx2: %g" % _tx2 # print "ty2: %g" % _ty2 _dist = math.hypot((_tx2 - sep), _ty2) # print "dist: %g" % _dist assert abs(_dist - r2) < 1e-10, "Invalid tangent point for circle 2" return _tx1, _ty1, _tx2, _ty2 def calc_two_circle_tangents(r1, r2, sep): # print "in calc_two_circle_tangents() ..." _r1 = r1 if not isinstance(_r1, float): _r1 = float(r1) if not _r1 > 0.0: raise ValueError, "Invalid radius: %g" % _r1 _r2 = r2 if not isinstance(_r2, float): _r2 = float(r2) if not _r2 > 0.0: raise ValueError, "Invalid radius: %g" % _r2 _sep = sep if not isinstance(_sep, float): _sep = float(sep) _tangents = [] if (abs(_sep) + min(_r1, _r2)) > max(_r1, _r2): # small circle not within larger if abs(_r1 - _r2) < 1e-10: # print "same radii ..." _tangents.append((0.0, _r1, _sep, _r2)) _tangents.append((0.0, -_r1, _sep, -_r2)) if abs(_sep) > _r1 + _r2: _mid = _sep/2.0 _angle = math.asin(_r1/_mid) _tanlen = _r1/math.tan(_angle) _xt = _tanlen * math.cos(_angle) _yt = _tanlen * math.sin(_angle) _tx1 = _mid - _xt _ty1 = _yt _tx2 = _mid + _xt _ty2 = -_yt _tangents.append((_tx1, _ty1, _tx2, _ty2)) # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) _tangents.append((_tx1, -_ty1, _tx2, -_ty2)) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) else: _alpha = pow((_r1/_r2), 2) # print "alpha: %g" % _alpha _a = (1.0 - _alpha) # print "a: %g" % _a _b = (2.0 * _alpha * _sep) # print "b: %g" % _b _c = (-1.0 * _alpha * pow(_sep, 2)) # print "c: %g" % _c _det = pow(_b, 2) - (4.0 * _a * _c) # print "det: %g" % _det if _det > 0.0: # can this ever be negative? # print "r1: %g" % _r1 # print "r2: %g" % _r2 # print "sep: %g" % _sep _denom = 2.0 * _a _det_sqrt = math.sqrt(_det) _num = (-1.0 * _b) + _det_sqrt _offset = _num/_denom # print "offset: %g" % _offset if (_r1 > _r2): # print "r1 > r2" if ((_offset > (_sep + _r2)) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) else: # _r1 < _r2 # print "r1 < r2" if ((_offset < -_r1) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) _num = (-1.0 * _b) - _det_sqrt _offset = _num/_denom # print "offset: %g" % _offset if (_r1 > _r2): # print "r1 > r2" if ((_offset > (_sep + _r2)) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) else: # _r1 < _r2 # print "r1 < r2" if ((_offset < -_r1) or ((_offset > _r1) and (_offset < (_sep - _r2)))): _tpts = _calc_tangent_triangle(_r1, _r2, _sep, _offset) _tangents.append(_tpts) _tx1, _ty1, _tx2, _ty2 = _tpts # _calc_values(_tx1, _ty1, _tx2, _ty2, 0.0, 0.0) # _calc_values(_tx1, _ty1, _tx2, _ty2, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, _sep, 0.0) # _calc_values(_tx2, _ty2, _tx1, _ty1, 0.0, 0.0) _tpts = (_tx1, - _ty1, _tx2, -_ty2) _tangents.append(_tpts) # _calc_values(_tx1, -_ty1, _tx2,-_ty2, 0.0, 0.0) # _calc_values(_tx1, -_ty1, _tx2, -_ty2, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, _sep, 0.0) # _calc_values(_tx2, -_ty2, _tx1, -_ty1, 0.0, 0.0) return _tangents