1 /** 2 * Contains the definition of a 2x2 matrix of doubles, and associated functions to transform 3 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this: 4 * <p> 5 * m00 m10<br> 6 * m01 m11<br> 7 * 8 * @author Joseph Burton 9 */ 10 module doml.matrix_2d; 11 12 import Math = doml.math; 13 import MemUtil = doml.mem_util; 14 15 import doml.matrix_3d; 16 import doml.matrix_3x2d; 17 18 import doml.vector_2d; 19 20 21 /* 22 * The MIT License 23 * 24 * Copyright (c) 2020-2021 JOML 25 %%$%# translated by jordan4ibanez 26 * 27 * Permission is hereby granted, free of charge, to any person obtaining a copy 28 * of this software and associated documentation files (the "Software"), to deal 29 * in the Software without restriction, including without limitation the rights 30 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 31 * copies of the Software, and to permit persons to whom the Software is 32 * furnished to do so, subject to the following conditions: 33 * 34 * The above copyright notice and this permission notice shall be included in 35 * all copies or substantial portions of the Software. 36 * 37 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 38 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 39 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 40 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 41 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 42 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 43 * THE SOFTWARE. 44 */ 45 46 47 /** 48 * Contains the definition of a 2x2 matrix of doubles, and associated functions to transform 49 * it. The matrix is column-major to match OpenGL's interpretation, and it looks like this: 50 * <p> 51 * m00 m10<br> 52 * m01 m11<br> 53 * 54 * @author Joseph Burton 55 */ 56 public struct Matrix2d { 57 58 // Defaults to identity 59 double m00 = 1.0; 60 double m01 = 0.0; 61 double m10 = 0.0; 62 double m11 = 1.0; 63 64 65 /** 66 * Create a new {@link Matrix2d} and make it a copy of the given matrix. 67 * 68 * @param mat 69 * the {@link Matrix2d} to copy the values from 70 */ 71 this(Matrix2d mat) { 72 setMatrix2d(mat); 73 } 74 75 76 /** 77 * Create a new {@link Matrix2d} and make it a copy of the upper left 2x2 of the given {@link Matrix3d}. 78 * 79 * @param mat 80 * the {@link Matrix3d} to copy the values from 81 */ 82 this(Matrix3d mat) { 83 setMatrix3d(mat); 84 } 85 86 87 /** 88 * Create a new 2x2 matrix using the supplied double values. The order of the parameter is column-major, 89 * so the first two parameters specify the two elements of the first column. 90 * 91 * @param m00 92 * the value of m00 93 * @param m01 94 * the value of m01 95 * @param m10 96 * the value of m10 97 * @param m11 98 * the value of m11 99 */ 100 this(double m00, double m01, 101 double m10, double m11) { 102 this.m00 = m00; 103 this.m01 = m01; 104 this.m10 = m10; 105 this.m11 = m11; 106 } 107 108 /** 109 * Create a new {@link Matrix2d} and initialize its two columns using the supplied vectors. 110 * 111 * @param col0 112 * the first column 113 * @param col1 114 * the second column 115 */ 116 this(Vector2d col0, Vector2d col1) { 117 m00 = col0.x; 118 m01 = col0.y; 119 m10 = col1.x; 120 m11 = col1.y; 121 } 122 123 /** 124 * Set the value of the matrix element at column 0 and row 0. 125 * 126 * @param m00 127 * the new value 128 * @return this 129 */ 130 ref public Matrix2d setm00(double m00) return { 131 this.m00 = m00; 132 return this; 133 } 134 /** 135 * Set the value of the matrix element at column 0 and row 1. 136 * 137 * @param m01 138 * the new value 139 * @return this 140 */ 141 ref public Matrix2d setm01(double m01) return { 142 this.m01 = m01; 143 return this; 144 } 145 /** 146 * Set the value of the matrix element at column 1 and row 0. 147 * 148 * @param m10 149 * the new value 150 * @return this 151 */ 152 ref public Matrix2d setm10(double m10) return { 153 this.m10 = m10; 154 return this; 155 } 156 /** 157 * Set the value of the matrix element at column 1 and row 1. 158 * 159 * @param m11 160 * the new value 161 * @return this 162 */ 163 ref public Matrix2d setm11(double m11) return { 164 this.m11 = m11; 165 return this; 166 } 167 168 /** 169 * Set the value of the matrix element at column 0 and row 0. 170 * 171 * @param m00 172 * the new value 173 * @return this 174 */ 175 ref Matrix2d _m00(double m00) return { 176 this.m00 = m00; 177 return this; 178 } 179 /** 180 * Set the value of the matrix element at column 0 and row 1. 181 * 182 * @param m01 183 * the new value 184 * @return this 185 */ 186 ref Matrix2d _m01(double m01) return { 187 this.m01 = m01; 188 return this; 189 } 190 /** 191 * Set the value of the matrix element at column 1 and row 0. 192 * 193 * @param m10 194 * the new value 195 * @return this 196 */ 197 ref Matrix2d _m10(double m10) return { 198 this.m10 = m10; 199 return this; 200 } 201 /** 202 * Set the value of the matrix element at column 1 and row 1. 203 * 204 * @param m11 205 * the new value 206 * @return this 207 */ 208 ref Matrix2d _m11(double m11) return { 209 this.m11 = m11; 210 return this; 211 } 212 213 /** 214 * Set the elements of this matrix to the ones in <code>m</code>. 215 * 216 * @param m 217 * the matrix to copy the elements from 218 * @return this 219 */ 220 ref public Matrix2d set(Matrix2d m) return { 221 setMatrix2d(m); 222 return this; 223 } 224 private void setMatrix2d(Matrix2d mat) { 225 m00 = mat.m00; 226 m01 = mat.m01; 227 m10 = mat.m10; 228 m11 = mat.m11; 229 } 230 231 232 /** 233 * Set the elements of this matrix to the left 2x2 submatrix of <code>m</code>. 234 * 235 * @param m 236 * the matrix to copy the elements from 237 * @return this 238 */ 239 ref public Matrix2d set(Matrix3x2d m) return { 240 setMatrix3x2d(m); 241 return this; 242 } 243 private void setMatrix3x2d(Matrix3x2d mat) { 244 m00 = mat.m00; 245 m01 = mat.m01; 246 m10 = mat.m10; 247 m11 = mat.m11; 248 } 249 250 /** 251 * Set the elements of this matrix to the upper left 2x2 of the given {@link Matrix3d}. 252 * 253 * @param m 254 * the {@link Matrix3d} to copy the values from 255 * @return this 256 */ 257 ref public Matrix2d set(Matrix3d m) return { 258 setMatrix3d(m); 259 return this; 260 } 261 private void setMatrix3d(Matrix3d mat) { 262 m00 = mat.m00; 263 m01 = mat.m01; 264 m10 = mat.m10; 265 m11 = mat.m11; 266 } 267 268 269 /** 270 * Multiply this matrix by the supplied <code>right</code> matrix. 271 * <p> 272 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the <code>right</code> matrix, 273 * then the new matrix will be <code>M * R</code>. So when transforming a 274 * vector <code>v</code> with the new matrix by using <code>M * R * v</code>, the 275 * transformation of the right matrix will be applied first! 276 * 277 * @param right 278 * the right operand of the matrix multiplication 279 * @return this 280 */ 281 ref public Matrix2d mul(Matrix2d right) return { 282 this.mul(right, this); 283 return this; 284 } 285 286 public Matrix2d mul(Matrix2d right, ref Matrix2d dest) { 287 double nm00 = m00 * right.m00 + m10 * right.m01; 288 double nm01 = m01 * right.m00 + m11 * right.m01; 289 double nm10 = m00 * right.m10 + m10 * right.m11; 290 double nm11 = m01 * right.m10 + m11 * right.m11; 291 dest.m00 = nm00; 292 dest.m01 = nm01; 293 dest.m10 = nm10; 294 dest.m11 = nm11; 295 return dest; 296 } 297 298 /** 299 * Pre-multiply this matrix by the supplied <code>left</code> matrix and store the result in <code>this</code>. 300 * <p> 301 * If <code>M</code> is <code>this</code> matrix and <code>L</code> the <code>left</code> matrix, 302 * then the new matrix will be <code>L * M</code>. So when transforming a 303 * vector <code>v</code> with the new matrix by using <code>L * M * v</code>, the 304 * transformation of <code>this</code> matrix will be applied first! 305 * 306 * @param left 307 * the left operand of the matrix multiplication 308 * @return this 309 */ 310 ref public Matrix2d mulLocal(Matrix2d left) return { 311 this.mulLocal(left, this); 312 return this; 313 } 314 315 public Matrix2d mulLocal(Matrix2d left, ref Matrix2d dest) { 316 double nm00 = left.m00 * m00 + left.m10 * m01; 317 double nm01 = left.m01 * m00 + left.m11 * m01; 318 double nm10 = left.m00 * m10 + left.m10 * m11; 319 double nm11 = left.m01 * m10 + left.m11 * m11; 320 dest.m00 = nm00; 321 dest.m01 = nm01; 322 dest.m10 = nm10; 323 dest.m11 = nm11; 324 return dest; 325 } 326 327 /** 328 * Set the values within this matrix to the supplied double values. The result looks like this: 329 * <p> 330 * m00, m10<br> 331 * m01, m11<br> 332 * 333 * @param m00 334 * the new value of m00 335 * @param m01 336 * the new value of m01 337 * @param m10 338 * the new value of m10 339 * @param m11 340 * the new value of m11 341 * @return this 342 */ 343 ref public Matrix2d set(double m00, double m01, 344 double m10, double m11) return { 345 this.m00 = m00; 346 this.m01 = m01; 347 this.m10 = m10; 348 this.m11 = m11; 349 return this; 350 } 351 /** 352 * Set the two columns of this matrix to the supplied vectors, respectively. 353 * 354 * @param col0 355 * the first column 356 * @param col1 357 * the second column 358 * @return this 359 */ 360 ref public Matrix2d set(Vector2d col0, Vector2d col1) return { 361 m00 = col0.x; 362 m01 = col0.y; 363 m10 = col1.x; 364 m11 = col1.y; 365 return this; 366 } 367 368 public double determinant() { 369 return m00 * m11 - m10 * m01; 370 } 371 372 /** 373 * Invert this matrix. 374 * 375 * @return this 376 */ 377 ref public Matrix2d invert() return { 378 this.invert(this); 379 return this; 380 } 381 382 public Matrix2d invert(ref Matrix2d dest) { 383 double s = 1.0 / determinant(); 384 double nm00 = m11 * s; 385 double nm01 = -m01 * s; 386 double nm10 = -m10 * s; 387 double nm11 = m00 * s; 388 dest.m00 = nm00; 389 dest.m01 = nm01; 390 dest.m10 = nm10; 391 dest.m11 = nm11; 392 return dest; 393 } 394 395 /** 396 * Transpose this matrix. 397 * 398 * @return this 399 */ 400 ref public Matrix2d transpose() return { 401 this.transpose(this); 402 return this; 403 } 404 405 public Matrix2d transpose(ref Matrix2d dest) { 406 dest.set(m00, m10, 407 m01, m11); 408 return dest; 409 } 410 411 412 /** 413 * Get the current values of <code>this</code> matrix and store them into 414 * <code>dest</code>. 415 * <p> 416 * This is the reverse method of {@link #set(Matrix2d)} and allows to obtain 417 * intermediate calculation results when chaining multiple transformations. 418 * 419 * @see #set(Matrix2d) 420 * 421 * @param dest 422 * the destination matrix 423 * @return the passed in destination 424 */ 425 public Matrix2d get(ref Matrix2d dest) { 426 return dest.set(this); 427 } 428 429 public Matrix3x2d get(ref Matrix3x2d dest) { 430 return dest.set(this); 431 } 432 433 public Matrix3d get(ref Matrix3d dest) { 434 return dest.set(this); 435 } 436 437 public double getRotation() { 438 return cast(double) Math.atan2(m01, m11); 439 } 440 441 /** 442 * Set all values within this matrix to zero. 443 * 444 * @return this 445 */ 446 ref public Matrix2d zero() return { 447 MemUtil.zero(this); 448 return this; 449 } 450 451 /** 452 * Set this matrix to the identity. 453 * 454 * @return this 455 */ 456 ref public Matrix2d identity() return { 457 m00 = 1.0; 458 m01 = 0.0; 459 m10 = 0.0; 460 m11 = 1.0; 461 return this; 462 } 463 464 public Matrix2d scale(Vector2d xy, ref Matrix2d dest) { 465 return scale(xy.x, xy.y, dest); 466 } 467 468 /** 469 * Apply scaling to this matrix by scaling the base axes by the given <code>xy.x</code> and 470 * <code>xy.y</code> factors, respectively. 471 * <p> 472 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 473 * then the new matrix will be <code>M * S</code>. So when transforming a 474 * vector <code>v</code> with the new matrix by using <code>M * S * v</code>, the 475 * scaling will be applied first! 476 * 477 * @param xy 478 * the factors of the x and y component, respectively 479 * @return this 480 */ 481 ref public Matrix2d scale(Vector2d xy) return { 482 this.scale(xy.x, xy.y, this); 483 return this; 484 } 485 486 public Matrix2d scale(double x, double y, ref Matrix2d dest) { 487 // scale matrix elements: 488 // m00 = x, m11 = y 489 // all others = 0 490 dest.m00 = m00 * x; 491 dest.m01 = m01 * x; 492 dest.m10 = m10 * y; 493 dest.m11 = m11 * y; 494 return dest; 495 } 496 497 /** 498 * Apply scaling to this matrix by scaling the base axes by the given x and 499 * y factors. 500 * <p> 501 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 502 * then the new matrix will be <code>M * S</code>. So when transforming a 503 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 504 * , the scaling will be applied first! 505 * 506 * @param x 507 * the factor of the x component 508 * @param y 509 * the factor of the y component 510 * @return this 511 */ 512 ref public Matrix2d scale(double x, double y) return { 513 this.scale(x, y, this); 514 return this; 515 } 516 517 public Matrix2d scale(double xy, ref Matrix2d dest) { 518 return scale(xy, xy, dest); 519 } 520 521 /** 522 * Apply scaling to this matrix by uniformly scaling all base axes by the given <code>xy</code> factor. 523 * <p> 524 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 525 * then the new matrix will be <code>M * S</code>. So when transforming a 526 * vector <code>v</code> with the new matrix by using <code>M * S * v</code> 527 * , the scaling will be applied first! 528 * 529 * @see #scale(double, double) 530 * 531 * @param xy 532 * the factor for all components 533 * @return this 534 */ 535 ref public Matrix2d scale(double xy) return { 536 return scale(xy, xy); 537 } 538 539 public Matrix2d scaleLocal(double x, double y, ref Matrix2d dest) { 540 dest.m00 = x * m00; 541 dest.m01 = y * m01; 542 dest.m10 = x * m10; 543 dest.m11 = y * m11; 544 return dest; 545 } 546 547 /** 548 * Pre-multiply scaling to this matrix by scaling the base axes by the given x and 549 * y factors. 550 * <p> 551 * If <code>M</code> is <code>this</code> matrix and <code>S</code> the scaling matrix, 552 * then the new matrix will be <code>S * M</code>. So when transforming a 553 * vector <code>v</code> with the new matrix by using <code>S * M * v</code>, the 554 * scaling will be applied last! 555 * 556 * @param x 557 * the factor of the x component 558 * @param y 559 * the factor of the y component 560 * @return this 561 */ 562 ref public Matrix2d scaleLocal(double x, double y) return { 563 this.scaleLocal(x, y, this); 564 return this; 565 } 566 567 /** 568 * Set this matrix to be a simple scale matrix, which scales all axes uniformly by the given factor. 569 * <p> 570 * The resulting matrix can be multiplied against another transformation 571 * matrix to obtain an additional scaling. 572 * <p> 573 * In order to post-multiply a scaling transformation directly to a 574 * matrix, use {@link #scale(double) scale()} instead. 575 * 576 * @see #scale(double) 577 * 578 * @param factor 579 * the scale factor in x and y 580 * @return this 581 */ 582 ref public Matrix2d scaling(double factor) return { 583 MemUtil.zero(this); 584 m00 = factor; 585 m11 = factor; 586 return this; 587 } 588 589 /** 590 * Set this matrix to be a simple scale matrix. 591 * 592 * @param x 593 * the scale in x 594 * @param y 595 * the scale in y 596 * @return this 597 */ 598 ref public Matrix2d scaling(double x, double y) return { 599 MemUtil.zero(this); 600 m00 = x; 601 m11 = y; 602 return this; 603 } 604 605 /** 606 * Set this matrix to be a simple scale matrix which scales the base axes by <code>xy.x</code> and <code>xy.y</code> respectively. 607 * <p> 608 * The resulting matrix can be multiplied against another transformation 609 * matrix to obtain an additional scaling. 610 * <p> 611 * In order to post-multiply a scaling transformation directly to a 612 * matrix use {@link #scale(Vector2d) scale()} instead. 613 * 614 * @see #scale(Vector2d) 615 * 616 * @param xy 617 * the scale in x and y respectively 618 * @return this 619 */ 620 ref public Matrix2d scaling(Vector2d xy) return { 621 return scaling(xy.x, xy.y); 622 } 623 624 /** 625 * Set this matrix to a rotation matrix which rotates the given radians about the origin. 626 * <p> 627 * The produced rotation will rotate a vector counter-clockwise around the origin. 628 * <p> 629 * The resulting matrix can be multiplied against another transformation 630 * matrix to obtain an additional rotation. 631 * <p> 632 * In order to post-multiply a rotation transformation directly to a 633 * matrix, use {@link #rotate(double) rotate()} instead. 634 * 635 * @see #rotate(double) 636 * 637 * @param angle 638 * the angle in radians 639 * @return this 640 */ 641 ref public Matrix2d rotation(double angle) return { 642 double sin = Math.sin(angle); 643 double cos = Math.cosFromSin(sin, angle); 644 m00 = cos; 645 m01 = sin; 646 m10 = -sin; 647 m11 = cos; 648 return this; 649 } 650 651 public Vector2d transform(Vector2d v) { 652 return v.mul(this); 653 } 654 655 public Vector2d transform(Vector2d v, ref Vector2d dest) { 656 v.mul(this, dest); 657 return dest; 658 } 659 660 public Vector2d transform(double x, double y, ref Vector2d dest) { 661 dest.set(m00 * x + m10 * y, 662 m01 * x + m11 * y); 663 return dest; 664 } 665 666 public Vector2d transformTranspose(Vector2d v) { 667 return v.mulTranspose(this); 668 } 669 670 public Vector2d transformTranspose(Vector2d v, ref Vector2d dest) { 671 v.mulTranspose(this, dest); 672 return dest; 673 } 674 675 public Vector2d transformTranspose(double x, double y, ref Vector2d dest) { 676 dest.set(m00 * x + m01 * y, 677 m10 * x + m11 * y); 678 return dest; 679 } 680 681 /** 682 * Apply rotation about the origin to this matrix by rotating the given amount of radians. 683 * <p> 684 * The produced rotation will rotate a vector counter-clockwise around the origin. 685 * <p> 686 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 687 * then the new matrix will be <code>M * R</code>. So when transforming a 688 * vector <code>v</code> with the new matrix by using <code>M * R * v</code> 689 * , the rotation will be applied first! 690 * <p> 691 * Reference: <a href="https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions">http://en.wikipedia.org</a> 692 * 693 * @param angle 694 * the angle in radians 695 * @return this 696 */ 697 ref public Matrix2d rotate(double angle) return { 698 this.rotate(angle, this); 699 return this; 700 } 701 702 public Matrix2d rotate(double angle, ref Matrix2d dest) { 703 double s = Math.sin(angle); 704 double c = Math.cosFromSin(s, angle); 705 // rotation matrix elements: 706 // m00 = c, m01 = s, m10 = -s, m11 = c 707 double nm00 = m00 * c + m10 * s; 708 double nm01 = m01 * c + m11 * s; 709 double nm10 = m10 * c - m00 * s; 710 double nm11 = m11 * c - m01 * s; 711 dest.m00 = nm00; 712 dest.m01 = nm01; 713 dest.m10 = nm10; 714 dest.m11 = nm11; 715 return dest; 716 } 717 718 /** 719 * Pre-multiply a rotation to this matrix by rotating the given amount of radians about the origin. 720 * <p> 721 * The produced rotation will rotate a vector counter-clockwise around the origin. 722 * <p> 723 * If <code>M</code> is <code>this</code> matrix and <code>R</code> the rotation matrix, 724 * then the new matrix will be <code>R * M</code>. So when transforming a 725 * vector <code>v</code> with the new matrix by using <code>R * M * v</code>, the 726 * rotation will be applied last! 727 * <p> 728 * In order to set the matrix to a rotation matrix without pre-multiplying the rotation 729 * transformation, use {@link #rotation(double) rotation()}. 730 * <p> 731 * Reference: <a href="https://en.wikipedia.org/wiki/Rotation_matrix#In_two_dimensions">http://en.wikipedia.org</a> 732 * 733 * @see #rotation(double) 734 * 735 * @param angle 736 * the angle in radians to rotate about the X axis 737 * @return this 738 */ 739 ref public Matrix2d rotateLocal(double angle) return { 740 this.rotateLocal(angle, this); 741 return this; 742 } 743 744 public Matrix2d rotateLocal(double angle, ref Matrix2d dest) { 745 double s = Math.sin(angle); 746 double c = Math.cosFromSin(s, angle); 747 // rotation matrix elements: 748 // m00 = c, m01 = s, m10 = -s, m11 = c 749 double nm00 = c * m00 - s * m01; 750 double nm01 = s * m00 + c * m01; 751 double nm10 = c * m10 - s * m11; 752 double nm11 = s * m10 + c * m11; 753 dest.m00 = nm00; 754 dest.m01 = nm01; 755 dest.m10 = nm10; 756 dest.m11 = nm11; 757 return dest; 758 } 759 760 public Vector2d getRow(int row, ref Vector2d dest) { 761 switch (row) { 762 case 0: 763 dest.x = m00; 764 dest.y = m10; 765 break; 766 case 1: 767 dest.x = m01; 768 dest.y = m11; 769 break; 770 default: {} 771 } 772 return dest; 773 } 774 775 /** 776 * Set the row at the given <code>row</code> index, starting with <code>0</code>. 777 * 778 * @param row 779 * the row index in <code>[0..1]</code> 780 * @param src 781 * the row components to set 782 * @return this 783 * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..1]</code> 784 */ 785 ref public Matrix2d setRow(int row, Vector2d src) return { 786 return setRow(row, src.x, src.y); 787 } 788 789 /** 790 * Set the row at the given <code>row</code> index, starting with <code>0</code>. 791 * 792 * @param row 793 * the row index in <code>[0..1]</code> 794 * @param x 795 * the first element in the row 796 * @param y 797 * the second element in the row 798 * @return this 799 * @throws IndexOutOfBoundsException if <code>row</code> is not in <code>[0..1]</code> 800 */ 801 ref public Matrix2d setRow(int row, double x, double y) return { 802 switch (row) { 803 case 0: 804 this.m00 = x; 805 this.m10 = y; 806 break; 807 case 1: 808 this.m01 = x; 809 this.m11 = y; 810 break; 811 default:{} 812 } 813 return this; 814 } 815 816 public Vector2d getColumn(int column, ref Vector2d dest){ 817 switch (column) { 818 case 0: 819 dest.x = m00; 820 dest.y = m01; 821 break; 822 case 1: 823 dest.x = m10; 824 dest.y = m11; 825 break; 826 default:{} 827 } 828 return dest; 829 } 830 831 /** 832 * Set the column at the given <code>column</code> index, starting with <code>0</code>. 833 * 834 * @param column 835 * the column index in <code>[0..1]</code> 836 * @param src 837 * the column components to set 838 * @return this 839 * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..1]</code> 840 */ 841 ref public Matrix2d setColumn(int column, Vector2d src) return { 842 return setColumn(column, src.x, src.y); 843 } 844 845 /** 846 * Set the column at the given <code>column</code> index, starting with <code>0</code>. 847 * 848 * @param column 849 * the column index in <code>[0..1]</code> 850 * @param x 851 * the first element in the column 852 * @param y 853 * the second element in the column 854 * @return this 855 * @throws IndexOutOfBoundsException if <code>column</code> is not in <code>[0..1]</code> 856 */ 857 ref public Matrix2d setColumn(int column, double x, double y) return { 858 switch (column) { 859 case 0: 860 this.m00 = x; 861 this.m01 = y; 862 break; 863 case 1: 864 this.m10 = x; 865 this.m11 = y; 866 break; 867 default: {} 868 } 869 return this; 870 } 871 872 public double get(int column, int row) { 873 switch (column) { 874 case 0: 875 switch (row) { 876 case 0: 877 return m00; 878 case 1: 879 return m01; 880 default: 881 break; 882 } 883 break; 884 case 1: 885 switch (row) { 886 case 0: 887 return m10; 888 case 1: 889 return m11; 890 default: 891 break; 892 } 893 break; 894 default:{} 895 } 896 return 0; 897 } 898 899 /** 900 * Set the matrix element at the given column and row to the specified value. 901 * 902 * @param column 903 * the colum index in <code>[0..1]</code> 904 * @param row 905 * the row index in <code>[0..1]</code> 906 * @param value 907 * the value 908 * @return this 909 */ 910 ref public Matrix2d set(int column, int row, double value) return { 911 switch (column) { 912 case 0: 913 switch (row) { 914 case 0: 915 this.m00 = value; 916 return this; 917 case 1: 918 this.m01 = value; 919 return this; 920 default: 921 break; 922 } 923 break; 924 case 1: 925 switch (row) { 926 case 0: 927 this.m10 = value; 928 return this; 929 case 1: 930 this.m11 = value; 931 return this; 932 default: 933 break; 934 } 935 break; 936 default:{} 937 } 938 return this; 939 } 940 941 /** 942 * Set <code>this</code> matrix to its own normal matrix. 943 * <p> 944 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 945 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 946 * In this case, use {@link #set(Matrix2d)} to set a given Matrix2d to this matrix. 947 * 948 * @see #set(Matrix2d) 949 * 950 * @return this 951 */ 952 ref public Matrix2d normal() return { 953 this.normal(this); 954 return this; 955 } 956 957 /** 958 * Compute a normal matrix from <code>this</code> matrix and store it into <code>dest</code>. 959 * <p> 960 * Please note that, if <code>this</code> is an orthogonal matrix or a matrix whose columns are orthogonal vectors, 961 * then this method <i>need not</i> be invoked, since in that case <code>this</code> itself is its normal matrix. 962 * In this case, use {@link #set(Matrix2d)} to set a given Matrix2d to this matrix. 963 * 964 * @see #set(Matrix2d) 965 * 966 * @param dest 967 * will hold the result 968 * @return dest 969 */ 970 public Matrix2d normal(ref Matrix2d dest) { 971 double det = m00 * m11 - m10 * m01; 972 double s = 1.0 / det; 973 /* Invert and transpose in one go */ 974 double nm00 = m11 * s; 975 double nm01 = -m10 * s; 976 double nm10 = -m01 * s; 977 double nm11 = m00 * s; 978 dest.m00 = nm00; 979 dest.m01 = nm01; 980 dest.m10 = nm10; 981 dest.m11 = nm11; 982 return dest; 983 } 984 985 public Vector2d getScale(ref Vector2d dest) { 986 dest.x = Math.sqrt(m00 * m00 + m01 * m01); 987 dest.y = Math.sqrt(m10 * m10 + m11 * m11); 988 return dest; 989 } 990 991 public Vector2d positiveX(Vector2d dir) { 992 if (m00 * m11 < m01 * m10) { // negative determinant? 993 dir.x = -m11; 994 dir.y = m01; 995 } else { 996 dir.x = m11; 997 dir.y = -m01; 998 } 999 return dir.normalize(dir); 1000 } 1001 1002 public Vector2d normalizedPositiveX(Vector2d dir) { 1003 if (m00 * m11 < m01 * m10) { // negative determinant? 1004 dir.x = -m11; 1005 dir.y = m01; 1006 } else { 1007 dir.x = m11; 1008 dir.y = -m01; 1009 } 1010 return dir; 1011 } 1012 1013 public Vector2d positiveY(Vector2d dir) { 1014 if (m00 * m11 < m01 * m10) { // negative determinant? 1015 dir.x = m10; 1016 dir.y = -m00; 1017 } else { 1018 dir.x = -m10; 1019 dir.y = m00; 1020 } 1021 return dir.normalize(dir); 1022 } 1023 1024 public Vector2d normalizedPositiveY(Vector2d dir) { 1025 if (m00 * m11 < m01 * m10) { // negative determinant? 1026 dir.x = m10; 1027 dir.y = -m00; 1028 } else { 1029 dir.x = -m10; 1030 dir.y = m00; 1031 } 1032 return dir; 1033 } 1034 1035 public int hashCode() { 1036 immutable int prime = 31; 1037 int result = 1; 1038 long temp; 1039 temp = Math.doubleToLongBits(m00); 1040 result = prime * result + cast(int) ((temp >>> 32) ^ temp); 1041 temp = Math.doubleToLongBits(m01); 1042 result = prime * result + cast(int) ((temp >>> 32) ^ temp); 1043 temp = Math.doubleToLongBits(m10); 1044 result = prime * result + cast(int) ((temp >>> 32) ^ temp); 1045 temp = Math.doubleToLongBits(m11); 1046 result = prime * result + cast(int) ((temp >>> 32) ^ temp); 1047 return result; 1048 } 1049 1050 public bool equals(Matrix2d m, double delta) { 1051 if (this == m) 1052 return true; 1053 if (!Math.equals(m00, m.m00, delta)) 1054 return false; 1055 if (!Math.equals(m01, m.m01, delta)) 1056 return false; 1057 if (!Math.equals(m10, m.m10, delta)) 1058 return false; 1059 if (!Math.equals(m11, m.m11, delta)) 1060 return false; 1061 return true; 1062 } 1063 1064 /** 1065 * Exchange the values of <code>this</code> matrix with the given <code>other</code> matrix. 1066 * 1067 * @param other 1068 * the other matrix to exchange the values with 1069 * @return this 1070 */ 1071 ref public Matrix2d swap(ref Matrix2d other) return { 1072 MemUtil.swap(this, other); 1073 return this; 1074 } 1075 1076 /** 1077 * Component-wise add <code>this</code> and <code>other</code>. 1078 * 1079 * @param other 1080 * the other addend 1081 * @return this 1082 */ 1083 ref public Matrix2d add(Matrix2d other) return { 1084 this.add(other, this); 1085 return this; 1086 } 1087 1088 public Matrix2d add(Matrix2d other, ref Matrix2d dest) { 1089 dest.m00 = m00 + other.m00; 1090 dest.m01 = m01 + other.m01; 1091 dest.m10 = m10 + other.m10; 1092 dest.m11 = m11 + other.m11; 1093 return dest; 1094 } 1095 1096 /** 1097 * Component-wise subtract <code>subtrahend</code> from <code>this</code>. 1098 * 1099 * @param subtrahend 1100 * the subtrahend 1101 * @return this 1102 */ 1103 ref public Matrix2d sub(Matrix2d subtrahend) return { 1104 this.sub(subtrahend, this); 1105 return this; 1106 } 1107 1108 public Matrix2d sub(Matrix2d other, ref Matrix2d dest) { 1109 dest.m00 = m00 - other.m00; 1110 dest.m01 = m01 - other.m01; 1111 dest.m10 = m10 - other.m10; 1112 dest.m11 = m11 - other.m11; 1113 return dest; 1114 } 1115 1116 /** 1117 * Component-wise multiply <code>this</code> by <code>other</code>. 1118 * 1119 * @param other 1120 * the other matrix 1121 * @return this 1122 */ 1123 public Matrix2d mulComponentWise(Matrix2d other) { 1124 return sub(other, this); 1125 } 1126 1127 public Matrix2d mulComponentWise(Matrix2d other, ref Matrix2d dest) { 1128 dest.m00 = m00 * other.m00; 1129 dest.m01 = m01 * other.m01; 1130 dest.m10 = m10 * other.m10; 1131 dest.m11 = m11 * other.m11; 1132 return dest; 1133 } 1134 1135 /** 1136 * Linearly interpolate <code>this</code> and <code>other</code> using the given interpolation factor <code>t</code> 1137 * and store the result in <code>this</code>. 1138 * <p> 1139 * If <code>t</code> is <code>0.0</code> then the result is <code>this</code>. If the interpolation factor is <code>1.0</code> 1140 * then the result is <code>other</code>. 1141 * 1142 * @param other 1143 * the other matrix 1144 * @param t 1145 * the interpolation factor between 0.0 and 1.0 1146 * @return this 1147 */ 1148 public Matrix2d lerp(Matrix2d other, double t) { 1149 return lerp(other, t, this); 1150 } 1151 1152 public Matrix2d lerp(Matrix2d other, double t, ref Matrix2d dest) { 1153 dest.m00 = Math.fma(other.m00 - m00, t, m00); 1154 dest.m01 = Math.fma(other.m01 - m01, t, m01); 1155 dest.m10 = Math.fma(other.m10 - m10, t, m10); 1156 dest.m11 = Math.fma(other.m11 - m11, t, m11); 1157 return dest; 1158 } 1159 1160 public bool isFinite() { 1161 return Math.isFinite(m00) && Math.isFinite(m01) && 1162 Math.isFinite(m10) && Math.isFinite(m11); 1163 } 1164 }