@itwin/core-geometry 4.0.0-dev.63 → 4.0.0-dev.68

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 (53) hide show
  1. package/lib/cjs/Geometry.d.ts +367 -243
  2. package/lib/cjs/Geometry.d.ts.map +1 -1
  3. package/lib/cjs/Geometry.js +481 -311
  4. package/lib/cjs/Geometry.js.map +1 -1
  5. package/lib/cjs/clipping/ConvexClipPlaneSet.d.ts +6 -4
  6. package/lib/cjs/clipping/ConvexClipPlaneSet.d.ts.map +1 -1
  7. package/lib/cjs/clipping/ConvexClipPlaneSet.js +9 -7
  8. package/lib/cjs/clipping/ConvexClipPlaneSet.js.map +1 -1
  9. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.d.ts +5 -3
  10. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.d.ts.map +1 -1
  11. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.js +4 -2
  12. package/lib/cjs/clipping/UnionOfConvexClipPlaneSets.js.map +1 -1
  13. package/lib/cjs/geometry3d/Plane3dByOriginAndUnitNormal.d.ts +4 -4
  14. package/lib/cjs/geometry3d/Plane3dByOriginAndUnitNormal.d.ts.map +1 -1
  15. package/lib/cjs/geometry3d/Plane3dByOriginAndUnitNormal.js +17 -9
  16. package/lib/cjs/geometry3d/Plane3dByOriginAndUnitNormal.js.map +1 -1
  17. package/lib/cjs/geometry3d/Point2dVector2d.js +2 -2
  18. package/lib/cjs/geometry3d/Point2dVector2d.js.map +1 -1
  19. package/lib/cjs/geometry3d/Point3dVector3d.d.ts +13 -7
  20. package/lib/cjs/geometry3d/Point3dVector3d.d.ts.map +1 -1
  21. package/lib/cjs/geometry3d/Point3dVector3d.js +19 -18
  22. package/lib/cjs/geometry3d/Point3dVector3d.js.map +1 -1
  23. package/lib/cjs/geometry4d/Point4d.d.ts +1 -1
  24. package/lib/cjs/geometry4d/Point4d.d.ts.map +1 -1
  25. package/lib/cjs/geometry4d/Point4d.js +12 -13
  26. package/lib/cjs/geometry4d/Point4d.js.map +1 -1
  27. package/lib/esm/Geometry.d.ts +367 -243
  28. package/lib/esm/Geometry.d.ts.map +1 -1
  29. package/lib/esm/Geometry.js +481 -311
  30. package/lib/esm/Geometry.js.map +1 -1
  31. package/lib/esm/clipping/ConvexClipPlaneSet.d.ts +6 -4
  32. package/lib/esm/clipping/ConvexClipPlaneSet.d.ts.map +1 -1
  33. package/lib/esm/clipping/ConvexClipPlaneSet.js +9 -7
  34. package/lib/esm/clipping/ConvexClipPlaneSet.js.map +1 -1
  35. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.d.ts +5 -3
  36. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.d.ts.map +1 -1
  37. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.js +4 -2
  38. package/lib/esm/clipping/UnionOfConvexClipPlaneSets.js.map +1 -1
  39. package/lib/esm/geometry3d/Plane3dByOriginAndUnitNormal.d.ts +4 -4
  40. package/lib/esm/geometry3d/Plane3dByOriginAndUnitNormal.d.ts.map +1 -1
  41. package/lib/esm/geometry3d/Plane3dByOriginAndUnitNormal.js +17 -9
  42. package/lib/esm/geometry3d/Plane3dByOriginAndUnitNormal.js.map +1 -1
  43. package/lib/esm/geometry3d/Point2dVector2d.js +2 -2
  44. package/lib/esm/geometry3d/Point2dVector2d.js.map +1 -1
  45. package/lib/esm/geometry3d/Point3dVector3d.d.ts +13 -7
  46. package/lib/esm/geometry3d/Point3dVector3d.d.ts.map +1 -1
  47. package/lib/esm/geometry3d/Point3dVector3d.js +19 -18
  48. package/lib/esm/geometry3d/Point3dVector3d.js.map +1 -1
  49. package/lib/esm/geometry4d/Point4d.d.ts +1 -1
  50. package/lib/esm/geometry4d/Point4d.d.ts.map +1 -1
  51. package/lib/esm/geometry4d/Point4d.js +12 -13
  52. package/lib/esm/geometry4d/Point4d.js.map +1 -1
  53. package/package.json +3 -3
@@ -11,7 +11,7 @@ const Point3dVector3d_1 = require("./geometry3d/Point3dVector3d");
11
11
  /**
12
12
  * Enumeration of the 6 possible orderings of XYZ axis order
13
13
  * * **Note:** There are 3 axis order with right hand system (XYZ = 0, YZX = 1, ZXY = 2) and 3 axis order with
14
- * left hand system (XZY = 4, YXZ = 5, ZYX = 6). Note that AxisOrder is encoding the handedness as well. Cross
14
+ * left hand system (XZY = 4, YXZ = 5, ZYX = 6). Note that `AxisOrder` is encoding the handedness as well. Cross
15
15
  * product of the i_th axis in an ordering (i=0,1,2), with the i+1_th in that ordering, will produce the i+2_th
16
16
  * axis in that ordering.
17
17
  * @public
@@ -44,7 +44,8 @@ var AxisIndex;
44
44
  /** 2 axis is index 2 */
45
45
  AxisIndex[AxisIndex["Z"] = 2] = "Z";
46
46
  })(AxisIndex = exports.AxisIndex || (exports.AxisIndex = {}));
47
- /** Standard views. Used in `Matrix3d.createStandardViewAxes(index: StandardViewIndex, invert: boolean)`
47
+ /**
48
+ * Standard views. Used in `Matrix3d.createStandardViewAxes(index: StandardViewIndex, invert: boolean)`
48
49
  * @public
49
50
  */
50
51
  var StandardViewIndex;
@@ -53,20 +54,21 @@ var StandardViewIndex;
53
54
  StandardViewIndex[StandardViewIndex["Top"] = 1] = "Top";
54
55
  /** X to right, negative Y up */
55
56
  StandardViewIndex[StandardViewIndex["Bottom"] = 2] = "Bottom";
56
- /** negative Y to right, Z up */
57
+ /** Negative Y to right, Z up */
57
58
  StandardViewIndex[StandardViewIndex["Left"] = 3] = "Left";
58
- /** Y to right, Z up */
59
+ /** Y to right, Z up */
59
60
  StandardViewIndex[StandardViewIndex["Right"] = 4] = "Right";
60
61
  /** X to right, Z up */
61
62
  StandardViewIndex[StandardViewIndex["Front"] = 5] = "Front";
62
- /** negative X to right, Z up */
63
+ /** Negative X to right, Z up */
63
64
  StandardViewIndex[StandardViewIndex["Back"] = 6] = "Back";
64
- /** isometric: view towards origin from (-1,-1,1) */
65
+ /** Isometric: view towards origin from (-1,-1,1) */
65
66
  StandardViewIndex[StandardViewIndex["Iso"] = 7] = "Iso";
66
- /** right isometric: view towards origin from (1,-1,1) */
67
+ /** Right isometric: view towards origin from (1,-1,1) */
67
68
  StandardViewIndex[StandardViewIndex["RightIso"] = 8] = "RightIso";
68
69
  })(StandardViewIndex = exports.StandardViewIndex || (exports.StandardViewIndex = {}));
69
- /** Enumeration among choice for how a coordinate transformation should incorporate scaling.
70
+ /**
71
+ * Enumeration among choice for how a coordinate transformation should incorporate scaling.
70
72
  * @public
71
73
  */
72
74
  var AxisScaleSelect;
@@ -78,7 +80,8 @@ var AxisScaleSelect;
78
80
  /** On each axis, the vector length matches he length of the corresponding edge of the range. */
79
81
  AxisScaleSelect[AxisScaleSelect["NonUniformRangeContainment"] = 2] = "NonUniformRangeContainment";
80
82
  })(AxisScaleSelect = exports.AxisScaleSelect || (exports.AxisScaleSelect = {}));
81
- /** Enumeration of possible locations of a point in the plane of a polygon.
83
+ /**
84
+ * Enumeration of possible locations of a point in the plane of a polygon.
82
85
  * @public
83
86
  */
84
87
  var PolygonLocation;
@@ -111,18 +114,26 @@ var PolygonLocation;
111
114
  * @public
112
115
  */
