1 module prova.math.vector3; 2 3 import prova.math; 4 import std.math; 5 6 /// 7 struct Vector3 8 { 9 /// 10 static immutable auto left = Vector3(-1, 0, 0); 11 /// 12 static immutable auto right = Vector3(1, 0, 0); 13 /// 14 static immutable auto up = Vector3(0, 1, 0); 15 /// 16 static immutable auto down = Vector3(0, -1, 0); 17 /// 18 static immutable auto forward = Vector3(0, 0, -1); 19 /// 20 static immutable auto back = Vector3(0, 0, 1); 21 22 /// 23 float x = 0; 24 /// 25 float y = 0; 26 /// 27 float z = 0; 28 29 /// 30 this(float x, float y, float z) 31 { 32 set(x, y, z); 33 } 34 35 /// 36 this(Vector2 vector) 37 { 38 set(vector.x, vector.y, 0); 39 } 40 41 /// Sets the values of x, y, and z in a single statement 42 void set(float x, float y, float z) 43 { 44 this.x = x; 45 this.y = y; 46 this.z = z; 47 } 48 49 /// Creates a normalized vector with a random direction 50 static Vector3 random() 51 { 52 Vector3 vector = Vector3( 53 randomF(-1, 1), 54 randomF(-1, 1), 55 randomF(-1, 1) 56 ); 57 58 vector.normalize(); 59 60 return vector; 61 } 62 63 /// 64 @property Vector2 xy() const 65 { 66 return Vector2(x, y); 67 } 68 69 /// Returns a normalized copy of this vector 70 Vector3 getNormalized() const 71 { 72 const float magnitude = getMagnitude(); 73 74 Vector3 result; 75 76 if(magnitude != 0) { 77 result.x = x / magnitude; 78 result.y = y / magnitude; 79 result.z = y / magnitude; 80 } 81 82 return result; 83 } 84 85 /// Normalizes the vector 86 void normalize() 87 { 88 const float magnitude = getMagnitude(); 89 90 if(magnitude == 0) 91 return; 92 93 x = x / magnitude; 94 y = y / magnitude; 95 z = z / magnitude; 96 } 97 98 /// Returns the magnitude of the vector 99 float getMagnitude() const 100 { 101 return sqrt(x * x + y * y + z * z); 102 } 103 104 /** 105 * Sets the magnitude of this vector 106 * 107 * If the previous magnitude is zero, the x value 108 * of the vector will be set to the magnitude 109 */ 110 void setMagnitude(float magnitude) 111 { 112 if(getMagnitude() == 0) { 113 x = magnitude; 114 return; 115 } 116 117 normalize(); 118 119 x *= magnitude; 120 y *= magnitude; 121 z *= magnitude; 122 } 123 124 /// 125 Quaternion getDirection() const 126 { 127 Vector3 normalizedThis = getNormalized(); 128 Vector3 perpendicular = forward.cross(normalizedThis); 129 130 auto result = Quaternion.fromAxisAngle(perpendicular, 90); 131 132 // flip if the this vector is > 180deg away from forward 133 if(z > 0) { 134 result *= Quaternion(0, 1, 0, 0); 135 result.y *= -1; 136 } 137 138 return result; 139 } 140 141 /// Returns the distance between the vectors 142 float distanceTo(Vector3 vector) const 143 { 144 const float a = vector.x - x; 145 const float b = vector.y - y; 146 const float c = vector.z - z; 147 148 return sqrt(a * a + b * b + c * c); 149 } 150 151 /// Returns the squared distance between the vectors 152 float distanceToSquared(Vector3 vector) const 153 { 154 const float a = vector.x - x; 155 const float b = vector.y - y; 156 const float c = vector.z - z; 157 158 return a * a + b * b + c * c; 159 } 160 161 /// Returns the dot product of the two vectors 162 float dot(Vector3 vector) const 163 { 164 return x * vector.x + y * vector.y + z * vector.z; 165 } 166 167 /// Returns the cross product of the two vectors 168 Vector3 cross(Vector3 vector) const 169 { 170 Vector3 result; 171 result.x = y * vector.z - vector.y * z; 172 result.y = -(x * vector.z - vector.x * z); 173 result.z = x * vector.y - vector.x * y; 174 175 return result; 176 } 177 178 179 // assignment overloading 180 /// 181 Vector3 opAddAssign(Vector3 vector) 182 { 183 x += vector.x; 184 y += vector.y; 185 z += vector.z; 186 187 return this; 188 } 189 190 /// 191 Vector3 opAddAssign(Vector2 vector) 192 { 193 x += vector.x; 194 y += vector.y; 195 196 return this; 197 } 198 199 /// 200 Vector3 opSubAssign(Vector3 vector) 201 { 202 x -= vector.x; 203 y -= vector.y; 204 z -= vector.z; 205 206 return this; 207 } 208 209 /// 210 Vector3 opSubAssign(Vector2 vector) 211 { 212 x -= vector.x; 213 y -= vector.y; 214 215 return this; 216 } 217 218 /// 219 Vector3 opMulAssign(Vector3 vector) 220 { 221 x *= vector.x; 222 y *= vector.y; 223 z *= vector.z; 224 225 return this; 226 } 227 228 /// 229 Vector3 opMulAssign(float a) 230 { 231 x *= a; 232 y *= a; 233 z *= a; 234 235 return this; 236 } 237 238 /// 239 Vector3 opDivAssign(Vector3 vector) 240 { 241 x /= vector.x; 242 y /= vector.y; 243 z /= vector.z; 244 245 return this; 246 } 247 248 /// 249 Vector3 opDivAssign(float a) 250 { 251 x /= a; 252 y /= a; 253 z /= a; 254 255 return this; 256 } 257 258 259 // arithmetic overloading 260 /// 261 Vector3 opAdd(Vector3 vector) const 262 { 263 Vector3 result; 264 result.x = x + vector.x; 265 result.y = y + vector.y; 266 result.z = z + vector.z; 267 268 return result; 269 } 270 271 /// 272 Vector3 opAdd(Vector2 vector) const 273 { 274 Vector3 result; 275 result.x = x + vector.x; 276 result.y = y + vector.y; 277 result.z = z; 278 279 return result; 280 } 281 282 /// 283 Vector3 opSub(Vector3 vector) const 284 { 285 Vector3 result; 286 result.x = x - vector.x; 287 result.y = y - vector.y; 288 result.z = z - vector.z; 289 290 return result; 291 } 292 293 /// 294 Vector3 opSub(Vector2 vector) const 295 { 296 Vector3 result; 297 result.x = x - vector.x; 298 result.y = y - vector.y; 299 result.z = z; 300 301 return result; 302 } 303 304 /// 305 Vector3 opUnary(string s)() const if (s == "-") 306 { 307 Vector3 result; 308 result.x = -x; 309 result.y = -y; 310 result.z = -z; 311 312 return result; 313 } 314 315 /// 316 Vector3 opMul(Vector3 vector) const 317 { 318 Vector3 result; 319 result.x = x * vector.x; 320 result.y = y * vector.y; 321 result.z = z * vector.z; 322 323 return result; 324 } 325 326 /// 327 Vector3 opMul(float a) const 328 { 329 Vector3 result; 330 result.x = x * a; 331 result.y = y * a; 332 result.z = z * a; 333 334 return result; 335 } 336 337 /// 338 Vector3 opDiv(Vector3 vector) 339 { 340 Vector3 result; 341 result.x = x / vector.x; 342 result.y = y / vector.y; 343 result.z = z / vector.z; 344 345 return result; 346 } 347 348 /// 349 Vector3 opDiv(float a) const 350 { 351 Vector3 result; 352 result.x = x / a; 353 result.y = y / a; 354 result.z = z / a; 355 356 return result; 357 } 358 359 /// 360 void opAssign(Vector2 vector) 361 { 362 x = vector.x; 363 y = vector.y; 364 z = 0; 365 } 366 }