1 /* 2 Copyright (c) 2011-2021 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 6 Permission is hereby granted, free of charge, to any person or organization 7 obtaining a copy of the software and accompanying documentation covered by 8 this license (the "Software") to use, reproduce, display, distribute, 9 execute, and transmit the Software, and to prepare derivative works of the 10 Software, and to permit third-parties to whom the Software is furnished to 11 do so, all subject to the following: 12 13 The copyright notices in the Software and this entire statement, including 14 the above license grant, this restriction and the following disclaimer, 15 must be included in all copies of the Software, in whole or in part, and 16 all derivative works of the Software, unless such copies or derivative 17 works are solely in the form of machine-executable object code generated by 18 a source language processor. 19 20 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 21 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 22 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 23 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 24 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 25 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 */ 28 29 /** 30 * Vectors of Euclidean space 31 * 32 * Copyright: Timur Gafarov 2011-2021. 33 * License: $(LINK2 boost.org/LICENSE_1_0.txt, Boost License 1.0). 34 * Authors: Timur Gafarov 35 */ 36 module dlib.math.vector; 37 38 import std.conv; 39 import std.math; 40 import std.random; 41 import std.range; 42 import std.format; 43 import std.traits; 44 import dlib.core.tuple; 45 import dlib.math.utils; 46 import dlib.math.matrix; 47 48 /** 49 * Vector representation 50 */ 51 struct Vector(T, int size) 52 { 53 public: 54 55 /** 56 * Vector constructor. 57 * Supports initializing from vector of arbitrary length and type 58 */ 59 this (T2, int size2)(Vector!(T2, size2) v) 60 { 61 if (v.arrayof.length >= size) 62 { 63 foreach(i; 0..size) 64 arrayof[i] = cast(T)v.arrayof[i]; 65 } 66 else 67 { 68 foreach(i; 0..v.arrayof.length) 69 arrayof[i] = cast(T)v.arrayof[i]; 70 } 71 } 72 73 /** 74 * Array constructor 75 */ 76 this (A)(A components) if (isDynamicArray!A && !isSomeString!A) 77 { 78 if (components.length >= size) 79 { 80 foreach(i; 0..size) 81 arrayof[i] = cast(T)components[i]; 82 } 83 else 84 { 85 foreach(i; 0..components.length) 86 arrayof[i] = cast(T)components[i]; 87 } 88 } 89 90 /** 91 * Static array constructor 92 */ 93 this (T2, size_t arrSize)(T2[arrSize] components) 94 { 95 if (components.length >= size) 96 { 97 foreach(i; 0..size) 98 arrayof[i] = cast(T)components[i]; 99 } 100 else 101 { 102 foreach(i; 0..components.length) 103 arrayof[i] = cast(T)components[i]; 104 } 105 } 106 107 /** 108 * Tuple constructor 109 */ 110 this (F...)(F components) 111 { 112 foreach(i; RangeTuple!(0, size)) 113 { 114 static if (i < components.length) 115 arrayof[i] = cast(T)components[i]; 116 else 117 arrayof[i] = cast(T)components[$-1]; 118 } 119 } 120 121 /** 122 * String constructor 123 */ 124 this (S)(S str) if (isSomeString!S) 125 { 126 arrayof = parse!(T[size])(str); 127 } 128 129 /** 130 * Vector!(T,size) = Vector!(T,size2) 131 */ 132 void opAssign(T2, int size2)(Vector!(T2,size2) v) 133 { 134 if (v.arrayof.length >= size) 135 { 136 foreach(i; 0..size) 137 arrayof[i] = cast(T)v.arrayof[i]; 138 } 139 else 140 { 141 foreach(i; 0..v.arrayof.length) 142 arrayof[i] = cast(T)v.arrayof[i]; 143 } 144 } 145 146 /** 147 * Vector!(T,size) = Vector!(T,size2) for enums 148 */ 149 void opAssign(T2)(T2 ev) if (is(T2 == enum)) 150 { 151 opAssign(cast(OriginalType!T2)ev); 152 } 153 154 /** 155 * -Vector!(T,size) 156 */ 157 Vector!(T,size) opUnary(string s) () const if (s == "-") 158 do 159 { 160 Vector!(T,size) res; 161 foreach(i; RangeTuple!(0, size)) 162 res.arrayof[i] = -arrayof[i]; 163 return res; 164 } 165 166 /** 167 * +Vector!(T,size) 168 */ 169 Vector!(T,size) opUnary(string s) () const if (s == "+") 170 do 171 { 172 return Vector!(T,size)(this); 173 } 174 175 /** 176 * Vector!(T,size) + Vector!(T,size) 177 */ 178 Vector!(T,size) opBinary(string op)(Vector!(T,size) v) const if (op == "+") 179 do 180 { 181 Vector!(T,size) res; 182 foreach(i; RangeTuple!(0, size)) 183 res.arrayof[i] = cast(T)(arrayof[i] + v.arrayof[i]); 184 return res; 185 } 186 187 /** 188 * Vector!(T,size) - Vector!(T,size) 189 */ 190 Vector!(T,size) opBinary(string op)(Vector!(T,size) v) const if (op == "-") 191 do 192 { 193 Vector!(T,size) res; 194 foreach(i; RangeTuple!(0, size)) 195 res.arrayof[i] = cast(T)(arrayof[i] - v.arrayof[i]); 196 return res; 197 } 198 199 /** 200 * Vector!(T,size) * Vector!(T,size) 201 */ 202 Vector!(T,size) opBinary(string op)(Vector!(T,size) v) const if (op == "*") 203 do 204 { 205 Vector!(T,size) res; 206 foreach(i; RangeTuple!(0, size)) 207 res.arrayof[i] = cast(T)(arrayof[i] * v.arrayof[i]); 208 return res; 209 } 210 211 /** 212 * Vector!(T,size) / Vector!(T,size) 213 */ 214 Vector!(T,size) opBinary(string op)(Vector!(T,size) v) const if (op == "/") 215 do 216 { 217 Vector!(T,size) res; 218 foreach(i; RangeTuple!(0, size)) 219 res.arrayof[i] = cast(T)(arrayof[i] / v.arrayof[i]); 220 return res; 221 } 222 223 /** 224 * Vector!(T,size) + T 225 */ 226 Vector!(T,size) opBinary(string op)(T t) const if (op == "+") 227 do 228 { 229 Vector!(T,size) res; 230 foreach(i; RangeTuple!(0, size)) 231 res.arrayof[i] = cast(T)(arrayof[i] + t); 232 return res; 233 } 234 235 /** 236 * Vector!(T,size) - T 237 */ 238 Vector!(T,size) opBinary(string op)(T t) const if (op == "-") 239 do 240 { 241 Vector!(T,size) res; 242 foreach(i; RangeTuple!(0, size)) 243 res.arrayof[i] = cast(T)(arrayof[i] - t); 244 return res; 245 } 246 247 /** 248 * Vector!(T,size) * T 249 */ 250 Vector!(T,size) opBinary(string op)(T t) const if (op == "*") 251 do 252 { 253 Vector!(T,size) res; 254 foreach(i; RangeTuple!(0, size)) 255 res.arrayof[i] = cast(T)(arrayof[i] * t); 256 return res; 257 } 258 259 /** 260 * T * Vector!(T,size) 261 */ 262 Vector!(T,size) opBinaryRight(string op) (T t) const 263 if (op == "*" && isNumeric!T) 264 do 265 { 266 Vector!(T,size) res; 267 foreach(i; RangeTuple!(0, size)) 268 res.arrayof[i] = cast(T)(arrayof[i] * t); 269 return res; 270 } 271 272 /** 273 * Vector!(T,size) / T 274 */ 275 Vector!(T,size) opBinary(string op)(T t) const if (op == "/") 276 do 277 { 278 Vector!(T,size) res; 279 foreach(i; RangeTuple!(0, size)) 280 res.arrayof[i] = cast(T)(arrayof[i] / t); 281 return res; 282 } 283 284 /** 285 * Vector!(T,size) % T 286 */ 287 Vector!(T,size) opBinary(string op, T2) (T2 t) const if (op == "%") 288 do 289 { 290 Vector!(T,size) res; 291 foreach(i; RangeTuple!(0, size)) 292 res.arrayof[i] = cast(T)(arrayof[i] % t); 293 return res; 294 } 295 296 /** 297 * Vector!(T,size) += Vector!(T,size) 298 */ 299 Vector!(T,size) opOpAssign(string op)(Vector!(T,size) v) if (op == "+") 300 do 301 { 302 foreach(i; RangeTuple!(0, size)) 303 arrayof[i] += v.arrayof[i]; 304 return this; 305 } 306 307 /** 308 * Vector!(T,size) -= Vector!(T,size) 309 */ 310 Vector!(T,size) opOpAssign(string op)(Vector!(T,size) v) if (op == "-") 311 do 312 { 313 foreach(i; RangeTuple!(0, size)) 314 arrayof[i] -= v.arrayof[i]; 315 return this; 316 } 317 318 /** 319 * Vector!(T,size) *= Vector!(T,size) 320 */ 321 Vector!(T,size) opOpAssign(string op)(Vector!(T,size) v) if (op == "*") 322 do 323 { 324 foreach(i; RangeTuple!(0, size)) 325 arrayof[i] *= v.arrayof[i]; 326 return this; 327 } 328 329 /** 330 * Vector!(T,size) /= Vector!(T,size) 331 */ 332 Vector!(T,size) opOpAssign(string op)(Vector!(T,size) v) if (op == "/") 333 do 334 { 335 foreach(i; RangeTuple!(0, size)) 336 arrayof[i] /= v.arrayof[i]; 337 return this; 338 } 339 340 /** 341 * Vector!(T,size) += T 342 */ 343 Vector!(T,size) opOpAssign(string op)(T t) if (op == "+") 344 do 345 { 346 foreach(i; RangeTuple!(0, size)) 347 arrayof[i] += t; 348 return this; 349 } 350 351 /** 352 * Vector!(T,size) -= T 353 */ 354 Vector!(T,size) opOpAssign(string op)(T t) if (op == "-") 355 do 356 { 357 foreach(i; RangeTuple!(0, size)) 358 arrayof[i] -= t; 359 return this; 360 } 361 362 /** 363 * Vector!(T,size) *= T 364 */ 365 Vector!(T,size) opOpAssign(string op)(T t) if (op == "*") 366 do 367 { 368 foreach(i; RangeTuple!(0, size)) 369 arrayof[i] *= t; 370 return this; 371 } 372 373 /** 374 * Vector!(T,size) /= T 375 */ 376 Vector!(T,size) opOpAssign(string op)(T t) if (op == "/") 377 do 378 { 379 foreach(i; RangeTuple!(0, size)) 380 arrayof[i] /= t; 381 return this; 382 } 383 384 /** 385 * Vector!(T,size) %= T 386 */ 387 Vector!(T,size) opOpAssign(string op, T2)(T2 t) if (op == "%") 388 do 389 { 390 foreach(i; RangeTuple!(0, size)) 391 arrayof[i] %= t; 392 return this; 393 } 394 395 /** 396 * T = Vector!(T,size)[index] 397 */ 398 auto ref T opIndex(this X)(size_t index) 399 in 400 { 401 assert ((0 <= index) && (index < size), 402 "Vector!(T,size).opIndex(int index): array index out of bounds"); 403 } 404 do 405 { 406 return arrayof[index]; 407 } 408 409 /** 410 * Vector!(T,size)[index] = T 411 */ 412 void opIndexAssign(T n, size_t index) 413 in 414 { 415 assert ((0 <= index) && (index < size), 416 "Vector!(T,size).opIndexAssign(int index): array index out of bounds"); 417 } 418 do 419 { 420 arrayof[index] = n; 421 } 422 423 /** 424 * T[] = Vector!(T,size)[index1..index2] 425 */ 426 auto opSlice(this X)(size_t index1, size_t index2) 427 in 428 { 429 assert ((0 <= index1) || (index1 < 3) || (0 <= index2) || (index2 < 3) || (index1 < index2), 430 "Vector!(T,size).opSlice(int index1, int index2): array index out of bounds"); 431 } 432 do 433 { 434 return arrayof[index1..index2]; 435 } 436 437 /** 438 * Vector!(T,size)[index1..index2] = T 439 */ 440 T opSliceAssign(T t, size_t index1, size_t index2) 441 in 442 { 443 assert ((0 <= index1) || (index1 < 3) || (0 <= index2) || (index2 < 3) || (index1 < index2), 444 "Vector!(T,size).opSliceAssign(T t, int index1, int index2): array index out of bounds"); 445 } 446 do 447 { 448 arrayof[index1..index2] = t; 449 return t; 450 } 451 452 /** 453 * T = Vector!(T,size)[] 454 */ 455 auto opSlice(this X)() 456 do 457 { 458 return arrayof[]; 459 } 460 461 /** 462 * Vector!(T,size)[] = T 463 */ 464 T opSliceAssign(T t) 465 do 466 { 467 foreach(i; RangeTuple!(0, size)) 468 arrayof[i] = t; 469 return t; 470 } 471 472 static if (isNumeric!(T)) 473 { 474 /** 475 * Get vector length squared 476 */ 477 @property T lengthsqr() const 478 do 479 { 480 T res = 0; 481 foreach (component; arrayof) 482 res += component * component; 483 return res; 484 } 485 486 /** 487 * Get vector length 488 */ 489 @property T length() const 490 do 491 { 492 static if (isFloatingPoint!T) 493 { 494 T t = 0; 495 foreach (component; arrayof) 496 t += component * component; 497 return sqrt(t); 498 } 499 else 500 { 501 T t = 0; 502 foreach (component; arrayof) 503 t += component * component; 504 return cast(T)sqrt(cast(float)t); 505 } 506 } 507 508 /** 509 * Set vector length to 1 510 */ 511 void normalize() 512 do 513 { 514 static if (isFloatingPoint!T) 515 { 516 T lensqr = lengthsqr(); 517 if (lensqr > 0) 518 { 519 T coef = 1.0 / sqrt(lensqr); 520 foreach (ref component; arrayof) 521 component *= coef; 522 } 523 } 524 else 525 { 526 T lensqr = lengthsqr(); 527 if (lensqr > 0) 528 { 529 float coef = 1.0 / sqrt(cast(float)lensqr); 530 foreach (ref component; arrayof) 531 component = cast(T)(component * coef); 532 } 533 } 534 } 535 536 /** 537 * Return normalized copy 538 */ 539 @property Vector!(T,size) normalized() const 540 do 541 { 542 Vector!(T,size) res = this; 543 res.normalize(); 544 return res; 545 } 546 547 /** 548 * Return true if all components are zero 549 */ 550 @property bool isZero() const 551 do 552 { 553 foreach(i; RangeTuple!(0, size)) 554 if (arrayof[i] != 0) 555 return false; 556 return true; 557 } 558 559 /** 560 * Clamp components to min/max value 561 */ 562 void clamp(T minv, T maxv) 563 { 564 foreach (ref v; arrayof) 565 v = .clamp(v, minv, maxv); 566 } 567 } 568 569 /** 570 * Convert to string 571 */ 572 @property string toString() const 573 do 574 { 575 auto writer = appender!string(); 576 formattedWrite(writer, "%s", arrayof); 577 return writer.data; 578 } 579 580 /** 581 * Swizzling 582 */ 583 template opDispatch(string s) if (valid(s)) 584 { 585 static if (s.length <= 4) 586 { 587 private static auto extend(string s) 588 { 589 while (s.length < 4) 590 s ~= s[$-1]; 591 return s; 592 } 593 594 unittest 595 { 596 assert(extend("x") == "xxxx"); 597 } 598 599 @property auto ref opDispatch(this X)() 600 { 601 enum p = extend(s); 602 enum i = (char c) => ['x':0, 'y':1, 'z':2, 'w':3, 603 'r':0, 'g':1, 'b':2, 'a':3, 604 's':0, 't':1, 'p':2, 'q':3][c]; 605 enum i0 = i(p[0]), 606 i1 = i(p[1]), 607 i2 = i(p[2]), 608 i3 = i(p[3]); 609 610 static if (s.length == 4) 611 return Vector!(T,4)(arrayof[i0], arrayof[i1], arrayof[i2], arrayof[i3]); 612 else static if (s.length == 3) 613 return Vector!(T,3)(arrayof[i0], arrayof[i1], arrayof[i2]); 614 else static if (s.length == 2) 615 return Vector!(T,2)(arrayof[i0], arrayof[i1]); 616 } 617 } 618 } 619 620 private static bool valid(string s) 621 { 622 if (s.length < 2) 623 return false; 624 625 foreach(c; s) 626 { 627 switch(c) 628 { 629 case 'w', 'a', 'q': 630 if (size < 4) return false; 631 else break; 632 case 'z', 'b', 'p': 633 if (size < 3) return false; 634 else break; 635 case 'y', 'g', 't': 636 if (size < 2) return false; 637 else break; 638 case 'x', 'r', 's': 639 if (size < 1) return false; 640 else break; 641 default: 642 return false; 643 } 644 } 645 return true; 646 } 647 648 unittest 649 { 650 static if (size == 3) 651 { 652 assert(valid("xyz")); 653 assert(valid("rgb")); 654 assert(valid("stp")); 655 assert(!valid("m")); 656 assert(!valid("km")); 657 } 658 else static if (size == 3) 659 { 660 assert(valid("xyzw")); 661 assert(valid("rgba")); 662 assert(valid("stpq")); 663 } 664 } 665 666 /** 667 * Symbolic element access 668 */ 669 private static string elements(string[4] letters) @property 670 do 671 { 672 string res; 673 foreach (i; 0..size) 674 { 675 res ~= "T " ~ letters[i] ~ "; "; 676 } 677 return res; 678 } 679 680 unittest 681 { 682 static if (size == 3) 683 { 684 assert(elements(["x", "y", "z", "w"]) == "T x; T y; T z; "); 685 } 686 } 687 688 /** 689 * Vector components 690 */ 691 union 692 { 693 // Elements as static array 694 T[size] arrayof; 695 696 static if (size < 5) 697 { 698 /// Elements as x, y, z, w 699 struct { mixin(elements(["x", "y", "z", "w"])); } 700 701 /// Elements as r, g, b, a 702 struct { mixin(elements(["r", "g", "b", "a"])); } 703 704 /// Elements as s, t, p, q 705 struct { mixin(elements(["s", "t", "p", "q"])); } 706 } 707 } 708 } 709 710 /// 711 unittest 712 { 713 { 714 const vec3 a = vec3(10.5f, 20.0f, 33.12345f); 715 const vec3 b = -a; 716 const vec3 c = +a - b; 717 const vec3 d = a * b / c; 718 719 assert(isAlmostZero(to!vec3(c.toString()) - c)); 720 721 const vec3 v = vec3(10, 10, 10); 722 const vec3 vRes = (v / 10) * 2 - 1 + 5; 723 assert(isAlmostZero(vRes - vec3(6, 6, 6))); 724 assert(!vRes.isZero); 725 726 ivec2 ab = ivec2(5, 15); 727 ab += ivec2(20, 30); 728 ab *= 3; 729 730 assert(ab[0] == 75 && ab[1] == 135); 731 732 auto len = c.length(); 733 auto lensqr = c.lengthsqr(); 734 auto dist = distance(a, b); 735 736 auto xy = a[0..1]; 737 auto n = a[]; 738 739 vec3 v1 = vec3(2.0f, 0.0f, 1.0f); 740 ivec3 v2 = v1; 741 assert(ivec3(v1) == ivec3(2, 0, 1)); 742 743 vec3 v3 = [0, 2, 3.5]; 744 assert(v3 == vec3(0.0f, 2.0f, 3.5f)); 745 746 ivec3 v4 = [7, 8, 3]; 747 v4 %= 2; 748 assert(v4 == ivec3(1, 0, 1)); 749 } 750 751 { 752 Vector3f a = Vector3f(1, 2, 3); 753 Vector2f b = Vector2f(a); 754 assert(b == Vector2f(1, 2)); 755 } 756 757 { 758 Vector3f a = Vector3f([0, 1]); 759 assert(isNaN(a.z)); 760 } 761 762 { 763 Vector3f a = Vector3f(0, 1, 2); 764 a += 1; 765 assert(a == Vector3f(1, 2, 3)); 766 a *= 2; 767 assert(a == Vector3f(2, 4, 6)); 768 a -= 1; 769 assert(a == Vector3f(1, 3, 5)); 770 a /= 3; 771 assert(a.y == 1); 772 } 773 774 { 775 Vector3f a; 776 a[1] = 3; 777 assert(a.y == 3); 778 779 a[0..3] = 1; 780 assert(a == Vector3f(1, 1, 1)); 781 782 a[] = 0; 783 assert(a == Vector3f(0, 0, 0)); 784 } 785 786 { 787 Vector3i a = Vector3i(0, 0, 3); 788 a = a.normalized; 789 assert(a == Vector3i(0, 0, 1)); 790 assert(a.length == 1); 791 } 792 793 { 794 Vector3f a = Vector3f(0, 0, 0); 795 assert(a.isZero); 796 } 797 798 { 799 Vector3f a = Vector3f(2, -3, 0); 800 a.clamp(-1, 1); 801 assert(a == Vector3f(1, -1, 0)); 802 } 803 804 { 805 Vector3f a = Vector3f(2, 5, 7); 806 Vector4f b = Vector4f(a); 807 assert(b == Vector4f(2, 5, 7, float.nan)); 808 } 809 810 { 811 Vector3f a = Vector3f([0, 1]); 812 assert(a == Vector3f(0, 1, float.nan)); 813 814 Vector4f b = a.xyy; 815 assert(b == Vector4f(0, 1, 1, float.nan)); 816 } 817 818 { 819 Vector3f a = Vector3f(1, 2, 3); 820 a = a + 1; 821 assert(a == Vector3f(2, 3, 4)); 822 a = a * 2; 823 assert(a == Vector3f(4, 6, 8)); 824 a = a - 2; 825 assert(a == Vector3f(2, 4, 6)); 826 a = a / 2; 827 assert(a == Vector3f(1, 2, 3)); 828 829 Vector3f b = Vector3f(3, 2, 1); 830 b += a; 831 assert(b == Vector3f(4, 4, 4)); 832 b *= b; 833 assert(b == Vector3f(16, 16, 16)); 834 b /= Vector3f(8, 4, 2); 835 assert(b == Vector3f(2, 4, 8)); 836 b -= a; 837 assert(b == Vector3f(1, 2, 5)); 838 } 839 840 { 841 Vector3f v = Vector3f(0, 0, 0); 842 v[0] = 5; 843 v[1] = 2; 844 assert(v == Vector3f(5, 2, 0)); 845 v[1..3] = 12; 846 assert(v == Vector3f(5, 12, 12)); 847 v[] = 0; 848 assert(v == Vector3f(0, 0, 0)); 849 } 850 851 { 852 Vector4f a = Vector4f(2, 4, 6, 8); 853 Vector4f b = a.wxyz; 854 assert(b == Vector4f(8, 2, 4, 6)); 855 float d = dot(a, b); 856 assert(d == 96.0f); 857 } 858 859 { 860 Vector2f a = Vector2f(1, 2); 861 Vector2f b = Vector2f(2, 1); 862 float d = dot(a, b); 863 assert(d == 4.0f); 864 } 865 } 866 867 /** 868 * Dot product 869 */ 870 T dot(T, int size) (Vector!(T,size) a, Vector!(T,size) b) 871 do 872 { 873 static if (size == 1) 874 { 875 return a.x * b.x; 876 } 877 else 878 static if (size == 2) 879 { 880 return ((a.x * b.x) + (a.y * b.y)); 881 } 882 else 883 static if (size == 3) 884 { 885 return ((a.x * b.x) + (a.y * b.y) + (a.z * b.z)); 886 } 887 else 888 { 889 T d = 0; 890 //foreach (i; 0..size) 891 foreach(i; RangeTuple!(0, size)) 892 d += a[i] * b[i]; 893 return d; 894 } 895 } 896 897 /// 898 unittest 899 { 900 Vector3f v = Vector3f(1, 0, 0); 901 assert(dot(v, v) == 1); 902 903 Vector3f a = Vector3f(1, 2, 3, 4); 904 assert(dot(a, a) == 14); 905 } 906 907 /** 908 * Cross product 909 */ 910 Vector!(T,size) cross(T, int size) (Vector!(T,size) a, Vector!(T,size) b) if (size == 3) 911 do 912 { 913 return Vector!(T,size) 914 ( 915 (a.y * b.z) - (a.z * b.y), 916 (a.z * b.x) - (a.x * b.z), 917 (a.x * b.y) - (a.y * b.x) 918 ); 919 } 920 921 /** 922 * Cross product for 4-vectors 923 */ 924 Vector!(T,size) cross(T, int size) (Vector!(T,size) a, Vector!(T,size) b, Vector!(T,size) c) if (size == 4) 925 do 926 { 927 return Vector!(T,size) 928 ( 929 (a.y * b.z * c.w) - (a.y * b.w * c.z) 930 + (a.z * b.w * c.y) - (a.z * b.y * c.w) 931 + (a.w * b.y * c.z) - (a.w * b.z * c.y), 932 933 (a.z * b.w * c.x) - (a.z * b.x * c.w) 934 + (a.w * b.x * c.z) - (a.w * b.z * c.x) 935 + (a.x * b.z * c.w) - (a.x * b.w * c.z), 936 937 (a.w * b.x * c.y) - (a.w * b.y * c.x) 938 + (a.x * b.y * c.w) - (a.x * b.w * c.y) 939 + (a.y * b.w * c.x) - (a.y * b.x * c.w), 940 941 (a.x * b.y * c.z) - (a.x * b.z * c.y) 942 + (a.y * b.z * c.x) - (a.y * b.x * c.z) 943 + (a.z * b.x * c.y) - (a.z * b.y * c.x) 944 ); 945 } 946 947 /** 948 * Tensor product 949 */ 950 Matrix!(T,N) tensorProduct(T, size_t N) (Vector!(T,N) u, Vector!(T,N) v) 951 do 952 { 953 Matrix!(T,N) res; 954 foreach(i; 0..N) 955 foreach(j; 0..N) 956 { 957 res[i, j] = u[i] * v[j]; 958 } 959 return res; 960 } 961 962 alias outerProduct = tensorProduct; 963 964 /** 965 * Compute normal of a plane from three points 966 */ 967 Vector!(T,3) planeNormal(T) (Vector!(T,3) p1, Vector!(T,3) p2, Vector!(T,3) p3) 968 do 969 { 970 Vector!(T,3) vec1 = Vector!(T,3)(p1 - p2); 971 Vector!(T,3) vec2 = Vector!(T,3)(p1 - p3); 972 973 Vector!(T,3) result = Vector!(T,3)(cross(vec1,vec2)); 974 result.normalize(); 975 976 return result; 977 } 978 979 /// 980 unittest 981 { 982 Vector3f n = planeNormal( 983 Vector3f(0, 0, 0), 984 Vector3f(0, 0, 1), 985 Vector3f(1, 0, 0) 986 ); 987 assert(isAlmostZero(n - Vector3f(0, 1, 0))); 988 } 989 990 /** 991 * 992 */ 993 void rotateAroundAxis(T) (ref Vector!(T,3) V, Vector!(T,3) P, Vector!(T,3) D, T angle) 994 { 995 T axx,axy,axz,ax1; 996 T ayx,ayy,ayz,ay1; 997 T azx,azy,azz,az1; 998 999 T u,v,w; 1000 T u2,v2,w2; 1001 T a,b,c; 1002 1003 T sa,ca; 1004 1005 sa = sin(angle); 1006 ca = cos(angle); 1007 1008 u = D.x; 1009 v = D.y; 1010 w = D.z; 1011 1012 u2 = u * u; 1013 v2 = v * v; 1014 w2 = w * w; 1015 1016 a = P.x; 1017 b = P.y; 1018 c = P.z; 1019 1020 axx = u2+(v2+w2)*ca; 1021 axy = u*v*(1-ca)-w*sa; 1022 axz = u*w*(1-ca)+v*sa; 1023 ax1 = a*(v2+w2)-u*(b*v+c*w)+(u*(b*v+c*w)-a*(v2+w2))*ca+(b*w-c*v)*sa; 1024 1025 ayx = u*v*(1-ca)+w*sa; 1026 ayy = v2+(u2+w2)*ca; 1027 ayz = v*w*(1-ca)-u*sa; 1028 ay1 = b*(u2+w2)-v*(a*u+c*w)+(v*(a*u+c*w)-b*(u2+w2))*ca+(c*u-a*w)*sa; 1029 1030 azx = u*w*(1-ca)-v*sa; 1031 azy = v*w*(1-ca)+u*sa; 1032 azz = w2+(u2+v2)*ca; 1033 1034 az1 = c*(u2+v2)-w*(a*u+b*v)+(w*(a*u+b*v)-c*(u2+v2))*ca+(a*v-b*u)*sa; 1035 1036 Vector!(T,3) W; 1037 W.x = axx * V.x + axy * V.y + axz * V.z + ax1; 1038 W.y = ayx * V.x + ayy * V.y + ayz * V.z + ay1; 1039 W.z = azx * V.x + azy * V.y + azz * V.z + az1; 1040 1041 V = W; 1042 } 1043 1044 /** 1045 * Compute distance between two 2D points 1046 */ 1047 T distance(T) (Vector!(T,2) a, Vector!(T,2) b) 1048 do 1049 { 1050 T dx = a.x - b.x; 1051 T dy = a.y - b.y; 1052 return sqrt((dx * dx) + (dy * dy)); 1053 } 1054 1055 /** 1056 * Compute squared distance between two 2D points 1057 */ 1058 T distancesqr(T) (Vector!(T,2) a, Vector!(T,2) b) 1059 do 1060 { 1061 T dx = a.x - b.x; 1062 T dy = a.y - b.y; 1063 return ((dx * dx) + (dy * dy)); 1064 } 1065 1066 /** 1067 * Compute distance between two 3D points 1068 */ 1069 T distance(T) (Vector!(T,3) a, Vector!(T,3) b) 1070 do 1071 { 1072 T dx = a.x - b.x; 1073 T dy = a.y - b.y; 1074 T dz = a.z - b.z; 1075 return sqrt((dx * dx) + (dy * dy) + (dz * dz)); 1076 } 1077 1078 /** 1079 * Compute squared distance between two 3D points 1080 */ 1081 T distancesqr(T) (Vector!(T,3) a, Vector!(T,3) b) 1082 do 1083 { 1084 T dx = a.x - b.x; 1085 T dy = a.y - b.y; 1086 T dz = a.z - b.z; 1087 return ((dx * dx) + (dy * dy) + (dz * dz)); 1088 } 1089 1090 /** 1091 * Random unit length 2-vector 1092 */ 1093 Vector!(T,2) randomUnitVector2(T)() 1094 { 1095 float azimuth = uniform(0.0, 1.0) * 2 * PI; 1096 return Vector!(T,2)(cos(azimuth), sin(azimuth)); 1097 } 1098 1099 /** 1100 * Random unit length 3-vector 1101 */ 1102 Vector!(T,3) randomUnitVector3(T)() 1103 { 1104 float z = (2 * uniform(0.0, 1.0)) - 1; 1105 Vector!(T,2) planar = randomUnitVector2!(T)() * sqrt(1 - z * z); 1106 return Vector!(T,3)(planar.x, planar.y, z); 1107 } 1108 1109 /** 1110 * Spherical linear interpolation 1111 * (simple lerp is in dlib.math.interpolation) 1112 */ 1113 Vector!(T,3) slerp(T) (Vector!(T,3) a, Vector!(T,3) b, T t) 1114 { 1115 T dp = dot(a, b); 1116 dp = clamp(dp, -1.0, 1.0); 1117 T theta = acos(dp) * t; 1118 Vector!(T,3) relativeVec = b - a * dp; 1119 relativeVec.normalize(); 1120 return ((a * cos(theta)) + (relativeVec * sin(theta))); 1121 } 1122 1123 /** 1124 * Gradually decrease vector to zero length 1125 */ 1126 Vector!(T,3) vectorDecreaseToZero(T) (Vector!(T,3) vector, T step) 1127 { 1128 foreach (ref component; vector.arrayof) 1129 { 1130 if (component > 0.0) 1131 component -= step; 1132 if (component < 0.0) 1133 component += step; 1134 } 1135 return vector; 1136 } 1137 1138 /** 1139 * Is all elements almost zero 1140 */ 1141 bool isAlmostZero(Vector3f v) 1142 { 1143 return (isConsiderZero(v.x) && 1144 isConsiderZero(v.y) && 1145 isConsiderZero(v.z)); 1146 } 1147 1148 /** 1149 * 1150 */ 1151 Vector!(T,3) reflect(T)(Vector!(T,3) I, Vector!(T,3) N) 1152 { 1153 return I - N * dot(N, I) * 2.0; 1154 } 1155 1156 /** 1157 * 1158 */ 1159 Vector!(T,3) refract(T)(Vector!(T,3) I, Vector!(T,3) N, T r) 1160 { 1161 T d = 1.0 - r * r * (1.0 - dot(N, I) * dot(N, I)); 1162 if (d < 0.0) 1163 return Vector!(T,3)(0.0, 0.0, 0.0); 1164 return I * r - N * (r * dot(N, I) + sqrt(d)); 1165 } 1166 1167 /** 1168 * 1169 */ 1170 Vector!(T,3) faceforward(T)(Vector!(T,3) N, Vector!(T,3) I, Vector!(T,3) Nref) 1171 { 1172 return dot(Nref, I) < 0.0 ? N : -N; 1173 } 1174 1175 /** 1176 * Predefined vector types 1177 */ 1178 /// Alias for 2-vector of ints 1179 alias Vector2i = Vector!(int, 2); 1180 /// Alias for 2-vector of uints 1181 alias Vector2u = Vector!(uint, 2); 1182 /// Alias for 2-vector of floats 1183 alias Vector2f = Vector!(float, 2); 1184 /// Alias for 2-vector of doubles 1185 alias Vector2d = Vector!(double, 2); 1186 1187 /// Alias for 3-vector of ints 1188 alias Vector3i = Vector!(int, 3); 1189 /// Alias for 3-vector of uints 1190 alias Vector3u = Vector!(uint, 3); 1191 /// Alias for 3-vector of floats 1192 alias Vector3f = Vector!(float, 3); 1193 /// Alias for 2-vector of doubles 1194 alias Vector3d = Vector!(double, 3); 1195 1196 /// Alias for 4-vector of ints 1197 alias Vector4i = Vector!(int, 4); 1198 /// Alias for 4-vector of uints 1199 alias Vector4u = Vector!(uint, 4); 1200 /// Alias for 4-vector of floats 1201 alias Vector4f = Vector!(float, 4); 1202 /// Alias for 4-vector of doubles 1203 alias Vector4d = Vector!(double, 4); 1204 1205 /** 1206 * GLSL-like short aliases 1207 */ 1208 alias ivec2 = Vector2i; 1209 alias uvec2 = Vector2u; 1210 alias vec2 = Vector2f; 1211 alias dvec2 = Vector2d; 1212 1213 alias ivec3 = Vector3i; 1214 alias uvec3 = Vector3u; 1215 alias vec3 = Vector3f; 1216 alias dvec3 = Vector3d; 1217 1218 alias ivec4 = Vector4i; 1219 alias uvec4 = Vector4u; 1220 alias vec4 = Vector4f; 1221 alias dvec4 = Vector4d; 1222 1223 /** 1224 * Axis vectors 1225 */ 1226 static struct AxisVector 1227 { 1228 Vector3f x = Vector3f(1.0f, 0.0f, 0.0f); 1229 Vector3f y = Vector3f(0.0f, 1.0f, 0.0f); 1230 Vector3f z = Vector3f(0.0f, 0.0f, 1.0f); 1231 } 1232 1233 /** 1234 * Vector factory function 1235 */ 1236 auto vectorf(T...)(T t) if (t.length > 0) 1237 { 1238 return Vector!(float, t.length)(t); 1239 } 1240 1241 /** 1242 * L-value pseudovector for assignment purposes. 1243 * 1244 * Examples: 1245 * -------------------- 1246 * float a, b, c; 1247 * lvector(a, b, c) = Vector3f(10, 4, 2); 1248 * -------------------- 1249 */ 1250 auto lvector(T...)(ref T x) 1251 { 1252 struct Result(T, uint size) 1253 { 1254 T*[size] arrayof; 1255 1256 void opAssign(int size2)(Vector!(T,size2) v) 1257 { 1258 if (v.arrayof.length >= size) 1259 foreach(i; 0..size) 1260 *arrayof[i] = v.arrayof[i]; 1261 else 1262 foreach(i; 0..v.arrayof.length) 1263 *arrayof[i] = v.arrayof[i]; 1264 } 1265 } 1266 1267 auto res = Result!(typeof(x[0]), x.length)(); 1268 1269 foreach(i, ref v; x) 1270 res.arrayof[i] = &v; 1271 1272 return res; 1273 }