@itwin/core-geometry 4.0.0-dev.10 → 4.0.0-dev.15

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.
Files changed (34) hide show
  1. package/CHANGELOG.md +10 -1
  2. package/lib/cjs/geometry3d/Angle.d.ts +1 -0
  3. package/lib/cjs/geometry3d/Angle.d.ts.map +1 -1
  4. package/lib/cjs/geometry3d/Angle.js +1 -0
  5. package/lib/cjs/geometry3d/Angle.js.map +1 -1
  6. package/lib/cjs/geometry3d/AngleSweep.d.ts +1 -0
  7. package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
  8. package/lib/cjs/geometry3d/AngleSweep.js +1 -0
  9. package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
  10. package/lib/cjs/geometry3d/Matrix3d.d.ts +161 -96
  11. package/lib/cjs/geometry3d/Matrix3d.d.ts.map +1 -1
  12. package/lib/cjs/geometry3d/Matrix3d.js +245 -206
  13. package/lib/cjs/geometry3d/Matrix3d.js.map +1 -1
  14. package/lib/cjs/geometry3d/Point3dVector3d.d.ts +3 -0
  15. package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
  16. package/lib/cjs/geometry3d/Point3dVector3d.js +3 -0
  17. package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
  18. package/lib/esm/geometry3d/Angle.d.ts +1 -0
  19. package/lib/esm/geometry3d/Angle.d.ts.map +1 -1
  20. package/lib/esm/geometry3d/Angle.js +1 -0
  21. package/lib/esm/geometry3d/Angle.js.map +1 -1
  22. package/lib/esm/geometry3d/AngleSweep.d.ts +1 -0
  23. package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
  24. package/lib/esm/geometry3d/AngleSweep.js +1 -0
  25. package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
  26. package/lib/esm/geometry3d/Matrix3d.d.ts +161 -96
  27. package/lib/esm/geometry3d/Matrix3d.d.ts.map +1 -1
  28. package/lib/esm/geometry3d/Matrix3d.js +245 -206
  29. package/lib/esm/geometry3d/Matrix3d.js.map +1 -1
  30. package/lib/esm/geometry3d/Point3dVector3d.d.ts +3 -0
  31. package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
  32. package/lib/esm/geometry3d/Point3dVector3d.js +3 -0
  33. package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
  34. package/package.json +4 -4
@@ -12,7 +12,7 @@ import { Point2d } from "./Point2dVector2d";
12
12
  import { Point3d, Vector3d } from "./Point3dVector3d";
13
13
  import { Transform } from "./Transform";
14
14
  /* eslint-disable @itwin/prefer-get */
