@itwin/core-geometry 4.0.0-dev.4 → 4.0.0-dev.40
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 +17 -3
- package/lib/cjs/Geometry.d.ts +56 -16
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +87 -30
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/bspline/BSplineCurveOps.js +4 -5
- package/lib/cjs/bspline/BSplineCurveOps.js.map +1 -1
- package/lib/cjs/bspline/InterpolationCurve3d.js +7 -10
- package/lib/cjs/bspline/InterpolationCurve3d.js.map +1 -1
- package/lib/cjs/clipping/ClipPrimitive.js +2 -2
- package/lib/cjs/clipping/ClipPrimitive.js.map +1 -1
- package/lib/cjs/clipping/ClipUtils.js +4 -4
- package/lib/cjs/clipping/ClipUtils.js.map +1 -1
- package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
- package/lib/cjs/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js +20 -13
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/cjs/curve/CurveCollection.js +1 -1
- package/lib/cjs/curve/CurveCollection.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/curve/Loop.d.ts +2 -2
- package/lib/cjs/curve/Loop.d.ts.map +1 -1
- package/lib/cjs/curve/Loop.js +6 -0
- package/lib/cjs/curve/Loop.js.map +1 -1
- package/lib/cjs/curve/RegionOps.d.ts +10 -10
- package/lib/cjs/curve/RegionOps.d.ts.map +1 -1
- package/lib/cjs/curve/RegionOps.js +11 -11
- package/lib/cjs/curve/RegionOps.js.map +1 -1
- package/lib/cjs/curve/RegionOpsClassificationSweeps.d.ts +2 -1
- package/lib/cjs/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
- package/lib/cjs/curve/RegionOpsClassificationSweeps.js +5 -2
- package/lib/cjs/curve/RegionOpsClassificationSweeps.js.map +1 -1
- package/lib/cjs/curve/StrokeOptions.js +1 -2
- package/lib/cjs/curve/StrokeOptions.js.map +1 -1
- package/lib/cjs/curve/spiral/DirectSpiral3d.js +1 -2
- package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.js +1 -2
- package/lib/cjs/curve/spiral/IntegratedSpiral3d.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/BarycentricTriangle.d.ts +195 -8
- package/lib/cjs/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/cjs/geometry3d/BarycentricTriangle.js +459 -11
- package/lib/cjs/geometry3d/BarycentricTriangle.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/GrowableFloat64Array.js +2 -2
- package/lib/cjs/geometry3d/GrowableFloat64Array.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYArray.js +2 -2
- package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.js +1 -1
- package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYCollection.d.ts +22 -7
- package/lib/cjs/geometry3d/IndexedXYCollection.d.ts.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYCollection.js +41 -5
- package/lib/cjs/geometry3d/IndexedXYCollection.js.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts +58 -4
- package/lib/cjs/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
- package/lib/cjs/geometry3d/IndexedXYZCollection.js +102 -4
- package/lib/cjs/geometry3d/IndexedXYZCollection.js.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.d.ts +479 -265
- package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Matrix3d.js +996 -784
- package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
- package/lib/cjs/geometry3d/OrderedRotationAngles.d.ts +1 -0
- package/lib/cjs/geometry3d/OrderedRotationAngles.d.ts.map +1 -1
- package/lib/cjs/geometry3d/OrderedRotationAngles.js +1 -0
- package/lib/cjs/geometry3d/OrderedRotationAngles.js.map +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts +10 -0
- package/lib/cjs/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js +14 -0
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/lib/cjs/geometry3d/Point2dVector2d.js +4 -6
- package/lib/cjs/geometry3d/Point2dVector2d.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts +0 -6
- package/lib/cjs/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point3dArrayCarrier.js +0 -6
- package/lib/cjs/geometry3d/Point3dArrayCarrier.js.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts +57 -57
- package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Point3dVector3d.js +63 -65
- package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/cjs/geometry3d/PointHelpers.d.ts +14 -1
- package/lib/cjs/geometry3d/PointHelpers.d.ts.map +1 -1
- package/lib/cjs/geometry3d/PointHelpers.js +33 -1
- package/lib/cjs/geometry3d/PointHelpers.js.map +1 -1
- package/lib/cjs/geometry3d/PolygonOps.d.ts +127 -19
- package/lib/cjs/geometry3d/PolygonOps.d.ts.map +1 -1
- package/lib/cjs/geometry3d/PolygonOps.js +420 -22
- package/lib/cjs/geometry3d/PolygonOps.js.map +1 -1
- package/lib/cjs/geometry3d/Ray3d.js +1 -1
- package/lib/cjs/geometry3d/Ray3d.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/AuxData.js +1 -1
- package/lib/cjs/polyface/AuxData.js.map +1 -1
- package/lib/cjs/polyface/FacetLocationDetail.d.ts +264 -0
- package/lib/cjs/polyface/FacetLocationDetail.d.ts.map +1 -0
- package/lib/cjs/polyface/FacetLocationDetail.js +376 -0
- package/lib/cjs/polyface/FacetLocationDetail.js.map +1 -0
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.js +5 -2
- package/lib/cjs/polyface/IndexedPolyfaceVisitor.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts +24 -14
- package/lib/cjs/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceBuilder.js +74 -23
- package/lib/cjs/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceClip.js +6 -7
- package/lib/cjs/polyface/PolyfaceClip.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceData.d.ts +1 -1
- package/lib/cjs/polyface/PolyfaceData.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceData.js.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts +76 -1
- package/lib/cjs/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/cjs/polyface/PolyfaceQuery.js +123 -3
- 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/BGFBReader.js +4 -4
- package/lib/cjs/serialization/BGFBReader.js.map +1 -1
- package/lib/cjs/serialization/GeometrySamples.d.ts +8 -6
- package/lib/cjs/serialization/GeometrySamples.d.ts.map +1 -1
- package/lib/cjs/serialization/GeometrySamples.js +26 -19
- package/lib/cjs/serialization/GeometrySamples.js.map +1 -1
- package/lib/cjs/serialization/IModelJsonSchema.js +1 -2
- package/lib/cjs/serialization/IModelJsonSchema.js.map +1 -1
- package/lib/cjs/solid/Sphere.d.ts +5 -5
- package/lib/cjs/solid/Sphere.js +5 -5
- package/lib/cjs/solid/Sphere.js.map +1 -1
- package/lib/cjs/solid/SweepContour.d.ts.map +1 -1
- package/lib/cjs/solid/SweepContour.js +8 -1
- package/lib/cjs/solid/SweepContour.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/cjs/topology/HalfEdgeGraphSearch.d.ts +2 -1
- package/lib/cjs/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
- package/lib/cjs/topology/HalfEdgeGraphSearch.js +1 -0
- package/lib/cjs/topology/HalfEdgeGraphSearch.js.map +1 -1
- package/lib/cjs/topology/Triangulation.js +1 -1
- package/lib/cjs/topology/Triangulation.js.map +1 -1
- package/lib/esm/Geometry.d.ts +56 -16
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +86 -29
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/bspline/BSplineCurveOps.js +4 -5
- package/lib/esm/bspline/BSplineCurveOps.js.map +1 -1
- package/lib/esm/bspline/InterpolationCurve3d.js +7 -10
- package/lib/esm/bspline/InterpolationCurve3d.js.map +1 -1
- package/lib/esm/clipping/ClipPrimitive.js +2 -2
- package/lib/esm/clipping/ClipPrimitive.js.map +1 -1
- package/lib/esm/clipping/ClipUtils.js +4 -4
- package/lib/esm/clipping/ClipUtils.js.map +1 -1
- package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js +2 -2
- package/lib/esm/clipping/internalContexts/LineStringOffsetClipperContext.js.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js +21 -14
- package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/esm/curve/CurveCollection.js +1 -1
- package/lib/esm/curve/CurveCollection.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/curve/Loop.d.ts +2 -2
- package/lib/esm/curve/Loop.d.ts.map +1 -1
- package/lib/esm/curve/Loop.js +6 -0
- package/lib/esm/curve/Loop.js.map +1 -1
- package/lib/esm/curve/RegionOps.d.ts +10 -10
- package/lib/esm/curve/RegionOps.d.ts.map +1 -1
- package/lib/esm/curve/RegionOps.js +11 -11
- package/lib/esm/curve/RegionOps.js.map +1 -1
- package/lib/esm/curve/RegionOpsClassificationSweeps.d.ts +2 -1
- package/lib/esm/curve/RegionOpsClassificationSweeps.d.ts.map +1 -1
- package/lib/esm/curve/RegionOpsClassificationSweeps.js +5 -2
- package/lib/esm/curve/RegionOpsClassificationSweeps.js.map +1 -1
- package/lib/esm/curve/StrokeOptions.js +1 -2
- package/lib/esm/curve/StrokeOptions.js.map +1 -1
- package/lib/esm/curve/spiral/DirectSpiral3d.js +1 -2
- package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
- package/lib/esm/curve/spiral/IntegratedSpiral3d.js +1 -2
- package/lib/esm/curve/spiral/IntegratedSpiral3d.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/BarycentricTriangle.d.ts +195 -8
- package/lib/esm/geometry3d/BarycentricTriangle.d.ts.map +1 -1
- package/lib/esm/geometry3d/BarycentricTriangle.js +459 -12
- package/lib/esm/geometry3d/BarycentricTriangle.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/GrowableFloat64Array.js +2 -2
- package/lib/esm/geometry3d/GrowableFloat64Array.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.d.ts +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
- package/lib/esm/geometry3d/GrowableXYArray.js +2 -2
- package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.js +1 -1
- package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
- package/lib/esm/geometry3d/IndexedXYCollection.d.ts +22 -7
- package/lib/esm/geometry3d/IndexedXYCollection.d.ts.map +1 -1
- package/lib/esm/geometry3d/IndexedXYCollection.js +41 -5
- package/lib/esm/geometry3d/IndexedXYCollection.js.map +1 -1
- package/lib/esm/geometry3d/IndexedXYZCollection.d.ts +58 -4
- package/lib/esm/geometry3d/IndexedXYZCollection.d.ts.map +1 -1
- package/lib/esm/geometry3d/IndexedXYZCollection.js +103 -5
- package/lib/esm/geometry3d/IndexedXYZCollection.js.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.d.ts +479 -265
- package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Matrix3d.js +996 -784
- package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
- package/lib/esm/geometry3d/OrderedRotationAngles.d.ts +1 -0
- package/lib/esm/geometry3d/OrderedRotationAngles.d.ts.map +1 -1
- package/lib/esm/geometry3d/OrderedRotationAngles.js +1 -0
- package/lib/esm/geometry3d/OrderedRotationAngles.js.map +1 -1
- package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts +10 -0
- package/lib/esm/geometry3d/Point2dArrayCarrier.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point2dArrayCarrier.js +14 -0
- package/lib/esm/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/lib/esm/geometry3d/Point2dVector2d.js +4 -6
- package/lib/esm/geometry3d/Point2dVector2d.js.map +1 -1
- package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts +0 -6
- package/lib/esm/geometry3d/Point3dArrayCarrier.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point3dArrayCarrier.js +0 -6
- package/lib/esm/geometry3d/Point3dArrayCarrier.js.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.d.ts +57 -57
- package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
- package/lib/esm/geometry3d/Point3dVector3d.js +63 -65
- package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
- package/lib/esm/geometry3d/PointHelpers.d.ts +14 -1
- package/lib/esm/geometry3d/PointHelpers.d.ts.map +1 -1
- package/lib/esm/geometry3d/PointHelpers.js +33 -1
- package/lib/esm/geometry3d/PointHelpers.js.map +1 -1
- package/lib/esm/geometry3d/PolygonOps.d.ts +127 -19
- package/lib/esm/geometry3d/PolygonOps.d.ts.map +1 -1
- package/lib/esm/geometry3d/PolygonOps.js +419 -22
- package/lib/esm/geometry3d/PolygonOps.js.map +1 -1
- package/lib/esm/geometry3d/Ray3d.js +1 -1
- package/lib/esm/geometry3d/Ray3d.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/AuxData.js +1 -1
- package/lib/esm/polyface/AuxData.js.map +1 -1
- package/lib/esm/polyface/FacetLocationDetail.d.ts +264 -0
- package/lib/esm/polyface/FacetLocationDetail.d.ts.map +1 -0
- package/lib/esm/polyface/FacetLocationDetail.js +369 -0
- package/lib/esm/polyface/FacetLocationDetail.js.map +1 -0
- package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts +2 -5
- package/lib/esm/polyface/IndexedPolyfaceVisitor.d.ts.map +1 -1
- package/lib/esm/polyface/IndexedPolyfaceVisitor.js +5 -2
- package/lib/esm/polyface/IndexedPolyfaceVisitor.js.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.d.ts +24 -14
- package/lib/esm/polyface/PolyfaceBuilder.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceBuilder.js +74 -23
- package/lib/esm/polyface/PolyfaceBuilder.js.map +1 -1
- package/lib/esm/polyface/PolyfaceClip.js +6 -7
- package/lib/esm/polyface/PolyfaceClip.js.map +1 -1
- package/lib/esm/polyface/PolyfaceData.d.ts +1 -1
- package/lib/esm/polyface/PolyfaceData.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceData.js.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts +76 -1
- package/lib/esm/polyface/PolyfaceQuery.d.ts.map +1 -1
- package/lib/esm/polyface/PolyfaceQuery.js +121 -2
- 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/BGFBReader.js +4 -4
- package/lib/esm/serialization/BGFBReader.js.map +1 -1
- package/lib/esm/serialization/GeometrySamples.d.ts +8 -6
- package/lib/esm/serialization/GeometrySamples.d.ts.map +1 -1
- package/lib/esm/serialization/GeometrySamples.js +26 -19
- package/lib/esm/serialization/GeometrySamples.js.map +1 -1
- package/lib/esm/serialization/IModelJsonSchema.js +1 -2
- package/lib/esm/serialization/IModelJsonSchema.js.map +1 -1
- package/lib/esm/solid/Sphere.d.ts +5 -5
- package/lib/esm/solid/Sphere.js +5 -5
- package/lib/esm/solid/Sphere.js.map +1 -1
- package/lib/esm/solid/SweepContour.d.ts.map +1 -1
- package/lib/esm/solid/SweepContour.js +8 -1
- package/lib/esm/solid/SweepContour.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/lib/esm/topology/HalfEdgeGraphSearch.d.ts +2 -1
- package/lib/esm/topology/HalfEdgeGraphSearch.d.ts.map +1 -1
- package/lib/esm/topology/HalfEdgeGraphSearch.js +1 -0
- package/lib/esm/topology/HalfEdgeGraphSearch.js.map +1 -1
- package/lib/esm/topology/Triangulation.js +1 -1
- package/lib/esm/topology/Triangulation.js.map +1 -1
- 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 arctan newcommand diagonalization
|
|
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
|
|
@@ -311,7 +312,7 @@ class Matrix3d {
|
|
|
311
312
|
/**
|
|
312
313
|
* Here we rotate this.columnX() around this.columnZ() by "angle" and expect to get other.columnX().
|
|
313
314
|
* Then we rotate this.columnY() around this.columnZ() by the same "angle" and if we get other.columnY(),
|
|
314
|
-
* that means this` and `other` have X and Y columns differing only by a rotation around
|
|
315
|
+
* that means `this` and `other` have X and Y columns differing only by a rotation around column Z.
|
|
315
316
|
*/
|
|
316
317
|
let column = Point3dVector3d_1.Vector3d.createRotateVectorAroundVector(columnX, columnZ, angle);
|
|
317
318
|
if (other.isAlmostEqualColumnXYZ(0, column.x, column.y, column.z, tol)) {
|
|
@@ -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,14 @@ class Matrix3d {
|
|
|
655
669
|
}
|
|
656
670
|
return Matrix3d.createIdentity(result);
|
|
657
671
|
}
|
|
658
|
-
/**
|
|
672
|
+
/**
|
|
673
|
+
* Return the matrix for rotation of `angle` around desired `axis`
|
|
674
|
+
* * Visualization can be found at https://www.itwinjs.org/sandbox/SaeedTorabi/CubeRotationAroundAnAxis
|
|
675
|
+
* @param axis the axis of rotation
|
|
676
|
+
* @param angle the angle of rotation
|
|
677
|
+
* @param result caller-allocated matrix (optional)
|
|
678
|
+
* @returns the `rotation matrix` or `undefined` (if axis magnitude is near zero).
|
|
679
|
+
*/
|
|
659
680
|
static createRotationAroundVector(axis, angle, result) {
|
|
660
681
|
// Rodriguez formula (matrix form), https://mathworld.wolfram.com/RodriguesRotationFormula.html
|
|
661
682
|
const c = angle.cos();
|
|
@@ -669,7 +690,7 @@ class Matrix3d {
|
|
|
669
690
|
}
|
|
670
691
|
return undefined;
|
|
671
692
|
}
|
|
672
|
-
/** Returns a rotation of specified angle around
|
|
693
|
+
/** Returns a rotation of specified angle around one of the main axis (X,Y,Z).
|
|
673
694
|
* @param axisIndex index of axis (AxisIndex.X, AxisIndex.Y, AxisIndex.Z) kept fixed by the rotation.
|
|
674
695
|
* @param angle angle of rotation
|
|
675
696
|
* @param result optional result matrix.
|
|
@@ -692,14 +713,33 @@ class Matrix3d {
|
|
|
692
713
|
return myResult;
|
|
693
714
|
}
|
|
694
715
|
/**
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
716
|
+
* Replace current rows Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
717
|
+
* * There is no checking for i,j being 0,1,2.
|
|
718
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
719
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
720
|
+
* @param c fist coefficient
|
|
721
|
+
* @param s second coefficient
|
|
722
|
+
*/
|
|
723
|
+
applyGivensRowOp(i, j, c, s) {
|
|
724
|
+
let ii = 3 * i;
|
|
725
|
+
let jj = 3 * j;
|
|
726
|
+
const limit = ii + 3;
|
|
727
|
+
for (; ii < limit; ii++, jj++) {
|
|
728
|
+
const a = this.coffs[ii];
|
|
729
|
+
const b = this.coffs[jj];
|
|
730
|
+
this.coffs[ii] = a * c + b * s;
|
|
731
|
+
this.coffs[jj] = -a * s + b * c;
|
|
732
|
+
}
|
|
733
|
+
}
|
|
734
|
+
/**
|
|
735
|
+
* Replace current columns Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
|
|
736
|
+
* * There is no checking for i,j being 0,1,2.
|
|
737
|
+
* * This is used in compute intensive inner loops
|
|
738
|
+
* @param i first row index. **must be 0,1,2** (unchecked)
|
|
739
|
+
* @param j second row index. **must be 0,1,2** (unchecked)
|
|
740
|
+
* @param c fist coefficient
|
|
741
|
+
* @param s second coefficient
|
|
742
|
+
*/
|
|
703
743
|
applyGivensColumnOp(i, j, c, s) {
|
|
704
744
|
const limit = i + 9;
|
|
705
745
|
for (; i < limit; i += 3, j += 3) {
|
|
@@ -710,12 +750,12 @@ class Matrix3d {
|
|
|
710
750
|
}
|
|
711
751
|
}
|
|
712
752
|
/**
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
753
|
+
* Create a matrix from column vectors.
|
|
754
|
+
* ```
|
|
755
|
+
* equation
|
|
756
|
+
* \begin{bmatrix}U_x & V_x & W_x \\ U_y & V_y & W_y \\ U_z & V_z & W_z \end{bmatrix}
|
|
757
|
+
* ```
|
|
758
|
+
*/
|
|
719
759
|
static createColumns(vectorU, vectorV, vectorW, result) {
|
|
720
760
|
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z, result);
|
|
721
761
|
}
|
|
@@ -728,29 +768,36 @@ class Matrix3d {
|
|
|
728
768
|
static createColumnsXYW(vectorU, u, vectorV, v, vectorW, w, result) {
|
|
729
769
|
return Matrix3d.createRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, u, v, w, result);
|
|
730
770
|
}
|
|
731
|
-
/**
|
|
732
|
-
*
|
|
733
|
-
* *
|
|
771
|
+
/**
|
|
772
|
+
* Create a matrix from "as viewed" right and up vectors.
|
|
773
|
+
* * ColumnX points in the rightVector direction.
|
|
774
|
+
* * ColumnY points in the upVector direction.
|
|
734
775
|
* * ColumnZ is a unit cross product of ColumnX and ColumnY.
|
|
735
|
-
* * Optionally rotate
|
|
736
|
-
* * Optionally rotate
|
|
737
|
-
*
|
|
776
|
+
* * Optionally rotate by 45 degrees around `upVector` to bring its left or right vertical edge to center.
|
|
777
|
+
* * Optionally rotate by arctan(1/sqrt(2)) ~ 35.264 degrees around `rightVector` to bring the top or bottom
|
|
778
|
+
* horizontal edge of the view to the center (for isometric views).
|
|
779
|
+
*
|
|
780
|
+
* This is expected to be used with various principal unit vectors that are perpendicular to each other.
|
|
738
781
|
* * STANDARD TOP VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(), 0, 0)
|
|
739
782
|
* * STANDARD FRONT VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 0, 0)
|
|
740
783
|
* * STANDARD BACK VIEW: createViewedAxes(Vector3d.unitX(-1), Vector3d.unitZ(), 0, 0)
|
|
741
784
|
* * STANDARD RIGHT VIEW: createViewedAxes(Vector3d.unitY(), Vector3d.unitZ(), 0, 0)
|
|
742
785
|
* * STANDARD LEFT VIEW: createViewedAxes(Vector3d.unitY(-1), Vector3d.unitZ(), 0, 0)
|
|
743
786
|
* * STANDARD BOTTOM VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitY(-1), 0, 0)
|
|
787
|
+
* * STANDARD ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), -1, 1)
|
|
788
|
+
* * STANDARD RIGHT ISO VIEW: createViewedAxes(Vector3d.unitX(), Vector3d.unitZ(), 1, 1)
|
|
789
|
+
* * Front, right, back, left, top, and bottom standard views are views from faces of the cube
|
|
790
|
+
* and iso and right iso standard views are views from corners of the cube.
|
|
744
791
|
* * Note: createViewedAxes is column-based so always returns local to world
|
|
745
792
|
*
|
|
746
793
|
* @param rightVector ColumnX of the returned matrix. Expected to be perpendicular to upVector.
|
|
747
794
|
* @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,
|
|
795
|
+
* @param leftNoneRight Specifies the ccw rotation around `upVector` axis. Normally one of "-1", "0", and "1",
|
|
796
|
+
* where "-1" indicates rotation by 45 degrees to bring the left vertical edge to center, "0" means no rotation,
|
|
750
797
|
* and "1" indicates rotation by 45 degrees to bring the right vertical edge to center. Other numbers are
|
|
751
798
|
* 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,
|
|
799
|
+
* @param topNoneBottom Specifies the ccw rotation around `rightVector` axis. Normally one of "-1", "0", and "1",
|
|
800
|
+
* where "-1" indicates isometric rotation (35.264 degrees) to bring the bottom upward, "0" means no rotation,
|
|
754
801
|
* and "1" indicates isometric rotation (35.264 degrees) to bring the top downward. Other numbers are
|
|
755
802
|
* used as multiplier for the 35.264 degree rotation.
|
|
756
803
|
* @returns matrix = [rightVector, upVector, rightVector cross upVector] with the applied rotations specified
|
|
@@ -788,9 +835,11 @@ class Matrix3d {
|
|
|
788
835
|
* * Default is TOP view (`local X = world X`, `local Y = world Y`, `local Z = world Z`).
|
|
789
836
|
* * To change view from the TOP to one of the other 7 standard views, we need to multiply "world data" to
|
|
790
837
|
* the corresponding matrix1 provided by `createStandardWorldToView(index, false)` and then
|
|
791
|
-
* `matrix1.multiply(world data)` will
|
|
838
|
+
* `matrix1.multiply(world data)` will return "local data".
|
|
792
839
|
* * To change view back to the TOP, we need to multiply "local data" to the corresponding matrix2 provided
|
|
793
840
|
* by `createStandardWorldToView(index, true)` and then `matrix2.multiply(local data)` will returns "world data".
|
|
841
|
+
* * Note: No matter how you rotate the world axis, local X is always pointing right, local Y is always pointing up,
|
|
842
|
+
* and local Z is always pointing toward you.
|
|
794
843
|
*
|
|
795
844
|
* @param index standard view index `StandardViewIndex.Top, Bottom, Left, Right, Front, Back, Iso, RightIso`
|
|
796
845
|
* @param invert if false (default), the return matrix is world to local (view) and if true, the the return
|
|
@@ -799,200 +848,388 @@ class Matrix3d {
|
|
|
799
848
|
*/
|
|
800
849
|
static createStandardWorldToView(index, invert = false, result) {
|
|
801
850
|
switch (index) {
|
|
802
|
-
//
|
|
851
|
+
// Start with TOP view, ccw rotation by 180 degrees around X
|
|
803
852
|
case Geometry_1.StandardViewIndex.Bottom:
|
|
804
853
|
result = Matrix3d.createRowValues(1, 0, 0, 0, -1, 0, 0, 0, -1);
|
|
805
854
|
break;
|
|
806
|
-
//
|
|
855
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 90 degrees around Z
|
|
807
856
|
case Geometry_1.StandardViewIndex.Left:
|
|
808
857
|
result = Matrix3d.createRowValues(0, -1, 0, 0, 0, 1, -1, 0, 0);
|
|
809
858
|
break;
|
|
810
|
-
//
|
|
859
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by -90 degrees around Z
|
|
811
860
|
case Geometry_1.StandardViewIndex.Right:
|
|
812
861
|
result = Matrix3d.createRowValues(0, 1, 0, 0, 0, 1, 1, 0, 0);
|
|
813
862
|
break;
|
|
814
|
-
//
|
|
863
|
+
// Start with TOP view, ccw rotation by -90 degrees around X
|
|
815
864
|
case Geometry_1.StandardViewIndex.Front:
|
|
816
865
|
result = Matrix3d.createRowValues(1, 0, 0, 0, 0, 1, 0, -1, 0);
|
|
817
866
|
break;
|
|
818
|
-
//
|
|
867
|
+
// Start with TOP view, ccw rotation by -90 degrees around X and by 180 degrees around Z
|
|
819
868
|
case Geometry_1.StandardViewIndex.Back:
|
|
820
869
|
result = Matrix3d.createRowValues(-1, 0, 0, 0, 0, 1, 0, 1, 0);
|
|
821
870
|
break;
|
|
871
|
+
/**
|
|
872
|
+
* Isometric view
|
|
873
|
+
* Start with FRONT view, ccw rotation by -45 degrees around Y and by arctan(1/sqrt(2)) ~ 35.264 degrees around X
|
|
874
|
+
* cos(45) = 1/sqrt(2) = 0.70710678118 and sin(45) = 1/sqrt(2) = 0.70710678118
|
|
875
|
+
* cos(35.264) = 2/sqrt(6) = 0.81649658092 and sin(35.264) = 1/sqrt(3) = 0.57735026919
|
|
876
|
+
* More info: https://en.wikipedia.org/wiki/Isometric_projection
|
|
877
|
+
*/
|
|
822
878
|
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
879
|
result = Matrix3d.createRowValues(0.707106781186548, -0.70710678118654757, 0.00000000000000000, 0.408248290463863, 0.40824829046386302, 0.81649658092772603, -0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
825
880
|
break;
|
|
881
|
+
// Start with FRONT view, ccw rotation by 45 degrees around Y and by 35.264 degrees around X
|
|
826
882
|
case Geometry_1.StandardViewIndex.RightIso:
|
|
827
883
|
result = Matrix3d.createRowValues(0.707106781186548, 0.70710678118654757, 0.00000000000000000, -0.408248290463863, 0.40824829046386302, 0.81649658092772603, 0.577350269189626, -0.57735026918962573, 0.57735026918962573);
|
|
828
884
|
break;
|
|
829
|
-
|
|
885
|
+
// no rotation
|
|
886
|
+
case Geometry_1.StandardViewIndex.Top:
|
|
830
887
|
default:
|
|
831
888
|
result = Matrix3d.createIdentity(result);
|
|
832
889
|
}
|
|
833
890
|
if (invert)
|
|
834
|
-
result.transposeInPlace();
|
|
891
|
+
result.transposeInPlace(); // matrix is rigid so transpose and inverse are the same
|
|
835
892
|
return result;
|
|
836
893
|
}
|
|
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
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
894
|
+
/**
|
|
895
|
+
* Apply (in place) a jacobi eigenvalue algorithm.
|
|
896
|
+
* @param i row index of zeroed member
|
|
897
|
+
* @param j column index of zeroed member
|
|
898
|
+
* @param leftEigenvectors a matrix that its columns will be filled by the left eigenvectors of `this` Matrix3d
|
|
899
|
+
* (allocated by caller, computed and filled by this function). Note that columns of leftEigenVectors will be
|
|
900
|
+
* mutually perpendicular because `this` matrix is symmetric.
|
|
901
|
+
* @param lambda a matrix that its diagonal entries will be filled by eigenvalues and its non-diagonal elements
|
|
902
|
+
* converge to 0 (allocated by caller, computed and filled by this function).
|
|
903
|
+
*/
|
|
904
|
+
applySymmetricJacobi(i, j, leftEigenvectors, lambda) {
|
|
905
|
+
const sii = lambda.at(i, i);
|
|
906
|
+
const sjj = lambda.at(j, j);
|
|
907
|
+
const sij = lambda.at(i, j);
|
|
908
|
+
if (Math.abs(sij) < 1.0e-15 * (sii + sjj))
|
|
909
|
+
return 0.0;
|
|
910
|
+
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(sii - sjj, 2.0 * sij);
|
|
911
|
+
const c = jacobi.c;
|
|
912
|
+
const s = jacobi.s;
|
|
913
|
+
/**
|
|
914
|
+
* The following check does not exist in applyFastSymmetricJacobi because here if we don't return
|
|
915
|
+
* early, the matrix remains untouched. However, applyFastSymmetricJacobi zeroes-out elements ij
|
|
916
|
+
* and ji. Therefore, if we return early in applyFastSymmetricJacobi, zeroing-out wont happen.
|
|
917
|
+
*/
|
|
918
|
+
if (Math.abs(s) < 2.0e-15)
|
|
919
|
+
return 0.0;
|
|
920
|
+
/**
|
|
921
|
+
* If you apply the following 2 lines to a symmetric matrix, you get same lines used in
|
|
922
|
+
* applyFastSymmetricJacobi. There are 2 differences which make applyFastSymmetricJacobi
|
|
923
|
+
* more efficient. First, we directly set elements ij and ji equal to zero rather than
|
|
924
|
+
* calculation them. Second, we copy symmetric elements from upper triangle to lower
|
|
925
|
+
* instead of calculating them.
|
|
926
|
+
*/
|
|
927
|
+
lambda.applyGivensRowOp(i, j, c, s);
|
|
928
|
+
lambda.applyGivensColumnOp(i, j, c, s);
|
|
929
|
+
leftEigenvectors.applyGivensColumnOp(i, j, c, s);
|
|
930
|
+
return Math.abs(sij);
|
|
931
|
+
}
|
|
932
|
+
/**
|
|
933
|
+
* Factor `this` matrix as a product `U * lambda * UT` where `U` is an orthogonal matrix and `lambda`
|
|
934
|
+
* is a diagonal matrix.
|
|
935
|
+
*
|
|
936
|
+
* * **Note 1:** You must apply this function to a `symmetric` matrix. Otherwise, the lower triangle is ignored
|
|
937
|
+
* and the upper triangle is mirrored to the lower triangle to enforce symmetry.
|
|
938
|
+
* * **Note 2:** This function is replaced by a faster method called `fastSymmetricEigenvalues` so consider
|
|
939
|
+
* using the fast version instead.
|
|
940
|
+
* @param leftEigenvectors a matrix that its columns will be filled by the left eigenvectors of `this` Matrix3d
|
|
941
|
+
* (allocated by caller, computed and filled by this function). Note that columns of leftEigenVectors will be
|
|
942
|
+
* mutually perpendicular because `this` matrix is symmetric.
|
|
943
|
+
* @param lambda a vector that its entries will be filled by eigenvalues of `this` Matrix3d (allocated by
|
|
944
|
+
* caller, computed and filled by this function).
|
|
945
|
+
*/
|
|
946
|
+
symmetricEigenvalues(leftEigenvectors, lambda) {
|
|
947
|
+
const matrix = this.clone();
|
|
948
|
+
leftEigenvectors.setIdentity();
|
|
949
|
+
matrix.coffs[3] = matrix.coffs[1];
|
|
950
|
+
matrix.coffs[6] = matrix.coffs[2];
|
|
951
|
+
matrix.coffs[7] = matrix.coffs[5];
|
|
952
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
953
|
+
const numberOfIterations = 7;
|
|
954
|
+
for (let iteration = 0; iteration < numberOfIterations; iteration++) {
|
|
955
|
+
const sum = this.applySymmetricJacobi(0, 1, leftEigenvectors, matrix)
|
|
956
|
+
+ this.applySymmetricJacobi(0, 2, leftEigenvectors, matrix)
|
|
957
|
+
+ this.applySymmetricJacobi(1, 2, leftEigenvectors, matrix);
|
|
958
|
+
if (sum < tolerance) {
|
|
959
|
+
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
960
|
+
return true;
|
|
961
|
+
}
|
|
962
|
+
}
|
|
963
|
+
return false;
|
|
964
|
+
}
|
|
965
|
+
/**
|
|
966
|
+
* Apply (in place) a jacobi eigenvalue algorithm that diagonalize `this` matrix, i.e., zeros out this.at(i,j).
|
|
967
|
+
* * During diagonalization, the upper triangle is mirrored to lower triangle to enforce symmetry.
|
|
968
|
+
* * Math details can be found at docs/learning/geometry/Matrix.md
|
|
969
|
+
* @param i row index of zeroed member.
|
|
970
|
+
* @param j column index of zeroed member.
|
|
971
|
+
* @param k other row/column index (different from i and j).
|
|
972
|
+
* @param leftEigenVectors a matrix that its columns will be filled by the left eigenvectors of `this` Matrix3d
|
|
973
|
+
* (allocated by caller, computed and filled by this function). Note that columns of leftEigenVectors will be
|
|
974
|
+
* mutually perpendicular because `this` matrix is symmetric.
|
|
975
|
+
*/
|
|
976
|
+
applyFastSymmetricJacobi(i, j, k, leftEigenVectors) {
|
|
977
|
+
const indexII = 4 * i;
|
|
978
|
+
const indexJJ = 4 * j;
|
|
979
|
+
const indexIJ = 3 * i + j;
|
|
980
|
+
const indexJI = 3 * j + i;
|
|
981
|
+
const indexIK = 3 * i + k;
|
|
982
|
+
const indexKI = 3 * k + i;
|
|
983
|
+
const indexJK = 3 * j + k;
|
|
984
|
+
const indexKJ = 3 * k + j;
|
|
985
|
+
const sii = this.coffs[indexII];
|
|
986
|
+
const sjj = this.coffs[indexJJ];
|
|
987
|
+
const sij = this.coffs[indexIJ];
|
|
988
|
+
if (Math.abs(sij) < 1.0e-15 * (sii + sjj))
|
|
989
|
+
return 0.0;
|
|
990
|
+
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(sii - sjj, 2.0 * sij);
|
|
991
|
+
const c = jacobi.c;
|
|
992
|
+
const s = jacobi.s;
|
|
993
|
+
const cc = c * c;
|
|
994
|
+
const ss = s * s;
|
|
995
|
+
const sc2 = 2.0 * c * s;
|
|
996
|
+
this.coffs[indexII] = cc * sii + sc2 * sij + ss * sjj;
|
|
997
|
+
this.coffs[indexJJ] = ss * sii - sc2 * sij + cc * sjj;
|
|
998
|
+
this.coffs[indexIJ] = 0.0;
|
|
999
|
+
this.coffs[indexJI] = 0.0;
|
|
1000
|
+
const a = this.coffs[indexIK];
|
|
1001
|
+
const b = this.coffs[indexJK];
|
|
1002
|
+
this.coffs[indexIK] = c * a + s * b;
|
|
1003
|
+
this.coffs[indexJK] = -s * a + c * b;
|
|
1004
|
+
this.coffs[indexKI] = this.coffs[indexIK];
|
|
1005
|
+
this.coffs[indexKJ] = this.coffs[indexJK];
|
|
1006
|
+
leftEigenVectors.applyGivensColumnOp(i, j, c, s);
|
|
1007
|
+
return Math.abs(sij);
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Factor `this` matrix as a product `U * lambda * UT` where `U` is an orthogonal matrix and `lambda`
|
|
1011
|
+
* is a diagonal matrix.
|
|
1012
|
+
*
|
|
1013
|
+
* * **Note:** You must apply this function to a `symmetric` matrix. Otherwise, the lower triangle is ignored
|
|
1014
|
+
* and the upper triangle is mirrored to the lower triangle to enforce symmetry.
|
|
1015
|
+
* * Math details can be found at docs/learning/geometry/Matrix.md
|
|
1016
|
+
* @param leftEigenvectors a matrix that its columns will be filled by the left eigenvectors of `this` Matrix3d
|
|
1017
|
+
* (allocated by caller, computed and filled by this function). Note that columns of leftEigenVectors will be
|
|
1018
|
+
* mutually perpendicular because `this` matrix is symmetric.
|
|
1019
|
+
* @param lambda a vector that its entries will be filled by eigenvalues of `this` Matrix3d (allocated by
|
|
1020
|
+
* caller, computed and filled by this function).
|
|
1021
|
+
*/
|
|
1022
|
+
fastSymmetricEigenvalues(leftEigenvectors, lambda) {
|
|
1023
|
+
const matrix = this.clone();
|
|
1024
|
+
leftEigenvectors.setIdentity();
|
|
1025
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1026
|
+
const numberOfIterations = 7;
|
|
1027
|
+
for (let iteration = 0; iteration < numberOfIterations; iteration++) {
|
|
1028
|
+
const sum = matrix.applyFastSymmetricJacobi(0, 1, 2, leftEigenvectors)
|
|
1029
|
+
+ matrix.applyFastSymmetricJacobi(0, 2, 1, leftEigenvectors)
|
|
1030
|
+
+ matrix.applyFastSymmetricJacobi(1, 2, 0, leftEigenvectors);
|
|
1031
|
+
if (sum < tolerance) {
|
|
1032
|
+
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
1033
|
+
return true;
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
return false;
|
|
1037
|
+
}
|
|
1038
|
+
/**
|
|
1039
|
+
* Compute the (unit vector) axis and angle for the rotation generated by `this` Matrix3d.
|
|
1040
|
+
* * Math details can be found at docs/learning/geometry/Angle.md
|
|
906
1041
|
* @returns Returns axis and angle of rotation with result.ok === true when the conversion succeeded.
|
|
907
1042
|
*/
|
|
908
1043
|
getAxisAndAngleOfRotation() {
|
|
909
1044
|
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;
|
|
1045
|
+
const skewXY = this.coffs[3] - this.coffs[1]; // 2*z*sin
|
|
1046
|
+
const skewYZ = this.coffs[7] - this.coffs[5]; // 2*y*sin
|
|
1047
|
+
const skewZX = this.coffs[2] - this.coffs[6]; // 2*x*sin
|
|
1048
|
+
// trace = (m00^2 + m11^2 + m22^2) * (1-cos) + 3cos = (1-cos) + 3cos = 1 + 2cos ==> cos = (trace-1) / 2
|
|
1049
|
+
const c = (trace - 1.0) / 2.0; // cosine
|
|
1050
|
+
const s = Geometry_1.Geometry.hypotenuseXYZ(skewXY, skewYZ, skewZX) / 2.0; // sine
|
|
1051
|
+
const e = c * c + s * s - 1.0; // s^2 + c^2 = 1
|
|
1052
|
+
// if s^2 + c^2 != 1 then we have a bad matrix so return false
|
|
917
1053
|
if (Math.abs(e) > Geometry_1.Geometry.smallAngleRadians) {
|
|
918
|
-
// the sine and cosine are not a unit circle point. bad matrix . ..
|
|
919
1054
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
920
1055
|
}
|
|
1056
|
+
// sin is close to 0 then we got to special cases (angle 0 or 180) which needs to be handled differently
|
|
921
1057
|
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
|
|
1058
|
+
if (c > 0) // sin = 0 and cos = 1 so angle = 0 (i.e., no rotation)
|
|
926
1059
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: true };
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1060
|
+
/**
|
|
1061
|
+
* If sin = 0 and cos = -1 then angle = 180 (i.e., 180 degree rotation around some axis)
|
|
1062
|
+
* then the rotation matrix becomes
|
|
1063
|
+
* 2x^2-1 2xy 2xz
|
|
1064
|
+
* 2xy 2y^2-1 2yz
|
|
1065
|
+
* 2xz 2yz 2z^2-1
|
|
1066
|
+
* Note that the matrix is "symmetric".
|
|
1067
|
+
* If rotation is around one the standard basis then non-diagonal entries become 0 and we
|
|
1068
|
+
* have one 1 and two -1s on the diagonal.
|
|
1069
|
+
* If rotation is around an axis other than standard basis, then the axis is the eigenvector
|
|
1070
|
+
* of the rotation matrix with eigenvalue = 1.
|
|
1071
|
+
*/
|
|
930
1072
|
const axx = this.coffs[0];
|
|
931
1073
|
const ayy = this.coffs[4];
|
|
932
1074
|
const azz = this.coffs[8];
|
|
933
|
-
|
|
934
|
-
// Look for principal axis flips as a special case . ..
|
|
1075
|
+
// Look for a pair of "-1" entries on the diagonal (for rotation around the basis X,Y,Z axis)
|
|
935
1076
|
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 };
|
|
1077
|
+
return { axis: Point3dVector3d_1.Vector3d.create(1, 0, 0), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
938
1078
|
}
|
|
939
1079
|
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:
|
|
1080
|
+
return { axis: Point3dVector3d_1.Vector3d.create(0, 1, 0), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
941
1081
|
}
|
|
942
1082
|
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:
|
|
1083
|
+
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
944
1084
|
}
|
|
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.
|
|
1085
|
+
// Look for eigenvector with eigenvalue = 1
|
|
950
1086
|
const eigenvectors = Matrix3d.createIdentity();
|
|
951
1087
|
const eigenvalues = Point3dVector3d_1.Vector3d.create(0, 0, 0);
|
|
952
|
-
if (this.fastSymmetricEigenvalues(eigenvectors, eigenvalues)) {
|
|
1088
|
+
if (this.fastSymmetricEigenvalues(eigenvectors, eigenvalues)) { // note: this matrix is "symmetric"
|
|
953
1089
|
for (let axisIndex = 0; axisIndex < 2; axisIndex++) {
|
|
954
1090
|
const lambda = eigenvalues.at(axisIndex);
|
|
955
1091
|
if (Geometry_1.Geometry.isAlmostEqualNumber(1, lambda))
|
|
956
|
-
return { axis: eigenvectors.getColumn(axisIndex), angle:
|
|
1092
|
+
return { axis: eigenvectors.getColumn(axisIndex), angle: Angle_1.Angle.createDegrees(180), ok: true };
|
|
957
1093
|
}
|
|
958
|
-
//
|
|
1094
|
+
// if no eigenvalue = 1 was found return false
|
|
959
1095
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
960
1096
|
}
|
|
1097
|
+
// if no axis was found return false
|
|
961
1098
|
return { axis: Point3dVector3d_1.Vector3d.create(0, 0, 1), angle: Angle_1.Angle.createRadians(0), ok: false };
|
|
962
1099
|
}
|
|
1100
|
+
// good matrix and non-zero sine
|
|
963
1101
|
const a = 1.0 / (2.0 * s);
|
|
964
|
-
const result = {
|
|
1102
|
+
const result = {
|
|
1103
|
+
axis: Point3dVector3d_1.Vector3d.create(skewYZ * a, skewZX * a, skewXY * a),
|
|
1104
|
+
angle: Angle_1.Angle.createAtan2(s, c),
|
|
1105
|
+
ok: true,
|
|
1106
|
+
};
|
|
965
1107
|
return result;
|
|
966
1108
|
}
|
|
967
1109
|
/**
|
|
968
|
-
*
|
|
1110
|
+
* Rotate columns i and j of `this` matrix to make them perpendicular using the angle that zero-out
|
|
1111
|
+
* `thisTranspose * this`.
|
|
1112
|
+
* @param i row index of zeroed member.
|
|
1113
|
+
* @param j column index of zeroed member.
|
|
1114
|
+
* @param matrixU a matrix that its columns will be filled by the right eigenvectors of `thisTranspose * this`
|
|
1115
|
+
* (allocated by caller, computed and filled by this function). Note that columns of matrixU will be mutually
|
|
1116
|
+
* perpendicular because `thisTranspose * this` matrix is symmetric.
|
|
969
1117
|
*/
|
|
970
|
-
|
|
971
|
-
|
|
1118
|
+
applyJacobiColumnRotation(i, j, matrixU) {
|
|
1119
|
+
const uDotU = this.coffs[i] * this.coffs[i]
|
|
1120
|
+
+ this.coffs[i + 3] * this.coffs[i + 3]
|
|
1121
|
+
+ this.coffs[i + 6] * this.coffs[i + 6];
|
|
1122
|
+
const vDotV = this.coffs[j] * this.coffs[j]
|
|
1123
|
+
+ this.coffs[j + 3] * this.coffs[j + 3]
|
|
1124
|
+
+ this.coffs[j + 6] * this.coffs[j + 6];
|
|
1125
|
+
const uDotV = this.coffs[i] * this.coffs[j]
|
|
1126
|
+
+ this.coffs[i + 3] * this.coffs[j + 3]
|
|
1127
|
+
+ this.coffs[i + 6] * this.coffs[j + 6];
|
|
1128
|
+
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(uDotU - vDotV, 2.0 * uDotV);
|
|
1129
|
+
const c = jacobi.c;
|
|
1130
|
+
const s = jacobi.s;
|
|
1131
|
+
if (Math.abs(s) < 2.0e-15)
|
|
1132
|
+
return 0.0;
|
|
1133
|
+
this.applyGivensColumnOp(i, j, c, s); // make columns i and j of `this` matrix perpendicular
|
|
1134
|
+
matrixU.applyGivensRowOp(i, j, c, s); // right eigenvalues of `thisTranspose * this`
|
|
1135
|
+
return Math.abs(uDotV);
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Factor `this` matrix as a product `VD * U` where `VD` has mutually perpendicular columns and `U` is orthogonal.
|
|
1139
|
+
* @param matrixVD a matrix that its columns will be filled by rotating columns of `this` to make them mutually
|
|
1140
|
+
* perpendicular (allocated by caller, computed and filled by this function).
|
|
1141
|
+
* @param matrixU a matrix that its columns will be filled by the right eigenvectors of `thisTranspose * this`
|
|
1142
|
+
* (allocated by caller, computed and filled by this function). Note that columns of matrixU will be mutually
|
|
1143
|
+
* perpendicular because `thisTranspose * this` matrix is symmetric.
|
|
1144
|
+
*/
|
|
1145
|
+
factorPerpendicularColumns(matrixVD, matrixU) {
|
|
1146
|
+
matrixVD.setFrom(this);
|
|
1147
|
+
matrixU.setIdentity();
|
|
1148
|
+
const tolerance = 1.0e-12 * this.sumSquares();
|
|
1149
|
+
const numberOfIterations = 7;
|
|
1150
|
+
for (let iteration = 0; iteration < numberOfIterations; iteration++) {
|
|
1151
|
+
const sum = matrixVD.applyJacobiColumnRotation(0, 1, matrixU)
|
|
1152
|
+
+ matrixVD.applyJacobiColumnRotation(0, 2, matrixU)
|
|
1153
|
+
+ matrixVD.applyJacobiColumnRotation(1, 2, matrixU);
|
|
1154
|
+
if (sum < tolerance) {
|
|
1155
|
+
return true;
|
|
1156
|
+
}
|
|
1157
|
+
}
|
|
1158
|
+
return false;
|
|
1159
|
+
}
|
|
1160
|
+
/**
|
|
1161
|
+
* Factor `this` matrix as a product `V * D * U` where `V` and `U` are orthogonal and `D` is diagonal with
|
|
1162
|
+
* positive entries.
|
|
1163
|
+
* * This is formally known as the `Singular Value Decomposition` or `SVD`.
|
|
1164
|
+
* @param matrixV an orthogonal matrix that its columns will be filled by the left eigenvectors of
|
|
1165
|
+
* `thisTranspose * this` (allocated by caller, computed and filled by this function).
|
|
1166
|
+
* @param scale singular values of `this` (allocated by caller, computed and filled by this function).
|
|
1167
|
+
* The singular values in the `scale` are non-negative and decreasing.
|
|
1168
|
+
* @param matrixU an orthogonal matrix that its columns will be filled by the right eigenvectors of
|
|
1169
|
+
* `thisTranspose * this` (allocated by caller, computed and filled by this function).
|
|
1170
|
+
*/
|
|
1171
|
+
factorOrthogonalScaleOrthogonal(matrixV, scale, matrixU) {
|
|
1172
|
+
const matrixVD = Matrix3d.createZero();
|
|
1173
|
+
if (!this.factorPerpendicularColumns(matrixVD, matrixU))
|
|
1174
|
+
return false;
|
|
1175
|
+
const column = [];
|
|
1176
|
+
column.push(matrixVD.getColumn(0));
|
|
1177
|
+
column.push(matrixVD.getColumn(1));
|
|
1178
|
+
column.push(matrixVD.getColumn(2));
|
|
1179
|
+
scale.set(column[0].magnitude(), column[1].magnitude(), column[2].magnitude()); // singular values of `this`
|
|
1180
|
+
const det = matrixVD.determinant();
|
|
1181
|
+
if (det < 0)
|
|
1182
|
+
scale.z = -scale.z;
|
|
1183
|
+
const almostZero = 1.0e-15;
|
|
1184
|
+
const scaleXIsZero = Math.abs(scale.x) < almostZero;
|
|
1185
|
+
const scaleYIsZero = Math.abs(scale.y) < almostZero;
|
|
1186
|
+
const scaleZIsZero = Math.abs(scale.z) < almostZero;
|
|
1187
|
+
// NOTE: We assume any zero-magnitude column(s) of matrixVD are last
|
|
1188
|
+
if (!scaleXIsZero && !scaleYIsZero && !scaleZIsZero) { // full rank
|
|
1189
|
+
matrixV = matrixVD.scaleColumns(1 / scale.x, 1 / scale.y, 1 / scale.z, matrixV);
|
|
1190
|
+
}
|
|
1191
|
+
else if (!scaleXIsZero && !scaleYIsZero) { // rank 2
|
|
1192
|
+
column[0].scaleInPlace(1 / scale.x);
|
|
1193
|
+
column[1].scaleInPlace(1 / scale.y);
|
|
1194
|
+
column[2] = column[0].unitCrossProduct(column[1], column[2]);
|
|
1195
|
+
matrixV.setColumns(column[0], column[1], column[2]);
|
|
1196
|
+
}
|
|
1197
|
+
else if (!scaleXIsZero) { // rank 1
|
|
1198
|
+
matrixV = Matrix3d.createRigidHeadsUp(column[0], Geometry_1.AxisOrder.XYZ, matrixV); // preserve column0
|
|
1199
|
+
}
|
|
1200
|
+
else { // rank 0
|
|
1201
|
+
matrixV.setIdentity();
|
|
1202
|
+
}
|
|
1203
|
+
return true;
|
|
972
1204
|
}
|
|
973
1205
|
/**
|
|
974
1206
|
* Return a matrix that rotates a fraction of the angular sweep from vectorA to vectorB.
|
|
975
1207
|
* @param vectorA initial vector position
|
|
976
|
-
* @param fraction fractional rotation
|
|
1208
|
+
* @param fraction fractional rotation (1 means rotate all the way)
|
|
977
1209
|
* @param vectorB final vector position
|
|
978
1210
|
* @param result optional result matrix.
|
|
979
1211
|
*/
|
|
980
1212
|
static createPartialRotationVectorToVector(vectorA, fraction, vectorB, result) {
|
|
981
1213
|
let upVector = vectorA.unitCrossProduct(vectorB);
|
|
982
|
-
|
|
1214
|
+
// the usual case (both vectors and also their cross product is non-zero)
|
|
1215
|
+
if (upVector) {
|
|
983
1216
|
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * vectorA.planarAngleTo(vectorB, upVector).radians));
|
|
984
1217
|
}
|
|
985
|
-
//
|
|
1218
|
+
// if either vector is zero
|
|
986
1219
|
if (Geometry_1.Geometry.isSmallMetricDistance(vectorA.magnitude())
|
|
987
1220
|
|| Geometry_1.Geometry.isSmallMetricDistance(vectorB.magnitude()))
|
|
988
1221
|
return undefined;
|
|
989
|
-
//
|
|
1222
|
+
// aligned vectors (cross product = 0, dot product > 0)
|
|
990
1223
|
if (vectorA.dotProduct(vectorB) > 0.0)
|
|
991
1224
|
return Matrix3d.createIdentity(result);
|
|
992
|
-
//
|
|
1225
|
+
// opposing vectors (cross product = 0, dot product < 0)
|
|
993
1226
|
upVector = Matrix3d.createPerpendicularVectorFavorPlaneContainingZ(vectorA, upVector);
|
|
994
1227
|
return Matrix3d.createRotationAroundVector(upVector, Angle_1.Angle.createRadians(fraction * Math.PI));
|
|
995
1228
|
}
|
|
1229
|
+
/** Returns a matrix that rotates from vectorA to vectorB. */
|
|
1230
|
+
static createRotationVectorToVector(vectorA, vectorB, result) {
|
|
1231
|
+
return this.createPartialRotationVectorToVector(vectorA, 1.0, vectorB, result);
|
|
1232
|
+
}
|
|
996
1233
|
/** Create a 90 degree rotation around a principal axis */
|
|
997
1234
|
static create90DegreeRotationAroundAxis(axisIndex) {
|
|
998
1235
|
axisIndex = Geometry_1.Geometry.cyclic3dAxis(axisIndex);
|
|
@@ -1013,43 +1250,78 @@ class Matrix3d {
|
|
|
1013
1250
|
}
|
|
1014
1251
|
}
|
|
1015
1252
|
/** Return (a copy of) the X column */
|
|
1016
|
-
columnX(result) {
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
/** Return (a copy of)the
|
|
1020
|
-
|
|
1253
|
+
columnX(result) {
|
|
1254
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[3], this.coffs[6], result);
|
|
1255
|
+
}
|
|
1256
|
+
/** Return (a copy of) the Y column */
|
|
1257
|
+
columnY(result) {
|
|
1258
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[1], this.coffs[4], this.coffs[7], result);
|
|
1259
|
+
}
|
|
1260
|
+
/** Return (a copy of) the Z column */
|
|
1261
|
+
columnZ(result) {
|
|
1262
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[2], this.coffs[5], this.coffs[8], result);
|
|
1263
|
+
}
|
|
1021
1264
|
/** Return the X column magnitude squared */
|
|
1022
|
-
columnXMagnitudeSquared() {
|
|
1265
|
+
columnXMagnitudeSquared() {
|
|
1266
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1267
|
+
}
|
|
1023
1268
|
/** Return the Y column magnitude squared */
|
|
1024
|
-
columnYMagnitudeSquared() {
|
|
1269
|
+
columnYMagnitudeSquared() {
|
|
1270
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1271
|
+
}
|
|
1025
1272
|
/** Return the Z column magnitude squared */
|
|
1026
|
-
columnZMagnitudeSquared() {
|
|
1273
|
+
columnZMagnitudeSquared() {
|
|
1274
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1275
|
+
}
|
|
1027
1276
|
/** Return the X column magnitude */
|
|
1028
|
-
columnXMagnitude() {
|
|
1277
|
+
columnXMagnitude() {
|
|
1278
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6]);
|
|
1279
|
+
}
|
|
1029
1280
|
/** Return the Y column magnitude */
|
|
1030
|
-
columnYMagnitude() {
|
|
1281
|
+
columnYMagnitude() {
|
|
1282
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1283
|
+
}
|
|
1031
1284
|
/** Return the Z column magnitude */
|
|
1032
|
-
columnZMagnitude() {
|
|
1285
|
+
columnZMagnitude() {
|
|
1286
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
1287
|
+
}
|
|
1033
1288
|
/** Return magnitude of columnX cross columnY. */
|
|
1034
1289
|
columnXYCrossProductMagnitude() {
|
|
1035
1290
|
return Geometry_1.Geometry.crossProductMagnitude(this.coffs[0], this.coffs[3], this.coffs[6], this.coffs[1], this.coffs[4], this.coffs[7]);
|
|
1036
1291
|
}
|
|
1037
|
-
/** Return the X row magnitude
|
|
1038
|
-
rowXMagnitude() {
|
|
1292
|
+
/** Return the X row magnitude */
|
|
1293
|
+
rowXMagnitude() {
|
|
1294
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[1], this.coffs[2]);
|
|
1295
|
+
}
|
|
1039
1296
|
/** Return the Y row magnitude */
|
|
1040
|
-
rowYMagnitude() {
|
|
1297
|
+
rowYMagnitude() {
|
|
1298
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[3], this.coffs[4], this.coffs[5]);
|
|
1299
|
+
}
|
|
1041
1300
|
/** Return the Z row magnitude */
|
|
1042
|
-
rowZMagnitude() {
|
|
1043
|
-
|
|
1301
|
+
rowZMagnitude() {
|
|
1302
|
+
return Geometry_1.Geometry.hypotenuseXYZ(this.coffs[6], this.coffs[7], this.coffs[8]);
|
|
1303
|
+
}
|
|
1044
1304
|
/** Return the dot product of column X with column Y */
|
|
1045
1305
|
columnXDotColumnY() {
|
|
1046
1306
|
return this.coffs[0] * this.coffs[1]
|
|
1047
1307
|
+ this.coffs[3] * this.coffs[4]
|
|
1048
1308
|
+ this.coffs[6] * this.coffs[7];
|
|
1049
1309
|
}
|
|
1310
|
+
/** Return the dot product of column X with column Z */
|
|
1311
|
+
columnXDotColumnZ() {
|
|
1312
|
+
return this.coffs[0] * this.coffs[2]
|
|
1313
|
+
+ this.coffs[3] * this.coffs[5]
|
|
1314
|
+
+ this.coffs[6] * this.coffs[8];
|
|
1315
|
+
}
|
|
1316
|
+
/** Return the dot product of column Y with column Z */
|
|
1317
|
+
columnYDotColumnZ() {
|
|
1318
|
+
return this.coffs[1] * this.coffs[2]
|
|
1319
|
+
+ this.coffs[4] * this.coffs[5]
|
|
1320
|
+
+ this.coffs[7] * this.coffs[8];
|
|
1321
|
+
}
|
|
1050
1322
|
/**
|
|
1051
1323
|
* Dot product of an indexed column with a vector given as x,y,z
|
|
1052
|
-
* @param columnIndex index of column.
|
|
1324
|
+
* @param columnIndex index of column. Must be 0,1,2.
|
|
1053
1325
|
* @param x x component of vector
|
|
1054
1326
|
* @param y y component of vector
|
|
1055
1327
|
* @param z z component of vector
|
|
@@ -1058,285 +1330,58 @@ class Matrix3d {
|
|
|
1058
1330
|
return this.coffs[columnIndex] * x + this.coffs[columnIndex + 3] * y + this.coffs[columnIndex + 6] * z;
|
|
1059
1331
|
}
|
|
1060
1332
|
/** Return (a copy of) the X row */
|
|
1061
|
-
rowX(result) {
|
|
1333
|
+
rowX(result) {
|
|
1334
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[0], this.coffs[1], this.coffs[2], result);
|
|
1335
|
+
}
|
|
1062
1336
|
/** Return (a copy of) the Y row */
|
|
1063
|
-
rowY(result) {
|
|
1337
|
+
rowY(result) {
|
|
1338
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[3], this.coffs[4], this.coffs[5], result);
|
|
1339
|
+
}
|
|
1064
1340
|
/** Return (a copy of) the Z row */
|
|
1065
|
-
rowZ(result) {
|
|
1341
|
+
rowZ(result) {
|
|
1342
|
+
return Point3dVector3d_1.Vector3d.create(this.coffs[6], this.coffs[7], this.coffs[8], result);
|
|
1343
|
+
}
|
|
1066
1344
|
/** Return the dot product of the vector parameter with the X column. */
|
|
1067
|
-
dotColumnX(vector) {
|
|
1068
|
-
|
|
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);
|
|
1345
|
+
dotColumnX(vector) {
|
|
1346
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[3] + vector.z * this.coffs[6];
|
|
1088
1347
|
}
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
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
|
-
}
|
|
1348
|
+
/** Return the dot product of the vector parameter with the Y column. */
|
|
1349
|
+
dotColumnY(vector) {
|
|
1350
|
+
return vector.x * this.coffs[1] + vector.y * this.coffs[4] + vector.z * this.coffs[7];
|
|
1106
1351
|
}
|
|
1107
|
-
/**
|
|
1108
|
-
|
|
1109
|
-
|
|
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
|
-
}
|
|
1139
|
-
return result;
|
|
1352
|
+
/** Return the dot product of the vector parameter with the Z column. */
|
|
1353
|
+
dotColumnZ(vector) {
|
|
1354
|
+
return vector.x * this.coffs[2] + vector.y * this.coffs[5] + vector.z * this.coffs[8];
|
|
1140
1355
|
}
|
|
1141
|
-
/**
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
const vDotV = this.coffs[j] * this.coffs[j] + this.coffs[j + 3] * this.coffs[j + 3] + this.coffs[j + 6] * this.coffs[j + 6];
|
|
1145
|
-
const uDotV = this.coffs[i] * this.coffs[j] + this.coffs[i + 3] * this.coffs[j + 3] + this.coffs[i + 6] * this.coffs[j + 6];
|
|
1146
|
-
// const c2 = uDotU - vDotV;
|
|
1147
|
-
// const s2 = 2.0 * uDotV;
|
|
1148
|
-
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(uDotU - vDotV, 2.0 * uDotV);
|
|
1149
|
-
// const h = Math.hypot(c2, s2);
|
|
1150
|
-
// console.log(" c2 s2", c2 / h, s2 / h);
|
|
1151
|
-
// console.log(" C S ", Math.cos(2 * jacobi.radians), Math.sin(2 * jacobi.radians));
|
|
1152
|
-
// console.log("i j uDotV", i, j, uDotV);
|
|
1153
|
-
if (Math.abs(jacobi.s) < 2.0e-15)
|
|
1154
|
-
return 0.0;
|
|
1155
|
-
this.applyGivensColumnOp(i, j, jacobi.c, jacobi.s);
|
|
1156
|
-
matrixU.applyGivensRowOp(i, j, jacobi.c, jacobi.s);
|
|
1157
|
-
// const BTB = this.multiplyMatrixTransposeMatrix(this);
|
|
1158
|
-
// console.log("BTB", BTB.at(0, 0), BTB.at(1, 1), BTB.at(2, 2), " off", BTB.at(0, 1), BTB.at(0, 2), BTB.at(1, 2), " at(i,j)", BTB.at(i, j));
|
|
1159
|
-
return Math.abs(uDotV);
|
|
1356
|
+
/** Return the dot product of the vector parameter with the X row. */
|
|
1357
|
+
dotRowX(vector) {
|
|
1358
|
+
return vector.x * this.coffs[0] + vector.y * this.coffs[1] + vector.z * this.coffs[2];
|
|
1160
1359
|
}
|
|
1161
|
-
/**
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
* @param matrixC (allocate by caller, computed here)
|
|
1165
|
-
* @param matrixU (allocate by caller, computed here)
|
|
1166
|
-
*/
|
|
1167
|
-
factorPerpendicularColumns(matrixC, matrixU) {
|
|
1168
|
-
matrixC.setFrom(this);
|
|
1169
|
-
matrixU.setIdentity();
|
|
1170
|
-
const ss = this.sumSquares();
|
|
1171
|
-
const tolerance = 1.0e-12 * ss;
|
|
1172
|
-
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1173
|
-
const sum = matrixC.applyJacobiColumnRotation(0, 1, matrixU)
|
|
1174
|
-
+ matrixC.applyJacobiColumnRotation(0, 2, matrixU)
|
|
1175
|
-
+ matrixC.applyJacobiColumnRotation(1, 2, matrixU);
|
|
1176
|
-
// console.log (" sum", sum);
|
|
1177
|
-
if (sum < tolerance) {
|
|
1178
|
-
// console.log("jacobi iterations", iteration);
|
|
1179
|
-
return true;
|
|
1180
|
-
}
|
|
1181
|
-
}
|
|
1182
|
-
return false;
|
|
1360
|
+
/** Return the dot product of the vector parameter with the Y row. */
|
|
1361
|
+
dotRowY(vector) {
|
|
1362
|
+
return vector.x * this.coffs[3] + vector.y * this.coffs[4] + vector.z * this.coffs[5];
|
|
1183
1363
|
}
|
|
1184
|
-
/**
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
* @param scale diagonal entries of D (allocate by caller, computed here)
|
|
1188
|
-
* @param matrixU right orthogonal factor (allocate by caller, computed here)
|
|
1189
|
-
*/
|
|
1190
|
-
factorOrthogonalScaleOrthogonal(matrixV, scale, matrixU) {
|
|
1191
|
-
const matrixVD = Matrix3d.createZero();
|
|
1192
|
-
if (!this.factorPerpendicularColumns(matrixVD, matrixU))
|
|
1193
|
-
return false;
|
|
1194
|
-
const column = [];
|
|
1195
|
-
column.push(matrixVD.getColumn(0));
|
|
1196
|
-
column.push(matrixVD.getColumn(1));
|
|
1197
|
-
column.push(matrixVD.getColumn(2));
|
|
1198
|
-
scale.set(column[0].magnitude(), column[1].magnitude(), column[2].magnitude());
|
|
1199
|
-
const det = matrixVD.determinant();
|
|
1200
|
-
if (det < 0)
|
|
1201
|
-
scale.z = -scale.z;
|
|
1202
|
-
const almostZero = 1.0e-15;
|
|
1203
|
-
const scaleXIsZero = Math.abs(scale.x) < almostZero;
|
|
1204
|
-
const scaleYIsZero = Math.abs(scale.y) < almostZero;
|
|
1205
|
-
const scaleZIsZero = Math.abs(scale.z) < almostZero;
|
|
1206
|
-
// ASSUME: any zero-magnitude column(s) of matrixVD are last
|
|
1207
|
-
if (!scaleXIsZero && !scaleYIsZero && !scaleZIsZero) { // full rank
|
|
1208
|
-
matrixV = matrixVD.scaleColumns(1 / scale.x, 1 / scale.y, 1 / scale.z, matrixV);
|
|
1209
|
-
}
|
|
1210
|
-
else if (!scaleXIsZero && !scaleYIsZero) { // rank 2
|
|
1211
|
-
column[0].scaleInPlace(1 / scale.x);
|
|
1212
|
-
column[1].scaleInPlace(1 / scale.y);
|
|
1213
|
-
column[2] = column[0].unitCrossProduct(column[1], column[2]);
|
|
1214
|
-
matrixV.setColumns(column[0], column[1], column[2]);
|
|
1215
|
-
}
|
|
1216
|
-
else if (!scaleXIsZero) { // rank 1
|
|
1217
|
-
matrixV = Matrix3d.createRigidHeadsUp(column[0], Geometry_1.AxisOrder.XYZ, matrixV); // preserve column0
|
|
1218
|
-
}
|
|
1219
|
-
else { // rank 0
|
|
1220
|
-
matrixV.setIdentity();
|
|
1221
|
-
}
|
|
1222
|
-
return true;
|
|
1364
|
+
/** Return the dot product of the vector parameter with the Z row. */
|
|
1365
|
+
dotRowZ(vector) {
|
|
1366
|
+
return vector.x * this.coffs[6] + vector.y * this.coffs[7] + vector.z * this.coffs[8];
|
|
1223
1367
|
}
|
|
1224
|
-
/**
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
const vDotV = lambda.at(j, j);
|
|
1228
|
-
const uDotV = lambda.at(i, j);
|
|
1229
|
-
if (Math.abs(uDotV) < 1.0e-15 * (uDotU + vDotV))
|
|
1230
|
-
return 0.0;
|
|
1231
|
-
// const c2 = uDotU - vDotV;
|
|
1232
|
-
// const s2 = 2.0 * uDotV;
|
|
1233
|
-
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(uDotU - vDotV, 2.0 * uDotV);
|
|
1234
|
-
// const h = Math.hypot(c2, s2);
|
|
1235
|
-
// console.log(" c2 s2", c2 / h, s2 / h);
|
|
1236
|
-
// console.log(" C S ", Math.cos(2 * jacobi.radians), Math.sin(2 * jacobi.radians));
|
|
1237
|
-
// console.log("i j uDotV", i, j, uDotV);
|
|
1238
|
-
if (Math.abs(jacobi.s) < 2.0e-15)
|
|
1239
|
-
return 0.0;
|
|
1240
|
-
// Factored form is this *lambda * thisTranspose
|
|
1241
|
-
// Let Q be the rotation matrix. Q*QT is inserted, viz
|
|
1242
|
-
// this*Q * QT * lambda * Q*thisTranspose
|
|
1243
|
-
this.applyGivensColumnOp(i, j, jacobi.c, jacobi.s);
|
|
1244
|
-
lambda.applyGivensRowOp(i, j, jacobi.c, jacobi.s);
|
|
1245
|
-
lambda.applyGivensColumnOp(i, j, jacobi.c, jacobi.s);
|
|
1246
|
-
// const BTB = this.multiplyMatrixTransposeMatrix(this);
|
|
1247
|
-
// console.log("BTB", BTB.at(0, 0), BTB.at(1, 1), BTB.at(2, 2), " off", BTB.at(0, 1), BTB.at(0, 2), BTB.at(1, 2), " at(i,j)", BTB.at(i, j));
|
|
1248
|
-
return Math.abs(uDotV);
|
|
1368
|
+
/** Return the dot product of the x,y,z with the X row. */
|
|
1369
|
+
dotRowXXYZ(x, y, z) {
|
|
1370
|
+
return x * this.coffs[0] + y * this.coffs[1] + z * this.coffs[2];
|
|
1249
1371
|
}
|
|
1250
|
-
/**
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
* @param matrixC (allocate by caller, computed here)
|
|
1254
|
-
* @param factor (allocate by caller, computed here)
|
|
1255
|
-
*/
|
|
1256
|
-
symmetricEigenvalues(leftEigenvectors, lambda) {
|
|
1257
|
-
const matrix = this.clone();
|
|
1258
|
-
leftEigenvectors.setIdentity();
|
|
1259
|
-
matrix.coffs[3] = matrix.coffs[1];
|
|
1260
|
-
matrix.coffs[6] = matrix.coffs[2];
|
|
1261
|
-
matrix.coffs[7] = matrix.coffs[5];
|
|
1262
|
-
const ss = this.sumSquares();
|
|
1263
|
-
const tolerance = 1.0e-12 * ss;
|
|
1264
|
-
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1265
|
-
const sum = leftEigenvectors.applySymmetricJacobi(0, 1, matrix)
|
|
1266
|
-
+ leftEigenvectors.applySymmetricJacobi(0, 2, matrix)
|
|
1267
|
-
+ leftEigenvectors.applySymmetricJacobi(1, 2, matrix);
|
|
1268
|
-
// console.log("symmetric sum", sum);
|
|
1269
|
-
// console.log (" sum", sum);
|
|
1270
|
-
if (sum < tolerance) {
|
|
1271
|
-
// console.log("symmetric iterations", iteration);
|
|
1272
|
-
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
1273
|
-
return true;
|
|
1274
|
-
}
|
|
1275
|
-
}
|
|
1276
|
-
return false;
|
|
1372
|
+
/** Return the dot product of the x,y,z with the Y row. */
|
|
1373
|
+
dotRowYXYZ(x, y, z) {
|
|
1374
|
+
return x * this.coffs[3] + y * this.coffs[4] + z * this.coffs[5];
|
|
1277
1375
|
}
|
|
1278
|
-
/**
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
applyFastSymmetricJacobiUpdate(i, // row index of zeroed member
|
|
1282
|
-
j, // column index of zeroed member
|
|
1283
|
-
k, // other row/column index (different from i and j)
|
|
1284
|
-
leftEigenVectors) {
|
|
1285
|
-
const indexII = 4 * i;
|
|
1286
|
-
const indexJJ = 4 * j;
|
|
1287
|
-
const indexIJ = 3 * i + j;
|
|
1288
|
-
const indexIK = 3 * i + k;
|
|
1289
|
-
const indexJK = 3 * j + k;
|
|
1290
|
-
const dotUU = this.coffs[indexII];
|
|
1291
|
-
const dotVV = this.coffs[indexJJ];
|
|
1292
|
-
const dotUV = this.coffs[indexIJ];
|
|
1293
|
-
const jacobi = Angle_1.Angle.trigValuesToHalfAngleTrigValues(dotUU - dotVV, 2.0 * dotUV);
|
|
1294
|
-
if (Math.abs(dotUV) < 1.0e-15 * (dotUU + dotVV))
|
|
1295
|
-
return 0.0;
|
|
1296
|
-
const c = jacobi.c;
|
|
1297
|
-
const s = jacobi.s;
|
|
1298
|
-
const cc = c * c;
|
|
1299
|
-
const ss = s * s;
|
|
1300
|
-
const sc2 = 2.0 * c * s;
|
|
1301
|
-
this.coffs[indexII] = cc * dotUU + sc2 * dotUV + ss * dotVV;
|
|
1302
|
-
this.coffs[indexJJ] = ss * dotUU - sc2 * dotUV + cc * dotVV;
|
|
1303
|
-
this.coffs[indexIJ] = 0.0;
|
|
1304
|
-
const a = this.coffs[indexIK];
|
|
1305
|
-
const b = this.coffs[indexJK];
|
|
1306
|
-
this.coffs[indexIK] = a * c + b * s;
|
|
1307
|
-
this.coffs[indexJK] = -s * a + c * b;
|
|
1308
|
-
this.coffs[3 * j + i] = 0.0;
|
|
1309
|
-
this.coffs[3 * k + i] = this.coffs[indexIK];
|
|
1310
|
-
this.coffs[3 * k + j] = this.coffs[indexJK];
|
|
1311
|
-
leftEigenVectors.applyGivensColumnOp(i, j, c, s);
|
|
1312
|
-
return Math.abs(dotUV);
|
|
1376
|
+
/** Return the dot product of the x,y,z with the Z row. */
|
|
1377
|
+
dotRowZXYZ(x, y, z) {
|
|
1378
|
+
return x * this.coffs[6] + y * this.coffs[7] + z * this.coffs[8];
|
|
1313
1379
|
}
|
|
1314
|
-
/**
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
* @param matrixC (allocate by caller, computed here)
|
|
1318
|
-
* @param factor (allocate by caller, computed here)
|
|
1319
|
-
*/
|
|
1320
|
-
fastSymmetricEigenvalues(leftEigenvectors, lambda) {
|
|
1321
|
-
const matrix = this.clone();
|
|
1322
|
-
leftEigenvectors.setIdentity();
|
|
1323
|
-
const ss = this.sumSquares();
|
|
1324
|
-
const tolerance = 1.0e-12 * ss;
|
|
1325
|
-
for (let iteration = 0; iteration < 7; iteration++) {
|
|
1326
|
-
const sum = matrix.applyFastSymmetricJacobiUpdate(0, 1, 2, leftEigenvectors)
|
|
1327
|
-
+ matrix.applyFastSymmetricJacobiUpdate(0, 2, 1, leftEigenvectors)
|
|
1328
|
-
+ matrix.applyFastSymmetricJacobiUpdate(1, 2, 0, leftEigenvectors);
|
|
1329
|
-
// console.log("symmetric sum", sum);
|
|
1330
|
-
// console.log (" sum", sum);
|
|
1331
|
-
if (sum < tolerance) {
|
|
1332
|
-
// console.log("symmetric iterations", iteration);
|
|
1333
|
-
lambda.set(matrix.at(0, 0), matrix.at(1, 1), matrix.at(2, 2));
|
|
1334
|
-
return true;
|
|
1335
|
-
}
|
|
1336
|
-
}
|
|
1337
|
-
return false;
|
|
1380
|
+
/** Return the cross product of the Z column with the vector parameter. */
|
|
1381
|
+
columnZCrossVector(vector, result) {
|
|
1382
|
+
return Geometry_1.Geometry.crossProductXYZXYZ(this.coffs[2], this.coffs[5], this.coffs[8], vector.x, vector.y, vector.z, result);
|
|
1338
1383
|
}
|
|
1339
|
-
/**
|
|
1384
|
+
/** Set data from xyz parts of Point4d (w part of Point4d ignored) */
|
|
1340
1385
|
setColumnsPoint4dXYZ(vectorU, vectorV, vectorW) {
|
|
1341
1386
|
this.inverseState = InverseMatrixState.unknown;
|
|
1342
1387
|
this.setRowValues(vectorU.x, vectorV.x, vectorW.x, vectorU.y, vectorV.y, vectorW.y, vectorU.z, vectorV.z, vectorW.z);
|
|
@@ -1360,16 +1405,22 @@ class Matrix3d {
|
|
|
1360
1405
|
this.coffs[index + 6] = 0.0;
|
|
1361
1406
|
}
|
|
1362
1407
|
}
|
|
1363
|
-
/**
|
|
1408
|
+
/**
|
|
1409
|
+
* Set all columns of the matrix. Any undefined vector is zeros.
|
|
1410
|
+
* @param vectorX values for column 0
|
|
1411
|
+
* @param vectorY values for column 1
|
|
1412
|
+
* @param vectorZ optional values for column 2 (it's optional in case column 2 is 000, which is a
|
|
1413
|
+
* projection onto the xy-plane)
|
|
1414
|
+
*/
|
|
1364
1415
|
setColumns(vectorX, vectorY, vectorZ) {
|
|
1365
1416
|
this.setColumn(0, vectorX);
|
|
1366
1417
|
this.setColumn(1, vectorY);
|
|
1367
1418
|
this.setColumn(2, vectorZ);
|
|
1368
1419
|
}
|
|
1369
1420
|
/**
|
|
1370
|
-
*
|
|
1371
|
-
* @param rowIndex row index.
|
|
1372
|
-
* @param value x,
|
|
1421
|
+
* Set entries in one row of the matrix.
|
|
1422
|
+
* @param rowIndex row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1423
|
+
* @param value x,y,z values for row.
|
|
1373
1424
|
*/
|
|
1374
1425
|
setRow(rowIndex, value) {
|
|
1375
1426
|
const index = 3 * Geometry_1.Geometry.cyclic3dAxis(rowIndex);
|
|
@@ -1378,21 +1429,26 @@ class Matrix3d {
|
|
|
1378
1429
|
this.coffs[index + 2] = value.z;
|
|
1379
1430
|
this.inverseState = InverseMatrixState.unknown;
|
|
1380
1431
|
}
|
|
1381
|
-
/**
|
|
1382
|
-
*
|
|
1432
|
+
/**
|
|
1433
|
+
* Return (a copy of) a column of the matrix.
|
|
1434
|
+
* @param i column index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1435
|
+
* @param result optional preallocated result.
|
|
1383
1436
|
*/
|
|
1384
1437
|
getColumn(columnIndex, result) {
|
|
1385
1438
|
const index = Geometry_1.Geometry.cyclic3dAxis(columnIndex);
|
|
1386
1439
|
return Point3dVector3d_1.Vector3d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], result);
|
|
1387
1440
|
}
|
|
1388
|
-
/**
|
|
1389
|
-
*
|
|
1441
|
+
/**
|
|
1442
|
+
* Return a (copy of) a row of the matrix.
|
|
1443
|
+
* @param i row index. This is interpreted cyclically (using Geometry.cyclic3dAxis).
|
|
1444
|
+
* @param result optional preallocated result.
|
|
1390
1445
|
*/
|
|
1391
1446
|
getRow(columnIndex, result) {
|
|
1392
1447
|
const index = 3 * Geometry_1.Geometry.cyclic3dAxis(columnIndex);
|
|
1393
1448
|
return Point3dVector3d_1.Vector3d.create(this.coffs[index], this.coffs[index + 1], this.coffs[index + 2], result);
|
|
1394
1449
|
}
|
|
1395
|
-
/**
|
|
1450
|
+
/**
|
|
1451
|
+
* Create a matrix from row vectors.
|
|
1396
1452
|
* ```
|
|
1397
1453
|
* equation
|
|
1398
1454
|
* \begin{bmatrix}U_x & U_y & U_z \\ V_x & V_y & V_z \\ W_x & W_y & W_z \end{bmatrix}
|
|
@@ -1401,14 +1457,20 @@ class Matrix3d {
|
|
|
1401
1457
|
static createRows(vectorU, vectorV, vectorW, result) {
|
|
1402
1458
|
return Matrix3d.createRowValues(vectorU.x, vectorU.y, vectorU.z, vectorV.x, vectorV.y, vectorV.z, vectorW.x, vectorW.y, vectorW.z, result);
|
|
1403
1459
|
}
|
|
1404
|
-
/**
|
|
1405
|
-
*
|
|
1406
|
-
*
|
|
1460
|
+
/**
|
|
1461
|
+
* Create a matrix that scales along a specified `direction`. This means if you multiply the returned matrix
|
|
1462
|
+
* by a `vector`, you get `directional scale` of that `vector`. Suppose `plane` is the plane perpendicular
|
|
1463
|
+
* to the `direction`. When scale = 0, `directional scale` is projection of the `vector` to the `plane`.
|
|
1464
|
+
* When scale = 1, `directional scale` is the `vector` itself. When scale = -1, `directional scale` is
|
|
1465
|
+
* mirror of the `vector` across the `plane`. In general, When scale != 0, the result is computed by first
|
|
1466
|
+
* projecting the `vector` to the `plane`, then translating that projection along the `direction` (if scale > 0)
|
|
1467
|
+
* or in opposite direction (if scale < 0).
|
|
1407
1468
|
* ```
|
|
1408
1469
|
* equation
|
|
1409
|
-
* \text{The matrix is } I
|
|
1410
|
-
* \\ \text{with }
|
|
1470
|
+
* \text{The matrix is } I + (s-1) D D^T
|
|
1471
|
+
* \\ \text{with }D\text{ being the normalized direction vector and }s\text{ being the scale.}
|
|
1411
1472
|
* ```
|
|
1473
|
+
* * Visualization can be found at itwinjs.org/sandbox/SaeedTorabi/DirectionalScale
|
|
1412
1474
|
*/
|
|
1413
1475
|
static createDirectionalScale(direction, scale, result) {
|
|
1414
1476
|
const unit = direction.normalize();
|
|
@@ -1416,19 +1478,13 @@ class Matrix3d {
|
|
|
1416
1478
|
const x = unit.x;
|
|
1417
1479
|
const y = unit.y;
|
|
1418
1480
|
const z = unit.z;
|
|
1419
|
-
const a =
|
|
1481
|
+
const a = scale - 1;
|
|
1420
1482
|
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
1483
|
}
|
|
1422
1484
|
return Matrix3d.createUniformScale(scale);
|
|
1423
1485
|
}
|
|
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.
|
|
1486
|
+
/**
|
|
1487
|
+
* Multiply `matrix * vector`, treating the vector is a column vector on the right.
|
|
1432
1488
|
* ```
|
|
1433
1489
|
* equation
|
|
1434
1490
|
* \matrixXY{A}\columnSubXYZ{U}
|
|
@@ -1439,36 +1495,38 @@ class Matrix3d {
|
|
|
1439
1495
|
const x = vectorU.x;
|
|
1440
1496
|
const y = vectorU.y;
|
|
1441
1497
|
const z = vectorU.z;
|
|
1442
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1498
|
+
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
1499
|
}
|
|
1444
|
-
/**
|
|
1445
|
-
*
|
|
1500
|
+
/**
|
|
1501
|
+
* Multiply `matrix * vector` in place for vector in the array, i.e. treating the vector is a column
|
|
1502
|
+
* vector on the right.
|
|
1503
|
+
* * Each `vector` is updated to be `matrix * vector`
|
|
1446
1504
|
*/
|
|
1447
1505
|
multiplyVectorArrayInPlace(data) {
|
|
1448
1506
|
for (const v of data)
|
|
1449
|
-
v.set(
|
|
1507
|
+
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
1508
|
}
|
|
1451
|
-
/**
|
|
1509
|
+
/** Compute `origin - matrix * vector` */
|
|
1452
1510
|
static xyzMinusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1453
1511
|
const x = vector.x;
|
|
1454
1512
|
const y = vector.y;
|
|
1455
1513
|
const z = vector.z;
|
|
1456
1514
|
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
1515
|
}
|
|
1458
|
-
/**
|
|
1516
|
+
/** Compute `origin + matrix * vector` using only the xy parts of the inputs. */
|
|
1459
1517
|
static xyPlusMatrixTimesXY(origin, matrix, vector, result) {
|
|
1460
1518
|
const x = vector.x;
|
|
1461
1519
|
const y = vector.y;
|
|
1462
1520
|
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
1521
|
}
|
|
1464
|
-
/**
|
|
1522
|
+
/** Compute `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1465
1523
|
static xyzPlusMatrixTimesXYZ(origin, matrix, vector, result) {
|
|
1466
1524
|
const x = vector.x;
|
|
1467
1525
|
const y = vector.y;
|
|
1468
1526
|
const z = vector.z;
|
|
1469
1527
|
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
1528
|
}
|
|
1471
|
-
/**
|
|
1529
|
+
/** Updates vector to be `origin + matrix * vector` using all xyz parts of the inputs. */
|
|
1472
1530
|
static xyzPlusMatrixTimesXYZInPlace(origin, matrix, vector) {
|
|
1473
1531
|
const x = vector.x;
|
|
1474
1532
|
const y = vector.y;
|
|
@@ -1477,65 +1535,76 @@ class Matrix3d {
|
|
|
1477
1535
|
vector.y = origin.y + matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z;
|
|
1478
1536
|
vector.z = origin.z + matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z;
|
|
1479
1537
|
}
|
|
1480
|
-
/**
|
|
1538
|
+
/** Compute `origin + matrix * vector` where the final vector is given as direct x,y,z coordinates */
|
|
1481
1539
|
static xyzPlusMatrixTimesCoordinates(origin, matrix, x, y, z, result) {
|
|
1482
1540
|
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
1541
|
}
|
|
1484
1542
|
/**
|
|
1485
1543
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1486
|
-
* Multiply
|
|
1544
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1545
|
+
* ```
|
|
1546
|
+
* equation
|
|
1547
|
+
* \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}
|
|
1548
|
+
* ```
|
|
1487
1549
|
* @param origin translation part (xyz in column 3)
|
|
1488
1550
|
* @param matrix matrix part (leading 3x3)
|
|
1489
1551
|
* @param x x part of multiplied point
|
|
1490
1552
|
* @param y y part of multiplied point
|
|
1491
1553
|
* @param z z part of multiplied point
|
|
1492
1554
|
* @param w w part of multiplied point
|
|
1493
|
-
* @param result optional result.
|
|
1555
|
+
* @param result optional preallocated result.
|
|
1494
1556
|
*/
|
|
1495
1557
|
static xyzPlusMatrixTimesWeightedCoordinates(origin, matrix, x, y, z, w, result) {
|
|
1496
|
-
return Point4d_1.Point4d.create(
|
|
1558
|
+
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
1559
|
}
|
|
1498
1560
|
/**
|
|
1499
1561
|
* Treat the 3x3 matrix and origin as upper 3x4 part of a 4x4 matrix, with 0001 as the final row.
|
|
1500
|
-
* Multiply
|
|
1562
|
+
* Multiply the 4x4 matrix by `[x,y,z,w]`
|
|
1563
|
+
* ```
|
|
1564
|
+
* equation
|
|
1565
|
+
* \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}
|
|
1566
|
+
* ```
|
|
1501
1567
|
* @param origin translation part (xyz in column 3)
|
|
1502
1568
|
* @param matrix matrix part (leading 3x3)
|
|
1503
1569
|
* @param x x part of multiplied point
|
|
1504
1570
|
* @param y y part of multiplied point
|
|
1505
1571
|
* @param z z part of multiplied point
|
|
1506
1572
|
* @param w w part of multiplied point
|
|
1507
|
-
* @param result optional result.
|
|
1573
|
+
* @param result optional preallocated result.
|
|
1508
1574
|
*/
|
|
1509
1575
|
static xyzPlusMatrixTimesWeightedCoordinatesToFloat64Array(origin, matrix, x, y, z, w, result) {
|
|
1510
1576
|
if (!result)
|
|
1511
1577
|
result = new Float64Array(4);
|
|
1512
|
-
result[0] =
|
|
1513
|
-
result[1] =
|
|
1514
|
-
result[2] =
|
|
1578
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x * w;
|
|
1579
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y * w;
|
|
1580
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z * w;
|
|
1515
1581
|
result[3] = w;
|
|
1516
1582
|
return result;
|
|
1517
1583
|
}
|
|
1518
1584
|
/**
|
|
1519
|
-
* Treat the 3x3 matrix and origin as
|
|
1520
|
-
* Multiply
|
|
1585
|
+
* Treat the 3x3 matrix and origin as a 3x4 matrix.
|
|
1586
|
+
* * Multiply the 3x4 matrix by `[x,y,z,1]`
|
|
1587
|
+
* ```
|
|
1588
|
+
* equation
|
|
1589
|
+
* \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}
|
|
1590
|
+
* ```
|
|
1521
1591
|
* @param origin translation part (xyz in column 3)
|
|
1522
1592
|
* @param matrix matrix part (leading 3x3)
|
|
1523
1593
|
* @param x x part of multiplied point
|
|
1524
1594
|
* @param y y part of multiplied point
|
|
1525
1595
|
* @param z z part of multiplied point
|
|
1526
|
-
* @param
|
|
1527
|
-
* @param result optional result.
|
|
1596
|
+
* @param result optional preallocated result.
|
|
1528
1597
|
*/
|
|
1529
1598
|
static xyzPlusMatrixTimesCoordinatesToFloat64Array(origin, matrix, x, y, z, result) {
|
|
1530
1599
|
if (!result)
|
|
1531
1600
|
result = new Float64Array(3);
|
|
1532
|
-
result[0] =
|
|
1533
|
-
result[1] =
|
|
1534
|
-
result[2] =
|
|
1601
|
+
result[0] = matrix.coffs[0] * x + matrix.coffs[1] * y + matrix.coffs[2] * z + origin.x;
|
|
1602
|
+
result[1] = matrix.coffs[3] * x + matrix.coffs[4] * y + matrix.coffs[5] * z + origin.y;
|
|
1603
|
+
result[2] = matrix.coffs[6] * x + matrix.coffs[7] * y + matrix.coffs[8] * z + origin.z;
|
|
1535
1604
|
return result;
|
|
1536
1605
|
}
|
|
1537
1606
|
/**
|
|
1538
|
-
* Multiply transpose
|
|
1607
|
+
* Multiply the transpose matrix times a vector.
|
|
1539
1608
|
* * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
|
|
1540
1609
|
* ```
|
|
1541
1610
|
* equation
|
|
@@ -1544,99 +1613,112 @@ class Matrix3d {
|
|
|
1544
1613
|
* \text{Treating U as a row to the left of untransposed matrix\: return row}&\rowSubXYZ{V}&=&\rowSubXYZ{U}\matrixXY{A}
|
|
1545
1614
|
* \end{matrix}
|
|
1546
1615
|
* ```
|
|
1547
|
-
* @
|
|
1616
|
+
* @param result the vector result (optional)
|
|
1548
1617
|
*/
|
|
1549
1618
|
multiplyTransposeVector(vector, result) {
|
|
1550
1619
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1551
1620
|
const x = vector.x;
|
|
1552
1621
|
const y = vector.y;
|
|
1553
1622
|
const z = vector.z;
|
|
1554
|
-
result.x =
|
|
1555
|
-
result.y =
|
|
1556
|
-
result.z =
|
|
1623
|
+
result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1624
|
+
result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1625
|
+
result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1557
1626
|
return result;
|
|
1558
1627
|
}
|
|
1559
|
-
/**
|
|
1560
|
-
*
|
|
1628
|
+
/**
|
|
1629
|
+
* Multiply the matrix * [x,y,z], i.e. the vector [x,y,z] is a column vector on the right.
|
|
1630
|
+
* @param result the vector result (optional)
|
|
1561
1631
|
*/
|
|
1562
1632
|
multiplyXYZ(x, y, z, result) {
|
|
1563
1633
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1564
|
-
result.x =
|
|
1565
|
-
result.y =
|
|
1566
|
-
result.z =
|
|
1634
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1635
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1636
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1567
1637
|
return result;
|
|
1568
1638
|
}
|
|
1569
|
-
/**
|
|
1570
|
-
*
|
|
1571
|
-
*
|
|
1639
|
+
/**
|
|
1640
|
+
* Multiply the matrix * xyz, place result in (required) return value.
|
|
1641
|
+
* @param xyz right side
|
|
1642
|
+
* @param result the result.
|
|
1572
1643
|
*/
|
|
1573
1644
|
multiplyXYZtoXYZ(xyz, result) {
|
|
1574
1645
|
const x = xyz.x;
|
|
1575
1646
|
const y = xyz.y;
|
|
1576
1647
|
const z = xyz.z;
|
|
1577
|
-
result.x =
|
|
1578
|
-
result.y =
|
|
1579
|
-
result.z =
|
|
1648
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1649
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1650
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1580
1651
|
return result;
|
|
1581
1652
|
}
|
|
1582
|
-
/**
|
|
1583
|
-
*
|
|
1653
|
+
/**
|
|
1654
|
+
* Multiply the matrix * [x,y,0], i.e. the vector [x,y,0] is a column vector on the right.
|
|
1655
|
+
* @param result the vector result (optional)
|
|
1584
1656
|
*/
|
|
1585
1657
|
multiplyXY(x, y, result) {
|
|
1586
1658
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1587
|
-
result.x =
|
|
1588
|
-
result.y =
|
|
1589
|
-
result.z =
|
|
1659
|
+
result.x = this.coffs[0] * x + this.coffs[1] * y;
|
|
1660
|
+
result.y = this.coffs[3] * x + this.coffs[4] * y;
|
|
1661
|
+
result.z = this.coffs[6] * x + this.coffs[7] * y;
|
|
1590
1662
|
return result;
|
|
1591
1663
|
}
|
|
1592
|
-
/**
|
|
1664
|
+
/**
|
|
1665
|
+
* Compute origin + the matrix * [x,y,0].
|
|
1666
|
+
* @param result the Point3d result (optional)
|
|
1667
|
+
*/
|
|
1593
1668
|
originPlusMatrixTimesXY(origin, x, y, result) {
|
|
1594
1669
|
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
1670
|
}
|
|
1596
|
-
/**
|
|
1671
|
+
/**
|
|
1672
|
+
* Multiply the matrix * (x,y,z) in place, i.e. the vector (x,y,z) is a column vector on the right and
|
|
1673
|
+
* the multiplication updates the vector values.
|
|
1674
|
+
* @param xyzData the vector data.
|
|
1675
|
+
*/
|
|
1597
1676
|
multiplyVectorInPlace(xyzData) {
|
|
1598
1677
|
const x = xyzData.x;
|
|
1599
1678
|
const y = xyzData.y;
|
|
1600
1679
|
const z = xyzData.z;
|
|
1601
|
-
|
|
1602
|
-
xyzData.
|
|
1603
|
-
xyzData.
|
|
1604
|
-
xyzData.z = (coffs[6] * x + coffs[7] * y + coffs[8] * z);
|
|
1680
|
+
xyzData.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
|
|
1681
|
+
xyzData.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
|
|
1682
|
+
xyzData.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
|
|
1605
1683
|
}
|
|
1606
|
-
/**
|
|
1607
|
-
*
|
|
1684
|
+
/**
|
|
1685
|
+
* Multiply the transpose matrix times [x,y,z] in place, i.e. the vector [x,y,z] is a column vector on
|
|
1686
|
+
* the right and the multiplication updates the vector values.
|
|
1687
|
+
* * This is equivalent to `multiplyTransposeVector` but always returns the result directly in the input.
|
|
1688
|
+
* @param vectorU the vector data
|
|
1608
1689
|
*/
|
|
1609
1690
|
multiplyTransposeVectorInPlace(vectorU) {
|
|
1610
1691
|
const x = vectorU.x;
|
|
1611
1692
|
const y = vectorU.y;
|
|
1612
1693
|
const z = vectorU.z;
|
|
1613
|
-
|
|
1614
|
-
vectorU.
|
|
1615
|
-
vectorU.
|
|
1616
|
-
vectorU.z = (coffs[2] * x + coffs[5] * y + coffs[8] * z);
|
|
1694
|
+
vectorU.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1695
|
+
vectorU.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1696
|
+
vectorU.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1617
1697
|
}
|
|
1618
|
-
/**
|
|
1619
|
-
*
|
|
1698
|
+
/**
|
|
1699
|
+
* Multiply the transpose matrix times column using individual numeric inputs.
|
|
1700
|
+
* * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
|
|
1620
1701
|
* ```
|
|
1621
1702
|
* equation
|
|
1622
1703
|
* \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 \\
|
|
1704
|
+
* \text{treating the input as a column vector } \columnXYZ{x}{y}{z}\text{ compute }&\columnSubXYZ{V} &= &A^T \columnXYZ{x}{y}{z} \\
|
|
1705
|
+
* \text{or as a row vector } \rowXYZ{x}{y}{z} \text{ compute }&\rowSubXYZ{V} &= &\rowXYZ{x}{y}{z} A \\
|
|
1625
1706
|
* \phantom{8888}\text{and return V as a Vector3d} & & &
|
|
1626
1707
|
* \end{matrix}
|
|
1627
1708
|
* ````
|
|
1628
|
-
* @
|
|
1709
|
+
* @param result the vector result (optional)
|
|
1629
1710
|
*/
|
|
1630
1711
|
multiplyTransposeXYZ(x, y, z, result) {
|
|
1631
1712
|
result = result ? result : new Point3dVector3d_1.Vector3d();
|
|
1632
|
-
result.x =
|
|
1633
|
-
result.y =
|
|
1634
|
-
result.z =
|
|
1713
|
+
result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
|
|
1714
|
+
result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
|
|
1715
|
+
result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
|
|
1635
1716
|
return result;
|
|
1636
1717
|
}
|
|
1637
|
-
/**
|
|
1718
|
+
/**
|
|
1719
|
+
* Solve `matrix * result = vector` for an unknown `result`.
|
|
1638
1720
|
* * This is equivalent to multiplication `result = matrixInverse * vector`.
|
|
1639
|
-
* * Result is undefined if the matrix is singular (e.g. has parallel or zero
|
|
1721
|
+
* * Result is `undefined` if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1640
1722
|
*/
|
|
1641
1723
|
multiplyInverse(vector, result) {
|
|
1642
1724
|
this.computeCachedInverse(true);
|
|
@@ -1644,13 +1726,14 @@ class Matrix3d {
|
|
|
1644
1726
|
const x = vector.x;
|
|
1645
1727
|
const y = vector.y;
|
|
1646
1728
|
const z = vector.z;
|
|
1647
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1729
|
+
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
1730
|
}
|
|
1649
1731
|
return undefined;
|
|
1650
1732
|
}
|
|
1651
|
-
/**
|
|
1733
|
+
/**
|
|
1734
|
+
* Solve `matrixTranspose * result = vector` for an unknown `result`.
|
|
1652
1735
|
* * This is equivalent to multiplication `result = matrixInverseTranspose * vector`.
|
|
1653
|
-
* * Result is undefined if the matrix is singular (e.g. has parallel or zero
|
|
1736
|
+
* * Result is `undefined` if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1654
1737
|
*/
|
|
1655
1738
|
multiplyInverseTranspose(vector, result) {
|
|
1656
1739
|
this.computeCachedInverse(true);
|
|
@@ -1658,87 +1741,91 @@ class Matrix3d {
|
|
|
1658
1741
|
const x = vector.x;
|
|
1659
1742
|
const y = vector.y;
|
|
1660
1743
|
const z = vector.z;
|
|
1661
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1744
|
+
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
1745
|
}
|
|
1663
1746
|
return undefined;
|
|
1664
1747
|
}
|
|
1665
1748
|
/**
|
|
1666
|
-
*
|
|
1667
|
-
* *
|
|
1668
|
-
* *
|
|
1749
|
+
* Multiply `matrixInverse * [x,y,z]`.
|
|
1750
|
+
* * This is equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1751
|
+
* * Result is `undefined` if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1752
|
+
* @return result as a Vector3d or undefined (if the matrix is singular).
|
|
1669
1753
|
*/
|
|
1670
1754
|
multiplyInverseXYZAsVector3d(x, y, z, result) {
|
|
1671
1755
|
this.computeCachedInverse(true);
|
|
1672
1756
|
if (this.inverseCoffs) {
|
|
1673
|
-
return Point3dVector3d_1.Vector3d.create(
|
|
1757
|
+
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
1758
|
}
|
|
1675
1759
|
return undefined;
|
|
1676
1760
|
}
|
|
1677
1761
|
/**
|
|
1678
|
-
*
|
|
1679
|
-
* *
|
|
1680
|
-
* *
|
|
1681
|
-
*
|
|
1762
|
+
* Multiply `matrixInverse * [x,y,z]` and return result as `Point4d` with given weight.
|
|
1763
|
+
* * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1764
|
+
* * Result is `undefined` if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1765
|
+
* @return result as a Point4d with the same weight.
|
|
1682
1766
|
*/
|
|
1683
1767
|
multiplyInverseXYZW(x, y, z, w, result) {
|
|
1684
1768
|
this.computeCachedInverse(true);
|
|
1685
1769
|
if (this.inverseCoffs) {
|
|
1686
|
-
return Point4d_1.Point4d.create(
|
|
1770
|
+
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
1771
|
}
|
|
1688
1772
|
return undefined;
|
|
1689
1773
|
}
|
|
1690
1774
|
/**
|
|
1691
|
-
*
|
|
1692
|
-
* *
|
|
1693
|
-
*
|
|
1694
|
-
* * return as a Point3d.
|
|
1775
|
+
* Multiply `matrixInverse * [x,y,z]` and return result as `Point3d`.
|
|
1776
|
+
* * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
|
|
1777
|
+
* @return result as a Point3d or `undefined` (if the matrix is singular).
|
|
1695
1778
|
*/
|
|
1696
1779
|
multiplyInverseXYZAsPoint3d(x, y, z, result) {
|
|
1697
1780
|
this.computeCachedInverse(true);
|
|
1698
1781
|
if (this.inverseCoffs) {
|
|
1699
|
-
return Point3dVector3d_1.Point3d.create(
|
|
1782
|
+
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
1783
|
}
|
|
1701
1784
|
return undefined;
|
|
1702
1785
|
}
|
|
1703
1786
|
/**
|
|
1704
|
-
*
|
|
1705
|
-
* * set
|
|
1706
|
-
*
|
|
1787
|
+
* Invoke a given matrix*matrix operation to compute the inverse matrix and set this.inverseCoffs
|
|
1788
|
+
* * If either input coffA or coffB is `undefined`, set state to `InverseMatrixState.unknown` but
|
|
1789
|
+
* leave the inverseCoffs untouched.
|
|
1790
|
+
* @param f the given matrix*matrix operation that is called by this function to compute the inverse.
|
|
1791
|
+
* `f` must be a matrix*matrix operation. Otherwise, the function does not generate the inverse properly.
|
|
1707
1792
|
*/
|
|
1708
1793
|
finishInverseCoffs(f, coffA, coffB) {
|
|
1709
1794
|
if (coffA && coffB) {
|
|
1710
1795
|
this.createInverseCoffsWithZeros();
|
|
1711
1796
|
this.inverseState = InverseMatrixState.inverseStored;
|
|
1712
|
-
f(coffA, coffB, this.inverseCoffs);
|
|
1797
|
+
f(coffA, coffB, this.inverseCoffs); // call function f (which is provided by user) to compute the inverse.
|
|
1713
1798
|
}
|
|
1714
1799
|
else {
|
|
1715
1800
|
this.inverseState = InverseMatrixState.unknown;
|
|
1716
1801
|
}
|
|
1717
1802
|
}
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
* @return the matrix product A * B
|
|
1803
|
+
// Notes on inverse of matrix products:
|
|
1804
|
+
// 1) M = A * B ===> MInverse = BInverse * AInverse
|
|
1805
|
+
// 2) M = A * BInverse ===> MInverse = B * AInverse
|
|
1806
|
+
// 3) M = AInverse * B ===> MInverse = BInverse * A
|
|
1807
|
+
// 4) M = A * BTranspose ===> MInverse = BInverseTranspose * AInverse
|
|
1808
|
+
// 5) M = ATranspose * B ===> MInverse = BInverse * AInverseTranspose
|
|
1809
|
+
/**
|
|
1810
|
+
* Multiply `this` matrix times `other` matrix
|
|
1811
|
+
* @return the matrix result: this*other
|
|
1728
1812
|
*/
|
|
1729
1813
|
multiplyMatrixMatrix(other, result) {
|
|
1730
1814
|
result = result ? result : new Matrix3d();
|
|
1731
1815
|
PackedMatrix3dOps.multiplyMatrixMatrix(this.coffs, other.coffs, result.coffs);
|
|
1732
|
-
if (this.inverseState === InverseMatrixState.inverseStored
|
|
1816
|
+
if (this.inverseState === InverseMatrixState.inverseStored
|
|
1817
|
+
&& other.inverseState === InverseMatrixState.inverseStored)
|
|
1733
1818
|
result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixMatrix, other.inverseCoffs, this.inverseCoffs);
|
|
1734
|
-
else if (this.inverseState === InverseMatrixState.singular
|
|
1819
|
+
else if (this.inverseState === InverseMatrixState.singular
|
|
1820
|
+
|| other.inverseState === InverseMatrixState.singular)
|
|
1735
1821
|
result.inverseState = InverseMatrixState.singular;
|
|
1736
1822
|
else
|
|
1737
1823
|
result.inverseState = InverseMatrixState.unknown;
|
|
1738
1824
|
return result;
|
|
1739
1825
|
}
|
|
1740
|
-
/**
|
|
1741
|
-
*
|
|
1826
|
+
/**
|
|
1827
|
+
* Multiply `this` matrix times `inverse of other` matrix
|
|
1828
|
+
* @return the matrix result: this*otherInverse
|
|
1742
1829
|
*/
|
|
1743
1830
|
multiplyMatrixMatrixInverse(other, result) {
|
|
1744
1831
|
if (!other.computeCachedInverse(true))
|
|
@@ -1752,8 +1839,9 @@ class Matrix3d {
|
|
|
1752
1839
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
|
|
1753
1840
|
return result;
|
|
1754
1841
|
}
|
|
1755
|
-
/**
|
|
1756
|
-
*
|
|
1842
|
+
/**
|
|
1843
|
+
* Multiply `inverse of this` matrix times `other` matrix
|
|
1844
|
+
* @return the matrix result: thisInverse*other
|
|
1757
1845
|
*/
|
|
1758
1846
|
multiplyMatrixInverseMatrix(other, result) {
|
|
1759
1847
|
if (!this.computeCachedInverse(true))
|
|
@@ -1767,30 +1855,32 @@ class Matrix3d {
|
|
|
1767
1855
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
|
|
1768
1856
|
return result;
|
|
1769
1857
|
}
|
|
1770
|
-
/**
|
|
1858
|
+
/**
|
|
1859
|
+
* Multiply `this` matrix times the transpose of `other` matrix
|
|
1771
1860
|
* ```
|
|
1772
1861
|
* equation
|
|
1773
|
-
* \text{for instance matrix }A\text{ and
|
|
1862
|
+
* \text{for instance matrix }A\text{ and matrix }B\text{ return matrix }C{\text where }\\\matrixXY{C}=\matrixXY{A}\matrixTransposeSubXY{B}
|
|
1774
1863
|
* ```
|
|
1775
|
-
* @return the matrix result
|
|
1864
|
+
* @return the matrix result: this*otherTranspose
|
|
1776
1865
|
*/
|
|
1777
|
-
multiplyMatrixMatrixTranspose(
|
|
1866
|
+
multiplyMatrixMatrixTranspose(other, result) {
|
|
1778
1867
|
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 ||
|
|
1868
|
+
PackedMatrix3dOps.multiplyMatrixMatrixTranspose(this.coffs, other.coffs, result.coffs);
|
|
1869
|
+
if (this.inverseState === InverseMatrixState.inverseStored && other.inverseState === InverseMatrixState.inverseStored)
|
|
1870
|
+
result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixTransposeMatrix, other.inverseCoffs, this.inverseCoffs);
|
|
1871
|
+
else if (this.inverseState === InverseMatrixState.singular || other.inverseState === InverseMatrixState.singular)
|
|
1783
1872
|
result.inverseState = InverseMatrixState.singular;
|
|
1784
1873
|
else
|
|
1785
1874
|
result.inverseState = InverseMatrixState.unknown;
|
|
1786
1875
|
return result;
|
|
1787
1876
|
}
|
|
1788
|
-
/**
|
|
1877
|
+
/**
|
|
1878
|
+
* Multiply the transpose of `this` matrix times `other` matrix
|
|
1789
1879
|
* ```
|
|
1790
1880
|
* equation
|
|
1791
1881
|
* \matrixXY{result}=\matrixXY{\text{this}}\matrixTransposeSubXY{\text{other}}
|
|
1792
1882
|
* ```
|
|
1793
|
-
*
|
|
1883
|
+
* @return the matrix result: thisTranspose*other
|
|
1794
1884
|
*/
|
|
1795
1885
|
multiplyMatrixTransposeMatrix(other, result) {
|
|
1796
1886
|
result = result ? result : new Matrix3d();
|
|
@@ -1803,30 +1893,31 @@ class Matrix3d {
|
|
|
1803
1893
|
result.inverseState = InverseMatrixState.unknown;
|
|
1804
1894
|
return result;
|
|
1805
1895
|
}
|
|
1806
|
-
/**
|
|
1896
|
+
/**
|
|
1897
|
+
* Multiply `this` Matrix3d (considered as a Transform with 0 translation) times `other` Transform.
|
|
1807
1898
|
* ```
|
|
1808
1899
|
* equation
|
|
1809
1900
|
* \begin{matrix}
|
|
1810
|
-
*
|
|
1811
|
-
*
|
|
1901
|
+
* \text{This matrix }\bold{A}\text{ promoted to block transform} & \blockTransform{A}{0} \\
|
|
1902
|
+
* \text{other transform with matrix part }\bold{B}\text{ and translation }\bold{b} & \blockTransform{B}{b}\\
|
|
1812
1903
|
* \text{product}& \blockTransform{A}{0}\blockTransform{B}{b}=\blockTransform{AB}{Ab}
|
|
1813
1904
|
* \end{matrix}
|
|
1814
1905
|
* ```
|
|
1815
|
-
* @param other
|
|
1816
|
-
* @param result
|
|
1906
|
+
* @param other Right hand Matrix3d for multiplication.
|
|
1907
|
+
* @param result the Transform result (optional)
|
|
1817
1908
|
*/
|
|
1818
1909
|
multiplyMatrixTransform(other, result) {
|
|
1819
1910
|
if (!result)
|
|
1820
1911
|
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
|
|
1912
|
+
// be sure to do the point multiplication first before aliasing changes the matrix
|
|
1822
1913
|
this.multiplyXYZtoXYZ(other.origin, result.origin);
|
|
1823
1914
|
this.multiplyMatrixMatrix(other.matrix, result.matrix);
|
|
1824
1915
|
return result;
|
|
1825
1916
|
}
|
|
1826
1917
|
/**
|
|
1827
1918
|
* 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
|
|
1919
|
+
* * If `result` is passed as argument, then the function copies the transpose of `this` into `result`.
|
|
1920
|
+
* * `this` is not changed unless also passed as the result, i.e., `this.transpose(this)` transposes `this` in place.
|
|
1830
1921
|
*/
|
|
1831
1922
|
transpose(result) {
|
|
1832
1923
|
if (!result)
|
|
@@ -1848,18 +1939,22 @@ class Matrix3d {
|
|
|
1848
1939
|
transposeInPlace() {
|
|
1849
1940
|
PackedMatrix3dOps.transposeInPlace(this.coffs);
|
|
1850
1941
|
if (this.inverseCoffs)
|
|
1851
|
-
PackedMatrix3dOps.transposeInPlace(this.inverseCoffs);
|
|
1942
|
+
PackedMatrix3dOps.transposeInPlace(this.inverseCoffs); // inverse of transpose is equal to transpose of inverse
|
|
1852
1943
|
}
|
|
1853
|
-
/**
|
|
1854
|
-
*
|
|
1855
|
-
*
|
|
1856
|
-
* *
|
|
1944
|
+
/**
|
|
1945
|
+
* Return the inverse matrix.
|
|
1946
|
+
* The return is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
|
|
1947
|
+
* * If `result == this`, then content of inverse of `this` matrix is copied into `this`. Otherwise, inverse
|
|
1948
|
+
* of `this` is stored in `result`.
|
|
1949
|
+
* * **Note:** Each Matrix3d object caches its own inverse (`this.inverseCoffs`) and has methods to multiply
|
|
1950
|
+
* the inverse times matrices and vectors (e.g., `multiplyMatrixInverseMatrix`, `multiplyMatrixMatrixInverse`,
|
|
1951
|
+
* `multiplyInverse`). Hence explicitly constructing this new inverse object is rarely necessary.
|
|
1857
1952
|
*/
|
|
1858
1953
|
inverse(result) {
|
|
1859
1954
|
if (!this.computeCachedInverse(true))
|
|
1860
1955
|
return undefined;
|
|
1861
1956
|
if (result === this) {
|
|
1862
|
-
// swap the contents
|
|
1957
|
+
// swap the contents of this.coffs and this.inverseCoffs
|
|
1863
1958
|
PackedMatrix3dOps.copy(this.coffs, Matrix3d._productBuffer);
|
|
1864
1959
|
PackedMatrix3dOps.copy(this.inverseCoffs, this.coffs);
|
|
1865
1960
|
PackedMatrix3dOps.copy(Matrix3d._productBuffer, this.inverseCoffs);
|
|
@@ -1874,33 +1969,50 @@ class Matrix3d {
|
|
|
1874
1969
|
result.inverseState = this.inverseState;
|
|
1875
1970
|
return result;
|
|
1876
1971
|
}
|
|
1877
|
-
|
|
1878
|
-
|
|
1879
|
-
|
|
1880
|
-
|
|
1972
|
+
/**
|
|
1973
|
+
* Take the dot product of a row (specified by `rowStartA`) of `coffA` and `columnStartB` of `coffB`.
|
|
1974
|
+
* * **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.
|
|
1975
|
+
*/
|
|
1976
|
+
static rowColumnDot(coffA, rowStartA, coffB, columnStartB) {
|
|
1977
|
+
return coffA[rowStartA] * coffB[columnStartB] +
|
|
1978
|
+
coffA[rowStartA + 1] * coffB[columnStartB + 3] +
|
|
1979
|
+
coffA[rowStartA + 2] * coffB[columnStartB + 6];
|
|
1980
|
+
}
|
|
1981
|
+
/**
|
|
1982
|
+
* Take the cross product of 2 rows (specified by `rowStart0` and `rowStart1`) of `source` and store the result
|
|
1983
|
+
* in `columnStart` of `dest`.
|
|
1984
|
+
* * **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.
|
|
1985
|
+
*/
|
|
1881
1986
|
static indexedRowCrossProduct(source, rowStart0, rowStart1, dest, columnStart) {
|
|
1882
1987
|
dest[columnStart] = source[rowStart0 + 1] * source[rowStart1 + 2] - source[rowStart0 + 2] * source[rowStart1 + 1];
|
|
1883
1988
|
dest[columnStart + 3] = source[rowStart0 + 2] * source[rowStart1] - source[rowStart0] * source[rowStart1 + 2];
|
|
1884
1989
|
dest[columnStart + 6] = source[rowStart0] * source[rowStart1 + 1] - source[rowStart0 + 1] * source[rowStart1];
|
|
1885
1990
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1991
|
+
/**
|
|
1992
|
+
* Take the cross product of 2 columns (i.e., `colStart0` and `colStart1`) of `this` matrix and store the
|
|
1993
|
+
* result in `colStart2` of the same matrix.
|
|
1994
|
+
* * **Note:** We don't validate column numbers. Pass 0/1/2 for column 0/1/2.
|
|
1995
|
+
*/
|
|
1889
1996
|
indexedColumnCrossProductInPlace(colStart0, colStart1, colStart2) {
|
|
1890
1997
|
const coffs = this.coffs;
|
|
1891
1998
|
coffs[colStart2] = coffs[colStart0 + 3] * coffs[colStart1 + 6] - coffs[colStart0 + 6] * coffs[colStart1 + 3];
|
|
1892
1999
|
coffs[colStart2 + 3] = coffs[colStart0 + 6] * coffs[colStart1] - coffs[colStart0] * coffs[colStart1 + 6];
|
|
1893
2000
|
coffs[colStart2 + 6] = coffs[colStart0] * coffs[colStart1 + 3] - coffs[colStart0 + 3] * coffs[colStart1];
|
|
1894
2001
|
}
|
|
1895
|
-
/**
|
|
1896
|
-
*
|
|
1897
|
-
*
|
|
2002
|
+
/**
|
|
2003
|
+
* Form cross products among columns in axisOrder.
|
|
2004
|
+
* For axis order ABC:
|
|
2005
|
+
* * form cross product of column A and B, store in C.
|
|
1898
2006
|
* * form cross product of column C and A, store in B.
|
|
2007
|
+
* * [A B C] ===> [A B AxB] ===> [A (AxB)xA AxB]
|
|
2008
|
+
*
|
|
1899
2009
|
* This means that in the final matrix:
|
|
1900
|
-
* * column
|
|
1901
|
-
* * column
|
|
1902
|
-
* * column
|
|
1903
|
-
* * original column C does not participate in the result.
|
|
2010
|
+
* * first column is same as original column A.
|
|
2011
|
+
* * second column is linear combination of original A and B (i.e., is in the plane of original A and B).
|
|
2012
|
+
* * third column is perpendicular to first and second columns of both the original and final.
|
|
2013
|
+
* * original column C is overwritten and does not participate in the result.
|
|
2014
|
+
*
|
|
2015
|
+
* The final matrix will have 3 orthogonal columns.
|
|
1904
2016
|
*/
|
|
1905
2017
|
axisOrderCrossProductsInPlace(axisOrder) {
|
|
1906
2018
|
switch (axisOrder) {
|
|
@@ -1936,41 +2048,44 @@ class Matrix3d {
|
|
|
1936
2048
|
}
|
|
1937
2049
|
}
|
|
1938
2050
|
}
|
|
1939
|
-
/**
|
|
1940
|
-
*
|
|
1941
|
-
* @
|
|
1942
|
-
* @
|
|
2051
|
+
/**
|
|
2052
|
+
* Normalize each column in place.
|
|
2053
|
+
* @param originalColumnMagnitudes optional vector to store original column magnitudes.
|
|
2054
|
+
* @returns return true if all columns have non-zero lengths. Otherwise, return false.
|
|
2055
|
+
* * If false is returned, the magnitudes are stored in the `originalColumnMagnitudes` vector but no columns
|
|
2056
|
+
* are altered.
|
|
1943
2057
|
*/
|
|
1944
|
-
normalizeColumnsInPlace(
|
|
2058
|
+
normalizeColumnsInPlace(originalColumnMagnitudes) {
|
|
1945
2059
|
const ax = this.columnXMagnitude();
|
|
1946
2060
|
const ay = this.columnYMagnitude();
|
|
1947
2061
|
const az = this.columnZMagnitude();
|
|
1948
|
-
if (
|
|
1949
|
-
|
|
2062
|
+
if (originalColumnMagnitudes)
|
|
2063
|
+
originalColumnMagnitudes.set(ax, ay, az);
|
|
1950
2064
|
if (Geometry_1.Geometry.isSmallMetricDistance(ax) || Geometry_1.Geometry.isSmallMetricDistance(ay) || Geometry_1.Geometry.isSmallMetricDistance(az))
|
|
1951
2065
|
return false;
|
|
1952
2066
|
this.scaleColumns(1.0 / ax, 1.0 / ay, 1.0 / az, this);
|
|
1953
2067
|
return true;
|
|
1954
2068
|
}
|
|
1955
|
-
/**
|
|
1956
|
-
|
|
2069
|
+
/**
|
|
2070
|
+
* Normalize each row in place.
|
|
2071
|
+
* @param originalRowMagnitudes optional vector to store original row magnitudes.
|
|
2072
|
+
* @returns return true if all rows have non-zero lengths. Otherwise, return false.
|
|
2073
|
+
* * If false is returned, the magnitudes are stored in the `originalRowMagnitudes` vector but no rows
|
|
2074
|
+
* are altered.
|
|
2075
|
+
*/
|
|
2076
|
+
normalizeRowsInPlace(originalRowMagnitudes) {
|
|
1957
2077
|
const ax = this.rowXMagnitude();
|
|
1958
2078
|
const ay = this.rowYMagnitude();
|
|
1959
2079
|
const az = this.rowZMagnitude();
|
|
1960
|
-
if (
|
|
1961
|
-
|
|
2080
|
+
if (originalRowMagnitudes)
|
|
2081
|
+
originalRowMagnitudes.set(ax, ay, az);
|
|
1962
2082
|
if (Geometry_1.Geometry.isSmallMetricDistance(ax) || Geometry_1.Geometry.isSmallMetricDistance(ay) || Geometry_1.Geometry.isSmallMetricDistance(az))
|
|
1963
2083
|
return false;
|
|
1964
2084
|
this.scaleRows(1.0 / ax, 1.0 / ay, 1.0 / az, this);
|
|
1965
2085
|
return true;
|
|
1966
2086
|
}
|
|
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
2087
|
/**
|
|
1973
|
-
* Returns true if the matrix is singular
|
|
2088
|
+
* Returns true if the matrix is singular.
|
|
1974
2089
|
*/
|
|
1975
2090
|
isSingular() {
|
|
1976
2091
|
return !this.computeCachedInverse(true);
|
|
@@ -1982,18 +2097,10 @@ class Matrix3d {
|
|
|
1982
2097
|
this.inverseState = InverseMatrixState.singular;
|
|
1983
2098
|
}
|
|
1984
2099
|
/**
|
|
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.)
|
|
2100
|
+
* Compute the inverse of `this` Matrix3d. The inverse is stored in `this.inverseCoffs` for later use.
|
|
2101
|
+
* @param useCacheIfAvailable if `true`, use the previously computed inverse if available. If `false`,
|
|
2102
|
+
* recompute the inverse.
|
|
2103
|
+
* @returns return `true` if the inverse is computed. Return `false` if matrix is singular.
|
|
1997
2104
|
*/
|
|
1998
2105
|
computeCachedInverse(useCacheIfAvailable) {
|
|
1999
2106
|
if (useCacheIfAvailable && Matrix3d.useCachedInverse && this.inverseState !== InverseMatrixState.unknown) {
|
|
@@ -2004,71 +2111,46 @@ class Matrix3d {
|
|
|
2004
2111
|
this.createInverseCoffsWithZeros();
|
|
2005
2112
|
const coffs = this.coffs;
|
|
2006
2113
|
const inverseCoffs = this.inverseCoffs;
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2114
|
+
/**
|
|
2115
|
+
* We calculate the inverse using cross products.
|
|
2116
|
+
* Math details can be found at docs/learning/matrix/Matrix.md
|
|
2117
|
+
* [ A ]
|
|
2118
|
+
* In summary, if M = [ B ] then inverse of M = (1/det)[BxC CxA AxB] where
|
|
2119
|
+
* [ C ]
|
|
2120
|
+
* det is the determinant of matrix M (which is equal to "A dot BxC").
|
|
2121
|
+
*/
|
|
2122
|
+
Matrix3d.indexedRowCrossProduct(coffs, 3, 6, inverseCoffs, 0); // BxC
|
|
2123
|
+
Matrix3d.indexedRowCrossProduct(coffs, 6, 0, inverseCoffs, 1); // CxA
|
|
2124
|
+
Matrix3d.indexedRowCrossProduct(coffs, 0, 3, inverseCoffs, 2); // AxB
|
|
2010
2125
|
Matrix3d.numComputeCache++;
|
|
2011
|
-
const
|
|
2012
|
-
if (
|
|
2126
|
+
const det = Matrix3d.rowColumnDot(coffs, 0, inverseCoffs, 0); // A dot BxC
|
|
2127
|
+
if (det === 0.0) {
|
|
2013
2128
|
this.inverseState = InverseMatrixState.singular;
|
|
2014
2129
|
this.inverseCoffs = undefined;
|
|
2015
2130
|
return false;
|
|
2016
2131
|
}
|
|
2017
|
-
const f = 1.0 /
|
|
2132
|
+
const f = 1.0 / det;
|
|
2018
2133
|
for (let i = 0; i < 9; i++)
|
|
2019
2134
|
inverseCoffs[i] *= f;
|
|
2020
2135
|
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
2136
|
return true;
|
|
2027
2137
|
}
|
|
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 */
|
|
2138
|
+
/**
|
|
2139
|
+
* Convert a (row,column) index pair to the single index within flattened array of 9 numbers in row-major-order
|
|
2140
|
+
* * **Note:** Out of range row/column is interpreted cyclically.
|
|
2141
|
+
*/
|
|
2063
2142
|
static flatIndexOf(row, column) {
|
|
2064
2143
|
return 3 * Geometry_1.Geometry.cyclic3dAxis(row) + Geometry_1.Geometry.cyclic3dAxis(column);
|
|
2065
2144
|
}
|
|
2066
|
-
/**
|
|
2145
|
+
/**
|
|
2146
|
+
* Get elements of column `index` packaged as a Point4d with given `weight`.
|
|
2147
|
+
* * **Note:** Out of range index is interpreted cyclically.
|
|
2148
|
+
*/
|
|
2067
2149
|
indexedColumnWithWeight(index, weight, result) {
|
|
2068
2150
|
index = Geometry_1.Geometry.cyclic3dAxis(index);
|
|
2069
2151
|
return Point4d_1.Point4d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], weight, result);
|
|
2070
2152
|
}
|
|
2071
|
-
/**
|
|
2153
|
+
/** Return the entry at specific row and column */
|
|
2072
2154
|
at(row, column) {
|
|
2073
2155
|
return this.coffs[Matrix3d.flatIndexOf(row, column)];
|
|
2074
2156
|
}
|
|
@@ -2077,19 +2159,30 @@ class Matrix3d {
|
|
|
2077
2159
|
this.coffs[Matrix3d.flatIndexOf(row, column)] = value;
|
|
2078
2160
|
this.inverseState = InverseMatrixState.unknown;
|
|
2079
2161
|
}
|
|
2080
|
-
/**
|
|
2081
|
-
*
|
|
2082
|
-
* @param
|
|
2083
|
-
* @param scaleZ scale factor for column z
|
|
2162
|
+
/**
|
|
2163
|
+
* Create a Matrix3d whose values are uniformly scaled from `this` Matrix3d.
|
|
2164
|
+
* @param scale scale factor to apply.
|
|
2084
2165
|
* @param result optional result.
|
|
2166
|
+
* @returns return the scaled matrix.
|
|
2167
|
+
*/
|
|
2168
|
+
scale(scale, result) {
|
|
2169
|
+
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);
|
|
2170
|
+
}
|
|
2171
|
+
/**
|
|
2172
|
+
* Create a Matrix3d whose columns are scaled copies of `this` Matrix3d.
|
|
2173
|
+
* @param scaleX scale factor for column 0
|
|
2174
|
+
* @param scaleY scale factor for column 1
|
|
2175
|
+
* @param scaleZ scale factor for column 2
|
|
2176
|
+
* @param result optional result
|
|
2085
2177
|
*/
|
|
2086
2178
|
scaleColumns(scaleX, scaleY, scaleZ, result) {
|
|
2087
2179
|
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);
|
|
2088
2180
|
}
|
|
2089
|
-
/**
|
|
2090
|
-
*
|
|
2091
|
-
* @param
|
|
2092
|
-
* @param
|
|
2181
|
+
/**
|
|
2182
|
+
* Scale the columns of `this` Matrix3d in place.
|
|
2183
|
+
* @param scaleX scale factor for column 0
|
|
2184
|
+
* @param scaleY scale factor for column 1
|
|
2185
|
+
* @param scaleZ scale factor for column 2
|
|
2093
2186
|
*/
|
|
2094
2187
|
scaleColumnsInPlace(scaleX, scaleY, scaleZ) {
|
|
2095
2188
|
this.coffs[0] *= scaleX;
|
|
@@ -2102,7 +2195,7 @@ class Matrix3d {
|
|
|
2102
2195
|
this.coffs[7] *= scaleY;
|
|
2103
2196
|
this.coffs[8] *= scaleZ;
|
|
2104
2197
|
if (this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined) {
|
|
2105
|
-
// apply reciprocal scales to the ROWS of the inverse
|
|
2198
|
+
// apply reciprocal scales to the ROWS of the inverse
|
|
2106
2199
|
const divX = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleX);
|
|
2107
2200
|
const divY = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleY);
|
|
2108
2201
|
const divZ = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleZ);
|
|
@@ -2121,18 +2214,55 @@ class Matrix3d {
|
|
|
2121
2214
|
this.inverseState = InverseMatrixState.singular;
|
|
2122
2215
|
}
|
|
2123
2216
|
}
|
|
2124
|
-
/**
|
|
2125
|
-
*
|
|
2126
|
-
* @param
|
|
2127
|
-
* @param
|
|
2128
|
-
* @param
|
|
2217
|
+
/**
|
|
2218
|
+
* Create a Matrix3d whose rows are scaled copies of `this` Matrix3d.
|
|
2219
|
+
* @param scaleX scale factor for row 0
|
|
2220
|
+
* @param scaleY scale factor for row 1
|
|
2221
|
+
* @param scaleZ scale factor for row 2
|
|
2222
|
+
* @param result optional result
|
|
2129
2223
|
*/
|
|
2130
2224
|
scaleRows(scaleX, scaleY, scaleZ, result) {
|
|
2131
2225
|
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);
|
|
2132
2226
|
}
|
|
2133
2227
|
/**
|
|
2134
|
-
*
|
|
2135
|
-
* @param
|
|
2228
|
+
* Scale the rows of `this` Matrix3d in place.
|
|
2229
|
+
* @param scaleX scale factor for row 0
|
|
2230
|
+
* @param scaleY scale factor for row 1
|
|
2231
|
+
* @param scaleZ scale factor for row 2
|
|
2232
|
+
*/
|
|
2233
|
+
scaleRowsInPlace(scaleX, scaleY, scaleZ) {
|
|
2234
|
+
this.coffs[0] *= scaleX;
|
|
2235
|
+
this.coffs[1] *= scaleX;
|
|
2236
|
+
this.coffs[2] *= scaleX;
|
|
2237
|
+
this.coffs[3] *= scaleY;
|
|
2238
|
+
this.coffs[4] *= scaleY;
|
|
2239
|
+
this.coffs[5] *= scaleY;
|
|
2240
|
+
this.coffs[6] *= scaleZ;
|
|
2241
|
+
this.coffs[7] *= scaleZ;
|
|
2242
|
+
this.coffs[8] *= scaleZ;
|
|
2243
|
+
if (this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined) {
|
|
2244
|
+
// apply reciprocal scales to the COLUMNs of the inverse
|
|
2245
|
+
const divX = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleX);
|
|
2246
|
+
const divY = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleY);
|
|
2247
|
+
const divZ = Geometry_1.Geometry.conditionalDivideFraction(1.0, scaleZ);
|
|
2248
|
+
if (divX !== undefined && divY !== undefined && divZ !== undefined) {
|
|
2249
|
+
this.inverseCoffs[0] *= divX;
|
|
2250
|
+
this.inverseCoffs[1] *= divY;
|
|
2251
|
+
this.inverseCoffs[2] *= divZ;
|
|
2252
|
+
this.inverseCoffs[3] *= divX;
|
|
2253
|
+
this.inverseCoffs[4] *= divY;
|
|
2254
|
+
this.inverseCoffs[5] *= divZ;
|
|
2255
|
+
this.inverseCoffs[6] *= divX;
|
|
2256
|
+
this.inverseCoffs[7] *= divY;
|
|
2257
|
+
this.inverseCoffs[8] *= divZ;
|
|
2258
|
+
}
|
|
2259
|
+
else
|
|
2260
|
+
this.inverseState = InverseMatrixState.singular;
|
|
2261
|
+
}
|
|
2262
|
+
}
|
|
2263
|
+
/**
|
|
2264
|
+
* Add scaled values from `other` Matrix3d to `this` Matrix3d.
|
|
2265
|
+
* @param other Matrix3d with values to be added.
|
|
2136
2266
|
* @param scale scale factor to apply to the added values.
|
|
2137
2267
|
*/
|
|
2138
2268
|
addScaledInPlace(other, scale) {
|
|
@@ -2141,18 +2271,19 @@ class Matrix3d {
|
|
|
2141
2271
|
this.inverseState = InverseMatrixState.unknown;
|
|
2142
2272
|
}
|
|
2143
2273
|
/**
|
|
2144
|
-
*
|
|
2145
|
-
* * The scaled outer product is a
|
|
2274
|
+
* Add scaled values from an outer product of vectors U and V.
|
|
2275
|
+
* * The scaled outer product is a matrix with `rank 1` (all columns/rows are linearly dependent).
|
|
2146
2276
|
* * This is useful in constructing mirrors and directional scales.
|
|
2147
2277
|
* ```
|
|
2148
2278
|
* equation
|
|
2149
2279
|
* A += s \columnSubXYZ{U}\rowSubXYZ{V}
|
|
2150
2280
|
* \\ \matrixXY{A} += s \begin{bmatrix}
|
|
2151
|
-
* U_x * V_x &
|
|
2152
|
-
*
|
|
2153
|
-
*
|
|
2281
|
+
* U_x * V_x & U_x * V_y & U_x * V_z \\
|
|
2282
|
+
* U_y * V_x & U_y * V_y & U_y * V_z \\
|
|
2283
|
+
* U_z * V_x & U_z * V_y & U_z * V_z \end{bmatrix}
|
|
2154
2284
|
* ```
|
|
2155
|
-
* @param
|
|
2285
|
+
* @param vectorU first vector in the outer product.
|
|
2286
|
+
* @param vectorV second vector in the outer product.
|
|
2156
2287
|
* @param scale scale factor to apply to the added values.
|
|
2157
2288
|
*/
|
|
2158
2289
|
addScaledOuterProductInPlace(vectorU, vectorV, scale) {
|
|
@@ -2167,65 +2298,107 @@ class Matrix3d {
|
|
|
2167
2298
|
this.coffs[8] += scale * vectorU.z * vectorV.z;
|
|
2168
2299
|
this.inverseState = InverseMatrixState.unknown;
|
|
2169
2300
|
}
|
|
2170
|
-
/**
|
|
2171
|
-
*
|
|
2172
|
-
*
|
|
2173
|
-
*
|
|
2301
|
+
/**
|
|
2302
|
+
* Create a rigid matrix (columns and rows are unit length and pairwise perpendicular) for the given eye coordinate.
|
|
2303
|
+
* * column 2 is parallel to (x,y,z).
|
|
2304
|
+
* * column 0 is perpendicular to column 2 and is in the xy plane.
|
|
2305
|
+
* * column 1 is perpendicular to both. It is the "up" vector on the view plane.
|
|
2306
|
+
* * Multiplying the returned matrix times a local (view) vector gives the world vector.
|
|
2307
|
+
* * Multiplying transpose of the returned matrix times a world vector gives the local (view) vector.
|
|
2308
|
+
* @param x eye x coordinate
|
|
2309
|
+
* @param y eye y coordinate
|
|
2310
|
+
* @param z eye z coordinate
|
|
2311
|
+
* @param result optional preallocated result
|
|
2174
2312
|
*/
|
|
2175
|
-
|
|
2176
|
-
|
|
2313
|
+
static createRigidViewAxesZTowardsEye(x, y, z, result) {
|
|
2314
|
+
result = Matrix3d.createIdentity(result);
|
|
2315
|
+
const rxy = Geometry_1.Geometry.hypotenuseXY(x, y);
|
|
2316
|
+
// if coordinate is (0,0,z), i.e., Top or Bottom view
|
|
2317
|
+
if (Geometry_1.Geometry.isSmallMetricDistance(rxy)) {
|
|
2318
|
+
if (z < 0.0)
|
|
2319
|
+
result.scaleColumnsInPlace(1.0, -1.0, -1.0);
|
|
2320
|
+
}
|
|
2321
|
+
else {
|
|
2322
|
+
/**
|
|
2323
|
+
* The matrix that the "else" statement creates is
|
|
2324
|
+
* [-s -s1*c c1*c]
|
|
2325
|
+
* [c -s1*s c1*s]
|
|
2326
|
+
* [0 c1 s1 ]
|
|
2327
|
+
* where
|
|
2328
|
+
* c = x / sqrt(x*x + y*y)
|
|
2329
|
+
* s = y / sqrt(x*x + y*y)
|
|
2330
|
+
* c1 = sqrt(x*x + y*y) / sqrt(x*x + y*y + z*z)
|
|
2331
|
+
* s1 = z / sqrt(x*x + y*y + z*z)
|
|
2332
|
+
*
|
|
2333
|
+
* This is an orthogonal matrix meaning it rotates the standard XYZ axis to ABC axis system
|
|
2334
|
+
* (if matrix is [A B C]). The matrix rotates (0,0,1), i.e., the default Top view or Z axis,
|
|
2335
|
+
* to the eye point (x/r,y/r,z/r) where r = sqrt(x*x + y*y + z*z). The matrix also rotates
|
|
2336
|
+
* (1,0,0) to a point on XY plane.
|
|
2337
|
+
*/
|
|
2338
|
+
const c = x / rxy;
|
|
2339
|
+
const s = y / rxy;
|
|
2340
|
+
// 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)
|
|
2341
|
+
result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
|
|
2342
|
+
// if coordinate is (x,y,z) and z is not 0, i.e., other views such as Iso or RightIso
|
|
2343
|
+
if (z !== 0.0) {
|
|
2344
|
+
const r = Geometry_1.Geometry.hypotenuseXYZ(x, y, z);
|
|
2345
|
+
const s1 = z / r;
|
|
2346
|
+
const c1 = rxy / r;
|
|
2347
|
+
result.applyGivensColumnOp(1, 2, c1, -s1);
|
|
2348
|
+
}
|
|
2349
|
+
}
|
|
2350
|
+
return result;
|
|
2177
2351
|
}
|
|
2178
|
-
/** Return the determinant of this matrix. */
|
|
2352
|
+
/** Return the determinant of `this` matrix. */
|
|
2179
2353
|
determinant() {
|
|
2180
2354
|
return this.coffs[0] * this.coffs[4] * this.coffs[8]
|
|
2181
|
-
- this.coffs[0] * this.coffs[
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
+ this.coffs[
|
|
2185
|
-
- this.coffs[
|
|
2355
|
+
- this.coffs[0] * this.coffs[5] * this.coffs[7]
|
|
2356
|
+
- this.coffs[1] * this.coffs[3] * this.coffs[8]
|
|
2357
|
+
+ this.coffs[1] * this.coffs[5] * this.coffs[6]
|
|
2358
|
+
+ this.coffs[2] * this.coffs[3] * this.coffs[7]
|
|
2359
|
+
- this.coffs[2] * this.coffs[4] * this.coffs[6];
|
|
2186
2360
|
}
|
|
2187
|
-
/**
|
|
2361
|
+
/**
|
|
2362
|
+
* Return an estimate of how independent the columns of `this` matrix are. Near zero is bad (i.e.,
|
|
2363
|
+
* columns are almost dependent and matrix is nearly singular). Near 1 is good (i.e., columns are
|
|
2364
|
+
* almost independent and matrix is invertible).
|
|
2188
2365
|
*/
|
|
2189
2366
|
conditionNumber() {
|
|
2190
2367
|
const determinant = this.determinant();
|
|
2191
|
-
const
|
|
2368
|
+
const columnMagnitudeSum = Geometry_1.Geometry.hypotenuseXYZ(this.coffs[0], this.coffs[3], this.coffs[6])
|
|
2192
2369
|
+ Geometry_1.Geometry.hypotenuseXYZ(this.coffs[1], this.coffs[4], this.coffs[7])
|
|
2193
2370
|
+ Geometry_1.Geometry.hypotenuseXYZ(this.coffs[2], this.coffs[5], this.coffs[8]);
|
|
2194
|
-
return Geometry_1.Geometry.safeDivideFraction(determinant,
|
|
2371
|
+
return Geometry_1.Geometry.safeDivideFraction(determinant, columnMagnitudeSum, 0.0);
|
|
2195
2372
|
}
|
|
2196
2373
|
/** Return the sum of squares of all entries */
|
|
2197
2374
|
sumSquares() {
|
|
2198
|
-
let i = 0;
|
|
2199
2375
|
let sum = 0;
|
|
2200
|
-
for (i = 0; i < 9; i++)
|
|
2376
|
+
for (let i = 0; i < 9; i++)
|
|
2201
2377
|
sum += this.coffs[i] * this.coffs[i];
|
|
2202
2378
|
return sum;
|
|
2203
2379
|
}
|
|
2204
2380
|
/** Return the sum of squares of diagonal entries */
|
|
2205
2381
|
sumDiagonalSquares() {
|
|
2206
|
-
let i = 0;
|
|
2207
2382
|
let sum = 0;
|
|
2208
|
-
for (i = 0; i < 9; i += 4)
|
|
2383
|
+
for (let i = 0; i < 9; i += 4)
|
|
2209
2384
|
sum += this.coffs[i] * this.coffs[i];
|
|
2210
2385
|
return sum;
|
|
2211
2386
|
}
|
|
2212
|
-
/** Return the sum of diagonal entries
|
|
2387
|
+
/** Return the matrix `trace` (sum of diagonal entries) */
|
|
2213
2388
|
sumDiagonal() {
|
|
2214
2389
|
return this.coffs[0] + this.coffs[4] + this.coffs[8];
|
|
2215
2390
|
}
|
|
2216
2391
|
/** Return the Maximum absolute value of any single entry */
|
|
2217
2392
|
maxAbs() {
|
|
2218
|
-
let i = 0;
|
|
2219
2393
|
let max = 0;
|
|
2220
|
-
for (i = 0; i < 9; i++)
|
|
2394
|
+
for (let i = 0; i < 9; i++)
|
|
2221
2395
|
max = Math.max(max, Math.abs(this.coffs[i]));
|
|
2222
2396
|
return max;
|
|
2223
2397
|
}
|
|
2224
2398
|
/** Return the maximum absolute difference between corresponding entries of `this` and `other` */
|
|
2225
2399
|
maxDiff(other) {
|
|
2226
|
-
let i = 0;
|
|
2227
2400
|
let max = 0;
|
|
2228
|
-
for (i = 0; i < 9; i++)
|
|
2401
|
+
for (let i = 0; i < 9; i++)
|
|
2229
2402
|
max = Math.max(max, Math.abs(this.coffs[i] - other.coffs[i]));
|
|
2230
2403
|
return max;
|
|
2231
2404
|
}
|
|
@@ -2240,90 +2413,111 @@ class Matrix3d {
|
|
|
2240
2413
|
const sumOff = Math.abs(sumAll - sumDiagonal);
|
|
2241
2414
|
return Math.sqrt(sumOff) <= Geometry_1.Geometry.smallAngleRadians * (1.0 + Math.sqrt(sumAll));
|
|
2242
2415
|
}
|
|
2416
|
+
/** Sum of squared differences between symmetric pairs (symmetric pairs have indices (1,3), (2,6), and (5,7).) */
|
|
2417
|
+
sumSkewSquares() {
|
|
2418
|
+
return Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[1] - this.coffs[3], this.coffs[2] - this.coffs[6], this.coffs[5] - this.coffs[7]);
|
|
2419
|
+
}
|
|
2420
|
+
/** Test if the matrix is (very near to) symmetric */
|
|
2421
|
+
isSymmetric() {
|
|
2422
|
+
const offDiagonal = this.sumSkewSquares();
|
|
2423
|
+
return Math.sqrt(offDiagonal) <= Geometry_1.Geometry.smallAngleRadians * (1.0 + Math.sqrt(this.sumSquares()));
|
|
2424
|
+
}
|
|
2243
2425
|
/** Test if the stored inverse is present and marked valid */
|
|
2244
2426
|
get hasCachedInverse() {
|
|
2245
2427
|
return this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined;
|
|
2246
2428
|
}
|
|
2247
|
-
/** Test if the below diagonal entries are all nearly zero */
|
|
2429
|
+
/** Test if the below diagonal entries (3,6,7) are all nearly zero */
|
|
2248
2430
|
get isUpperTriangular() {
|
|
2249
2431
|
const sumAll = this.sumSquares();
|
|
2250
2432
|
const sumLow = Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[3], this.coffs[6], this.coffs[7]);
|
|
2251
2433
|
return Math.sqrt(sumLow) <= Geometry_1.Geometry.smallAngleRadians * (1.0 + Math.sqrt(sumAll));
|
|
2252
2434
|
}
|
|
2253
|
-
/**
|
|
2435
|
+
/** Test if the above diagonal entries (1,2,5) are all nearly zero */
|
|
2436
|
+
get isLowerTriangular() {
|
|
2437
|
+
const sumAll = this.sumSquares();
|
|
2438
|
+
const sumLow = Geometry_1.Geometry.hypotenuseSquaredXYZ(this.coffs[1], this.coffs[2], this.coffs[5]);
|
|
2439
|
+
return Math.sqrt(sumLow) <= Geometry_1.Geometry.smallAngleRadians * (1.0 + Math.sqrt(sumAll));
|
|
2440
|
+
}
|
|
2441
|
+
/**
|
|
2442
|
+
* If the matrix is diagonal and all diagonals are almost equal, return the first diagonal (entry 0
|
|
2443
|
+
* which is same as entry 4 and 8). Otherwise return `undefined`.
|
|
2254
2444
|
*/
|
|
2255
2445
|
sameDiagonalScale() {
|
|
2256
2446
|
const sumAll = this.sumSquares();
|
|
2257
2447
|
const sumDiagonal = this.sumDiagonalSquares();
|
|
2258
2448
|
const sumOff = Math.abs(sumAll - sumDiagonal);
|
|
2259
2449
|
if (Math.sqrt(sumOff) <= Geometry_1.Geometry.smallAngleRadians * (1.0 + Math.sqrt(sumAll))
|
|
2260
|
-
&& Geometry_1.Geometry.isSameCoordinate(this.coffs[0], this.coffs[4])
|
|
2450
|
+
&& Geometry_1.Geometry.isSameCoordinate(this.coffs[0], this.coffs[4])
|
|
2451
|
+
&& Geometry_1.Geometry.isSameCoordinate(this.coffs[0], this.coffs[8]))
|
|
2261
2452
|
return this.coffs[0];
|
|
2262
2453
|
return undefined;
|
|
2263
2454
|
}
|
|
2264
|
-
/**
|
|
2265
|
-
|
|
2266
|
-
|
|
2455
|
+
/**
|
|
2456
|
+
* Test if all rows and columns are unit length and are perpendicular to each other, i.e., the matrix is either
|
|
2457
|
+
* a `pure rotation` (determinant is +1) or is a `mirror` (determinant is -1).
|
|
2458
|
+
* * **Note:** such a matrix is called `orthogonal` and its inverse is its transpose.
|
|
2459
|
+
*/
|
|
2460
|
+
testPerpendicularUnitRowsAndColumns() {
|
|
2461
|
+
const product = this.multiplyMatrixMatrixTranspose(this);
|
|
2462
|
+
return product.isIdentity;
|
|
2267
2463
|
}
|
|
2268
|
-
/**
|
|
2269
|
-
*
|
|
2464
|
+
/**
|
|
2465
|
+
* Test if the matrix is a `rigid` matrix (or `pure rotation`, i.e., columns and rows are unit length and
|
|
2466
|
+
* pairwise perpendicular and determinant is +1).
|
|
2467
|
+
* @param allowMirror whether to widen the test to return true if the matrix is a `mirror` (determinant is -1).
|
|
2270
2468
|
*/
|
|
2271
2469
|
isRigid(allowMirror = false) {
|
|
2272
2470
|
return this.testPerpendicularUnitRowsAndColumns() && (allowMirror || this.determinant() > 0);
|
|
2273
2471
|
}
|
|
2274
|
-
/**
|
|
2275
|
-
*
|
|
2276
|
-
*
|
|
2277
|
-
*
|
|
2472
|
+
/**
|
|
2473
|
+
* Test if all rows and columns are perpendicular to each other and have equal length.
|
|
2474
|
+
* If so, the length (or its negative) is the `scale` factor from a set of `orthonormal axes` to
|
|
2475
|
+
* the set of axes created by columns of `this` matrix. Otherwise, returns `undefined`.
|
|
2476
|
+
* @returns returns `{ rigidAxes, scale }` where `rigidAxes` is a Matrix3d with its columns as the rigid axes
|
|
2477
|
+
* (with the scale factor removed) and `scale` is the scale factor.
|
|
2478
|
+
* * Note that determinant of a rigid matrix is +1.
|
|
2479
|
+
* * The context for this method is to determine if the matrix is the product a `rotation` matrix and a uniform
|
|
2480
|
+
* `scale` matrix (diagonal matrix with all diagonal entries the same nonzero number).
|
|
2278
2481
|
*/
|
|
2279
2482
|
factorRigidWithSignedScale() {
|
|
2280
2483
|
const product = this.multiplyMatrixMatrixTranspose(this);
|
|
2281
|
-
const
|
|
2282
|
-
if (
|
|
2484
|
+
const scaleSquare = product.sameDiagonalScale();
|
|
2485
|
+
if (scaleSquare === undefined || scaleSquare <= 0.0)
|
|
2283
2486
|
return undefined;
|
|
2284
|
-
const
|
|
2285
|
-
const
|
|
2286
|
-
const result = { rigidAxes: this.scaleColumns(
|
|
2487
|
+
const scale = this.determinant() > 0 ? Math.sqrt(scaleSquare) : -Math.sqrt(scaleSquare);
|
|
2488
|
+
const scaleInverse = 1.0 / scale;
|
|
2489
|
+
const result = { rigidAxes: this.scaleColumns(scaleInverse, scaleInverse, scaleInverse), scale };
|
|
2287
2490
|
return result;
|
|
2288
2491
|
}
|
|
2289
|
-
/** Test if
|
|
2492
|
+
/** Test if `this` matrix reorders and/or negates the columns of the `identity` matrix. */
|
|
2290
2493
|
get isSignedPermutation() {
|
|
2291
2494
|
let count = 0;
|
|
2292
2495
|
for (let row = 0; row < 3; row++)
|
|
2293
2496
|
for (let col = 0; col < 3; col++) {
|
|
2294
2497
|
const q = this.at(row, col);
|
|
2295
|
-
if (q === 0) {
|
|
2498
|
+
if (q === 0) {
|
|
2499
|
+
// do nothing
|
|
2296
2500
|
}
|
|
2297
2501
|
else if (q === 1 || q === -1) {
|
|
2298
|
-
// the rest of this row and column should be 0.
|
|
2299
|
-
// "at" will apply cyclic indexing.
|
|
2300
2502
|
count++;
|
|
2301
|
-
if
|
|
2302
|
-
|
|
2303
|
-
|
|
2304
|
-
return false;
|
|
2305
|
-
if (this.at(row, col + 1) !== 0)
|
|
2306
|
-
return false;
|
|
2307
|
-
if (this.at(row, col + 2) !== 0)
|
|
2503
|
+
// if the rest of this row and column should be 0 ("at" will apply cyclic indexing)
|
|
2504
|
+
if ((this.at(row + 1, col) !== 0) || (this.at(row + 2, col) !== 0) ||
|
|
2505
|
+
(this.at(row, col + 1) !== 0) || (this.at(row, col + 2) !== 0))
|
|
2308
2506
|
return false;
|
|
2309
2507
|
}
|
|
2310
|
-
else { // entry is not
|
|
2508
|
+
else { // entry is not 0, 1, or -1
|
|
2311
2509
|
return false;
|
|
2312
2510
|
}
|
|
2313
2511
|
}
|
|
2314
2512
|
return count === 3;
|
|
2315
2513
|
}
|
|
2316
|
-
/**
|
|
2317
|
-
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
/** Adjust the matrix in place so that:
|
|
2322
|
-
* * columns are perpendicular and have unit length
|
|
2323
|
-
* * transpose equals inverse
|
|
2324
|
-
* * mirroring is removed
|
|
2514
|
+
/**
|
|
2515
|
+
* Adjust the matrix in place to make is a `rigid` matrix so that:
|
|
2516
|
+
* * columns are perpendicular and have unit length.
|
|
2517
|
+
* * transpose equals inverse.
|
|
2518
|
+
* * mirroring is removed.
|
|
2325
2519
|
* @param axisOrder how to reorder the matrix columns
|
|
2326
|
-
* @return whether the
|
|
2520
|
+
* @return whether the adjusted matrix is `rigid` on return
|
|
2327
2521
|
*/
|
|
2328
2522
|
makeRigid(axisOrder = Geometry_1.AxisOrder.XYZ) {
|
|
2329
2523
|
const maxAbs = this.maxAbs();
|
|
@@ -2344,22 +2538,13 @@ class Matrix3d {
|
|
|
2344
2538
|
return result;
|
|
2345
2539
|
return undefined;
|
|
2346
2540
|
}
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
}
|
|
2355
|
-
else {
|
|
2356
|
-
coff = numerator * reciprocal;
|
|
2357
|
-
}
|
|
2358
|
-
return coff;
|
|
2359
|
-
}
|
|
2360
|
-
/** create a matrix from a quaternion.
|
|
2361
|
-
* **WARNING:** There is frequent confusion over whether a "from quaternion" matrix is organized by rows and columns.
|
|
2362
|
-
* **WARNING:** If you find that the matrix seems to rotate by the opposite angle expect it, transpose it.
|
|
2541
|
+
/**
|
|
2542
|
+
* Create a matrix from a quaternion.
|
|
2543
|
+
* **WARNING:** There is frequent confusion over whether a "from quaternion" matrix is organized by
|
|
2544
|
+
* rows or columns. If you find that the matrix seems to rotate by the opposite angle, transpose it.
|
|
2545
|
+
*
|
|
2546
|
+
* Some math details can be found at
|
|
2547
|
+
* http://marc-b-reynolds.github.io/quaternions/2017/08/08/QuatRotMatrix.html
|
|
2363
2548
|
*/
|
|
2364
2549
|
static createFromQuaternion(quat) {
|
|
2365
2550
|
const qqx = quat.x * quat.x;
|
|
@@ -2372,31 +2557,57 @@ class Matrix3d {
|
|
|
2372
2557
|
}
|
|
2373
2558
|
else {
|
|
2374
2559
|
const a = 1.0 / mag2;
|
|
2375
|
-
const matrix = Matrix3d.createRowValues(
|
|
2560
|
+
const matrix = Matrix3d.createRowValues(
|
|
2561
|
+
// first row
|
|
2562
|
+
a * (qqw + qqx - qqy - qqz), 2.0 * a * (quat.w * quat.z + quat.x * quat.y), 2.0 * a * (quat.x * quat.z - quat.w * quat.y),
|
|
2563
|
+
// second row
|
|
2564
|
+
2.0 * a * (quat.x * quat.y - quat.w * quat.z), a * (qqw - qqx + qqy - qqz), 2.0 * a * (quat.w * quat.x + quat.y * quat.z),
|
|
2565
|
+
// third row
|
|
2566
|
+
2.0 * a * (quat.x * quat.z + quat.w * quat.y), 2.0 * a * (quat.y * quat.z - quat.w * quat.x), a * (qqw - qqx - qqy + qqz));
|
|
2376
2567
|
return matrix;
|
|
2377
2568
|
}
|
|
2378
2569
|
}
|
|
2379
|
-
/** convert
|
|
2380
|
-
|
|
2381
|
-
|
|
2382
|
-
|
|
2570
|
+
/** Calculate quaternion terms used to convert matrix to a quaternion */
|
|
2571
|
+
static computeQuatTerm(numerator, denomCoff, reciprocal, diagSum) {
|
|
2572
|
+
let coff;
|
|
2573
|
+
const diagTol = 0.500;
|
|
2574
|
+
if (diagSum > diagTol) {
|
|
2575
|
+
coff = 0.5 * Math.sqrt(diagSum);
|
|
2576
|
+
if (denomCoff * numerator < 0.0)
|
|
2577
|
+
coff = -coff;
|
|
2578
|
+
}
|
|
2579
|
+
else {
|
|
2580
|
+
coff = numerator * reciprocal;
|
|
2581
|
+
}
|
|
2582
|
+
return coff;
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* Create `this` matrix to a quaternion.
|
|
2586
|
+
* **Note:** This calculation requires `this` matrix to have unit length rows and columns.
|
|
2587
|
+
* **WARNING:** There is frequent confusion over whether a "from quaternion" matrix is organized by
|
|
2588
|
+
* rows or columns. If you find that the matrix seems to rotate by the opposite angle, transpose it.
|
|
2589
|
+
*
|
|
2590
|
+
* Some math details can be found at
|
|
2591
|
+
* http://marc-b-reynolds.github.io/quaternions/2017/08/08/QuatRotMatrix.html
|
|
2383
2592
|
*/
|
|
2384
2593
|
toQuaternion() {
|
|
2385
2594
|
const result = Point4d_1.Point4d.createZero();
|
|
2386
|
-
const props = [
|
|
2595
|
+
const props = [
|
|
2596
|
+
[this.coffs[0], this.coffs[3], this.coffs[6]],
|
|
2387
2597
|
[this.coffs[1], this.coffs[4], this.coffs[7]],
|
|
2388
|
-
[this.coffs[2], this.coffs[5], this.coffs[8]]
|
|
2598
|
+
[this.coffs[2], this.coffs[5], this.coffs[8]],
|
|
2599
|
+
];
|
|
2389
2600
|
const xx = props[0][0];
|
|
2390
2601
|
const yy = props[1][1];
|
|
2391
2602
|
const zz = props[2][2];
|
|
2392
2603
|
const dSum = [];
|
|
2393
|
-
let denom, maxIndex, i;
|
|
2394
2604
|
dSum[0] = 1.0 + xx - yy - zz;
|
|
2395
2605
|
dSum[1] = 1.0 - xx + yy - zz;
|
|
2396
2606
|
dSum[2] = 1.0 - xx - yy + zz;
|
|
2397
2607
|
dSum[3] = 1.0 + xx + yy + zz;
|
|
2398
|
-
|
|
2399
|
-
|
|
2608
|
+
let denom;
|
|
2609
|
+
let maxIndex = 0;
|
|
2610
|
+
for (let i = 1; i <= 3; i++) {
|
|
2400
2611
|
if (dSum[i] > dSum[maxIndex])
|
|
2401
2612
|
maxIndex = i;
|
|
2402
2613
|
}
|
|
@@ -2438,5 +2649,6 @@ Matrix3d.useCachedInverse = true; // cached inverse can be suppressed for testin
|
|
|
2438
2649
|
Matrix3d.numUseCache = 0;
|
|
2439
2650
|
/** Total number of times a cached inverse was computed. */
|
|
2440
2651
|
Matrix3d.numComputeCache = 0;
|
|
2652
|
+
/** temporary buffer to store a matrix as a Float64Array (array of 9 floats) */
|
|
2441
2653
|
Matrix3d._productBuffer = new Float64Array(9);
|
|
2442
2654
|
//# sourceMappingURL=Matrix3d.js.map
|