@itwin/core-geometry 4.0.0-dev.7 → 4.0.0-dev.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/cjs/Geometry.d.ts +3 -3
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +27 -11
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/curve/CurveCurve.d.ts +11 -8
- package/lib/cjs/curve/CurveCurve.d.ts.map +1 -1
- package/lib/cjs/curve/CurveCurve.js +16 -12
- package/lib/cjs/curve/CurveCurve.js.map +1 -1
- package/lib/cjs/curve/CurveCurveIntersectXY.d.ts +5 -1
- package/lib/cjs/curve/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/cjs/curve/CurveCurveIntersectXY.js +11 -10
- package/lib/cjs/curve/CurveCurveIntersectXY.js.map +1 -1
- package/lib/cjs/geometry3d/CoincidentGeometryOps.d.ts +1 -0
- package/lib/cjs/geometry3d/CoincidentGeometryOps.d.ts.map +1 -1
- package/lib/cjs/geometry3d/CoincidentGeometryOps.js +3 -0
- package/lib/cjs/geometry3d/CoincidentGeometryOps.js.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.d.ts +171 -118
- package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.js +448 -417
- package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.js +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/cjs/geometry3d/Segment1d.d.ts +1 -1
- package/lib/cjs/geometry3d/Segment1d.js +1 -1
- package/lib/cjs/geometry3d/Segment1d.js.map +1 -1
- package/lib/esm/Geometry.d.ts +3 -3
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +27 -11
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/curve/CurveCurve.d.ts +11 -8
- package/lib/esm/curve/CurveCurve.d.ts.map +1 -1
- package/lib/esm/curve/CurveCurve.js +16 -12
- package/lib/esm/curve/CurveCurve.js.map +1 -1
- package/lib/esm/curve/CurveCurveIntersectXY.d.ts +5 -1
- package/lib/esm/curve/CurveCurveIntersectXY.d.ts.map +1 -1
- package/lib/esm/curve/CurveCurveIntersectXY.js +11 -10
- package/lib/esm/curve/CurveCurveIntersectXY.js.map +1 -1
- package/lib/esm/geometry3d/CoincidentGeometryOps.d.ts +1 -0
- package/lib/esm/geometry3d/CoincidentGeometryOps.d.ts.map +1 -1
- package/lib/esm/geometry3d/CoincidentGeometryOps.js +3 -0
- package/lib/esm/geometry3d/CoincidentGeometryOps.js.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.d.ts +171 -118
- package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.js +448 -417
- package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.d.ts +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.js +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/esm/geometry3d/Segment1d.d.ts +1 -1
- package/lib/esm/geometry3d/Segment1d.js +1 -1
- package/lib/esm/geometry3d/Segment1d.js.map +1 -1
- package/package.json +4 -4
|
@@ -12,6 +12,7 @@ import { Point2d } from "./Point2dVector2d";
|
|
|
12
12
|
import { Point3d, Vector3d } from "./Point3dVector3d";
|
|
13
13
|
import { Transform } from "./Transform";
|
|
14
14
|
/* eslint-disable @itwin/prefer-get */
|
|
15
|
+
// cSpell:words XXYZ YXYZ ZXYZ
|
|
15
16
|
/**
|
|
16
17
|
* PackedMatrix3dOps contains static methods for matrix operations where the matrix is a Float64Array.
|
|
17
18
|
* * The Float64Array contains the matrix entries in row-major order
|
|
@@ -639,7 +640,8 @@ export class Matrix3d {
|
|
|
639
640
|
return undefined;
|
|
640
641
|
}
|
|
641
642
|
/**
|
|
642
|
-
* Construct a rigid matrix using vectorA and its 2 perpendicular.
|
|
643
|
+
* Construct a rigid matrix (orthogonal matrix with +1 determinant) using vectorA and its 2 perpendicular.
|
|
644
|
+
* * If axisOrder is not passed then `AxisOrder = AxisOrder.ZXY` is used as default.
|
|
643
645
|
* * This function internally uses createPerpendicularVectorFavorXYPlane and createRigidFromColumns.
|
|
644
646
|
*/
|
|
645
647
|
static createRigidHeadsUp(vectorA, axisOrder = AxisOrder.ZXY, result) {
|
|
@@ -651,7 +653,7 @@ export class Matrix3d {
|
|
|
651
653
|
}
|
|
652
654
|
return Matrix3d.createIdentity(result);
|
|
653
655
|
}
|
|
654
|
-
/** Return the matrix for rotation of `angle` around `axis` */
|
|
656
|
+
/** Return the matrix for rotation of `angle` around desired `axis` */
|
|
655
657
|
static createRotationAroundVector(axis, angle, result) {
|
|
656
658
|
// Rodriguez formula (matrix form), https://mathworld.wolfram.com/RodriguesRotationFormula.html
|
|
657
659
|
const c = angle.cos();
|
|
@@ -665,7 +667,7 @@ export class Matrix3d {
|
|
|
665
667
|
}
|
|
666
668
|
return undefined;
|
|
667
669
|
}
|
|
668
|
-
/** Returns a rotation of specified angle around
|
|
670
|
+
/** Returns a rotation of specified angle around one of the main axis (X,Y,Z).
|
|
669
671
|
* @param axisIndex index of axis (AxisIndex.X, AxisIndex.Y, AxisIndex.Z) kept fixed by the rotation.
|
|
670
672
|
* @param angle angle of rotation
|
|
671
673
|
* @param result optional result matrix.
|
|
@@ -688,14 +690,33 @@ export class Matrix3d {
|
|
|
688
690
|
return myResult;
|
|
689
691
|
}
|
|
690
692
|
/**
|
|
691
|
-
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
693
|
+
* Replace current rows Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
694
|
+
* * There is no checking for i,j being 0,1,2.
|
|
695
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
696
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
697
|
+
* @param c fist coefficient
|
|
698
|
+
* @param s second coefficient
|
|
699
|
+
*/
|
|
700
|
+
applyGivensRowOp(i, j, c, s) {
|
|
701
|
+
let ii = 3 * i;
|
|
702
|
+
let jj = 3 * j;
|
|
703
|
+
const limit = ii + 3;
|
|
704
|
+
for (; ii < limit; ii++, jj++) {
|
|
705
|
+
const a = this.coffs[ii];
|
|
706
|
+
const b = this.coffs[jj];
|
|
707
|
+
this.coffs[ii] = a * c + b * s;
|
|
708
|
+
this.coffs[jj] = -a * s + b * c;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
/**
|
|
712
|
+
* Replace current columns Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
713
|
+
* * There is no checking for i,j being 0,1,2.
|
|
714
|
+
* * This is used in compute intensive inner loops
|
|
715
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
716
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
717
|
+
* @param c fist coefficient
|
|
718
|
+
* @param s second coefficient
|
|
719
|
+
*/
|
|
699
720
|
applyGivensColumnOp(i, j, c, s) {
|
|
700
721
|
const limit = i + 9;
|
|
701
722
|
for (; i < limit; i += 3, j += 3) {
|
|
@@ -706,12 +727,12 @@ export class Matrix3d {
|
|
|
706
727
|
}
|
|
707
728
|
}
|
|
708
729
|
/**
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
730
|
+
* Create a matrix from column vectors.
|
|
731
|
+
* ```
|
|
732
|
+
* equation
|
|
733
|
+
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ U_z & V_z & W_z \end{bmatrix}
|
|
734
|
+
* ```
|
|
735
|
+
*/
|
|
715
736
|
static createColumns(vectorU, vectorV, vectorW, result) {
|
|
716
737
|
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z, result);
|
|
717
738
|
}
|
|
@@ -728,8 +749,9 @@ export class Matrix3d {
|
|
|
728
749
|
* * ColumnX points in the rightVector direction
|
|
729
750
|
* * ColumnY points in the upVector direction
|
|
730
751
|
* * ColumnZ is a unit cross product of ColumnX and ColumnY.
|
|
731
|
-
* * Optionally rotate
|
|
732
|
-
* * Optionally rotate
|
|
752
|
+
* * Optionally rotate by 45 degrees around `upVector` to bring its left or right vertical edge to center.
|
|
753
|
+
* * Optionally rotate by arctan(1/sqrt(2)) ~ 35.264 degrees around `rightVector` to bring the top or bottom
|
|
754
|
+
* horizontal edge of the view to the center (for isometric views).
|
|
733
755
|
* * This is expected to be used with various principal unit vectors that are perpendicular to each other.
|
|
734
756
|
* * STANDARD TOP VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(), 0, 0)
|
|
735
757
|
* * STANDARD FRONT VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 0, 0)
|
|
@@ -737,16 +759,20 @@ export class Matrix3d {
|
|
|
737
759
|
* * STANDARD RIGHT VIEW: createViewedAxes(Vector3d.unitY(), Vector3d.unitZ(), 0, 0)
|
|
738
760
|
* * STANDARD LEFT VIEW: createViewedAxes(Vector3d.unitY(-1), Vector3d.unitZ(), 0, 0)
|
|
739
761
|
* * STANDARD BOTTOM VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(-1), 0, 0)
|
|
762
|
+
* * STANDARD ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), -1, 1)
|
|
763
|
+
* * STANDARD RIGHT ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 1, 1)
|
|
764
|
+
* * Front, right, back, left, top, and bottom standard views are views from faces of the cube
|
|
765
|
+
* and iso and right iso standard views are views from corners of the cube.
|
|
740
766
|
* * Note: createViewedAxes is column-based so always returns local to world
|
|
741
767
|
*
|
|
742
768
|
* @param rightVector ColumnX of the returned matrix. Expected to be perpendicular to upVector.
|
|
743
769
|
* @param upVector ColumnY of the returned matrix. Expected to be perpendicular to rightVector.
|
|
744
|
-
* @param leftNoneRight Specifies the ccw rotation around
|
|
745
|
-
* "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
770
|
+
* @param leftNoneRight Specifies the ccw rotation around `upVector` axis. Normally one of "-1", "0", and "1",
|
|
771
|
+
* where "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
746
772
|
* and "1" indicates rotation by 45 degrees to bring the right vertical edge to center. Other numbers are
|
|
747
773
|
* used as multiplier for this 45 degree rotation.
|
|
748
|
-
* @param topNoneBottom Specifies the ccw rotation around
|
|
749
|
-
* "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
774
|
+
* @param topNoneBottom Specifies the ccw rotation around `rightVector` axis. Normally one of "-1", "0", and "1",
|
|
775
|
+
* where "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
750
776
|
* and "1" indicates isometric rotation (35.264 degrees) to bring the top downward. Other numbers are
|
|
751
777
|
* used as multiplier for the 35.264 degree rotation.
|
|
752
778
|
* @returns matrix = [rightVector, upVector, rightVector cross upVector] with the applied rotations specified
|
|
@@ -784,9 +810,11 @@ export class Matrix3d {
|
|
|
784
810
|
* * Default is TOP view (`local X = world X`, `local Y = world Y`, `local Z = world Z`).
|
|
785
811
|
* * To change view from the TOP to one of the other 7 standard views, we need to multiply "world data" to
|
|
786
812
|
* the corresponding matrix1 provided by `createStandardWorldToView(index, false)` and then
|
|
787
|
-
* `matrix1.multiply(world data)` will
|
|
813
|
+
* `matrix1.multiply(world data)` will return "local data".
|
|
788
814
|
* * To change view back to the TOP, we need to multiply "local data" to the corresponding matrix2 provided
|
|
789
815
|
* by `createStandardWorldToView(index, true)` and then `matrix2.multiply(local data)` will returns "world data".
|
|
816
|
+
* * Note: No matter how you rotate the world axis, local X is always pointing right, local Y is always pointing up,
|
|
817
|
+
* and local Z is always pointing toward you.
|
|
790
818
|
*
|
|
791
819
|
* @param index standard view index `StandardViewIndex.Top, Bottom, Left, Right, Front, Back, Iso, RightIso`
|
|
792
820
|
* @param invert if false (default), the return matrix is world to local (view) and if true, the the return
|
|
@@ -795,343 +823,182 @@ export class Matrix3d {
|
|
|
795
823
|
*/
|
|
796
824
|
static createStandardWorldToView(index, invert = false, result) {
|
|
797
825
|
switch (index) {
|
|
798
|
-
//
|
|
826
|
+
// Start with TOP view, ccw rotation by 180 degrees around X
|
|
799
827
|
case StandardViewIndex.Bottom:
|
|
800
828
|
result = Matrix3d.createRowValues(1, 0, 0, 0, -1, 0, 0, 0, -1);
|
|
801
829
|
break;
|
|
802
|
-
//
|
|
830
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 90 degrees around Z
|
|
803
831
|
case StandardViewIndex.Left:
|
|
804
832
|
result = Matrix3d.createRowValues(0, -1, 0, 0, 0, 1, -1, 0, 0);
|
|
805
833
|
break;
|
|
806
|
-
//
|
|
834
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by -90 degrees around Z
|
|
807
835
|
case StandardViewIndex.Right:
|
|
808
836
|
result = Matrix3d.createRowValues(0, 1, 0, 0, 0, 1, 1, 0, 0);
|
|
809
837
|
break;
|
|
810
|
-
//
|
|
838
|
+
// Start with TOP view, ccw rotation by -90 degrees around X
|
|
811
839
|
case StandardViewIndex.Front:
|
|
812
840
|
result = Matrix3d.createRowValues(1, 0, 0, 0, 0, 1, 0, -1, 0);
|
|
813
841
|
break;
|
|
814
|
-
//
|
|
842
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 180 degrees around Z
|
|
815
843
|
case StandardViewIndex.Back:
|
|
816
844
|
result = Matrix3d.createRowValues(-1, 0, 0, 0, 0, 1, 0, 1, 0);
|
|
817
845
|
break;
|
|
846
|
+
/**
|
|
847
|
+
* Isometric view
|
|
848
|
+
* Start with FRONT view, ccw rotation by -45 degrees around Y and by arctan(1/sqrt(2)) ~ 35.264 degrees around X
|
|
849
|
+
* cos(45) = 1/sqrt(2) = 0.70710678118 and sin(45) = 1/sqrt(2) = 0.70710678118
|
|
850
|
+
* cos(35.264) = 2/sqrt(6) = 0.81649658092 and sin(35.264) = 1/sqrt(3) = 0.57735026919
|
|
851
|
+
* More info: https://en.wikipedia.org/wiki/Isometric_projection
|
|
852
|
+
*/
|
|
818
853
|
case StandardViewIndex.Iso:
|
|
819
|
-
// start with FRONT view, ccw rotation by -45 degrees around Y and by 35.264 degrees around X
|
|
820
854
|
result = Matrix3d.createRowValues(0.707106781186548, -0.70710678118654757, 0.00000000000000000, 0.408248290463863, 0.40824829046386302, 0.81649658092772603, -0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
821
855
|
break;
|
|
856
|
+
// Start with FRONT view, ccw rotation by 45 degrees around Y and by 35.264 degrees around X
|
|
822
857
|
case StandardViewIndex.RightIso:
|
|
823
858
|
result = Matrix3d.createRowValues(0.707106781186548, 0.70710678118654757, 0.00000000000000000, -0.408248290463863, 0.40824829046386302, 0.81649658092772603, 0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
824
859
|
break;
|
|
825
|
-
|
|
860
|
+
// no rotation
|
|
861
|
+
case StandardViewIndex.Top:
|
|
826
862
|
default:
|
|
827
863
|
result = Matrix3d.createIdentity(result);
|
|
828
864
|
}
|
|
829
865
|
if (invert)
|
|
830
|
-
result.transposeInPlace();
|
|
866
|
+
result.transposeInPlace(); // matrix is rigid so transpose and inverse are the same
|
|
831
867
|
return result;
|
|
832
868
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
return result
|
|
898
|
-
}
|
|
899
|
-
*/
|
|
869
|
+
/**
|
|
870
|
+
* Apply (in place) a jacobi update that zeros out this.at(i,j).
|
|
871
|
+
* @param i row index of zeroed member
|
|
872
|
+
* @param j column index of zeroed member
|
|
873
|
+
* @param k other row/column index (different from i and j)
|
|
874
|
+
* @param leftEigenVectors a matrix that its columns will be filled by eigenvectors of this Matrix3d
|
|
875
|
+
* (allocated by caller, computed and filled by this function)
|
|
876
|
+
*/
|
|
877
|
+
applyFastSymmetricJacobiUpdate(i, j, k, leftEigenVectors) {
|
|
878
|
+
const indexII = 4 * i;
|
|
879
|
+
const indexJJ = 4 * j;
|
|
880
|
+
const indexIJ = 3 * i + j;
|
|
881
|
+
const indexIK = 3 * i + k;
|
|
882
|
+
const indexJK = 3 * j + k;
|
|
883
|
+
const dotUU = this.coffs[indexII];
|
|
884
|
+
const dotVV = this.coffs[indexJJ];
|
|
885
|
+
const dotUV = this.coffs[indexIJ];
|
|
886
|
+
const jacobi = Angle.trigValuesToHalfAngleTrigValues(dotUU - dotVV, 2.0 * dotUV);
|
|
887
|
+
if (Math.abs(dotUV) < 1.0e-15 * (dotUU + dotVV))
|
|
888
|
+
return 0.0;
|
|
889
|
+
const c = jacobi.c;
|
|
890
|
+
const s = jacobi.s;
|
|
891
|
+
const cc = c * c;
|
|
892
|
+
const ss = s * s;
|
|
893
|
+
const sc2 = 2.0 * c * s;
|
|
894
|
+
this.coffs[indexII] = cc * dotUU + sc2 * dotUV + ss * dotVV;
|
|
895
|
+
this.coffs[indexJJ] = ss * dotUU - sc2 * dotUV + cc * dotVV;
|
|
896
|
+
this.coffs[indexIJ] = 0.0;
|
|
897
|
+
const a = this.coffs[indexIK];
|
|
898
|
+
const b = this.coffs[indexJK];
|
|
899
|
+
this.coffs[indexIK] = a * c + b * s;
|
|
900
|
+
this.coffs[indexJK] = -s * a + c * b;
|
|
901
|
+
this.coffs[3 * j + i] = 0.0;
|
|
902
|
+
this.coffs[3 * k + i] = this.coffs[indexIK];
|
|
903
|
+
this.coffs[3 * k + j] = this.coffs[indexJK];
|
|
904
|
+
leftEigenVectors.applyGivensColumnOp(i, j, c, s);
|
|
905
|
+
return Math.abs(dotUV);
|
|
906
|
+
}
|
|
907
|
+
/**
|
|
908
|
+
* Factor this (symmetrized) as a product U * lambda * UT where U is orthogonal, lambda is diagonal.
|
|
909
|
+
* The upper triangle is mirrored to lower triangle to enforce symmetry.
|
|
910
|
+
* @param leftEigenvectors a matrix that its columns will be filled by eigenvectors of this Matrix3d
|
|
911
|
+
* (allocated by caller, computed and filled by this function)
|
|
912
|
+
* @param lambda a vector that its entries will be filled by eigenvalues of this Matrix3d
|
|
913
|
+
* (allocated by caller, computed and filled by this function)
|
|
914
|
+
*/
|
|
915
|
+
fastSymmetricEigenvalues(leftEigenvectors, lambda) {
|
|
916
|
+
const matrix = this.clone();
|
|
917
|
+
leftEigenvectors.setIdentity();
|
|
918
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
919
|
+
for (let iteration = 0; iteration < 7; iteration++) {
|
|
920
|
+
const sum = matrix.applyFastSymmetricJacobiUpdate(0, 1, 2, leftEigenvectors)
|
|
921
|
+
+ matrix.applyFastSymmetricJacobiUpdate(0, 2, 1, leftEigenvectors)
|
|
922
|
+
+ matrix.applyFastSymmetricJacobiUpdate(1, 2, 0, leftEigenvectors);
|
|
923
|
+
// console.log("symmetric sum", sum);
|
|
924
|
+
// console.log ("sum", sum);
|
|
925
|
+
if (sum < tolerance) {
|
|
926
|
+
// console.log("symmetric iterations", iteration);
|
|
927
|
+
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
928
|
+
return true;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
return false;
|
|
932
|
+
}
|
|
900
933
|
/**
|
|
901
934
|
* Compute the (unit vector) axis and angle of rotation.
|
|
935
|
+
* * math details can be found at docs/learning/geometry/Angle.md
|
|
902
936
|
* @returns Returns axis and angle of rotation with result.ok === true when the conversion succeeded.
|
|
903
937
|
*/
|
|
904
938
|
getAxisAndAngleOfRotation() {
|
|
905
939
|
const trace = this.coffs[0] + this.coffs[4] + this.coffs[8];
|
|
906
|
-
|
|
907
|
-
const
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
const c = (trace - 1.0) / 2.0;
|
|
911
|
-
const s = Geometry.hypotenuseXYZ(skewXY, skewYZ, skewZX) / 2.0;
|
|
912
|
-
const e = c * c + s * s - 1.0;
|
|
940
|
+
const skewXY = this.coffs[3] - this.coffs[1]; // 2*z*sin
|
|
941
|
+
const skewYZ = this.coffs[7] - this.coffs[5]; // 2*y*sin
|
|
942
|
+
const skewZX = this.coffs[2] - this.coffs[6]; // 2*x*sin
|
|
943
|
+
// trace = (m00^2 + m11^2 + m22^2) * (1-cos) + 3cos = (1-cos) + 3cos = 1 + 2cos ==> cos = (trace-1) / 2
|
|
944
|
+
const c = (trace - 1.0) / 2.0; // cosine
|
|
945
|
+
const s = Geometry.hypotenuseXYZ(skewXY, skewYZ, skewZX) / 2.0; // sine
|
|
946
|
+
const e = c * c + s * s - 1.0; // s^2 + c^2 = 1
|
|
947
|
+
// if s^2 + c^2 != 1 then we have a bad matrix so return false
|
|
913
948
|
if (Math.abs(e) > Geometry.smallAngleRadians) {
|
|
914
|
-
// the sine and cosine are not a unit circle point. bad matrix . ..
|
|
915
949
|
return { axis: Vector3d.create(0, 0, 1), angle: Angle.createRadians(0), ok: false };
|
|
916
950
|
}
|
|
951
|
+
// sin is close to 0 then we got to special cases (angle 0 or 180) which needs to be handled differently
|
|
917
952
|
if (Math.abs(s) < Geometry.smallAngleRadians) {
|
|
918
|
-
//
|
|
919
|
-
// The matrix is symmetric
|
|
920
|
-
// So it has simple eigenvalues -- either (1,1,1) or (1,-1,-1).
|
|
921
|
-
if (c > 0) // no rotation
|
|
953
|
+
if (c > 0) // sin = 0 and cos = 1 so angle = 0 (i.e., no rotation)
|
|
922
954
|
return { axis: Vector3d.create(0, 0, 1), angle: Angle.createRadians(0), ok: true };
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
955
|
+
/**
|
|
956
|
+
* If sin = 0 and cos = -1 then angle = 180 (i.e., 180 degree rotation around some axis)
|
|
957
|
+
* then the rotation matrix becomes
|
|
958
|
+
* 2x^2-1 2xy 2xz
|
|
959
|
+
* 2xy 2y^2-1 2yz
|
|
960
|
+
* 2xz 2yz 2z^2-1
|
|
961
|
+
* Note that the matrix is symmetric.
|
|
962
|
+
* If rotation is around one the standard basis then non-diagonal entries become 0 and we
|
|
963
|
+
* have one 1 and two -1s on the diagonal.
|
|
964
|
+
* If rotation is around an axis other than standard basis, then the axis is the eigenvector
|
|
965
|
+
* of the rotation matrix with eigenvalue = 1.
|
|
966
|
+
*/
|
|
926
967
|
const axx = this.coffs[0];
|
|
927
968
|
const ayy = this.coffs[4];
|
|
928
969
|
const azz = this.coffs[8];
|
|
929
|
-
|
|
930
|
-
// Look for principal axis flips as a special case . ..
|
|
970
|
+
// Look for a pair of "-1" entries on the diagonal (for rotation around the basis X,Y,Z axis)
|
|
931
971
|
if (Geometry.isAlmostEqualNumber(-1.0, ayy) && Geometry.isAlmostEqualNumber(-1, azz)) {
|
|
932
|
-
|
|
933
|
-
return { axis: Vector3d.create(1, 0, 0), angle: theta180, ok: true };
|
|
972
|
+
return { axis: Vector3d.create(1, 0, 0), angle: Angle.createDegrees(180), ok: true };
|
|
934
973
|
}
|
|
935
974
|
else if (Geometry.isAlmostEqualNumber(-1.0, axx) && Geometry.isAlmostEqualNumber(-1, azz)) {
|
|
936
|
-
return { axis: Vector3d.create(0, 1, 0), angle:
|
|
975
|
+
return { axis: Vector3d.create(0, 1, 0), angle: Angle.createDegrees(180), ok: true };
|
|
937
976
|
}
|
|
938
977
|
else if (Geometry.isAlmostEqualNumber(-1.0, axx) && Geometry.isAlmostEqualNumber(-1, ayy)) {
|
|
939
|
-
return { axis: Vector3d.create(0, 0, 1), angle:
|
|
978
|
+
return { axis: Vector3d.create(0, 0, 1), angle: Angle.createDegrees(180), ok: true };
|
|
940
979
|
}
|
|
941
|
-
//
|
|
942
|
-
// eigenvalues will have 1.0 once, -1.0 twice.
|
|
943
|
-
// These cases look for each place (x,y,z) that the 1.0 might appear.
|
|
944
|
-
// But fastSymmetricEigenvalues reliably always seems to put the 1.0 as the x eigenvalue.
|
|
945
|
-
// so only the getColumn(0) return seems reachable in unit tests.
|
|
980
|
+
// Look for eigenvector with eigenvalue = 1
|
|
946
981
|
const eigenvectors = Matrix3d.createIdentity();
|
|
947
982
|
const eigenvalues = Vector3d.create(0, 0, 0);
|
|
948
983
|
if (this.fastSymmetricEigenvalues(eigenvectors, eigenvalues)) {
|
|
949
984
|
for (let axisIndex = 0; axisIndex < 2; axisIndex++) {
|
|
950
985
|
const lambda = eigenvalues.at(axisIndex);
|
|
951
986
|
if (Geometry.isAlmostEqualNumber(1, lambda))
|
|
952
|
-
return { axis: eigenvectors.getColumn(axisIndex), angle:
|
|
987
|
+
return { axis: eigenvectors.getColumn(axisIndex), angle: Angle.createDegrees(180), ok: true };
|
|
953
988
|
}
|
|
954
|
-
//
|
|
989
|
+
// if no eigenvalue = 1 was found return false
|
|
955
990
|
return { axis: Vector3d.create(0, 0, 1), angle: Angle.createRadians(0), ok: false };
|
|
956
991
|
}
|
|
992
|
+
// if no axis was found return false
|
|
957
993
|
return { axis: Vector3d.create(0, 0, 1), angle: Angle.createRadians(0), ok: false };
|
|
958
994
|
}
|
|
995
|
+
// good matrix and non-zero sine
|
|
959
996
|
const a = 1.0 / (2.0 * s);
|
|
960
|
-
const result = {
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
*/
|
|
966
|
-
static createRotationVectorToVector(vectorA, vectorB, result) {
|
|
967
|
-
return this.createPartialRotationVectorToVector(vectorA, 1.0, vectorB, result);
|
|
968
|
-
}
|
|
969
|
-
/**
|
|
970
|
-
* Return a matrix that rotates a fraction of the angular sweep from vectorA to vectorB.
|
|
971
|
-
* @param vectorA initial vector position
|
|
972
|
-
* @param fraction fractional rotation. 1.0 is "all the way"
|
|
973
|
-
* @param vectorB final vector position
|
|
974
|
-
* @param result optional result matrix.
|
|
975
|
-
*/
|
|
976
|
-
static createPartialRotationVectorToVector(vectorA, fraction, vectorB, result) {
|
|
977
|
-
let upVector = vectorA.unitCrossProduct(vectorB);
|
|
978
|
-
if (upVector) { // the usual case --
|
|
979
|
-
return Matrix3d.createRotationAroundVector(upVector, Angle.createRadians(fraction * vectorA.planarAngleTo(vectorB, upVector).radians));
|
|
980
|
-
}
|
|
981
|
-
// fail if either vector is zero ...
|
|
982
|
-
if (Geometry.isSmallMetricDistance(vectorA.magnitude())
|
|
983
|
-
|| Geometry.isSmallMetricDistance(vectorB.magnitude()))
|
|
984
|
-
return undefined;
|
|
985
|
-
// nonzero but aligned vectors ...
|
|
986
|
-
if (vectorA.dotProduct(vectorB) > 0.0)
|
|
987
|
-
return Matrix3d.createIdentity(result);
|
|
988
|
-
// nonzero opposing vectors ..
|
|
989
|
-
upVector = Matrix3d.createPerpendicularVectorFavorPlaneContainingZ(vectorA, upVector);
|
|
990
|
-
return Matrix3d.createRotationAroundVector(upVector, Angle.createRadians(fraction * Math.PI));
|
|
991
|
-
}
|
|
992
|
-
/** Create a 90 degree rotation around a principal axis */
|
|
993
|
-
static create90DegreeRotationAroundAxis(axisIndex) {
|
|
994
|
-
axisIndex = Geometry.cyclic3dAxis(axisIndex);
|
|
995
|
-
if (axisIndex === 0) {
|
|
996
|
-
const retVal = Matrix3d.createRowValues(1, 0, 0, 0, 0, -1, 0, 1, 0);
|
|
997
|
-
retVal.setupInverseTranspose();
|
|
998
|
-
return retVal;
|
|
999
|
-
}
|
|
1000
|
-
else if (axisIndex === 1) {
|
|
1001
|
-
const retVal = Matrix3d.createRowValues(0, 0, 1, 0, 1, 0, -1, 0, 0);
|
|
1002
|
-
retVal.setupInverseTranspose();
|
|
1003
|
-
return retVal;
|
|
1004
|
-
}
|
|
1005
|
-
else {
|
|
1006
|
-
const retVal = Matrix3d.createRowValues(0, -1, 0, 1, 0, 0, 0, 0, 1);
|
|
1007
|
-
retVal.setupInverseTranspose();
|
|
1008
|
-
return retVal;
|
|
1009
|
-
}
|
|
1010
|
-
}
|
|
1011
|
-
/** Return (a copy of) the X column */
|
|
1012
|
-
columnX(result) { return Vector3d.create(this.coffs[0], this.coffs[3], this.coffs[6], result); }
|
|
1013
|
-
/** Return (a copy of)the Y column */
|
|
1014
|
-
columnY(result) { return Vector3d.create(this.coffs[1], this.coffs[4], this.coffs[7], result); }
|
|
1015
|
-
/** Return (a copy of)the Z column */
|
|
1016
|
-
columnZ(result) { return Vector3d.create(this.coffs[2], this.coffs[5], this.coffs[8], result); }
|
|
1017
|
-
/** Return the X column magnitude squared */
|
|
1018
|
-
columnXMagnitudeSquared() { return Geometry.hypotenuseSquaredXYZ(this.coffs[0], this.coffs[3], this.coffs[6]); }
|
|
1019
|
-
/** Return the Y column magnitude squared */
|
|
1020
|
-
columnYMagnitudeSquared() { return Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[4], this.coffs[7]); }
|
|
1021
|
-
/** Return the Z column magnitude squared */
|
|
1022
|
-
columnZMagnitudeSquared() { return Geometry.hypotenuseSquaredXYZ(this.coffs[2], this.coffs[5], this.coffs[8]); }
|
|
1023
|
-
/** Return the X column magnitude */
|
|
1024
|
-
columnXMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6]); }
|
|
1025
|
-
/** Return the Y column magnitude */
|
|
1026
|
-
columnYMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7]); }
|
|
1027
|
-
/** Return the Z column magnitude */
|
|
1028
|
-
columnZMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]); }
|
|
1029
|
-
/** Return magnitude of columnX cross columnY. */
|
|
1030
|
-
columnXYCrossProductMagnitude() {
|
|
1031
|
-
return Geometry.crossProductMagnitude(this.coffs[0], this.coffs[3], this.coffs[6], this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1032
|
-
}
|
|
1033
|
-
/** Return the X row magnitude d */
|
|
1034
|
-
rowXMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[1], this.coffs[2]); }
|
|
1035
|
-
/** Return the Y row magnitude */
|
|
1036
|
-
rowYMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[3], this.coffs[4], this.coffs[5]); }
|
|
1037
|
-
/** Return the Z row magnitude */
|
|
1038
|
-
rowZMagnitude() { return Geometry.hypotenuseXYZ(this.coffs[6], this.coffs[7], this.coffs[8]); }
|
|
1039
|
-
/** Return the dot product of column X with column Y */
|
|
1040
|
-
/** Return the dot product of column X with column Y */
|
|
1041
|
-
columnXDotColumnY() {
|
|
1042
|
-
return this.coffs[0] * this.coffs[1]
|
|
1043
|
-
+ this.coffs[3] * this.coffs[4]
|
|
1044
|
-
+ this.coffs[6] * this.coffs[7];
|
|
1045
|
-
}
|
|
1046
|
-
/**
|
|
1047
|
-
* Dot product of an indexed column with a vector given as x,y,z
|
|
1048
|
-
* @param columnIndex index of column. Must be 0,1,2
|
|
1049
|
-
* @param x x component of vector
|
|
1050
|
-
* @param y y component of vector
|
|
1051
|
-
* @param z z component of vector
|
|
1052
|
-
*/
|
|
1053
|
-
columnDotXYZ(columnIndex, x, y, z) {
|
|
1054
|
-
return this.coffs[columnIndex] * x + this.coffs[columnIndex + 3] * y + this.coffs[columnIndex + 6] * z;
|
|
1055
|
-
}
|
|
1056
|
-
/** Return (a copy of) the X row */
|
|
1057
|
-
rowX(result) { return Vector3d.create(this.coffs[0], this.coffs[1], this.coffs[2], result); }
|
|
1058
|
-
/** Return (a copy of) the Y row */
|
|
1059
|
-
rowY(result) { return Vector3d.create(this.coffs[3], this.coffs[4], this.coffs[5], result); }
|
|
1060
|
-
/** Return (a copy of) the Z row */
|
|
1061
|
-
rowZ(result) { return Vector3d.create(this.coffs[6], this.coffs[7], this.coffs[8], result); }
|
|
1062
|
-
/** Return the dot product of the vector parameter with the X column. */
|
|
1063
|
-
dotColumnX(vector) { return vector.x * this.coffs[0] + vector.y * this.coffs[3] + vector.z * this.coffs[6]; }
|
|
1064
|
-
/** Return the dot product of the vector parameter with the Y column. */
|
|
1065
|
-
dotColumnY(vector) { return vector.x * this.coffs[1] + vector.y * this.coffs[4] + vector.z * this.coffs[7]; }
|
|
1066
|
-
/** Return the dot product of the vector parameter with the Z column. */
|
|
1067
|
-
dotColumnZ(vector) { return vector.x * this.coffs[2] + vector.y * this.coffs[5] + vector.z * this.coffs[8]; }
|
|
1068
|
-
/** Return the dot product of the vector parameter with the X row. */
|
|
1069
|
-
dotRowX(vector) { return vector.x * this.coffs[0] + vector.y * this.coffs[1] + vector.z * this.coffs[2]; }
|
|
1070
|
-
/** Return the dot product of the vector parameter with the Y row. */
|
|
1071
|
-
dotRowY(vector) { return vector.x * this.coffs[3] + vector.y * this.coffs[4] + vector.z * this.coffs[5]; }
|
|
1072
|
-
/** Return the dot product of the vector parameter with the Z row. */
|
|
1073
|
-
dotRowZ(vector) { return vector.x * this.coffs[6] + vector.y * this.coffs[7] + vector.z * this.coffs[8]; }
|
|
1074
|
-
// cSpell:words XXYZ YXYZ ZXYZ XYZAs Eigen
|
|
1075
|
-
/** Return the dot product of the x,y,z with the X row. */
|
|
1076
|
-
dotRowXXYZ(x, y, z) { return x * this.coffs[0] + y * this.coffs[1] + z * this.coffs[2]; }
|
|
1077
|
-
/** Return the dot product of the x,y,z with the Y row. */
|
|
1078
|
-
dotRowYXYZ(x, y, z) { return x * this.coffs[3] + y * this.coffs[4] + z * this.coffs[5]; }
|
|
1079
|
-
/** Return the dot product of the x,y,z with the Z row. */
|
|
1080
|
-
dotRowZXYZ(x, y, z) { return x * this.coffs[6] + y * this.coffs[7] + z * this.coffs[8]; }
|
|
1081
|
-
/** Return the (vector) cross product of the Z column with the vector parameter. */
|
|
1082
|
-
columnZCrossVector(vector, result) {
|
|
1083
|
-
return Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
1084
|
-
}
|
|
1085
|
-
/*
|
|
1086
|
-
* Replace current rows Ui Uj with (c*Ui - s*Uj) and (c*Uj + s*Ui).
|
|
1087
|
-
* @param i first row index. must be 0,1,2 (unchecked)
|
|
1088
|
-
* @param j second row index. must be 0,1,2 (unchecked)
|
|
1089
|
-
* @param c fist coefficient
|
|
1090
|
-
* @param s second coefficient
|
|
1091
|
-
*/
|
|
1092
|
-
applyGivensRowOp(i, j, c, s) {
|
|
1093
|
-
let ii = 3 * i;
|
|
1094
|
-
let jj = 3 * j;
|
|
1095
|
-
const limit = ii + 3;
|
|
1096
|
-
for (; ii < limit; ii++, jj++) {
|
|
1097
|
-
const a = this.coffs[ii];
|
|
1098
|
-
const b = this.coffs[jj];
|
|
1099
|
-
this.coffs[ii] = a * c + b * s;
|
|
1100
|
-
this.coffs[jj] = -a * s + b * c;
|
|
1101
|
-
}
|
|
1102
|
-
}
|
|
1103
|
-
/**
|
|
1104
|
-
* create a rigid coordinate frame column z parallel to (_x_,_y_,_z_) and column x in the xy plane.
|
|
1105
|
-
* * column z points from origin to x,y,z
|
|
1106
|
-
* * column x is perpendicular and in the xy plane
|
|
1107
|
-
* * column y is perpendicular to both. It is the "up" vector on the view plane.
|
|
1108
|
-
* * Multiplying a world vector times the transpose of this matrix transforms into the view xy
|
|
1109
|
-
* * Multiplying the matrix times the an in-view vector transforms the vector to world.
|
|
1110
|
-
* @param x eye x coordinate
|
|
1111
|
-
* @param y eye y coordinate
|
|
1112
|
-
* @param z eye z coordinate
|
|
1113
|
-
* @param result
|
|
1114
|
-
*/
|
|
1115
|
-
static createRigidViewAxesZTowardsEye(x, y, z, result) {
|
|
1116
|
-
result = Matrix3d.createIdentity(result);
|
|
1117
|
-
const rxy = Geometry.hypotenuseXY(x, y);
|
|
1118
|
-
if (Geometry.isSmallMetricDistance(rxy)) {
|
|
1119
|
-
// special case for top or bottom view.
|
|
1120
|
-
if (z < 0.0)
|
|
1121
|
-
result.scaleColumnsInPlace(1.0, -1, -1.0);
|
|
1122
|
-
}
|
|
1123
|
-
else {
|
|
1124
|
-
// const d = Geometry.hypotenuseSquaredXYZ(x, y, z);
|
|
1125
|
-
const c = x / rxy;
|
|
1126
|
-
const s = y / rxy;
|
|
1127
|
-
result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
|
|
1128
|
-
if (z !== 0.0) {
|
|
1129
|
-
const r = Geometry.hypotenuseXYZ(x, y, z);
|
|
1130
|
-
const s1 = z / r;
|
|
1131
|
-
const c1 = rxy / r;
|
|
1132
|
-
result.applyGivensColumnOp(1, 2, c1, -s1);
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
997
|
+
const result = {
|
|
998
|
+
axis: Vector3d.create(skewYZ * a, skewZX * a, skewXY * a),
|
|
999
|
+
angle: Angle.createAtan2(s, c),
|
|
1000
|
+
ok: true,
|
|
1001
|
+
};
|
|
1135
1002
|
return result;
|
|
1136
1003
|
}
|
|
1137
1004
|
/** Rotate so columns i and j become perpendicular */
|
|
@@ -1163,8 +1030,7 @@ export class Matrix3d {
|
|
|
1163
1030
|
factorPerpendicularColumns(matrixC, matrixU) {
|
|
1164
1031
|
matrixC.setFrom(this);
|
|
1165
1032
|
matrixU.setIdentity();
|
|
1166
|
-
const
|
|
1167
|
-
const tolerance = 1.0e-12 * ss;
|
|
1033
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1168
1034
|
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1169
1035
|
const sum = matrixC.applyJacobiColumnRotation(0, 1, matrixU)
|
|
1170
1036
|
+ matrixC.applyJacobiColumnRotation(0, 2, matrixU)
|
|
@@ -1255,8 +1121,7 @@ export class Matrix3d {
|
|
|
1255
1121
|
matrix.coffs[3] = matrix.coffs[1];
|
|
1256
1122
|
matrix.coffs[6] = matrix.coffs[2];
|
|
1257
1123
|
matrix.coffs[7] = matrix.coffs[5];
|
|
1258
|
-
const
|
|
1259
|
-
const tolerance = 1.0e-12 * ss;
|
|
1124
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1260
1125
|
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1261
1126
|
const sum = leftEigenvectors.applySymmetricJacobi(0, 1, matrix)
|
|
1262
1127
|
+ leftEigenvectors.applySymmetricJacobi(0, 2, matrix)
|
|
@@ -1271,68 +1136,174 @@ export class Matrix3d {
|
|
|
1271
1136
|
}
|
|
1272
1137
|
return false;
|
|
1273
1138
|
}
|
|
1274
|
-
/**
|
|
1275
|
-
*
|
|
1139
|
+
/**
|
|
1140
|
+
* Return a matrix that rotates a fraction of the angular sweep from vectorA to vectorB.
|
|
1141
|
+
* @param vectorA initial vector position
|
|
1142
|
+
* @param fraction fractional rotation (1 means rotate all the way)
|
|
1143
|
+
* @param vectorB final vector position
|
|
1144
|
+
* @param result optional result matrix.
|
|
1276
1145
|
*/
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1146
|
+
static createPartialRotationVectorToVector(vectorA, fraction, vectorB, result) {
|
|
1147
|
+
let upVector = vectorA.unitCrossProduct(vectorB);
|
|
1148
|
+
// the usual case (both vectors and also their cross product is non-zero)
|
|
1149
|
+
if (upVector) {
|
|
1150
|
+
return Matrix3d.createRotationAroundVector(upVector, Angle.createRadians(fraction * vectorA.planarAngleTo(vectorB, upVector).radians));
|
|
1151
|
+
}
|
|
1152
|
+
// if either vector is zero
|
|
1153
|
+
if (Geometry.isSmallMetricDistance(vectorA.magnitude())
|
|
1154
|
+
|| Geometry.isSmallMetricDistance(vectorB.magnitude()))
|
|
1155
|
+
return undefined;
|
|
1156
|
+
// aligned vectors (cross product = 0, dot product > 0)
|
|
1157
|
+
if (vectorA.dotProduct(vectorB) > 0.0)
|
|
1158
|
+
return Matrix3d.createIdentity(result);
|
|
1159
|
+
// opposing vectors (cross product = 0, dot product < 0)
|
|
1160
|
+
upVector = Matrix3d.createPerpendicularVectorFavorPlaneContainingZ(vectorA, upVector);
|
|
1161
|
+
return Matrix3d.createRotationAroundVector(upVector, Angle.createRadians(fraction * Math.PI));
|
|
1162
|
+
}
|
|
1163
|
+
/** Returns a matrix that rotates from vectorA to vectorB. */
|
|
1164
|
+
static createRotationVectorToVector(vectorA, vectorB, result) {
|
|
1165
|
+
return this.createPartialRotationVectorToVector(vectorA, 1.0, vectorB, result);
|
|
1166
|
+
}
|
|
1167
|
+
/** Create a 90 degree rotation around a principal axis */
|
|
1168
|
+
static create90DegreeRotationAroundAxis(axisIndex) {
|
|
1169
|
+
axisIndex = Geometry.cyclic3dAxis(axisIndex);
|
|
1170
|
+
if (axisIndex === 0) {
|
|
1171
|
+
const retVal = Matrix3d.createRowValues(1, 0, 0, 0, 0, -1, 0, 1, 0);
|
|
1172
|
+
retVal.setupInverseTranspose();
|
|
1173
|
+
return retVal;
|
|
1174
|
+
}
|
|
1175
|
+
else if (axisIndex === 1) {
|
|
1176
|
+
const retVal = Matrix3d.createRowValues(0, 0, 1, 0, 1, 0, -1, 0, 0);
|
|
1177
|
+
retVal.setupInverseTranspose();
|
|
1178
|
+
return retVal;
|
|
1179
|
+
}
|
|
1180
|
+
else {
|
|
1181
|
+
const retVal = Matrix3d.createRowValues(0, -1, 0, 1, 0, 0, 0, 0, 1);
|
|
1182
|
+
retVal.setupInverseTranspose();
|
|
1183
|
+
return retVal;
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
/** Return (a copy of) the X column */
|
|
1187
|
+
columnX(result) {
|
|
1188
|
+
return Vector3d.create(this.coffs[0], this.coffs[3], this.coffs[6], result);
|
|
1189
|
+
}
|
|
1190
|
+
/** Return (a copy of) the Y column */
|
|
1191
|
+
columnY(result) {
|
|
1192
|
+
return Vector3d.create(this.coffs[1], this.coffs[4], this.coffs[7], result);
|
|
1193
|
+
}
|
|
1194
|
+
/** Return (a copy of) the Z column */
|
|
1195
|
+
columnZ(result) {
|
|
1196
|
+
return Vector3d.create(this.coffs[2], this.coffs[5], this.coffs[8], result);
|
|
1197
|
+
}
|
|
1198
|
+
/** Return the X column magnitude squared */
|
|
1199
|
+
columnXMagnitudeSquared() {
|
|
1200
|
+
return Geometry.hypotenuseSquaredXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1201
|
+
}
|
|
1202
|
+
/** Return the Y column magnitude squared */
|
|
1203
|
+
columnYMagnitudeSquared() {
|
|
1204
|
+
return Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1205
|
+
}
|
|
1206
|
+
/** Return the Z column magnitude squared */
|
|
1207
|
+
columnZMagnitudeSquared() {
|
|
1208
|
+
return Geometry.hypotenuseSquaredXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1209
|
+
}
|
|
1210
|
+
/** Return the X column magnitude */
|
|
1211
|
+
columnXMagnitude() {
|
|
1212
|
+
return Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1213
|
+
}
|
|
1214
|
+
/** Return the Y column magnitude */
|
|
1215
|
+
columnYMagnitude() {
|
|
1216
|
+
return Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1217
|
+
}
|
|
1218
|
+
/** Return the Z column magnitude */
|
|
1219
|
+
columnZMagnitude() {
|
|
1220
|
+
return Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1221
|
+
}
|
|
1222
|
+
/** Return magnitude of columnX cross columnY. */
|
|
1223
|
+
columnXYCrossProductMagnitude() {
|
|
1224
|
+
return Geometry.crossProductMagnitude(this.coffs[0], this.coffs[3], this.coffs[6], this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1225
|
+
}
|
|
1226
|
+
/** Return the X row magnitude */
|
|
1227
|
+
rowXMagnitude() {
|
|
1228
|
+
return Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[1], this.coffs[2]);
|
|
1229
|
+
}
|
|
1230
|
+
/** Return the Y row magnitude */
|
|
1231
|
+
rowYMagnitude() {
|
|
1232
|
+
return Geometry.hypotenuseXYZ(this.coffs[3], this.coffs[4], this.coffs[5]);
|
|
1233
|
+
}
|
|
1234
|
+
/** Return the Z row magnitude */
|
|
1235
|
+
rowZMagnitude() {
|
|
1236
|
+
return Geometry.hypotenuseXYZ(this.coffs[6], this.coffs[7], this.coffs[8]);
|
|
1237
|
+
}
|
|
1238
|
+
/** Return the dot product of column X with column Y */
|
|
1239
|
+
columnXDotColumnY() {
|
|
1240
|
+
return this.coffs[0] * this.coffs[1]
|
|
1241
|
+
+ this.coffs[3] * this.coffs[4]
|
|
1242
|
+
+ this.coffs[6] * this.coffs[7];
|
|
1309
1243
|
}
|
|
1310
1244
|
/**
|
|
1311
|
-
*
|
|
1312
|
-
*
|
|
1313
|
-
* @param
|
|
1314
|
-
* @param
|
|
1245
|
+
* Dot product of an indexed column with a vector given as x,y,z
|
|
1246
|
+
* @param columnIndex index of column. Must be 0,1,2.
|
|
1247
|
+
* @param x x component of vector
|
|
1248
|
+
* @param y y component of vector
|
|
1249
|
+
* @param z z component of vector
|
|
1315
1250
|
*/
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
// console.log (" sum", sum);
|
|
1327
|
-
if (sum < tolerance) {
|
|
1328
|
-
// console.log("symmetric iterations", iteration);
|
|
1329
|
-
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
1330
|
-
return true;
|
|
1331
|
-
}
|
|
1332
|
-
}
|
|
1333
|
-
return false;
|
|
1251
|
+
columnDotXYZ(columnIndex, x, y, z) {
|
|
1252
|
+
return this.coffs[columnIndex] * x + this.coffs[columnIndex + 3] * y + this.coffs[columnIndex + 6] * z;
|
|
1253
|
+
}
|
|
1254
|
+
/** Return (a copy of) the X row */
|
|
1255
|
+
rowX(result) {
|
|
1256
|
+
return Vector3d.create(this.coffs[0], this.coffs[1], this.coffs[2], result);
|
|
1257
|
+
}
|
|
1258
|
+
/** Return (a copy of) the Y row */
|
|
1259
|
+
rowY(result) {
|
|
1260
|
+
return Vector3d.create(this.coffs[3], this.coffs[4], this.coffs[5], result);
|
|
1334
1261
|
}
|
|
1335
|
-
/**
|
|
1262
|
+
/** Return (a copy of) the Z row */
|
|
1263
|
+
rowZ(result) {
|
|
1264
|
+
return Vector3d.create(this.coffs[6], this.coffs[7], this.coffs[8], result);
|
|
1265
|
+
}
|
|
1266
|
+
/** Return the dot product of the vector parameter with the X column. */
|
|
1267
|
+
dotColumnX(vector) {
|
|
1268
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[3] + vector.z * this.coffs[6];
|
|
1269
|
+
}
|
|
1270
|
+
/** Return the dot product of the vector parameter with the Y column. */
|
|
1271
|
+
dotColumnY(vector) {
|
|
1272
|
+
return vector.x * this.coffs[1] + vector.y * this.coffs[4] + vector.z * this.coffs[7];
|
|
1273
|
+
}
|
|
1274
|
+
/** Return the dot product of the vector parameter with the Z column. */
|
|
1275
|
+
dotColumnZ(vector) {
|
|
1276
|
+
return vector.x * this.coffs[2] + vector.y * this.coffs[5] + vector.z * this.coffs[8];
|
|
1277
|
+
}
|
|
1278
|
+
/** Return the dot product of the vector parameter with the X row. */
|
|
1279
|
+
dotRowX(vector) {
|
|
1280
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[1] + vector.z * this.coffs[2];
|
|
1281
|
+
}
|
|
1282
|
+
/** Return the dot product of the vector parameter with the Y row. */
|
|
1283
|
+
dotRowY(vector) {
|
|
1284
|
+
return vector.x * this.coffs[3] + vector.y * this.coffs[4] + vector.z * this.coffs[5];
|
|
1285
|
+
}
|
|
1286
|
+
/** Return the dot product of the vector parameter with the Z row. */
|
|
1287
|
+
dotRowZ(vector) {
|
|
1288
|
+
return vector.x * this.coffs[6] + vector.y * this.coffs[7] + vector.z * this.coffs[8];
|
|
1289
|
+
}
|
|
1290
|
+
/** Return the dot product of the x,y,z with the X row. */
|
|
1291
|
+
dotRowXXYZ(x, y, z) {
|
|
1292
|
+
return x * this.coffs[0] + y * this.coffs[1] + z * this.coffs[2];
|
|
1293
|
+
}
|
|
1294
|
+
/** Return the dot product of the x,y,z with the Y row. */
|
|
1295
|
+
dotRowYXYZ(x, y, z) {
|
|
1296
|
+
return x * this.coffs[3] + y * this.coffs[4] + z * this.coffs[5];
|
|
1297
|
+
}
|
|
1298
|
+
/** Return the dot product of the x,y,z with the Z row. */
|
|
1299
|
+
dotRowZXYZ(x, y, z) {
|
|
1300
|
+
return x * this.coffs[6] + y * this.coffs[7] + z * this.coffs[8];
|
|
1301
|
+
}
|
|
1302
|
+
/** Return the cross product of the Z column with the vector parameter. */
|
|
1303
|
+
columnZCrossVector(vector, result) {
|
|
1304
|
+
return Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
1305
|
+
}
|
|
1306
|
+
/** Set data from xyz parts of Point4d (w part of Point4d ignored) */
|
|
1336
1307
|
setColumnsPoint4dXYZ(vectorU, vectorV, vectorW) {
|
|
1337
1308
|
this.inverseState = InverseMatrixState.unknown;
|
|
1338
1309
|
this.setRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z);
|
|
@@ -1356,16 +1327,22 @@ export class Matrix3d {
|
|
|
1356
1327
|
this.coffs[index + 6] = 0.0;
|
|
1357
1328
|
}
|
|
1358
1329
|
}
|
|
1359
|
-
/**
|
|
1330
|
+
/**
|
|
1331
|
+
* Set all columns of the matrix. Any undefined vector is zeros.
|
|
1332
|
+
* @param vectorX values for column 0
|
|
1333
|
+
* @param vectorY values for column 1
|
|
1334
|
+
* @param vectorZ optional values for column 2 (it's optional in case column 2 is 000, which is a
|
|
1335
|
+
* projection onto the xy-plane)
|
|
1336
|
+
*/
|
|
1360
1337
|
setColumns(vectorX, vectorY, vectorZ) {
|
|
1361
1338
|
this.setColumn(0, vectorX);
|
|
1362
1339
|
this.setColumn(1, vectorY);
|
|
1363
1340
|
this.setColumn(2, vectorZ);
|
|
1364
1341
|
}
|
|
1365
1342
|
/**
|
|
1366
|
-
*
|
|
1367
|
-
* @param rowIndex row index.
|
|
1368
|
-
* @param value x,
|
|
1343
|
+
* Set entries in one row of the matrix.
|
|
1344
|
+
* @param rowIndex row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1345
|
+
* @param value x,y,z values for row.
|
|
1369
1346
|
*/
|
|
1370
1347
|
setRow(rowIndex, value) {
|
|
1371
1348
|
const index = 3 * Geometry.cyclic3dAxis(rowIndex);
|
|
@@ -1374,21 +1351,26 @@ export class Matrix3d {
|
|
|
1374
1351
|
this.coffs[index + 2] = value.z;
|
|
1375
1352
|
this.inverseState = InverseMatrixState.unknown;
|
|
1376
1353
|
}
|
|
1377
|
-
/**
|
|
1378
|
-
*
|
|
1354
|
+
/**
|
|
1355
|
+
* Return (a copy of) a column of the matrix.
|
|
1356
|
+
* @param i column index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1357
|
+
* @param result optional preallocated result.
|
|
1379
1358
|
*/
|
|
1380
1359
|
getColumn(columnIndex, result) {
|
|
1381
1360
|
const index = Geometry.cyclic3dAxis(columnIndex);
|
|
1382
1361
|
return Vector3d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], result);
|
|
1383
1362
|
}
|
|
1384
|
-
/**
|
|
1385
|
-
*
|
|
1363
|
+
/**
|
|
1364
|
+
* Return a (copy of) a row of the matrix.
|
|
1365
|
+
* @param i row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1366
|
+
* @param result optional preallocated result.
|
|
1386
1367
|
*/
|
|
1387
1368
|
getRow(columnIndex, result) {
|
|
1388
1369
|
const index = 3 * Geometry.cyclic3dAxis(columnIndex);
|
|
1389
1370
|
return Vector3d.create(this.coffs[index], this.coffs[index + 1], this.coffs[index + 2], result);
|
|
1390
1371
|
}
|
|
1391
|
-
/**
|
|
1372
|
+
/**
|
|
1373
|
+
* Create a matrix from row vectors.
|
|
1392
1374
|
* ```
|
|
1393
1375
|
* equation
|
|
1394
1376
|
* \begin{bmatrix}U_x & U_y & U_z \\ V_x & V_y & V_z \\ W_x & W_y & W_z \end{bmatrix}
|
|
@@ -1397,13 +1379,18 @@ export class Matrix3d {
|
|
|
1397
1379
|
static createRows(vectorU, vectorV, vectorW, result) {
|
|
1398
1380
|
return Matrix3d.createRowValues(vectorU.x, vectorU.y, vectorU.z, vectorV.x, vectorV.y, vectorV.z, vectorW.x, vectorW.y, vectorW.z, result);
|
|
1399
1381
|
}
|
|
1400
|
-
/**
|
|
1401
|
-
*
|
|
1402
|
-
*
|
|
1382
|
+
/**
|
|
1383
|
+
* Create a matrix that scales along a specified `direction`. This means if you multiply the returned matrix
|
|
1384
|
+
* by a `vector`, you get `directional scale` of that `vector`. Suppose `plane` is the plane perpendicular
|
|
1385
|
+
* to the `direction`. When scale = 0, `directional scale` is projection of the `vector` to the `plane`.
|
|
1386
|
+
* When scale = 1, `directional scale` is the `vector` itself. When scale = -1, `directional scale` is
|
|
1387
|
+
* mirror of the `vector` across the `plane`. In general, When scale != 0, the result is computed by first
|
|
1388
|
+
* projecting the `vector` to the `plane`, then translating that projection along the `direction` (if scale > 0)
|
|
1389
|
+
* or in opposite direction (if scale < 0).
|
|
1403
1390
|
* ```
|
|
1404
1391
|
* equation
|
|
1405
|
-
* \text{The matrix is } I
|
|
1406
|
-
* \\ \text{with }
|
|
1392
|
+
* \text{The matrix is } I + (s-1) D D^T
|
|
1393
|
+
* \\ \text{with }D\text{ being the normalized direction vector and }s\text{ being the scale.}
|
|
1407
1394
|
* ```
|
|
1408
1395
|
*/
|
|
1409
1396
|
static createDirectionalScale(direction, scale, result) {
|
|
@@ -1412,19 +1399,13 @@ export class Matrix3d {
|
|
|
1412
1399
|
const x = unit.x;
|
|
1413
1400
|
const y = unit.y;
|
|
1414
1401
|
const z = unit.z;
|
|
1415
|
-
const a =
|
|
1402
|
+
const a = scale - 1;
|
|
1416
1403
|
return Matrix3d.createRowValues(1 + a * x * x, a * x * y, a * x * z, a * y * x, 1 + a * y * y, a * y * z, a * z * x, a * z * y, 1 + a * z * z, result);
|
|
1417
1404
|
}
|
|
1418
1405
|
return Matrix3d.createUniformScale(scale);
|
|
1419
1406
|
}
|
|
1420
|
-
|
|
1421
|
-
* *
|
|
1422
|
-
* * If the direction vector is not close to Z, the "next" column ((axisIndex + 1) mod 3) will be in the XY plane in the direction of (direction cross Z)
|
|
1423
|
-
* * If the direction vector is close to Z, the "next" column ((axisIndex + 1) mode 3) will be in the direction of (direction cross Y)
|
|
1424
|
-
*/
|
|
1425
|
-
// static create1Vector(direction: Vector3d, axisIndex: number): Matrix3d;
|
|
1426
|
-
// static createFromXYVectors(vectorX: Vector3d, vectorY: Vector3d, axisIndex: number): Matrix3d;
|
|
1427
|
-
/** Multiply the matrix * vector, treating the vector is a column vector on the right.
|
|
1407
|
+
/**
|
|
1408
|
+
* Multiply `matrix * vector`, treating the vector is a column vector on the right.
|
|
1428
1409
|
* ```
|
|
1429
1410
|
* equation
|
|
1430
1411
|
* \matrixXY{A}\columnSubXYZ{U}
|
|
@@ -1435,36 +1416,38 @@ export class Matrix3d {
|
|
|
1435
1416
|
const x = vectorU.x;
|
|
1436
1417
|
const y = vectorU.y;
|
|
1437
1418
|
const z = vectorU.z;
|
|
1438
|
-
return Vector3d.create(
|
|
1419
|
+
return Vector3d.create(this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z, this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z, this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z, result);
|
|
1439
1420
|
}
|
|
1440
|
-
/**
|
|
1441
|
-
*
|
|
1421
|
+
/**
|
|
1422
|
+
* Multiply `matrix * vector` in place for vector in the array, i.e. treating the vector is a column
|
|
1423
|
+
* vector on the right.
|
|
1424
|
+
* * Each `vector` is updated to be `matrix * vector`
|
|
1442
1425
|
*/
|
|
1443
1426
|
multiplyVectorArrayInPlace(data) {
|
|
1444
1427
|
for (const v of data)
|
|
1445
|
-
v.set(
|
|
1428
|
+
v.set(this.coffs[0] * v.x + this.coffs[1] * v.y + this.coffs[2] * v.z, this.coffs[3] * v.x + this.coffs[4] * v.y + this.coffs[5] * v.z, this.coffs[6] * v.x + this.coffs[7] * v.y + this.coffs[8] * v.z);
|
|
1446
1429
|
}
|
|
1447
|
-
/**
|
|
1430
|
+
/** Compute `origin - matrix * vector` */
|
|
1448
1431
|
static xyzMinusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1449
1432
|
const x = vector.x;
|
|
1450
1433
|
const y = vector.y;
|
|
1451
1434
|
const z = vector.z;
|
|
1452
1435
|
return Point3d.create(origin.x - (matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z), origin.y - (matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z), origin.z - (matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z), result);
|
|
1453
1436
|
}
|
|
1454
|
-
/**
|
|
1437
|
+
/** Compute `origin + matrix * vector` using only the xy parts of the inputs. */
|
|
1455
1438
|
static xyPlusMatrixTimesXY(origin, matrix, vector, result) {
|
|
1456
1439
|
const x = vector.x;
|
|
1457
1440
|
const y = vector.y;
|
|
1458
1441
|
return Point2d.create(origin.x + matrix.coffs[0] * x + matrix.coffs[1] * y, origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y, result);
|
|
1459
1442
|
}
|
|
1460
|
-
/**
|
|
1443
|
+
/** Compute `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1461
1444
|
static xyzPlusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1462
1445
|
const x = vector.x;
|
|
1463
1446
|
const y = vector.y;
|
|
1464
1447
|
const z = vector.z;
|
|
1465
1448
|
return Point3d.create(origin.x + matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z, origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z, origin.z + matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z, result);
|
|
1466
1449
|
}
|
|
1467
|
-
/**
|
|
1450
|
+
/** Updates vector to be `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1468
1451
|
static xyzPlusMatrixTimesXYZInPlace(origin, matrix, vector) {
|
|
1469
1452
|
const x = vector.x;
|
|
1470
1453
|
const y = vector.y;
|
|
@@ -1473,61 +1456,72 @@ export class Matrix3d {
|
|
|
1473
1456
|
vector.y = origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z;
|
|
1474
1457
|
vector.z = origin.z + matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z;
|
|
1475
1458
|
}
|
|
1476
|
-
/**
|
|
1459
|
+
/** Compute `origin + matrix * vector` where the final vector is given as direct x,y,z coordinates */
|
|
1477
1460
|
static xyzPlusMatrixTimesCoordinates(origin, matrix, x, y, z, result) {
|
|
1478
1461
|
return Point3d.create(origin.x + matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z, origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z, origin.z + matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z, result);
|
|
1479
1462
|
}
|
|
1480
1463
|
/**
|
|
1481
1464
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1482
|
-
* Multiply
|
|
1465
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1466
|
+
* ```
|
|
1467
|
+
* equation
|
|
1468
|
+
* \begin{bmatrix}M_0 & M_1 & M_2 & Ox \\ M_3 & M_4 & M_5 & Oy \\ M_6 & M_7 & M_8 & Oz \\ 0 & 0 & 0 & 1\end{bmatrix} * \begin{bmatrix}x \\ y \\ z \\ w\end{bmatrix}
|
|
1469
|
+
* ```
|
|
1483
1470
|
* @param origin translation part (xyz in column 3)
|
|
1484
1471
|
* @param matrix matrix part (leading 3x3)
|
|
1485
1472
|
* @param x x part of multiplied point
|
|
1486
1473
|
* @param y y part of multiplied point
|
|
1487
1474
|
* @param z z part of multiplied point
|
|
1488
1475
|
* @param w w part of multiplied point
|
|
1489
|
-
* @param result optional result.
|
|
1476
|
+
* @param result optional preallocated result.
|
|
1490
1477
|
*/
|
|
1491
1478
|
static xyzPlusMatrixTimesWeightedCoordinates(origin, matrix, x, y, z, w, result) {
|
|
1492
|
-
return Point4d.create(
|
|
1479
|
+
return Point4d.create(matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x * w, matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y * w, matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z * w, w, result);
|
|
1493
1480
|
}
|
|
1494
1481
|
/**
|
|
1495
1482
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1496
|
-
* Multiply
|
|
1483
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1484
|
+
* ```
|
|
1485
|
+
* equation
|
|
1486
|
+
* \begin{bmatrix}M_0 & M_1 & M_2 & Ox \\ M_3 & M_4 & M_5 & Oy \\ M_6 & M_7 & M_8 & Oz \\ 0 & 0 & 0 & 1\end{bmatrix} * \begin{bmatrix}x \\ y \\ z \\ w\end{bmatrix}
|
|
1487
|
+
* ```
|
|
1497
1488
|
* @param origin translation part (xyz in column 3)
|
|
1498
1489
|
* @param matrix matrix part (leading 3x3)
|
|
1499
1490
|
* @param x x part of multiplied point
|
|
1500
1491
|
* @param y y part of multiplied point
|
|
1501
1492
|
* @param z z part of multiplied point
|
|
1502
1493
|
* @param w w part of multiplied point
|
|
1503
|
-
* @param result optional result.
|
|
1494
|
+
* @param result optional preallocated result.
|
|
1504
1495
|
*/
|
|
1505
1496
|
static xyzPlusMatrixTimesWeightedCoordinatesToFloat64Array(origin, matrix, x, y, z, w, result) {
|
|
1506
1497
|
if (!result)
|
|
1507
1498
|
result = new Float64Array(4);
|
|
1508
|
-
result[0] =
|
|
1509
|
-
result[1] =
|
|
1510
|
-
result[2] =
|
|
1499
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x * w;
|
|
1500
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y * w;
|
|
1501
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z * w;
|
|
1511
1502
|
result[3] = w;
|
|
1512
1503
|
return result;
|
|
1513
1504
|
}
|
|
1514
1505
|
/**
|
|
1515
|
-
* Treat the 3x3 matrix and origin as
|
|
1516
|
-
* Multiply
|
|
1506
|
+
* Treat the 3x3 matrix and origin as a 3x4 matrix.
|
|
1507
|
+
* * Multiply the 3x4 matrix by `[x,y,z,1]`
|
|
1508
|
+
* ```
|
|
1509
|
+
* equation
|
|
1510
|
+
* \begin{bmatrix}M_0 & M_1 & M_2 & Ox \\ M_3 & M_4 & M_5 & Oy \\ M_6 & M_7 & M_8 & Oz\end{bmatrix} * \begin{bmatrix}x \\ y \\ z \\ 1\end{bmatrix}
|
|
1511
|
+
* ```
|
|
1517
1512
|
* @param origin translation part (xyz in column 3)
|
|
1518
1513
|
* @param matrix matrix part (leading 3x3)
|
|
1519
1514
|
* @param x x part of multiplied point
|
|
1520
1515
|
* @param y y part of multiplied point
|
|
1521
1516
|
* @param z z part of multiplied point
|
|
1522
|
-
* @param
|
|
1523
|
-
* @param result optional result.
|
|
1517
|
+
* @param result optional preallocated result.
|
|
1524
1518
|
*/
|
|
1525
1519
|
static xyzPlusMatrixTimesCoordinatesToFloat64Array(origin, matrix, x, y, z, result) {
|
|
1526
1520
|
if (!result)
|
|
1527
1521
|
result = new Float64Array(3);
|
|
1528
|
-
result[0] =
|
|
1529
|
-
result[1] =
|
|
1530
|
-
result[2] =
|
|
1522
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x;
|
|
1523
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y;
|
|
1524
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z;
|
|
1531
1525
|
return result;
|
|
1532
1526
|
}
|
|
1533
1527
|
/**
|
|
@@ -1547,9 +1541,9 @@ export class Matrix3d {
|
|
|
1547
1541
|
const x = vector.x;
|
|
1548
1542
|
const y = vector.y;
|
|
1549
1543
|
const z = vector.z;
|
|
1550
|
-
result.x =
|
|
1551
|
-
result.y =
|
|
1552
|
-
result.z =
|
|
1544
|
+
result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1545
|
+
result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1546
|
+
result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1553
1547
|
return result;
|
|
1554
1548
|
}
|
|
1555
1549
|
/** Multiply the matrix * (x,y,z), i.e. the vector (x,y,z) is a column vector on the right.
|
|
@@ -2077,7 +2071,7 @@ export class Matrix3d {
|
|
|
2077
2071
|
* @param scaleX scale factor for column x
|
|
2078
2072
|
* @param scaleY scale factor for column y
|
|
2079
2073
|
* @param scaleZ scale factor for column z
|
|
2080
|
-
* @param result optional result.
|
|
2074
|
+
* @param result optional preallocated result.
|
|
2081
2075
|
*/
|
|
2082
2076
|
scaleColumns(scaleX, scaleY, scaleZ, result) {
|
|
2083
2077
|
return Matrix3d.createRowValues(this.coffs[0] * scaleX, this.coffs[1] * scaleY, this.coffs[2] * scaleZ, this.coffs[3] * scaleX, this.coffs[4] * scaleY, this.coffs[5] * scaleZ, this.coffs[6] * scaleX, this.coffs[7] * scaleY, this.coffs[8] * scaleZ, result);
|
|
@@ -2098,7 +2092,7 @@ export class Matrix3d {
|
|
|
2098
2092
|
this.coffs[7] *= scaleY;
|
|
2099
2093
|
this.coffs[8] *= scaleZ;
|
|
2100
2094
|
if (this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined) {
|
|
2101
|
-
// apply
|
|
2095
|
+
// apply reverse scales to the ROWS of the inverse
|
|
2102
2096
|
const divX = Geometry.conditionalDivideFraction(1.0, scaleX);
|
|
2103
2097
|
const divY = Geometry.conditionalDivideFraction(1.0, scaleY);
|
|
2104
2098
|
const divZ = Geometry.conditionalDivideFraction(1.0, scaleZ);
|
|
@@ -2121,7 +2115,7 @@ export class Matrix3d {
|
|
|
2121
2115
|
* @param scaleX scale factor for row x
|
|
2122
2116
|
* @param scaleY scale factor for row y
|
|
2123
2117
|
* @param scaleZ scale factor for row z
|
|
2124
|
-
* @param result optional result.
|
|
2118
|
+
* @param result optional preallocated result.
|
|
2125
2119
|
*/
|
|
2126
2120
|
scaleRows(scaleX, scaleY, scaleZ, result) {
|
|
2127
2121
|
return Matrix3d.createRowValues(this.coffs[0] * scaleX, this.coffs[1] * scaleX, this.coffs[2] * scaleX, this.coffs[3] * scaleY, this.coffs[4] * scaleY, this.coffs[5] * scaleY, this.coffs[6] * scaleZ, this.coffs[7] * scaleZ, this.coffs[8] * scaleZ, result);
|
|
@@ -2165,12 +2159,49 @@ export class Matrix3d {
|
|
|
2165
2159
|
}
|
|
2166
2160
|
/** create a Matrix3d whose values are uniformly scaled from this.
|
|
2167
2161
|
* @param scale scale factor to apply.
|
|
2168
|
-
* @param result optional result.
|
|
2162
|
+
* @param result optional preallocated result.
|
|
2169
2163
|
* @returns Return the new or repopulated matrix
|
|
2170
2164
|
*/
|
|
2171
2165
|
scale(scale, result) {
|
|
2172
2166
|
return Matrix3d.createRowValues(this.coffs[0] * scale, this.coffs[1] * scale, this.coffs[2] * scale, this.coffs[3] * scale, this.coffs[4] * scale, this.coffs[5] * scale, this.coffs[6] * scale, this.coffs[7] * scale, this.coffs[8] * scale, result);
|
|
2173
2167
|
}
|
|
2168
|
+
/**
|
|
2169
|
+
* Create a rigid matrix (columns and rows are unit length and pairwise perpendicular) for
|
|
2170
|
+
* the given eye coordinate.
|
|
2171
|
+
* * column z is parallel to x,y,z
|
|
2172
|
+
* * column x is perpendicular to column z and is in the xy plane
|
|
2173
|
+
* * column y is perpendicular to both. It is the "up" vector on the view plane.
|
|
2174
|
+
* * Multiplying the returned matrix times a local (view) vector gives the world vector.
|
|
2175
|
+
* * Multiplying transpose of the returned matrix times a world vector gives the local
|
|
2176
|
+
* (view) vector.
|
|
2177
|
+
* @param x eye x coordinate
|
|
2178
|
+
* @param y eye y coordinate
|
|
2179
|
+
* @param z eye z coordinate
|
|
2180
|
+
* @param result optional preallocated result
|
|
2181
|
+
*/
|
|
2182
|
+
static createRigidViewAxesZTowardsEye(x, y, z, result) {
|
|
2183
|
+
result = Matrix3d.createIdentity(result);
|
|
2184
|
+
const rxy = Geometry.hypotenuseXY(x, y);
|
|
2185
|
+
// if coordinate is (0,0,z), i.e., Top or Bottom view
|
|
2186
|
+
if (Geometry.isSmallMetricDistance(rxy)) {
|
|
2187
|
+
if (z < 0.0)
|
|
2188
|
+
result.scaleColumnsInPlace(1.0, -1.0, -1.0);
|
|
2189
|
+
}
|
|
2190
|
+
else {
|
|
2191
|
+
const c = x / rxy;
|
|
2192
|
+
const s = y / rxy;
|
|
2193
|
+
// if coordinate is (x,y,0), i.e., Front or Back or Left or Right view
|
|
2194
|
+
result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
|
|
2195
|
+
// if coordinate is (x,y,z), i.e., other views such as Iso or RightIso
|
|
2196
|
+
if (z !== 0.0) {
|
|
2197
|
+
const r = Geometry.hypotenuseXYZ(x, y, z);
|
|
2198
|
+
const s1 = z / r;
|
|
2199
|
+
const c1 = rxy / r;
|
|
2200
|
+
result.applyGivensColumnOp(1, 2, c1, -s1);
|
|
2201
|
+
}
|
|
2202
|
+
}
|
|
2203
|
+
return result;
|
|
2204
|
+
}
|
|
2174
2205
|
/** Return the determinant of this matrix. */
|
|
2175
2206
|
determinant() {
|
|
2176
2207
|
return this.coffs[0] * this.coffs[4] * this.coffs[8]
|