15
- // cSpell:words XXYZ YXYZ ZXYZ
15
+ // cSpell:words XXYZ YXYZ ZXYZ SaeedTorabi
16
16
  /**
17
17
  * PackedMatrix3dOps contains static methods for matrix operations where the matrix is a Float64Array.
18
18
  * * The Float64Array contains the matrix entries in row-major order
@@ -422,9 +422,20 @@ export class Matrix3d {
422
422
  return result;
423
423
  }
424
424
  /**
425
- * Copy the transpose of the coffs to the inverseCoffs.
426
- * * Mark the matrix as inverseStored.
427
- */
425
+ * Create the inverseCoffs member (filled with zeros)
426
+ * This is for use by matrix * matrix multiplications which need to be sure the member is there to be
427
+ * filled with method-specific content.
428
+ */
429
+ createInverseCoffsWithZeros() {
430
+ if (!this.inverseCoffs) {
431
+ this.inverseState = InverseMatrixState.unknown;
432
+ this.inverseCoffs = new Float64Array(9);
433
+ }
434
+ }
435
+ /**
436
+ * Copy the transpose of the coffs to the inverseCoffs.
437
+ * * Mark the matrix as inverseStored.
438
+ */
428
439
  setupInverseTranspose() {
429
440
  const coffs = this.coffs;
430
441
  this.inverseState = InverseMatrixState.inverseStored;
@@ -643,6 +654,7 @@ export class Matrix3d {
643
654
  * Construct a rigid matrix (orthogonal matrix with +1 determinant) using vectorA and its 2 perpendicular.
644
655
  * * If axisOrder is not passed then `AxisOrder = AxisOrder.ZXY` is used as default.
645
656
  * * This function internally uses createPerpendicularVectorFavorXYPlane and createRigidFromColumns.
657
+ * * Visualization can be found at https://www.itwinjs.org/sandbox/SaeedTorabi/2PerpendicularVectorsTo1Vector
646
658
  */
647
659
  static createRigidHeadsUp(vectorA, axisOrder = AxisOrder.ZXY, result) {
648
660
  const vectorB = Matrix3d.createPerpendicularVectorFavorXYPlane(vectorA);
@@ -692,7 +704,7 @@ export class Matrix3d {
692
704
  /**
693
705
  * Replace current rows Ui and Uj with (c*Ui + s*Uj) and (c*Uj - s*Ui).
694
706
  * * There is no checking for i,j being 0,1,2.
695
- * @param i first row index. **must be 0,1,2** (unchecked)
707
+ * @param i first row index. **must be 0,1,2** (unchecked)
696
708
  * @param j second row index. **must be 0,1,2** (unchecked)
697
709
  * @param c fist coefficient
698
710
  * @param s second coefficient
@@ -1392,6 +1404,7 @@ export class Matrix3d {
1392
1404
  * \text{The matrix is } I + (s-1) D D^T
1393
1405
  * \\ \text{with }D\text{ being the normalized direction vector and }s\text{ being the scale.}
1394
1406
  * ```
1407
+ * * Visualization can be found at itwinjs.org/sandbox/SaeedTorabi/DirectionalScale
1395
1408
  */
1396
1409
  static createDirectionalScale(direction, scale, result) {
1397
1410
  const unit = direction.normalize();
@@ -1525,7 +1538,7 @@ export class Matrix3d {
1525
1538
  return result;
1526
1539
  }
1527
1540
  /**
1528
- * Multiply transpose of this matrix times a vector.
1541
+ * Multiply the transpose matrix times a vector.
1529
1542
  * * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
1530
1543
  * ```
1531
1544
  * equation
@@ -1534,7 +1547,7 @@ export class Matrix3d {
1534
1547
  * \text{Treating U as a row to the left of untransposed matrix\: return row}&\rowSubXYZ{V}&=&\rowSubXYZ{U}\matrixXY{A}
1535
1548
  * \end{matrix}
1536
1549
  * ```
1537
- * @return the vector result
1550
+ * @return the vector result (optional)
1538
1551
  */
1539
1552
  multiplyTransposeVector(vector, result) {
1540
1553
  result = result ? result : new Vector3d();
@@ -1546,87 +1559,100 @@ export class Matrix3d {
1546
1559
  result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
1547
1560
  return result;
1548
1561
  }
1549
- /** Multiply the matrix * (x,y,z), i.e. the vector (x,y,z) is a column vector on the right.
1550
- * @return the vector result
1562
+ /**
1563
+ * Multiply the matrix * [x,y,z], i.e. the vector [x,y,z] is a column vector on the right.
1564
+ * @return the vector result (optional)
1551
1565
  */
1552
1566
  multiplyXYZ(x, y, z, result) {
1553
1567
  result = result ? result : new Vector3d();
1554
- result.x = (this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z);
1555
- result.y = (this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z);
1556
- result.z = (this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z);
1568
+ result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
1569
+ result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
1570
+ result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
1557
1571
  return result;
1558
1572
  }
1559
- /** Multiply the matrix * xyz, place result in (required) return value.
1560
- * @param xyz right side
1561
- * @param result result.
1573
+ /**
1574
+ * Multiply the matrix * xyz, place result in (required) return value.
1575
+ * @param xyz right side
1576
+ * @param result the result.
1562
1577
  */
1563
1578
  multiplyXYZtoXYZ(xyz, result) {
1564
1579
  const x = xyz.x;
1565
1580
  const y = xyz.y;
1566
1581
  const z = xyz.z;
1567
- result.x = (this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z);
1568
- result.y = (this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z);
1569
- result.z = (this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z);
1582
+ result.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
1583
+ result.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
1584
+ result.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
1570
1585
  return result;
1571
1586
  }
1572
- /** Multiply the matrix * (x,y,0), i.e. the vector (x,y,z) is a column vector on the right.
1573
- * @return the vector result
1587
+ /**
1588
+ * Multiply the matrix * [x,y,0], i.e. the vector [x,y,0] is a column vector on the right.
1589
+ * @return the vector result (optional)
1574
1590
  */
1575
1591
  multiplyXY(x, y, result) {
1576
1592
  result = result ? result : new Vector3d();
1577
- result.x = (this.coffs[0] * x + this.coffs[1] * y);
1578
- result.y = (this.coffs[3] * x + this.coffs[4] * y);
1579
- result.z = (this.coffs[6] * x + this.coffs[7] * y);
1593
+ result.x = this.coffs[0] * x + this.coffs[1] * y;
1594
+ result.y = this.coffs[3] * x + this.coffs[4] * y;
1595
+ result.z = this.coffs[6] * x + this.coffs[7] * y;
1580
1596
  return result;
1581
1597
  }
1582
- /** compute `origin + this*[x,y,0]` */
1598
+ /**
1599
+ * Compute origin + the matrix * [x,y,0].
1600
+ * @return the vector result (optional)
1601
+ */
1583
1602
  originPlusMatrixTimesXY(origin, x, y, result) {
1584
1603
  return 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);
1585
1604
  }
1586
- /** Multiply matrix * (x, y, z) using any 3d object given containing those members */
1605
+ /**
1606
+ * Multiply the matrix * (x,y,z) in place, i.e. the vector (x,y,z) is a column vector on the right and
1607
+ * the multiplication updates the vector values.
1608
+ * @param xyzData the vector data
1609
+ */
1587
1610
  multiplyVectorInPlace(xyzData) {
1588
1611
  const x = xyzData.x;
1589
1612
  const y = xyzData.y;
1590
1613
  const z = xyzData.z;
1591
- const coffs = this.coffs;
1592
- xyzData.x = (coffs[0] * x + coffs[1] * y + coffs[2] * z);
1593
- xyzData.y = (coffs[3] * x + coffs[4] * y + coffs[5] * z);
1594
- xyzData.z = (coffs[6] * x + coffs[7] * y + coffs[8] * z);
1614
+ xyzData.x = this.coffs[0] * x + this.coffs[1] * y + this.coffs[2] * z;
1615
+ xyzData.y = this.coffs[3] * x + this.coffs[4] * y + this.coffs[5] * z;
1616
+ xyzData.z = this.coffs[6] * x + this.coffs[7] * y + this.coffs[8] * z;
1595
1617
  }
1596
- /** Multiply the transpose matrix times column using any 3d object with x,y,z members.
1597
- * This is equivalent to `multiplyTransposeVector` but always returns the result directly in the input.
1618
+ /**
1619
+ * Multiply the transpose matrix times [x,y,z] in place, i.e. the vector [x,y,z] is a column vector on
1620
+ * the right and the multiplication updates the vector values.
1621
+ * * This is equivalent to `multiplyTransposeVector` but always returns the result directly in the input.
1622
+ * @param xyzData the vector data
1598
1623
  */
1599
1624
  multiplyTransposeVectorInPlace(vectorU) {
1600
1625
  const x = vectorU.x;
1601
1626
  const y = vectorU.y;
1602
1627
  const z = vectorU.z;
1603
- const coffs = this.coffs;
1604
- vectorU.x = (coffs[0] * x + coffs[3] * y + coffs[6] * z);
1605
- vectorU.y = (coffs[1] * x + coffs[4] * y + coffs[7] * z);
1606
- vectorU.z = (coffs[2] * x + coffs[5] * y + coffs[8] * z);
1628
+ vectorU.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
1629
+ vectorU.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
1630
+ vectorU.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
1607
1631
  }
1608
- /** Multiply the transpose matrix times column using individual numeric inputs.
1609
- * * This is equivalent to multiplying with the vector as a row to the left of the plain matrix.
1632
+ /**
1633
+ * Multiply the transpose matrix times column using individual numeric inputs.
1634
+ * * This produces the same x,y,z as treating the vector as a row on the left of the (un-transposed) matrix.
1610
1635
  * ```
1611
1636
  * equation
1612
1637
  * \begin{matrix}
1613
- * \text{treating the input as a column } \columnXYZ{x}{y}{z}\text{ compute }&\columnSubXYZ{V} &= &A^T \columnXYZ{x}{y}{z} \\
1614
- * \text{or row vector } \rowXYZ{x}{y}{z} \text{ compute }&\rowSubXYZ{V} &= &\rowXYZ{x}{y}{z} A \\
1638
+ * \text{treating the input as a column vector } \columnXYZ{x}{y}{z}\text{ compute }&\columnSubXYZ{V} &= &A^T \columnXYZ{x}{y}{z} \\
1639
+ * \text{or as a row vector } \rowXYZ{x}{y}{z} \text{ compute }&\rowSubXYZ{V} &= &\rowXYZ{x}{y}{z} A \\
1615
1640
  * \phantom{8888}\text{and return V as a Vector3d} & & &
1616
1641
  * \end{matrix}
1617
1642
  * ````
1618
- * @return the vector result
1643
+ * @return the vector result (optional)
1619
1644
  */
1620
1645
  multiplyTransposeXYZ(x, y, z, result) {
1621
1646
  result = result ? result : new Vector3d();
1622
- result.x = (this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z);
1623
- result.y = (this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z);
1624
- result.z = (this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z);
1647
+ result.x = this.coffs[0] * x + this.coffs[3] * y + this.coffs[6] * z;
1648
+ result.y = this.coffs[1] * x + this.coffs[4] * y + this.coffs[7] * z;
1649
+ result.z = this.coffs[2] * x + this.coffs[5] * y + this.coffs[8] * z;
1625
1650
  return result;
1626
1651
  }
1627
- /** Solve `matrix * result = vector`.
1628
- * * This is equivalent to multiplication `result = matrixInverse * vector`.
1629
- * * Result is undefined if the matrix is singular (e.g. has parallel or zero length columns)
1652
+ /**
1653
+ * Solve `matrix * result = vector` for an unknown `result`.
1654
+ * * This is equivalent to multiplication `result = inverse matrix * vector`.
1655
+ * * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
1630
1656
  */
1631
1657
  multiplyInverse(vector, result) {
1632
1658
  this.computeCachedInverse(true);
@@ -1634,13 +1660,14 @@ export class Matrix3d {
1634
1660
  const x = vector.x;
1635
1661
  const y = vector.y;
1636
1662
  const z = vector.z;
1637
- return 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);
1663
+ return 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);
1638
1664
  }
1639
1665
  return undefined;
1640
1666
  }
1641
- /** Solve `matrixTranspose * result = vector`.
1667
+ /**
1668
+ * Solve `matrixTranspose * result = vector` for an unknown `result`.
1642
1669
  * * This is equivalent to multiplication `result = matrixInverseTranspose * vector`.
1643
- * * Result is undefined if the matrix is singular (e.g. has parallel or zero length columns)
1670
+ * * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
1644
1671
  */
1645
1672
  multiplyInverseTranspose(vector, result) {
1646
1673
  this.computeCachedInverse(true);
@@ -1648,87 +1675,91 @@ export class Matrix3d {
1648
1675
  const x = vector.x;
1649
1676
  const y = vector.y;
1650
1677
  const z = vector.z;
1651
- return 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);
1678
+ return 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);
1652
1679
  }
1653
1680
  return undefined;
1654
1681
  }
1655
1682
  /**
1656
- * multiply `matrixInverse * [x,y,z]`.
1657
- * * This is equivalent to solving `matrix * result = [x,y,z]`
1658
- * * return as a Vector3d, or undefined if the matrix is singular.
1683
+ * Multiply `matrixInverse * [x,y,z]`.
1684
+ * * This is equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
1685
+ * * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
1686
+ * @return result as a Vector3d or undefined (if the matrix is singular).
1659
1687
  */
1660
1688
  multiplyInverseXYZAsVector3d(x, y, z, result) {
1661
1689
  this.computeCachedInverse(true);
1662
1690
  if (this.inverseCoffs) {
1663
- return 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);
1691
+ return 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);
1664
1692
  }
