1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Math.Vector3; 25 26 private: 27 28 import std.traits : isNumeric; 29 static import std.math; 30 31 public: 32 33 /** 34 * Vector3 is a structure that defines a three-dimensional point. 35 * 36 * Author: Randy Schuett (rswhite4@googlemail.com) 37 */ 38 struct Vector3(T) if (isNumeric!(T)) { 39 T x = 0; /// The x coordinate 40 T y = 0; /// The y coordinate 41 T z = 0; /// The z coordinate 42 43 /** 44 * CTor 45 */ 46 @nogc 47 this(T x, T y, T z = 0) pure nothrow { 48 this.x = x; 49 this.y = y; 50 this.z = z; 51 } 52 53 /** 54 * CTor 55 */ 56 @nogc 57 this(U)(U x, U y, U z = 0) pure nothrow if (isNumeric!(U) && !is(U == T)) { 58 this(cast(T) x, cast(T) y, cast(T) z); 59 } 60 61 /** 62 * CTor 63 */ 64 @nogc 65 this(U)(const Vector3!(U) vec) pure nothrow if (!is(U == T)) { 66 this(vec.x, vec.y, vec.z); 67 } 68 69 /** 70 * Compares two vectors by checking whether the coordinates are equals. 71 */ 72 @nogc 73 bool opEquals(const Vector3!(T) vec) const pure nothrow { 74 return vec.x == this.x && vec.y == this.y && vec.z == this.z; 75 } 76 77 /** 78 * Checks if this vector is empty. This means that his coordinates are 0. 79 */ 80 @nogc 81 bool isEmpty() const pure nothrow { 82 return this.x == 0 && this.y == 0 && this.z == 0; 83 } 84 85 /** 86 * Calculate the scalar product. 87 */ 88 @nogc 89 float scalar(const Vector3!(T) vec) const pure nothrow { 90 return this.x * vec.x + this.y * vec.y + this.z * vec.z; 91 } 92 93 /** 94 * alias for scalar 95 */ 96 alias dot = scalar; 97 98 /** 99 * Calculate the length. 100 */ 101 @nogc 102 @property 103 float length() const pure nothrow { 104 if (this.isEmpty()) 105 return 0f; 106 return std.math.sqrt(std.math.pow(this.x, 2f) + std.math.pow(this.y, 2f) + std.math.pow(this.z, 2f)); 107 } 108 109 /** 110 * Calculate the diff between two vectors. 111 */ 112 @nogc 113 float diff(const Vector3!(T) vec) const pure nothrow { 114 return std.math.sqrt(std.math.pow(this.x - vec.x, 2f) + std.math.pow(this.y - vec.y, 2f) + std.math.pow(this.z - vec.z, 2f)); 115 } 116 117 /** 118 * Supported operation: +=, -=, *=, /= and %= 119 */ 120 @nogc 121 ref Vector3!(T) opOpAssign(string op)(const Vector3!(T) vec) pure nothrow { 122 switch (op) { 123 case "+": 124 case "-": 125 case "*": 126 case "/": 127 case "%": 128 mixin("this.x " ~ op ~ "= vec.x;"); 129 mixin("this.y " ~ op ~ "= vec.y;"); 130 mixin("this.z " ~ op ~ "= vec.z;"); 131 break; 132 default: 133 assert(0, "Unsupported operator " ~ op); 134 } 135 136 return this; 137 } 138 139 /** 140 * Supported operation: +=, -=, *=, /= and %= 141 */ 142 @nogc 143 ref Vector3!(T) opOpAssign(string op)(float num) pure nothrow { 144 switch (op) { 145 case "+": 146 case "-": 147 case "*": 148 case "/": 149 case "%": 150 mixin("this.x = cast(T)(this.x " ~ op ~ " num);"); 151 mixin("this.y = cast(T)(this.y " ~ op ~ " num);"); 152 mixin("this.z = cast(T)(this.z " ~ op ~ " num);"); 153 break; 154 default: 155 assert(0, "Unsupported operator " ~ op); 156 } 157 158 return this; 159 } 160 161 /** 162 * Supported operation: +, -, *, / and % 163 */ 164 @nogc 165 Vector3!(T) opBinary(string op)(const Vector3!(T) vec) const pure nothrow { 166 switch (op) { 167 case "+": 168 case "-": 169 case "*": 170 case "/": 171 case "%": 172 mixin("return Vector3!(T)(this.x " ~ op ~ " vec.x, this.y " ~ op ~ " vec.y, this.z " ~ op ~ " vec.z);"); 173 default: 174 assert(0, "Unsupported operator " ~ op); 175 } 176 } 177 178 /** 179 * Supported operation: +, -, *, / and % 180 */ 181 @nogc 182 Vector3!(T) opBinary(string op)(float num) const pure { 183 switch (op) { 184 case "+": 185 case "-": 186 case "*": 187 case "/": 188 case "%": 189 mixin("return Vector3!(T)(cast(T)(this.x " ~ op ~ " num), cast(T)(this.y " ~ op ~ " num), cast(T)(this.z " ~ op ~ " num));"); 190 default: 191 assert(0, "Unsupported operator " ~ op); 192 } 193 } 194 195 /** 196 * Returns the cross product of this and another Vector. 197 */ 198 @nogc 199 Vector3!(T) cross(const Vector3!(T) vec) const pure nothrow { 200 return Vector3!(T)(this.y * vec.z - this.z * vec.y, this.z * vec.x - this.x * vec.z, this.x * vec.y - this.y * vec.x); 201 } 202 203 /** 204 * Normalize the vector in which the coordinates are divided by the length. 205 */ 206 Vector3!(T) normalize() pure nothrow { 207 immutable float len = this.length; 208 if (len > 0) 209 return this / len; 210 return this; 211 } 212 213 /** 214 * Rotate the current Vector by an angle and rotation Vector and returns the result 215 */ 216 Vector3!(T) rotate(float angle, const Vector3!(T) rot) const pure nothrow { 217 immutable float len1 = this.length; 218 immutable float len2 = rot.length; 219 220 assert(len1 > 0 && len2 > 0); 221 222 const Vector3!(T) norm1 = this / len1; 223 const Vector3!(T) norm2 = rot / len2; 224 225 immutable float rho_rad = angle / 180 * std.math.PI; 226 immutable float c = std.math.cos(rho_rad); 227 immutable float s = std.math.sin(rho_rad); 228 immutable float t = 1 - c; 229 230 immutable float norm_final_x = norm1.x * (t * norm2.x * norm2.x + c) + norm1.y * (t * norm2.x * norm2.y - s * norm2.z) + norm1.z * (t * norm2.x * norm2.z + s * norm2.y); 231 immutable float norm_final_y = norm1.x * (t * norm2.x * norm2.y + s * norm2.z) + norm1.y * (t * norm2.y * norm2.y + c) + norm1.z * (t * norm2.y * norm2.z - s * norm2.x); 232 immutable float norm_final_z = norm1.x * (t * norm2.x * norm2.z - s * norm2.y) + norm1.y * (t * norm2.y * norm2.z + s * norm2.x) + norm1.z * (t * norm2.z * norm2.z + c); 233 234 Vector3!(T) final_norm = Vector3!(T)(norm_final_x, norm_final_y, norm_final_z); 235 final_norm *= this.length; 236 237 return final_norm; 238 } 239 } 240 241 alias Vector3f = Vector3!(float); /// A float representation 242 alias Vector3i = Vector3!(int); /// An int representation