0001"""
0002**line segment** connecting the points of a line on a given 
0003geometric object
0004"""
0005__Def__ =       ['Chord']
0006
0007__Classes__ =   ['CircleChord', 'SphereChord','BiChord','ConicChord']
0008
0009__all__= __Classes__+__Def__
0010
0011__doc_hints__={'m_type':'factory'}
0012
0013import pygeo.base.abstracts._real as Real
0014
0015from pygeo.base.analytics._position3 import Position3
0016from pygeo.base.analytics.pygeomath import sqrt, arccos, array, matrixmultiply,                                  transpose, toXY,  quadratic, cross3
0018from pygeo.base.support.pygeoopts import DO_TESTS, EPS
0019
0020
0021class CircleChord(Real._Line):
0022    """
0023*line segment* joining the points of intersection of the given **circle** 
0024and **line**
0025
0026    inherits
0027    
0028        `_Line`__
0029
0030__ class-base.abstracts._real._Line.html        
0031
0032    """
0033
0034    __doc_hints__=  {'factory':'Chord',
0035                    'args':['circle,line'],
0036                    'conditions':['circle and line are coplanar',
0037                                 'circle and line intersection is real'],
0038                    'otherwise':'None; None'}
0039
0040    def __init__(self,circle,line,**kws):
0041        self.tp=Position3()
0042        self.circle=circle
0043        self.line=line
0044        Real._Line.__init__(self,*[circle,line],**kws)
0045        self.seg=True
0046        self.deps=[self.p1,self.p2]
0047        self.init()
0048
0049    def findSelf(self):
0050        if DO_TESTS:
0051            t=(self.line.p1.onPlane(self.circle)
0052                and self.line.p2.onPlane(self.circle))
0053        else:
0054            t=True
0055        if t:
0056            self.tp.set(self.circle._center)
0057            if self.tp.toLine(self.line.p1,self.line.p2):
0058                d=self.tp.distanceSquared(self.circle._center)
0059                if sqrt(d) > self.circle._radius:
0060                    print self.__class__.__name__
0061                    print """no real point of intersection for circle 
0062                          and line returned False"""
0063                    return False
0064                if not d < EPS:
0065                    r=self.circle._radiusSquared
0066                    factor=sqrt(r-d)/self.tp.distance(self.line.p1)
0067                    self.p1.set((self.line.p1-self.tp)*factor+self.tp)
0068                    self.p2.set(self.tp*2-self.p1)
0069                else:
0070                    # line is through circle center
0071                    self.p1.set(self.line.getDirection()*self.circle._radius
0072                               +self.tp)
0073                    self.p2.set(self.line.getDirection()*-self.circle._radius
0074                               +self.tp)
0075                return True
0076            else:
0077                print self.__class__.__name__
0078                print """line segment points not distinct, toLine opreation 
0079                         returned False"""
0080                return False
0081        else:
0082            print self.__class__.__name__
0083            print """circle and line are not coplanar, no intersection 
0084                    chord defined, returned False"""
0085            return False
0086
0087
0088class SphereChord(Real._Line):
0089    """
0090*line segment* joining the points of intersection of the given **sphere** 
0091and **line**
0092    
0093    inherits
0094    
0095        `_Line`__
0096
0097__ class-base.abstracts._real._Line.html        
0098    
0099    """
0100
0101    __doc_hints__=  {'factory':'Chord',
0102                    'args':['sphere,line'],
0103                    'conditions':['sphere and line intersection is real'],
0104                    'otherwise':'None'}
0105
0106    def __init__(self,sphere,line,**kws):
0107        self.sphere=sphere
0108        self.line=line
0109        self.t=Real._Point()
0110        Real._Line.__init__(self,*[sphere,line],**kws)
0111        self.seg=True
0112        self.deps=[self.p1,self.p2]
0113        self.init()
0114
0115    def findSelf(self):
0116        line=self.line
0117        sphere=self.sphere
0118        self.t.set(sphere._center)
0119        self.t.toLine(line.p1,line.p2)
0120        self.t-=sphere._center
0121        t2=self.t.mag2
0122        r2 = sphere._radiusSquared
0123        if t2 > r2:
0124            self.t*=.5
0125            d = 0.50*(1.0+(r2-t2)/t2)
0126            self.t*=d
0127            crad = sqrt(r2 - d**2*t2)
0128            self.p1.set(cross3(line.p1,line.p2,sphere._center).norm())
0129            self.p1*=crad
0130            self.p2.set(self.p1*-1)
0131            self.t+=sphere._center
0132            self.p1+=self.t
0133            self.p2+=self.t
0134        else:
0135            self.p1.set((line.p2-line.p1).norm())
0136            crad=sqrt(r2-t2)
0137            self.p1*=crad
0138            self.p2.set(self.p1*-1)
0139            self.t += sphere._center
0140            self.p1 += self.t
0141            self.p2 += self.t
0142        return True
0143
0144
0145class BiChord(Real._Line):
0146    """
0147*line segment* joining the points of intersection of the given **2 circles**
0148    
0149    inherits
0150    
0151        `_Line`__
0152
0153__ class-base.abstracts._real._Line.html        
0154    
0155    """
0156
0157    __doc_hints__=  {'factory':'Chord',
0158                    'args':['circle1,circle2'],
0159                    'conditions':['the circles are coplanar',
0160                     'the circles intersection is real'],
0161                    'otherwise':'None; None'}
0162
0163    def __init__(self,circle1,circle2,**kws):
0164        self.circle1=circle1
0165        self.circle2=circle2
0166        Real._Line.__init__(self,*[circle1,circle2],**kws)
0167        self.seg=True
0168        self.deps=[self.p1,self.p2]
0169        self.init()
0170
0171    def findSelf(self):
0172        circle1=self.circle1
0173        circle2=self.circle2
0174        if DO_TESTS:
0175            t=(circle1._center.onPlane(circle2)
0176              and circle1._cpoint.onPlane(circle2))
0177        else:
0178            t=True
0179        if t:
0180            dcenters=circle1._center.distance(circle2._center)
0181            if dcenters < EPS:
0182                print self.__class__.__name__
0183                print """circles are concentric, no intersection defined, 
0184                      return False"""
0185                return False
0186            try:
0187                angle=arccos((circle1._center.distanceSquared(circle2._center)+
0188                             circle1._radiusSquared-circle2._radiusSquared)/
0189                             (2*dcenters*circle1._radius))
0190            except ValueError:
0191                print self.__class__.__name__
0192                print """circles do not intersect in real points, 
0193                      returning False"""
0194                return False
0195            self.p1.set(circle2._center)
0196            self.p1.toCircle(circle1)
0197            self.p2.set(self.p1)
0198            self.p1.toCircumPoint(self.circle1,angle)
0199            self.p2.toCircumPoint(self.circle1,-angle)
0200            return True
0201        else:
0202            print self.__class__.__name__
0203            print """circles are not coplanar, no intersection defined, 
0204                  returning false"""
0205            return False
0206
0207
0208class ConicChord(Real._Line):
0209    """
0210*line segment* joining the points of intersection of the given **conic** and **line**
0211    
0212    inherits
0213    
0214        `_Line`__
0215
0216__ class-base.abstracts._real._Line.html        
0217    
0218    """
0219
0220    __doc_hints__=  {'factory':'Chord',
0221                    'args':['conic,line'],
0222                    'conditions':[' conic and line are coplanar',
0223                     'conic and line intersection is real'],
0224                    'otherwise':'None; None'}
0225
0226    def __init__(self,conic,line,**kws):
0227        self.conic=conic
0228        self.line=line
0229        self.pt=array([0.,0.,-1.,1.])
0230        Real._Line.__init__(self,*[self.conic,self.line],**kws)
0231        self.seg=True
0232        self.deps=[self.p1,self.p2]
0233        self.init()
0234
0235    def __repr__(self):
0236        return self.__class__.__name__ + "(" + str(self.p1) +"," +                                           str(self.p2) + ")"
0238
0239    def findSelf(self):
0240        equat=self.conic.getPlane()
0241        tp1= toXY(self.line.p1)
0242        tp2= toXY(self.line.p2)
0243        C=self.conic.getC()
0244        cx = matrixmultiply(matrixmultiply(C,tp1),transpose(tp1))
0245        ax = matrixmultiply(matrixmultiply(C,tp2),transpose(tp2))
0246        bx =2*matrixmultiply(matrixmultiply(C,tp2),transpose(tp1))
0247        h= quadratic(ax,bx,cx)
0248        if h[0]:
0249            x1=tp1+tp2*h[0]
0250            x2=tp1+tp2*h[1]
0251            x1z=array([x1[0]/x1[2],x1[1]/x1[2],0])
0252            x2z=array([x2[0]/x2[2],x2[1]/x2[2],0])
0253            self.p1.fromXY(equat,x1z)
0254            self.p2.fromXY(equat,x2z)
0255            return True
0256        else:
0257            print self.__class__.__name__
0258            print """No real intersections between conic and line, 
0259                 returning False"""
0260            return False
0261
0262def  Chord(*args,**kws):
0263    """
0264'class factory' function returns instance of object derived from the _Line 
0265abstract class, representing the segment connecting the points of the line on 
0266a given geometric object
0267    """
0268
0269    from pygeo.base.abstracts._element import method_get
0270    from pygeo.base.support.pygeoexceptions import Argument_Type_Error
0271    from pygeo.base.geometry_real.pointarrays import Conic
0272
0273    __sigs__=[[Real._Circle,Real._Line],[Real._Sphere,Real._Line],
0274             [Real._Circle,Real._Circle],[Conic,Real._Line]]
0275
0276    t,i = method_get(__sigs__,args)
0277
0278    if t is None:
0279        raise Argument_Type_Error(__sigs__,args)
0280    else:
0281        if i==0:
0282            return CircleChord(t[0],t[1],**kws)
0283        elif i==1:
0284            return SphereChord(t[0],t[1],**kws)
0285        elif i==2:
0286            return BiChord(t[0],t[1],**kws)
0287        elif i==3:
0288            return ConicChord(t[0],t[1],**kws)
0289        else:
0290            raise Argument_Type_Error(__sigs__,args)