1665
1693
  return undefined;
1666
1694
  }
1667
1695
  /**
1668
- * multiply `matrixInverse * [x,y,z]` and return packaged as `Point4d` with given weight.
1669
- * * Equivalent to solving matrix * result = [x,y,z]
1670
- * * return as a Point4d with the same weight.
1671
- * * Called by Transform with x,y,z adjusted by subtraction ((xw) - w * origin.x, etc) where xw is the pre-weighted space point.
1696
+ * Multiply `matrixInverse * [x,y,z]` and return result as `Point4d` with given weight.
1697
+ * * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
1698
+ * * Result is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
1699
+ * @return result as a Point4d with the same weight.
1672
1700
  */
1673
1701
  multiplyInverseXYZW(x, y, z, w, result) {
1674
1702
  this.computeCachedInverse(true);
1675
1703
  if (this.inverseCoffs) {
1676
- return 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);
1704
+ return 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);
1677
1705
  }
1678
1706
  return undefined;
1679
1707
  }
1680
1708
  /**
1681
- * multiply `matrixInverse * [x,y,z]` and return packaged as `Point3d`.
1682
- * * multiply matrixInverse * [x,y,z]
1683
- * * Equivalent to solving matrix * result = [x,y,z]
1684
- * * return as a Point3d.
1709
+ * Multiply `matrixInverse * [x,y,z]` and return result as `Point3d`.
1710
+ * * Equivalent to solving `matrix * result = [x,y,z]` for an unknown `result`.
1711
+ * @return result as a Point3d or undefined (if the matrix is singular).
1685
1712
  */
1686
1713
  multiplyInverseXYZAsPoint3d(x, y, z, result) {
1687
1714
  this.computeCachedInverse(true);
1688
1715
  if (this.inverseCoffs) {
1689
- return 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);
1716
+ return 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);
1690
1717
  }
1691
1718
  return undefined;
1692
1719
  }
1693
1720
  /**
1694
- * * invoke a given matrix-matrix operation (product function) to compute this.inverseCOffs
1695
- * * set this.inverseCoffs
1696
- * * if either input cffA or coffB is undefined, set state to `InverseMatrixState.unknown` (but leave the inverseCoffs untouched)
1721
+ * Invoke a given matrix*matrix operation to compute the inverse matrix and set this.inverseCoffs
1722
+ * * If either input coffA or coffB is undefined, set state to `InverseMatrixState.unknown` but
1723
+ * leave the inverseCoffs untouched.
1724
+ * @param f the given matrix*matrix operation that is called by this function to compute the inverse.
1725
+ * `f` must be a matrix*matrix operation. Otherwise, the function does not generate the inverse properly.
1697
1726
  */
