0001"""
0002**line** in space representing breathless length
0003"""
0004
0005__Def__ = ['Line']
0006
0007__Classes__ = ['LineFromPoints', 'PlanePerp', 'PlanesLine', 'ParaLine',
0008 'Transversal','NearLine', 'ConicPolar','LinePerp',
0009 'CirclePolar']
0010
0011__all__= __Classes__ + __Def__
0012
0013__doc_hints__={'m_type':'factory'}
0014
0015import pygeo.base.abstracts._real as Real
0016
0017from pygeo.base.analytics._position3 import Position3
0018from pygeo.base.support.pygeoconstants import *
0019from pygeo.base.analytics.pygeomath import cross3, vector, solve, array, determinant, matrixmultiply, quadratic, absolute, sqrt, transpose, AlgebraError
0022from pygeo.base.abstracts._element import Element
0023from pygeo.base.support.pygeoopts import DO_TESTS, EPS
0024
0025
0026class LineFromPoints(Real._Line):
0027 """
0028*line* connecting the **2 given points**
0029
0030 inherits
0031
0032 `_Line`__
0033
0034__ class-base.abstracts._real._Line.html
0035
0036 """
0037 __doc_hints__= {'factory':'Line',
0038 'args':['point1,point2']}
0039
0040 def __init__(self,p1,p2,**kws):
0041 Real._Line.__init__(self,*[p1,p2],**kws)
0042 self.p1=p1
0043 self.p2=p2
0044 self.init()
0045
0046 def __repr__(self):
0047 return self.__class__.__name__ + "(" + str(self.p1) +"," + str(self.p2) + ")"
0049
0050 def findSelf(self):
0051 if DO_TESTS:
0052 if self.p1 == self.p2:
0053 print self.__class__.__name__
0054 print """points are not distinct, no line defined,
0055 returned False"""
0056 return False
0057 return True
0058
0059
0060class PlanePerp(Real._Line):
0061 """
0062*line* perpendicular to the given **plane** and through the given **point**
0063
0064 inherits
0065
0066 `_Line`__
0067
0068__ class-base.abstracts._real._Line.html
0069
0070 """
0071 __doc_hints__= {'factory':'Line',
0072 'args':['plane,point'],
0073 'conditions':['point not on plane'],
0074 'otherwise':'None'}
0075
0076 def __init__(self,plane,p1,**kws):
0077 self.plane=plane
0078 self.drawlen=kws.get("drawlen",20)
0079 Real._Line.__init__(self,*[plane,p1],**kws)
0080 self.p1=p1
0081 self.deps=[self.p2]
0082 self.init()
0083
0084 def findSelf(self):
0085 t=self.p1.onPlane(self.plane)
0086 if t:
0087 self.p2.set(self.plane._u*self.drawlen+self.p1)
0088 else:
0089 self.p2.set(self.p1)
0090 self.p2.toPlane(self.plane)
0091 return True
0092
0093class LinePerp(Real._Line):
0094 """
0095*line* through **2nd given point** and perpendicular to the line through
0096**1st and 2nd given points**, on the plane of 3 given points
0097
0098 inherits
0099
0100 `_Line`__
0101
0102__ class-base.abstracts._real._Line.html
0103
0104 """
0105 __doc_hints__= {'factory':'Line',
0106 'args':['point1,point2,point3'],
0107 'conditions':['points unique'],
0108 'otherwise':'None'}
0109
0110 def __init__(self,p1,p2,p3,**kws):
0111 self.n1 = p1
0112 self.drawlen=kws.get("drawlen",20)
0113 self.n3 = p3
0114 self.n2=p2
0115 self.u1=Position3()
0116 self.u2=Position3()
0117 self.n=Position3()
0118 Real._Line.__init__(self,*[p1,p2,p3],**kws)
0119 self.deps=[self.p1,self.p2]
0120 self.init()
0121
0122 def findSelf(self):
0123 n1=self.n1
0124 n2=self.n2
0125 n3=self.n3
0126 u1=self.u1
0127 u2=self.u2
0128 drawlen=self.drawlen/2.
0129 u1.set((n2-n1).norm())
0130 d1 = u1.dot(n2)
0131 u2.set(cross3(n1,n2,n3).norm())
0132 d2=u2.dot(n2)
0133 direction = u2.cross(u1).norm()
0134 self.n.set(vector(solve(
0135 array([u2,u1,direction]),
0136 array([d2,d1,0.]))))
0137 self.p1.set(direction*drawlen+self.n)
0138 self.p2.set(direction*-drawlen+self.n)
0139 return True
0140
0141class PlanesLine(Real._Line):
0142 """
0143*line* determined by the intersection of the **2 given planes**
0144
0145 inherits
0146
0147 `_Line`__
0148
0149__ class-base.abstracts._real._Line.html
0150
0151 """
0152 __doc_hints__= {'factory':'Line',
0153 'args':['plane1,plane2'],
0154 'conditions':['planes not parallel'],
0155 'otherwise':'None'}
0156
0157 __opts__ = Real._Line.__opts__[:]+["drawlen"]
0158
0159 def __init__(self,plane1,plane2,**kws):
0160 self.plane1=plane1
0161 self.plane2=plane2
0162 self.drawlen=kws.get("drawlen",20)
0163 Real._Line.__init__(self,*[plane1,plane2],**kws)
0164 self.deps=[self.p1,self.p2]
0165 self.init()
0166
0167 def getDirection(self):
0168 return self.plane1._u.cross(self.plane2._u).norm()
0169
0170 def getNormal(self):
0171 plane1=self.plane1
0172 plane2=self.plane2
0173 return vector(solve(
0174 array([plane1._u,plane2._u,self.getDirection()]),
0175 array([plane1._d,plane2._d,0.])))
0176
0177 def parameters(self):
0178 plane1=self.plane1
0179 plane2=self.plane2
0180 direction = self.getDirection()
0181 try:
0182 normal = vector(solve(
0183 array([plane1._u,plane2._u,direction]),
0184 array([plane1._d,plane2._d,0.])))
0185 except AlgebraError:
0186 print self.__class__.__name__
0187 print "planes parallel, not intersection found"
0188 return None,None
0189 return normal,direction
0190
0191 def findSelf(self):
0192 normal,direction=self.parameters()
0193 if normal:
0194 drawlen=self.drawlen/2.
0195 self.p1.set(direction*drawlen+normal)
0196 self.p2.set(direction*-drawlen+normal)
0197 return True
0198 else:
0199 print self.__class__.__name__
0200 print " planes parallel, returned False"
0201 return False
0202
0203
0204class ParaLine(Real._Line):
0205 """
0206*line* parallel to the given **line**, through the given **point**,
0207on the plane of the point and the line.
0208
0209 inherits
0210
0211 `_Line`__
0212
0213__ class-base.abstracts._real._Line.html
0214
0215 """
0216 __doc_hints__= {'factory':'Line',
0217 'args':['point,line'],
0218 'conditions':['point not on line'],
0219 'otherwise':'None'}
0220
0221 def __init__(self,line,point,**kws):
0222 self.line=line
0223 self.point=point
0224 Real._Line.__init__(self,*[line,point],**kws)
0225 self.drawlen=kws.get("drawlen",20)
0226 self.deps=[self.p1,self.p2]
0227 self.init()
0228
0229 def parameters(self):
0230 direction=self.line.getDirection()
0231 normal = self.point - self.point.dot(direction)*direction
0232 return normal, direction
0233
0234 def findSelf(self):
0235 normal,direction=self.parameters()
0236 drawlen=self.drawlen/2.
0237 self.p1.set(direction*drawlen+normal)
0238 self.p2.set(direction*-drawlen+normal)
0239 return True
0240
0241class NearLine(Real._Line):
0242 """
0243*line* connecting the nearest points of the **2 given lines**
0244
0245 inherits
0246
0247 `_Line`__
0248
0249__ class-base.abstracts._real._Line.html
0250
0251 """
0252
0253 __doc_hints__= {'factory':'Line',
0254 'args':['line1,line2'],
0255 'conditions':['lines are not coincident',
0256 'lines do not intersect'],
0257 'otherwise':'None; None'}
0258
0259 def __init__(self,line1,line2,**kws):
0260 self.line1=line1
0261 self.line2=line2
0262 Real._Line.__init__(self,*[line1,line2],**kws)
0263 self.lines=[self.line1,self.line2]
0264 self.drawlen=kws.get("drawlen",20)
0265 self.deps=[self.p1,self.p2]
0266 self.extend=kws.get("extend",False)
0267 self.init()
0268
0269 def findSelf(self):
0270 n1,d1=self.line1.parameters()
0271 n2,d2=self.line2.parameters()
0272 c=d1.cross(d2)
0273 o=n2-n1
0274 try:
0275 f1=determinant(array((o,d2,c)))/c.mag2
0276 f2=determinant(array((o,d1,c)))/c.mag2
0277 self.p1.set(d1*f1+n1)
0278 self.p2.set(d2*f2+n2)
0279 if self.p1 == self.p2:
0280 print self.__class__.__name__
0281 print "Lines intersect, Near line of zero length"
0282 return False
0283 except ZeroDivisionError:
0284 print self.__class__.__name__
0285 print "lines are parallel, near line undefined, returned False"
0286 return False
0287 return True
0288
0289 def setext(self):
0290 if self.Not_null:
0291 if self.show:
0292 if (self.line1.get_extension(self.p1) or
0293 self.line1.get_extension(self.p2)):
0294 self.line1._redraw()
0295 if (self.line2.get_extension(self.p1) or
0296 self.line2.get_extension(self.p2)):
0297 self.line2._redraw()
0298
0299
0300class Transversal(Real._Line):
0301 """
0302*line* through the given **point** and intersecting the **2 given lines**
0303
0304 inherits
0305
0306 `_Line`__
0307
0308__ class-base.abstracts._real._Line.html
0309
0310 """
0311 __doc_hints__= {'factory':'Line',
0312 'args':['line1,line2,point']}
0313
0314 def __init__(self,line1,line2,point,**kws):
0315 self.line1=line1
0316 self.line2=line2
0317 self.point=point
0318 Real._Line.__init__(self,*[line1,line2,point],**kws)
0319 self.deps=[self.p1,self.p2]
0320 self.pointsize=kws.get('pointsize',5)
0321 self.extend=kws.get("extend",False)
0322 self.lines=[self.line1,self.line2]
0323 self.ip1=Position3()
0324 self.ip2=Position3()
0325 self.init()
0326
0327 def findSelf(self):
0328 ip1=self.ip1
0329 ip2=self.ip2
0330 line1=self.line1
0331 line2=self.line2
0332 point=self.point
0333 u1= cross3(line1.p1,line1.p2,point)
0334 d1=u1.dot(line1.p1)
0335 u2= cross3(line2.p1,line2.p2,point)
0336 d2=u2.dot(line2.p1)
0337 dir=u1.cross(u2)
0338 try:
0339 ip1.set(vector(solve(
0340 array([u1,u2,dir]),
0341 array([d1,d2,0.]))))
0342 except AlgebraError:
0343 print self.__class__.__name__
0344 if u1 == u2:
0345 print """lines conincident, transversal undefined,
0346 returned False"""
0347 else:
0348 print """point is on a given line, transversal undefined,
0349 returned False"""
0350 return False
0351
0352 ip2.set(dir + ip1)
0353 self.p1.toInterSection(ip1,ip2,line1.p1,line1.p2)
0354 self.p2.toInterSection(ip1,ip2,line2.p1,line2.p2)
0355 return True
0356
0357 def setext(self):
0358 self.get_extension(self.point)
0359 for line in self.lines:
0360 if self.Not_null:
0361 if self.show:
0362 if line.show:
0363 line.get_extension(self.p1)
0364
0365
0366class CirclePolar(Real._Line):
0367 """
0368*line* polar to the given **point** with the respect to the given **circle**.
0369
0370 inherits
0371
0372 `_Line`__
0373
0374__ class-base.abstracts._real._Line.html
0375
0376 """
0377 __doc_hints__= {'factory':'Line',
0378 'args':['circle,point,<chord=(boolean)>'],
0379 'conditions':['point and circle are coplanar',
0380 'if chord = True,point exterior to circle'],
0381 'otherwise':'None'}
0382
0383 __opts__= Real._Line.__opts__[:] + ["chord"]
0384
0385 def __init__(self,circle,epoint,**kws):
0386 self.circle=circle
0387 self.epoint=epoint
0388 Real._Line.__init__(self,*[circle,epoint],**kws)
0389 self.chord=kws.get('chord',True)
0390 self.drawlen=kws.get("drawlen",20)
0391 self.deps=[self.p1,self.p2]
0392 self.u=Position3()
0393 self.n=Position3()
0394 self.tp=Position3()
0395 self.init()
0396
0397 def findSelf(self):
0398 circle=self.circle
0399 point=self.epoint
0400 if DO_TESTS:
0401 t=point.onPlane(circle)
0402 else:
0403 t=True
0404 if t:
0405 drawlen=self.drawlen/2.
0406 self.p2.toInvertPoint(circle,self.epoint)
0407 self.u.set((self.p2-self.epoint).norm())
0408 d = self.u.dot(self.p2)
0409 direction = circle._u.cross(self.u).norm()
0410 try:
0411 self.n.set(vector(solve(
0412 array([circle._u,self.u,direction]),
0413 array([circle._d,d,0.]))))
0414 except AlgebraError:
0415 print self.__class__.__name__
0416 print "epoint at center, polar at infinity, returned False"
0417 return False
0418 self.p1.set(direction*drawlen+self.n)
0419 self.p2.set(direction*-drawlen+self.n)
0420 if self.chord:
0421 self.tp.set(self.circle._center)
0422 self.tp.toLine(self.p1,self.p2)
0423 dist=self.tp.distanceSquared(circle._center)
0424 if sqrt(dist) > circle._radius:
0425 print self.__class__.__name__
0426 print """no real point of intersection for circle and
0427 line returned False"""
0428 return False
0429 if not dist < EPS:
0430 rad2=circle._radiusSquared
0431 factor=sqrt(rad2-dist)/self.tp.distance(self.p1)
0432 self.p1.set((self.p1-self.tp)*factor+self.tp)
0433 self.p2.set(self.tp*2-self.p1)
0434 else:
0435
0436 self.p1.set(direction*circle._radius+self.tp)
0437 self.p2.set(direction*-circle._radius+self.tp)
0438 return True
0439 else:
0440 print self.__class__.__name__
0441 print """circle and point are not coplanar, no polar defined,
0442 returned False"""
0443 return False
0444
0445class ConicPolar(Real._Line):
0446 """
0447*line* polar to the given **point** with respect to the given **conic**
0448
0449 inherits
0450
0451 `_Line`__
0452
0453__ class-base.abstracts._real._Line.html
0454
0455 """
0456
0457 __doc_hints__= {'factory':'Line',
0458 'args':['conic,point,<chord=(boolean)>'],
0459 'conditions':['point and conic are coplanar',
0460 'if chord = True,point exterior to conic'],
0461 'otherwise':'None;None'}
0462
0463 __opts__= Element.__opts__[:] + ["chord"]
0464
0465 def __init__(self,conic,point,**kws):
0466 self.conic=conic
0467 self.point=point
0468 Real._Line.__init__(self,*[conic,point],**kws)
0469 self.deps=[self.p1,self.p2]
0470 self.chord=kws.get('chord',True)
0471 if self.chord:
0472 self.seg=True
0473 self.tp=Position3()
0474 self.init()
0475
0476 def findSelf(self):
0477 if DO_TESTS:
0478 t = self.point.coPlanar(self.conic.p1,self.conic.p2,self.conic.p3)
0479 else:
0480 t = True
0481 if t:
0482 tp=self.tp
0483 equat=self.conic.getPlane()
0484 tp.toXY(self.point)
0485 C=self.conic.getC()
0486 L=matrixmultiply(self.tp,C)
0487 if absolute(
0488 matrixmultiply(L,transpose(tp))) < EPS:
0489 try:
0490 L1=array([0,-L[2]/L[1],1])
0491 except ZeroDivisionError:
0492 print self.__class__.__name__
0493 print "ZDE"
0494 L1=array([-L[2]/L[0],0,1])
0495 return False
0496 self.p1.set(self.point)
0497 self.p2.fromXY(equat,L1)
0498 else:
0499 L= matrixmultiply(C*2,tp)
0500 tp1=array([0.,-L[2]/L[1],1.])
0501 tp2=array([-L[2]/L[0],0.,1.])
0502 cx = matrixmultiply(matrixmultiply(C,tp1),transpose(tp1))
0503 ax = matrixmultiply(matrixmultiply(C,tp2),transpose(tp2))
0504 bx =2*matrixmultiply(matrixmultiply(C,tp2),transpose(tp1))
0505 h= quadratic(ax,bx,cx)
0506 if h[0]:
0507 x1=tp1+tp2*h[0]
0508 x2=tp1+tp2*h[1]
0509 else:
0510 if self.chord:
0511 x1=tp1+tp2
0512 x2=tp1+tp2
0513 print self.__class__.__name__
0514 print """point interior to conic, no chord defined,
0515 returning False"""
0516 return False
0517 else:
0518 x1=tp1
0519 x2=tp2
0520 x1z=array([x1[0]/x1[2],x1[1]/x1[2],0])
0521 x2z=array([x2[0]/x2[2],x2[1]/x2[2],0])
0522 self.p1.fromXY(equat,x1z)
0523 self.p2.fromXY(equat,x2z)
0524 return True
0525 else:
0526 print self.__class__.__name__
0527 print """point and conic not coplanar, polar undefined,
0528 returned False"""
0529 return False
0530
0531
0532def Line(*args,**kws):
0533 """
0534'class factory' function returns instance of object derived from the _Line
0535abstract class, representing breathless length in space
0536 """
0537
0538 from pygeo.base.abstracts._element import method_get
0539 from pygeo.base.support.pygeoexceptions import Argument_Type_Error
0540 from pygeo.base.geometry_real.pointarrays import Conic
0541
0542 __sigs__=[ [vector,vector],[Real._Plane,vector],
0543 [Real._Plane,Real._Plane],[Real._Line,vector],
0544 [Real._Line,Real._Line],[Real._Line,Real._Line,vector],
0545 [Conic,vector],[vector,vector,vector],[Real._Circle,vector]]
0546
0547 t,i = method_get(__sigs__,args)
0548
0549 if t is None:
0550 raise Argument_Type_Error(__sigs__,args)
0551 else:
0552 if i==0:
0553 return LineFromPoints(t[0],t[1],**kws)
0554 elif i==1:
0555 return PlanePerp(t[0],t[1],**kws)
0556 elif i==2:
0557 return PlanesLine(t[0],t[1],**kws)
0558 elif i==3:
0559 return ParaLine(t[0],t[1],**kws)
0560 elif i==4:
0561 return NearLine(t[0],t[1],**kws)
0562 elif i==5:
0563 return Transversal(t[0],t[1],t[2],**kws)
0564 elif i==6:
0565 return ConicPolar(t[0],t[1],**kws)
0566 elif i==7:
0567 return LinePerp(t[0],t[1],t[2],**kws)
0568 elif i==8:
0569 return CirclePolar(t[0],t[1],**kws)
0570 else:
0571 raise Argument_Type_Error(__sigs__,args)