//| //| ___ __ ______ __________ //| __ | / /_______ /______________(_)_ /_____ __ //| __ | / /_ _ \_ /_ __ \ ___/_ /_ __/_ / / / //| __ |/ / / __/ / / /_/ / /__ _ / / /_ _ /_/ / //| _____/ \___//_/ \____/\___/ /_/ \__/ _\__, / //| __/____/ //| Copyright (c) 2006 Kyle Furlong //| module velocity.math.Vector; private import std.math; private import velocity.tools.Boxer; private import velocity.tools.Common; /************************************************** A fast vector implementation Examples: --- alias Vector!(int,2) Point; Point origin = Point(0,0); alias Vector!(int,3) Vec; for(Vec t1 = Vec(1,1,0); t1 != Vec(4,4,3); t1++) { writefln("(%d,%d,%d)", t1[0], t1[1], t1[2]); } --- **************************************************/ struct Vector(T, int Dim = 4) { static this() { static if(isNumericType!(T)) {} else static if(isCharacterType!(T)) { pragma(msg, "velocity.math.Vector: Vector cannot use a field of characters."); static assert(false); } else static if(isBooleanType!(T)) { pragma(msg, "velocity.math.Vector: Vector cannot use a field of bits."); static assert(false); } else static if(isVoidType!(T)) { pragma(msg, "velocity.math.Vector: Vector cannot use a field of voids."); static assert(false); } else static if(isUserDefinedType!(T)) { pragma(msg, "velocity.math.Vector: Vector cannot use a field of user defined types."); static assert(false); } static if(Dim < 1) { pragma(msg, "velocity.math.Vector: Dimensions of less than one are not permissible."); static assert(false); } } private T[Dim] storage; public T Magnitude() { static if(!isImaginaryType!(T)) { static if(isComplexType!(T)) { return (*this) * ~(*this); } else { T sum = zero!(T); for(int i = 0; i < Dim; i++) { sum += storage[i] * storage[i]; } return cast(T)sqrt(cast(real)sum); } } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support the Maginitude attribute."); } } static Vector Zero() { Vector v; for(int i = 0; i < Dim; i++) { v[i] = zero!(T); } return v; } Vector ImaginaryPart() { static if(isImaginaryType!(T) || isComplexType!(T)) { Vector imaginarypart; for(int i = 0; i < Dim; i++) { imaginarypart[i] = (storage[i].im) * 1i; } return imaginarypart; } else { throw new VelocityException("velocity.math.Vector: Non-complex types do not have an imaginary part."); } } Vector RealPart() { static if(isComplexType!(T)) { Vector realpart; for(int i = 0; i < Dim; i++) { realpart[i] = storage[i].re; } return realpart; } else { throw new VelocityException("velocity.math.Vector: Non-complex types do not have a real part."); } } T[] opCast() { return storage; } Vector opNeg() { Vector v; for(int i = 0; i < Dim; i++) { v[i] = -storage[i]; } return v; } Vector opPos() { Vector v; for(int i = 0; i < Dim; i++) { v[i] = +storage[i]; } return v; } Vector opCom() { static if(isImaginaryType!(T) || isComplexType!(T)) { return (*this) - ((*this).ImaginaryPart * 2); } else { return *this; } } Vector opPostInc() { for(int i = 0; i < Dim; i++) { storage[i]++; } return *this; } Vector opPostDec() { for(int i = 0; i < Dim; i++) { storage[i]--; } return *this; } T opIndex(int index) { return storage[index]; } T opIndexAssign(T value, int index) { storage[index] = value; return value; } Vector opAdd(Vector a) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] + a[i]; } return ret; } Vector opAdd(T a) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] + a; } return ret; } Vector opAddAssign(Vector a) { for(int i = 0; i < Dim; i++) { storage[i] += a[i]; } return *this; } Vector opAddAssign(T a) { for(int i = 0; i < Dim; i++) { storage[i] += a; } return *this; } Vector opSub(Vector a) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] - a[i]; } return ret; } Vector opSub(T a) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] - a; } return ret; } Vector opSubAssign(Vector a) { for(int i = 0; i < Dim; i++) { storage[i] -= a[i]; } return *this; } Vector opSubAssign(T a) { for(int i = 0; i < Dim; i++) { storage[i] -= a; } return *this; } /// The * operator will perform the inner product when used with two vectors T opMul(Vector a) { static if(!isImaginaryType!(T)) { T ret = zero!(T); for(int i = 0; i < Dim; i++) { ret += (storage[i] * a[i]); } return ret; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support the dot product."); } } /// The * operator will perform the scalar product when used with a vector and a scalar Vector opMul(T a) { static if(!isImaginaryType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] * a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support scalar multiplication"); } } Vector opMulAssign(T a) { static if(!isImaginaryType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] *= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support scalar multiplication"); } } /// The catenation operator (~) is overloaded to mean the cross product of two vectors. Vector opCat(Vector a) { static if(!isImaginaryType!(T)) { Vector ret; static if(Dim == 3) { ret[0] = (storage[1]*a[2] - storage[2]*a[1]); ret[1] = (storage[0]*a[2] - storage[2]*a[0]); ret[2] = (storage[0]*a[1] - storage[1]*a[0]); } return ret; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support the cross product"); } } Vector opCatAssign(Vector a) { static if(!isImaginaryType!(T)) { T[Dim] ret; static if(Dim == 3) { ret[0] = (storage[1]*a[2] - storage[2]*a[1]); ret[1] = (storage[0]*a[2] - storage[2]*a[0]); ret[2] = (storage[0]*a[1] - storage[1]*a[0]); } for(int i = 0; i < Dim; i++) { storage[i] = ret[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support the cross product"); } } Vector opDiv(T a) { static if(!isImaginaryType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] / a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support scalar division"); } } Vector opDivAssign(T a) { static if(!isImaginaryType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] /= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support scalar division"); } } Vector opMod(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] % a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support modulus arithmetic."); } } Vector opMod(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] % a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support modulus arithmetic."); } } Vector opModAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] %= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support modulus arithmetic."); } } Vector opModAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] %= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support modulus arithmetic."); } } Vector opShl(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] << a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShl(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] << a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShlAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] <<= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShlAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] <<= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShr(Vector a) { Vector ret; static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { ret[i] = storage[i] >> a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShr(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] >> a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShrAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] >>= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opShrAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] >>= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opUShr(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] >>> a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opUShr(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] >>> a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opUShrAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] >>>= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opUShrAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] >>>= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opAnd(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] & a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opAnd(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] & a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opAndAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] &= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opAndAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] &= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opOr(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] | a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opOr(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] | a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opOrAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] |= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opOrAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] |= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opXor(Vector a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] ^ a[i]; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opXor(T a) { static if(isIntegralType!(T)) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = storage[i] ^ a; } return ret; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opXorAssign(Vector a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] ^= a[i]; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } Vector opXorAssign(T a) { static if(isIntegralType!(T)) { for(int i = 0; i < Dim; i++) { storage[i] ^= a; } return *this; } else { throw new VelocityException("velocity.math.Vector: Non-integral vectors do not support bitwise operations."); } } /// Comparing vectors will compare their magnitudes. This may change in later versions. int opCmp(Vector a) { static if(!isImaginaryType!(T)) { return cast(int)(this.Magnitude - a.Magnitude); } else { throw new VelocityException("velocity.math.Vector: Imaginary vectors do not support compare operations."); } } static Vector opCall(...) { Vector v; Box[] arguments = boxArray(_arguments, _argptr); for (int i = 0; i < Dim; i++) { v[i] = unbox!(T)(arguments[i]); } return v; } static Vector opCall(T[] arr) { Vector ret; for(int i = 0; i < Dim; i++) { ret[i] = arr[i]; } return ret; } }