Advertisement
GeneralGDA

Vector4

Feb 24th, 2015
608
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
D 6.07 KB | None | 0 0
  1. module ru.nsk.sampler.math.vector;
  2.  
  3. //math stuff (sqrt, cos, sin)
  4. import std.math;
  5.  
  6. //'zip', 'repeat', 'take' lie here
  7. import std.range;
  8.  
  9. //'map' and 'reduce' lie here
  10. import std.algorithm;
  11.  
  12. //to make char upper case + 'format' - a sprintf-like function
  13. import std.string;
  14.  
  15. public static immutable X = 0;
  16. public static immutable Y = 1;
  17. public static immutable Z = 2;
  18. public static immutable W = 3;
  19.  
  20. public struct Vector4
  21. {
  22.     public
  23.     {
  24.  
  25.         static immutable DIMENSION = 4;
  26.  
  27.         this(Range)(Range coords) pure
  28.         {
  29.             auto i = 0u;
  30.             foreach (immutable coord; coords)
  31.             {
  32.                 this.coords[i] = coord;
  33.                 i++;
  34.             }
  35.         }
  36.  
  37.         this(in float x, in float y, in float z, in float w) pure nothrow
  38.         {
  39.             coords[X] = x;
  40.             coords[Y] = y;
  41.             coords[Z] = z;
  42.             coords[W] = w;
  43.         }
  44.  
  45.         this(in float x, in float y, in float z) pure nothrow
  46.         {
  47.             coords[X] = x;
  48.             coords[Y] = y;
  49.             coords[Z] = z;
  50.         }
  51.  
  52.         @property float[] get() pure nothrow
  53.         {
  54.             return coords;
  55.         }
  56.  
  57.         @property const (float[]) get() const pure nothrow
  58.         {
  59.             return coords;
  60.         }
  61.  
  62.         alias get this;
  63.  
  64.         mixin(generatePerCoordAccess("xyzw"));
  65.  
  66.         auto opUnary(const string op)() const pure if ("-" == op || "+" == op)
  67.         {
  68.             return Vector4 ( coords[0..$-1].map!(op ~ "a") );
  69.         }
  70.  
  71.         auto opBinary(const string op)(in Vector4 right) const pure if ("-" == op || "+" == op)
  72.         {
  73.             return Vector4 ( zip(this.coords[0..$-1], right.coords[0..$-1]).map!("a[0]" ~ op ~ "a[1]") );
  74.         }
  75.  
  76.         auto opBinary(const string op)(in float scalar) const pure if ("/" == op || "*" == op)
  77.         {
  78.             return Vector4 ( this.coords[0..$-1].map!( element => mixin(format("element %s scalar", op)) ));
  79.         }
  80.  
  81.         @property auto opDispatch(const string swizzling)() const pure
  82.             if (swizzling.length == DIMENSION || swizzling.length == DIMENSION - 1)
  83.         {
  84.             immutable expression = "coords".repeat().take(swizzling.length).zip(swizzling)
  85.                 .map!( a => format("%s[%c]", a[0], a[1].toUpper()) ).reduce!((a,b) => a ~ "," ~ b);
  86.  
  87.             mixin( "return Vector4 (" ~ expression ~ ");" );
  88.         }
  89.  
  90.         auto opEquals(in Vector4 other) const pure nothrow
  91.         {
  92.             return this.coords == other.coords;
  93.         }
  94.  
  95.     } // public
  96.  
  97.     private
  98.     {
  99.         static string generatePerCoordAccess(in string coords) pure
  100.         {
  101.             string result = "";
  102.  
  103.             foreach (immutable name; coords)
  104.             {
  105.             result ~= format("@property pure nothrow ref float %c() { return coords[%c]; }", name, name.toUpper);
  106.             result ~= format("@property pure nothrow float %c() const { return coords[%c]; }", name, name.toUpper);
  107.             }
  108.  
  109.             return result;
  110.         }
  111.  
  112.         float[DIMENSION] coords = [0.0f, 0.0f, 0.0f, 1.0f,];
  113.  
  114.     } // private
  115. };
  116.  
  117. private float dot(in float[] left, in float[] right) pure
  118. {
  119.     return zip(left, right).map!(a => a[0] * a[1]).reduce!((a, b) => a + b);
  120. }
  121.  
  122. public
  123. {
  124.    
  125.     float dot3(T)(in T left, in T right) pure
  126.     {
  127.         return dot(left.coords[0..$-1], right.coords[0..$-1]);
  128.     }
  129.  
  130.     float dot4(T)(in T left, in T right) pure
  131.     {
  132.         return dot(left.coords[0..$], right.coords[0..$]);
  133.     }
  134.  
  135.     float norm(T)(in T vector) pure
  136.     {
  137.         return sqrt(dot3(vector, vector));
  138.     }
  139.  
  140.     T identity(T)(in T vector) pure
  141.     {
  142.         return vector / norm(vector);
  143.     }
  144.  
  145.     T mul(T)(in T left, in T right) pure
  146.     {
  147.         return Vector4( zip(left.get(), right.get()).map!(a => a[0] * a[1]) );
  148.     }
  149.  
  150.     auto cross(in Vector4 l, in Vector4 r) pure
  151.     {
  152.         return mul( l.yzx, r.zxy ) - mul( l.zxy, r.yzx );
  153.     }
  154.  
  155.     auto rotateAroundY(in Vector4 v, in float angleDegrees) pure nothrow
  156.     {
  157.         import ru.nsk.sampler.math.utils:radians;
  158.  
  159.         immutable angleRadians = radians(angleDegrees);
  160.  
  161.         immutable c = cos(angleRadians);
  162.         immutable s = sin(angleRadians);
  163.  
  164.         immutable x = v.x * c - v.z * s;
  165.         immutable y = v.y;
  166.         immutable z = v.x * s + v.z * c;
  167.  
  168.         return Vector4(x, y, z);
  169.     }
  170.  
  171.     auto rotateAroundX(in Vector4 v, in float angleDegrees) pure nothrow
  172.     {
  173.         import ru.nsk.sampler.math.utils:radians;
  174.  
  175.         immutable angleRadians = radians(angleDegrees);
  176.  
  177.         immutable c = cos(angleRadians);
  178.         immutable s = sin(angleRadians);
  179.  
  180.         immutable x = v.x;
  181.         immutable y = v.y * c - v.z * s;
  182.         immutable z = v.y * s + v.z * c;
  183.  
  184.         return Vector4(x, y, z);
  185.     }
  186.  
  187. } // public
  188.  
  189. unittest
  190. {
  191.     immutable Vector4 v;
  192.  
  193.     immutable wwww = v.wwww;
  194.     immutable xwxw = v.xwxw;
  195.     immutable wxxx = v.wxxx;
  196.  
  197.     assert(wwww == Vector4(1, 1, 1, 1) );
  198.     assert(xwxw == Vector4(0, 1, 0, 1) );
  199.     assert(wxxx == Vector4(1, 0, 0, 0) );
  200. }
  201.  
  202. unittest
  203. {
  204.     const v = Vector4();
  205.  
  206.     assert(0.0f == v.norm());
  207. }
  208.  
  209. unittest
  210. {
  211.     const a = Vector4(1,0,0);
  212.     const b = Vector4(1,1,1);
  213.  
  214.     assert(1.0f == a.dot3(b));
  215. }
  216.  
  217. unittest
  218. {
  219.     const a = Vector4(1,0,0);
  220.     const b = Vector4(0,1,0);
  221.  
  222.     assert(Vector4(0,0,+1) == a.cross(b));
  223.     assert(Vector4(0,0,-1) == b.cross(a));
  224.    
  225.     assert(Vector4(0,0,0) == cross(Vector4(), Vector4()));
  226. }
  227.  
  228. unittest
  229. {
  230.     assert (Vector4.sizeof == Vector4.DIMENSION * float.sizeof);
  231. }
  232.  
  233. unittest
  234. {
  235.     const v = Vector4();
  236.  
  237.     assert (0.0f == v.x);
  238.     assert (0.0f == v[X]);
  239.  
  240.     assert (0.0f == v.y);
  241.     assert (0.0f == v[Y]);
  242.  
  243.     assert (0.0f == v.z);
  244.     assert (0.0f == v[Z]);
  245.  
  246.     assert (1.0f == v.w);
  247.     assert (1.0f == v[W]);
  248. }
  249.  
  250. unittest
  251. {
  252.     auto v = Vector4();
  253.     v.x = 2.0f;
  254.  
  255.     assert (2.0f == v.x);
  256.     assert (2.0f == v[X]);
  257.  
  258.     assert (0.0f == v.y);
  259.     assert (0.0f == v[Y]);
  260.  
  261.     assert (0.0f == v.z);
  262.     assert (0.0f == v[Z]);
  263.  
  264.     assert (1.0f == v.w);
  265.     assert (1.0f == v[W]);
  266. }
  267.  
  268. unittest
  269. {
  270.     auto v = Vector4();
  271.     v.y = 2.0f;
  272.  
  273.     assert (0.0f == v.x);
  274.     assert (0.0f == v[X]);
  275.  
  276.     assert (2.0f == v.y);
  277.     assert (2.0f == v[Y]);
  278.  
  279.     assert (0.0f == v.z);
  280.     assert (0.0f == v[Z]);
  281.  
  282.     assert (1.0f == v.w);
  283.     assert (1.0f == v[W]);
  284. }
  285.  
  286. unittest
  287. {
  288.     auto v = Vector4();
  289.     v.z = 3.0f;
  290.  
  291.     assert (0.0f == v.x);
  292.     assert (0.0f == v[X]);
  293.  
  294.     assert (0.0f == v.y);
  295.     assert (0.0f == v[Y]);
  296.  
  297.     assert (3.0f == v.z);
  298.     assert (3.0f == v[Z]);
  299.  
  300.     assert (1.0f == v.w);
  301.     assert (1.0f == v[W]);
  302. }
  303.  
  304. unittest
  305. {
  306.     auto v = Vector4();
  307.     v.w = 2.0f;
  308.  
  309.     assert (0.0f == v.x);
  310.     assert (0.0f == v[X]);
  311.  
  312.     assert (0.0f == v.y);
  313.     assert (0.0f == v[Y]);
  314.  
  315.     assert (0.0f == v.z);
  316.     assert (0.0f == v[Z]);
  317.  
  318.     assert (2.0f == v.w);
  319.     assert (2.0f == v[W]);
  320. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement