1 module beziermeshmaker.datastructures.vec3; 2 3 import std.stdio; 4 import std..string; 5 import std.conv; 6 import std.math; 7 8 /* 9 *This acts as an ordinary Vector3f, except that it can also be passed into openGL functions 10 */ 11 class vec3{ 12 float* values; 13 alias values this; 14 15 this(){ 16 this(0, 0, 0); 17 } 18 this(float a, float b, float c){ 19 values = [a, b, c].ptr; 20 } 21 this(vec3 input){ 22 this(input.x, input.y, input.z); 23 } 24 25 @property{ 26 nothrow float x(){ return values[0]; } 27 nothrow float x(float newX){ return values[0] = newX; } 28 nothrow float y(){ return values[1]; } 29 nothrow float y(float newY){ return values[1] = newY; } 30 nothrow float z(){ return values[2]; } 31 nothrow float z(float newZ){ return values[2] = newZ; } 32 33 float u() { return x; } 34 float u(float newU){ return x(newU); } 35 float q() { return y; } 36 float q(float newQ){ return y(newQ); } 37 float v() { return z; } 38 float v(float newV){ return z(newV); } 39 } 40 41 float dot(vec3 other){ 42 return (x * other.x) + (y * other.y) + (z * other.z); 43 } 44 vec3 cross(vec3 v){ 45 return new vec3(y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x); 46 } 47 vec3 normalize(){ 48 return this / length(); 49 } 50 //Returns a copy of this vector, interpolated by <amount> between this vector and <other> 51 vec3 interpolate(float amount, vec3 other) { 52 float inverse = 1 - amount; 53 54 return new vec3(x * inverse + other.x * amount, y * inverse + other.y * amount, z * inverse + other.z * amount); 55 } 56 //Returns a copy of this vector, rotated around <axis> by <theta> radians. 57 //This uses Rodrigues' rotation formula https://en.wikipedia.org/wiki/Rodrigues%27_rotation_formula 58 vec3 rotateAround(vec3 axis, float theta) { 59 axis = axis.normalize(); 60 61 return (this * cos(theta) ) + (axis.cross(this) * sin(theta) ) + (axis * (axis.dot(this)) * (1 - cos(theta) ) ); 62 } 63 float length(){ 64 return sqrt(x * x + y * y + z * z); 65 } 66 float angleBetween(vec3 other){ 67 float value = dot(other) / (length() * other.length() ); 68 69 return acos(value); 70 } 71 float distanceBetween(vec3 other) { 72 float xDiff = x - other.x; 73 float yDiff = y - other.y; 74 float zDiff = z - other.z; 75 76 return sqrt(xDiff * xDiff + yDiff * yDiff + zDiff * zDiff); 77 } 78 79 vec3 opBinary(string op)(float val){ 80 if(op == "*"){ 81 return new vec3(x * val, y * val, z * val); 82 } 83 else if(op == "/"){ 84 return new vec3(x / val, y / val, z / val); 85 } 86 else{ 87 assert(0, "Operator "~op~" not implemented"); 88 } 89 } 90 vec3 opBinaryRight(string op)(float val){ 91 if(op == "*"){ 92 return new vec3(x * val, y * val, z * val); 93 } 94 else{ 95 assert(0, "Operator "~op~" not implemented"); 96 } 97 } 98 vec3 opBinary(string op)(vec3 val){ 99 if(op == "+"){ 100 return new vec3(x + val.x, y + val.y, z + val.z); 101 } 102 else if(op == "-"){ 103 return new vec3(x - val.x, y - val.y, z - val.z); 104 } 105 else{ 106 assert(0, "Operator "~op~" not implemented"); 107 } 108 } 109 110 override bool opEquals(Object o) { 111 vec3 other = cast(vec3) o; 112 113 if (other is null) { 114 return false; 115 } 116 else { 117 return approxEqual(x, other.x, 0.00001) && approxEqual(y, other.y, 0.00001) && approxEqual(z, other.z, 0.00001); 118 } 119 } 120 override @trusted size_t toHash() { 121 return cast(ulong)(x * 10000 + y * 10000 + z * 10000); 122 } 123 124 override string toString(){ 125 return "vec3(" ~ to!string(x) ~ ", " ~ to!string(y) ~ ", " ~ to!string(z) ~ ")"; 126 } 127 string toNiceString(int chars){ 128 string xStr = to!string(x); 129 string yStr = to!string(y); 130 string zStr = to!string(z); 131 132 xStr = leftJustify!string(xStr, chars, ' '); 133 yStr = leftJustify!string(yStr, chars, ' '); 134 zStr = leftJustify!string(zStr, chars, ' '); 135 136 return "vec3(" ~ xStr ~ ", " ~ yStr ~ ", " ~ zStr ~ ")"; 137 } 138 }