0001"""
0002**array of points** with a defined geoemtric relationship
0003"""
0004
0005__Def__ =       ['PointArray']
0006
0007__Classes__ =   [ 'PointPencil', 'CirclingPencil',
0008                'CirclePoints','GrowthMeasure','Harmonics', 'Conic',
0009                'ArrayIntersect','PlanePoints','CorrelationPoints']
0010
0011__all__= __Classes__+ __Def__
0012
0013__doc_hints__={'m_type':'factory'}
0014
0015
0016import pygeo.base.abstracts._real as Real
0017
0018from pygeo.base.analytics._position3 import Position3
0019
0020from pygeo.base.analytics.pygeomath import arrayrange, sin, cos, transpose, PI, array,                                   matrixmultiply, cross3,eigenvectors, vector,                                  inverse
0023
0024from pygeo.base.support.pygeoopts import MAX, DO_TESTS
0025
0026class PointPencil(Real._PointArray):
0027    __opts__= Real._PointArray.__opts__[:] + ["seg"]
0028    """
0029*array of points* equidistant on given **line** 
0030    
0031    inherits
0032    
0033        `_PointArray`__
0034
0035__ class-base.abstracts._real._PointArray.html       
0036    
0037    """
0038
0039    __doc_hints__=  {'factory':'PointArray',
0040                    'args':['line <,seg=Boolean>']}
0041
0042    def __init__(self,line,**kws):
0043        self.line=line
0044        self.seg=kws.get('seg',False)
0045        Real._PointArray.__init__(self,*[line],**kws)
0046        self.init()
0047
0048    def findSelf(self):
0049        line =self.line
0050        p= line.getDirection()
0051        if (self.seg or self.line.seg):
0052            length=self.line.length()
0053            start=line.p1
0054        else:
0055            length=MAX*2
0056            start = (p*-MAX)+(line.p1+line.p2)/2
0057        steps=[length/float(self.density-1)*i for i in range(self.density)]
0058        for point,step in zip(self,steps):
0059            point.set(p*step+start)
0060        return True
0061
0062
0063class CirclingPencil(Real._PointArray):
0064    """
0065*array points* of intersection of the given **array of lines** 
0066and **the given line**
0067    
0068    inherits
0069    
0070        `_PointArray`__
0071
0072__ class-base.abstracts._real._PointArray.html       
0073    
0074    """
0075    __doc_hints__=  {'factory':'PointArray',
0076                    'args':['linearray,line'],
0077                    'conditions':['line and line array are coplanar'],
0078                    'otherwise':'None'}
0079
0080    def __init__(self,linearray,line,**kws):
0081        self.linearray=linearray
0082        self.line=line
0083        self.extend=kws.get("extend",True)
0084        self.density = self.linearray.density
0085        Real._PointArray.__init__(self,*[linearray,line],**kws)
0086        self.init()
0087
0088    def findSelf(self):
0089        if DO_TESTS:
0090            t = self.line.p1.coPlanar(self.line.p2,self.linearray.lines[0].p1,
0091                                    self.linearray.lines[0].p2)
0092        else:
0093           t =True
0094        if t :
0095            for point,line in zip(self,self.linearray):
0096                point.toInterSection(self.line.p1,self.line.p2,line.p1,line.p2)
0097            return True
0098        else:
0099            print self.__class__.__name__
0100            print """line and line array are not coplanar, 
0101                    points of intersection undefined,returned False"""
0102            return False
0103
0104    def setext(self):
0105        if self.Not_null:
0106            if self.show:
0107                for point,line in zip(self,self.linearray):
0108                    if line.show:
0109                        line.get_extension(point)
0110                        line._redraw()
0111
0112class CirclePoints(Real._PointArray):
0113    """
0114*array of points* equidistant on given circumference of given **circle**
0115    
0116    inherits
0117    
0118        `_PointArray`__
0119
0120__ class-base.abstracts._real._PointArray.html       
0121    
0122    """
0123    __doc_hints__=  {'factory':'PointArray',
0124                    'args':['circle']}
0125
0126    def __init__(self,circle,**kws):
0127        self.circle=circle
0128        Real._PointArray.__init__(self,*[circle],**kws)
0129        t = arrayrange(0,2*PI,2*PI/self.density)
0130        self.c = transpose((0*t, sin(t), cos(t)))
0131        self.init()
0132
0133    def findSelf(self):
0134        for point,s in zip(self.points,self.c):
0135            t=s*self.circle._radius
0136            n=array([t[0],t[1],t[2],1])
0137            m=matrixmultiply(n,self.circle.rmatrix())
0138            point.to_3d(m)
0139        return True
0140
0141
0142class GrowthMeasure(Real._PointArray):
0143    """
0144*array of points* of line with any sequential 4 points 
0145with crossratio equal to that of the **4 given points**  
0146    
0147    inherits
0148    
0149        `_PointArray`__
0150
0151__ class-base.abstracts._real._PointArray.html       
0152    
0153    """
0154    __doc_hints__=  {'factory':'PointArray',
0155                    'args':['point1,point2,point3,point4'],
0156                    'conditions':['points are coplanar',
0157                                'points are distinct'],
0158                    'otherwise':'None; None'}
0159
0160    def __init__(self,M,N,a,b,**kws):
0161        self.a=a
0162        self.b=b
0163        self.M=M
0164        self.N=N
0165        self.cd=0
0166        Real._PointArray.__init__(self,*[M,N,a,b],**kws)
0167        self.steps=self.density
0168        self.init()
0169
0170    def findSelf(self):
0171        if DO_TESTS:
0172            t=self.M.coLinear(self.a,self.b) and self.N.coLinear(self.a,self.b)
0173        else:
0174            t= True
0175        if t :
0176            self.cd=self.M.distance(self.N)
0177            mt=self.multiplier()
0178            iter=self.__iter__()
0179            iter.next().set(self.a)
0180            iter.next().set(self.b)
0181            def step(seed):
0182                try:
0183                    point=iter.next()
0184                    ad=seed.distance(self.N)
0185                    ac=seed.distance(self.M)
0186                    if ad > self.cd:
0187                        ac=-ac
0188                    try:
0189                        v= mt*ac/ad
0190                        point.set((self.M-self.N)/(1+v)+self.N)
0191                    except ZeroDivisionError:
0192                        print self.__class__.__name__
0193                        print """coincident points causing zero division, 
0194                              returned False """
0195                        print "point set to double point 'M'"
0196                        v=0
0197                        point.set(self.M)
0198                    step(point)
0199                except StopIteration:
0200                    pass
0201            step(self.a)
0202            return True
0203        else:
0204            print self.__class__.__name__
0205            print """points are not collinear, crossratio undefined, 
0206                   returning False"""
0207            return False
0208
0209    def multiplier(self):
0210        da=self.N.distance(self.a)
0211        ac=self.a.distance(self.M)
0212        bc=self.b.distance(self.M)
0213        db = self.N.distance(self.b)
0214        if da > self.cd:
0215            ac=-ac
0216        if db > self.cd:
0217            bc=-bc
0218        return (-da/ac)*(bc/-db)
0219
0220
0221class Harmonics(Real._PointArray):
0222    """
0223*array of points* harmonic to the given **point array**, 
0224with respect to the given **points**
0225    
0226    inherits
0227    
0228        `_PointArray`__
0229
0230__ class-base.abstracts._real._PointArray.html       
0231    
0232    """
0233
0234    __doc_hints__=  {'factory':'PointArray',
0235                    'args':['pointarray,point1,point2'],
0236                    'conditions':['array and points are coplanar ',
0237                                'points are distinct'],
0238                    'otherwise':'Undefined; Undefined'}
0239
0240    def __init__(self,pa,M,N,**kws):
0241        self.pa=pa
0242        self.M=M
0243        self.N=N
0244        self.density=self.pa.density
0245        Real._PointArray.__init__(self,*[pa,M,N],**kws)
0246        self.init()
0247
0248    def findSelf(self):
0249        for point,hpoint in zip(self,self.pa):
0250            point.toHarmonic(hpoint,self.M,self.N)
0251        return True
0252
0253
0254class Conic(Real._PointArray):
0255    """
0256*array of points* on the conic determined by the given **5 points**
0257    
0258    inherits
0259    
0260        `_PointArray`__
0261
0262__ class-base.abstracts._real._PointArray.html       
0263    
0264    """
0265    __doc_hints__=  {'factory':'PointArray',
0266                    'args':['point1,point2,point3,point4,point5'],
0267                    'conditions':['points are coplanar',
0268                                'points are distinct',
0269                                'no 3 points are collinear'],
0270                    'otherwise':'None; None; Undefined'}
0271
0272    def __init__(self,p1,p2,p3,p4,p5,**kws):
0273        self.p1=p1
0274        self.p2=p2
0275        self.p3=p3
0276        self.p4=p4
0277        self.p5=p5
0278        self.m=Position3()
0279        self.a=Position3()
0280        self.t=Position3()
0281        self.c1=Position3()
0282        self.c2=Position3()
0283        self.c3=Position3()
0284        self.c4=Position3()
0285        self.c5=Position3()
0286        Real._PointArray.__init__(self,*[p1,p2,p3,p4,p5],**kws)
0287        self.i=[2*PI/self.density*i for i in range(self.density)]
0288        self.init()
0289
0290    def findSelf(self):
0291        p1=self.p1
0292        p2=self.p2
0293        p3=self.p3
0294        p4=self.p4
0295        p5=self.p5
0296        if DO_TESTS:
0297            t = (p1.coPlanar(p2,p3,p4) and p2.coPlanar(p3,p4,p5))
0298        else:
0299            t= True
0300        if t:
0301            if self.m.toInterSection(p1,p2,p3,p4):
0302                u=cross3(p1,p2,p3).norm()
0303                radius=p1.distance(p2)
0304                cpoint=(p2-p1).norm()*radius
0305                for point,rad in zip(self,self.i):
0306                    p=p2 + cpoint.rotate(rad,u)
0307                    self.a.toInterSection(p,p2,p3,p5,test=False)
0308                    self.t.toInterSection(self.m,self.a,p1,p5,test=False)
0309                    point.toInterSection(p,p2,self.t,p4,test=False)
0310                return True
0311            else:
0312                print self.__class__.__name__
0313                print "points are not distinct, conic undfined, returned False"
0314                return False
0315        else:
0316            print self.__class__.__name__
0317            print "points are not coPlanar, conic undefined, returned False"
0318            return False
0319
0320    def getPlane(self):
0321        u= cross3(self.p1,self.p2,self.p3).norm()
0322        d=u.dot(self.p1)
0323        return array([u.x,u.y,u.z,-d])
0324
0325    def getC(self):
0326        self.c1.toXY(self.p1)
0327        self.c2.toXY(self.p2)
0328        self.c3.toXY(self.p3)
0329        self.c4.toXY(self.p4)
0330        self.c5.toXY(self.p5)
0331        c1=self.c1
0332        c2=self.c2
0333        c3=self.c3
0334        c4=self.c4
0335        c5=self.c5
0336        A=array([
0337        [c1.x**2,c1.x*c1.y,c1.y**2,c1.x,c1.y,1],
0338        [c2.x**2,c2.x*c2.y,c2.y**2,c2.x,c2.y,1],
0339        [c3.x**2,c3.x*c3.y,c3.y**2,c3.x,c3.y,1],
0340        [c4.x**2,c4.x*c4.y,c4.y**2,c4.x,c4.y,1],
0341        [c5.x**2,c5.x*c5.y,c5.y**2,c5.x,c5.y,1],
0342        [0,0,0,0,0,0]])
0343        evalues, evectors =  eigenvectors(A)
0344        V = evectors[5].real
0345        b2=V[1]/2.
0346        d2=V[3]/2.
0347        e2=V[4]/2
0348        C=array([[V[0],b2,d2],[b2,V[2],e2],[d2,e2,V[5]]])
0349        return C
0350
0351
0352class ArrayIntersect(Real._PointArray):
0353    """
0354*array of points* of intersection of the given **2 arrays of lines**
0355    
0356    inherits
0357    
0358        `_PointArray`__
0359
0360__ class-base.abstracts._real._PointArray.html       
0361    
0362    """
0363    __doc_hints__=  {'factory':'PointArray',
0364                    'args':['line_array1,line_array2'],
0365                    'conditions':['linearrays are coplanar'],
0366                    'otherwise':'None'}
0367
0368    def __init__(self,lp1,lp2,**kws):
0369        self.lp1=lp1
0370        self.lp2=lp2
0371        self.t=Position3()
0372        self.extend=kws.get("extend",False)
0373        self.density=min(lp1.density,lp2.density)
0374        Real._PointArray.__init__(self,*[lp1,lp2],**kws)
0375        self.init()
0376
0377    def findSelf(self):
0378        if DO_TESTS:
0379            t = self.lp1.lines[0].p1.coPlanar(self.lp1.lines[0].p2,
0380                                     self.lp2.lines[1].p2,self.lp2.lines[1].p2)
0381        else:
0382            t = True
0383        if t:
0384            for point,line1,line2 in zip(self,self.lp1,self.lp2):
0385                point.toInterSection(line1.p1,line1.p2,line2.p1,line2.p2,test=False)
0386            return True
0387        else:
0388            print self.__class__.__name__
0389            print """line arrays are not coplanar, points of intersections 
0390                    undefined, returned False"""
0391            return False
0392
0393    def setext(self):
0394        for point,line in zip(self,self.lp1):
0395            line.get_extension(point)
0396            line._redraw()
0397        for point,line in zip(self,self.lp2):
0398            line.get_extension(point)
0399            line._redraw()
0400
0401
0402class CorrelationPoints(Real._PointArray):
0403    """
0404*array of point* as poles of the given **line array** with respect to 
0405the given **conic**
0406    
0407    inherits
0408    
0409        `_PointArray`__
0410
0411__ class-base.abstracts._real._PointArray.html       
0412    
0413    """
0414    __doc_hints__=  {'factory':'PointArray',
0415                    'args':['conic, linearray'],
0416                    'conditions':['line arrray and conic are coplanar'],
0417                    'otherwise':'Undefined'}
0418
0419    def __init__(self,conic,la,**kws):
0420        self.conic=conic
0421        self.line_array=la
0422        self.density=self.line_array.density
0423        Real._PointArray.__init__(self,*[conic,la],**kws)
0424        self.h1=Position3()
0425        self.h2=Position3()
0426        self.tpz=Position3()
0427        self.init()
0428
0429    def findSelf(self):
0430        if DO_TESTS:
0431            t = self.line_array.lines[0].p1.coPlanar(self.line_array.lines[0].p2,
0432                                                   self.conic.p1,self.conic.p2)
0433        else:
0434            t = True
0435        if t:
0436            equat=self.conic.getPlane()
0437            Ci=inverse(self.conic.getC())
0438            for point,line in zip(self,self.line_array):
0439                self.h1.toXY(line.p1)
0440                self.h2.toXY(line.p2)
0441                h=self.h1.cross(self.h2)
0442                tp = matrixmultiply(Ci,h)
0443                self.tpz.set(vector(tp[0]/tp[2],tp[1]/tp[2],0))
0444                point.fromXY(equat,self.tpz)
0445            return True
0446        else:
0447            print self.__class__.__name__
0448            print """line array and conic are not coplanar, correlation points 
0449                    undefined,returned False"""
0450            return False
0451
0452
0453class PlanePoints(Real._PointArray):
0454    """
0455*array of points* of intersection of the given **line array** with 
0456the given **plane**
0457    
0458    inherits
0459    
0460        `_PointArray`__
0461
0462__ class-base.abstracts._real._PointArray.html       
0463    
0464    """
0465
0466    __doc_hints__=  {'factory':'PointArray',
0467                    'args':['plane, linearray'],
0468                    'conditions':['line arrray not on plane'],
0469                    'otherwise':'Undefined'}
0470
0471    def __init__(self,plane,la,**kws):
0472        self.plane=plane
0473        self.line_array=la
0474        self.density=self.line_array.density
0475        Real._PointArray.__init__(self,*[plane,la],**kws)
0476        self.init()
0477
0478    def findSelf(self):
0479        if DO_TESTS:
0480            t = not (self.line_array.lines[0].p1.onPlane(self.plane)
0481                     and self.line_array.lines[0].p2.onPlane(self.plane))
0482        else:
0483           t = True
0484        if t:
0485            for point,line in zip(self,self.line_array):
0486                                  point.toPlaneIntersection(self.plane,line.p1,
0487                                                            line.p2)
0488            return True
0489        else:
0490            print self.__class__.__name__
0491            print """line array on plane, intersection points undefined,
0492                    returned False"""
0493            return False
0494
0495
0496def  PointArray(*args,**kws):
0497    """
0498'class factory' function returns instance of object derived from the  
0499_PointArray abstract class representing an array of points with a 
0500defined geoemtric relationship
0501    """
0502
0503    from pygeo.base.abstracts._element import method_get
0504    from pygeo.base.support.pygeoexceptions import Argument_Type_Error
0505
0506    __sigs__=[[Real._Line],[Real._LineArray,Real._Line],[Real._Circle],
0507             [vector,vector,vector,vector,vector],
0508             [Real._LineArray,Real._LineArray],[vector,vector,vector,vector],
0509             [Real._PointArray,vector,vector],[Conic,Real._LineArray],
0510             [Real._Plane,Real._LineArray]]
0511
0512    t,i = method_get(__sigs__,args)
0513
0514    if t is None:
0515        raise Argument_Type_Error(__sigs__,args)
0516    else:
0517        if i==0:
0518            return PointPencil(t[0],**kws)
0519        elif i==1:
0520            return CirclingPencil(t[0],t[1],**kws)
0521        elif i==2:
0522            return CirclePoints(t[0],**kws)
0523        elif i==3:
0524            return Conic(t[0],t[1],t[2],t[3],t[4],**kws)
0525        elif i==4:
0526            return ArrayIntersect(t[0],t[1],**kws)
0527        elif i==5:
0528            return GrowthMeasure(t[0],t[1],t[2],t[3],**kws)
0529        elif i==6:
0530            return Harmonics(t[0],t[1],t[2],**kws)
0531        elif i==7:
0532            return CorrelationPoints(t[0],t[1],**kws)
0533        elif i==8:
0534            return PlanePoints(t[0],t[1],**kws)
0535        else:
0536            raise Argument_Type_Error(__sigs__,args)