0001"""
0002base class for points of the complex plane
0003Much from the PyPy complex number implementation - but now mutable
0004"""
0005from __future__ import division
0006
0007import string
0008from pygeo.base.analytics.pygeomath import arctan2,absolute,array
0009from pygeo.base.support.pygeoopts import EPS
0010
0011
0012class CPosition(object):
0013 """The pypy complex object code, made mutable by removing the properties declarations
0014 for real and imag, and with additional attributes and methods used by Pygeo"""
0015
0016 PREC_REPR = 17
0017 PREC_STR = 12
0018 __slots__ = ['real', 'imag']
0019
0020
0021 def __new__(typ, *args,**kws):
0022
0023 if args:
0024 if isinstance(args[0],CPosition):
0025 real=args[0].real
0026 imag=args[0].imag
0027 elif isinstance(args[0],complex):
0028 real=args[0].real
0029 imag=args[0].imag
0030 elif isinstance(args[0],(float,int)):
0031 real=args[0]
0032 try:
0033 if isinstance(args[1],(float,int)):
0034 imag=args[1]
0035 except IndexError:
0036 imag=0
0037 else:
0038 real=0
0039 imag=0
0040 else:
0041 real=0
0042 imag=0
0043 ret = object.__new__(typ)
0044 ret._init(real, imag)
0045 return ret
0046
0047 def __getnewargs__(self):
0048 return (CPosition(self.real, self.imag),)
0049
0050 def __reduce__(self):
0051 return (self.__class__, (self.real, self.imag),
0052 getattr(self, '__dict__', None))
0053
0054 def _init(self, re, im):
0055 real_slot.__set__(self, re)
0056 imag_slot.__set__(self, im)
0057
0058 def __getitem__(self, index):
0059 return self.vector[index]
0060
0061 def get_name(self):
0062 return self.__class__.__name__
0063
0064 def set_x(self,value):
0065 self.real=value
0066
0067 def set_y(self,value):
0068 self.imag=value
0069
0070 def get_x(self):
0071 return self.real
0072
0073 def get_y(self):
0074 return self.imag
0075
0076 def get_z(self):
0077 return 0.
0078
0079 def get_pos(self):
0080 return self.real,self.imag
0081
0082 pos= property(get_pos,None,None,"The 3 (z=0) coordinate drawing position vector")
0083
0084 x = property(get_x,set_x,None,"The real coordinate ")
0085 y = property(get_y,set_y,None,"The imag coordinate ")
0086 z = property(get_z,None,None,"The complex plane z position")
0087
0088 def __description(self, precision):
0089 if self.real != 0.:
0090 return self.__class__.__name__ + "(%.*g%+.*gj)"%(precision, self.real, precision, self.imag)
0091 else:
0092 return "%.*gj"%(precision, self.imag)
0093
0094 def __repr__(self):
0095 return self.__description(self.PREC_REPR)
0096
0097 def __str__(self):
0098 return self.__description(self.PREC_STR)
0099
0100 def __hash__(self):
0101 hashreal = hash(self.real)
0102 hashimag = hash(self.imag)
0103
0104
0105
0106
0107
0108 return hashreal + 1000003 * hashimag
0109
0110 def __add__(self, other):
0111 result = self.__coerce__(other)
0112 if result is NotImplemented:
0113 return result
0114 self, other = result
0115 real = self.real + other.real
0116 imag = self.imag + other.imag
0117 return CPosition(real, imag)
0118
0119 __radd__ = __add__
0120
0121 def __sub__(self, other):
0122 result = self.__coerce__(other)
0123 if result is NotImplemented:
0124 return result
0125 self, other = result
0126 real = self.real - other.real
0127 imag = self.imag - other.imag
0128 return CPosition(real, imag)
0129
0130 def __rsub__(self, other):
0131 result = self.__coerce__(other)
0132 if result is NotImplemented:
0133 return result
0134 self, other = result
0135 return other.__sub__(self)
0136
0137 def __mul__(self, other):
0138 result = self.__coerce__(other)
0139 if result is NotImplemented:
0140 return result
0141 self, other = result
0142 real = self.real*other.real - self.imag*other.imag
0143 imag = self.real*other.imag + self.imag*other.real
0144 return CPosition(real, imag)
0145
0146 __rmul__ = __mul__
0147
0148 def __div__(self, other):
0149 result = self.__coerce__(other)
0150 if result is NotImplemented:
0151 return result
0152 self, other = result
0153 if absolute(other.real) >= absolute(other.imag):
0154
0155 try:
0156 ratio = other.imag / other.real
0157 except ZeroDivisionError:
0158 raise ZeroDivisionError, "Complex division"
0159 denom = other.real + other.imag * ratio
0160 real = (self.real + self.imag * ratio) / denom
0161 imag = (self.imag - self.real * ratio) / denom
0162 else:
0163
0164 assert other.imag != 0.0
0165
0166 ratio = other.real / other.imag
0167 denom = other.real * ratio + other.imag
0168 real = (self.real * ratio + self.imag) / denom
0169 imag = (self.imag * ratio - self.real) / denom
0170 return CPosition(real, imag)
0171
0172 def __rdiv__(self, other):
0173 result = self.__coerce__(other)
0174 if result is NotImplemented:
0175 return result
0176 self, other = result
0177 return other.__div__(self)
0178
0179 def __floordiv__(self, other):
0180 result = self.__divmod__(other)
0181 if result is NotImplemented:
0182 return result
0183 div, mod = result
0184 return div
0185
0186 def __rfloordiv__(self, other):
0187 result = self.__coerce__(other)
0188 if result is NotImplemented:
0189 return result
0190 self, other = result
0191 return other.__floordiv__(self)
0192
0193 __truediv__ = __div__
0194
0195 __rtruediv__ = __rdiv__
0196
0197 def __mod__(self, other):
0198 result = self.__divmod__(other)
0199 if result is NotImplemented:
0200 return result
0201 div, mod = result
0202 return mod
0203
0204 def __rmod__(self, other):
0205 result = self.__coerce__(other)
0206 if result is NotImplemented:
0207 return result
0208 self, other = result
0209 return other.__mod__(self)
0210
0211 def __divmod__(self, other):
0212 result = self.__coerce__(other)
0213 if result is NotImplemented:
0214 return result
0215 self, other = result
0216 import warnings, math
0217 warnings.warn("complex divmod(), // and % are deprecated", DeprecationWarning)
0218 try:
0219 div = self/other
0220 except ZeroDivisionError:
0221 raise ZeroDivisionError, "Complex remainder"
0222 div = CPosition(math.floor(div.real), 0.0)
0223 mod = self - div*other
0224 return div, mod
0225
0226 def __rdivmod__(self, other):
0227 result = self.__coerce__(other)
0228 if result is NotImplemented:
0229 return result
0230 self, other = result
0231 return other.__divmod__(self)
0232
0233 def __pow__(self, other, mod=None):
0234 if mod is not None:
0235 raise ValueError("Complex modulo")
0236 result = self.__coerce__(other)
0237 if result is NotImplemented:
0238 return result
0239 a, b = result
0240 import math
0241 if b.real == 0. and b.imag == 0.:
0242 real = 1.
0243 imag = 0.
0244 elif a.real == 0. and a.imag == 0.:
0245 if b.imag != 0. or b.real < 0.:
0246 raise ZeroDivisionError, "0.0 to a negative or Complex power"
0247 real = 0.
0248 imag = 0.
0249 else:
0250 vabs = math.hypot(a.real,a.imag)
0251 len = math.pow(vabs,b.real)
0252 at = math.atan2(a.imag, a.real)
0253 phase = at*b.real
0254 if b.imag != 0.0:
0255 len /= math.exp(at*b.imag)
0256 phase += b.imag*math.log(vabs)
0257 real = len*math.cos(phase)
0258 imag = len*math.sin(phase)
0259 result = CPosition(real, imag)
0260 return result
0261
0262 def __rpow__(self, other, mod=None):
0263 result = self.__coerce__(other)
0264 if result is NotImplemented:
0265 return result
0266 self, other = result
0267 return other.__pow__(self, mod)
0268
0269 def __neg__(self):
0270 return CPosition(-self.real, -self.imag)
0271
0272 def __pos__(self):
0273 return CPosition(self.real, self.imag)
0274
0275 def __abs__(self):
0276 import math
0277 result = math.hypot(self.real, self.imag)
0278 return float(result)
0279
0280 def __nonzero__(self):
0281 return self.real != 0.0 or self.imag != 0.0
0282
0283 def __coerce__(self, other):
0284 if isinstance(other, complex):
0285 return self, CPosition(other)
0286 if isinstance(other, (int, long, float)):
0287 return self, CPosition(other)
0288 if isinstance(other,CPosition):
0289 return self,other
0290 return NotImplemented
0291
0292 def conjugate(self):
0293 return CPosition(self.real, -self.imag)
0294
0295 def __eq__(self, other):
0296 result = self.__coerce__(other)
0297 if result is NotImplemented:
0298 return id(self) == id(other)
0299 self, other = result
0300 return ((absolute(self.real-other.real)) < EPS
0301 and absolute((self.imag-other.imag)) < EPS)
0302
0303 def __ne__(self, other):
0304 result = self.__coerce__(other)
0305 if result is NotImplemented:
0306 return result
0307 self, other = result
0308 return ((self.real-other.real) >= EPS
0309 or (self.imag-other.imag) >= EPS)
0310
0311
0312 def __lt__(self, other):
0313 result = self.__coerce__(other)
0314 if result is NotImplemented:
0315 return result
0316 raise TypeError, "cannot compare Complex numbers using <, <=, >, >="
0317
0318 __le__ = __gt__ = __ge__ = __lt__
0319
0320 def __int__(self):
0321 raise TypeError, "can't convert Complex to int; use e.g. int(absolute(z))"
0322
0323 def __long__(self):
0324 raise TypeError, "can't convert Complex to long; use e.g. long(absolute(z))"
0325
0326 def __float__(self):
0327 raise TypeError, "can't convert Complex to float; use e.g. float(absolute(z))"
0328
0329
0330
0331
0332 def arg(self):
0333 return arctan2(self.imag,self.real)
0334
0335 def mod2(self):
0336 return self.real**2+self.imag**2
0337
0338 def mod(self):
0339 return absolute(self)
0340
0341 def distance(self,other):
0342 import math
0343 real=self.real-other.real
0344 imag=self.imag-other.imag
0345 result = math.hypot(real, imag)
0346 return float(result)
0347
0348 def distanceSquared(self,other):
0349 return self.distance(other)**2
0350
0351 def homogenous(self):
0352 return array([CPosition(self.real,self.imag),CPosition(1,0)])
0353
0354 def set(self,other):
0355 CPosition.real.__set__(self, other.real)
0356 CPosition.imag.__set__(self, other.imag)
0357
0358
0359 def toComplex(self):
0360 return complex(self.real,self.imag)
0361
0362real_slot = CPosition.real
0363
0364imag_slot = CPosition.imag