1698
1727
  finishInverseCoffs(f, coffA, coffB) {
1699
1728
  if (coffA && coffB) {
1700
1729
  this.createInverseCoffsWithZeros();
1701
1730
  this.inverseState = InverseMatrixState.inverseStored;
1702
- f(coffA, coffB, this.inverseCoffs);
1731
+ f(coffA, coffB, this.inverseCoffs); // call function f (which is provided by user) to compute the inverse.
1703
1732
  }
1704
1733
  else {
1705
1734
  this.inverseState = InverseMatrixState.unknown;
1706
1735
  }
1707
1736
  }
1708
- /*
1709
- Notes on inverses of products
1710
- * 1) M = A * B MInverse = BInverse * AInverse
1711
- * 2) M = A * BInverse MInverse = B * AInverse
1712
- * 3) M = AInverse * B MInverse = BInverse * A
1713
- * 4) M = ATranspose * B MInverse = BInverse * AInverseTranspose
1714
- * 5) M = A * BTranspose MInverse = BInverseTranspose * AInverse
1715
- */
1716
- /** Multiply the instance matrix A by the input matrix B.
1717
- * @return the matrix product A * B
1737
+ // Notes on inverse of matrix products:
1738
+ // 1) M = A * B ===> MInverse = BInverse * AInverse
1739
+ // 2) M = A * BInverse ===> MInverse = B * AInverse
1740
+ // 3) M = AInverse * B ===> MInverse = BInverse * A
1741
+ // 4) M = A * BTranspose ===> MInverse = BInverseTranspose * AInverse
1742
+ // 5) M = ATranspose * B ===> MInverse = BInverse * AInverseTranspose
1743
+ /**
1744
+ * Multiply `this` matrix times `other` matrix
1745
+ * @return the matrix result: this*other
1718
1746
  */
1719
1747
  multiplyMatrixMatrix(other, result) {
1720
1748
  result = result ? result : new Matrix3d();
1721
1749
  PackedMatrix3dOps.multiplyMatrixMatrix(this.coffs, other.coffs, result.coffs);
1722
- if (this.inverseState === InverseMatrixState.inverseStored && other.inverseState === InverseMatrixState.inverseStored)
1750
+ if (this.inverseState === InverseMatrixState.inverseStored
1751
+ && other.inverseState === InverseMatrixState.inverseStored)
1723
1752
  result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixMatrix, other.inverseCoffs, this.inverseCoffs);
1724
- else if (this.inverseState === InverseMatrixState.singular || other.inverseState === InverseMatrixState.singular)
1753
+ else if (this.inverseState === InverseMatrixState.singular
1754
+ || other.inverseState === InverseMatrixState.singular)
1725
1755
  result.inverseState = InverseMatrixState.singular;
1726
1756
  else
1727
1757
  result.inverseState = InverseMatrixState.unknown;
1728
1758
  return result;
1729
1759
  }
1730
- /** Multiply this matrix times inverse of other
1731
- * @return the matrix result
1760
+ /**
1761
+ * Multiply `this` matrix times `inverse of other` matrix
1762
+ * @return the matrix result: this*otherInverse
1732
1763
  */
