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