Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- module ru.nsk.sampler.math.vector;
- //math stuff (sqrt, cos, sin)
- import std.math;
- //'zip', 'repeat', 'take' lie here
- import std.range;
- //'map' and 'reduce' lie here
- import std.algorithm;
- //to make char upper case + 'format' - a sprintf-like function
- import std.string;
- public static immutable X = 0;
- public static immutable Y = 1;
- public static immutable Z = 2;
- public static immutable W = 3;
- public struct Vector4
- {
- public
- {
- static immutable DIMENSION = 4;
- this(Range)(Range coords)
- {
- assert(DIMENSION >= coords.length);
- auto i = 0u;
- foreach (immutable coord; coords)
- {
- this.coords[i] = coord;
- i++;
- }
- }
- this(T...)(T coords) pure if (T.length <= DIMENSION)
- {
- auto i = 0u;
- foreach (immutable coord; coords)
- {
- this.coords[i] = coord;
- i++;
- }
- }
- @property float[] get() pure nothrow
- {
- return coords;
- }
- @property const (float[]) get() const pure nothrow
- {
- return coords;
- }
- alias get this;
- mixin(acessor('x'));
- mixin(acessor('y'));
- mixin(acessor('z'));
- mixin(acessor('w'));
- auto opUnary(const string op)() const pure if ("-" == op || "+" == op)
- {
- return Vector4 ( coords[0..$-1].map!(op ~ "a") );
- }
- auto opBinary(const string op)(in Vector4 right) const pure if ("-" == op || "+" == op)
- {
- return Vector4 ( zip(this.coords[0..$-1], right.coords[0..$-1]).map!("a[0]" ~ op ~ "a[1]") );
- }
- auto opBinary(const string op)(in float scalar) const pure if ("/" == op || "*" == op)
- {
- return Vector4 ( this.coords[0..$-1].map!( element => mixin(format("element %s scalar", op)) ));
- }
- @property auto opDispatch(const string swizzling)() const pure
- {
- immutable expression = "coords".repeat().take(swizzling.length)
- .zip(swizzling).map!( a => format("%s[%c]", a[0], a[1].toUpper()) ).reduce!((a,b) => a ~ "," ~ b);
- mixin( "return Vector4 (" ~ expression ~ ");" );
- }
- auto opEquals(in Vector4 other) const pure nothrow
- {
- return this.coords == other.coords;
- }
- } // public
- private
- {
- static string acessor(in char name) pure
- {
- immutable setter = format("@property ref float %c() pure nothrow { return coords[%c]; }", name, name.toUpper);
- immutable getter = format("@property float %c() const pure nothrow { return coords[%c]; }", name, name.toUpper);
- return setter ~ getter;
- }
- float[DIMENSION] coords = [0.0f, 0.0f, 0.0f, 1.0f,];
- } // private
- };
- private float dot(in float[] left, in float[] right) pure
- {
- return zip(left, right).map!(a => a[0] * a[1]).reduce!((a, b) => a + b);
- }
- public
- {
- float dot3(T)(in T left, in T right) pure
- {
- return dot(left.coords[0..$-1], right.coords[0..$-1]);
- }
- float dot4(T)(in T left, in T right) pure
- {
- return dot(left.coords[0..$], right.coords[0..$]);
- }
- float norm(T)(in T vector) pure
- {
- return sqrt(dot3(vector, vector));
- }
- T identity(T)(in T vector) pure
- {
- return vector / norm(vector);
- }
- T mul(T)(in T left, in T right) pure
- {
- return Vector4( zip(left.get(), right.get()).map!(a => a[0] * a[1]) );
- }
- auto cross(in Vector4 l, in Vector4 r) pure
- {
- return mul( l.yzx, r.zxy ) - mul( l.zxy, r.yzx );
- }
- auto rotateAroundY(in Vector4 v, in float angleDegrees) pure nothrow
- {
- import ru.nsk.sampler.math.utils:radians;
- immutable angleRadians = radians(angleDegrees);
- immutable c = cos(angleRadians);
- immutable s = sin(angleRadians);
- immutable x = v.x * c - v.z * s;
- immutable y = v.y;
- immutable z = v.x * s + v.z * c;
- return Vector4(x, y, z);
- }
- auto rotateAroundX(in Vector4 v, in float angleDegrees) pure nothrow
- {
- import ru.nsk.sampler.math.utils:radians;
- immutable angleRadians = radians(angleDegrees);
- immutable c = cos(angleRadians);
- immutable s = sin(angleRadians);
- immutable x = v.x;
- immutable y = v.y * c - v.z * s;
- immutable z = v.y * s + v.z * c;
- return Vector4(x, y, z);
- }
- } // public
- unittest
- {
- immutable Vector4 v;
- immutable wwww = v.wwww;
- immutable xwxw = v.xwxw;
- immutable wxxx = v.wxxx;
- assert(wwww == Vector4(1, 1, 1, 1) );
- assert(xwxw == Vector4(0, 1, 0, 1) );
- assert(wxxx == Vector4(1, 0, 0, 0) );
- }
- unittest
- {
- const v = Vector4(1, 2, 3, 4);
- assert(v.yzx == Vector4(2, 3, 1) );
- assert(v.zxy == Vector4(3, 1, 2) );
- }
- unittest
- {
- const v = Vector4();
- assert(0.0f == v.norm());
- }
- unittest
- {
- const a = Vector4(1,0,0);
- const b = Vector4(1,1,1);
- assert(1.0f == a.dot3(b));
- }
- unittest
- {
- const a = Vector4(1,0,0);
- const b = Vector4(0,1,0);
- assert(Vector4(0,0,+1) == a.cross(b));
- assert(Vector4(0,0,-1) == b.cross(a));
- assert(Vector4(0,0,0) == cross(Vector4(), Vector4()));
- }
- unittest
- {
- assert (Vector4.sizeof == Vector4.DIMENSION * float.sizeof);
- }
- unittest
- {
- const v = Vector4(1, 2, 3, 4);
- assert (v.zz == Vector4(3, 3));
- assert (v.wx == Vector4(4, 1));
- assert (v.yy == Vector4(2, 2));
- assert (v.xz == Vector4(1, 3));
- }
- unittest
- {
- const v = Vector4();
- assert (0.0f == v.x);
- assert (0.0f == v[X]);
- assert (0.0f == v.y);
- assert (0.0f == v[Y]);
- assert (0.0f == v.z);
- assert (0.0f == v[Z]);
- assert (1.0f == v.w);
- assert (1.0f == v[W]);
- }
- unittest
- {
- auto v = Vector4();
- v.x = 2.0f;
- assert (2.0f == v.x);
- assert (2.0f == v[X]);
- assert (0.0f == v.y);
- assert (0.0f == v[Y]);
- assert (0.0f == v.z);
- assert (0.0f == v[Z]);
- assert (1.0f == v.w);
- assert (1.0f == v[W]);
- }
- unittest
- {
- auto v = Vector4();
- v.y = 2.0f;
- assert (0.0f == v.x);
- assert (0.0f == v[X]);
- assert (2.0f == v.y);
- assert (2.0f == v[Y]);
- assert (0.0f == v.z);
- assert (0.0f == v[Z]);
- assert (1.0f == v.w);
- assert (1.0f == v[W]);
- }
- unittest
- {
- auto v = Vector4();
- v.z = 3.0f;
- assert (0.0f == v.x);
- assert (0.0f == v[X]);
- assert (0.0f == v.y);
- assert (0.0f == v[Y]);
- assert (3.0f == v.z);
- assert (3.0f == v[Z]);
- assert (1.0f == v.w);
- assert (1.0f == v[W]);
- }
- unittest
- {
- auto v = Vector4();
- v.w = 2.0f;
- assert (0.0f == v.x);
- assert (0.0f == v[X]);
- assert (0.0f == v.y);
- assert (0.0f == v[Y]);
- assert (0.0f == v.z);
- assert (0.0f == v[Z]);
- assert (2.0f == v.w);
- assert (2.0f == v[W]);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement