@itwin/core-geometry 4.0.0-dev.2 → 4.0.0-dev.22
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/CHANGELOG.md +10 -1
- 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/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js +19 -12
- package/lib/cjs/curve/CurveChainWithDistanceIndex.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/Angle.d.ts +19 -0
- package/lib/cjs/geometry3d/Angle.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Angle.js +39 -0
- package/lib/cjs/geometry3d/Angle.js.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.d.ts +1 -0
- package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.js +1 -0
- package/lib/cjs/geometry3d/AngleSweep.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 +326 -208
- package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.js +683 -613
- package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts +15 -13
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.js +18 -13
- 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/cjs/numerics/Polynomials.d.ts +12 -0
- package/lib/cjs/numerics/Polynomials.d.ts.map +1 -1
- package/lib/cjs/numerics/Polynomials.js +14 -0
- package/lib/cjs/numerics/Polynomials.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts +1 -0
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.js +46 -6
- package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts +54 -0
- package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.js +71 -1
- package/lib/cjs/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/cjs/polyface/multiclip/OffsetMeshContext.d.ts +202 -0
- package/lib/cjs/polyface/multiclip/OffsetMeshContext.d.ts.map +1 -0
- package/lib/cjs/polyface/multiclip/OffsetMeshContext.js +1038 -0
- package/lib/cjs/polyface/multiclip/OffsetMeshContext.js.map +1 -0
- package/lib/cjs/serialization/GeometrySamples.d.ts +4 -1
- package/lib/cjs/serialization/GeometrySamples.d.ts.map +1 -1
- package/lib/cjs/serialization/GeometrySamples.js +14 -6
- package/lib/cjs/serialization/GeometrySamples.js.map +1 -1
- package/lib/cjs/topology/Graph.d.ts +113 -7
- package/lib/cjs/topology/Graph.d.ts.map +1 -1
- package/lib/cjs/topology/Graph.js +185 -7
- package/lib/cjs/topology/Graph.js.map +1 -1
- package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts +38 -0
- package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts.map +1 -0
- package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.js +82 -0
- package/lib/cjs/topology/HalfEdgeGraphFromIndexedLoopsContext.js.map +1 -0
- 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/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js +20 -13
- package/lib/esm/curve/CurveChainWithDistanceIndex.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/Angle.d.ts +19 -0
- package/lib/esm/geometry3d/Angle.d.ts.map +1 -1
- package/lib/esm/geometry3d/Angle.js +39 -0
- package/lib/esm/geometry3d/Angle.js.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.d.ts +1 -0
- package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.js +1 -0
- package/lib/esm/geometry3d/AngleSweep.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 +326 -208
- package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.js +683 -613
- package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.d.ts +15 -13
- package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.js +18 -13
- 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/lib/esm/numerics/Polynomials.d.ts +12 -0
- package/lib/esm/numerics/Polynomials.d.ts.map +1 -1
- package/lib/esm/numerics/Polynomials.js +14 -0
- package/lib/esm/numerics/Polynomials.js.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.d.ts +1 -0
- package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.js +46 -6
- package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts +54 -0
- package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.js +69 -0
- package/lib/esm/polyface/PolyfaceQuery.js.map +1 -1
- package/lib/esm/polyface/multiclip/OffsetMeshContext.d.ts +202 -0
- package/lib/esm/polyface/multiclip/OffsetMeshContext.d.ts.map +1 -0
- package/lib/esm/polyface/multiclip/OffsetMeshContext.js +1032 -0
- package/lib/esm/polyface/multiclip/OffsetMeshContext.js.map +1 -0
- package/lib/esm/serialization/GeometrySamples.d.ts +4 -1
- package/lib/esm/serialization/GeometrySamples.d.ts.map +1 -1
- package/lib/esm/serialization/GeometrySamples.js +14 -6
- package/lib/esm/serialization/GeometrySamples.js.map +1 -1
- package/lib/esm/topology/Graph.d.ts +113 -7
- package/lib/esm/topology/Graph.d.ts.map +1 -1
- package/lib/esm/topology/Graph.js +185 -7
- package/lib/esm/topology/Graph.js.map +1 -1
- package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts +38 -0
- package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.d.ts.map +1 -0
- package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.js +78 -0
- package/lib/esm/topology/HalfEdgeGraphFromIndexedLoopsContext.js.map +1 -0
- package/package.json +5 -5
|
@@ -15,6 +15,7 @@ const Point2dVector2d_1 = require("./Point2dVector2d");
|
|
|
15
15
|
const Point3dVector3d_1 = require("./Point3dVector3d");
|
|
16
16
|
const Transform_1 = require("./Transform");
|
|
17
17
|
/* eslint-disable @itwin/prefer-get */
|
|
18
|
+
// cSpell:words XXYZ YXYZ ZXYZ SaeedTorabi
|
|
18
19
|
/**
|
|
19
20
|
* PackedMatrix3dOps contains static methods for matrix operations where the matrix is a Float64Array.
|
|
20
21
|
* * The Float64Array contains the matrix entries in row-major order
|
|
@@ -425,9 +426,20 @@ class Matrix3d {
|
|
|
425
426
|
return result;
|
|
426
427
|
}
|
|
427
428
|
/**
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
429
|
+
* Create the inverseCoffs member (filled with zeros)
|
|
430
|
+
* This is for use by matrix * matrix multiplications which need to be sure the member is there to be
|
|
431
|
+
* filled with method-specific content.
|
|
432
|
+
*/
|
|
433
|
+
createInverseCoffsWithZeros() {
|
|
434
|
+
if (!this.inverseCoffs) {
|
|
435
|
+
this.inverseState = InverseMatrixState.unknown;
|
|
436
|
+
this.inverseCoffs = new Float64Array(9);
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* Copy the transpose of the coffs to the inverseCoffs.
|
|
441
|
+
* * Mark the matrix as inverseStored.
|
|
442
|
+
*/
|
|
431
443
|
setupInverseTranspose() {
|
|
432
444
|
const coffs = this.coffs;
|
|
433
445
|
this.inverseState = InverseMatrixState.inverseStored;
|
|
@@ -643,8 +655,10 @@ class Matrix3d {
|
|
|
643
655
|
return undefined;
|
|
644
656
|
}
|
|
645
657
|
/**
|
|
646
|
-
* Construct a rigid matrix using vectorA and its 2 perpendicular.
|
|
658
|
+
* Construct a rigid matrix (orthogonal matrix with +1 determinant) using vectorA and its 2 perpendicular.
|
|
659
|
+
* * If axisOrder is not passed then `AxisOrder = AxisOrder.ZXY` is used as default.
|
|
647
660
|
* * This function internally uses createPerpendicularVectorFavorXYPlane and createRigidFromColumns.
|
|
661
|
+
* * Visualization can be found at https://www.itwinjs.org/sandbox/SaeedTorabi/2PerpendicularVectorsTo1Vector
|
|
648
662
|
*/
|
|
649
663
|
static createRigidHeadsUp(vectorA, axisOrder = Geometry_1.AxisOrder.ZXY, result) {
|
|
650
664
|
const vectorB = Matrix3d.createPerpendicularVectorFavorXYPlane(vectorA);
|
|
@@ -655,7 +669,7 @@ class Matrix3d {
|
|
|
655
669
|
}
|
|
656
670
|
return Matrix3d.createIdentity(result);
|
|
657
671
|
}
|
|
658
|
-
/** Return the matrix for rotation of `angle` around `axis` */
|
|
672
|
+
/** Return the matrix for rotation of `angle` around desired `axis` */
|
|
659
673
|
static createRotationAroundVector(axis, angle, result) {
|
|
660
674
|
// Rodriguez formula (matrix form), https://mathworld.wolfram.com/RodriguesRotationFormula.html
|
|
661
675
|
const c = angle.cos();
|
|
@@ -669,7 +683,7 @@ class Matrix3d {
|
|
|
669
683
|
}
|
|
670
684
|
return undefined;
|
|
671
685
|
}
|
|
672
|
-
/** Returns a rotation of specified angle around
|
|
686
|
+
/** Returns a rotation of specified angle around one of the main axis (X,Y,Z).
|
|
673
687
|
* @param axisIndex index of axis (AxisIndex.X, AxisIndex.Y, AxisIndex.Z) kept fixed by the rotation.
|
|
674
688
|
* @param angle angle of rotation
|
|
675
689
|
* @param result optional result matrix.
|
|
@@ -692,14 +706,33 @@ class Matrix3d {
|
|
|
692
706
|
return myResult;
|
|
693
707
|
}
|
|
694
708
|
/**
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
709
|
+
* Replace current rows Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
710
|
+
* * There is no checking for i,j being 0,1,2.
|
|
711
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
712
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
713
|
+
* @param c fist coefficient
|
|
714
|
+
* @param s second coefficient
|
|
715
|
+
*/
|
|
716
|
+
applyGivensRowOp(i, j, c, s) {
|
|
717
|
+
let ii = 3 * i;
|
|
718
|
+
let jj = 3 * j;
|
|
719
|
+
const limit = ii + 3;
|
|
720
|
+
for (; ii < limit; ii++, jj++) {
|
|
721
|
+
const a = this.coffs[ii];
|
|
722
|
+
const b = this.coffs[jj];
|
|
723
|
+
this.coffs[ii] = a * c + b * s;
|
|
724
|
+
this.coffs[jj] = -a * s + b * c;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
/**
|
|
728
|
+
* Replace current columns Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
729
|
+
* * There is no checking for i,j being 0,1,2.
|
|
730
|
+
* * This is used in compute intensive inner loops
|
|
731
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
732
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
733
|
+
* @param c fist coefficient
|
|
734
|
+
* @param s second coefficient
|
|
735
|
+
*/
|
|
703
736
|
applyGivensColumnOp(i, j, c, s) {
|
|
704
737
|
const limit = i + 9;
|
|
705
738
|
for (; i < limit; i += 3, j += 3) {
|
|
@@ -710,12 +743,12 @@ class Matrix3d {
|
|
|
710
743
|
}
|
|
711
744
|
}
|
|
712
745
|
/**
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
746
|
+
* Create a matrix from column vectors.
|
|
747
|
+
* ```
|
|
748
|
+
* equation
|
|
749
|
+
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ U_z & V_z & W_z \end{bmatrix}
|
|
750
|
+
* ```
|
|
751
|
+
*/
|
|
719
752
|
static createColumns(vectorU, vectorV, vectorW, result) {
|
|
720
753
|
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z, result);
|
|
721
754
|
}
|
|
@@ -732,8 +765,9 @@ class Matrix3d {
|
|
|
732
765
|
* * ColumnX points in the rightVector direction
|
|
733
766
|
* * ColumnY points in the upVector direction
|
|
734
767
|
* * ColumnZ is a unit cross product of ColumnX and ColumnY.
|
|
735
|
-
* * Optionally rotate
|
|
736
|
-
* * Optionally rotate
|
|
768
|
+
* * Optionally rotate by 45 degrees around `upVector` to bring its left or right vertical edge to center.
|
|
769
|
+
* * Optionally rotate by arctan(1/sqrt(2)) ~ 35.264 degrees around `rightVector` to bring the top or bottom
|
|
770
|
+
* horizontal edge of the view to the center (for isometric views).
|
|
737
771
|
* * This is expected to be used with various principal unit vectors that are perpendicular to each other.
|
|
738
772
|
* * STANDARD TOP VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(), 0, 0)
|
|
739
773
|
* * STANDARD FRONT VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 0, 0)
|
|
@@ -741,16 +775,20 @@ class Matrix3d {
|
|
|
741
775
|
* * STANDARD RIGHT VIEW: createViewedAxes(Vector3d.unitY(), Vector3d.unitZ(), 0, 0)
|
|
742
776
|
* * STANDARD LEFT VIEW: createViewedAxes(Vector3d.unitY(-1), Vector3d.unitZ(), 0, 0)
|
|
743
777
|
* * STANDARD BOTTOM VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(-1), 0, 0)
|
|
778
|
+
* * STANDARD ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), -1, 1)
|
|
779
|
+
* * STANDARD RIGHT ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 1, 1)
|
|
780
|
+
* * Front, right, back, left, top, and bottom standard views are views from faces of the cube
|
|
781
|
+
* and iso and right iso standard views are views from corners of the cube.
|
|
744
782
|
* * Note: createViewedAxes is column-based so always returns local to world
|
|
745
783
|
*
|
|
746
784
|
* @param rightVector ColumnX of the returned matrix. Expected to be perpendicular to upVector.
|
|
747
785
|
* @param upVector ColumnY of the returned matrix. Expected to be perpendicular to rightVector.
|
|
748
|
-
* @param leftNoneRight Specifies the ccw rotation around
|
|
749
|
-
* "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
786
|
+
* @param leftNoneRight Specifies the ccw rotation around `upVector` axis. Normally one of "-1", "0", and "1",
|
|
787
|
+
* where "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
750
788
|
* and "1" indicates rotation by 45 degrees to bring the right vertical edge to center. Other numbers are
|
|
751
789
|
* used as multiplier for this 45 degree rotation.
|
|
752
|
-
* @param topNoneBottom Specifies the ccw rotation around
|
|
753
|
-
* "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
790
|
+
* @param topNoneBottom Specifies the ccw rotation around `rightVector` axis. Normally one of "-1", "0", and "1",
|
|
791
|
+
* where "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
754
792
|
* and "1" indicates isometric rotation (35.264 degrees) to bring the top downward. Other numbers are
|
|
755
793
|
* used as multiplier for the 35.264 degree rotation.
|
|
756
794
|
* @returns matrix = [rightVector, upVector, rightVector cross upVector] with the applied rotations specified
|
|
@@ -788,9 +826,11 @@ class Matrix3d {
|
|
|
788
826
|
* * Default is TOP view (`local X = world X`, `local Y = world Y`, `local Z = world Z`).
|
|
789
827
|
* * To change view from the TOP to one of the other 7 standard views, we need to multiply "world data" to
|
|
790
828
|
* the corresponding matrix1 provided by `createStandardWorldToView(index, false)` and then
|
|
791
|
-
* `matrix1.multiply(world data)` will
|
|
829
|
+
* `matrix1.multiply(world data)` will return "local data".
|
|
792
830
|
* * To change view back to the TOP, we need to multiply "local data" to the corresponding matrix2 provided
|
|
793
831
|
* by `createStandardWorldToView(index, true)` and then `matrix2.multiply(local data)` will returns "world data".
|
|
832
|
+
* * Note: No matter how you rotate the world axis, local X is always pointing right, local Y is always pointing up,
|
|
833
|
+
* and local Z is always pointing toward you.
|
|
794
834
|
*
|
|
795
835
|
* @param index standard view index `StandardViewIndex.Top, Bottom, Left, Right, Front, Back, Iso, RightIso`
|
|
796
836
|
* @param invert if false (default), the return matrix is world to local (view) and if true, the the return
|
|
@@ -799,343 +839,182 @@ class Matrix3d {
|
|
|
799
839
|
*/
|
|
800
840
|
static createStandardWorldToView(index, invert = false, result) {
|
|
801
841
|
switch (index) {
|
|
802
|
-
//
|
|
842
|
+
// Start with TOP view, ccw rotation by 180 degrees around X
|
|
803
843
|
case Geometry_1.StandardViewIndex.Bottom:
|
|
804
844
|
result = Matrix3d.createRowValues(1, 0, 0, 0, -1, 0, 0, 0, -1);
|
|
805
845
|
break;
|
|
806
|
-
//
|
|
846
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 90 degrees around Z
|
|
807
847
|
case Geometry_1.StandardViewIndex.Left:
|
|
808
848
|
result = Matrix3d.createRowValues(0, -1, 0, 0, 0, 1, -1, 0, 0);
|
|
809
849
|
break;
|
|
810
|
-
//
|
|
850
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by -90 degrees around Z
|
|
811
851
|
case Geometry_1.StandardViewIndex.Right:
|
|
812
852
|
result = Matrix3d.createRowValues(0, 1, 0, 0, 0, 1, 1, 0, 0);
|
|
813
853
|
break;
|
|
814
|
-
//
|
|
854
|
+
// Start with TOP view, ccw rotation by -90 degrees around X
|
|
815
855
|
case Geometry_1.StandardViewIndex.Front:
|
|
816
856
|
result = Matrix3d.createRowValues(1, 0, 0, 0, 0, 1, 0, -1, 0);
|
|
817
857
|
break;
|
|
818
|
-
//
|
|
858
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 180 degrees around Z
|
|
819
859
|
case Geometry_1.StandardViewIndex.Back:
|
|
820
860
|
result = Matrix3d.createRowValues(-1, 0, 0, 0, 0, 1, 0, 1, 0);
|
|
821
861
|
break;
|
|
862
|
+
/**
|
|
863
|
+
* Isometric view
|
|
864
|
+
* Start with FRONT view, ccw rotation by -45 degrees around Y and by arctan(1/sqrt(2)) ~ 35.264 degrees around X
|
|
865
|
+
* cos(45) = 1/sqrt(2) = 0.70710678118 and sin(45) = 1/sqrt(2) = 0.70710678118
|
|
866
|
+
* cos(35.264) = 2/sqrt(6) = 0.81649658092 and sin(35.264) = 1/sqrt(3) = 0.57735026919
|
|
867
|
+
* More info: https://en.wikipedia.org/wiki/Isometric_projection
|
|
868
|
+
*/
|
|
822
869
|
case Geometry_1.StandardViewIndex.Iso:
|
|
823
|
-
// start with FRONT view, ccw rotation by -45 degrees around Y and by 35.264 degrees around X
|
|
824
870
|
result = Matrix3d.createRowValues(0.707106781186548, -0.70710678118654757, 0.00000000000000000, 0.408248290463863, 0.40824829046386302, 0.81649658092772603, -0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
825
871
|
break;
|
|
872
|
+
// Start with FRONT view, ccw rotation by 45 degrees around Y and by 35.264 degrees around X
|
|
826
873
|
case Geometry_1.StandardViewIndex.RightIso:
|
|
827
874
|
result = Matrix3d.createRowValues(0.707106781186548, 0.70710678118654757, 0.00000000000000000, -0.408248290463863, 0.40824829046386302, 0.81649658092772603, 0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
828
875
|
break;
|
|
829
|
-
|
|
876
|
+
// no rotation
|
|
877
|
+
case Geometry_1.StandardViewIndex.Top:
|
|
830
878
|
default:
|
|
831
879
|
result = Matrix3d.createIdentity(result);
|
|
832
880
|
}
|
|
833
881
|
if (invert)
|
|
834
|
-
result.transposeInPlace();
|
|
882
|
+
result.transposeInPlace(); // matrix is rigid so transpose and inverse are the same
|
|
835
883
|
return result;
|
|
836
884
|
}
|
|
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
|
-
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
return result
|
|
902
|
-
}
|
|
903
|
-
*/
|
|
885
|
+
/**
|
|
886
|
+
* Apply (in place) a jacobi update that zeros out this.at(i,j).
|
|
887
|
+
* @param i row index of zeroed member
|
|
888
|
+
* @param j column index of zeroed member
|
|
889
|
+
* @param k other row/column index (different from i and j)
|
|
890
|
+
* @param leftEigenVectors a matrix that its columns will be filled by eigenvectors of this Matrix3d
|
|
891
|
+
* (allocated by caller, computed and filled by this function)
|
|
892
|
+
*/
|
|
893
|
+
applyFastSymmetricJacobiUpdate(i, j, k, leftEigenVectors) {
|
|
894
|
+
const indexII = 4 * i;
|
|
895
|
+
const indexJJ = 4 * j;
|
|
896
|
+
const indexIJ = 3 * i + j;
|
|
897
|
+
const indexIK = 3 * i + k;
|
|
898
|
+
const indexJK = 3 * j + k;
|
|
899
|
+
const dotUU = this.coffs[indexII];
|
|
900
|
+
const dotVV = this.coffs[indexJJ];
|
|
901
|
+
const dotUV = this.coffs[indexIJ];
|
|
902
|
+
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(dotUU - dotVV, 2.0 * dotUV);
|
|
903
|
+
if (Math.abs(dotUV) < 1.0e-15 * (dotUU + dotVV))
|
|
904
|
+
return 0.0;
|
|
905
|
+
const c = jacobi.c;
|
|
906
|
+
const s = jacobi.s;
|
|
907
|
+
const cc = c * c;
|
|
908
|
+
const ss = s * s;
|
|
909
|
+
const sc2 = 2.0 * c * s;
|
|
910
|
+
this.coffs[indexII] = cc * dotUU + sc2 * dotUV + ss * dotVV;
|
|
911
|
+
this.coffs[indexJJ] = ss * dotUU - sc2 * dotUV + cc * dotVV;
|
|
912
|
+
this.coffs[indexIJ] = 0.0;
|
|
913
|
+
const a = this.coffs[indexIK];
|
|
914
|
+
const b = this.coffs[indexJK];
|
|
915
|
+
this.coffs[indexIK] = a * c + b * s;
|
|
916
|
+
this.coffs[indexJK] = -s * a + c * b;
|
|
917
|
+
this.coffs[3 * j + i] = 0.0;
|
|
918
|
+
this.coffs[3 * k + i] = this.coffs[indexIK];
|
|
919
|
+
this.coffs[3 * k + j] = this.coffs[indexJK];
|
|
920
|
+
leftEigenVectors.applyGivensColumnOp(i, j, c, s);
|
|
921
|
+
return Math.abs(dotUV);
|
|
922
|
+
}
|
|
923
|
+
/**
|
|
924
|
+
* Factor this (symmetrized) as a product U * lambda * UT where U is orthogonal, lambda is diagonal.
|
|
925
|
+
* The upper triangle is mirrored to lower triangle to enforce symmetry.
|
|
926
|
+
* @param leftEigenvectors a matrix that its columns will be filled by eigenvectors of this Matrix3d
|
|
927
|
+
* (allocated by caller, computed and filled by this function)
|
|
928
|
+
* @param lambda a vector that its entries will be filled by eigenvalues of this Matrix3d
|
|
929
|
+
* (allocated by caller, computed and filled by this function)
|
|
930
|
+
*/
|
|
931
|
+
fastSymmetricEigenvalues(leftEigenvectors, lambda) {
|
|
932
|
+
const matrix = this.clone();
|
|
933
|
+
leftEigenvectors.setIdentity();
|
|
934
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
935
|
+
for (let iteration = 0; iteration < 7; iteration++) {
|
|
936
|
+
const sum = matrix.applyFastSymmetricJacobiUpdate(0, 1, 2, leftEigenvectors)
|
|
937
|
+
+ matrix.applyFastSymmetricJacobiUpdate(0, 2, 1, leftEigenvectors)
|
|
938
|
+
+ matrix.applyFastSymmetricJacobiUpdate(1, 2, 0, leftEigenvectors);
|
|
939
|
+
// console.log("symmetric sum", sum);
|
|
940
|
+
// console.log ("sum", sum);
|
|
941
|
+
if (sum < tolerance) {
|
|
942
|
+
// console.log("symmetric iterations", iteration);
|
|
943
|
+
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
944
|
+
return true;
|
|
945
|
+
}
|
|
946
|
+
}
|
|
947
|
+
return false;
|
|
948
|
+
}
|
|
904
949
|
/**
|
|
905
950
|
* Compute the (unit vector) axis and angle of rotation.
|
|
951
|
+
* * math details can be found at docs/learning/geometry/Angle.md
|
|
906
952
|
* @returns Returns axis and angle of rotation with result.ok === true when the conversion succeeded.
|
|
907
953
|
*/
|
|
908
954
|
getAxisAndAngleOfRotation() {
|
|
909
955
|
const trace = this.coffs[0] + this.coffs[4] + this.coffs[8];
|
|
910
|
-
|
|
911
|
-
const
|
|
912
|
-
const
|
|
913
|
-
|
|
914
|
-
const c = (trace - 1.0) / 2.0;
|
|
915
|
-
const s = Geometry_1.Geometry.hypotenuseXYZ(skewXY, skewYZ, skewZX) / 2.0;
|
|
916
|
-
const e = c * c + s * s - 1.0;
|
|
956
|
+
const skewXY = this.coffs[3] - this.coffs[1]; // 2*z*sin
|
|
957
|
+
const skewYZ = this.coffs[7] - this.coffs[5]; // 2*y*sin
|
|
958
|
+
const skewZX = this.coffs[2] - this.coffs[6]; // 2*x*sin
|
|
959
|
+
// trace = (m00^2 + m11^2 + m22^2) * (1-cos) + 3cos = (1-cos) + 3cos = 1 + 2cos ==> cos = (trace-1) / 2
|
|
960
|
+
const c = (trace - 1.0) / 2.0; // cosine
|
|
961
|
+
const s = Geometry_1.Geometry.hypotenuseXYZ(skewXY, skewYZ, skewZX) / 2.0; // sine
|
|
962
|
+
const e = c * c + s * s - 1.0; // s^2 + c^2 = 1
|
|
963
|
+
// if s^2 + c^2 != 1 then we have a bad matrix so return false
|
|
917
964
|
if (Math.abs(e) > Geometry_1.Geometry.smallAngleRadians) {
|
|
918
|
-
// the sine and cosine are not a unit circle point. bad matrix . ..
|
|
919
965
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
920
966
|
}
|
|
967
|
+
// sin is close to 0 then we got to special cases (angle 0 or 180) which needs to be handled differently
|
|
921
968
|
if (Math.abs(s) < Geometry_1.Geometry.smallAngleRadians) {
|
|
922
|
-
//
|
|
923
|
-
// The matrix is symmetric
|
|
924
|
-
// So it has simple eigenvalues -- either (1,1,1) or (1,-1,-1).
|
|
925
|
-
if (c > 0) // no rotation
|
|
969
|
+
if (c > 0) // sin = 0 and cos = 1 so angle = 0 (i.e., no rotation)
|
|
926
970
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: true };
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
971
|
+
/**
|
|
972
|
+
* If sin = 0 and cos = -1 then angle = 180 (i.e., 180 degree rotation around some axis)
|
|
973
|
+
* then the rotation matrix becomes
|
|
974
|
+
* 2x^2-1 2xy 2xz
|
|
975
|
+
* 2xy 2y^2-1 2yz
|
|
976
|
+
* 2xz 2yz 2z^2-1
|
|
977
|
+
* Note that the matrix is symmetric.
|
|
978
|
+
* If rotation is around one the standard basis then non-diagonal entries become 0 and we
|
|
979
|
+
* have one 1 and two -1s on the diagonal.
|
|
980
|
+
* If rotation is around an axis other than standard basis, then the axis is the eigenvector
|
|
981
|
+
* of the rotation matrix with eigenvalue = 1.
|
|
982
|
+
*/
|
|
930
983
|
const axx = this.coffs[0];
|
|
931
984
|
const ayy = this.coffs[4];
|
|
932
985
|
const azz = this.coffs[8];
|
|
933
|
-
|
|
934
|
-
// Look for principal axis flips as a special case . ..
|
|
986
|
+
// Look for a pair of "-1" entries on the diagonal (for rotation around the basis X,Y,Z axis)
|
|
935
987
|
if (Geometry_1.Geometry.isAlmostEqualNumber(-1.0, ayy) && Geometry_1.Geometry.isAlmostEqualNumber(-1, azz)) {
|
|
936
|
-
|
|
937
|
-
return { axis: Point3dVector3d_1.Vector3d.create(1, 0, 0), angle: theta180, ok: true };
|
|
988
|
+
return { axis: Point3dVector3d_1.Vector3d.create(1, 0, 0), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
938
989
|
}
|
|
939
990
|
else if (Geometry_1.Geometry.isAlmostEqualNumber(-1.0, axx) && Geometry_1.Geometry.isAlmostEqualNumber(-1, azz)) {
|
|
940
|
-
return { axis: Point3dVector3d_1.Vector3d.create(0, 1, 0), angle:
|
|
991
|
+
return { axis: Point3dVector3d_1.Vector3d.create(0, 1, 0), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
941
992
|
}
|
|
942
993
|
else if (Geometry_1.Geometry.isAlmostEqualNumber(-1.0, axx) && Geometry_1.Geometry.isAlmostEqualNumber(-1, ayy)) {
|
|
943
|
-
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle:
|
|
994
|
+
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
944
995
|
}
|
|
945
|
-
//
|
|
946
|
-
// eigenvalues will have 1.0 once, -1.0 twice.
|
|
947
|
-
// These cases look for each place (x,y,z) that the 1.0 might appear.
|
|
948
|
-
// But fastSymmetricEigenvalues reliably always seems to put the 1.0 as the x eigenvalue.
|
|
949
|
-
// so only the getColumn(0) return seems reachable in unit tests.
|
|
996
|
+
// Look for eigenvector with eigenvalue = 1
|
|
950
997
|
const eigenvectors = Matrix3d.createIdentity();
|
|
951
998
|
const eigenvalues = Point3dVector3d_1.Vector3d.create(0, 0, 0);
|
|
952
999
|
if (this.fastSymmetricEigenvalues(eigenvectors, eigenvalues)) {
|
|
953
1000
|
for (let axisIndex = 0; axisIndex < 2; axisIndex++) {
|
|
954
1001
|
const lambda = eigenvalues.at(axisIndex);
|
|
955
1002
|
if (Geometry_1.Geometry.isAlmostEqualNumber(1, lambda))
|
|
956
|
-
return { axis: eigenvectors.getColumn(axisIndex), angle:
|
|
1003
|
+
return { axis: eigenvectors.getColumn(axisIndex), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
957
1004
|
}
|
|
958
|
-
//
|
|
1005
|
+
// if no eigenvalue = 1 was found return false
|
|
959
1006
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
960
1007
|
}
|
|
1008
|
+
// if no axis was found return false
|
|
961
1009
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
962
1010
|
}
|
|
1011
|
+
// good matrix and non-zero sine
|
|
963
1012
|
const a = 1.0 / (2.0 * s);
|
|
964
|
-
const result = {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
*/
|
|
970
|
-
static createRotationVectorToVector(vectorA, vectorB, result) {
|
|
971
|
-
return this.createPartialRotationVectorToVector(vectorA, 1.0, vectorB, result);
|
|
972
|
-
}
|
|
973
|
-
/**
|
|
974
|
-
* Return a matrix that rotates a fraction of the angular sweep from vectorA to vectorB.
|
|
975
|
-
* @param vectorA initial vector position
|
|
976
|
-
* @param fraction fractional rotation. 1.0 is "all the way"
|
|
977
|
-
* @param vectorB final vector position
|
|
978
|
-
* @param result optional result matrix.
|
|
979
|
-
*/
|
|
980
|
-
static createPartialRotationVectorToVector(vectorA, fraction, vectorB, result) {
|
|
981
|
-
let upVector = vectorA.unitCrossProduct(vectorB);
|
|
982
|
-
if (upVector) { // the usual case --
|
|
983
|
-
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * vectorA.planarAngleTo(vectorB, upVector).radians));
|
|
984
|
-
}
|
|
985
|
-
// fail if either vector is zero ...
|
|
986
|
-
if (Geometry_1.Geometry.isSmallMetricDistance(vectorA.magnitude())
|
|
987
|
-
|| Geometry_1.Geometry.isSmallMetricDistance(vectorB.magnitude()))
|
|
988
|
-
return undefined;
|
|
989
|
-
// nonzero but aligned vectors ...
|
|
990
|
-
if (vectorA.dotProduct(vectorB) > 0.0)
|
|
991
|
-
return Matrix3d.createIdentity(result);
|
|
992
|
-
// nonzero opposing vectors ..
|
|
993
|
-
upVector = Matrix3d.createPerpendicularVectorFavorPlaneContainingZ(vectorA, upVector);
|
|
994
|
-
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * Math.PI));
|
|
995
|
-
}
|
|
996
|
-
/** Create a 90 degree rotation around a principal axis */
|
|
997
|
-
static create90DegreeRotationAroundAxis(axisIndex) {
|
|
998
|
-
axisIndex = Geometry_1.Geometry.cyclic3dAxis(axisIndex);
|
|
999
|
-
if (axisIndex === 0) {
|
|
1000
|
-
const retVal = Matrix3d.createRowValues(1, 0, 0, 0, 0, -1, 0, 1, 0);
|
|
1001
|
-
retVal.setupInverseTranspose();
|
|
1002
|
-
return retVal;
|
|
1003
|
-
}
|
|
1004
|
-
else if (axisIndex === 1) {
|
|
1005
|
-
const retVal = Matrix3d.createRowValues(0, 0, 1, 0, 1, 0, -1, 0, 0);
|
|
1006
|
-
retVal.setupInverseTranspose();
|
|
1007
|
-
return retVal;
|
|
1008
|
-
}
|
|
1009
|
-
else {
|
|
1010
|
-
const retVal = Matrix3d.createRowValues(0, -1, 0, 1, 0, 0, 0, 0, 1);
|
|
1011
|
-
retVal.setupInverseTranspose();
|
|
1012
|
-
return retVal;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
/** Return (a copy of) the X column */
|
|
1016
|
-
columnX(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[3], this.coffs[6], result); }
|
|
1017
|
-
/** Return (a copy of)the Y column */
|
|
1018
|
-
columnY(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[1], this.coffs[4], this.coffs[7], result); }
|
|
1019
|
-
/** Return (a copy of)the Z column */
|
|
1020
|
-
columnZ(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[2], this.coffs[5], this.coffs[8], result); }
|
|
1021
|
-
/** Return the X column magnitude squared */
|
|
1022
|
-
columnXMagnitudeSquared() { return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[0], this.coffs[3], this.coffs[6]); }
|
|
1023
|
-
/** Return the Y column magnitude squared */
|
|
1024
|
-
columnYMagnitudeSquared() { return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[4], this.coffs[7]); }
|
|
1025
|
-
/** Return the Z column magnitude squared */
|
|
1026
|
-
columnZMagnitudeSquared() { return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[2], this.coffs[5], this.coffs[8]); }
|
|
1027
|
-
/** Return the X column magnitude */
|
|
1028
|
-
columnXMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6]); }
|
|
1029
|
-
/** Return the Y column magnitude */
|
|
1030
|
-
columnYMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7]); }
|
|
1031
|
-
/** Return the Z column magnitude */
|
|
1032
|
-
columnZMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]); }
|
|
1033
|
-
/** Return magnitude of columnX cross columnY. */
|
|
1034
|
-
columnXYCrossProductMagnitude() {
|
|
1035
|
-
return Geometry_1.Geometry.crossProductMagnitude(this.coffs[0], this.coffs[3], this.coffs[6], this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1036
|
-
}
|
|
1037
|
-
/** Return the X row magnitude d */
|
|
1038
|
-
rowXMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[1], this.coffs[2]); }
|
|
1039
|
-
/** Return the Y row magnitude */
|
|
1040
|
-
rowYMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[3], this.coffs[4], this.coffs[5]); }
|
|
1041
|
-
/** Return the Z row magnitude */
|
|
1042
|
-
rowZMagnitude() { return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[6], this.coffs[7], this.coffs[8]); }
|
|
1043
|
-
/** Return the dot product of column X with column Y */
|
|
1044
|
-
/** Return the dot product of column X with column Y */
|
|
1045
|
-
columnXDotColumnY() {
|
|
1046
|
-
return this.coffs[0] * this.coffs[1]
|
|
1047
|
-
+ this.coffs[3] * this.coffs[4]
|
|
1048
|
-
+ this.coffs[6] * this.coffs[7];
|
|
1049
|
-
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Dot product of an indexed column with a vector given as x,y,z
|
|
1052
|
-
* @param columnIndex index of column. Must be 0,1,2
|
|
1053
|
-
* @param x x component of vector
|
|
1054
|
-
* @param y y component of vector
|
|
1055
|
-
* @param z z component of vector
|
|
1056
|
-
*/
|
|
1057
|
-
columnDotXYZ(columnIndex, x, y, z) {
|
|
1058
|
-
return this.coffs[columnIndex] * x + this.coffs[columnIndex + 3] * y + this.coffs[columnIndex + 6] * z;
|
|
1059
|
-
}
|
|
1060
|
-
/** Return (a copy of) the X row */
|
|
1061
|
-
rowX(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[1], this.coffs[2], result); }
|
|
1062
|
-
/** Return (a copy of) the Y row */
|
|
1063
|
-
rowY(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[3], this.coffs[4], this.coffs[5], result); }
|
|
1064
|
-
/** Return (a copy of) the Z row */
|
|
1065
|
-
rowZ(result) { return Point3dVector3d_1.Vector3d.create(this.coffs[6], this.coffs[7], this.coffs[8], result); }
|
|
1066
|
-
/** Return the dot product of the vector parameter with the X column. */
|
|
1067
|
-
dotColumnX(vector) { return vector.x * this.coffs[0] + vector.y * this.coffs[3] + vector.z * this.coffs[6]; }
|
|
1068
|
-
/** Return the dot product of the vector parameter with the Y column. */
|
|
1069
|
-
dotColumnY(vector) { return vector.x * this.coffs[1] + vector.y * this.coffs[4] + vector.z * this.coffs[7]; }
|
|
1070
|
-
/** Return the dot product of the vector parameter with the Z column. */
|
|
1071
|
-
dotColumnZ(vector) { return vector.x * this.coffs[2] + vector.y * this.coffs[5] + vector.z * this.coffs[8]; }
|
|
1072
|
-
/** Return the dot product of the vector parameter with the X row. */
|
|
1073
|
-
dotRowX(vector) { return vector.x * this.coffs[0] + vector.y * this.coffs[1] + vector.z * this.coffs[2]; }
|
|
1074
|
-
/** Return the dot product of the vector parameter with the Y row. */
|
|
1075
|
-
dotRowY(vector) { return vector.x * this.coffs[3] + vector.y * this.coffs[4] + vector.z * this.coffs[5]; }
|
|
1076
|
-
/** Return the dot product of the vector parameter with the Z row. */
|
|
1077
|
-
dotRowZ(vector) { return vector.x * this.coffs[6] + vector.y * this.coffs[7] + vector.z * this.coffs[8]; }
|
|
1078
|
-
// cSpell:words XXYZ YXYZ ZXYZ XYZAs Eigen
|
|
1079
|
-
/** Return the dot product of the x,y,z with the X row. */
|
|
1080
|
-
dotRowXXYZ(x, y, z) { return x * this.coffs[0] + y * this.coffs[1] + z * this.coffs[2]; }
|
|
1081
|
-
/** Return the dot product of the x,y,z with the Y row. */
|
|
1082
|
-
dotRowYXYZ(x, y, z) { return x * this.coffs[3] + y * this.coffs[4] + z * this.coffs[5]; }
|
|
1083
|
-
/** Return the dot product of the x,y,z with the Z row. */
|
|
1084
|
-
dotRowZXYZ(x, y, z) { return x * this.coffs[6] + y * this.coffs[7] + z * this.coffs[8]; }
|
|
1085
|
-
/** Return the (vector) cross product of the Z column with the vector parameter. */
|
|
1086
|
-
columnZCrossVector(vector, result) {
|
|
1087
|
-
return Geometry_1.Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
1088
|
-
}
|
|
1089
|
-
/*
|
|
1090
|
-
* Replace current rows Ui Uj with (c*Ui - s*Uj) and (c*Uj + s*Ui).
|
|
1091
|
-
* @param i first row index. must be 0,1,2 (unchecked)
|
|
1092
|
-
* @param j second row index. must be 0,1,2 (unchecked)
|
|
1093
|
-
* @param c fist coefficient
|
|
1094
|
-
* @param s second coefficient
|
|
1095
|
-
*/
|
|
1096
|
-
applyGivensRowOp(i, j, c, s) {
|
|
1097
|
-
let ii = 3 * i;
|
|
1098
|
-
let jj = 3 * j;
|
|
1099
|
-
const limit = ii + 3;
|
|
1100
|
-
for (; ii < limit; ii++, jj++) {
|
|
1101
|
-
const a = this.coffs[ii];
|
|
1102
|
-
const b = this.coffs[jj];
|
|
1103
|
-
this.coffs[ii] = a * c + b * s;
|
|
1104
|
-
this.coffs[jj] = -a * s + b * c;
|
|
1105
|
-
}
|
|
1106
|
-
}
|
|
1107
|
-
/**
|
|
1108
|
-
* create a rigid coordinate frame column z parallel to (_x_,_y_,_z_) and column x in the xy plane.
|
|
1109
|
-
* * column z points from origin to x,y,z
|
|
1110
|
-
* * column x is perpendicular and in the xy plane
|
|
1111
|
-
* * column y is perpendicular to both. It is the "up" vector on the view plane.
|
|
1112
|
-
* * Multiplying a world vector times the transpose of this matrix transforms into the view xy
|
|
1113
|
-
* * Multiplying the matrix times the an in-view vector transforms the vector to world.
|
|
1114
|
-
* @param x eye x coordinate
|
|
1115
|
-
* @param y eye y coordinate
|
|
1116
|
-
* @param z eye z coordinate
|
|
1117
|
-
* @param result
|
|
1118
|
-
*/
|
|
1119
|
-
static createRigidViewAxesZTowardsEye(x, y, z, result) {
|
|
1120
|
-
result = Matrix3d.createIdentity(result);
|
|
1121
|
-
const rxy = Geometry_1.Geometry.hypotenuseXY(x, y);
|
|
1122
|
-
if (Geometry_1.Geometry.isSmallMetricDistance(rxy)) {
|
|
1123
|
-
// special case for top or bottom view.
|
|
1124
|
-
if (z < 0.0)
|
|
1125
|
-
result.scaleColumnsInPlace(1.0, -1, -1.0);
|
|
1126
|
-
}
|
|
1127
|
-
else {
|
|
1128
|
-
// const d = Geometry.hypotenuseSquaredXYZ(x, y, z);
|
|
1129
|
-
const c = x / rxy;
|
|
1130
|
-
const s = y / rxy;
|
|
1131
|
-
result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
|
|
1132
|
-
if (z !== 0.0) {
|
|
1133
|
-
const r = Geometry_1.Geometry.hypotenuseXYZ(x, y, z);
|
|
1134
|
-
const s1 = z / r;
|
|
1135
|
-
const c1 = rxy / r;
|
|
1136
|
-
result.applyGivensColumnOp(1, 2, c1, -s1);
|
|
1137
|
-
}
|
|
1138
|
-
}
|
|
1013
|
+
const result = {
|
|
1014
|
+
axis: Point3dVector3d_1.Vector3d.create(skewYZ * a, skewZX * a, skewXY * a),
|
|
1015
|
+
angle: Angle_1.Angle.createAtan2(s, c),
|
|
1016
|
+
ok: true,
|
|
1017
|
+
};
|
|
1139
1018
|
return result;
|
|
1140
1019
|
}
|
|
1141
1020
|
/** Rotate so columns i and j become perpendicular */
|
|
@@ -1167,8 +1046,7 @@ class Matrix3d {
|
|
|
1167
1046
|
factorPerpendicularColumns(matrixC, matrixU) {
|
|
1168
1047
|
matrixC.setFrom(this);
|
|
1169
1048
|
matrixU.setIdentity();
|
|
1170
|
-
const
|
|
1171
|
-
const tolerance = 1.0e-12 * ss;
|
|
1049
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1172
1050
|
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1173
1051
|
const sum = matrixC.applyJacobiColumnRotation(0, 1, matrixU)
|
|
1174
1052
|
+ matrixC.applyJacobiColumnRotation(0, 2, matrixU)
|
|
@@ -1259,8 +1137,7 @@ class Matrix3d {
|
|
|
1259
1137
|
matrix.coffs[3] = matrix.coffs[1];
|
|
1260
1138
|
matrix.coffs[6] = matrix.coffs[2];
|
|
1261
1139
|
matrix.coffs[7] = matrix.coffs[5];
|
|
1262
|
-
const
|
|
1263
|
-
const tolerance = 1.0e-12 * ss;
|
|
1140
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1264
1141
|
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1265
1142
|
const sum = leftEigenvectors.applySymmetricJacobi(0, 1, matrix)
|
|
1266
1143
|
+ leftEigenvectors.applySymmetricJacobi(0, 2, matrix)
|
|
@@ -1275,68 +1152,174 @@ class Matrix3d {
|
|
|
1275
1152
|
}
|
|
1276
1153
|
return false;
|
|
1277
1154
|
}
|
|
1278
|
-
/**
|
|
1279
|
-
*
|
|
1155
|
+
/**
|
|
1156
|
+
* Return a matrix that rotates a fraction of the angular sweep from vectorA to vectorB.
|
|
1157
|
+
* @param vectorA initial vector position
|
|
1158
|
+
* @param fraction fractional rotation (1 means rotate all the way)
|
|
1159
|
+
* @param vectorB final vector position
|
|
1160
|
+
* @param result optional result matrix.
|
|
1280
1161
|
*/
|
|
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
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1162
|
+
static createPartialRotationVectorToVector(vectorA, fraction, vectorB, result) {
|
|
1163
|
+
let upVector = vectorA.unitCrossProduct(vectorB);
|
|
1164
|
+
// the usual case (both vectors and also their cross product is non-zero)
|
|
1165
|
+
if (upVector) {
|
|
1166
|
+
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * vectorA.planarAngleTo(vectorB, upVector).radians));
|
|
1167
|
+
}
|
|
1168
|
+
// if either vector is zero
|
|
1169
|
+
if (Geometry_1.Geometry.isSmallMetricDistance(vectorA.magnitude())
|
|
1170
|
+
|| Geometry_1.Geometry.isSmallMetricDistance(vectorB.magnitude()))
|
|
1171
|
+
return undefined;
|
|
1172
|
+
// aligned vectors (cross product = 0, dot product > 0)
|
|
1173
|
+
if (vectorA.dotProduct(vectorB) > 0.0)
|
|
1174
|
+
return Matrix3d.createIdentity(result);
|
|
1175
|
+
// opposing vectors (cross product = 0, dot product < 0)
|
|
1176
|
+
upVector = Matrix3d.createPerpendicularVectorFavorPlaneContainingZ(vectorA, upVector);
|
|
1177
|
+
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * Math.PI));
|
|
1178
|
+
}
|
|
1179
|
+
/** Returns a matrix that rotates from vectorA to vectorB. */
|
|
1180
|
+
static createRotationVectorToVector(vectorA, vectorB, result) {
|
|
1181
|
+
return this.createPartialRotationVectorToVector(vectorA, 1.0, vectorB, result);
|
|
1182
|
+
}
|
|
1183
|
+
/** Create a 90 degree rotation around a principal axis */
|
|
1184
|
+
static create90DegreeRotationAroundAxis(axisIndex) {
|
|
1185
|
+
axisIndex = Geometry_1.Geometry.cyclic3dAxis(axisIndex);
|
|
1186
|
+
if (axisIndex === 0) {
|
|
1187
|
+
const retVal = Matrix3d.createRowValues(1, 0, 0, 0, 0, -1, 0, 1, 0);
|
|
1188
|
+
retVal.setupInverseTranspose();
|
|
1189
|
+
return retVal;
|
|
1190
|
+
}
|
|
1191
|
+
else if (axisIndex === 1) {
|
|
1192
|
+
const retVal = Matrix3d.createRowValues(0, 0, 1, 0, 1, 0, -1, 0, 0);
|
|
1193
|
+
retVal.setupInverseTranspose();
|
|
1194
|
+
return retVal;
|
|
1195
|
+
}
|
|
1196
|
+
else {
|
|
1197
|
+
const retVal = Matrix3d.createRowValues(0, -1, 0, 1, 0, 0, 0, 0, 1);
|
|
1198
|
+
retVal.setupInverseTranspose();
|
|
1199
|
+
return retVal;
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
/** Return (a copy of) the X column */
|
|
1203
|
+
columnX(result) {
|
|
1204
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[3], this.coffs[6], result);
|
|
1205
|
+
}
|
|
1206
|
+
/** Return (a copy of) the Y column */
|
|
1207
|
+
columnY(result) {
|
|
1208
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[1], this.coffs[4], this.coffs[7], result);
|
|
1209
|
+
}
|
|
1210
|
+
/** Return (a copy of) the Z column */
|
|
1211
|
+
columnZ(result) {
|
|
1212
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[2], this.coffs[5], this.coffs[8], result);
|
|
1213
|
+
}
|
|
1214
|
+
/** Return the X column magnitude squared */
|
|
1215
|
+
columnXMagnitudeSquared() {
|
|
1216
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1217
|
+
}
|
|
1218
|
+
/** Return the Y column magnitude squared */
|
|
1219
|
+
columnYMagnitudeSquared() {
|
|
1220
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1221
|
+
}
|
|
1222
|
+
/** Return the Z column magnitude squared */
|
|
1223
|
+
columnZMagnitudeSquared() {
|
|
1224
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1225
|
+
}
|
|
1226
|
+
/** Return the X column magnitude */
|
|
1227
|
+
columnXMagnitude() {
|
|
1228
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1229
|
+
}
|
|
1230
|
+
/** Return the Y column magnitude */
|
|
1231
|
+
columnYMagnitude() {
|
|
1232
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1233
|
+
}
|
|
1234
|
+
/** Return the Z column magnitude */
|
|
1235
|
+
columnZMagnitude() {
|
|
1236
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1237
|
+
}
|
|
1238
|
+
/** Return magnitude of columnX cross columnY. */
|
|
1239
|
+
columnXYCrossProductMagnitude() {
|
|
1240
|
+
return Geometry_1.Geometry.crossProductMagnitude(this.coffs[0], this.coffs[3], this.coffs[6], this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1241
|
+
}
|
|
1242
|
+
/** Return the X row magnitude */
|
|
1243
|
+
rowXMagnitude() {
|
|
1244
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[1], this.coffs[2]);
|
|
1245
|
+
}
|
|
1246
|
+
/** Return the Y row magnitude */
|
|
1247
|
+
rowYMagnitude() {
|
|
1248
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[3], this.coffs[4], this.coffs[5]);
|
|
1249
|
+
}
|
|
1250
|
+
/** Return the Z row magnitude */
|
|
1251
|
+
rowZMagnitude() {
|
|
1252
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[6], this.coffs[7], this.coffs[8]);
|
|
1253
|
+
}
|
|
1254
|
+
/** Return the dot product of column X with column Y */
|
|
1255
|
+
columnXDotColumnY() {
|
|
1256
|
+
return this.coffs[0] * this.coffs[1]
|
|
1257
|
+
+ this.coffs[3] * this.coffs[4]
|
|
1258
|
+
+ this.coffs[6] * this.coffs[7];
|
|
1313
1259
|
}
|
|
1314
1260
|
/**
|
|
1315
|
-
*
|
|
1316
|
-
*
|
|
1317
|
-
* @param
|
|
1318
|
-
* @param
|
|
1261
|
+
* Dot product of an indexed column with a vector given as x,y,z
|
|
1262
|
+
* @param columnIndex index of column. Must be 0,1,2.
|
|
1263
|
+
* @param x x component of vector
|
|
1264
|
+
* @param y y component of vector
|
|
1265
|
+
* @param z z component of vector
|
|
1319
1266
|
*/
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
return
|
|
1267
|
+
columnDotXYZ(columnIndex, x, y, z) {
|
|
1268
|
+
return this.coffs[columnIndex] * x + this.coffs[columnIndex + 3] * y + this.coffs[columnIndex + 6] * z;
|
|
1269
|
+
}
|
|
1270
|
+
/** Return (a copy of) the X row */
|
|
1271
|
+
rowX(result) {
|
|
1272
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[1], this.coffs[2], result);
|
|
1273
|
+
}
|
|
1274
|
+
/** Return (a copy of) the Y row */
|
|
1275
|
+
rowY(result) {
|
|
1276
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[3], this.coffs[4], this.coffs[5], result);
|
|
1277
|
+
}
|
|
1278
|
+
/** Return (a copy of) the Z row */
|
|
1279
|
+
rowZ(result) {
|
|
1280
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[6], this.coffs[7], this.coffs[8], result);
|
|
1281
|
+
}
|
|
1282
|
+
/** Return the dot product of the vector parameter with the X column. */
|
|
1283
|
+
dotColumnX(vector) {
|
|
1284
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[3] + vector.z * this.coffs[6];
|
|
1285
|
+
}
|
|
1286
|
+
/** Return the dot product of the vector parameter with the Y column. */
|
|
1287
|
+
dotColumnY(vector) {
|
|
1288
|
+
return vector.x * this.coffs[1] + vector.y * this.coffs[4] + vector.z * this.coffs[7];
|
|
1289
|
+
}
|
|
1290
|
+
/** Return the dot product of the vector parameter with the Z column. */
|
|
1291
|
+
dotColumnZ(vector) {
|
|
1292
|
+
return vector.x * this.coffs[2] + vector.y * this.coffs[5] + vector.z * this.coffs[8];
|
|
1293
|
+
}
|
|
1294
|
+
/** Return the dot product of the vector parameter with the X row. */
|
|
1295
|
+
dotRowX(vector) {
|
|
1296
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[1] + vector.z * this.coffs[2];
|
|
1297
|
+
}
|
|
1298
|
+
/** Return the dot product of the vector parameter with the Y row. */
|
|
1299
|
+
dotRowY(vector) {
|
|
1300
|
+
return vector.x * this.coffs[3] + vector.y * this.coffs[4] + vector.z * this.coffs[5];
|
|
1301
|
+
}
|
|
1302
|
+
/** Return the dot product of the vector parameter with the Z row. */
|
|
1303
|
+
dotRowZ(vector) {
|
|
1304
|
+
return vector.x * this.coffs[6] + vector.y * this.coffs[7] + vector.z * this.coffs[8];
|
|
1305
|
+
}
|
|
1306
|
+
/** Return the dot product of the x,y,z with the X row. */
|
|
1307
|
+
dotRowXXYZ(x, y, z) {
|
|
1308
|
+
return x * this.coffs[0] + y * this.coffs[1] + z * this.coffs[2];
|
|
1309
|
+
}
|
|
1310
|
+
/** Return the dot product of the x,y,z with the Y row. */
|
|
1311
|
+
dotRowYXYZ(x, y, z) {
|
|
1312
|
+
return x * this.coffs[3] + y * this.coffs[4] + z * this.coffs[5];
|
|
1313
|
+
}
|
|
1314
|
+
/** Return the dot product of the x,y,z with the Z row. */
|
|
1315
|
+
dotRowZXYZ(x, y, z) {
|
|
1316
|
+
return x * this.coffs[6] + y * this.coffs[7] + z * this.coffs[8];
|
|
1338
1317
|
}
|
|
1339
|
-
/**
|
|
1318
|
+
/** Return the cross product of the Z column with the vector parameter. */
|
|
1319
|
+
columnZCrossVector(vector, result) {
|
|
1320
|
+
return Geometry_1.Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
1321
|
+
}
|
|
1322
|
+
/** Set data from xyz parts of Point4d (w part of Point4d ignored) */
|
|
1340
1323
|
setColumnsPoint4dXYZ(vectorU, vectorV, vectorW) {
|
|
1341
1324
|
this.inverseState = InverseMatrixState.unknown;
|
|
1342
1325
|
this.setRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z);
|
|
@@ -1360,16 +1343,22 @@ class Matrix3d {
|
|
|
1360
1343
|
this.coffs[index + 6] = 0.0;
|
|
1361
1344
|
}
|
|
1362
1345
|
}
|
|
1363
|
-
/**
|
|
1346
|
+
/**
|
|
1347
|
+
* Set all columns of the matrix. Any undefined vector is zeros.
|
|
1348
|
+
* @param vectorX values for column 0
|
|
1349
|
+
* @param vectorY values for column 1
|
|
1350
|
+
* @param vectorZ optional values for column 2 (it's optional in case column 2 is 000, which is a
|
|
1351
|
+
* projection onto the xy-plane)
|
|
1352
|
+
*/
|
|
1364
1353
|
setColumns(vectorX, vectorY, vectorZ) {
|
|
1365
1354
|
this.setColumn(0, vectorX);
|
|
1366
1355
|
this.setColumn(1, vectorY);
|
|
1367
1356
|
this.setColumn(2, vectorZ);
|
|
1368
1357
|
}
|
|
1369
1358
|
/**
|
|
1370
|
-
*
|
|
1371
|
-
* @param rowIndex row index.
|
|
1372
|
-
* @param value x,
|
|
1359
|
+
* Set entries in one row of the matrix.
|
|
1360
|
+
* @param rowIndex row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1361
|
+
* @param value x,y,z values for row.
|
|
1373
1362
|
*/
|
|
1374
1363
|
setRow(rowIndex, value) {
|
|
1375
1364
|
const index = 3 * Geometry_1.Geometry.cyclic3dAxis(rowIndex);
|
|
@@ -1378,21 +1367,26 @@ class Matrix3d {
|
|
|
1378
1367
|
this.coffs[index + 2] = value.z;
|
|
1379
1368
|
this.inverseState = InverseMatrixState.unknown;
|
|
1380
1369
|
}
|
|
1381
|
-
/**
|
|
1382
|
-
*
|
|
1370
|
+
/**
|
|
1371
|
+
* Return (a copy of) a column of the matrix.
|
|
1372
|
+
* @param i column index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1373
|
+
* @param result optional preallocated result.
|
|
1383
1374
|
*/
|
|
1384
1375
|
getColumn(columnIndex, result) {
|
|
1385
1376
|
const index = Geometry_1.Geometry.cyclic3dAxis(columnIndex);
|
|
1386
1377
|
return Point3dVector3d_1.Vector3d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], result);
|
|
1387
1378
|
}
|
|
1388
|
-
/**
|
|
1389
|
-
*
|
|
1379
|
+
/**
|
|
1380
|
+
* Return a (copy of) a row of the matrix.
|
|
1381
|
+
* @param i row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1382
|
+
* @param result optional preallocated result.
|
|
1390
1383
|
*/
|
|
1391
1384
|
getRow(columnIndex, result) {
|
|
1392
1385
|
const index = 3 * Geometry_1.Geometry.cyclic3dAxis(columnIndex);
|
|
1393
1386
|
return Point3dVector3d_1.Vector3d.create(this.coffs[index], this.coffs[index + 1], this.coffs[index + 2], result);
|
|
1394
1387
|
}
|
|
1395
|
-
/**
|
|
1388
|
+
/**
|
|
1389
|
+
* Create a matrix from row vectors.
|
|
1396
1390
|
* ```
|
|
1397
1391
|
* equation
|
|
1398
1392
|
* \begin{bmatrix}U_x & U_y & U_z \\ V_x & V_y & V_z \\ W_x & W_y & W_z \end{bmatrix}
|
|
@@ -1401,14 +1395,20 @@ class Matrix3d {
|
|
|
1401
1395
|
static createRows(vectorU, vectorV, vectorW, result) {
|
|
1402
1396
|
return Matrix3d.createRowValues(vectorU.x, vectorU.y, vectorU.z, vectorV.x, vectorV.y, vectorV.z, vectorW.x, vectorW.y, vectorW.z, result);
|
|
1403
1397
|
}
|
|
1404
|
-
/**
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1398
|
+
/**
|
|
1399
|
+
* Create a matrix that scales along a specified `direction`. This means if you multiply the returned matrix
|
|
1400
|
+
* by a `vector`, you get `directional scale` of that `vector`. Suppose `plane` is the plane perpendicular
|
|
1401
|
+
* to the `direction`. When scale = 0, `directional scale` is projection of the `vector` to the `plane`.
|
|
1402
|
+
* When scale = 1, `directional scale` is the `vector` itself. When scale = -1, `directional scale` is
|
|
1403
|
+
* mirror of the `vector` across the `plane`. In general, When scale != 0, the result is computed by first
|
|
1404
|
+
* projecting the `vector` to the `plane`, then translating that projection along the `direction` (if scale > 0)
|
|
1405
|
+
* or in opposite direction (if scale < 0).
|
|
1407
1406
|
* ```
|
|
1408
1407
|
* equation
|
|
1409
|
-
* \text{The matrix is } I
|
|
1410
|
-
* \\ \text{with }
|
|
1408
|
+
* \text{The matrix is } I + (s-1) D D^T
|
|
1409
|
+
* \\ \text{with }D\text{ being the normalized direction vector and }s\text{ being the scale.}
|
|
1411
1410
|
* ```
|
|
1411
|
+
* * Visualization can be found at itwinjs.org/sandbox/SaeedTorabi/DirectionalScale
|
|
1412
1412
|
*/
|
|
1413
1413
|
static createDirectionalScale(direction, scale, result) {
|
|
1414
1414
|
const unit = direction.normalize();
|
|
@@ -1416,19 +1416,13 @@ class Matrix3d {
|
|
|
1416
1416
|
const x = unit.x;
|
|
1417
1417
|
const y = unit.y;
|
|
1418
1418
|
const z = unit.z;
|
|
1419
|
-
const a =
|
|
1419
|
+
const a = scale - 1;
|
|
1420
1420
|
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);
|
|
1421
1421
|
}
|
|
1422
1422
|
return Matrix3d.createUniformScale(scale);
|
|
1423
1423
|
}
|
|
1424
|
-
|
|
1425
|
-
* *
|
|
1426
|
-
* * 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)
|
|
1427
|
-
* * If the direction vector is close to Z, the "next" column ((axisIndex + 1) mode 3) will be in the direction of (direction cross Y)
|
|
1428
|
-
*/
|
|
1429
|
-
// static create1Vector(direction: Vector3d, axisIndex: number): Matrix3d;
|
|
1430
|
-
// static createFromXYVectors(vectorX: Vector3d, vectorY: Vector3d, axisIndex: number): Matrix3d;
|
|
1431
|
-
/** Multiply the matrix * vector, treating the vector is a column vector on the right.
|
|
1424
|
+
/**
|
|
1425
|
+
* Multiply `matrix * vector`, treating the vector is a column vector on the right.
|
|
1432
1426
|
* ```
|
|
1433
1427
|
* equation
|
|
1434
1428
|
* \matrixXY{A}\columnSubXYZ{U}
|
|
@@ -1439,36 +1433,38 @@ class Matrix3d {
|
|
|
1439
1433
|
const x = vectorU.x;
|
|
1440
1434
|
const y = vectorU.y;
|
|
1441
1435
|
const z = vectorU.z;
|
|
1442
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1436
|
+
return Point3dVector3d_1.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);
|
|
1443
1437
|
}
|
|
1444
|
-
/**
|
|
1445
|
-
*
|
|
1438
|
+
/**
|
|
1439
|
+
* Multiply `matrix * vector` in place for vector in the array, i.e. treating the vector is a column
|
|
1440
|
+
* vector on the right.
|
|
1441
|
+
* * Each `vector` is updated to be `matrix * vector`
|
|
1446
1442
|
*/
|
|
1447
1443
|
multiplyVectorArrayInPlace(data) {
|
|
1448
1444
|
for (const v of data)
|
|
1449
|
-
v.set(
|
|
1445
|
+
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);
|
|
1450
1446
|
}
|
|
1451
|
-
/**
|
|
1447
|
+
/** Compute `origin - matrix * vector` */
|
|
1452
1448
|
static xyzMinusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1453
1449
|
const x = vector.x;
|
|
1454
1450
|
const y = vector.y;
|
|
1455
1451
|
const z = vector.z;
|
|
1456
1452
|
return Point3dVector3d_1.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);
|
|
1457
1453
|
}
|
|
1458
|
-
/**
|
|
1454
|
+
/** Compute `origin + matrix * vector` using only the xy parts of the inputs. */
|
|
1459
1455
|
static xyPlusMatrixTimesXY(origin, matrix, vector, result) {
|
|
1460
1456
|
const x = vector.x;
|
|
1461
1457
|
const y = vector.y;
|
|
1462
1458
|
return Point2dVector2d_1.Point2d.create(origin.x + matrix.coffs[0] * x + matrix.coffs[1] * y, origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y, result);
|
|
1463
1459
|
}
|
|
1464
|
-
/**
|
|
1460
|
+
/** Compute `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1465
1461
|
static xyzPlusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1466
1462
|
const x = vector.x;
|
|
1467
1463
|
const y = vector.y;
|
|
1468
1464
|
const z = vector.z;
|
|
1469
1465
|
return Point3dVector3d_1.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);
|
|
1470
1466
|
}
|
|
1471
|
-
/**
|
|
1467
|
+
/** Updates vector to be `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1472
1468
|
static xyzPlusMatrixTimesXYZInPlace(origin, matrix, vector) {
|
|
1473
1469
|
const x = vector.x;
|
|
1474
1470
|
const y = vector.y;
|
|
@@ -1477,65 +1473,76 @@ class Matrix3d {
|
|
|
1477
1473
|
vector.y = origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z;
|
|
1478
1474
|
vector.z = origin.z + matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z;
|
|
1479
1475
|
}
|
|
1480
|
-
/**
|
|
1476
|
+
/** Compute `origin + matrix * vector` where the final vector is given as direct x,y,z coordinates */
|
|
1481
1477
|
static xyzPlusMatrixTimesCoordinates(origin, matrix, x, y, z, result) {
|
|
1482
1478
|
return Point3dVector3d_1.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);
|
|
1483
1479
|
}
|
|
1484
1480
|
/**
|
|
1485
1481
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1486
|
-
* Multiply
|
|
1482
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1483
|
+
* ```
|
|
1484
|
+
* equation
|
|
1485
|
+
* \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}
|
|
1486
|
+
* ```
|
|
1487
1487
|
* @param origin translation part (xyz in column 3)
|
|
1488
1488
|
* @param matrix matrix part (leading 3x3)
|
|
1489
1489
|
* @param x x part of multiplied point
|
|
1490
1490
|
* @param y y part of multiplied point
|
|
1491
1491
|
* @param z z part of multiplied point
|
|
1492
1492
|
* @param w w part of multiplied point
|
|
1493
|
-
* @param result optional result.
|
|
1493
|
+
* @param result optional preallocated result.
|
|
1494
1494
|
*/
|
|
1495
1495
|
static xyzPlusMatrixTimesWeightedCoordinates(origin, matrix, x, y, z, w, result) {
|
|
1496
|
-
return Point4d_1.Point4d.create(
|
|
1496
|
+
return Point4d_1.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);
|
|
1497
1497
|
}
|
|
1498
1498
|
/**
|
|
1499
1499
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1500
|
-
* Multiply
|
|
1500
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1501
|
+
* ```
|
|
1502
|
+
* equation
|
|
1503
|
+
* \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}
|
|
1504
|
+
* ```
|
|
1501
1505
|
* @param origin translation part (xyz in column 3)
|
|
1502
1506
|
* @param matrix matrix part (leading 3x3)
|
|
1503
1507
|
* @param x x part of multiplied point
|
|
1504
1508
|
* @param y y part of multiplied point
|
|
1505
1509
|
* @param z z part of multiplied point
|
|
1506
1510
|
* @param w w part of multiplied point
|
|
1507
|
-
* @param result optional result.
|
|
1511
|
+
* @param result optional preallocated result.
|
|
1508
1512
|
*/
|
|
1509
1513
|
static xyzPlusMatrixTimesWeightedCoordinatesToFloat64Array(origin, matrix, x, y, z, w, result) {
|
|
1510
1514
|
if (!result)
|
|
1511
1515
|
result = new Float64Array(4);
|
|
1512
|
-
result[0] =
|
|
1513
|
-
result[1] =
|
|
1514
|
-
result[2] =
|
|
1516
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x * w;
|
|
1517
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y * w;
|
|
1518
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z * w;
|
|
1515
1519
|
result[3] = w;
|
|
1516
1520
|
return result;
|
|
1517
1521
|
}
|
|
1518
1522
|
/**
|
|
1519
|
-
* Treat the 3x3 matrix and origin as
|
|
1520
|
-
* Multiply
|
|
1523
|
+
* Treat the 3x3 matrix and origin as a 3x4 matrix.
|
|
1524
|
+
* * Multiply the 3x4 matrix by `[x,y,z,1]`
|
|
1525
|
+
* ```
|
|
1526
|
+
* equation
|
|
1527
|
+
* \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}
|
|
1528
|
+
* ```
|
|
1521
1529
|
* @param origin translation part (xyz in column 3)
|
|
1522
1530
|
* @param matrix matrix part (leading 3x3)
|
|
1523
1531
|
* @param x x part of multiplied point
|
|
1524
1532
|
* @param y y part of multiplied point
|
|
1525
1533
|
* @param z z part of multiplied point
|
|
1526
|
-
* @param
|
|
1527
|
-
* @param result optional result.
|
|
1534
|
+
* @param result optional preallocated result.
|
|
1528
1535
|
*/
|
|
1529
1536
|
static xyzPlusMatrixTimesCoordinatesToFloat64Array(origin, matrix, x, y, z, result) {
|
|
1530
1537
|
if (!result)
|
|
1531
1538
|
result = new Float64Array(3);
|
|
1532
|
-
result[0] =
|
|
1533
|
-
result[1] =
|
|
1534
|
-
result[2] =
|
|
1539
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x;
|
|
1540
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y;
|
|
1541
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z;
|
|
1535
1542
|
return result;
|
|
1536
1543
|
}
|
|
1537
1544
|
/**
|
|
1538
|
-
* Multiply transpose
|
|
1545
|
+
* Multiply the transpose matrix times a vector.
|
|
1539
1546
|
* * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
|
|
1540
1547
|
* ```
|
|
1541
1548
|
* equation
|
|
@@ -1544,99 +1551,112 @@ class Matrix3d {
|
|
|
1544
1551
|
* \text{Treating U as a row to the left of untransposed matrix\: return row}&\rowSubXYZ{V}&=&\rowSubXYZ{U}\matrixXY{A}
|
|
1545
1552
|
* \end{matrix}
|
|
1546
1553
|
* ```
|
|
1547
|
-
* @return the vector result
|
|
1554
|
+
* @return the vector result (optional)
|
|
1548
1555
|
*/
|
|
1549
1556
|
multiplyTransposeVector(vector, result) {
|
|
1550
1557
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1551
1558
|
const x = vector.x;
|
|
1552
1559
|
const y = vector.y;
|
|
1553
1560
|
const z = vector.z;
|
|
1554
|
-
result.x =
|
|
1555
|
-
result.y =
|
|
1556
|
-
result.z =
|
|
1561
|
+
result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1562
|
+
result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1563
|
+
result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1557
1564
|
return result;
|
|
1558
1565
|
}
|
|
1559
|
-
/**
|
|
1560
|
-
*
|
|
1566
|
+
/**
|
|
1567
|
+
* Multiply the matrix * [x,y,z], i.e. the vector [x,y,z] is a column vector on the right.
|
|
1568
|
+
* @return the vector result (optional)
|
|
1561
1569
|
*/
|
|
1562
1570
|
multiplyXYZ(x, y, z, result) {
|
|
1563
1571
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1564
|
-
result.x =
|
|
1565
|
-
result.y =
|
|
1566
|
-
result.z =
|
|
1572
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1573
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1574
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1567
1575
|
return result;
|
|
1568
1576
|
}
|
|
1569
|
-
/**
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1577
|
+
/**
|
|
1578
|
+
* Multiply the matrix * xyz, place result in (required) return value.
|
|
1579
|
+
* @param xyz right side
|
|
1580
|
+
* @param result the result.
|
|
1572
1581
|
*/
|
|
1573
1582
|
multiplyXYZtoXYZ(xyz, result) {
|
|
1574
1583
|
const x = xyz.x;
|
|
1575
1584
|
const y = xyz.y;
|
|
1576
1585
|
const z = xyz.z;
|
|
1577
|
-
result.x =
|
|
1578
|
-
result.y =
|
|
1579
|
-
result.z =
|
|
1586
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1587
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1588
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1580
1589
|
return result;
|
|
1581
1590
|
}
|
|
1582
|
-
/**
|
|
1583
|
-
*
|
|
1591
|
+
/**
|
|
1592
|
+
* Multiply the matrix * [x,y,0], i.e. the vector [x,y,0] is a column vector on the right.
|
|
1593
|
+
* @return the vector result (optional)
|
|
1584
1594
|
*/
|
|
1585
1595
|
multiplyXY(x, y, result) {
|
|
1586
1596
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1587
|
-
result.x =
|
|
1588
|
-
result.y =
|
|
1589
|
-
result.z =
|
|
1597
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y;
|
|
1598
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y;
|
|
1599
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y;
|
|
1590
1600
|
return result;
|
|
1591
1601
|
}
|
|
1592
|
-
/**
|
|
1602
|
+
/**
|
|
1603
|
+
* Compute origin + the matrix * [x,y,0].
|
|
1604
|
+
* @return the vector result (optional)
|
|
1605
|
+
*/
|
|
1593
1606
|
originPlusMatrixTimesXY(origin, x, y, result) {
|
|
1594
1607
|
return Point3dVector3d_1.Point3d.create(origin.x + this.coffs[0] * x + this.coffs[1] * y, origin.y + this.coffs[3] * x + this.coffs[4] * y, origin.z + this.coffs[6] * x + this.coffs[7] * y, result);
|
|
1595
1608
|
}
|
|
1596
|
-
/**
|
|
1609
|
+
/**
|
|
1610
|
+
* Multiply the matrix * (x,y,z) in place, i.e. the vector (x,y,z) is a column vector on the right and
|
|
1611
|
+
* the multiplication updates the vector values.
|
|
1612
|
+
* @param xyzData the vector data
|
|
1613
|
+
*/
|
|
1597
1614
|
multiplyVectorInPlace(xyzData) {
|
|
1598
1615
|
const x = xyzData.x;
|
|
1599
1616
|
const y = xyzData.y;
|
|
1600
1617
|
const z = xyzData.z;
|
|
1601
|
-
|
|
1602
|
-
xyzData.
|
|
1603
|
-
xyzData.
|
|
1604
|
-
xyzData.z = (coffs[6] * x + coffs[7] * y + coffs[8] * z);
|
|
1618
|
+
xyzData.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1619
|
+
xyzData.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1620
|
+
xyzData.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1605
1621
|
}
|
|
1606
|
-
/**
|
|
1607
|
-
*
|
|
1622
|
+
/**
|
|
1623
|
+
* Multiply the transpose matrix times [x,y,z] in place, i.e. the vector [x,y,z] is a column vector on
|
|
1624
|
+
* the right and the multiplication updates the vector values.
|
|
1625
|
+
* * This is equivalent to `multiplyTransposeVector` but always returns the result directly in the input.
|
|
1626
|
+
* @param xyzData the vector data
|
|
1608
1627
|
*/
|
|
1609
1628
|
multiplyTransposeVectorInPlace(vectorU) {
|
|
1610
1629
|
const x = vectorU.x;
|
|
1611
1630
|
const y = vectorU.y;
|
|
1612
1631
|
const z = vectorU.z;
|
|
1613
|
-
|
|
1614
|
-
vectorU.
|
|
1615
|
-
vectorU.
|
|
1616
|
-
vectorU.z = (coffs[2] * x + coffs[5] * y + coffs[8] * z);
|
|
1632
|
+
vectorU.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1633
|
+
vectorU.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1634
|
+
vectorU.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1617
1635
|
}
|
|
1618
|
-
/**
|
|
1619
|
-
*
|
|
1636
|
+
/**
|
|
1637
|
+
* Multiply the transpose matrix times column using individual numeric inputs.
|
|
1638
|
+
* * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
|
|
1620
1639
|
* ```
|
|
1621
1640
|
* equation
|
|
1622
1641
|
* \begin{matrix}
|
|
1623
|
-
* \text{treating the input as a column } \columnXYZ{x}{y}{z}\text{ compute }&\columnSubXYZ{V} &= &A^T \columnXYZ{x}{y}{z} \\
|
|
1624
|
-
* \text{or row vector } \rowXYZ{x}{y}{z} \text{ compute }&\rowSubXYZ{V} &= &\rowXYZ{x}{y}{z} A \\
|
|
1642
|
+
* \text{treating the input as a column vector } \columnXYZ{x}{y}{z}\text{ compute }&\columnSubXYZ{V} &= &A^T \columnXYZ{x}{y}{z} \\
|
|
1643
|
+
* \text{or as a row vector } \rowXYZ{x}{y}{z} \text{ compute }&\rowSubXYZ{V} &= &\rowXYZ{x}{y}{z} A \\
|
|
1625
1644
|
* \phantom{8888}\text{and return V as a Vector3d} & & &
|
|
1626
1645
|
* \end{matrix}
|
|
1627
1646
|
* ````
|
|
1628
|
-
* @return the vector result
|
|
1647
|
+
* @return the vector result (optional)
|
|
1629
1648
|
*/
|
|
1630
1649
|
multiplyTransposeXYZ(x, y, z, result) {
|
|
1631
1650
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1632
|
-
result.x =
|
|
1633
|
-
result.y =
|
|
1634
|
-
result.z =
|
|
1651
|
+
result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1652
|
+
result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1653
|
+
result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1635
1654
|
return result;
|
|
1636
1655
|
}
|
|
1637
|
-
/**
|
|
1638
|
-
*
|
|
1639
|
-
* *
|
|
1656
|
+
/**
|
|
1657
|
+
* Solve `matrix * result = vector` for an unknown `result`.
|
|
1658
|
+
* * This is equivalent to multiplication `result = inverse matrix * vector`.
|
|
1659
|
+
* * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1640
1660
|
*/
|
|
1641
1661
|
multiplyInverse(vector, result) {
|
|
1642
1662
|
this.computeCachedInverse(true);
|
|
@@ -1644,13 +1664,14 @@ class Matrix3d {
|
|
|
1644
1664
|
const x = vector.x;
|
|
1645
1665
|
const y = vector.y;
|
|
1646
1666
|
const z = vector.z;
|
|
1647
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1667
|
+
return Point3dVector3d_1.Vector3d.create(this.inverseCoffs[0] * x + this.inverseCoffs[1] * y + this.inverseCoffs[2] * z, this.inverseCoffs[3] * x + this.inverseCoffs[4] * y + this.inverseCoffs[5] * z, this.inverseCoffs[6] * x + this.inverseCoffs[7] * y + this.inverseCoffs[8] * z, result);
|
|
1648
1668
|
}
|
|
1649
1669
|
return undefined;
|
|
1650
1670
|
}
|
|
1651
|
-
/**
|
|
1671
|
+
/**
|
|
1672
|
+
* Solve `matrixTranspose * result = vector` for an unknown `result`.
|
|
1652
1673
|
* * This is equivalent to multiplication `result = matrixInverseTranspose * vector`.
|
|
1653
|
-
* * Result is undefined if the matrix is singular (e.g. has parallel or zero
|
|
1674
|
+
* * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1654
1675
|
*/
|
|
1655
1676
|
multiplyInverseTranspose(vector, result) {
|
|
1656
1677
|
this.computeCachedInverse(true);
|
|
@@ -1658,87 +1679,91 @@ class Matrix3d {
|
|
|
1658
1679
|
const x = vector.x;
|
|
1659
1680
|
const y = vector.y;
|
|
1660
1681
|
const z = vector.z;
|
|
1661
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1682
|
+
return Point3dVector3d_1.Vector3d.create(this.inverseCoffs[0] * x + this.inverseCoffs[3] * y + this.inverseCoffs[6] * z, this.inverseCoffs[1] * x + this.inverseCoffs[4] * y + this.inverseCoffs[7] * z, this.inverseCoffs[2] * x + this.inverseCoffs[5] * y + this.inverseCoffs[8] * z, result);
|
|
1662
1683
|
}
|
|
1663
1684
|
return undefined;
|
|
1664
1685
|
}
|
|
1665
1686
|
/**
|
|
1666
|
-
*
|
|
1667
|
-
* *
|
|
1668
|
-
* *
|
|
1687
|
+
* Multiply `matrixInverse * [x,y,z]`.
|
|
1688
|
+
* * This is equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1689
|
+
* * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1690
|
+
* @return result as a Vector3d or undefined (if the matrix is singular).
|
|
1669
1691
|
*/
|
|
1670
1692
|
multiplyInverseXYZAsVector3d(x, y, z, result) {
|
|
1671
1693
|
this.computeCachedInverse(true);
|
|
1672
1694
|
if (this.inverseCoffs) {
|
|
1673
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1695
|
+
return Point3dVector3d_1.Vector3d.create(this.inverseCoffs[0] * x + this.inverseCoffs[1] * y + this.inverseCoffs[2] * z, this.inverseCoffs[3] * x + this.inverseCoffs[4] * y + this.inverseCoffs[5] * z, this.inverseCoffs[6] * x + this.inverseCoffs[7] * y + this.inverseCoffs[8] * z, result);
|
|
1674
1696
|
}
|
|
1675
1697
|
return undefined;
|
|
1676
1698
|
}
|
|
1677
1699
|
/**
|
|
1678
|
-
*
|
|
1679
|
-
* *
|
|
1680
|
-
* *
|
|
1681
|
-
*
|
|
1700
|
+
* Multiply `matrixInverse * [x,y,z]` and return result as `Point4d` with given weight.
|
|
1701
|
+
* * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1702
|
+
* * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1703
|
+
* @return result as a Point4d with the same weight.
|
|
1682
1704
|
*/
|
|
1683
1705
|
multiplyInverseXYZW(x, y, z, w, result) {
|
|
1684
1706
|
this.computeCachedInverse(true);
|
|
1685
1707
|
if (this.inverseCoffs) {
|
|
1686
|
-
return Point4d_1.Point4d.create(
|
|
1708
|
+
return Point4d_1.Point4d.create(this.inverseCoffs[0] * x + this.inverseCoffs[1] * y + this.inverseCoffs[2] * z, this.inverseCoffs[3] * x + this.inverseCoffs[4] * y + this.inverseCoffs[5] * z, this.inverseCoffs[6] * x + this.inverseCoffs[7] * y + this.inverseCoffs[8] * z, w, result);
|
|
1687
1709
|
}
|
|
1688
1710
|
return undefined;
|
|
1689
1711
|
}
|
|
1690
1712
|
/**
|
|
1691
|
-
*
|
|
1692
|
-
* *
|
|
1693
|
-
*
|
|
1694
|
-
* * return as a Point3d.
|
|
1713
|
+
* Multiply `matrixInverse * [x,y,z]` and return result as `Point3d`.
|
|
1714
|
+
* * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1715
|
+
* @return result as a Point3d or undefined (if the matrix is singular).
|
|
1695
1716
|
*/
|
|
1696
1717
|
multiplyInverseXYZAsPoint3d(x, y, z, result) {
|
|
1697
1718
|
this.computeCachedInverse(true);
|
|
1698
1719
|
if (this.inverseCoffs) {
|
|
1699
|
-
return Point3dVector3d_1.Point3d.create(
|
|
1720
|
+
return Point3dVector3d_1.Point3d.create(this.inverseCoffs[0] * x + this.inverseCoffs[1] * y + this.inverseCoffs[2] * z, this.inverseCoffs[3] * x + this.inverseCoffs[4] * y + this.inverseCoffs[5] * z, this.inverseCoffs[6] * x + this.inverseCoffs[7] * y + this.inverseCoffs[8] * z, result);
|
|
1700
1721
|
}
|
|
1701
1722
|
return undefined;
|
|
1702
1723
|
}
|
|
1703
1724
|
/**
|
|
1704
|
-
*
|
|
1705
|
-
* * set
|
|
1706
|
-
*
|
|
1725
|
+
* Invoke a given matrix*matrix operation to compute the inverse matrix and set this.inverseCoffs
|
|
1726
|
+
* * If either input coffA or coffB is undefined, set state to `InverseMatrixState.unknown` but
|
|
1727
|
+
* leave the inverseCoffs untouched.
|
|
1728
|
+
* @param f the given matrix*matrix operation that is called by this function to compute the inverse.
|
|
1729
|
+
* `f` must be a matrix*matrix operation. Otherwise, the function does not generate the inverse properly.
|
|
1707
1730
|
*/
|
|
1708
1731
|
finishInverseCoffs(f, coffA, coffB) {
|
|
1709
1732
|
if (coffA && coffB) {
|
|
1710
1733
|
this.createInverseCoffsWithZeros();
|
|
1711
1734
|
this.inverseState = InverseMatrixState.inverseStored;
|
|
1712
|
-
f(coffA, coffB, this.inverseCoffs);
|
|
1735
|
+
f(coffA, coffB, this.inverseCoffs); // call function f (which is provided by user) to compute the inverse.
|
|
1713
1736
|
}
|
|
1714
1737
|
else {
|
|
1715
1738
|
this.inverseState = InverseMatrixState.unknown;
|
|
1716
1739
|
}
|
|
1717
1740
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
* @return the matrix product A * B
|
|
1741
|
+
// Notes on inverse of matrix products:
|
|
1742
|
+
// 1) M = A * B ===> MInverse = BInverse * AInverse
|
|
1743
|
+
// 2) M = A * BInverse ===> MInverse = B * AInverse
|
|
1744
|
+
// 3) M = AInverse * B ===> MInverse = BInverse * A
|
|
1745
|
+
// 4) M = A * BTranspose ===> MInverse = BInverseTranspose * AInverse
|
|
1746
|
+
// 5) M = ATranspose * B ===> MInverse = BInverse * AInverseTranspose
|
|
1747
|
+
/**
|
|
1748
|
+
* Multiply `this` matrix times `other` matrix
|
|
1749
|
+
* @return the matrix result: this*other
|
|
1728
1750
|
*/
|
|
1729
1751
|
multiplyMatrixMatrix(other, result) {
|
|
1730
1752
|
result = result ? result : new Matrix3d();
|
|
1731
1753
|
PackedMatrix3dOps.multiplyMatrixMatrix(this.coffs, other.coffs, result.coffs);
|
|
1732
|
-
if (this.inverseState === InverseMatrixState.inverseStored
|
|
1754
|
+
if (this.inverseState === InverseMatrixState.inverseStored
|
|
1755
|
+
&& other.inverseState === InverseMatrixState.inverseStored)
|
|
1733
1756
|
result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixMatrix, other.inverseCoffs, this.inverseCoffs);
|
|
1734
|
-
else if (this.inverseState === InverseMatrixState.singular
|
|
1757
|
+
else if (this.inverseState === InverseMatrixState.singular
|
|
1758
|
+
|| other.inverseState === InverseMatrixState.singular)
|
|
1735
1759
|
result.inverseState = InverseMatrixState.singular;
|
|
1736
1760
|
else
|
|
1737
1761
|
result.inverseState = InverseMatrixState.unknown;
|
|
1738
1762
|
return result;
|
|
1739
1763
|
}
|
|
1740
|
-
/**
|
|
1741
|
-
*
|
|
1764
|
+
/**
|
|
1765
|
+
* Multiply `this` matrix times `inverse of other` matrix
|
|
1766
|
+
* @return the matrix result: this*otherInverse
|
|
1742
1767
|
*/
|
|
1743
1768
|
multiplyMatrixMatrixInverse(other, result) {
|
|
1744
1769
|
if (!other.computeCachedInverse(true))
|
|
@@ -1752,8 +1777,9 @@ class Matrix3d {
|
|
|
1752
1777
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
|
|
1753
1778
|
return result;
|
|
1754
1779
|
}
|
|
1755
|
-
/**
|
|
1756
|
-
*
|
|
1780
|
+
/**
|
|
1781
|
+
* Multiply `inverse of this` matrix times `other` matrix
|
|
1782
|
+
* @return the matrix result: thisInverse*other
|
|
1757
1783
|
*/
|
|
1758
1784
|
multiplyMatrixInverseMatrix(other, result) {
|
|
1759
1785
|
if (!this.computeCachedInverse(true))
|
|
@@ -1767,30 +1793,32 @@ class Matrix3d {
|
|
|
1767
1793
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
|
|
1768
1794
|
return result;
|
|
1769
1795
|
}
|
|
1770
|
-
/**
|
|
1796
|
+
/**
|
|
1797
|
+
* Multiply `this` matrix times the transpose of `other` matrix
|
|
1771
1798
|
* ```
|
|
1772
1799
|
* equation
|
|
1773
|
-
* \text{for instance matrix }A\text{ and
|
|
1800
|
+
* \text{for instance matrix }A\text{ and matrix }B\text{ return matrix }C{\text where }\\\matrixXY{C}=\matrixXY{A}\matrixTransposeSubXY{B}
|
|
1774
1801
|
* ```
|
|
1775
|
-
* @return the matrix result
|
|
1802
|
+
* @return the matrix result: this*otherTranspose
|
|
1776
1803
|
*/
|
|
1777
|
-
multiplyMatrixMatrixTranspose(
|
|
1804
|
+
multiplyMatrixMatrixTranspose(other, result) {
|
|
1778
1805
|
result = result ? result : new Matrix3d();
|
|
1779
|
-
PackedMatrix3dOps.multiplyMatrixMatrixTranspose(this.coffs,
|
|
1780
|
-
if (this.inverseState === InverseMatrixState.inverseStored &&
|
|
1781
|
-
result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixTransposeMatrix,
|
|
1782
|
-
else if (this.inverseState === InverseMatrixState.singular ||
|
|
1806
|
+
PackedMatrix3dOps.multiplyMatrixMatrixTranspose(this.coffs, other.coffs, result.coffs);
|
|
1807
|
+
if (this.inverseState === InverseMatrixState.inverseStored && other.inverseState === InverseMatrixState.inverseStored)
|
|
1808
|
+
result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixTransposeMatrix, other.inverseCoffs, this.inverseCoffs);
|
|
1809
|
+
else if (this.inverseState === InverseMatrixState.singular || other.inverseState === InverseMatrixState.singular)
|
|
1783
1810
|
result.inverseState = InverseMatrixState.singular;
|
|
1784
1811
|
else
|
|
1785
1812
|
result.inverseState = InverseMatrixState.unknown;
|
|
1786
1813
|
return result;
|
|
1787
1814
|
}
|
|
1788
|
-
/**
|
|
1815
|
+
/**
|
|
1816
|
+
* Multiply the transpose of `this` matrix times `other` matrix
|
|
1789
1817
|
* ```
|
|
1790
1818
|
* equation
|
|
1791
1819
|
* \matrixXY{result}=\matrixXY{\text{this}}\matrixTransposeSubXY{\text{other}}
|
|
1792
1820
|
* ```
|
|
1793
|
-
*
|
|
1821
|
+
* @return the matrix result: thisTranspose*other
|
|
1794
1822
|
*/
|
|
1795
1823
|
multiplyMatrixTransposeMatrix(other, result) {
|
|
1796
1824
|
result = result ? result : new Matrix3d();
|
|
@@ -1803,30 +1831,31 @@ class Matrix3d {
|
|
|
1803
1831
|
result.inverseState = InverseMatrixState.unknown;
|
|
1804
1832
|
return result;
|
|
1805
1833
|
}
|
|
1806
|
-
/**
|
|
1834
|
+
/**
|
|
1835
|
+
* Multiply `this` Matrix3d (considered as a Transform with 0 translation) times `other` Transform.
|
|
1807
1836
|
* ```
|
|
1808
1837
|
* equation
|
|
1809
1838
|
* \begin{matrix}
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1839
|
+
* \text{This matrix }\bold{A}\text{ promoted to block transform} & \blockTransform{A}{0} \\
|
|
1840
|
+
* \text{other transform with matrix part }\bold{B}\text{ and translation }\bold{b} & \blockTransform{B}{b}\\
|
|
1812
1841
|
* \text{product}& \blockTransform{A}{0}\blockTransform{B}{b}=\blockTransform{AB}{Ab}
|
|
1813
1842
|
* \end{matrix}
|
|
1814
1843
|
* ```
|
|
1815
|
-
* @param other
|
|
1816
|
-
* @param result
|
|
1844
|
+
* @param other Right hand Matrix3d for multiplication.
|
|
1845
|
+
* @param result the Transform result (optional)
|
|
1817
1846
|
*/
|
|
1818
1847
|
multiplyMatrixTransform(other, result) {
|
|
1819
1848
|
if (!result)
|
|
1820
1849
|
return Transform_1.Transform.createRefs(this.multiplyXYZ(other.origin.x, other.origin.y, other.origin.z), this.multiplyMatrixMatrix(other.matrix));
|
|
1821
|
-
// be sure to do the point multiplication first before aliasing changes the matrix
|
|
1850
|
+
// be sure to do the point multiplication first before aliasing changes the matrix
|
|
1822
1851
|
this.multiplyXYZtoXYZ(other.origin, result.origin);
|
|
1823
1852
|
this.multiplyMatrixMatrix(other.matrix, result.matrix);
|
|
1824
1853
|
return result;
|
|
1825
1854
|
}
|
|
1826
1855
|
/**
|
|
1827
1856
|
* Return the transpose of `this` matrix.
|
|
1828
|
-
* If `result` is passed as argument, then the function copies the transpose of `this` into `result
|
|
1829
|
-
* `this` is not changed unless also passed as the result, i.e., this.transpose(this) transposes `this` in place
|
|
1857
|
+
* * If `result` is passed as argument, then the function copies the transpose of `this` into `result`.
|
|
1858
|
+
* * `this` is not changed unless also passed as the result, i.e., `this.transpose(this)` transposes `this` in place.
|
|
1830
1859
|
*/
|
|
1831
1860
|
transpose(result) {
|
|
1832
1861
|
if (!result)
|
|
@@ -1848,18 +1877,22 @@ class Matrix3d {
|
|
|
1848
1877
|
transposeInPlace() {
|
|
1849
1878
|
PackedMatrix3dOps.transposeInPlace(this.coffs);
|
|
1850
1879
|
if (this.inverseCoffs)
|
|
1851
|
-
PackedMatrix3dOps.transposeInPlace(this.inverseCoffs);
|
|
1880
|
+
PackedMatrix3dOps.transposeInPlace(this.inverseCoffs); // inverse of transpose is equal to transpose of inverse
|
|
1852
1881
|
}
|
|
1853
|
-
/**
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
* *
|
|
1882
|
+
/**
|
|
1883
|
+
* Return the inverse matrix.
|
|
1884
|
+
* The return is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1885
|
+
* * If `result == this`, then content of inverse of `this` matrix is copied into `this`. Otherwise, inverse
|
|
1886
|
+
* of `this` is stored in `result`.
|
|
1887
|
+
* * **Note:** Each Matrix3d object caches its own inverse (`this.inverseCoffs`) and has methods to multiply
|
|
1888
|
+
* the inverse times matrices and vectors (e.g., `multiplyMatrixInverseMatrix`, `multiplyMatrixMatrixInverse`,
|
|
1889
|
+
* `multiplyInverse`). Hence explicitly constructing this new inverse object is rarely necessary.
|
|
1857
1890
|
*/
|
|
1858
1891
|
inverse(result) {
|
|
1859
1892
|
if (!this.computeCachedInverse(true))
|
|
1860
1893
|
return undefined;
|
|
1861
1894
|
if (result === this) {
|
|
1862
|
-
// swap the contents
|
|
1895
|
+
// swap the contents of this.coffs and this.inverseCoffs
|
|
1863
1896
|
PackedMatrix3dOps.copy(this.coffs, Matrix3d._productBuffer);
|
|
1864
1897
|
PackedMatrix3dOps.copy(this.inverseCoffs, this.coffs);
|
|
1865
1898
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, this.inverseCoffs);
|
|
@@ -1874,33 +1907,48 @@ class Matrix3d {
|
|
|
1874
1907
|
result.inverseState = this.inverseState;
|
|
1875
1908
|
return result;
|
|
1876
1909
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1910
|
+
/**
|
|
1911
|
+
* Take the dot product of a row (specified by `rowStartA`) of `coffA` and `columnStartB` of `coffB`.
|
|
1912
|
+
* * **Note:** We don't validate row/column numbers. Pass 0/3/6 for row 0/1/2 and pass 0/1/2 for column 0/1/2.
|
|
1913
|
+
*/
|
|
1914
|
+
static rowColumnDot(coffA, rowStartA, coffB, columnStartB) {
|
|
1915
|
+
return coffA[rowStartA] * coffB[columnStartB] +
|
|
1916
|
+
coffA[rowStartA + 1] * coffB[columnStartB + 3] +
|
|
1917
|
+
coffA[rowStartA + 2] * coffB[columnStartB + 6];
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* Take the cross product of 2 rows (specified by `rowStart0` and `rowStart1`) of `source` and store the result
|
|
1921
|
+
* in `columnStart` of `dest`.
|
|
1922
|
+
* * **Note:** We don't validate row/column numbers. Pass 0/3/6 for row 0/1/2 and pass 0/1/2 for column 0/1/2.
|
|
1923
|
+
*/
|
|
1881
1924
|
static indexedRowCrossProduct(source, rowStart0, rowStart1, dest, columnStart) {
|
|
1882
1925
|
dest[columnStart] = source[rowStart0 + 1] * source[rowStart1 + 2] - source[rowStart0 + 2] * source[rowStart1 + 1];
|
|
1883
1926
|
dest[columnStart + 3] = source[rowStart0 + 2] * source[rowStart1] - source[rowStart0] * source[rowStart1 + 2];
|
|
1884
1927
|
dest[columnStart + 6] = source[rowStart0] * source[rowStart1 + 1] - source[rowStart0 + 1] * source[rowStart1];
|
|
1885
1928
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1929
|
+
/**
|
|
1930
|
+
* Take the cross product of 2 columns (i.e., `colStart0` and `colStart1`) of `this` matrix and store the
|
|
1931
|
+
* result in `colStart2` of the same matrix.
|
|
1932
|
+
* * **Note:** We don't validate column numbers. Pass 0/1/2 for column 0/1/2.
|
|
1933
|
+
*/
|
|
1889
1934
|
indexedColumnCrossProductInPlace(colStart0, colStart1, colStart2) {
|
|
1890
1935
|
const coffs = this.coffs;
|
|
1891
1936
|
coffs[colStart2] = coffs[colStart0 + 3] * coffs[colStart1 + 6] - coffs[colStart0 + 6] * coffs[colStart1 + 3];
|
|
1892
1937
|
coffs[colStart2 + 3] = coffs[colStart0 + 6] * coffs[colStart1] - coffs[colStart0] * coffs[colStart1 + 6];
|
|
1893
1938
|
coffs[colStart2 + 6] = coffs[colStart0] * coffs[colStart1 + 3] - coffs[colStart0 + 3] * coffs[colStart1];
|
|
1894
1939
|
}
|
|
1895
|
-
/**
|
|
1896
|
-
*
|
|
1897
|
-
*
|
|
1940
|
+
/**
|
|
1941
|
+
* Form cross products among columns in axisOrder.
|
|
1942
|
+
* For axis order ABC:
|
|
1943
|
+
* * form cross product of column A and B, store in C.
|
|
1898
1944
|
* * form cross product of column C and A, store in B.
|
|
1945
|
+
* * [A B C] ===> [A B AxB] ===> [A (AxB)xA AxB]
|
|
1946
|
+
*
|
|
1899
1947
|
* This means that in the final matrix:
|
|
1900
|
-
* * column A is
|
|
1901
|
-
* * column B is linear combination of
|
|
1948
|
+
* * column A is same as original column A.
|
|
1949
|
+
* * column B is linear combination of original A and B (i.e., is in the plane of original A and B).
|
|
1902
1950
|
* * column C is perpendicular to A and B of both the original and final.
|
|
1903
|
-
* * original column C does not participate in the result.
|
|
1951
|
+
* * original column C is overwritten and does not participate in the result.
|
|
1904
1952
|
*/
|
|
1905
1953
|
axisOrderCrossProductsInPlace(axisOrder) {
|
|
1906
1954
|
switch (axisOrder) {
|
|
@@ -1936,41 +1984,44 @@ class Matrix3d {
|
|
|
1936
1984
|
}
|
|
1937
1985
|
}
|
|
1938
1986
|
}
|
|
1939
|
-
/**
|
|
1940
|
-
*
|
|
1941
|
-
* @
|
|
1942
|
-
* @
|
|
1987
|
+
/**
|
|
1988
|
+
* Normalize each column in place.
|
|
1989
|
+
* @param originalRowMagnitudes optional vector to store original column magnitudes.
|
|
1990
|
+
* @returns Return true if all columns have non-zero lengths. Otherwise, return false.
|
|
1991
|
+
* * If false is returned, the magnitudes are stored in the `originalRowMagnitudes` vector but no columns
|
|
1992
|
+
* are altered.
|
|
1943
1993
|
*/
|
|
1944
|
-
normalizeColumnsInPlace(
|
|
1994
|
+
normalizeColumnsInPlace(originalRowMagnitudes) {
|
|
1945
1995
|
const ax = this.columnXMagnitude();
|
|
1946
1996
|
const ay = this.columnYMagnitude();
|
|
1947
1997
|
const az = this.columnZMagnitude();
|
|
1948
|
-
if (
|
|
1949
|
-
|
|
1998
|
+
if (originalRowMagnitudes)
|
|
1999
|
+
originalRowMagnitudes.set(ax, ay, az);
|
|
1950
2000
|
if (Geometry_1.Geometry.isSmallMetricDistance(ax) || Geometry_1.Geometry.isSmallMetricDistance(ay) || Geometry_1.Geometry.isSmallMetricDistance(az))
|
|
1951
2001
|
return false;
|
|
1952
2002
|
this.scaleColumns(1.0 / ax, 1.0 / ay, 1.0 / az, this);
|
|
1953
2003
|
return true;
|
|
1954
2004
|
}
|
|
1955
|
-
/**
|
|
1956
|
-
|
|
2005
|
+
/**
|
|
2006
|
+
* Normalize each row in place.
|
|
2007
|
+
* @param originalColumnMagnitudes optional vector to store original row magnitudes.
|
|
2008
|
+
* @returns Return true if all rows have non-zero lengths. Otherwise, return false.
|
|
2009
|
+
* * If false is returned, the magnitudes are stored in the `originalColumnMagnitudes` vector but no rows
|
|
2010
|
+
* are altered.
|
|
2011
|
+
*/
|
|
2012
|
+
normalizeRowsInPlace(originalColumnMagnitudes) {
|
|
1957
2013
|
const ax = this.rowXMagnitude();
|
|
1958
2014
|
const ay = this.rowYMagnitude();
|
|
1959
2015
|
const az = this.rowZMagnitude();
|
|
1960
|
-
if (
|
|
1961
|
-
|
|
2016
|
+
if (originalColumnMagnitudes)
|
|
2017
|
+
originalColumnMagnitudes.set(ax, ay, az);
|
|
1962
2018
|
if (Geometry_1.Geometry.isSmallMetricDistance(ax) || Geometry_1.Geometry.isSmallMetricDistance(ay) || Geometry_1.Geometry.isSmallMetricDistance(az))
|
|
1963
2019
|
return false;
|
|
1964
2020
|
this.scaleRows(1.0 / ax, 1.0 / ay, 1.0 / az, this);
|
|
1965
2021
|
return true;
|
|
1966
2022
|
}
|
|
1967
|
-
// take the cross product of two rows of source.
|
|
1968
|
-
// store as a column of dest.
|
|
1969
|
-
static rowColumnDot(coffA, rowStartA, coffB, columnStartB) {
|
|
1970
|
-
return coffA[rowStartA] * coffB[columnStartB] + coffA[rowStartA + 1] * coffB[columnStartB + 3] + coffA[rowStartA + 2] * coffB[columnStartB + 6];
|
|
1971
|
-
}
|
|
1972
2023
|
/**
|
|
1973
|
-
* Returns true if the matrix is singular
|
|
2024
|
+
* Returns true if the matrix is singular.
|
|
1974
2025
|
*/
|
|
1975
2026
|
isSingular() {
|
|
1976
2027
|
return !this.computeCachedInverse(true);
|
|
@@ -1982,18 +2033,10 @@ class Matrix3d {
|
|
|
1982
2033
|
this.inverseState = InverseMatrixState.singular;
|
|
1983
2034
|
}
|
|
1984
2035
|
/**
|
|
1985
|
-
*
|
|
1986
|
-
*
|
|
1987
|
-
*
|
|
1988
|
-
|
|
1989
|
-
createInverseCoffsWithZeros() {
|
|
1990
|
-
if (!this.inverseCoffs) {
|
|
1991
|
-
this.inverseState = InverseMatrixState.unknown;
|
|
1992
|
-
this.inverseCoffs = new Float64Array(9);
|
|
1993
|
-
}
|
|
1994
|
-
}
|
|
1995
|
-
/** compute the inverse of this Matrix3d. The inverse is stored for later use.
|
|
1996
|
-
* @returns Return true if the inverse computed. (False if the columns collapse to a point, line or plane.)
|
|
2036
|
+
* Compute the inverse of `this` Matrix3d. The inverse is stored in `this.inverseCoffs` for later use.
|
|
2037
|
+
* @param useCacheIfAvailable if `true`, use the previously computed inverse if available. If `false`,
|
|
2038
|
+
* recompute the inverse.
|
|
2039
|
+
* @returns Return `true` if the inverse is computed. Return `false` if matrix is singular.
|
|
1997
2040
|
*/
|
|
1998
2041
|
computeCachedInverse(useCacheIfAvailable) {
|
|
1999
2042
|
if (useCacheIfAvailable && Matrix3d.useCachedInverse && this.inverseState !== InverseMatrixState.unknown) {
|
|
@@ -2004,71 +2047,45 @@ class Matrix3d {
|
|
|
2004
2047
|
this.createInverseCoffsWithZeros();
|
|
2005
2048
|
const coffs = this.coffs;
|
|
2006
2049
|
const inverseCoffs = this.inverseCoffs;
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2050
|
+
/**
|
|
2051
|
+
* We calculate the inverse using cross products.
|
|
2052
|
+
* Math details can be found at
|
|
2053
|
+
* https://www.chilimath.com/lessons/advanced-algebra/determinant-3x3-matrix/
|
|
2054
|
+
* In summary, if M = [A B C] then inverse of M = (1/det)[BxC CxA AxB] where det is the
|
|
2055
|
+
* determinant of matrix M and can be calculated by "A dot BxC".
|
|
2056
|
+
*/
|
|
2057
|
+
Matrix3d.indexedRowCrossProduct(coffs, 3, 6, inverseCoffs, 0); // BxC
|
|
2058
|
+
Matrix3d.indexedRowCrossProduct(coffs, 6, 0, inverseCoffs, 1); // CxA
|
|
2059
|
+
Matrix3d.indexedRowCrossProduct(coffs, 0, 3, inverseCoffs, 2); // AxB
|
|
2010
2060
|
Matrix3d.numComputeCache++;
|
|
2011
|
-
const
|
|
2012
|
-
if (
|
|
2061
|
+
const det = Matrix3d.rowColumnDot(coffs, 0, inverseCoffs, 0); // A dot BxC
|
|
2062
|
+
if (det === 0.0) {
|
|
2013
2063
|
this.inverseState = InverseMatrixState.singular;
|
|
2014
2064
|
this.inverseCoffs = undefined;
|
|
2015
2065
|
return false;
|
|
2016
2066
|
}
|
|
2017
|
-
const f = 1.0 /
|
|
2067
|
+
const f = 1.0 / det;
|
|
2018
2068
|
for (let i = 0; i < 9; i++)
|
|
2019
2069
|
inverseCoffs[i] *= f;
|
|
2020
2070
|
this.inverseState = InverseMatrixState.inverseStored;
|
|
2021
|
-
// verify inverse
|
|
2022
|
-
// const p = new Float64Array(9);
|
|
2023
|
-
// for (let i = 0; i < 9; i += 3)
|
|
2024
|
-
// for (let j = 0; j < 3; j++)
|
|
2025
|
-
// p[i + j] = Matrix3d.rowColumnDot (coffs, i, inverseCoffs, j);
|
|
2026
2071
|
return true;
|
|
2027
2072
|
}
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
private static crossXY: Vector3d = Vector3d.create();
|
|
2033
|
-
private static crossZX: Vector3d = Vector3d.create();
|
|
2034
|
-
private static crossYZ: Vector3d = Vector3d.create();
|
|
2035
|
-
private computeCachedInverse(useCacheIfAvailable: boolean) {
|
|
2036
|
-
if (useCacheIfAvailable && Matrix3d.useCachedInverse && this.inverseState !== InverseMatrixState.unknown) {
|
|
2037
|
-
Matrix3d.numUseCache++;
|
|
2038
|
-
return this.inverseState === InverseMatrixState.inverseStored;
|
|
2039
|
-
}
|
|
2040
|
-
this.inverseState = InverseMatrixState.unknown;
|
|
2041
|
-
Matrix3d.numComputeCache++;
|
|
2042
|
-
const rowX = this.rowX(Matrix3d.rowX);
|
|
2043
|
-
const rowY = this.rowY(Matrix3d.rowY);
|
|
2044
|
-
const rowZ = this.rowZ(Matrix3d.rowZ);
|
|
2045
|
-
const crossXY = rowX.crossProduct(rowY, Matrix3d.crossXY);
|
|
2046
|
-
const crossYZ = rowY.crossProduct(rowZ, Matrix3d.crossYZ);
|
|
2047
|
-
const crossZX = rowZ.crossProduct(rowX, Matrix3d.crossZX);
|
|
2048
|
-
const d = rowX.dotProduct(crossYZ); // that's the determinant
|
|
2049
|
-
if (d === 0.0) { // better test?
|
|
2050
|
-
this.inverseState = InverseMatrixState.singular;
|
|
2051
|
-
this.inverseCoffs = undefined;
|
|
2052
|
-
return false;
|
|
2053
|
-
}
|
|
2054
|
-
const f = 1.0 / d;
|
|
2055
|
-
this.inverseState = InverseMatrixState.inverseStored; // Currently just lists that the inverse has been stored... singular case not handled
|
|
2056
|
-
this.inverseCoffs = Float64Array.from([crossYZ.x * f, crossZX.x * f, crossXY.x * f,
|
|
2057
|
-
crossYZ.y * f, crossZX.y * f, crossXY.y * f,
|
|
2058
|
-
crossYZ.z * f, crossZX.z * f, crossXY.z * f]);
|
|
2059
|
-
return true;
|
|
2060
|
-
}
|
|
2061
|
-
*/
|
|
2062
|
-
/** convert a (row,column) index pair to the single index within flattened array of 9 numbers in row-major-order */
|
|
2073
|
+
/**
|
|
2074
|
+
* Convert a (row,column) index pair to the single index within flattened array of 9 numbers in row-major-order
|
|
2075
|
+
* * **Note:** Out of range row/column is interpreted cyclically.
|
|
2076
|
+
*/
|
|
2063
2077
|
static flatIndexOf(row, column) {
|
|
2064
2078
|
return 3 * Geometry_1.Geometry.cyclic3dAxis(row) + Geometry_1.Geometry.cyclic3dAxis(column);
|
|
2065
2079
|
}
|
|
2066
|
-
/**
|
|
2080
|
+
/**
|
|
2081
|
+
* Get elements of column `index` packaged as a Point4d with given `weight`.
|
|
2082
|
+
* * **Note:** Out of range index is interpreted cyclically.
|
|
2083
|
+
*/
|
|
2067
2084
|
indexedColumnWithWeight(index, weight, result) {
|
|
2068
2085
|
index = Geometry_1.Geometry.cyclic3dAxis(index);
|
|
2069
2086
|
return Point4d_1.Point4d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], weight, result);
|
|
2070
2087
|
}
|
|
2071
|
-
/**
|
|
2088
|
+
/** Return the entry at specific row and column */
|
|
2072
2089
|
at(row, column) {
|
|
2073
2090
|
return this.coffs[Matrix3d.flatIndexOf(row, column)];
|
|
2074
2091
|
}
|
|
@@ -2081,7 +2098,7 @@ class Matrix3d {
|
|
|
2081
2098
|
* @param scaleX scale factor for column x
|
|
2082
2099
|
* @param scaleY scale factor for column y
|
|
2083
2100
|
* @param scaleZ scale factor for column z
|
|
2084
|
-
* @param result optional result.
|
|
2101
|
+
* @param result optional preallocated result.
|
|
2085
2102
|
*/
|
|
2086
2103
|
scaleColumns(scaleX, scaleY, scaleZ, result) {
|
|
2087
2104
|
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);
|
|
@@ -2102,7 +2119,7 @@ class Matrix3d {
|
|
|
2102
2119
|
this.coffs[7] *= scaleY;
|
|
2103
2120
|
this.coffs[8] *= scaleZ;
|
|
2104
2121
|
if (this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined) {
|
|
2105
|
-
// apply reciprocal scales to the ROWS of the inverse
|
|
2122
|
+
// apply reciprocal scales to the ROWS of the inverse
|
|
2106
2123
|
const divX = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleX);
|
|
2107
2124
|
const divY = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleY);
|
|
2108
2125
|
const divZ = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleZ);
|
|
@@ -2125,7 +2142,7 @@ class Matrix3d {
|
|
|
2125
2142
|
* @param scaleX scale factor for row x
|
|
2126
2143
|
* @param scaleY scale factor for row y
|
|
2127
2144
|
* @param scaleZ scale factor for row z
|
|
2128
|
-
* @param result optional result.
|
|
2145
|
+
* @param result optional preallocated result.
|
|
2129
2146
|
*/
|
|
2130
2147
|
scaleRows(scaleX, scaleY, scaleZ, result) {
|
|
2131
2148
|
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);
|
|
@@ -2169,12 +2186,64 @@ class Matrix3d {
|
|
|
2169
2186
|
}
|
|
2170
2187
|
/** create a Matrix3d whose values are uniformly scaled from this.
|
|
2171
2188
|
* @param scale scale factor to apply.
|
|
2172
|
-
* @param result optional result.
|
|
2189
|
+
* @param result optional preallocated result.
|
|
2173
2190
|
* @returns Return the new or repopulated matrix
|
|
2174
2191
|
*/
|
|
2175
2192
|
scale(scale, result) {
|
|
2176
2193
|
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);
|
|
2177
2194
|
}
|
|
2195
|
+
/**
|
|
2196
|
+
* Create a rigid matrix (columns and rows are unit length and pairwise perpendicular) for
|
|
2197
|
+
* the given eye coordinate.
|
|
2198
|
+
* * column 2 is parallel to (x,y,z).
|
|
2199
|
+
* * column 0 is perpendicular to column 2 and is in the xy plane.
|
|
2200
|
+
* * column 1 is perpendicular to both. It is the "up" vector on the view plane.
|
|
2201
|
+
* * Multiplying the returned matrix times a local (view) vector gives the world vector.
|
|
2202
|
+
* * Multiplying transpose of the returned matrix times a world vector gives the local (view) vector.
|
|
2203
|
+
* @param x eye x coordinate
|
|
2204
|
+
* @param y eye y coordinate
|
|
2205
|
+
* @param z eye z coordinate
|
|
2206
|
+
* @param result optional preallocated result
|
|
2207
|
+
*/
|
|
2208
|
+
static createRigidViewAxesZTowardsEye(x, y, z, result) {
|
|
2209
|
+
result = Matrix3d.createIdentity(result);
|
|
2210
|
+
const rxy = Geometry_1.Geometry.hypotenuseXY(x, y);
|
|
2211
|
+
// if coordinate is (0,0,z), i.e., Top or Bottom view
|
|
2212
|
+
if (Geometry_1.Geometry.isSmallMetricDistance(rxy)) {
|
|
2213
|
+
if (z < 0.0)
|
|
2214
|
+
result.scaleColumnsInPlace(1.0, -1.0, -1.0);
|
|
2215
|
+
}
|
|
2216
|
+
else {
|
|
2217
|
+
// if coordinate is (x,y,0), i.e., Front or Back or Left or Right view
|
|
2218
|
+
/**
|
|
2219
|
+
* The matrix that the "else" statement creates is
|
|
2220
|
+
* [-s -s1*c c1*c]
|
|
2221
|
+
* [c -s1*s c1*s]
|
|
2222
|
+
* [0 c1 s1 ]
|
|
2223
|
+
* where
|
|
2224
|
+
* c = x / sqrt(x*x + y*y)
|
|
2225
|
+
* s = y / sqrt(x*x + y*y)
|
|
2226
|
+
* c1 = sqrt(x*x + y*y) / sqrt(x*x + y*y + z*z)
|
|
2227
|
+
* s1 = z / sqrt(x*x + y*y + z*z)
|
|
2228
|
+
*
|
|
2229
|
+
* This is an orthogonal matrix meaning it rotates the standard XYZ axis to ABC axis system
|
|
2230
|
+
* (if matrix is [A B C]). The matrix rotates (0,0,1), i.e., the default Top view or Z axis,
|
|
2231
|
+
* to the eye point (x/r,y/r,z/r). The matrix also rotates (1,0,0) to a point on XY plane.
|
|
2232
|
+
*/
|
|
2233
|
+
const c = x / rxy;
|
|
2234
|
+
const s = y / rxy;
|
|
2235
|
+
// if coordinate is (x,y,0), e.g., Front or Back or Left or Right view (for those 4 views x or y is 0 not both)
|
|
2236
|
+
result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
|
|
2237
|
+
// if coordinate is (x,y,z) and z is not 0, i.e., other views such as Iso or RightIso
|
|
2238
|
+
if (z !== 0.0) {
|
|
2239
|
+
const r = Geometry_1.Geometry.hypotenuseXYZ(x, y, z);
|
|
2240
|
+
const s1 = z / r;
|
|
2241
|
+
const c1 = rxy / r;
|
|
2242
|
+
result.applyGivensColumnOp(1, 2, c1, -s1);
|
|
2243
|
+
}
|
|
2244
|
+
}
|
|
2245
|
+
return result;
|
|
2246
|
+
}
|
|
2178
2247
|
/** Return the determinant of this matrix. */
|
|
2179
2248
|
determinant() {
|
|
2180
2249
|
return this.coffs[0] * this.coffs[4] * this.coffs[8]
|
|
@@ -2438,5 +2507,6 @@ Matrix3d.useCachedInverse = true; // cached inverse can be suppressed for testin
|
|
|
2438
2507
|
Matrix3d.numUseCache = 0;
|
|
2439
2508
|
/** Total number of times a cached inverse was computed. */
|
|
2440
2509
|
Matrix3d.numComputeCache = 0;
|
|
2510
|
+
/** temporary buffer to store a matrix as a Float64Array (array of 9 floats) */
|
|
2441
2511
|
Matrix3d._productBuffer = new Float64Array(9);
|
|
2442
2512
|
//# sourceMappingURL=Matrix3d.js.map
|