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 debug import std.stdio : writeln; 28 import std.math : pow, sqrt; 29 import std.traits : isNumeric; 30 } 31 32 /** 33 * Vector3 is a structure that defines a two-dimensional point. 34 * 35 * Author: rschuett 36 */ 37 struct Vector3(T) if (isNumeric!T) { 38 /** 39 * x coordinate 40 */ 41 T x = 0; 42 /** 43 * y coordinate 44 */ 45 T y = 0; 46 /** 47 * z coordinate 48 */ 49 T z = 0; 50 51 /** 52 * CTor 53 */ 54 this(T x, T y, T z = 0) pure nothrow { 55 this.x = x; 56 this.y = y; 57 this.z = z; 58 } 59 60 /** 61 * CTor 62 */ 63 this(U)(U x, U y, U z = 0) pure nothrow if (isNumeric!U && !is(U : T)) { 64 this(cast(T) x, cast(T) y, cast(T) z); 65 } 66 67 /** 68 * CTor 69 */ 70 this(U)(U[3] pos) pure nothrow if (isNumeric!U) { 71 this(pos[0], pos[1], pos[2]); 72 } 73 74 /** 75 * CTor 76 */ 77 this(U)(ref const Vector3!U vec) pure nothrow { 78 this(vec.x, vec.y, vec.z); 79 } 80 81 // debug(Dgame) 82 // this(this) { 83 // writeln("Postblit Vector3"); 84 // } 85 86 /** 87 * Supported operation: +=, -=, *=, /= and %= 88 */ 89 ref Vector3 opOpAssign(string op)(ref const Vector3 vec) pure { 90 switch (op) { 91 case "+": 92 this.x += vec.x; 93 this.y += vec.y; 94 this.z += vec.z; 95 break; 96 case "-": 97 this.x -= vec.x; 98 this.y -= vec.y; 99 this.z -= vec.z; 100 break; 101 case "*": 102 this.x *= vec.x; 103 this.y *= vec.y; 104 this.z *= vec.z; 105 break; 106 case "/": 107 this.x /= vec.x; 108 this.y /= vec.y; 109 this.z /= vec.z; 110 break; 111 case "%": 112 this.x %= vec.x; 113 this.y %= vec.y; 114 this.z %= vec.z; 115 break; 116 default: throw new Exception("Unsupported operator " ~ op); 117 } 118 119 return this; 120 } 121 122 /** 123 * Supported operation: +=, -=, *=, /= and %= 124 */ 125 ref Vector3 opOpAssign(string op)(T number) pure { 126 switch (op) { 127 case "+": 128 this.x += number; 129 this.y += number; 130 this.z += number; 131 break; 132 case "-": 133 this.x -= number; 134 this.y -= number; 135 this.z -= number; 136 break; 137 case "*": 138 this.x *= number; 139 this.y *= number; 140 this.z *= number; 141 break; 142 case "/": 143 this.x /= number; 144 this.y /= number; 145 this.z /= number; 146 break; 147 case "%": 148 this.x %= number; 149 this.y %= number; 150 this.z %= number; 151 break; 152 default: throw new Exception("Unsupported operator " ~ op); 153 } 154 155 return this; 156 } 157 158 /** 159 * Supported operation: +, -, *, / and % 160 */ 161 Vector3 opBinary(string op)(ref const Vector3 vec) pure { 162 switch (op) { 163 case "+": return Vector3(vec.x + this.x, vec.y + this.y, vec.z + this.z); 164 case "-": return Vector3(vec.x - this.x, vec.y - this.y, vec.z - this.z); 165 case "*": return Vector3(vec.x * this.x, vec.y * this.y, vec.z * this.z); 166 case "/": return Vector3(vec.x / this.x, vec.y / this.y, vec.z / this.z); 167 case "%": return Vector3(vec.x % this.x, vec.y % this.y, vec.z % this.z); 168 default: throw new Exception("Unsupported operator " ~ op); 169 } 170 } 171 172 /** 173 * Supported operation: +, -, *, / and % 174 */ 175 Vector3 opBinary(string op)(T number) pure { 176 switch (op) { 177 case "+": return Vector3(number + this.x, number + this.y, number + this.z); 178 case "-": return Vector3(number - this.x, number - this.y, number - this.z); 179 case "*": return Vector3(number * this.x, number * this.y, number * this.z); 180 case "/": return Vector3(number / this.x, number / this.y, number / this.z); 181 case "%": return Vector3(number % this.x, number % this.y, number % this.z); 182 default: throw new Exception("Unsupported operator " ~ op); 183 } 184 } 185 186 /** 187 * Returns a negated copy of this Vector. 188 */ 189 Vector3 opNeg() const pure nothrow { 190 return Vector3(-this.x, -this.y, -this.z); 191 } 192 193 /** 194 * Negate this Vector 195 */ 196 void negate() pure nothrow { 197 this.x = -this.x; 198 this.y = -this.y; 199 this.z = -this.z; 200 } 201 202 /** 203 * Compares two vectors by checking whether the coordinates are equals. 204 */ 205 bool opEquals(ref const Vector3 vec) const pure nothrow { 206 return vec.x == this.x && vec.y == this.y && vec.z == this.z; 207 } 208 209 /** 210 * Checks if this vector is empty. This means that his coordinates are 0. 211 */ 212 bool isEmpty() const pure nothrow { 213 return this.x == 0 && this.y == 0 && this.z == 0; 214 } 215 216 /** 217 * Calculate the scalar product. 218 */ 219 float scalar(ref const Vector3 vec) const pure nothrow { 220 return this.x * vec.x + this.y * vec.y + this.z * vec.z; 221 } 222 223 /** 224 * alias for scalar 225 */ 226 alias dot = scalar; 227 228 /** 229 * Calculate the length. 230 */ 231 @property 232 float length() const pure nothrow { 233 if (this.isEmpty()) 234 return 0f; 235 236 return sqrt(pow(this.x, 2f) + pow(this.y, 2f) + pow(this.z, 2f)); 237 } 238 239 /** 240 * Calculate the diff between two vectors. 241 */ 242 float diff(ref const Vector3 vec) const pure nothrow { 243 return sqrt(pow(this.x - vec.x, 2f) + pow(this.y - vec.y, 2f) + pow(this.z - vec.z, 2f)); 244 } 245 246 /** 247 * Returns the cross product of this and another Vector. 248 */ 249 Vector3 cross(ref const Vector3 vec) const pure nothrow { 250 return Vector3(this.y * vec.z - this.z * vec.y, 251 this.z * vec.x - this.x * vec.z, 252 this.x * vec.y - this.y * vec.x); 253 } 254 255 /** 256 * Set new coordinates. 257 */ 258 void set(T x, T y, T z) pure nothrow { 259 this.x = x; 260 this.y = y; 261 this.z = z; 262 } 263 264 /** 265 * Move the current coordinates. 266 */ 267 void move(T x, T y, T z) pure nothrow { 268 this.x += x; 269 this.y += y; 270 this.z += z; 271 } 272 273 /** 274 * Returns the Vector as static array. 275 */ 276 T[3] asArray() const pure nothrow { 277 return [this.x, this.y, this.z]; 278 } 279 } 280 281 /** 282 * Alias for short Vector 283 */ 284 alias Vector3s = Vector3!(short); 285 /** 286 * Alias for float Vector 287 */ 288 alias Vector3f = Vector3!(float); 289 /** 290 * Alias for byte Vector 291 */ 292 alias Vector3b = Vector3!(byte);