113
116
  class Geometry {
114
- /** Test if absolute value of x is huge.
115
- * * See `Geometry.hugeCoordinate`
117
+ /** Test if absolute value of x is large (larger than `Geometry.largeCoordinateResult`) */
118
+ static isLargeCoordinateResult(x) {
119
+ return x > this.largeCoordinateResult || x < -this.largeCoordinateResult;
120
+ }
121
+ /**
122
+ * Test if absolute value of x is large (larger than `Geometry.largeCoordinateResult`).
123
+ * @deprecated in 4.x. Use `isLargeCoordinateResult`.
116
124
  */
117
125
  static isHugeCoordinate(x) {
118
- return x > this.hugeCoordinate || x < -this.hugeCoordinate;
126
+ return Geometry.isLargeCoordinateResult(x);
119
127
  }
120
- /** Test if a number is odd.
121
- */
128
+ /** Test if a number is odd */
122
129
  static isOdd(x) {
123
- return (x & (0x01)) === 1;
130
+ return (x & (0x01)) === 1; // bitwise operation
124
131
  }
125
- /** Correct `distance` to zero if undefined or smaller than metric tolerance. Otherwise return it unchanged. */
132
+ /**
133
+ * Correct distance to zero.
134
+ * * If `distance` magnitude is `undefined` or smaller than `smallMetricDistance`, then return `replacement`
135
+ * (or 0 if replacement is not passed). Otherwise return `distance`.
136
+ */
126
137
  static correctSmallMetricDistance(distance, replacement = 0.0) {
127
138
  if (distance === undefined || Math.abs(distance) < Geometry.smallMetricDistance) {
128
139
  return replacement;
@@ -130,64 +141,119 @@ class Geometry {
130
141
  return distance;
131
142
  }
132
143
  /**
133
- * If `a` is large enough for safe division, return `1/a`, using Geometry.smallMetricDistance as the tolerance for declaring it as divide by zero. Otherwise return `undefined`.
134
- * @param a denominator of division
135
- */
136
- static inverseMetricDistance(a) {
137
- return (Math.abs(a) <= Geometry.smallMetricDistance) ? undefined : 1.0 / a;
144
+ * Correct `fraction` to `replacement` if `fraction` is undefined or too small.
145
+ * @param fraction number to test
146
+ * @param replacement value to return if `fraction` is too small
147
+ * @returns `fraction` if its absolute value is at least `Geometry.smallFraction`; otherwise returns `replacement`
148
+ */
149
+ static correctSmallFraction(fraction, replacement = 0.0) {
150
+ if (fraction === undefined || Math.abs(fraction) < Geometry.smallFraction) {
151
+ return replacement;
152
+ }
153
+ return fraction;
154
+ }
155
+ /**
156
+ * Return the inverse of `distance`.
157
+ * * If `distance` magnitude is smaller than `smallMetricDistance` (i.e. distance is large enough for safe division),
158
+ * then return `1/distance`. Otherwise return `undefined`.
159
+ */
160
+ static inverseMetricDistance(distance) {
161
+ return (Math.abs(distance) <= Geometry.smallMetricDistance) ? undefined : 1.0 / distance;
138
162
  }
139
163
  /**
140
- * If `a` is large enough, return `1/a`, using the square of Geometry.smallMetricDistance as the tolerance for declaring it as divide by zero. Otherwise return `undefined`.
141
- * @param a denominator of division
164
+ * Return the inverse of `distanceSquared`.
165
+ * * If `distanceSquared ` magnitude is smaller than `smallMetricDistanceSquared` (i.e. distanceSquared is large
166
+ * enough for safe division), then return `1/distanceSquared `. Otherwise return `undefined`.
142
167
  */
143
- static inverseMetricDistanceSquared(a) {
144
- return (Math.abs(a) <= Geometry.smallMetricDistanceSquared) ? undefined : 1.0 / a;
168
+ static inverseMetricDistanceSquared(distanceSquared) {
169
+ return (Math.abs(distanceSquared) <= Geometry.smallMetricDistanceSquared) ? undefined : 1.0 / distanceSquared;
145
170
  }
146
171
  /**
147
- * Boolean test for metric coordinate near-equality (i.e., if x and y are almost equal). If tolerance is not passed,
148
- * `Geometry.smallMetricDistance` is used as tolerance.
172
+ * Boolean test for metric coordinate near-equality (i.e., if `x` and `y` are almost equal) using `tolerance`.
173
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
149
174
  */
150
- static isSameCoordinate(x, y, tol) {
151
- if (tol)
152
- return Math.abs(x - y) < Math.abs(tol);
153
- return Math.abs(x - y) < Geometry.smallMetricDistance;
175
+ static isSameCoordinate(x, y, tolerance = Geometry.smallMetricDistance) {
176
+ let d = x - y;
177
+ if (d < 0)
178
+ d = -d;
179
+ return d <= tolerance;
154
180
  }
155
- /** Boolean test for metric coordinate near-equality, with toleranceFactor applied to the usual smallMetricDistance */
181
+ /**
182
+ * Boolean test for metric coordinate near-equality (i.e., if `x` and `y` are almost equal) using
183
+ * `tolerance = toleranceFactor * smallMetricDistance`
184
+ * */
156
185
  static isSameCoordinateWithToleranceFactor(x, y, toleranceFactor) {
157
186
  return Geometry.isSameCoordinate(x, y, toleranceFactor * Geometry.smallMetricDistance);
158
187
  }
159
- /** Boolean test for metric coordinate near-equality of x, y pair */
160
- static isSameCoordinateXY(x0, y0, x1, y1, tol = Geometry.smallMetricDistance) {
188
+ /**
189
+ * Boolean test for metric coordinate pair near-equality (i.e., if `x0` and `x1` are almost equal
190
+ * and `y0` and `y1` are almost equal) using `tolerance`.
191
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
192
+ */
193
+ static isSameCoordinateXY(x0, y0, x1, y1, tolerance = Geometry.smallMetricDistance) {
161
194
  let d = x1 - x0;
162
195
  if (d < 0)
163
196
  d = -d;
164
- if (d > tol)
197
+ if (d > tolerance)
165
198
  return false;
166
199
  d = y1 - y0;
167
200
  if (d < 0)
168
201
  d = -d;
169
- return d < tol;
170
- }
171
- /** Boolean test for squared metric coordinate near-equality */
172
- static isSameCoordinateSquared(x, y) {
173
- return Math.abs(Math.sqrt(x) - Math.sqrt(y)) < Geometry.smallMetricDistance;
174
- }
175
- /** boolean test for small `dataA.distance (dataB)` within `smallMetricDistance` */
176
- static isSamePoint3d(dataA, dataB) { return dataA.distance(dataB) < Geometry.smallMetricDistance; }
177
- /** boolean test for distance between `XYZ` objects within `smallMetricDistance`
178
- * * Note that Point3d and Vector3d are both derived from XYZ, so this method tolerates mixed types.
179
- */
180
- static isSameXYZ(dataA, dataB) { return dataA.distance(dataB) < Geometry.smallMetricDistance; }
181
- /** boolean test for small `dataA.distanceXY (dataB)` within `smallMetricDistance` */
182
- static isSamePoint3dXY(dataA, dataB) { return dataA.distanceXY(dataB) < Geometry.smallMetricDistance; }
183
- /** boolean test for small `dataA.distanceXY (dataB)` within `smallMetricDistance` */
184
- static isSameVector3d(dataA, dataB) { return dataA.distance(dataB) < Geometry.smallMetricDistance; }
185
- /** boolean test for small `dataA.distanceXY (dataB)` within `smallMetricDistance` */
186
- static isSamePoint2d(dataA, dataB) { return dataA.distance(dataB) < Geometry.smallMetricDistance; }
187
- /** boolean test for small `dataA.distanceXY (dataB)` within `smallMetricDistance` */
188
- static isSameVector2d(dataA, dataB) { return dataA.distance(dataB) < Geometry.smallMetricDistance; }
189
- /**
190
- * Lexical comparison of (a.x,a.y) (b.x,b.y) with x as first test, y second.
202
+ return d <= tolerance;
203
+ }
204
+ /**
205
+ * Boolean test for squared metric coordinate near-equality (i.e., if `sqrt(x)` and `sqrt(y)` are
206
+ * almost equal) using `tolerance`.
207
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
208
+ */
209
+ static isSameCoordinateSquared(x, y, tolerance = Geometry.smallMetricDistance) {
210
+ return Math.abs(Math.sqrt(x) - Math.sqrt(y)) <= tolerance;
211
+ }
212
+ /**
213
+ * Boolean test for small `dataA.distance(dataB)` within `tolerance`.
214
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
215
+ */
216
+ static isSamePoint3d(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
217
+ return dataA.distance(dataB) <= tolerance;
218
+ }
219
+ /**
220
+ * Boolean test for small xyz-distance within `tolerance`.
221
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
222
+ * * Note that Point3d and Vector3d are both derived from XYZ, so this method tolerates mixed types.
223
+ */
224
+ static isSameXYZ(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
225
+ return dataA.distance(dataB) <= tolerance;
226
+ }
227
+ /**
228
+ * Boolean test for small xy-distance (ignoring z) within `tolerance`.
229
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
230
+ */
231
+ static isSamePoint3dXY(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
232
+ return dataA.distanceXY(dataB) <= tolerance;
233
+ }
234
+ /**
235
+ * Boolean test for small xyz-distance within `tolerance`.
236
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
237
+ */
238
+ static isSameVector3d(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
239
+ return dataA.distance(dataB) <= tolerance;
240
+ }
241
+ /**
242
+ * Boolean test for small xy-distance within `tolerance`.
243
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
244
+ */
245
+ static isSamePoint2d(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
246
+ return dataA.distance(dataB) <= tolerance;
247
+ }
248
+ /**
249
+ * Boolean test for small xy-distance within `tolerance`.
250
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
251
+ */
252
+ static isSameVector2d(dataA, dataB, tolerance = Geometry.smallMetricDistance) {
253
+ return dataA.distance(dataB) <= tolerance;
254
+ }
255
+ /**
256
+ * Lexical comparison of (a.x, a.y) and (b.x, b.y) with x as first test and y as second (z is ignored).
191
257
  * * This is appropriate for a horizontal sweep in the plane.
192
258
  */
193
259
  static lexicalXYLessThan(a, b) {
@@ -202,7 +268,7 @@ class Geometry {
202
268
  return 0;
203
269
  }
204
270
  /**
205
- * Lexical comparison of (a.x,a.y) (b.x,b.y) with y as first test, x second.
271
+ * Lexical comparison of (a.x, a.y) and (b.x, b.y) with y as first test and x as second (z is ignored).
206
272
  * * This is appropriate for a vertical sweep in the plane.
207
273
  */
208
274
  static lexicalYXLessThan(a, b) {
@@ -216,9 +282,7 @@ class Geometry {
216
282
  return 1;
217
283
  return 0;
218
284
  }
219
- /**
220
- * Lexical test, based on x first, y second, z third.
221
- */
285
+ /** Lexical comparison of (a.x, a.y, a.z) and (b.x, b.y, b.z) with x as first test, y as second, and z as third. */
222
286
  static lexicalXYZLessThan(a, b) {
223
287
  if (a.x < b.x)
224
288
  return -1;
@@ -234,19 +298,21 @@ class Geometry {
234
298
  return 1;
235
299
  return 0;
236
300
  }
237
- /** Test if `value` is small compared to `smallAngleRadians`.
301
+ /**
302
+ * Test if `value` is small compared to `smallFraction`.
238
303
  * * This is appropriate if `value` is know to be a typical 0..1 fraction.
239
304
  */
240
305
  static isSmallRelative(value) {
241
- return Math.abs(value) < Geometry.smallAngleRadians;
306
+ return Math.abs(value) < Geometry.smallFraction;
242
307
  }
243
308
  /** Test if `value` is small compared to `smallAngleRadians` */
244
309
  static isSmallAngleRadians(value) {
245
310
  return Math.abs(value) < Geometry.smallAngleRadians;
246
311
  }
247
- /** Returns true if both values are undefined or if both are defined and almost equal within tolerance.
248
- * If one is undefined and the other is not then false is returned.
249
- */
312
+ /**
313
+ * Returns `true` if both values are `undefined` or if both are defined and almost equal within tolerance.
314
+ * If one is `undefined` and the other is not, then `false` is returned.
315
+ */
250
316
  static isAlmostEqualOptional(a, b, tolerance) {
251
317
  if (a !== undefined && b !== undefined) {
252
318
  if (Math.abs(a - b) > tolerance)
@@ -258,44 +324,43 @@ class Geometry {
258
324
  }
259
325
  return true;
260
326
  }
261
- /** Toleranced equality test, using tolerance `smallAngleRadians * ( 1 + abs(a) + (abs(b)))`
262
- * * Effectively an absolute tolerance of `smallAngleRadians`, with tolerance increasing for larger values of a and b.
263
- */
264
- static isAlmostEqualNumber(a, b) {
327
+ /**
328
+ * Toleranced equality test using tolerance `tolerance * ( 1 + abs(a) + abs(b) )`.
329
+ * * `Geometry.smallAngleRadians` is used if tolerance is `undefined`.
330
+ */
331
+ static isAlmostEqualNumber(a, b, tolerance = Geometry.smallAngleRadians) {
265
332
  const sumAbs = 1.0 + Math.abs(a) + Math.abs(b);
266
- return Math.abs(a - b) <= Geometry.smallAngleRadians * sumAbs;
333
+ return Math.abs(a - b) <= tolerance * sumAbs;
267
334
  }
268
- /** Toleranced equality test, using tolerance `smallAngleRadians * ( 1 + abs(a) + (abs(b)))`
269
- * * Effectively an absolute tolerance of `smallAngleRadians`, with tolerance increasing for larger values of a and b.
270
- */
271
- static isAlmostEqualXAndY(a, b) {
272
- const sumAbs = 1.0 + Math.abs(a.x) + Math.abs(b.x) + Math.abs(a.y) + Math.abs(b.y);
273
- const tolerance = Geometry.smallAngleRadians * sumAbs;
274
- return Math.abs(a.x - b.x) <= tolerance && Math.abs(a.y - b.y) <= tolerance;
335
+ /**
336
+ * Toleranced equality test using tolerance `tolerance * ( 1 + abs(a.x) + abs(a.y) + abs(b.x) + abs(b.y) )`.
337
+ * * `Geometry.smallAngleRadians` is used if tolerance is `undefined`.
338
+ */
339
+ static isAlmostEqualXAndY(a, b, tolerance = Geometry.smallAngleRadians) {
340
+ const tol = tolerance * (1.0 + Math.abs(a.x) + Math.abs(b.x) + Math.abs(a.y) + Math.abs(b.y));
341
+ return (Math.abs(a.x - b.x) <= tol) && (Math.abs(a.y - b.y) <= tol);
275
342
  }
276
343
  /**
277
- * Toleranced equality test, using caller-supplied tolerance.
278
- * If no tolerance is given, use smallMetricDistance.
344
+ * Toleranced equality test using caller-supplied `tolerance`.
345
+ * * `Geometry.smallMetricDistance` is used if tolerance is `undefined`.
279
346
  */
280
- static isDistanceWithinTol(distance, tol) {
281
- if (tol !== undefined)
282
- return Math.abs(distance) <= Math.abs(tol);
283
- return Math.abs(distance) <= Geometry.smallMetricDistance;
347
+ static isDistanceWithinTol(distance, tolerance = Geometry.smallMetricDistance) {
348
+ return Math.abs(distance) <= tolerance;
284
349
  }
285
- /** Toleranced equality test, using `smallMetricDistance` tolerance. */
350
+ /** Toleranced equality test using `smallMetricDistance` tolerance. */
286
351
  static isSmallMetricDistance(distance) {
287
352
  return Math.abs(distance) <= Geometry.smallMetricDistance;
288
353
  }
289
- /** Toleranced equality, using `smallMetricDistanceSquared` tolerance. */
354
+ /** Toleranced equality test using `smallMetricDistanceSquared` tolerance. */
290
355
  static isSmallMetricDistanceSquared(distanceSquared) {
291
356
  return Math.abs(distanceSquared) <= Geometry.smallMetricDistanceSquared;
292
357
  }
293
358
  /**
294
359
  * Return `axis modulo 3` with proper handling of negative indices
295
360
  * ..., -3:x, -2:y, -1:z, 0:x, 1:y, 2:z, 3:x, 4:y, 5:z, 6:x, 7:y, 8:z, ...
296
- * */
361
+ */
297
362
  static cyclic3dAxis(axis) {
298
- /* Direct test for the most common cases, avoid modulo */
363
+ /* Direct test for the most common cases to avoid more expensive modulo operation */
299
364
  if (axis >= 0) {
300
365
  if (axis < 3)
301
366
  return axis;
@@ -308,7 +373,8 @@ class Geometry {
308
373
  return j;
309
374
  return 2 - ((-axis - 1) % 3);
310
375
  }
311
- /** Return the AxisOrder for which axisIndex is the first named axis.
376
+ /**
377
+ * Return the `AxisOrder` for which `axisIndex` is the first named axis.
312
378
  * * `axisIndex === 0` returns `AxisOrder.XYZ`
313
379
  * * `axisIndex === 1` returns `AxisOrder.YZX`
314
380
  * * `axisIndex === 2` returns `AxisOrder.ZXY`
@@ -322,32 +388,55 @@ class Geometry {
322
388
  return AxisOrder.ZXY;
323
389
  return Geometry.axisIndexToRightHandedAxisOrder(Geometry.cyclic3dAxis(axisIndex));
324
390
  }
325
- /** Return the largest absolute distance from a to either of b0 or b1 */
326
- static maxAbsDiff(a, b0, b1) {
327
- return Math.max(Math.abs(a - b0), Math.abs(a - b1));
391
+ /** Return the largest signed value among `a`, `b`, and `c` */
392
+ static maxXYZ(a, b, c) {
393
+ let max = a;
394
+ if (b > max)
395
+ max = b;
396
+ if (c > max)
397
+ max = c;
398
+ return max;
399
+ }
400
+ /** Return the smallest signed value among `a`, `b`, and `c` */
401
+ static minXYZ(a, b, c) {
402
+ let min = a;
403
+ if (b < min)
404
+ min = b;
405
+ if (c < min)
406
+ min = c;
407
+ return min;
408
+ }
409
+ /** Return the largest signed value among `a` and `b` */
410
+ static maxXY(a, b) {
411
+ let max = a;
412
+ if (b > max)
413
+ max = b;
414
+ return max;
328
415
  }
329
- /** Return the largest absolute absolute value among x,y,z */
416
+ /** Return the smallest signed value among `a` and `b` */
417
+ static minXY(a, b) {
418
+ let min = a;
419
+ if (b < min)
420
+ min = b;
421
+ return min;
422
+ }
423
+ /** Return the largest absolute value among `x`, `y`, and `z` */
330
424
  static maxAbsXYZ(x, y, z) {
331
425
  return Geometry.maxXYZ(Math.abs(x), Math.abs(y), Math.abs(z));
332
426
  }
333
- /** Return the largest absolute absolute value among x,y */
427
+ /** Return the largest absolute value among `x` and `y` */
334
428
  static maxAbsXY(x, y) {
335
429
  return Geometry.maxXY(Math.abs(x), Math.abs(y));
336
430
  }
337
- /** Return the largest signed value among a, b, c */
338
- static maxXYZ(a, b, c) {
339
- let q = a;
340
- if (b > q)
341
- q = b;
342
- if (c > q)
343
- q = c;
344
- return q;
431
+ /** Return the largest absolute distance from `a` to either of `b0` or `b1` */
432
+ static maxAbsDiff(a, b0, b1) {
433
+ return Math.max(Math.abs(a - b0), Math.abs(a - b1));
345
434
  }
346
435
  /**
347
- * Examine the value (particularly sign) of x.
348
- * * If x is negative, return outNegative.
349
- * * If x is true zero, return outZero
350
- * * If x is positive, return outPositive
436
+ * Examine the sign of `x`.
437
+ * * If `x` is negative, return `outNegative`
438
+ * * If `x` is true zero, return `outZero`
439
+ * * If `x` is positive, return `outPositive`
351
440
  */
352
441
  static split3WaySign(x, outNegative, outZero, outPositive) {
353
442
  if (x < 0)
@@ -369,45 +458,40 @@ class Geometry {
369
458
  return -1;
370
459
  return 0;
371
460
  }
372
- /** Return the largest signed value among a, b */
373
- static maxXY(a, b) {
374
- let q = a;
375
- if (b > q)
376
- q = b;
377
- return q;
378
- }
379
- /** Return the smallest signed value among a, b */
380
- static minXY(a, b) {
381
- let q = a;
382
- if (b < q)
383
- q = b;
384
- return q;
461
+ /** Return the square of x */
462
+ static square(x) {
463
+ return x * x;
385
464
  }
386
- /** Return the hypotenuse `sqrt(x*x + y*y)`. This is much faster than `Math.hypot(x,y)`. */
465
+ /**
466
+ * Return the hypotenuse (i.e., `sqrt(x*x + y*y)`).
467
+ * * This is much faster than `Math.hypot(x,y)`.
468
+ */
387
469
  static hypotenuseXY(x, y) {
388
470
  return Math.sqrt(x * x + y * y);
389
471
  }
390
- /** Return the squared `hypotenuse (x*x + y*y)`. */
472
+ /** Return the squared hypotenuse (i.e., `x*x + y*y`). */
391
473
  static hypotenuseSquaredXY(x, y) {
392
474
  return x * x + y * y;
393
475
  }
394
- /** Return the square of x */
395
- static square(x) {
396
- return x * x;
397
- }
398
- /** Return the hypotenuse `sqrt(x*x + y*y + z*z)`. This is much faster than `Math.hypot(x,y,z)`. */
476
+ /**
477
+ * Return the hypotenuse (i.e., `sqrt(x*x + y*y + z*z)`).
478
+ * * This is much faster than `Math.hypot(x,y,z)`.
479
+ */
399
480
  static hypotenuseXYZ(x, y, z) {
400
481
  return Math.sqrt(x * x + y * y + z * z);
401
482
  }
402
- /** Return the squared hypotenuse `(x*x + y*y + z*z)`. This is much faster than `Math.hypot(x,y,z)`. */
483
+ /** Return the squared hypotenuse (i.e., `x*x + y*y + z*z`). */
403
484
  static hypotenuseSquaredXYZ(x, y, z) {
404
485
  return x * x + y * y + z * z;
405
486
  }
406
- /** Return the (full 4d) hypotenuse `sqrt(x*x + y*y + z*z + w*w)`. This is much faster than `Math.hypot(x,y,z,w)`. */
487
+ /**
488
+ * Return the full 4d hypotenuse (i.e., `sqrt(x*x + y*y + z*z + w*w)`).
489
+ * * This is much faster than `Math.hypot(x,y,z,w)`.
490
+ */
407
491
  static hypotenuseXYZW(x, y, z, w) {
408
492
  return Math.sqrt(x * x + y * y + z * z + w * w);
409
493
  }
410
- /** Return the squared hypotenuse `(x*x + y*y + z*z+w*w)`. This is much faster than `Math.hypot(x,y,z)`. */
494
+ /** Return the squared hypotenuse (i.e., `x*x + y*y + z*z + w*w`). */
411
495
  static hypotenuseSquaredXYZW(x, y, z, w) {
412
496
  return x * x + y * y + z * z + w * w;
413
497
  }
@@ -433,8 +517,8 @@ class Geometry {
433
517
  static distanceXYZXYZ(x0, y0, z0, x1, y1, z1) {
434
518
  return Geometry.hypotenuseXYZ(x1 - x0, y1 - y0, z1 - z0);
435
519
  }
436
- /** Returns Returns the triple product of 3 vectors provided as x,y,z number sequences.
437
- *
520
+ /**
521
+ * Returns the triple product of 3 vectors provided as x,y,z number sequences.
438
522
  * * The triple product is the determinant of the 3x3 matrix with the 9 numbers (3 vectors placed in 3 rows).
439
523
  * * The triple product is positive if the 3 vectors form a right handed coordinate system.
440
524
  * * The triple product is negative if the 3 vectors form a left handed coordinate system.
@@ -442,170 +526,196 @@ class Geometry {
442
526
  * * U dot (V cross W)
443
527
  * * V dot (W cross U)
444
528
  * * W dot (U cross V)
445
- * * (-U dot (W cross V)) -- (note the negative -- reversing cross product order changes the sign)
446
- * * (-V dot (U cross W)) -- (note the negative -- reversing cross product order changes the sign)
447
- * * (-W dot (V cross U)) -- (note the negative -- reversing cross product order changes the sign)
448
- * * the triple product is 6 times the (signed) volume of the tetrahedron with the three vectors as edges from a common vertex.
529
+ * * -U dot (W cross V)
530
+ * * -V dot (U cross W)
531
+ * * -W dot (V cross U)
532
+ * * Note the negative in the last 3 formulas. Reversing cross product order changes the sign.
533
+ * * The triple product is 6 times the (signed) volume of the tetrahedron with the three vectors as edges from a
534
+ * common vertex.
449
535
  */
450
536
  static tripleProduct(ux, uy, uz, vx, vy, vz, wx, wy, wz) {
451
537
  return ux * (vy * wz - vz * wy)
452
538
  + uy * (vz * wx - vx * wz)
453
539
  + uz * (vx * wy - vy * wx);
454
540
  }
455
- /** Returns the determinant of the 4x4 matrix unrolled as the 16 parameters.
456
- */
541
+ /** Returns the determinant of the 4x4 matrix unrolled as the 16 parameters */
457
542
  static determinant4x4(xx, xy, xz, xw, yx, yy, yz, yw, zx, zy, zz, zw, wx, wy, wz, ww) {
458
543
  return xx * this.tripleProduct(yy, yz, yw, zy, zz, zw, wy, wz, ww)
459
544
  - yx * this.tripleProduct(xy, xz, xw, zy, zz, zw, wy, wz, ww)
460
545
  + zx * this.tripleProduct(xy, xz, xw, yy, yz, yw, wy, wz, ww)
461
546
  - wx * this.tripleProduct(xy, xz, xw, yy, yz, yw, zy, zz, zw);
462
547
  }
463
- /** Return the mean curvature for two radii, with 0 radius implying 0 curvature */
464
- static meanCurvatureOfRadii(r0, r1) {
465
- return 0.5 * (this.safeDivideFraction(1, r0, 0) + this.safeDivideFraction(1, r1, 0));
466
- }
467
548
  /**
468
- * Returns curvature magnitude from a first and second derivative vector.
469
- * @param ux first derivative x component
470
- * @param uy first derivative y component
471
- * @param uz first derivative z component
472
- * @param vx second derivative x component
473
- * @param vy second derivative y component
474
- * @param vz second derivative z component
475
- */
476
- static curvatureMagnitude(ux, uy, uz, vx, vy, vz) {
477
- let q = uy * vz - uz * vy;
478
- let sum = q * q;
479
- q = uz * vx - ux * vz;
480
- sum += q * q;
481
- q = ux * vy - uy * vx;
482
- sum += q * q;
483
- const a = Math.sqrt(ux * ux + uy * uy + uz * uz);
484
- const b = Math.sqrt(sum);
485
- // (sum and a are both nonnegative)
486
- const aaa = a * a * a;
487
- // radius of curvature = aaa / b;
488
- // curvature = b/aaa
489
- const tol = Geometry.smallAngleRadians;
490
- if (aaa > tol * b)
491
- return b / aaa;
492
- return 0; // hm.. maybe should be infinite?
493
- }
494
- /** Returns the determinant of 3x3 matrix with x and y rows taken from 3 points, third row from corresponding numbers.
495
- *
549
+ * Returns the determinant of 3x3 matrix with first and second rows created from the 3 xy points and the third
550
+ * row created from the 3 numbers:
551
+ * [columnA.x columnB.x columnC.x]
552
+ * [columnA.y columnB.y columnC.y]
553
+ * [ weightA weightB weightC ]
496
554
  */
497
555
  static tripleProductXYW(columnA, weightA, columnB, weightB, columnC, weightC) {
498
556
  return Geometry.tripleProduct(columnA.x, columnB.x, columnC.x, columnA.y, columnB.y, columnC.y, weightA, weightB, weightC);
499
557
  }
500
- /** Returns the determinant of 3x3 matrix with x and y rows taken from 3 points, third row from corresponding numbers.
501
- *
558
+ /**
559
+ * Returns the determinant of 3x3 matrix columns created by the given `Point4d` ignoring the z part:
560
+ * [columnA.x columnB.x columnC.x]
561
+ * [columnA.y columnB.y columnC.y]
562
+ * [columnA.w columnB.w columnC.w]
502
563
  */
503
564
  static tripleProductPoint4dXYW(columnA, columnB, columnC) {
504
565
  return Geometry.tripleProduct(columnA.x, columnB.x, columnC.x, columnA.y, columnB.y, columnC.y, columnA.w, columnB.w, columnC.w);
505
566
  }
506
- /** 2D cross product of vectors layed out as scalars. */
567
+ /** 2D cross product of vectors with the vectors presented as numbers. */
507
568
  static crossProductXYXY(ux, uy, vx, vy) {
508
569
  return ux * vy - uy * vx;
509
570
  }
510
- /** 3D cross product of vectors layed out as scalars. */
571
+ /** 3D cross product of vectors with the vectors presented as numbers. */
511
572
  static crossProductXYZXYZ(ux, uy, uz, vx, vy, vz, result) {
512
573
  return Point3dVector3d_1.Vector3d.create(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx, result);
513
574
  }
514
- /** magnitude of 3D cross product of vectors, with the vectors presented as */
575
+ /** Magnitude of 3D cross product of vectors with the vectors presented as numbers. */
515
576
  static crossProductMagnitude(ux, uy, uz, vx, vy, vz) {
516
577
  return Geometry.hypotenuseXYZ(uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx);
517
578
  }
518
- /** 3D dot product of vectors layed out as scalars. */
579
+ /** 2D dot product of vectors with the vectors presented as numbers. */
580
+ static dotProductXYXY(ux, uy, vx, vy) {
581
+ return ux * vx + uy * vy;
582
+ }
583
+ /** 3D dot product of vectors with the vectors presented as numbers. */
519
584
  static dotProductXYZXYZ(ux, uy, uz, vx, vy, vz) {
520
585
  return ux * vx + uy * vy + uz * vz;
521
586
  }
522
- /** 2D dot product of vectors layed out as scalars. */
523
- static dotProductXYXY(ux, uy, vx, vy) {
524
- return ux * vx + uy * vy;
587
+ /**
588
+ * Return the mean curvature for two radii.
589
+ * * Curvature is the reciprocal of radius.
590
+ * * 0 radius implies 0 curvature.
591
+ * @param r0 first radius
592
+ * @param r1 second radius
593
+ */
594
+ static meanCurvatureOfRadii(r0, r1) {
595
+ return 0.5 * (this.safeDivideFraction(1, r0, 0) + this.safeDivideFraction(1, r1, 0));
525
596
  }
526
597
  /**
527
- * Clamp to (min(a,b), max(a,b))
528
- * * always returns a number between a and b
529
- * @param x
530
- * @param a
531
- * @param b
598
+ * Returns curvature from the first and second derivative vectors.
599
+ * * If U is the first derivative and V is the second derivative, the curvature is defined as:
600
+ * * `|| U x V || / || U ||^3`.
601
+ * * Math details can be found at https://en.wikipedia.org/wiki/Curvature#General_expressions
602
+ * @param ux first derivative x component
603
+ * @param uy first derivative y component
604
+ * @param uz first derivative z component
605
+ * @param vx second derivative x component
606
+ * @param vy second derivative y component
607
+ * @param vz second derivative z component
608
+ */
609
+ static curvatureMagnitude(ux, uy, uz, vx, vy, vz) {
610
+ let q = uy * vz - uz * vy;
611
+ let sum = q * q;
612
+ q = uz * vx - ux * vz;
613
+ sum += q * q;
614
+ q = ux * vy - uy * vx;
615
+ sum += q * q;
616
+ const magUxV = Math.sqrt(sum);
617
+ const magU = Math.sqrt(ux * ux + uy * uy + uz * uz);
618
+ const magUCubed = magU * magU * magU;
619
+ if (magUCubed > Geometry.smallAngleRadians * magUxV)
620
+ return magUxV / magUCubed;
621
+ return 0;
622
+ }
623
+ /**
624
+ * Clamp to (min(a,b), max(a,b)).
625
+ * * Always returns a number between `a` and `b`.
626
+ * @param value value to clamp
627
+ * @param a smallest allowed output if `a < b` or largest allowed output if `a > b`
628
+ * @param b largest allowed output if `a < b` or smallest allowed output if `a > b`
532
629
  */
533
- static clampToStartEnd(x, a, b) {
630
+ static clampToStartEnd(value, a, b) {
534
631
  if (a > b)
535
- return Geometry.clampToStartEnd(x, b, a);
536
- if (x < a)
632
+ return Geometry.clampToStartEnd(value, b, a);
633
+ if (value < a)
537
634
  return a;
538
- if (b < x)
635
+ if (b < value)
539
636
  return b;
540
- return x;
637
+ return value;
541
638
  }
542
639
  /**
543
- * Clamp value to (min,max) with no test for order of (min,max)
640
+ * Clamp value to (min, max) with no test for order of (min, max).
641
+ * * Always returns a number between `min` and `max`.
544
642
  * @param value value to clamp
545
643
  * @param min smallest allowed output
546
- * @param max largest allowed result.
644
+ * @param max largest allowed output
547
645
  */
548
- static clamp(value, min, max) { return Math.max(min, Math.min(max, value)); }
549
- /** If given a number, return it. If given undefined, return `defaultValue`. */
646
+ static clamp(value, min, max) {
647
+ return Math.max(min, Math.min(max, value));
648
+ }
649
+ /** If given a `value`, return it. If given `undefined`, return `defaultValue`. */
550
650
  static resolveNumber(value, defaultValue = 0) {
551
651
  return value !== undefined ? value : defaultValue;
552
652
  }
553
- /** If given a value, return it. If given undefined, return `defaultValue`. */
653
+ /** If given a `value`, return it. If given `undefined`, return `defaultValue`. */
554
654
  static resolveValue(value, defaultValue) {
555
655
  return value !== undefined ? value : defaultValue;
556
656
  }
557
- /** If given value matches a target, return undefined. Otherwise return the value. */
657
+ /** If given `value` matches the `targetValue`, return `undefined`. Otherwise return the `value`. */
558
658
  static resolveToUndefined(value, targetValue) {
559
659
  return value === targetValue ? undefined : value;
560
660
  }
561
661
  /**
562
- * Simple interpolation between values, but choosing (based on fraction) a or b as starting
563
- * point for maximum accuracy.
662
+ * Simple interpolation between values `a` and `b` with fraction `f`.
564
663
  * * If `f = 0`, then `a` is returned and if `f = 1`, then `b` is returned.
664
+ * * For maximum accuracy, we choose `a` or `b` as starting point based on fraction `f`.
565
665
  */
566
666
  static interpolate(a, f, b) {
567
667
  return f <= 0.5 ? a + f * (b - a) : b - (1.0 - f) * (b - a);
568
668
  }
569
669
  /**
570
- * Given an axisOrder (e.g. XYZ, YZX, etc) and an index, returns the axis index at the given index.
571
- * * For example, if axisOrder = XYZ, then for index 0 returns X (or axis index 0), for index 1 returns
572
- * Y (or axis index 1), and for index 2 returns Z (or axis index 2). For indexes greater than 2 or smaller
573
- * than 0, it returns cyclic axis index. See Geometry.cyclic3dAxis for more info.
574
- * * Another example: if axisOrder = ZYX, then for index 0 returns Z (or axis index 2), for index 1 returns
575
- * Y (or axis index 1), and for index 2 returns X (or axis index 0).
576
- * */
670
+ * Given an `axisOrder` (e.g. XYZ, YZX, etc) and an `index`, return the `axis` at the given index.
671
+ * * For example, if `axisOrder = XYZ`, then for index 0 return `X` (or axis 0), for index 1 return
672
+ * `Y` (or axis 1), and for index 2 return `Z` (or axis 2).
673
+ * * Another example: if `axisOrder = ZXY`, then for index 0 return `Z` (or axis 2), for index 1 return
674
+ * `X` (or axis 0), and for index 2 return `Y` (or axis 1).
675
+ * * For indexes greater than 2 or smaller than 0, it return cyclic axis. See [[Geometry.cyclic3dAxis]]
676
+ * for more info.
677
+ */
577
678
  static axisOrderToAxis(order, index) {
578
679
  const axis = order <= AxisOrder.ZXY ? order + index : (order - AxisOrder.XZY) - index;
579
680
  return Geometry.cyclic3dAxis(axis);
580
681
  }
581
- /** Return (a modulo period), e.g. for use as a cyclic index. Both a and period may be negative. */
682
+ /**
683
+ * Return `a` modulo `period`.
684
+ * * Both `a` and `period` can be negative.
685
+ * * This function can be faster than the `%` operator for the common case when `p > 0` and `-p < a < 2p`.
686
+ */
582
687
  static modulo(a, period) {
688
+ // period is negative
583
689
  if (period <= 0) {
584
690
  if (period === 0)
585
691
  return a;
586
692
  return -Geometry.modulo(-a, -period);
587
693
  }
694
+ // period is positive
588
695
  if (a >= 0) {
589
- if (a < period)
696
+ if (a < period) // "0 < a < period"
590
697
  return a;
591
- if (a < 2 * period)
698
+ if (a < 2 * period) // "0 < period < a < 2*period"
592
699
  return a - period;
593
700
  }
594
- else {
595
- a += period; // hopefully move into primary period without division and floor
701
+ else { // "-period < a < 0"
702
+ a += period;
596
703
  if (a > 0)
597
704
  return a;
598
705
  }
706
+ // "0 < 2*period < a" or "a < -period < 0"
599
707
  const m = Math.floor(a / period);
600
708
  return a - m * period;
601
709
  }
602
- /** return 0 if the value is undefined, 1 if defined. */
603
- static defined01(value) { return value === undefined ? 0 : 1; }
710
+ /** Return 0 if the value is `undefined` and 1 if the value is defined. */
711
+ static defined01(value) {
712
+ return value === undefined ? 0 : 1;
713
+ }
604
714
  /**
605
- * Return `numerator` divided by `denominator`, or `undefined`.
715
+ * Return `numerator` divided by `denominator`.
606
716
  * @param numerator the numerator
607
717
  * @param denominator the denominator
608
- * @returns return `numerator/denominator` but if the ratio would exceed `Geometry.largeFractionResult`,
718
+ * @returns return `numerator/denominator` but if the ratio exceeds `Geometry.largeFractionResult`,
609
719
  * return `undefined`.
610
720
  */
611
721
  static conditionalDivideFraction(numerator, denominator) {
@@ -617,76 +727,105 @@ class Geometry {
617
727
  * Return `numerator` divided by `denominator`.
618
728
  * @param numerator the numerator
619
729
  * @param denominator the denominator
620
- * @returns return `numerator/denominator` but if the ratio would exceed `Geometry.largeFractionResult`,
730
+ * @returns return `numerator/denominator` but if the ratio exceeds `Geometry.largeFractionResult`,
621
731
  * return `defaultResult`.
622
732
  */
623
733
  static safeDivideFraction(numerator, denominator, defaultResult) {
624
- const a = Geometry.conditionalDivideFraction(numerator, denominator);
625
- if (a !== undefined)
626
- return a;
734
+ const ratio = Geometry.conditionalDivideFraction(numerator, denominator);
735
+ if (ratio !== undefined)
736
+ return ratio;
627
737
  return defaultResult;
628
738
  }
629
739
  /**
630
- * Return `numerator` divided by `denominator` (with a given `largestResult`), or `undefined`.
740
+ * Return `numerator` divided by `denominator` (with a given `largestResult`).
631
741
  * @param numerator the numerator
632
742
  * @param denominator the denominator
633
- * @param largestResult the ratio threshold.
634
- * @returns return `numerator/denominator` but if the ratio would exceed `largestResult`, return `undefined`.
743
+ * @param largestResult the ratio threshold
744
+ * @returns return `numerator/denominator` but if the ratio exceeds `largestResult`, return `undefined`.
635
745
  */
636
746
  static conditionalDivideCoordinate(numerator, denominator, largestResult = Geometry.largeCoordinateResult) {
637
747
  if (Math.abs(denominator * largestResult) > Math.abs(numerator))
638
748
  return numerator / denominator;
639
749
  return undefined;
640
750
  }
641
- /** return the 0, 1, or 2 pairs of (c,s) values that solve
642
- * {constCoff + cosCoff * c + sinCoff * s = 0}
643
- * with the constraint {c*c+s*s = 1}
751
+ /**
752
+ * Return solution(s) of equation `constCoff + cosCoff*c + sinCoff*s = 0` for `c` and `s` with the
753
+ * constraint `c*c + s*s = 1`.
754
+ * * There could be 0, 1, or 2 solutions. Return `undefined` if there is no solution.
644
755
  */
645
756
  static solveTrigForm(constCoff, cosCoff, sinCoff) {
646
- {
647
- const delta2 = cosCoff * cosCoff + sinCoff * sinCoff;
648
- const constCoff2 = constCoff * constCoff;
649
- // nSolution = 0
650
- let result;
651
- if (delta2 > 0.0) {
652
- const lambda = -constCoff / delta2;
653
- const a2 = constCoff2 / delta2;
654
- const D2 = 1.0 - a2;
655
- if (-Geometry.smallMetricDistanceSquared < D2 && D2 <= 0.0) { // observed D2 = -2.22e-16 in rotated system
656
- // nSolution = 1
657
- const c0 = lambda * cosCoff;
658
- const s0 = lambda * sinCoff;
659
- result = [Point2dVector2d_1.Vector2d.create(c0, s0)];
660
- }
661
- else if (D2 > 0.0) {
662
- const mu = Math.sqrt(D2 / delta2);
663
- /* c0,s0 = closest approach of line to origin */
664
- const c0 = lambda * cosCoff;
665
- const s0 = lambda * sinCoff;
666
- // nSolution = 2
667
- result = [Point2dVector2d_1.Vector2d.create(c0 - mu * sinCoff, s0 + mu * cosCoff), Point2dVector2d_1.Vector2d.create(c0 + mu * sinCoff, s0 - mu * cosCoff)];
668
- }
757
+ /**
758
+ * Solutions can be found by finding the intersection of line "ax + by + d = 0" and unit circle "x^2 + y^2 = 1".
759
+ * From the line equation we have "y = (-ax - d) / b". By replacing this into the circle equation we get
760
+ * "x^2 + (ax+d)^2/b^2 = 1". If we solve this by quadratic formula we get
761
+ * x = (-ad +- b*sqrt(a^2+b^2-d^2)) / (a^2+b^2)
762
+ * y = (-ad -+ a*sqrt(a^2+b^2-d^2)) / (a^2+b^2)
763
+ *
764
+ * If "a^2+b^2-d^2 > 0" then there are two solutions (above).
765
+ * If "a^2+b^2-d^2 = 0" then there is one solution which is (-ad/(a^2+b^2), -bd/(a^2+b^2)).
766
+ * If "a^2+b^2-d^2 < 0" then there is no solution.
767
+ *
768
+ * Below in the code we have "a = cosCoff", "b = sinCoff", and "d = constCoff". Also equivalent criterion
769
+ * is used in the code. For example, "a^2+b^2-d^2 > 0" is equivalent of "1 - d^2/(a^2+b^2) > 0".
770
+ */
771
+ const a2b2 = cosCoff * cosCoff + sinCoff * sinCoff; // a^2+b^2
772
+ const d2 = constCoff * constCoff; // d^2
773
+ let result;
774
+ if (a2b2 > 0.0) {
775
+ const a2b2r = 1.0 / a2b2; // 1/(a^2+b^2)
776
+ const d2a2b2 = d2 * a2b2r; // d^2/(a^2+b^2)
777
+ const criteria = 1.0 - d2a2b2; // 1 - d^2/(a^2+b^2); the criteria to specify how many solutions we got
778
+ if (criteria < -Geometry.smallMetricDistanceSquared) // nSolution = 0
779
+ return result;
780
+ const da2b2 = -constCoff * a2b2r; // -d/(a^2+b^2)
781
+ const c0 = da2b2 * cosCoff; // -ad/(a^2+b^2)
782
+ const s0 = da2b2 * sinCoff; // -bd/(a^2+b^2)
783
+ if (criteria <= 0.0) { // nSolution = 1 (observed criteria = -2.22e-16 in rotated system)
784
+ result = [Point2dVector2d_1.Vector2d.create(c0, s0)];
785
+ }
786
+ else if (criteria > 0.0) { // nSolution = 2
787
+ const s = Math.sqrt(criteria * a2b2r); // sqrt(a^2+b^2-d^2)) / (a^2+b^2)
788
+ result = [
789
+ Point2dVector2d_1.Vector2d.create(c0 - s * sinCoff, s0 + s * cosCoff),
790
+ Point2dVector2d_1.Vector2d.create(c0 + s * sinCoff, s0 - s * cosCoff),
791
+ ];
669
792
  }
670
- return result;
671
793
  }
794
+ return result;
672
795
  }
673
- /** For a line f(x) whose function values at x0 and x1 are f0 and f1, return the x value at which f(x)=fTarget; */
674
- static inverseInterpolate(x0, f0, x1, f1, targetF = 0, defaultResult) {
675
- const g = Geometry.conditionalDivideFraction(targetF - f0, f1 - f0);
676
- if (g)
677
- return Geometry.interpolate(x0, g, x1);
796
+ /**
797
+ * For a line `f(x)` where `f(x0) = f0` and `f(x1) = f1`, return the `x` value at which `f(x) = fTarget`
798
+ * Return `defaultResult` if `(fTarget - f0) / (f1 - f0)` exceeds `Geometry.largeFractionResult`
799
+ */
800
+ static inverseInterpolate(x0, f0, x1, f1, fTarget = 0, defaultResult) {
801
+ /**
802
+ * Line equation is "fTarget-f0 = (f1-f0)/(x1-x0) * (x-x0)" or "(fTarget-f0)/(f1-f0) = (x-x0)/(x1-x0)".
803
+ * The left hand side is known so if we call it "fr" (short for "fraction") we get "fr = (x-x0)/(x1-x0)".
804
+ * Therefore, "x = x0*(1-fr) + x1*fr". This is same as interpolation between "x0" and "x1" with fraction "fr".
805
+ */
806
+ const fr = Geometry.conditionalDivideFraction(fTarget - f0, f1 - f0); // (fTarget-f0)/(f1-f0)
807
+ if (fr !== undefined)
808
+ return Geometry.interpolate(x0, fr, x1); // x = x0*(1-fr) + x1*fr
678
809
  return defaultResult;
679
810
  }
680
- /** For a line f(x) whose function values at x=0 and x=1 are f0 and f1, return the x value at which f(x)=fTarget; */
681
- static inverseInterpolate01(f0, f1, targetF = 0) {
682
- return Geometry.conditionalDivideFraction(targetF - f0, f1 - f0);
811
+ /**
812
+ * For a line `f(x)` where `f(0) = f0` and `f(1) = f1`, return the `x` value at which `f(x) = fTarget`
813
+ * Return `undefined` if `(fTarget - f0) / (f1 - f0)` exceeds `Geometry.largeFractionResult`
814
+ */
815
+ static inverseInterpolate01(f0, f1, fTarget = 0) {
816
+ /**
817
+ * Line equation is "fTarget-f0 = (f1-f0)*x" so "x = (fTarget-f0)/(f1-f0)"
818
+ */
819
+ return Geometry.conditionalDivideFraction(fTarget - f0, f1 - f0); // x = (fTarget-f0)/(f1-f0)
683
820
  }
684
- /** Return true if json is an array with at least minEntries, and all entries are numbers (including those beyond minEntries) */
821
+ /**
822
+ * Return `true` if `json` is an array with at least `minEntries` entries and all entries are numbers (including
823
+ * those beyond minEntries).
824
+ */
685
825
  static isNumberArray(json, minEntries = 0) {
686
826
  if (Array.isArray(json) && json.length >= minEntries) {
687
827
  let entry;
688
828
  for (entry of json) {
689
- // if (!(entry as number) && entry !== 0.0)
690
829
  if (!Number.isFinite(entry))
691
830
  return false;
692
831
  }
@@ -694,10 +833,12 @@ class Geometry {
694
833
  }
695
834
  return false;
696
835
  }
697
- /** Return true if json is an array of at least numNumberArrays, with at least minEntries in each number array.
836
+ /**
837
+ * Return `true` if `json` is an array of at least `minArrays` arrays with at least `minEntries` entries in
838
+ * each array and all entries are numbers (including those beyond minEntries).
698
839
  */
699
- static isArrayOfNumberArray(json, numNumberArray, minEntries = 0) {
700
- if (Array.isArray(json) && json.length >= numNumberArray) {
840
+ static isArrayOfNumberArray(json, minArrays, minEntries = 0) {
841
+ if (Array.isArray(json) && json.length >= minArrays) {
701
842
  let entry;
702
843
  for (entry of json)
703
844
  if (!Geometry.isNumberArray(entry, minEntries))
@@ -706,36 +847,53 @@ class Geometry {
706
847
  }
707
848
  return false;
708
849
  }
709
- /** return the number of steps to take so that numSteps * stepSize >= total.
710
- * minCount is returned for both (a) setSize 0 or less and (b) stepSize > total.
711
- * A small tolerance is applied for almost
712
- */
850
+ /**
851
+ * Return the number of steps to take so that `numSteps * stepSize >= total`.
852
+ * * `minCount` is returned in the following 3 cases:
853
+ * * (a) `stepSize <= 0`
854
+ * * (b) `stepSize >= total`
855
+ * * (b) `numSteps < minCount`
856
+ * * `maxCount` is returned if `numSteps > maxCount`.
857
+ */
713
858
  static stepCount(stepSize, total, minCount = 1, maxCount = 101) {
714
859
  if (stepSize <= 0)
715
860
  return minCount;
716
861
  total = Math.abs(total);
717
862
  if (stepSize >= total)
718
863
  return minCount;
719
- const stepCount = Math.floor((total + 0.999999 * stepSize) / stepSize);
720
- if (stepCount < minCount)
864
+ /**
865
+ * 0.999999 is multiplied so we return the same "numSteps" if
866
+ * stepSize*(numSteps-1) < total <= stepSize*numSteps.
867
+ * For example, if "stepSize = 2" then we return "numSteps = 5" if 8 < total <= 10.
868
+ */
869
+ const numSteps = Math.floor((total + 0.999999 * stepSize) / stepSize);
870
+ if (numSteps < minCount)
721
871
  return minCount;
722
- if (stepCount > maxCount)
872
+ if (numSteps > maxCount)
723
873
  return maxCount;
724
- return stepCount;
874
+ return numSteps;
725
875
  }
726
- /** Test if x is in simple 0..1 interval. But optionally skip the test. (this odd behavior is very convenient for code that sometimes does not do the filtering.)
876
+ /**
877
+ * Test if `x` is in the interval [0,1] (but skip the test if `apply01 = false`).
878
+ * * This odd behavior is very convenient for code that sometimes does not do the filtering.
727
879
  * @param x value to test.
728
- * @param apply01 if false, accept all x.
880
+ * @param apply01 if false, return `true` for all values of `x`.
729
881
  */
730
- static isIn01(x, apply01 = true) { return apply01 ? x >= 0.0 && x <= 1.0 : true; }
731
- /** Test if x is in simple 0..1 interval. But optionally skip the test. (this odd behavior is very convenient for code that sometimes does not do the filtering.)
882
+ static isIn01(x, apply01 = true) {
883
+ return apply01 ? x >= 0.0 && x <= 1.0 : true;
884
+ }
885
+ /**
886
+ * Test if `x` is in the interval [0,1] for a given positive `tolerance`.
887
+ * * Make sure to pass a positive `tolerance` because there is no check for that in the code.
732
888
  * @param x value to test.
733
- * @param apply01 if false, accept all x.
889
+ * @param tolerance the tolerance.
734
890
  */
735
- static isIn01WithTolerance(x, tolerance) { return x + tolerance >= 0.0 && x - tolerance <= 1.0; }
891
+ static isIn01WithTolerance(x, tolerance) {
892
+ return x + tolerance >= 0.0 && x - tolerance <= 1.0;
893
+ }
736
894
  /**
737
- * restrict x so it is in the interval `[a,b]`, allowing a,b to be in either order.
738
- * @param x
895
+ * Restrict x so it is in the interval `[a,b]` (allowing `a` and `b` to be in either order).
896
+ * @param x value to restrict
739
897
  * @param a (usually the lower) interval limit
740
898
  * @param b (usually the upper) interval limit
741
899
  */
@@ -747,7 +905,7 @@ class Geometry {
747
905
  return b;
748
906
  return x;
749
907
  }
750
- // reversed interval ....
908
+ // reversed interval
751
909
  if (x < b)
752
910
  return b;
753
911
  if (x > a)
@@ -756,12 +914,15 @@ class Geometry {
756
914
  }
757
915
  /**
758
916
  * Case-insensitive string comparison.
759
- * * Return true if the toUpperCase values match.
917
+ * * Return `true` if the `toUpperCase` values of `string1` and `string2` match.
760
918
  */
761
919
  static equalStringNoCase(string1, string2) {
762
920
  return string1.toUpperCase() === string2.toUpperCase();
763
921
  }
764
- /** test for EXACT match of number arrays. */
922
+ /**
923
+ * Test for exact match of two number arrays.
924
+ * Returns `true` if both arrays have the same length and entries, or if both arrays are empty or `undefined`.
925
+ */
765
926
  static exactEqualNumberArrays(a, b) {
766
927
  if (Array.isArray(a) && a.length === 0)
767
928
  a = undefined;
@@ -779,7 +940,10 @@ class Geometry {
779
940
  }
780
941
  return false;
781
942
  }
782
- /** test for match of XYZ arrays. */
943
+ /**
944
+ * Test for match of two arrays of type `T`.
945
+ * Returns `true` if both arrays have the same length and have the same entries (or both are empty arrays).
946
+ */
783
947
  static almostEqualArrays(a, b, testFunction) {
784
948
  if (Array.isArray(a) && a.length === 0)
785
949
  a = undefined;
@@ -798,7 +962,10 @@ class Geometry {
798
962
  }
799
963
  return false;
800
964
  }
801
- /** test for match of typed arrays (e.g. Float64Array). */
965
+ /**
966
+ * Test for match of two arrays of type number or Float64Array.
967
+ * Returns `true` if both arrays have the same length and have the same entries (or both are empty arrays).
968
+ */
802
969
  static almostEqualNumberArrays(a, b, testFunction) {
803
970
  if (Array.isArray(a) && a.length === 0)
804
971
  a = undefined;
@@ -818,15 +985,12 @@ class Geometry {
818
985
  return false;
819
986
  }
820
987
  /**
821
- * Return
822
- * * true if both values are defined and equal (with ===).
823
- * * false if both defined by not equal
824
- * * return (option arg) resultIfBothUndefined when both are undefined.
825
- * * return false if one is defined and the other undefined
988
+ * Test for match of two values of type `T`.
826
989
  * @param a first value
827
990
  * @param b second value
828
- * @param resultIfBothUndefined return value when both are undefined.
829
- * @returns
991
+ * @param resultIfBothUndefined returned value when both are `undefined`
992
+ * @returns `true` if both values are defined and equal (with ===) and `false` if both values are defined
993
+ * but not equal or if one is defined and the other undefined.
830
994
  */
831
995
  static areEqualAllowUndefined(a, b, resultIfBothUndefined = true) {
832
996
  if (a === undefined && b === undefined)
@@ -835,46 +999,52 @@ class Geometry {
835
999
  return a === b;
836
1000
  return false;
837
1001
  }
838
- /** clone an array whose members have a clone method.
839
- * * undefined return from clone is forced into the output array.
840
- */
841
- static cloneMembers(a) {
842
- if (a === undefined)
1002
+ /**
1003
+ * Clone an array whose members have type `T`, which implements the clone method.
1004
+ * * If the clone method returns `undefined`, then `undefined` is forced into the cloned array.
1005
+ */
1006
+ static cloneMembers(array) {
1007
+ if (array === undefined)
843
1008
  return undefined;
844
- const b = [];
845
- for (const p of a) {
846
- b.push(p.clone());
1009
+ const clonedArray = [];
1010
+ for (const element of array) {
1011
+ clonedArray.push(element.clone());
847
1012
  }
848
- return b;
1013
+ return clonedArray;
849
1014
  }
850
1015
  }
851
- /** Tolerance for small distances in metric coordinates */
1016
+ /** Tolerance for small distances in metric coordinates. */
852
1017
  Geometry.smallMetricDistance = 1.0e-6;
853
- /** Square of `smallMetricTolerance` */
1018
+ /** Square of `smallMetricDistance`. */
854
1019
  Geometry.smallMetricDistanceSquared = 1.0e-12;
855
- /** tolerance for small angle measured in radians. */
1020
+ /** Tolerance for small angle measured in radians. */
856
1021
  Geometry.smallAngleRadians = 1.0e-12;
857
- /** square of `smallAngleRadians` */
1022
+ /** Square of `smallAngleRadians`. */
858
1023
  Geometry.smallAngleRadiansSquared = 1.0e-24;
859
- /** tolerance for small angle measured in degrees. */
1024
+ /** Tolerance for small angle measured in degrees. */
860
1025
  Geometry.smallAngleDegrees = 5.7e-11;
861
- /** tolerance for small angle measured in arc-seconds. */
1026
+ /** Tolerance for small angle measured in arc-seconds. */
862
1027
  Geometry.smallAngleSeconds = 2e-7;
863
- /** numeric value that may be considered huge for a ratio of numbers.
864
- * * Note that the "allowed" result value is vastly larger than 1.
1028
+ /** Numeric value that may be considered zero for fractions between 0 and 1. */
1029
+ Geometry.smallFraction = 1.0e-10;
1030
+ /** Radians value for full circle 2PI radians minus `smallAngleRadians`. */
1031
+ Geometry.fullCircleRadiansMinusSmallAngle = 2.0 * Math.PI - Geometry.smallAngleRadians;
1032
+ /**
1033
+ * Numeric value that may be considered large for a ratio of numbers.
1034
+ * * Note that the allowed result value is vastly larger than 1.
865
1035
  */
866
1036
  Geometry.largeFractionResult = 1.0e10;
867
- /** numeric value that may be considered zero for fractions between 0 and 1. */
868
- Geometry.smallFraction = 1.0e-10;
869
- /** numeric value that may considered huge for numbers expected to be coordinates.
1037
+ /**
1038
+ * Numeric value that may considered large for numbers expected to be coordinates.
870
1039
  * * This allows larger results than `largeFractionResult`.
871
1040
  */
872
1041
  Geometry.largeCoordinateResult = 1.0e13;
873
- /** numeric value that may considered infinite for metric coordinates.
874
- * * This coordinate should be used only as a placeholder indicating "at infinity" -- computing actual points at this coordinate invites numerical problems.
1042
+ /**
1043
+ * Numeric value that may considered infinite for metric coordinates.
1044
+ * @deprecated in 4.x. Use `largeCoordinateResult`.
1045
+ * * This coordinate should be used only as a placeholder indicating "at infinity" -- computing actual
1046
+ * points at this coordinate invites numerical problems.
875
1047
  */
876
1048
  Geometry.hugeCoordinate = 1.0e12;
877
- /** Radians value for full circle 2PI radians minus `smallAngleRadians` */
878
- Geometry.fullCircleRadiansMinusSmallAngle = 2.0 * Math.PI - 1.0e-12; // smallAngleRadians less than 360degrees
879
1049
  exports.Geometry = Geometry;
880
1050
  //# sourceMappingURL=Geometry.js.map