Former-commit-id:06a8b51d6d
[formerly9f19e3f712
[formerly 64fa9254b946eae7e61bbc3f513b7c3696c4f54f]] Former-commit-id:9f19e3f712
Former-commit-id:a02aeb236c
241 lines
7 KiB
Cython
Executable file
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
|