# # Copyright (c) 2002, 2003, 2006 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 # # # code to calculate if or where two objects intersect # # from __future__ import division import math from PythonCAD.Generic import point from PythonCAD.Generic import segment from PythonCAD.Generic import circle from PythonCAD.Generic import arc 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 _rtd = 180.0/math.pi _zero = 0.0 - 1e-10 _one = 1.0 + 1e-10 # # the following functions are used to calculate the # intersection of two line segments # # see comp.graphics.algorithms FAQ for details # def denom(p1, p2, p3, p4): if not isinstance(p1, point.Point): raise TypeError, "Invalid argument to denom(): " + `type(p1)` if not isinstance(p2, point.Point): raise TypeError, "Invalid argument to denom(): " + `type(p2)` if not isinstance(p3, point.Point): raise TypeError, "Invalid argument to denom(): " + `type(p3)` if not isinstance(p4, point.Point): raise TypeError, "Invalid argument to denom(): " + `type(p4)` _p1x, _p1y = p1.getCoords() _p2x, _p2y = p2.getCoords() _p3x, _p3y = p3.getCoords() _p4x, _p4y = p4.getCoords() return ((_p2x - _p1x)*(_p4y - _p3y)) - ((_p2y - _p1y)*(_p4x - _p3x)) def rnum(p1, p2, p3, p4): if not isinstance(p1, point.Point): raise TypeError, "Invalid argument to rnum(): " + `type(p1)` if not isinstance(p2, point.Point): raise TypeError, "Invalid argument to rnum(): " + `type(p2)` if not isinstance(p3, point.Point): raise TypeError, "Invalid argument to rnum(): " + `type(p3)` if not isinstance(p4, point.Point): raise TypeError, "Invalid argument to rnum(): " + `type(p4)` _p1x, _p1y = p1.getCoords() _p2x, _p2y = p2.getCoords() _p3x, _p3y = p3.getCoords() _p4x, _p4y = p4.getCoords() return ((_p1y - _p3y)*(_p4x - _p3x)) - ((_p1x - _p3x)*(_p4y - _p3y)) def snum(p1, p2, p3, p4): if not isinstance(p1, point.Point): raise TypeError, "Invalid argument to snum(): " + `type(p1)` if not isinstance(p2, point.Point): raise TypeError, "Invalid argument to snum(): " + `type(p2)` if not isinstance(p3, point.Point): raise TypeError, "Invalid argument to snum(): " + `type(p3)` if not isinstance(p4, point.Point): raise TypeError, "Invalid argument to snum(): " + `type(p4)` _p1x, _p1y = p1.getCoords() _p2x, _p2y = p2.getCoords() _p3x, _p3y = p3.getCoords() _p4x, _p4y = p4.getCoords() return ((_p1y - _p3y)*(_p2x - _p1x)) - ((_p1x - _p3x)*(_p2y - _p1y)) # # the following function is used to calculate the intersection # of a circle and a segment or a circle and an infite length line # # see Paul Bourke's web pages for details # def sc_intersection(x1, y1, x2, y2 ,_circ, skiptest=False): if not isinstance(x1, float): raise TypeError, "Invalid argument: " + `type(x1)` if not isinstance(y1, float): raise TypeError, "Invalid argument: " + `type(y1)` if not isinstance(x2, float): raise TypeError, "Invalid argument: " + `type(x2)` if not isinstance(y2, float): raise TypeError, "Invalid argument: " + `type(y2)` if not isinstance(_circ, (circle.Circle, arc.Arc, ccircle.CCircle)): raise TypeError, "Invalid circle for sc_intersection(): " + `type(_circ)` _plist = [] _xdiff = x2 - x1 _ydiff = y2 - y1 _xc, _yc = _circ.getCenter().getCoords() _r = _circ.getRadius() _u = ((_xc - x1)*(_xdiff) + (_yc - y1)*(_ydiff))/(pow(_xdiff, 2) + pow(_ydiff, 2)) _xp = x1 + (_u * _xdiff) _yp = y1 + (_u * _ydiff) _dist = math.hypot((_yp - _yc), (_xp - _xc)) if abs(_dist - _r) < 1e-10: if skiptest or not (_u < _zero or _u > _one): _plist.append((_xp, _yp)) else: if _dist < _r: _a = pow(_xdiff, 2) + pow(_ydiff, 2) _b = 2.0 * ((_xdiff * (x1 - _xc)) + (_ydiff * (y1 - _yc))) _c = (pow(_xc, 2) + pow(_yc, 2) + pow(x1, 2) + pow(y1, 2) - 2.0 * ((_xc*x1) + (_yc*y1)) - pow(_r,2)) _det = pow(_b, 2) - (4.0 * _a * _c) if _det > 1e-10: _dsq = math.sqrt(_det) _u = (-_b - _dsq)/(2.0 * _a) if skiptest or not (_u < _zero or _u > _one): _x = x1 + (_u * _xdiff) _y = y1 + (_u * _ydiff) _plist.append((_x, _y)) _u = (-_b + _dsq)/(2.0 * _a) if skiptest or not (_u < _zero or _u > _one): _x = x1 + (_u * _xdiff) _y = y1 + (_u * _ydiff) _plist.append((_x, _y)) return _plist # # intersection functions # def _null_intfunc(ipts, obja, objb): print "invoked _null_intfunc()" print "obja: " + `obja` print "objb: " + `objb` def _non_intersecting(ipts, obja, objb): pass # # segment - segment intersection # def _seg_seg_intersection(ipts, seg1, seg2): _p1, _p2 = seg1.getEndpoints() _p3, _p4 = seg2.getEndpoints() _xi = _yi = None if _p1 == _p3: _x, _y = _p4.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p1.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p1 == _p4: _x, _y = _p3.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p1.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _p3: _x, _y = _p4.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p2.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() elif _p2 == _p4: _x, _y = _p3.getCoords() _proj = seg1.getProjection(_x, _y) if _proj is None: _xi, _yi = _p2.getCoords() else: _px, _py = _proj if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _p3, _p4)/_d _s = snum(_p1, _p2, _p3 ,_p4)/_d if (not (_r < _zero or _r > _one) and not (_s < _zero or _s > _one)): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - circle intersection # def _seg_circ_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _circ = objb else: _seg = objb _circ = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1, _p2 = _seg.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _circ): ipts.append(_ip) # # segment - arc intersection # def _seg_arc_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _arc = objb else: _seg = objb _arc = obja _p1, _p2 = _seg.getEndpoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _ax, _ay = _arc.getCenter().getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _arc): _x, _y = _ip _angle = math.atan2((_y - _ay),(_x - _ax)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) # # segment - horizontal construction line intersection # def _seg_hcl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _hcl = objb else: _seg = objb _hcl = obja _p1, _p2 = _seg.getEndpoints() _hp = _hcl.getLocation() _hx, _hy = _hp.getCoords() _xi = _yi = None if _hp == _p1: _p2x, _p2y = _p2.getCoords() if abs(_hy - _p2y) > 1e-10: _xi, _yi = _p1.getCoords() elif _hp == _p2: _p1x, _p1y = _p1.getCoords() if abs(_hy - _p1y) > 1e-10: _xi, _yi = _p2.getCoords() else: _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _miny = min(_p1y, _p2y) _maxy = max(_p1y, _p2y) if abs(_p1y - _p2y) > 1e-10 and _miny < _hy < _maxy: _xi = _p1x + ((_hy - _p1y)*(_p2x - _p1x))/(_p2y - _p1y) _yi = _hy if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - vertical construction line intersection # def _seg_vcl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _vcl = objb else: _seg = objb _vcl = obja _p1, _p2 = _seg.getEndpoints() _vp = _vcl.getLocation() _vx, _vy = _vp.getCoords() _xi = _yi = None if _vp == _p1: _p2x, _p2y = _p2.getCoords() if abs(_vx - _p2x) > 1e-10: _xi, _yi = _p1.getCoords() elif _vp == _p2: _p1x, _p1y = _p1.getCoords() if abs(_vx - _p1x) > 1e-10: _xi, _yi = _p2.getCoords() else: _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _vx, _vy = _vp.getCoords() _minx = min(_p1x, _p2x) _maxx = max(_p1x, _p2x) if abs(_p1x - _p2x) > 1e-10 and _minx < _vx < _maxx: _xi = _vx _yi = _p1y + ((_p2y - _p1y)*(_vx - _p1x))/(_p2x - _p1x) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - angled construction line intersection # def _seg_acl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _acl = objb else: _seg = objb _acl = obja _p1, _p2 = _seg.getEndpoints() _ap = _acl.getLocation() _xi = _yi = None if _p1 == _ap: _x, _y = _p2.getCoords() _px, _py = _acl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _ap: _x, _y = _p1.getCoords() _px, _py = _acl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _ax, _ay = _ap.getCoords() _angle = _acl.getAngle() * _dtr _xt = _ax + math.cos(_angle) _yt = _ay + math.sin(_angle) _tp = point.Point(_xt, _yt) _d = denom(_p1, _p2, _ap, _tp) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _ap, _tp)/_d if not (_r < _zero or _r > _one): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # segment - 2-point construction line intersection # def _seg_cl_intersection(ipts, obja, objb): if isinstance(obja, segment.Segment): _seg = obja _cl = objb else: _seg = objb _cl = obja _p1, _p2 = _seg.getEndpoints() _p3, _p4 = _cl.getKeypoints() _xi = _yi = None if _p1 == _p3 or _p1 == _p4: _x, _y = _p2.getCoords() _px, _py = _cl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p1.getCoords() elif _p2 == _p3 or _p2 == _p4: _x, _y = _p1.getCoords() _px, _py = _cl.getProjection(_x, _y) if math.hypot((_px - _x), (_py - _y)) > 1e-10: _xi, _yi = _p2.getCoords() else: _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _r = rnum(_p1, _p2, _p3, _p4)/_d if not (_r < _zero or _r > _one): _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # circle - circle intersection # # see Paul Bourke's web pages for algorithm # def _circ_circ_intersection(ipts, circ1, circ2): _c1x, _c1y = circ1.getCenter().getCoords() _r1 = circ1.getRadius() _c2x, _c2y = circ2.getCenter().getCoords() _r2 = circ2.getRadius() _xdiff = _c2x - _c1x _ydiff = _c2y - _c1y if not (abs(_xdiff) < 1e-10 and abs(_ydiff) < 1e-10): # NOT concentric _sep = math.hypot(_xdiff, _ydiff) _maxsep = _r1 + _r2 + 1e-10 _minsep = abs(_r1 - _r2) - 1e-10 # print "sep: %g; maxsep: %g; minsep: %g" % (_sep, _maxsep, _minsep) if _minsep < _sep < _maxsep: _a = (pow(_r1, 2) - pow(_r2, 2) + pow(_sep, 2))/(2*_sep) _pcx = _c1x + _a * (_xdiff/_sep) _pcy = _c1y + _a * (_ydiff/_sep) # print "a: %g; pcx: %g; pcy: %g" % (_a, _pcx, _pcy) if abs(abs(_a) - _r1) < 1e-10: # single contact point ipts.append((_pcx, _pcy)) else: # two contact points _h = math.sqrt(pow(_r1, 2) - pow(_a, 2)) _x = _pcx + _h * (_ydiff/_sep) _y = _pcy - _h * (_xdiff/_sep) ipts.append((_x, _y)) _x = _pcx - _h * (_ydiff/_sep) _y = _pcy + _h * (_xdiff/_sep) ipts.append((_x, _y)) # # circle - arc intersection # def _circ_arc_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _circ = objb else: _circ = obja _arc = objb _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_circ_intersection(_ipts, _circ, _tempcirc) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # circle - horizontal contruction line intersection # def _circ_hcl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _hcl = objb else: _circ = objb _hcl = obja _cp = _circ.getCenter() _r = _circ.getRadius() _hp = _hcl.getLocation() _hx, _hy = _hp.getCoords() if _hp == _cp: ipts.append(((_hx - _r), _hy)) ipts.append(((_hx + _r), _hy)) else: _cx, _cy = _circ.getCenter().getCoords() _ymin = _cy - _r _ymax = _cy + _r if abs(_ymin - _hy) < 1e-10: ipts.append((_cx, _ymin)) elif abs(_ymax - _hy) < 1e-10: ipts.append((_cx, _ymax)) elif _ymin < _hy < _ymax: _offset = math.sqrt(pow(_r, 2) - pow((_cy - _hy), 2)) ipts.append(((_cx - _offset), _hy)) ipts.append(((_cx + _offset), _hy)) else: pass # # circle - vertical contruction line intersection # def _circ_vcl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _vcl = objb else: _circ = objb _vcl = obja _cp = _circ.getCenter() _r = _circ.getRadius() _vp = _vcl.getLocation() _vx, _vy = _vp.getCoords() if _vp == _cp: ipts.append((_vx, (_vy - _r))) ipts.append((_vx, (_vy + _r))) else: _cx, _cy = _circ.getCenter().getCoords() _xmin = _cx - _r _xmax = _cx + _r if abs(_xmin - _vx) < 1e-10: ipts.append((_xmin, _cy)) elif abs(_xmax - _vx) < 1e-10: ipts.append((_xmax, _cy)) elif _xmin < _vx < _xmax: _offset = math.sqrt(pow(_r, 2) - pow((_vx - _cx), 2)) ipts.append((_vx, (_cy - _offset))) ipts.append((_vx, (_cy + _offset))) else: pass # # circle - angled construction line intersection # def _circ_acl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _acl = objb else: _circ = objb _acl = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1x, _p1y = _acl.getLocation().getCoords() _angle = _acl.getAngle() * _dtr _xt = _p1x + math.cos(_angle) _yt = _p1y + math.sin(_angle) for _ip in sc_intersection(_p1x, _p1y, _xt, _yt, _circ, True): ipts.append(_ip) # # circle - 2-point construction line intersection # def _circ_cl_intersection(ipts, obja, objb): if isinstance(obja, (circle.Circle, ccircle.CCircle)): _circ = obja _cl = objb else: _circ = objb _cl = obja assert not isinstance(_circ, arc.Arc), "Arc found!" _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() for _ip in sc_intersection(_p1x, _p1y, _p2x, _p2y, _circ, True): ipts.append(_ip) # # arc - arc intersection # def _arc_arc_intersection(ipts, arc1, arc2): _cp1 = arc1.getCenter() _r1 = arc1.getRadius() _tempcirc1 = circle.Circle(_cp1, _r1) _cp2 = arc2.getCenter() _r2 = arc2.getRadius() _tempcirc2 = circle.Circle(_cp2, _r2) _ipts = [] _circ_circ_intersection(_ipts, _tempcirc1, _tempcirc2) if len(_ipts): # may have intersection points ... for _ip in _ipts: _cx, _cy = _cp1.getCoords() _x, _y = _ip _angle = math.atan2((_y - _cy), (_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if arc1.throughAngle(_angle): _cx, _cy = _cp2.getCoords() _angle = math.atan2((_y - _cy), (_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if arc2.throughAngle(_angle): ipts.append(_ip) _tempcirc1.finish() _tempcirc2.finish() # # arc - horizontal construction line intersection # def _arc_hcl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _hcl = objb else: _arc = objb _hcl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_hcl_intersection(_ipts, _tempcirc, _hcl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - vertical construction line intersection # def _arc_vcl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _vcl = objb else: _arc = objb _vcl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_vcl_intersection(_ipts, _tempcirc, _vcl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - angled construction line intersection # def _arc_acl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _acl = objb else: _arc = objb _acl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_acl_intersection(_ipts, _tempcirc, _acl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # arc - 2-point construction line intersection # def _arc_cl_intersection(ipts, obja, objb): if isinstance(obja, arc.Arc): _arc = obja _cl = objb else: _arc = objb _cl = obja _cp = _arc.getCenter() _r = _arc.getRadius() _tempcirc = circle.Circle(_cp, _r) _ipts = [] _circ_cl_intersection(_ipts, _tempcirc, _cl) if len(_ipts): # may have intersection points ... _cx, _cy = _cp.getCoords() for _ip in _ipts: _x, _y = _ip _angle = math.atan2((_y - _cy),(_x - _cx)) * _rtd if _angle < 0.0: _angle = _angle + 360.0 if _arc.throughAngle(_angle): ipts.append(_ip) _tempcirc.finish() # # horizontal construction line - vertical construction line intersection # def _hcl_vcl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _vcl = objb else: _hcl = objb _vcl = obja _hx, _hy = _hcl.getLocation().getCoords() _vx, _vh = _vcl.getLocation().getCoords() ipts.append((_vx, _hy)) # # horizontal construction line - angled construction line intersection # def _hcl_acl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _acl = objb else: _hcl = objb _acl = obja _angle = _acl.getAngle() if abs(_angle) > 1e-10: # acl is NOT horizontal _xi = _yi = None _hp = _hcl.getLocation() _ap = _acl.getLocation() if _hp == _ap: _xi, _yi = _hp.getCoords() else: _hx, _hy = _hp.getCoords() _yi = _hy _ax, _ay = _ap.getCoords() if abs(abs(_angle) - 90.0) < 1e-10: # acl is vertical _xi = _ax else: _slope = math.tan(_angle * _dtr) _yint = _ay - _slope*_ax _xi = (_hy - _yint)/_slope ipts.append((_xi, _yi)) # # horizontal construction line - 2-point construction line intersection # def _hcl_cl_intersection(ipts, obja, objb): if isinstance(obja, hcline.HCLine): _hcl = obja _cl = objb else: _hcl = objb _cl = obja _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _ydiff = _p2y - _p1y if abs(_ydiff) > 1e-10: # cline is NOT horizontal _xi = _yi = None _hp = _hcl.getLocation() if _hp == _p1: _xi, _yi = _p1.getCoords() elif _hp == _p2: _xi, _yi = _p2.getCoords() else: _hx, _hy = _hp.getCoords() _yi = _hy _xdiff = _p2x - _p1x if abs(_xdiff) < 1e-10: # cline is vertical _xi = _p1x else: _slope = _ydiff/_xdiff _yint = _p1y - _slope*_p1x _xi = (_hy - _yint)/_slope ipts.append((_xi, _yi)) # # vertical construction line - angled construction line intersection # def _vcl_acl_intersection(ipts, obja, objb): if isinstance(obja, vcline.VCLine): _vcl = obja _acl = objb else: _vcl = objb _acl = obja _angle = _acl.getAngle() if abs(abs(_angle) - 90.0) > 1e-10: # acl is NOT vertical _vp = _vcl.getLocation() _ap = _acl.getLocation() if _vp == _ap: _xi, _yi = _vp.getCoords() else: _vx, _vy = _vp.getCoords() _xi = _vx _ax, _ay = _ap.getCoords() _slope = math.tan(_angle * _dtr) _yint = _ay - _slope*_ax _yi = _slope*_vx + _yint ipts.append((_xi, _yi)) # # vertical construction line - 2-point construction line intersection # def _vcl_cl_intersection(ipts, obja, objb): if isinstance(obja, vcline.VCLine): _vcl = obja _cl = objb else: _vcl = objb _cl = obja _p1, _p2 = _cl.getKeypoints() _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xdiff = _p2x - _p1x if abs(_xdiff) > 1e-10: # cline is NOT vertical _xi = _yi = None _vp = _vcl.getLocation() if _vp == _p1: _xi, _yi = _p1.getCoords() elif _vp == _p2: _xi, _yi = _p2.getCoords() else: _vx, _vy = _vp.getCoords() _xi = _vx _ydiff = _p2y - _p1y if abs(_ydiff) < 1e-10: # cline is horizontal _yi = _p1y else: _slope = _ydiff/_xdiff _yint = _p1y - _slope*_p1x _yi = _slope*_vx + _yint ipts.append((_xi, _yi)) # # angled construction line - angled construction line intersection # def _acl_acl_intersection(ipts, acl1, acl2): _ap1 = acl1.getLocation() _ap1x, _ap1y = _ap1.getCoords() _angle1 = acl1.getAngle() * _dtr _xt1 = _ap1x + math.cos(_angle1) _yt1 = _ap1y + math.sin(_angle1) _t1 = point.Point(_xt1, _yt1) _ap2 = acl2.getLocation() _ap2x, _ap2y = _ap2.getCoords() _angle2 = acl2.getAngle() * _dtr _xt2 = _ap2x + math.cos(_angle2) _yt2 = _ap2y + math.sin(_angle2) _t2 = point.Point(_xt2, _yt2) _d = denom(_ap1, _t1, _ap2, _t2) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _ap1 == _ap2: _xi, _yi = _ap1.getCoords() else: _rn = rnum(_ap1, _t1, _ap2, _t2) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _xi = _ap1x + _r * (_xt1 - _ap1x) _yi = _ap1y + _r * (_yt1 - _ap1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # angled construction line - 2-point construction line intersection # def _acl_cl_intersection(ipts, obja, objb): if isinstance(obja, acline.ACLine): _acl = obja _cl = objb else: _acl = objb _cl = obja _ap = _acl.getLocation() _apx, _apy = _ap.getCoords() _angle = _acl.getAngle() * _dtr _xt = _apx + math.cos(_angle) _yt = _apy + math.sin(_angle) _t1 = point.Point(_xt, _yt) _p1, _p2 = _cl.getKeypoints() _d = denom(_ap, _t1, _p1, _p2) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _ap == _p1: _xi, _yi = _p1.getCoords() elif _ap == _p2: _xi, _yi = _p2.getCoords() else: _rn = rnum(_ap, _t1, _p1, _p2) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _xi = _apx + _r * (_xt - _apx) _yi = _apy + _r * (_yt - _apy) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # 2-point construction line - 2-point construction line intersection # def _cl_cl_intersection(ipts, cl1, cl2): _p1, _p2 = cl1.getKeypoints() _p3, _p4 = cl2.getKeypoints() _d = denom(_p1, _p2, _p3, _p4) if abs(_d) > 1e-10: # NOT parallel _xi = _yi = None if _p1 == _p3 or _p2 == _p3: _xi, _yi = _p3.getCoords() elif _p1 == _p4 or _p2 == _p4: _xi, _yi = _p4.getCoords() else: _rn = rnum(_p1, _p2, _p3, _p4) if abs(_rn) > 1e-10: # NOT colinear _r = _rn/_d _p1x, _p1y = _p1.getCoords() _p2x, _p2y = _p2.getCoords() _xi = _p1x + _r * (_p2x - _p1x) _yi = _p1y + _r * (_p2y - _p1y) if _xi is not None and _yi is not None: ipts.append((_xi, _yi)) # # set segment intersecting function # def _segment_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_seg_intersection elif isinstance(objb, arc.Arc): _func = _seg_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _seg_circ_intersection elif isinstance(objb, hcline.HCLine): _func = _seg_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _seg_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _seg_acl_intersection elif isinstance(objb, cline.CLine): _func = _seg_cl_intersection else: _func = _null_intfunc return _func # # set circle intersecting function # def _circ_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_circ_intersection elif isinstance(objb, arc.Arc): _func = _circ_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_circ_intersection elif isinstance(objb, hcline.HCLine): _func = _circ_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _circ_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _circ_acl_intersection elif isinstance(objb, cline.CLine): _func = _circ_cl_intersection else: _func = _null_intfunc return _func # # set arc intersecting function # def _arc_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_arc_intersection elif isinstance(objb, arc.Arc): _func = _arc_arc_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_arc_intersection elif isinstance(objb, hcline.HCLine): _func = _arc_hcl_intersection elif isinstance(objb, vcline.VCLine): _func = _arc_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _arc_acl_intersection elif isinstance(objb, cline.CLine): _func = _arc_cl_intersection else: _func = _null_intfunc return _func # # set hcline intersecting function # def _hcline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_hcl_intersection elif isinstance(objb, arc.Arc): _func = _arc_hcl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_hcl_intersection elif isinstance(objb, hcline.HCLine): _func = _non_intersecting elif isinstance(objb, vcline.VCLine): _func =_hcl_vcl_intersection elif isinstance(objb, acline.ACLine): _func = _hcl_acl_intersection elif isinstance(objb, cline.CLine): _func = _hcl_cl_intersection else: _func = _null_intfunc return _func # # set vcline intersecting function # def _vcline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_vcl_intersection elif isinstance(objb, arc.Arc): _func = _arc_vcl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_vcl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_vcl_intersection elif isinstance(objb, vcline.VCLine): _func = _non_intersecting elif isinstance(objb, acline.ACLine): _func = _vcl_acl_intersection elif isinstance(objb, cline.CLine): _func = _vcl_cl_intersection return _func # # set acline intersecting function # def _acline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_acl_intersection elif isinstance(objb, arc.Arc): _func = _arc_acl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_acl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_acl_intersection elif isinstance(objb, vcline.VCLine): _func = _vcl_acl_intersection elif isinstance(objb, acline.ACLine): _func = _acl_acl_intersection elif isinstance(objb, cline.CLine): _func = _acl_cl_intersection else: _func = _null_intfunc return _func # # set cline intersecting function # def _cline_intfuncs(objb): if isinstance(objb, segment.Segment): _func = _seg_cl_intersection elif isinstance(objb, arc.Arc): _func = _arc_cl_intersection elif isinstance(objb, (circle.Circle, ccircle.CCircle)): _func = _circ_cl_intersection elif isinstance(objb, hcline.HCLine): _func = _hcl_cl_intersection elif isinstance(objb, vcline.VCLine): _func = _vcl_cl_intersection elif isinstance(objb, acline.ACLine): _func = _acl_cl_intersection elif isinstance(objb, cline.CLine): _func = _cl_cl_intersection else: _func = _null_intfunc return _func # # intersection functions for polylines # def _get_intfunc(obja, objb): if isinstance(obja, segment.Segment): _intfunc = _segment_intfuncs(objb) elif isinstance(obja, arc.Arc): _intfunc = _arc_intfuncs(objb) elif isinstance(obja, (circle.Circle, ccircle.CCircle)): _intfunc = _circ_intfuncs(objb) elif isinstance(obja, hcline.HCLine): _intfunc = _hcline_intfuncs(objb) elif isinstance(obja, vcline.VCLine): _intfunc = _vcline_intfuncs(objb) elif isinstance(obja, acline.ACLine): _intfunc = _acline_intfuncs(objb) elif isinstance(obja, cline.CLine): _intfunc = _cline_intfuncs(objb) else: _intfunc = _null_intfunc return _intfunc def find_intersections(obja, objb): _ipts = [] _intfunc = _get_intfunc(obja, objb) _intfunc(_ipts, obja, objb) return _ipts