1733
1764
  multiplyMatrixMatrixInverse(other, result) {
1734
1765
  if (!other.computeCachedInverse(true))
@@ -1742,8 +1773,9 @@ export class Matrix3d {
1742
1773
  PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
1743
1774
  return result;
1744
1775
  }
1745
- /** Multiply this matrix times inverse of other
1746
- * @return the matrix result
1776
+ /**
1777
+ * Multiply `inverse of this` matrix times `other` matrix
1778
+ * @return the matrix result: thisInverse*other
1747
1779
  */
1748
1780
  multiplyMatrixInverseMatrix(other, result) {
1749
1781
  if (!this.computeCachedInverse(true))
@@ -1757,30 +1789,32 @@ export class Matrix3d {
1757
1789
  PackedMatrix3dOps.copy(Matrix3d._productBuffer, result.coffs);
1758
1790
  return result;
1759
1791
  }
1760
- /** Multiply `this` matrix times the transpose of `matrixB`.
1792
+ /**
1793
+ * Multiply `this` matrix times the transpose of `other` matrix
1761
1794
  * ```
1762
1795
  * equation
1763
- * \text{for instance matrix }A\text{ and other matrix }B\text{ return matrix }C{\text where }\\\matrixXY{C}=\matrixXY{A}\matrixTransposeSubXY{B}
1796
+ * \text{for instance matrix }A\text{ and matrix }B\text{ return matrix }C{\text where }\\\matrixXY{C}=\matrixXY{A}\matrixTransposeSubXY{B}
1764
1797
  * ```
1765
- * @return the matrix result
1798
+ * @return the matrix result: this*otherTranspose
1766
1799
  */
1767
- multiplyMatrixMatrixTranspose(matrixB, result) {
1800
+ multiplyMatrixMatrixTranspose(other, result) {
1768
1801
  result = result ? result : new Matrix3d();
1769
- PackedMatrix3dOps.multiplyMatrixMatrixTranspose(this.coffs, matrixB.coffs, result.coffs);
1770
- if (this.inverseState === InverseMatrixState.inverseStored && matrixB.inverseState === InverseMatrixState.inverseStored)
1771
- result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixTransposeMatrix, matrixB.inverseCoffs, this.inverseCoffs);
1772
- else if (this.inverseState === InverseMatrixState.singular || matrixB.inverseState === InverseMatrixState.singular)
1802
+ PackedMatrix3dOps.multiplyMatrixMatrixTranspose(this.coffs, other.coffs, result.coffs);
1803
+ if (this.inverseState === InverseMatrixState.inverseStored && other.inverseState === InverseMatrixState.inverseStored)
1804
+ result.finishInverseCoffs(PackedMatrix3dOps.multiplyMatrixTransposeMatrix, other.inverseCoffs, this.inverseCoffs);
1805
+ else if (this.inverseState === InverseMatrixState.singular || other.inverseState === InverseMatrixState.singular)
1773
1806
  result.inverseState = InverseMatrixState.singular;
1774
1807
  else
1775
1808
  result.inverseState = InverseMatrixState.unknown;
1776
1809
  return result;
1777
1810
  }
1778
- /** Matrix multiplication `thisTranspose * other`.
1811
+ /**
1812
+ * Multiply the transpose of `this` matrix times `other` matrix
1779
1813
  * ```
1780
1814
  * equation
1781
1815
  * \matrixXY{result}=\matrixXY{\text{this}}\matrixTransposeSubXY{\text{other}}
1782
1816
  * ```
1783
- * @return the matrix result
1817
+ * @return the matrix result: thisTranspose*other
1784
1818
  */
1785
1819
  multiplyMatrixTransposeMatrix(other, result) {
1786
1820
  result = result ? result : new Matrix3d();
@@ -1793,30 +1827,31 @@ export class Matrix3d {
1793
1827
  result.inverseState = InverseMatrixState.unknown;
1794
1828
  return result;
1795
1829
  }
1796
- /** multiply this Matrix3d (considered as a transform with 0 translation) times other Transform.
1830
+ /**
1831
+ * Multiply `this` Matrix3d (considered as a Transform with 0 translation) times `other` Transform.
1797
1832
  * ```
1798
1833
  * equation
1799
1834
  * \begin{matrix}
1800
- * \text{This matrix }\bold{A}\text{ promoted to block transform} & \blockTransform{A}{0} \\
1801
- * \text{other transform with matrix part }\bold{B}\text{ and translation }\bold{b} & \blockTransform{B}{b}\\
1835
+ * \text{This matrix }\bold{A}\text{ promoted to block transform} & \blockTransform{A}{0} \\
1836
+ * \text{other transform with matrix part }\bold{B}\text{ and translation }\bold{b} & \blockTransform{B}{b}\\
1802
1837
  * \text{product}& \blockTransform{A}{0}\blockTransform{B}{b}=\blockTransform{AB}{Ab}
1803
1838
  * \end{matrix}
1804
1839
  * ```
1805
- * @param other right hand Matrix3d for multiplication.
1806
- * @param result optional preallocated result to reuse.
1840
+ * @param other Right hand Matrix3d for multiplication.
1841
+ * @param result the Transform result (optional)
1807
1842
  */
1808
1843
  multiplyMatrixTransform(other, result) {
1809
1844
  if (!result)
1810
1845
  return Transform.createRefs(this.multiplyXYZ(other.origin.x, other.origin.y, other.origin.z), this.multiplyMatrixMatrix(other.matrix));
1811
- // be sure to do the point multiplication first before aliasing changes the matrix ..
1846
+ // be sure to do the point multiplication first before aliasing changes the matrix
1812
1847
  this.multiplyXYZtoXYZ(other.origin, result.origin);
1813
1848
  this.multiplyMatrixMatrix(other.matrix, result.matrix);
1814
1849
  return result;
1815
1850
  }
1816
1851
  /**
1817
1852
  * Return the transpose of `this` matrix.
1818
- * If `result` is passed as argument, then the function copies the transpose of `this` into `result`
1819
- * `this` is not changed unless also passed as the result, i.e., this.transpose(this) transposes `this` in place
1853
+ * * If `result` is passed as argument, then the function copies the transpose of `this` into `result`.
1854
+ * * `this` is not changed unless also passed as the result, i.e., `this.transpose(this)` transposes `this` in place.
1820
1855
  */
1821
1856
  transpose(result) {
1822
1857
  if (!result)
@@ -1838,18 +1873,22 @@ export class Matrix3d {
1838
1873
  transposeInPlace() {
1839
1874
  PackedMatrix3dOps.transposeInPlace(this.coffs);
1840
1875
  if (this.inverseCoffs)
1841
- PackedMatrix3dOps.transposeInPlace(this.inverseCoffs);
1876
+ PackedMatrix3dOps.transposeInPlace(this.inverseCoffs); // inverse of transpose is equal to transpose of inverse
1842
1877
  }
1843
- /** return the inverse matrix.
1844
- * The return is undefined if the matrix is singular (has columns that are coplanar or colinear)
1845
- * * Note that each Matrix3d object caches its own inverse, and has methods to multiply the inverse times matrices and vectors.
1846
- * * Hence explicitly constructing this new inverse object is rarely necessary.
1878
+ /**
1879
+ * Return the inverse matrix.
1880
+ * The return is undefined if the matrix is singular (e.g. has parallel columns or a zero magnitude column)
1881
+ * * If `result == this`, then content of inverse of `this` matrix is copied into `this`. Otherwise, inverse
1882
+ * of `this` is stored in `result`.
1883
+ * * **Note:** Each Matrix3d object caches its own inverse (`this.inverseCoffs`) and has methods to multiply
1884
+ * the inverse times matrices and vectors (e.g., `multiplyMatrixInverseMatrix`, `multiplyMatrixMatrixInverse`,
1885
+ * `multiplyInverse`). Hence explicitly constructing this new inverse object is rarely necessary.
1847
1886
  */
1848
1887
  inverse(result) {
1849
1888
  if (!this.computeCachedInverse(true))
1850
1889
  return undefined;
1851
1890
  if (result === this) {
1852
- // swap the contents (preserve pointers .. caller better know what they are doing)
1891
+ // swap the contents of this.coffs and this.inverseCoffs
1853
1892
  PackedMatrix3dOps.copy(this.coffs, Matrix3d._productBuffer);
1854
1893
  PackedMatrix3dOps.copy(this.inverseCoffs, this.coffs);
1855
1894
  PackedMatrix3dOps.copy(Matrix3d._productBuffer, this.inverseCoffs);
@@ -1864,33 +1903,48 @@ export class Matrix3d {
1864
1903
  result.inverseState = this.inverseState;
1865
1904
  return result;
1866
1905
  }
1867
- /* Alternate implementation of computedCachedInverse - more direct addressing of arrays.
1868
- This is indeed 10% faster than using static work areas. */
1869
- // take the cross product of two rows of source.
1870
- // store as a column of dest.
1906
+ /**
1907
+ * Take the dot product of a row (specified by `rowStartA`) of `coffA` and `columnStartB` of `coffB`.
1908
+ * * **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.
1909
+ */
1910
+ static rowColumnDot(coffA, rowStartA, coffB, columnStartB) {
1911
+ return coffA[rowStartA] * coffB[columnStartB] +
1912
+ coffA[rowStartA + 1] * coffB[columnStartB + 3] +
1913
+ coffA[rowStartA + 2] * coffB[columnStartB + 6];
1914
+ }
1915
+ /**
1916
+ * Take the cross product of 2 rows (specified by `rowStart0` and `rowStart1`) of `source` and store the result
1917
+ * in `columnStart` of `dest`.
1918
+ * * **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.
1919
+ */
1871
1920
  static indexedRowCrossProduct(source, rowStart0, rowStart1, dest, columnStart) {
1872
1921
  dest[columnStart] = source[rowStart0 + 1] * source[rowStart1 + 2] - source[rowStart0 + 2] * source[rowStart1 + 1];
1873
1922
  dest[columnStart + 3] = source[rowStart0 + 2] * source[rowStart1] - source[rowStart0] * source[rowStart1 + 2];
1874
1923
  dest[columnStart + 6] = source[rowStart0] * source[rowStart1 + 1] - source[rowStart0 + 1] * source[rowStart1];
1875
1924
  }
1876
- // take the cross product of two columns of source.
1877
- // store as third column in same Matrix3d.
1878
- // This is private because the columnStart values are unchecked raw indices into the coffs
1925
+ /**
1926
+ * Take the cross product of 2 columns (i.e., `colStart0` and `colStart1`) of `this` matrix and store the
1927
+ * result in `colStart2` of the same matrix.
1928
+ * * **Note:** We don't validate column numbers. Pass 0/1/2 for column 0/1/2.
1929
+ */
1879
1930
  indexedColumnCrossProductInPlace(colStart0, colStart1, colStart2) {
1880
1931
  const coffs = this.coffs;
1881
1932
  coffs[colStart2] = coffs[colStart0 + 3] * coffs[colStart1 + 6] - coffs[colStart0 + 6] * coffs[colStart1 + 3];
1882
1933
  coffs[colStart2 + 3] = coffs[colStart0 + 6] * coffs[colStart1] - coffs[colStart0] * coffs[colStart1 + 6];
1883
1934
  coffs[colStart2 + 6] = coffs[colStart0] * coffs[colStart1 + 3] - coffs[colStart0 + 3] * coffs[colStart1];
1884
1935
  }
1885
- /** Form cross products among columns in axisOrder.
1886
- * For axis order ABC,
1887
- * * form cross product of column A and B, store in C
1936
+ /**
1937
+ * Form cross products among columns in axisOrder.
1938
+ * For axis order ABC:
1939
+ * * form cross product of column A and B, store in C.
1888
1940
  * * form cross product of column C and A, store in B.
1941
+ * * [A B C] ===> [A B AxB] ===> [A (AxB)xA AxB]
1942
+ *
1889
1943
  * This means that in the final matrix:
1890
- * * column A is strictly parallel to original column A
1891
- * * column B is linear combination of only original A and B
1944
+ * * column A is same as original column A.
1945
+ * * column B is linear combination of original A and B (i.e., is in the plane of original A and B).
1892
1946
  * * column C is perpendicular to A and B of both the original and final.
1893
- * * original column C does not participate in the result.
1947
+ * * original column C is overwritten and does not participate in the result.
1894
1948
  */
1895
1949
  axisOrderCrossProductsInPlace(axisOrder) {
1896
1950
  switch (axisOrder) {
@@ -1926,41 +1980,44 @@ export class Matrix3d {
1926
1980
  }
1927
1981
  }
1928
1982
  }
1929
- /** Normalize each column in place.
1930
- * * For false return the magnitudes are stored in the originalMagnitudes vector but no columns are altered.
1931
- * @returns Return true if all columns had nonzero lengths.
1932
- * @param originalMagnitudes optional vector to receive original column magnitudes.
1983
+ /**
1984
+ * Normalize each column in place.
1985
+ * @param originalRowMagnitudes optional vector to store original column magnitudes.
1986
+ * @returns Return true if all columns have non-zero lengths. Otherwise, return false.
1987
+ * * If false is returned, the magnitudes are stored in the `originalRowMagnitudes` vector but no columns
1988
+ * are altered.
1933
1989
  */
1934
- normalizeColumnsInPlace(originalMagnitudes) {
1990
+ normalizeColumnsInPlace(originalRowMagnitudes) {
1935
1991
  const ax = this.columnXMagnitude();
1936
1992
  const ay = this.columnYMagnitude();
1937
1993
  const az = this.columnZMagnitude();
1938
- if (originalMagnitudes)
1939
- originalMagnitudes.set(ax, ay, az);
1994
+ if (originalRowMagnitudes)
1995
+ originalRowMagnitudes.set(ax, ay, az);
1940
1996
  if (Geometry.isSmallMetricDistance(ax) || Geometry.isSmallMetricDistance(ay) || Geometry.isSmallMetricDistance(az))
1941
1997
  return false;
1942
1998
  this.scaleColumns(1.0 / ax, 1.0 / ay, 1.0 / az, this);
1943
1999
  return true;
1944
2000
  }
1945
- /** Normalize each row in place */
1946
- normalizeRowsInPlace(originalMagnitudes) {
2001
+ /**
2002
+ * Normalize each row in place.
2003
+ * @param originalColumnMagnitudes optional vector to store original row magnitudes.
2004
+ * @returns Return true if all rows have non-zero lengths. Otherwise, return false.
2005
+ * * If false is returned, the magnitudes are stored in the `originalColumnMagnitudes` vector but no rows
2006
+ * are altered.
2007
+ */
2008
+ normalizeRowsInPlace(originalColumnMagnitudes) {
1947
2009
  const ax = this.rowXMagnitude();
1948
2010
  const ay = this.rowYMagnitude();
1949
2011
  const az = this.rowZMagnitude();
1950
- if (originalMagnitudes)
1951
- originalMagnitudes.set(ax, ay, az);
2012
+ if (originalColumnMagnitudes)
2013
+ originalColumnMagnitudes.set(ax, ay, az);
1952
2014
  if (Geometry.isSmallMetricDistance(ax) || Geometry.isSmallMetricDistance(ay) || Geometry.isSmallMetricDistance(az))
1953
2015
  return false;
1954
2016
  this.scaleRows(1.0 / ax, 1.0 / ay, 1.0 / az, this);
1955
2017
  return true;
1956
2018
  }
1957
- // take the cross product of two rows of source.
1958
- // store as a column of dest.
1959
- static rowColumnDot(coffA, rowStartA, coffB, columnStartB) {
1960
- return coffA[rowStartA] * coffB[columnStartB] + coffA[rowStartA + 1] * coffB[columnStartB + 3] + coffA[rowStartA + 2] * coffB[columnStartB + 6];
1961
- }
1962
2019
  /**
1963
- * Returns true if the matrix is singular (i.e. collapses data to a plane, line, or point)
2020
+ * Returns true if the matrix is singular.
1964
2021
  */
1965
2022
  isSingular() {
1966
2023
  return !this.computeCachedInverse(true);
@@ -1972,18 +2029,10 @@ export class Matrix3d {
1972
2029
  this.inverseState = InverseMatrixState.singular;
1973
2030
  }
1974
2031
  /**
1975
- * Create the inverseCoffs member (filled with zeros)
1976
- * This is for use by matrix * matrix multiplications which need to be sure the member is there to be
1977
- * filled with method-specific content.
1978
- */
1979
- createInverseCoffsWithZeros() {
1980
- if (!this.inverseCoffs) {
1981
- this.inverseState = InverseMatrixState.unknown;
1982
- this.inverseCoffs = new Float64Array(9);
1983
- }
1984
- }
1985
- /** compute the inverse of this Matrix3d. The inverse is stored for later use.
1986
- * @returns Return true if the inverse computed. (False if the columns collapse to a point, line or plane.)
2032
+ * Compute the inverse of `this` Matrix3d. The inverse is stored in `this.inverseCoffs` for later use.
2033
+ * @param useCacheIfAvailable if `true`, use the previously computed inverse if available. If `false`,
2034
+ * recompute the inverse.
2035
+ * @returns Return `true` if the inverse is computed. Return `false` if matrix is singular.
1987
2036
  */
1988
2037
  computeCachedInverse(useCacheIfAvailable) {
1989
2038
  if (useCacheIfAvailable && Matrix3d.useCachedInverse && this.inverseState !== InverseMatrixState.unknown) {
@@ -1994,71 +2043,45 @@ export class Matrix3d {
1994
2043
  this.createInverseCoffsWithZeros();
1995
2044
  const coffs = this.coffs;
1996
2045
  const inverseCoffs = this.inverseCoffs;
1997
- Matrix3d.indexedRowCrossProduct(coffs, 3, 6, inverseCoffs, 0);
1998
- Matrix3d.indexedRowCrossProduct(coffs, 6, 0, inverseCoffs, 1);
1999
- Matrix3d.indexedRowCrossProduct(coffs, 0, 3, inverseCoffs, 2);
2046
+ /**
2047
+ * We calculate the inverse using cross products.
2048
+ * Math details can be found at
2049
+ * https://www.chilimath.com/lessons/advanced-algebra/determinant-3x3-matrix/
2050
+ * In summary, if M = [A B C] then inverse of M = (1/det)[BxC CxA AxB] where det is the
2051
+ * determinant of matrix M and can be calculated by "A dot BxC".
2052
+ */
2053
+ Matrix3d.indexedRowCrossProduct(coffs, 3, 6, inverseCoffs, 0); // BxC
2054
+ Matrix3d.indexedRowCrossProduct(coffs, 6, 0, inverseCoffs, 1); // CxA
2055
+ Matrix3d.indexedRowCrossProduct(coffs, 0, 3, inverseCoffs, 2); // AxB
2000
2056
  Matrix3d.numComputeCache++;
2001
- const d = Matrix3d.rowColumnDot(coffs, 0, inverseCoffs, 0);
2002
- if (d === 0.0) { // better test?
2057
+ const det = Matrix3d.rowColumnDot(coffs, 0, inverseCoffs, 0); // A dot BxC
2058
+ if (det === 0.0) {
2003
2059
  this.inverseState = InverseMatrixState.singular;
2004
2060
  this.inverseCoffs = undefined;
2005
2061
  return false;
2006
2062
  }
2007
- const f = 1.0 / d;
2063
+ const f = 1.0 / det;
2008
2064
  for (let i = 0; i < 9; i++)
2009
2065
  inverseCoffs[i] *= f;
2010
2066
  this.inverseState = InverseMatrixState.inverseStored;
2011
- // verify inverse
2012
- // const p = new Float64Array(9);
2013
- // for (let i = 0; i < 9; i += 3)
2014
- // for (let j = 0; j < 3; j++)
2015
- // p[i + j] = Matrix3d.rowColumnDot (coffs, i, inverseCoffs, j);
2016
2067
  return true;
2017
2068
  }
2018
- /* "Classic" inverse implementation with temporary vectors.
2019
- private static rowX: Vector3d = Vector3d.create();
2020
- private static rowY: Vector3d = Vector3d.create();
2021
- private static rowZ: Vector3d = Vector3d.create();
2022
- private static crossXY: Vector3d = Vector3d.create();
2023
- private static crossZX: Vector3d = Vector3d.create();
2024
- private static crossYZ: Vector3d = Vector3d.create();
2025
- private computeCachedInverse(useCacheIfAvailable: boolean) {
2026
- if (useCacheIfAvailable && Matrix3d.useCachedInverse && this.inverseState !== InverseMatrixState.unknown) {
2027
- Matrix3d.numUseCache++;
2028
- return this.inverseState === InverseMatrixState.inverseStored;
2029
- }
2030
- this.inverseState = InverseMatrixState.unknown;
2031
- Matrix3d.numComputeCache++;
2032
- const rowX = this.rowX(Matrix3d.rowX);
2033
- const rowY = this.rowY(Matrix3d.rowY);
2034
- const rowZ = this.rowZ(Matrix3d.rowZ);
2035
- const crossXY = rowX.crossProduct(rowY, Matrix3d.crossXY);
2036
- const crossYZ = rowY.crossProduct(rowZ, Matrix3d.crossYZ);
2037
- const crossZX = rowZ.crossProduct(rowX, Matrix3d.crossZX);
2038
- const d = rowX.dotProduct(crossYZ); // that's the determinant
2039
- if (d === 0.0) { // better test?
2040
- this.inverseState = InverseMatrixState.singular;
2041
- this.inverseCoffs = undefined;
2042
- return false;
2043
- }
2044
- const f = 1.0 / d;
2045
- this.inverseState = InverseMatrixState.inverseStored; // Currently just lists that the inverse has been stored... singular case not handled
2046
- this.inverseCoffs = Float64Array.from([crossYZ.x * f, crossZX.x * f, crossXY.x * f,
2047
- crossYZ.y * f, crossZX.y * f, crossXY.y * f,
2048
- crossYZ.z * f, crossZX.z * f, crossXY.z * f]);
2049
- return true;
2050
- }
2051
- */
2052
- /** convert a (row,column) index pair to the single index within flattened array of 9 numbers in row-major-order */
2069
+ /**
2070
+ * Convert a (row,column) index pair to the single index within flattened array of 9 numbers in row-major-order
2071
+ * * **Note:** Out of range row/column is interpreted cyclically.
2072
+ */
2053
2073
  static flatIndexOf(row, column) {
2054
2074
  return 3 * Geometry.cyclic3dAxis(row) + Geometry.cyclic3dAxis(column);
2055
2075
  }
2056
- /** Get a column by index (0,1,2), packaged as a Point4d with given weight. Out of range index is interpreted cyclically. */
2076
+ /**
2077
+ * Get elements of column `index` packaged as a Point4d with given `weight`.
2078
+ * * **Note:** Out of range index is interpreted cyclically.
2079
+ */
2057
2080
  indexedColumnWithWeight(index, weight, result) {
2058
2081
  index = Geometry.cyclic3dAxis(index);
2059
2082
  return Point4d.create(this.coffs[index], this.coffs[index + 3], this.coffs[index + 6], weight, result);
2060
2083
  }
2061
- /** return the entry at specific row and column */
2084
+ /** Return the entry at specific row and column */
2062
2085
  at(row, column) {
2063
2086
  return this.coffs[Matrix3d.flatIndexOf(row, column)];
2064
2087
  }
@@ -2092,7 +2115,7 @@ export class Matrix3d {
2092
2115
  this.coffs[7] *= scaleY;
2093
2116
  this.coffs[8] *= scaleZ;
2094
2117
  if (this.inverseState === InverseMatrixState.inverseStored && this.inverseCoffs !== undefined) {
2095
- // apply reverse scales to the ROWS of the inverse
2118
+ // apply reciprocal scales to the ROWS of the inverse
2096
2119
  const divX = Geometry.conditionalDivideFraction(1.0, scaleX);
2097
2120
  const divY = Geometry.conditionalDivideFraction(1.0, scaleY);
2098
2121
  const divZ = Geometry.conditionalDivideFraction(1.0, scaleZ);
@@ -2168,12 +2191,11 @@ export class Matrix3d {
2168
2191
  /**
2169
2192
  * Create a rigid matrix (columns and rows are unit length and pairwise perpendicular) for
2170
2193
  * the given eye coordinate.
2171
- * * column z is parallel to x,y,z
2172
- * * column x is perpendicular to column z and is in the xy plane
2173
- * * column y is perpendicular to both. It is the "up" vector on the view plane.
2194
+ * * column 2 is parallel to (x,y,z).
2195
+ * * column 0 is perpendicular to column 2 and is in the xy plane.
2196
+ * * column 1 is perpendicular to both. It is the "up" vector on the view plane.
2174
2197
  * * Multiplying the returned matrix times a local (view) vector gives the world vector.
2175
- * * Multiplying transpose of the returned matrix times a world vector gives the local
2176
- * (view) vector.
2198
+ * * Multiplying transpose of the returned matrix times a world vector gives the local (view) vector.
2177
2199
  * @param x eye x coordinate
2178
2200
  * @param y eye y coordinate
2179
2201
  * @param z eye z coordinate
@@ -2188,11 +2210,27 @@ export class Matrix3d {
2188
2210
  result.scaleColumnsInPlace(1.0, -1.0, -1.0);
2189
2211
  }
2190
2212
  else {
2213
+ // if coordinate is (x,y,0), i.e., Front or Back or Left or Right view
2214
+ /**
2215
+ * The matrix that the "else" statement creates is
2216
+ * [-s -s1*c c1*c]
2217
+ * [c -s1*s c1*s]
2218
+ * [0 c1 s1 ]
2219
+ * where
2220
+ * c = x / sqrt(x*x + y*y)
2221
+ * s = y / sqrt(x*x + y*y)
2222
+ * c1 = sqrt(x*x + y*y) / sqrt(x*x + y*y + z*z)
2223
+ * s1 = z / sqrt(x*x + y*y + z*z)
2224
+ *
2225
+ * This is an orthogonal matrix meaning it rotates the standard XYZ axis to ABC axis system
2226
+ * (if matrix is [A B C]). The matrix rotates (0,0,1), i.e., the default Top view or Z axis,
2227
+ * to the eye point (x/r,y/r,z/r). The matrix also rotates (1,0,0) to a point on XY plane.
2228
+ */
2191
2229
  const c = x / rxy;
2192
2230
  const s = y / rxy;
2193
- // if coordinate is (x,y,0), i.e., Front or Back or Left or Right view
2231
+ // 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)
2194
2232
  result.setRowValues(-s, 0, c, c, 0, s, 0, 1, 0);
2195
- // if coordinate is (x,y,z), i.e., other views such as Iso or RightIso
2233
+ // if coordinate is (x,y,z) and z is not 0, i.e., other views such as Iso or RightIso
2196
2234
  if (z !== 0.0) {
2197
2235
  const r = Geometry.hypotenuseXYZ(x, y, z);
2198
2236
  const s1 = z / r;
@@ -2464,5 +2502,6 @@ Matrix3d.useCachedInverse = true; // cached inverse can be suppressed for testin
2464
2502
  Matrix3d.numUseCache = 0;
2465
2503
  /** Total number of times a cached inverse was computed. */
2466
2504
  Matrix3d.numComputeCache = 0;
2505
+ /** temporary buffer to store a matrix as a Float64Array (array of 9 floats) */
2467
2506
  Matrix3d._productBuffer = new Float64Array(9);
2468
2507
  //# sourceMappingURL=Matrix3d.js.map