awips2/pythonPackages/scientific/Src/Scientific_vector.pyx
root e2ecdcfe33 Initial revision of AWIPS2 11.9.0-7p5
Former-commit-id: a02aeb236c [formerly 9f19e3f712] [formerly a02aeb236c [formerly 9f19e3f712] [formerly 06a8b51d6d [formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f]]]
Former-commit-id: 06a8b51d6d
Former-commit-id: 8e80217e59 [formerly 3360eb6c5f]
Former-commit-id: 377dcd10b9
2012-01-06 08:55:05 -06:00

241 lines
7 KiB
Cython
Executable file

# Implementation of Scientific.Geometry.Vector in Pyrex
#
# Written by Konrad Hinsen
# last revision: 2008-8-27
#
cdef extern from "math.h":
double sqrt(double x)
double acos(double x)
from Scientific import N
#
# For efficiency reasons (calling __init__ makes the creation of a vector
# rather expensive), most of the operations happen in class "vector", which
# is not meant to be used directly in application code. Objects of this
# class are initialized with zero values and then initialized explicitly
# by calling the method "set".
# Application code should use the derived class "Vector", which adds
# only the __init__ method.
#
cdef class vector:
cdef double xv, yv, zv
property is_vector:
def __get__(self):
return 1
property array:
def __get__(self):
return N.array([self.xv, self.yv, self.zv])
# __array_priority__ and __array_wrap__ are needed to permit
# multiplication with numpy scalar types.
property __array_priority__:
def __get__(self):
return 10.0
def __array_wrap__(self, array):
result = vector()
vector.set(result, array[0], array[1], array[2])
return result
def __copy__(self, memo = None):
return self
def __deepcopy__(self, memo = None):
return self
def __getstate__(self):
return [self.xv, self.yv, self.zv]
def __setstate__(self, state):
self.xv, self.yv, self.zv = state
def __reduce__(self):
return (Vector, (self.xv, self.yv, self.zv))
cdef void set(self, double x, double y, double z):
self.xv = x
self.yv = y
self.zv = z
def x(self):
"Returns the x coordinate."
return self.xv
def y(self):
"Returns the y coordinate."
return self.yv
def z(self):
"Returns the z coordinate."
return self.zv
def __repr__(self):
return 'Vector(%f,%f,%f)' % (self.xv, self.yv, self.zv)
def __str__(self):
return str([self.xv, self.yv, self.zv])
def __add__(vector self, vector other):
result = vector()
vector.set(result,
self.xv+other.xv, self.yv+other.yv, self.zv+other.zv)
return result
def __neg__(vector self):
result = vector()
vector.set(result, -self.xv, -self.yv, -self.zv)
return result
def __sub__(vector self, vector other):
result = vector()
vector.set(result,
self.xv-other.xv, self.yv-other.yv, self.zv-other.zv)
return result
def __mul__(x, y):
cdef vector v1, v2
cdef int rmul
from Scientific import Geometry
rmul = 0
if isinstance(y, vector):
if isinstance(x, vector):
v1 = x
v2 = y
return v1.xv*v2.xv+v1.yv*v2.yv+v1.zv*v2.zv
else:
x, y = y, x
rmul = 1
if Geometry.isTensor(y):
if rmul:
product = y.dot(Geometry.Tensor(x.array, 1))
else:
product = Geometry.Tensor(x.array, 1).dot(y)
if product.rank == 1:
result = vector()
vector.set(result, product.array[0],
product.array[1], product.array[2])
return result
else:
return product
elif hasattr(y, "_product_with_vector"):
return y._product_with_vector(self)
else:
v1 = x
result = vector()
vector.set(result, v1.xv*y, v1.yv*y, v1.zv*y)
return result
def __div__(vector self, double factor):
result = vector()
vector.set(result, self.xv/factor, self.yv/factor, self.zv/factor)
return result
def __richcmp__(vector self, other, int op):
if op != 2 and op != 3:
return NotImplemented
if isinstance(other, vector):
eq = self.xv == other.x() and self.yv == other.y() \
and self.zv == other.z()
else:
eq = False
if op == 2:
return eq
else:
return not eq
def __len__(self):
return 3
def __getitem__(self, int index):
if index == 0 or index == -3:
return self.xv
elif index == 1 or index == -2:
return self.yv
elif index == 2 or index == -1:
return self.zv
raise IndexError
def length(self):
"Returns the length (norm)."
return sqrt(self.xv*self.xv+self.yv*self.yv+self.zv*self.zv)
def normal(self):
"Returns a normalized copy."
cdef double len
len = sqrt(self.xv*self.xv+self.yv*self.yv+self.zv*self.zv)
if len == 0:
raise ZeroDivisionError, "Can't normalize a zero-length vector"
result = vector()
vector.set(result, self.xv/len, self.yv/len, self.zv/len)
return result
def cross(vector self, vector other):
"Returns the cross product with vector |other|."
result = vector()
vector.set(result, self.yv*other.zv-self.zv*other.yv,
self.zv*other.xv-self.xv*other.zv,
self.xv*other.yv-self.yv*other.xv)
return result
def angle(vector self, vector other):
"Returns the angle to vector |other|."
cdef double cosa
cosa = (self.xv*other.xv+self.yv*other.yv+self.zv*other.zv) / \
sqrt((self.xv*self.xv+self.yv*self.yv+self.zv*self.zv)*
(other.xv*other.xv+other.yv*other.yv+other.zv*other.zv))
if cosa > 1.:
cosa = 1.
if cosa < -1.:
cosa = -1.
return acos(cosa)
def asTensor(self):
"Returns an equivalent tensor object of rank 1."
from Scientific import Geometry
return Geometry.Tensor(self.array, 1)
def dyadicProduct(self, other):
"Returns the dyadic product with vector or tensor |other|."
from Scientific import Geometry
if isinstance(other, vector):
return Geometry.Tensor(self.array[:, N.NewAxis]
* other.array[N.NewAxis, :], 1)
elif Geometry.isTensor(other):
return Geometry.Tensor(self.array, 1)*other
else:
raise TypeError, "Dyadic product with non-vector"
cdef class Vector(vector):
property __safe_for_unpickling__:
def __get__(self):
return 1
def __init__(self, x=None, y=None, z=None):
if x is None:
pass # values are pre-initialized to zero
elif y is None and z is None:
self.xv, self.yv, self.zv = x
else:
self.xv = x
self.yv = y
self.zv = z
#
# For compatibility reasons, this routine works like its predecessor
# by testing the attribute is_vector. However, isinstance() works
# as well and is probably more efficient.
#
def isVector(x):
try:
return x.is_vector
except AttributeError:
return 0