@itwin/core-geometry 3.5.0 → 3.6.0-dev.10
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 +5 -5
- package/lib/cjs/Geometry.d.ts.map +1 -1
- package/lib/cjs/Geometry.js +15 -9
- package/lib/cjs/Geometry.js.map +1 -1
- package/lib/cjs/bspline/BSplineCurve.d.ts +3 -7
- package/lib/cjs/bspline/BSplineCurve.d.ts.map +1 -1
- package/lib/cjs/bspline/BSplineCurve.js +15 -14
- package/lib/cjs/bspline/BSplineCurve.js.map +1 -1
- package/lib/cjs/curve/Arc3d.d.ts +2 -2
- package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
- package/lib/cjs/curve/Arc3d.js +2 -2
- package/lib/cjs/curve/Arc3d.js.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts +9 -5
- package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js +9 -18
- package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/cjs/geometry3d/Angle.d.ts +46 -32
- package/lib/cjs/geometry3d/Angle.d.ts.map +1 -1
- package/lib/cjs/geometry3d/Angle.js +171 -84
- package/lib/cjs/geometry3d/Angle.js.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.d.ts +102 -60
- package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/cjs/geometry3d/AngleSweep.js +191 -106
- package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js +1 -1
- package/lib/cjs/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/lib/esm/Geometry.d.ts +5 -5
- package/lib/esm/Geometry.d.ts.map +1 -1
- package/lib/esm/Geometry.js +15 -9
- package/lib/esm/Geometry.js.map +1 -1
- package/lib/esm/bspline/BSplineCurve.d.ts +3 -7
- package/lib/esm/bspline/BSplineCurve.d.ts.map +1 -1
- package/lib/esm/bspline/BSplineCurve.js +15 -14
- package/lib/esm/bspline/BSplineCurve.js.map +1 -1
- package/lib/esm/curve/Arc3d.d.ts +2 -2
- package/lib/esm/curve/Arc3d.d.ts.map +1 -1
- package/lib/esm/curve/Arc3d.js +2 -2
- package/lib/esm/curve/Arc3d.js.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts +9 -5
- package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
- package/lib/esm/curve/CurveChainWithDistanceIndex.js +9 -18
- package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
- package/lib/esm/geometry3d/Angle.d.ts +46 -32
- package/lib/esm/geometry3d/Angle.d.ts.map +1 -1
- package/lib/esm/geometry3d/Angle.js +171 -84
- package/lib/esm/geometry3d/Angle.js.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.d.ts +102 -60
- package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
- package/lib/esm/geometry3d/AngleSweep.js +191 -106
- package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
- package/lib/esm/geometry3d/Point2dArrayCarrier.js.map +1 -1
- package/package.json +4 -4
|
@@ -10,30 +10,46 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
10
10
|
exports.Angle = void 0;
|
|
11
11
|
const Geometry_1 = require("../Geometry");
|
|
12
12
|
/**
|
|
13
|
-
* An `Angle` carries the numeric value of an angle, with methods to allow (require!) callers to
|
|
14
|
-
*
|
|
15
|
-
* *
|
|
13
|
+
* An `Angle` carries the numeric value of an angle, with methods to allow (require!) callers to
|
|
14
|
+
* be clear about whether their angle is degrees or radians.
|
|
15
|
+
* * After the Angle object is created, the callers should not know or care whether it is stored in
|
|
16
|
+
* `degrees` or `radians` because both are available if requested by caller.
|
|
17
|
+
* * The various access method are named so that callers can specify whether untyped numbers passed in or
|
|
18
|
+
* out are degrees or radians.
|
|
16
19
|
* @public
|
|
17
20
|
*/
|
|
18
21
|
class Angle {
|
|
19
|
-
constructor(radians = 0, degrees) {
|
|
22
|
+
constructor(radians = 0, degrees) {
|
|
23
|
+
this._radians = radians;
|
|
24
|
+
this._degrees = degrees;
|
|
25
|
+
}
|
|
20
26
|
/** Return a new angle with the same content. */
|
|
21
|
-
clone() {
|
|
27
|
+
clone() {
|
|
28
|
+
return new Angle(this._radians, this._degrees);
|
|
29
|
+
}
|
|
22
30
|
/** Freeze this instance so it is read-only */
|
|
23
|
-
freeze() {
|
|
31
|
+
freeze() {
|
|
32
|
+
return Object.freeze(this);
|
|
33
|
+
}
|
|
24
34
|
/**
|
|
25
35
|
* Return a new Angle object for angle given in degrees.
|
|
26
36
|
* @param degrees angle in degrees
|
|
27
37
|
*/
|
|
28
|
-
static createDegrees(degrees) {
|
|
38
|
+
static createDegrees(degrees) {
|
|
39
|
+
return new Angle(Angle.degreesToRadians(degrees), degrees);
|
|
40
|
+
}
|
|
29
41
|
/**
|
|
30
42
|
* Return a (new) Angle object for a value given in radians.
|
|
31
43
|
* @param radians angle in radians
|
|
32
44
|
*/
|
|
33
|
-
static createRadians(radians) {
|
|
45
|
+
static createRadians(radians) {
|
|
46
|
+
return new Angle(radians);
|
|
47
|
+
}
|
|
34
48
|
/**
|
|
35
|
-
* Return a (new) Angle object that is interpolated between two inputs
|
|
36
|
-
* @param
|
|
49
|
+
* Return a (new) Angle object that is interpolated between two inputs (based on a fraction)
|
|
50
|
+
* @param angle0 first angle in radians
|
|
51
|
+
* @param fraction the interpolation fraction
|
|
52
|
+
* @param angle1 second angle in radians
|
|
37
53
|
*/
|
|
38
54
|
static createInterpolate(angle0, fraction, angle1) {
|
|
39
55
|
return new Angle(Geometry_1.Geometry.interpolate(angle0.radians, fraction, angle1.radians));
|
|
@@ -42,45 +58,49 @@ class Angle {
|
|
|
42
58
|
* Return a (new) Angle object, with angle scaled from existing angle.
|
|
43
59
|
* @param scale scale factor to apply to angle.
|
|
44
60
|
*/
|
|
45
|
-
cloneScaled(scale) {
|
|
61
|
+
cloneScaled(scale) {
|
|
62
|
+
return new Angle(this.radians * scale);
|
|
63
|
+
}
|
|
46
64
|
/**
|
|
47
65
|
* Set this angle to a value given in radians.
|
|
48
66
|
* @param radians angle given in radians
|
|
49
67
|
*/
|
|
50
|
-
setRadians(radians) {
|
|
68
|
+
setRadians(radians) {
|
|
69
|
+
this._radians = radians;
|
|
70
|
+
this._degrees = undefined;
|
|
71
|
+
}
|
|
51
72
|
/**
|
|
52
73
|
* Set this angle to a value given in degrees.
|
|
53
74
|
* @param degrees angle given in degrees.
|
|
54
75
|
*/
|
|
55
|
-
setDegrees(degrees) {
|
|
76
|
+
setDegrees(degrees) {
|
|
77
|
+
this._radians = Angle.degreesToRadians(degrees);
|
|
78
|
+
this._degrees = degrees;
|
|
79
|
+
}
|
|
56
80
|
/** Create an angle for a full circle. */
|
|
57
|
-
static create360() {
|
|
81
|
+
static create360() {
|
|
82
|
+
return new Angle(Math.PI * 2.0, 360.0);
|
|
83
|
+
}
|
|
58
84
|
/**
|
|
59
|
-
*
|
|
60
|
-
* quadrant.
|
|
85
|
+
* Create a (strongly typed) Angle whose tangent is `numerator/denominator`, using the signs of both in
|
|
86
|
+
* determining the (otherwise ambiguous) quadrant.
|
|
61
87
|
* @param numerator numerator for tangent
|
|
62
88
|
* @param denominator denominator for tangent
|
|
63
89
|
*/
|
|
64
|
-
static createAtan2(numerator, denominator) {
|
|
90
|
+
static createAtan2(numerator, denominator) {
|
|
91
|
+
return new Angle(Math.atan2(numerator, denominator));
|
|
92
|
+
}
|
|
65
93
|
/**
|
|
66
94
|
* Copy all contents of `other` to this Angle.
|
|
67
95
|
* @param other source data
|
|
68
96
|
*/
|
|
69
|
-
setFrom(other) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
* @param json object from JSON.parse. If a number, value is in *DEGREES*
|
|
73
|
-
* @param defaultValRadians if json is undefined, default value in radians.
|
|
74
|
-
* @return a new Angle
|
|
75
|
-
*/
|
|
76
|
-
static fromJSON(json, defaultValRadians) {
|
|
77
|
-
const val = new Angle();
|
|
78
|
-
val.setFromJSON(json, defaultValRadians);
|
|
79
|
-
return val;
|
|
97
|
+
setFrom(other) {
|
|
98
|
+
this._radians = other._radians;
|
|
99
|
+
this._degrees = other._degrees;
|
|
80
100
|
}
|
|
81
101
|
/**
|
|
82
|
-
*
|
|
83
|
-
* * A simple number is degrees.
|
|
102
|
+
* Set an Angle from a JSON object
|
|
103
|
+
* * A simple number is considered as degrees.
|
|
84
104
|
* * specified `json.degrees` or `json._degrees` is degree value.
|
|
85
105
|
* * specified `son.radians` or `json._radians` is radians value.
|
|
86
106
|
* @param json object from JSON.parse. If a number, value is in *DEGREES*
|
|
@@ -106,19 +126,40 @@ class Angle {
|
|
|
106
126
|
this.setRadians(json._radians);
|
|
107
127
|
}
|
|
108
128
|
}
|
|
129
|
+
/**
|
|
130
|
+
* Create an Angle from a JSON object
|
|
131
|
+
* @param json object from JSON.parse. If a number, value is in *DEGREES*
|
|
132
|
+
* @param defaultValRadians if json is undefined, default value in radians.
|
|
133
|
+
* @return a new Angle
|
|
134
|
+
*/
|
|
135
|
+
static fromJSON(json, defaultValRadians) {
|
|
136
|
+
const val = new Angle();
|
|
137
|
+
val.setFromJSON(json, defaultValRadians);
|
|
138
|
+
return val;
|
|
139
|
+
}
|
|
109
140
|
/** Convert an Angle to a JSON object as a number in degrees */
|
|
110
|
-
toJSON() {
|
|
141
|
+
toJSON() {
|
|
142
|
+
return this.degrees;
|
|
143
|
+
}
|
|
111
144
|
/** Return a json object with radians keyword, e.g. `{ radians: 0.10}` */
|
|
112
|
-
toJSONRadians() {
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
get
|
|
145
|
+
toJSONRadians() {
|
|
146
|
+
return { radians: this.radians };
|
|
147
|
+
}
|
|
148
|
+
/** Return the angle measured in radians. */
|
|
149
|
+
get radians() {
|
|
150
|
+
return this._radians;
|
|
151
|
+
}
|
|
152
|
+
/** Return the angle measured in degrees. */
|
|
153
|
+
get degrees() {
|
|
154
|
+
return this._degrees !== undefined ? this._degrees : Angle.radiansToDegrees(this._radians);
|
|
155
|
+
}
|
|
117
156
|
/**
|
|
118
157
|
* Convert an angle in degrees to radians.
|
|
119
158
|
* @param degrees angle in degrees
|
|
120
159
|
*/
|
|
121
|
-
static degreesToRadians(degrees) {
|
|
160
|
+
static degreesToRadians(degrees) {
|
|
161
|
+
return degrees * Math.PI / 180;
|
|
162
|
+
}
|
|
122
163
|
/**
|
|
123
164
|
* Convert an angle in radians to degrees.
|
|
124
165
|
* @param degrees angle in radians
|
|
@@ -129,6 +170,11 @@ class Angle {
|
|
|
129
170
|
// Now radians is positive ...
|
|
130
171
|
const pi = Math.PI;
|
|
131
172
|
const factor = 180.0 / pi;
|
|
173
|
+
/* the following if statements are for round-off reasons. The problem is that no IEEE number is
|
|
174
|
+
* an exact hit for any primary multiple of pi (90, 180, etc). The following is supposed to have
|
|
175
|
+
* a better chance that if the input was computed by direct assignment from 90, 180, etc degrees
|
|
176
|
+
* it will return exactly 90,180 etc.
|
|
177
|
+
*/
|
|
132
178
|
if (radians <= 0.25 * pi)
|
|
133
179
|
return factor * radians;
|
|
134
180
|
if (radians < 0.75 * pi)
|
|
@@ -143,27 +189,37 @@ class Angle {
|
|
|
143
189
|
/**
|
|
144
190
|
* Return the cosine of this Angle object's angle.
|
|
145
191
|
*/
|
|
146
|
-
cos() {
|
|
192
|
+
cos() {
|
|
193
|
+
return Math.cos(this._radians);
|
|
194
|
+
}
|
|
147
195
|
/**
|
|
148
196
|
* Return the sine of this Angle object's angle.
|
|
149
197
|
*/
|
|
150
|
-
sin() {
|
|
198
|
+
sin() {
|
|
199
|
+
return Math.sin(this._radians);
|
|
200
|
+
}
|
|
151
201
|
/**
|
|
152
202
|
* Return the tangent of this Angle object's angle.
|
|
153
203
|
*/
|
|
154
|
-
tan() {
|
|
155
|
-
|
|
204
|
+
tan() {
|
|
205
|
+
return Math.tan(this._radians);
|
|
206
|
+
}
|
|
207
|
+
/** Test if a radians (absolute) value is nearly 2PI or larger! */
|
|
156
208
|
static isFullCircleRadians(radians) {
|
|
157
209
|
return Math.abs(radians) >= Geometry_1.Geometry.fullCircleRadiansMinusSmallAngle;
|
|
158
210
|
}
|
|
159
|
-
/** Test if the radians value
|
|
211
|
+
/** Test if the radians value is a half circle */
|
|
160
212
|
static isHalfCircleRadians(radians) {
|
|
161
213
|
return Math.abs(Math.abs(radians) - Math.PI) <= Geometry_1.Geometry.smallAngleRadians;
|
|
162
214
|
}
|
|
163
|
-
/** test if the angle is
|
|
164
|
-
get isFullCircle() {
|
|
215
|
+
/** test if the angle is a full circle */
|
|
216
|
+
get isFullCircle() {
|
|
217
|
+
return Angle.isFullCircleRadians(this._radians);
|
|
218
|
+
}
|
|
165
219
|
/** test if the angle is a half circle (in either direction) */
|
|
166
|
-
get isHalfCircle() {
|
|
220
|
+
get isHalfCircle() {
|
|
221
|
+
return Angle.isHalfCircleRadians(this._radians);
|
|
222
|
+
}
|
|
167
223
|
/** Adjust a radians value so it is positive in 0..360 */
|
|
168
224
|
static adjustDegrees0To360(degrees) {
|
|
169
225
|
if (degrees >= 0) {
|
|
@@ -175,8 +231,8 @@ class Angle {
|
|
|
175
231
|
}
|
|
176
232
|
else if (degrees < 0) {
|
|
177
233
|
// negative angle ...
|
|
178
|
-
const
|
|
179
|
-
return 360.0 -
|
|
234
|
+
const radians = Angle.adjustDegrees0To360(-degrees);
|
|
235
|
+
return 360.0 - radians;
|
|
180
236
|
}
|
|
181
237
|
// fall through for Nan (disaster) !!!
|
|
182
238
|
return 0;
|
|
@@ -208,8 +264,7 @@ class Angle {
|
|
|
208
264
|
}
|
|
209
265
|
else if (radians < 0) {
|
|
210
266
|
// negative angle ...
|
|
211
|
-
|
|
212
|
-
return Math.PI * 2.0 - radians1;
|
|
267
|
+
return Math.PI * 2.0 - Angle.adjustRadians0To2Pi(-radians);
|
|
213
268
|
}
|
|
214
269
|
// fall through for NaN disaster.
|
|
215
270
|
return 0;
|
|
@@ -231,17 +286,29 @@ class Angle {
|
|
|
231
286
|
return 0;
|
|
232
287
|
}
|
|
233
288
|
/** return a (newly allocated) Angle object with value 0 radians */
|
|
234
|
-
static zero() {
|
|
289
|
+
static zero() {
|
|
290
|
+
return new Angle(0);
|
|
291
|
+
}
|
|
235
292
|
/** Test if the angle is exactly zero. */
|
|
236
|
-
get isExactZero() {
|
|
293
|
+
get isExactZero() {
|
|
294
|
+
return this.radians === 0;
|
|
295
|
+
}
|
|
237
296
|
/** Test if the angle is almost zero (within tolerance `Geometry.smallAngleRadians`) */
|
|
238
|
-
get isAlmostZero() {
|
|
297
|
+
get isAlmostZero() {
|
|
298
|
+
return Math.abs(this.radians) < Geometry_1.Geometry.smallAngleRadians;
|
|
299
|
+
}
|
|
239
300
|
/** Test if the angle is almost a north or south pole (within tolerance `Geometry.smallAngleRadians`) */
|
|
240
|
-
get isAlmostNorthOrSouthPole() {
|
|
301
|
+
get isAlmostNorthOrSouthPole() {
|
|
302
|
+
return Angle.isHalfCircleRadians(this.radians * 2.0);
|
|
303
|
+
}
|
|
241
304
|
/** Create an angle object with degrees adjusted into 0..360. */
|
|
242
|
-
static createDegreesAdjustPositive(degrees) {
|
|
305
|
+
static createDegreesAdjustPositive(degrees) {
|
|
306
|
+
return Angle.createDegrees(Angle.adjustDegrees0To360(degrees));
|
|
307
|
+
}
|
|
243
308
|
/** Create an angle object with degrees adjusted into -180..180. */
|
|
244
|
-
static createDegreesAdjustSigned180(degrees) {
|
|
309
|
+
static createDegreesAdjustSigned180(degrees) {
|
|
310
|
+
return Angle.createDegrees(Angle.adjustDegreesSigned180(degrees));
|
|
311
|
+
}
|
|
245
312
|
/**
|
|
246
313
|
* Test if two radians values are equivalent, allowing shift by full circle (i.e. by a multiple of `2*PI`)
|
|
247
314
|
* @param radiansA first radians value
|
|
@@ -305,40 +372,55 @@ class Angle {
|
|
|
305
372
|
&& dotUV * dotUV <= Geometry_1.Geometry.smallAngleRadiansSquared * dotUU * dotVV;
|
|
306
373
|
}
|
|
307
374
|
/**
|
|
308
|
-
* Return cosine, sine, and radians for the half angle of a cosine,sine pair.
|
|
375
|
+
* Return cosine, sine, and radians for the half angle of a "cosine,sine" pair.
|
|
376
|
+
* * This function assumes the input arguments are related to an angle between -PI and PI
|
|
377
|
+
* * This function returns an angle between -PI and PI
|
|
309
378
|
* @param rCos2A cosine value (scaled by radius) for initial angle.
|
|
310
379
|
* @param rSin2A sine value (scaled by radius) for final angle.
|
|
311
380
|
*/
|
|
312
381
|
static trigValuesToHalfAngleTrigValues(rCos2A, rSin2A) {
|
|
313
382
|
const r = Geometry_1.Geometry.hypotenuseXY(rCos2A, rSin2A);
|
|
314
383
|
if (r < Geometry_1.Geometry.smallMetricDistance) {
|
|
315
|
-
return { c: 1.0, s: 0.0, radians: 0.0 };
|
|
384
|
+
return { c: 1.0, s: 0.0, radians: 0.0 }; // angle = 0
|
|
316
385
|
}
|
|
317
386
|
else {
|
|
318
|
-
/* If the caller really gave you sine and cosine values, r should be 1. However
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
387
|
+
/* If the caller really gave you sine and cosine values, r should be 1. However,
|
|
388
|
+
* to allow scaled values -- e.g. the x and y components of any vector -- we normalize
|
|
389
|
+
* right here. This adds an extra sqrt and 2 divides to the whole process, but improves
|
|
390
|
+
* both the usefulness and robustness of the computation.
|
|
391
|
+
*/
|
|
322
392
|
let cosA;
|
|
323
393
|
let sinA = 0.0;
|
|
324
394
|
const cos2A = rCos2A / r;
|
|
325
395
|
const sin2A = rSin2A / r;
|
|
396
|
+
// Original angle in NE and SE quadrants. Half angle in same quadrant
|
|
326
397
|
if (cos2A >= 0.0) {
|
|
327
|
-
/*
|
|
398
|
+
/*
|
|
399
|
+
* We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2
|
|
400
|
+
* so 1 + cos2A = 2(cosA)^2 and therefore, cosA = sqrt((1+cos2A)/2)
|
|
401
|
+
* cosine is positive in NE and SE quadrants so we use +sqrt
|
|
402
|
+
*/
|
|
328
403
|
cosA = Math.sqrt(0.5 * (1.0 + cos2A));
|
|
329
|
-
sinA = sin2A
|
|
404
|
+
// We know sin2A = 2 sinA cosA so sinA = sin2A/(2*cosA)
|
|
405
|
+
sinA = sin2A / (2.0 * cosA);
|
|
330
406
|
}
|
|
331
407
|
else {
|
|
408
|
+
// Original angle in NW quadrant. Half angle in NE quadrant
|
|
332
409
|
if (sin2A > 0.0) {
|
|
333
|
-
/*
|
|
410
|
+
/*
|
|
411
|
+
* We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2
|
|
412
|
+
* so 1 - cos2A = 2(sinA)^2 and therefore, sinA = sqrt((1-cos2A)/2)
|
|
413
|
+
* sine is positive in NE quadrant so we use +sqrt
|
|
414
|
+
*/
|
|
334
415
|
sinA = Math.sqrt(0.5 * (1.0 - cos2A));
|
|
416
|
+
// Original angle in SW quadrant. Half angle in SE quadrant
|
|
335
417
|
}
|
|
336
418
|
else {
|
|
337
|
-
|
|
338
|
-
/* cosA comes out positive because both sines are negative. */
|
|
419
|
+
// sine is negative in SE quadrant so we use -sqrt
|
|
339
420
|
sinA = -Math.sqrt(0.5 * (1.0 - cos2A));
|
|
340
421
|
}
|
|
341
|
-
cosA = sin2A
|
|
422
|
+
// We know sin2A = 2 sinA cosA so cosA = sin2A/(2*sinA)
|
|
423
|
+
cosA = sin2A / (2.0 * sinA); // always positive
|
|
342
424
|
}
|
|
343
425
|
return { c: cosA, s: sinA, radians: Math.atan2(sinA, cosA) };
|
|
344
426
|
}
|
|
@@ -357,17 +439,24 @@ class Angle {
|
|
|
357
439
|
return value;
|
|
358
440
|
}
|
|
359
441
|
/**
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
442
|
+
* Return the half angle cosine, sine, and radians for given dot products between vectors. The vectors define
|
|
443
|
+
* an ellipse using x(t) = c + U cos(t) + V sin(t) so U and V are at angle t=0 degree and t=90 degree. The
|
|
444
|
+
* half angle t0 is an angle such that x(t0) is one of the ellipse semi-axis.
|
|
445
|
+
* * This construction arises e.g. in `Arc3d.toScaledMatrix3d`.
|
|
446
|
+
* * Given ellipse x(t) = c + U cos(t) + V sin(t), find t0 such that radial vector W(t0) = x(t0) - c is
|
|
447
|
+
* perpendicular to the ellipse.
|
|
448
|
+
* * Then 0 = W(t0).x'(t0) = (U cos(t0) + V sin(t0)).(V cos(t0) - U sin(t0)) = U.V cos(2t0) + 0.5 (V.V - U.U) sin(2t0)
|
|
449
|
+
* implies sin(2t0) / cos(2t0) = 2 U.V / (U.U - V.V), i.e., t0 can be computed given the three dot products on the RHS.
|
|
450
|
+
* @param dotUU dot product of vectorU with itself
|
|
451
|
+
* @param dotVV dot product of vectorV with itself
|
|
452
|
+
* @param dotUV dot product of vectorU with vectorV
|
|
453
|
+
*/
|
|
365
454
|
static dotProductsToHalfAngleTrigValues(dotUU, dotVV, dotUV, favorZero = true) {
|
|
366
|
-
const
|
|
367
|
-
const
|
|
368
|
-
if (favorZero && Math.abs(
|
|
455
|
+
const cos2t0 = dotUU - dotVV;
|
|
456
|
+
const sin2t0 = 2.0 * dotUV;
|
|
457
|
+
if (favorZero && Math.abs(sin2t0) < Geometry_1.Geometry.smallAngleRadians * (Math.abs(dotUU) + Math.abs(dotVV)))
|
|
369
458
|
return { c: 1.0, s: 0.0, radians: 0.0 };
|
|
370
|
-
return Angle.trigValuesToHalfAngleTrigValues(
|
|
459
|
+
return Angle.trigValuesToHalfAngleTrigValues(cos2t0, sin2t0);
|
|
371
460
|
}
|
|
372
461
|
/**
|
|
373
462
|
* * Returns the angle between two vectors, with the vectors given as xyz components
|
|
@@ -381,9 +470,7 @@ class Angle {
|
|
|
381
470
|
* @param vz z component of vector v
|
|
382
471
|
*/
|
|
383
472
|
static radiansBetweenVectorsXYZ(ux, uy, uz, vx, vy, vz) {
|
|
384
|
-
|
|
385
|
-
const uDotV = ux * vx + uy * vy + uz * vz; // magU magV cos(theta)
|
|
386
|
-
// const vv = vx * vx + vy * vy + vz * vz;
|
|
473
|
+
const uDotV = ux * vx + uy * vy + uz * vz;
|
|
387
474
|
return Math.atan2(Geometry_1.Geometry.crossProductMagnitude(ux, uy, uz, vx, vy, vz), uDotV);
|
|
388
475
|
}
|
|
389
476
|
/**
|
|
@@ -401,11 +488,13 @@ class Angle {
|
|
|
401
488
|
}
|
|
402
489
|
}
|
|
403
490
|
exports.Angle = Angle;
|
|
404
|
-
/** maximal accuracy value of pi/
|
|
491
|
+
/** maximal accuracy value of pi/12 (15 degrees), in radians */
|
|
492
|
+
Angle.piOver12Radians = 0.26179938779914943653855361527329;
|
|
493
|
+
/** maximal accuracy value of pi/4 (45 degrees), in radians */
|
|
405
494
|
Angle.piOver4Radians = 7.85398163397448280000e-001;
|
|
406
|
-
/** maximal accuracy value of pi/2 (
|
|
495
|
+
/** maximal accuracy value of pi/2 (90 degrees), in radians */
|
|
407
496
|
Angle.piOver2Radians = 1.57079632679489660000e+000;
|
|
408
|
-
/** maximal accuracy value of pi (
|
|
497
|
+
/** maximal accuracy value of pi (180 degrees), in radians */
|
|
409
498
|
Angle.piRadians = 3.14159265358979310000e+000;
|
|
410
499
|
/** maximal accuracy value of 2*pi (360 degrees), in radians */
|
|
411
500
|
Angle.pi2Radians = 6.28318530717958620000e+000;
|
|
@@ -413,6 +502,4 @@ Angle.pi2Radians = 6.28318530717958620000e+000;
|
|
|
413
502
|
Angle.degreesPerRadian = (45.0 / Angle.piOver4Radians);
|
|
414
503
|
/** scale factor for converting degrees to radians */
|
|
415
504
|
Angle.radiansPerDegree = (Angle.piOver4Radians / 45.0);
|
|
416
|
-
/** maximal accuracy value of pi/12 ( 15 degrees), in radians */
|
|
417
|
-
Angle.piOver12Radians = 0.26179938779914943653855361527329;
|
|
418
505
|
//# sourceMappingURL=Angle.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Angle.js","sourceRoot":"","sources":["../../../src/geometry3d/Angle.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module CartesianGeometry\r\n */\r\n\r\nimport { AngleProps, BeJSONFunctions, Geometry, TrigValues } from \"../Geometry\";\r\n\r\n/**\r\n * An `Angle` carries the numeric value of an angle, with methods to allow (require!) callers to be clear about whether their angle is degrees or radians.\r\n * * The numeric value is private, and callers should not know or care whether it is in degrees or radians.\r\n * * The various access method are named so that callers can specify whether untyped numbers passed in or out are degrees or radians.\r\n * @public\r\n */\r\nexport class Angle implements BeJSONFunctions {\r\n /** maximal accuracy value of pi/4 ( 45 degrees), in radians */\r\n public static readonly piOver4Radians = 7.85398163397448280000e-001;\r\n /** maximal accuracy value of pi/2 ( 90 degrees), in radians */\r\n public static readonly piOver2Radians = 1.57079632679489660000e+000;\r\n /** maximal accuracy value of pi ( 180 degrees), in radians */\r\n public static readonly piRadians = 3.14159265358979310000e+000;\r\n /** maximal accuracy value of 2*pi (360 degrees), in radians */\r\n public static readonly pi2Radians = 6.28318530717958620000e+000;\r\n /** scale factor for converting radians to degrees */\r\n public static readonly degreesPerRadian = (45.0 / Angle.piOver4Radians);\r\n /** scale factor for converting degrees to radians */\r\n public static readonly radiansPerDegree = (Angle.piOver4Radians / 45.0);\r\n /** maximal accuracy value of pi/12 ( 15 degrees), in radians */\r\n public static readonly piOver12Radians = 0.26179938779914943653855361527329;\r\n private _radians: number;\r\n private _degrees?: number;\r\n private constructor(radians = 0, degrees?: number) { this._radians = radians; this._degrees = degrees; }\r\n /** Return a new angle with the same content. */\r\n public clone(): Angle { return new Angle(this._radians, this._degrees); }\r\n /** Freeze this instance so it is read-only */\r\n public freeze(): Readonly<this> { return Object.freeze(this); }\r\n\r\n /**\r\n * Return a new Angle object for angle given in degrees.\r\n * @param degrees angle in degrees\r\n */\r\n public static createDegrees(degrees: number) { return new Angle(Angle.degreesToRadians(degrees), degrees); }\r\n /**\r\n * Return a (new) Angle object for a value given in radians.\r\n * @param radians angle in radians\r\n */\r\n public static createRadians(radians: number) { return new Angle(radians); }\r\n /**\r\n * Return a (new) Angle object that is interpolated between two inputs\r\n * @param radians angle in radians\r\n */\r\n public static createInterpolate(angle0: Angle, fraction: number, angle1: Angle) {\r\n return new Angle(Geometry.interpolate(angle0.radians, fraction, angle1.radians));\r\n }\r\n /**\r\n * Return a (new) Angle object, with angle scaled from existing angle.\r\n * @param scale scale factor to apply to angle.\r\n */\r\n public cloneScaled(scale: number) { return new Angle(this.radians * scale); }\r\n\r\n /**\r\n * Set this angle to a value given in radians.\r\n * @param radians angle given in radians\r\n */\r\n public setRadians(radians: number) { this._radians = radians; this._degrees = undefined; }\r\n /**\r\n * Set this angle to a value given in degrees.\r\n * @param degrees angle given in degrees.\r\n */\r\n public setDegrees(degrees: number) { this._radians = Angle.degreesToRadians(degrees); this._degrees = degrees; }\r\n /** Create an angle for a full circle. */\r\n public static create360() { return new Angle(Math.PI * 2.0, 360.0); }\r\n /**\r\n * @return a (strongly typed) Angle whose tangent is `numerator/denominator`, using the signs of both in determining the (otherwise ambiguous)\r\n * quadrant.\r\n * @param numerator numerator for tangent\r\n * @param denominator denominator for tangent\r\n */\r\n public static createAtan2(numerator: number, denominator: number): Angle { return new Angle(Math.atan2(numerator, denominator)); }\r\n /**\r\n * Copy all contents of `other` to this Angle.\r\n * @param other source data\r\n */\r\n public setFrom(other: Angle) { this._radians = other._radians; this._degrees = other._degrees; }\r\n /**\r\n * Create an Angle from a JSON object\r\n * @param json object from JSON.parse. If a number, value is in *DEGREES*\r\n * @param defaultValRadians if json is undefined, default value in radians.\r\n * @return a new Angle\r\n */\r\n public static fromJSON(json?: AngleProps, defaultValRadians?: number): Angle {\r\n const val = new Angle();\r\n val.setFromJSON(json, defaultValRadians);\r\n return val;\r\n }\r\n /**\r\n * set an Angle from a JSON object\r\n * * A simple number is degrees.\r\n * * specified `json.degrees` or `json._degrees` is degree value.\r\n * * specified `son.radians` or `json._radians` is radians value.\r\n * @param json object from JSON.parse. If a number, value is in *DEGREES*\r\n * @param defaultValRadians if json is undefined, default value in radians.\r\n */\r\n public setFromJSON(json?: AngleProps, defaultValRadians?: number) {\r\n this._radians = defaultValRadians ? defaultValRadians : 0;\r\n if (!json)\r\n return;\r\n if (typeof json === \"number\") {\r\n this.setDegrees(json);\r\n } else if (typeof (json as any).degrees === \"number\") {\r\n this.setDegrees((json as any).degrees);\r\n } else if (typeof (json as any)._degrees === \"number\") {\r\n this.setDegrees((json as any)._degrees);\r\n } else if (typeof (json as any).radians === \"number\") {\r\n this.setRadians((json as any).radians);\r\n } else if (typeof (json as any)._radians === \"number\") {\r\n this.setRadians((json as any)._radians);\r\n }\r\n }\r\n /** Convert an Angle to a JSON object as a number in degrees */\r\n public toJSON(): AngleProps { return this.degrees; }\r\n /** Return a json object with radians keyword, e.g. `{ radians: 0.10}` */\r\n public toJSONRadians(): AngleProps { return { radians: this.radians }; }\r\n /** Return the angle measured in radians. */\r\n public get radians(): number { return this._radians; }\r\n /** Return the angle measured in degrees. */\r\n public get degrees(): number { return this._degrees !== undefined ? this._degrees : Angle.radiansToDegrees(this._radians); }\r\n /**\r\n * Convert an angle in degrees to radians.\r\n * @param degrees angle in degrees\r\n */\r\n public static degreesToRadians(degrees: number) { return degrees * Math.PI / 180; }\r\n /**\r\n * Convert an angle in radians to degrees.\r\n * @param degrees angle in radians\r\n */\r\n public static radiansToDegrees(radians: number): number {\r\n if (radians < 0)\r\n return -Angle.radiansToDegrees(-radians);\r\n // Now radians is positive ...\r\n const pi = Math.PI;\r\n const factor = 180.0 / pi;\r\n if (radians <= 0.25 * pi)\r\n return factor * radians;\r\n if (radians < 0.75 * pi)\r\n return 90.0 + 180 * ((radians - 0.5 * pi) / pi);\r\n if (radians <= 1.25 * pi)\r\n return 180.0 + 180 * ((radians - pi) / pi);\r\n if (radians <= 1.75 * pi)\r\n return 270.0 + 180 * ((radians - 1.5 * pi) / pi);\r\n // all larger radians reference from 360 degrees (2PI)\r\n return 360.0 + 180 * ((radians - 2.0 * pi) / pi);\r\n }\r\n /**\r\n * Return the cosine of this Angle object's angle.\r\n */\r\n public cos(): number { return Math.cos(this._radians); }\r\n /**\r\n * Return the sine of this Angle object's angle.\r\n */\r\n public sin(): number { return Math.sin(this._radians); }\r\n /**\r\n * Return the tangent of this Angle object's angle.\r\n */\r\n public tan(): number { return Math.tan(this._radians); }\r\n /** Test if a radians (absolute) value is nearly 2PI or larger (!) */\r\n public static isFullCircleRadians(radians: number): boolean {\r\n return Math.abs(radians) >= Geometry.fullCircleRadiansMinusSmallAngle;\r\n }\r\n /** Test if the radians value is a complete circle */\r\n public static isHalfCircleRadians(radians: number): boolean {\r\n return Math.abs(Math.abs(radians) - Math.PI) <= Geometry.smallAngleRadians;\r\n }\r\n /** test if the angle is aa full circle */\r\n public get isFullCircle(): boolean { return Angle.isFullCircleRadians(this._radians); }\r\n\r\n /** test if the angle is a half circle (in either direction) */\r\n public get isHalfCircle(): boolean { return Angle.isHalfCircleRadians(this._radians); }\r\n /** Adjust a radians value so it is positive in 0..360 */\r\n public static adjustDegrees0To360(degrees: number): number {\r\n if (degrees >= 0) {\r\n const period = 360.0;\r\n if (degrees < period)\r\n return degrees;\r\n const numPeriods = Math.floor(degrees / period);\r\n return degrees - numPeriods * period;\r\n } else if (degrees < 0) {\r\n // negative angle ...\r\n const radians1 = Angle.adjustDegrees0To360(-degrees);\r\n return 360.0 - radians1;\r\n }\r\n // fall through for Nan (disaster) !!!\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is in -180..180 */\r\n public static adjustDegreesSigned180(degrees: number): number {\r\n if (Math.abs(degrees) <= 180.0)\r\n return degrees;\r\n if (degrees >= 0) {\r\n const period = 360.0;\r\n const numPeriods = 1 + Math.floor((degrees - 180.0) / period);\r\n return degrees - numPeriods * period;\r\n } else if (degrees < 0) {\r\n // negative angle ...\r\n return -Angle.adjustDegreesSigned180(-degrees);\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is positive in 0..2Pi */\r\n public static adjustRadians0To2Pi(radians: number): number {\r\n if (radians >= 0) {\r\n const period = Math.PI * 2.0;\r\n if (radians < period)\r\n return radians;\r\n const numPeriods = Math.floor(radians / period);\r\n return radians - numPeriods * period;\r\n } else if (radians < 0) {\r\n // negative angle ...\r\n const radians1 = Angle.adjustRadians0To2Pi(-radians);\r\n return Math.PI * 2.0 - radians1;\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is positive in -PI..PI */\r\n public static adjustRadiansMinusPiPlusPi(radians: number): number {\r\n if (Math.abs(radians) <= Math.PI)\r\n return radians;\r\n if (radians >= 0) {\r\n const period = Math.PI * 2.0;\r\n const numPeriods = 1 + Math.floor((radians - Math.PI) / period);\r\n return radians - numPeriods * period;\r\n } else if (radians < 0) {\r\n // negative angle ...\r\n return -Angle.adjustRadiansMinusPiPlusPi(-radians);\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** return a (newly allocated) Angle object with value 0 radians */\r\n public static zero() { return new Angle(0); }\r\n /** Test if the angle is exactly zero. */\r\n public get isExactZero() { return this.radians === 0; }\r\n /** Test if the angle is almost zero (within tolerance `Geometry.smallAngleRadians`) */\r\n public get isAlmostZero() { return Math.abs(this.radians) < Geometry.smallAngleRadians; }\r\n /** Test if the angle is almost a north or south pole (within tolerance `Geometry.smallAngleRadians`) */\r\n public get isAlmostNorthOrSouthPole() { return Angle.isHalfCircleRadians(this.radians * 2.0); }\r\n\r\n /** Create an angle object with degrees adjusted into 0..360. */\r\n public static createDegreesAdjustPositive(degrees: number): Angle { return Angle.createDegrees(Angle.adjustDegrees0To360(degrees)); }\r\n /** Create an angle object with degrees adjusted into -180..180. */\r\n public static createDegreesAdjustSigned180(degrees: number): Angle { return Angle.createDegrees(Angle.adjustDegreesSigned180(degrees)); }\r\n /**\r\n * Test if two radians values are equivalent, allowing shift by full circle (i.e. by a multiple of `2*PI`)\r\n * @param radiansA first radians value\r\n * @param radiansB second radians value\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public static isAlmostEqualRadiansAllowPeriodShift(radiansA: number, radiansB: number,\r\n radianTol: number = Geometry.smallAngleRadians): boolean {\r\n const delta = Math.abs(radiansA - radiansB);\r\n if (delta <= radianTol)\r\n return true;\r\n const period = Math.PI * 2.0;\r\n if (Math.abs(delta - period) <= radianTol)\r\n return true;\r\n const numPeriod = Math.round(delta / period);\r\n const delta1 = delta - numPeriod * period;\r\n return Math.abs(delta1) <= radianTol;\r\n }\r\n /**\r\n * Test if this angle and other are equivalent, allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqualAllowPeriodShift(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians, other._radians, radianTol);\r\n }\r\n /**\r\n * Test if two angle (in radians) almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param radiansA first radians value\r\n * @param radiansB second radians value\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public static isAlmostEqualRadiansNoPeriodShift(radiansA: number, radiansB: number,\r\n radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Math.abs(radiansA - radiansB) < radianTol;\r\n }\r\n /**\r\n * Test if two this angle and other are almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqualNoPeriodShift(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians, other._radians, radianTol);\r\n }\r\n /**\r\n * Test if two this angle and other are almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * * This function is same as isAlmostEqualRadiansNoPeriodShift. Please use isAlmostEqualRadiansNoPeriodShift.\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqual(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return this.isAlmostEqualNoPeriodShift(other, radianTol);\r\n }\r\n /**\r\n * Test if dot product values indicate non-zero length perpendicular vectors.\r\n * @param dotUU dot product of vectorU with itself\r\n * @param dotVV dot product of vectorV with itself\r\n * @param dotUV dot product of vectorU with vectorV\r\n */\r\n public static isPerpendicularDotSet(dotUU: number, dotVV: number, dotUV: number): boolean {\r\n return dotUU > Geometry.smallMetricDistanceSquared\r\n && dotVV > Geometry.smallMetricDistanceSquared\r\n && dotUV * dotUV <= Geometry.smallAngleRadiansSquared * dotUU * dotVV;\r\n }\r\n /**\r\n * Return cosine, sine, and radians for the half angle of a cosine,sine pair.\r\n * @param rCos2A cosine value (scaled by radius) for initial angle.\r\n * @param rSin2A sine value (scaled by radius) for final angle.\r\n */\r\n public static trigValuesToHalfAngleTrigValues(rCos2A: number, rSin2A: number): TrigValues {\r\n const r = Geometry.hypotenuseXY(rCos2A, rSin2A);\r\n if (r < Geometry.smallMetricDistance) {\r\n return { c: 1.0, s: 0.0, radians: 0.0 };\r\n } else {\r\n /* If the caller really gave you sine and cosine values, r should be 1. However,*/\r\n /* to allow scaled values -- e.g. the x and y components of any vector -- we normalize*/\r\n /* right here. This adds an extra sqrt and 2 divides to the whole process, but improves*/\r\n /* both the usefulness and robustness of the computation.*/\r\n let cosA;\r\n let sinA = 0.0;\r\n const cos2A = rCos2A / r;\r\n const sin2A = rSin2A / r;\r\n if (cos2A >= 0.0) {\r\n /* Original angle in NE and SE quadrants. Half angle in same quadrant */\r\n cosA = Math.sqrt(0.5 * (1.0 + cos2A));\r\n sinA = sin2A / (2.0 * (cosA));\r\n } else {\r\n if (sin2A > 0.0) {\r\n /* Original angle in NW quadrant. Half angle in NE quadrant */\r\n sinA = Math.sqrt(0.5 * (1.0 - cos2A));\r\n } else {\r\n /* Original angle in SW quadrant. Half angle in SE quadrant*/\r\n /* cosA comes out positive because both sines are negative. */\r\n sinA = -Math.sqrt(0.5 * (1.0 - cos2A));\r\n }\r\n cosA = sin2A / (2.0 * (sinA));\r\n }\r\n return { c: cosA, s: sinA, radians: Math.atan2(sinA, cosA) };\r\n }\r\n }\r\n /** If value is close to -1, -0.5, 0, 0.5, 1, adjust it to the exact value. */\r\n public static cleanupTrigValue(value: number, tolerance: number = 1.0e-15): number {\r\n const absValue = Math.abs(value);\r\n if (absValue <= tolerance)\r\n return 0;\r\n let a = Math.abs(absValue - 0.5);\r\n if (a <= tolerance)\r\n return value < 0.0 ? -0.5 : 0.5;\r\n a = Math.abs(absValue - 1.0);\r\n if (a <= tolerance)\r\n return value < 0.0 ? -1.0 : 1.0;\r\n return value;\r\n }\r\n /**\r\n * Return the half angle cosine, sine, and radians for given dot products between vectors.\r\n * @param dotUU dot product of vectorU with itself\r\n * @param dotVV dot product of vectorV with itself\r\n * @param dotUV dot product of vectorU with vectorV\r\n */\r\n public static dotProductsToHalfAngleTrigValues(dotUU: number, dotVV: number, dotUV: number, favorZero: boolean = true): TrigValues {\r\n const rCos = dotUU - dotVV;\r\n const rSin = 2.0 * dotUV;\r\n if (favorZero && Math.abs(rSin) < Geometry.smallAngleRadians * (Math.abs(dotUU) + Math.abs(dotVV)))\r\n return { c: 1.0, s: 0.0, radians: 0.0 };\r\n return Angle.trigValuesToHalfAngleTrigValues(rCos, rSin);\r\n }\r\n /**\r\n * * Returns the angle between two vectors, with the vectors given as xyz components\r\n * * The returned angle is between 0 and PI\r\n *\r\n * @param ux x component of vector u\r\n * @param uy y component of vector u\r\n * @param uz z component of vector u\r\n * @param vx x component of vector v\r\n * @param vy y component of vector v\r\n * @param vz z component of vector v\r\n */\r\n public static radiansBetweenVectorsXYZ(ux: number, uy: number, uz: number, vx: number, vy: number, vz: number): number {\r\n // const uu = ux * ux + uy * uy + uz * uz;\r\n const uDotV = ux * vx + uy * vy + uz * vz; // magU magV cos(theta)\r\n // const vv = vx * vx + vy * vy + vz * vz;\r\n return Math.atan2(Geometry.crossProductMagnitude(ux, uy, uz, vx, vy, vz), uDotV);\r\n }\r\n /**\r\n * Add a multiple of a full circle angle (360 degrees, 2PI) in place.\r\n * @param multiple multiplier factor\r\n */\r\n public addMultipleOf2PiInPlace(multiple: number) {\r\n if (this._degrees !== undefined) {\r\n this._degrees += multiple * 360.0;\r\n this._radians = Angle.degreesToRadians(this._degrees);\r\n } else {\r\n this._radians += multiple * Angle.pi2Radians;\r\n }\r\n }\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"file":"Angle.js","sourceRoot":"","sources":["../../../src/geometry3d/Angle.ts"],"names":[],"mappings":"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","sourcesContent":["/*---------------------------------------------------------------------------------------------\r\n* Copyright (c) Bentley Systems, Incorporated. All rights reserved.\r\n* See LICENSE.md in the project root for license terms and full copyright notice.\r\n*--------------------------------------------------------------------------------------------*/\r\n/** @packageDocumentation\r\n * @module CartesianGeometry\r\n */\r\n\r\nimport { AngleProps, BeJSONFunctions, Geometry, TrigValues } from \"../Geometry\";\r\n\r\n/**\r\n * An `Angle` carries the numeric value of an angle, with methods to allow (require!) callers to\r\n * be clear about whether their angle is degrees or radians.\r\n * * After the Angle object is created, the callers should not know or care whether it is stored in\r\n * `degrees` or `radians` because both are available if requested by caller.\r\n * * The various access method are named so that callers can specify whether untyped numbers passed in or\r\n * out are degrees or radians.\r\n * @public\r\n */\r\nexport class Angle implements BeJSONFunctions {\r\n /** maximal accuracy value of pi/12 (15 degrees), in radians */\r\n public static readonly piOver12Radians = 0.26179938779914943653855361527329;\r\n /** maximal accuracy value of pi/4 (45 degrees), in radians */\r\n public static readonly piOver4Radians = 7.85398163397448280000e-001;\r\n /** maximal accuracy value of pi/2 (90 degrees), in radians */\r\n public static readonly piOver2Radians = 1.57079632679489660000e+000;\r\n /** maximal accuracy value of pi (180 degrees), in radians */\r\n public static readonly piRadians = 3.14159265358979310000e+000;\r\n /** maximal accuracy value of 2*pi (360 degrees), in radians */\r\n public static readonly pi2Radians = 6.28318530717958620000e+000;\r\n /** scale factor for converting radians to degrees */\r\n public static readonly degreesPerRadian = (45.0 / Angle.piOver4Radians);\r\n /** scale factor for converting degrees to radians */\r\n public static readonly radiansPerDegree = (Angle.piOver4Radians / 45.0);\r\n private _radians: number;\r\n private _degrees?: number;\r\n private constructor(radians = 0, degrees?: number) {\r\n this._radians = radians;\r\n this._degrees = degrees;\r\n }\r\n /** Return a new angle with the same content. */\r\n public clone(): Angle {\r\n return new Angle(this._radians, this._degrees);\r\n }\r\n /** Freeze this instance so it is read-only */\r\n public freeze(): Readonly<this> {\r\n return Object.freeze(this);\r\n }\r\n /**\r\n * Return a new Angle object for angle given in degrees.\r\n * @param degrees angle in degrees\r\n */\r\n public static createDegrees(degrees: number): Angle {\r\n return new Angle(Angle.degreesToRadians(degrees), degrees);\r\n }\r\n /**\r\n * Return a (new) Angle object for a value given in radians.\r\n * @param radians angle in radians\r\n */\r\n public static createRadians(radians: number): Angle {\r\n return new Angle(radians);\r\n }\r\n /**\r\n * Return a (new) Angle object that is interpolated between two inputs (based on a fraction)\r\n * @param angle0 first angle in radians\r\n * @param fraction the interpolation fraction\r\n * @param angle1 second angle in radians\r\n */\r\n public static createInterpolate(angle0: Angle, fraction: number, angle1: Angle): Angle {\r\n return new Angle(Geometry.interpolate(angle0.radians, fraction, angle1.radians));\r\n }\r\n /**\r\n * Return a (new) Angle object, with angle scaled from existing angle.\r\n * @param scale scale factor to apply to angle.\r\n */\r\n public cloneScaled(scale: number): Angle {\r\n return new Angle(this.radians * scale);\r\n }\r\n /**\r\n * Set this angle to a value given in radians.\r\n * @param radians angle given in radians\r\n */\r\n public setRadians(radians: number) {\r\n this._radians = radians;\r\n this._degrees = undefined;\r\n }\r\n /**\r\n * Set this angle to a value given in degrees.\r\n * @param degrees angle given in degrees.\r\n */\r\n public setDegrees(degrees: number) {\r\n this._radians = Angle.degreesToRadians(degrees);\r\n this._degrees = degrees;\r\n }\r\n /** Create an angle for a full circle. */\r\n public static create360(): Angle {\r\n return new Angle(Math.PI * 2.0, 360.0);\r\n }\r\n /**\r\n * Create a (strongly typed) Angle whose tangent is `numerator/denominator`, using the signs of both in\r\n * determining the (otherwise ambiguous) quadrant.\r\n * @param numerator numerator for tangent\r\n * @param denominator denominator for tangent\r\n */\r\n public static createAtan2(numerator: number, denominator: number): Angle {\r\n return new Angle(Math.atan2(numerator, denominator));\r\n }\r\n /**\r\n * Copy all contents of `other` to this Angle.\r\n * @param other source data\r\n */\r\n public setFrom(other: Angle) {\r\n this._radians = other._radians;\r\n this._degrees = other._degrees;\r\n }\r\n /**\r\n * Set an Angle from a JSON object\r\n * * A simple number is considered as degrees.\r\n * * specified `json.degrees` or `json._degrees` is degree value.\r\n * * specified `son.radians` or `json._radians` is radians value.\r\n * @param json object from JSON.parse. If a number, value is in *DEGREES*\r\n * @param defaultValRadians if json is undefined, default value in radians.\r\n */\r\n public setFromJSON(json?: AngleProps, defaultValRadians?: number) {\r\n this._radians = defaultValRadians ? defaultValRadians : 0;\r\n if (!json)\r\n return;\r\n if (typeof json === \"number\") {\r\n this.setDegrees(json);\r\n } else if (typeof (json as any).degrees === \"number\") {\r\n this.setDegrees((json as any).degrees);\r\n } else if (typeof (json as any)._degrees === \"number\") {\r\n this.setDegrees((json as any)._degrees);\r\n } else if (typeof (json as any).radians === \"number\") {\r\n this.setRadians((json as any).radians);\r\n } else if (typeof (json as any)._radians === \"number\") {\r\n this.setRadians((json as any)._radians);\r\n }\r\n }\r\n /**\r\n * Create an Angle from a JSON object\r\n * @param json object from JSON.parse. If a number, value is in *DEGREES*\r\n * @param defaultValRadians if json is undefined, default value in radians.\r\n * @return a new Angle\r\n */\r\n public static fromJSON(json?: AngleProps, defaultValRadians?: number): Angle {\r\n const val = new Angle();\r\n val.setFromJSON(json, defaultValRadians);\r\n return val;\r\n }\r\n /** Convert an Angle to a JSON object as a number in degrees */\r\n public toJSON(): AngleProps {\r\n return this.degrees;\r\n }\r\n /** Return a json object with radians keyword, e.g. `{ radians: 0.10}` */\r\n public toJSONRadians(): AngleProps {\r\n return { radians: this.radians };\r\n }\r\n /** Return the angle measured in radians. */\r\n public get radians(): number {\r\n return this._radians;\r\n }\r\n /** Return the angle measured in degrees. */\r\n public get degrees(): number {\r\n return this._degrees !== undefined ? this._degrees : Angle.radiansToDegrees(this._radians);\r\n }\r\n /**\r\n * Convert an angle in degrees to radians.\r\n * @param degrees angle in degrees\r\n */\r\n public static degreesToRadians(degrees: number): number {\r\n return degrees * Math.PI / 180;\r\n }\r\n /**\r\n * Convert an angle in radians to degrees.\r\n * @param degrees angle in radians\r\n */\r\n public static radiansToDegrees(radians: number): number {\r\n if (radians < 0)\r\n return -Angle.radiansToDegrees(-radians);\r\n // Now radians is positive ...\r\n const pi = Math.PI;\r\n const factor = 180.0 / pi;\r\n /* the following if statements are for round-off reasons. The problem is that no IEEE number is\r\n * an exact hit for any primary multiple of pi (90, 180, etc). The following is supposed to have\r\n * a better chance that if the input was computed by direct assignment from 90, 180, etc degrees\r\n * it will return exactly 90,180 etc.\r\n */\r\n if (radians <= 0.25 * pi)\r\n return factor * radians;\r\n if (radians < 0.75 * pi)\r\n return 90.0 + 180 * ((radians - 0.5 * pi) / pi);\r\n if (radians <= 1.25 * pi)\r\n return 180.0 + 180 * ((radians - pi) / pi);\r\n if (radians <= 1.75 * pi)\r\n return 270.0 + 180 * ((radians - 1.5 * pi) / pi);\r\n // all larger radians reference from 360 degrees (2PI)\r\n return 360.0 + 180 * ((radians - 2.0 * pi) / pi);\r\n }\r\n /**\r\n * Return the cosine of this Angle object's angle.\r\n */\r\n public cos(): number {\r\n return Math.cos(this._radians);\r\n }\r\n /**\r\n * Return the sine of this Angle object's angle.\r\n */\r\n public sin(): number {\r\n return Math.sin(this._radians);\r\n }\r\n /**\r\n * Return the tangent of this Angle object's angle.\r\n */\r\n public tan(): number {\r\n return Math.tan(this._radians);\r\n }\r\n /** Test if a radians (absolute) value is nearly 2PI or larger! */\r\n public static isFullCircleRadians(radians: number): boolean {\r\n return Math.abs(radians) >= Geometry.fullCircleRadiansMinusSmallAngle;\r\n }\r\n /** Test if the radians value is a half circle */\r\n public static isHalfCircleRadians(radians: number): boolean {\r\n return Math.abs(Math.abs(radians) - Math.PI) <= Geometry.smallAngleRadians;\r\n }\r\n /** test if the angle is a full circle */\r\n public get isFullCircle(): boolean {\r\n return Angle.isFullCircleRadians(this._radians);\r\n }\r\n /** test if the angle is a half circle (in either direction) */\r\n public get isHalfCircle(): boolean {\r\n return Angle.isHalfCircleRadians(this._radians);\r\n }\r\n /** Adjust a radians value so it is positive in 0..360 */\r\n public static adjustDegrees0To360(degrees: number): number {\r\n if (degrees >= 0) {\r\n const period = 360.0;\r\n if (degrees < period)\r\n return degrees;\r\n const numPeriods = Math.floor(degrees / period);\r\n return degrees - numPeriods * period;\r\n } else if (degrees < 0) {\r\n // negative angle ...\r\n const radians = Angle.adjustDegrees0To360(-degrees);\r\n return 360.0 - radians;\r\n }\r\n // fall through for Nan (disaster) !!!\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is in -180..180 */\r\n public static adjustDegreesSigned180(degrees: number): number {\r\n if (Math.abs(degrees) <= 180.0)\r\n return degrees;\r\n if (degrees >= 0) {\r\n const period = 360.0;\r\n const numPeriods = 1 + Math.floor((degrees - 180.0) / period);\r\n return degrees - numPeriods * period;\r\n } else if (degrees < 0) {\r\n // negative angle ...\r\n return -Angle.adjustDegreesSigned180(-degrees);\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is positive in 0..2Pi */\r\n public static adjustRadians0To2Pi(radians: number): number {\r\n if (radians >= 0) {\r\n const period = Math.PI * 2.0;\r\n if (radians < period)\r\n return radians;\r\n const numPeriods = Math.floor(radians / period);\r\n return radians - numPeriods * period;\r\n } else if (radians < 0) {\r\n // negative angle ...\r\n return Math.PI * 2.0 - Angle.adjustRadians0To2Pi(-radians);\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** Adjust a radians value so it is positive in -PI..PI */\r\n public static adjustRadiansMinusPiPlusPi(radians: number): number {\r\n if (Math.abs(radians) <= Math.PI)\r\n return radians;\r\n if (radians >= 0) {\r\n const period = Math.PI * 2.0;\r\n const numPeriods = 1 + Math.floor((radians - Math.PI) / period);\r\n return radians - numPeriods * period;\r\n } else if (radians < 0) {\r\n // negative angle ...\r\n return -Angle.adjustRadiansMinusPiPlusPi(-radians);\r\n }\r\n // fall through for NaN disaster.\r\n return 0;\r\n }\r\n /** return a (newly allocated) Angle object with value 0 radians */\r\n public static zero(): Angle {\r\n return new Angle(0);\r\n }\r\n /** Test if the angle is exactly zero. */\r\n public get isExactZero(): boolean {\r\n return this.radians === 0;\r\n }\r\n /** Test if the angle is almost zero (within tolerance `Geometry.smallAngleRadians`) */\r\n public get isAlmostZero(): boolean {\r\n return Math.abs(this.radians) < Geometry.smallAngleRadians;\r\n }\r\n /** Test if the angle is almost a north or south pole (within tolerance `Geometry.smallAngleRadians`) */\r\n public get isAlmostNorthOrSouthPole(): boolean {\r\n return Angle.isHalfCircleRadians(this.radians * 2.0);\r\n }\r\n /** Create an angle object with degrees adjusted into 0..360. */\r\n public static createDegreesAdjustPositive(degrees: number): Angle {\r\n return Angle.createDegrees(Angle.adjustDegrees0To360(degrees));\r\n }\r\n /** Create an angle object with degrees adjusted into -180..180. */\r\n public static createDegreesAdjustSigned180(degrees: number): Angle {\r\n return Angle.createDegrees(Angle.adjustDegreesSigned180(degrees));\r\n }\r\n /**\r\n * Test if two radians values are equivalent, allowing shift by full circle (i.e. by a multiple of `2*PI`)\r\n * @param radiansA first radians value\r\n * @param radiansB second radians value\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public static isAlmostEqualRadiansAllowPeriodShift(radiansA: number, radiansB: number,\r\n radianTol: number = Geometry.smallAngleRadians): boolean {\r\n const delta = Math.abs(radiansA - radiansB);\r\n if (delta <= radianTol)\r\n return true;\r\n const period = Math.PI * 2.0;\r\n if (Math.abs(delta - period) <= radianTol)\r\n return true;\r\n const numPeriod = Math.round(delta / period);\r\n const delta1 = delta - numPeriod * period;\r\n return Math.abs(delta1) <= radianTol;\r\n }\r\n /**\r\n * Test if this angle and other are equivalent, allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqualAllowPeriodShift(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians, other._radians, radianTol);\r\n }\r\n /**\r\n * Test if two angle (in radians) almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param radiansA first radians value\r\n * @param radiansB second radians value\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public static isAlmostEqualRadiansNoPeriodShift(radiansA: number, radiansB: number,\r\n radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Math.abs(radiansA - radiansB) < radianTol;\r\n }\r\n /**\r\n * Test if two this angle and other are almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqualNoPeriodShift(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians, other._radians, radianTol);\r\n }\r\n /**\r\n * Test if two this angle and other are almost equal, NOT allowing shift by full circle (i.e., multiples of `2 * PI`).\r\n * * This function is same as isAlmostEqualRadiansNoPeriodShift. Please use isAlmostEqualRadiansNoPeriodShift.\r\n * @param other the other angle\r\n * @param radianTol radian tolerance with default value of Geometry.smallAngleRadians\r\n */\r\n public isAlmostEqual(other: Angle, radianTol: number = Geometry.smallAngleRadians): boolean {\r\n return this.isAlmostEqualNoPeriodShift(other, radianTol);\r\n }\r\n /**\r\n * Test if dot product values indicate non-zero length perpendicular vectors.\r\n * @param dotUU dot product of vectorU with itself\r\n * @param dotVV dot product of vectorV with itself\r\n * @param dotUV dot product of vectorU with vectorV\r\n */\r\n public static isPerpendicularDotSet(dotUU: number, dotVV: number, dotUV: number): boolean {\r\n return dotUU > Geometry.smallMetricDistanceSquared\r\n && dotVV > Geometry.smallMetricDistanceSquared\r\n && dotUV * dotUV <= Geometry.smallAngleRadiansSquared * dotUU * dotVV;\r\n }\r\n /**\r\n * Return cosine, sine, and radians for the half angle of a \"cosine,sine\" pair.\r\n * * This function assumes the input arguments are related to an angle between -PI and PI\r\n * * This function returns an angle between -PI and PI\r\n * @param rCos2A cosine value (scaled by radius) for initial angle.\r\n * @param rSin2A sine value (scaled by radius) for final angle.\r\n */\r\n public static trigValuesToHalfAngleTrigValues(rCos2A: number, rSin2A: number): TrigValues {\r\n const r = Geometry.hypotenuseXY(rCos2A, rSin2A);\r\n if (r < Geometry.smallMetricDistance) {\r\n return { c: 1.0, s: 0.0, radians: 0.0 }; // angle = 0\r\n } else {\r\n /* If the caller really gave you sine and cosine values, r should be 1. However,\r\n * to allow scaled values -- e.g. the x and y components of any vector -- we normalize\r\n * right here. This adds an extra sqrt and 2 divides to the whole process, but improves\r\n * both the usefulness and robustness of the computation.\r\n */\r\n let cosA;\r\n let sinA = 0.0;\r\n const cos2A = rCos2A / r;\r\n const sin2A = rSin2A / r;\r\n // Original angle in NE and SE quadrants. Half angle in same quadrant\r\n if (cos2A >= 0.0) {\r\n /*\r\n * We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2\r\n * so 1 + cos2A = 2(cosA)^2 and therefore, cosA = sqrt((1+cos2A)/2)\r\n * cosine is positive in NE and SE quadrants so we use +sqrt\r\n */\r\n cosA = Math.sqrt(0.5 * (1.0 + cos2A));\r\n // We know sin2A = 2 sinA cosA so sinA = sin2A/(2*cosA)\r\n sinA = sin2A / (2.0 * cosA);\r\n } else {\r\n // Original angle in NW quadrant. Half angle in NE quadrant\r\n if (sin2A > 0.0) {\r\n /*\r\n * We know cos2A = (cosA)^2 - (sinA)^2 and 1 = (cosA)^2 + (sinA)^2\r\n * so 1 - cos2A = 2(sinA)^2 and therefore, sinA = sqrt((1-cos2A)/2)\r\n * sine is positive in NE quadrant so we use +sqrt\r\n */\r\n sinA = Math.sqrt(0.5 * (1.0 - cos2A));\r\n // Original angle in SW quadrant. Half angle in SE quadrant\r\n } else {\r\n // sine is negative in SE quadrant so we use -sqrt\r\n sinA = -Math.sqrt(0.5 * (1.0 - cos2A));\r\n }\r\n // We know sin2A = 2 sinA cosA so cosA = sin2A/(2*sinA)\r\n cosA = sin2A / (2.0 * sinA); // always positive\r\n }\r\n return { c: cosA, s: sinA, radians: Math.atan2(sinA, cosA) };\r\n }\r\n }\r\n /** If value is close to -1, -0.5, 0, 0.5, 1, adjust it to the exact value. */\r\n public static cleanupTrigValue(value: number, tolerance: number = 1.0e-15): number {\r\n const absValue = Math.abs(value);\r\n if (absValue <= tolerance)\r\n return 0;\r\n let a = Math.abs(absValue - 0.5);\r\n if (a <= tolerance)\r\n return value < 0.0 ? -0.5 : 0.5;\r\n a = Math.abs(absValue - 1.0);\r\n if (a <= tolerance)\r\n return value < 0.0 ? -1.0 : 1.0;\r\n return value;\r\n }\r\n /**\r\n * Return the half angle cosine, sine, and radians for given dot products between vectors. The vectors define\r\n * an ellipse using x(t) = c + U cos(t) + V sin(t) so U and V are at angle t=0 degree and t=90 degree. The\r\n * half angle t0 is an angle such that x(t0) is one of the ellipse semi-axis.\r\n * * This construction arises e.g. in `Arc3d.toScaledMatrix3d`.\r\n * * Given ellipse x(t) = c + U cos(t) + V sin(t), find t0 such that radial vector W(t0) = x(t0) - c is\r\n * perpendicular to the ellipse.\r\n * * Then 0 = W(t0).x'(t0) = (U cos(t0) + V sin(t0)).(V cos(t0) - U sin(t0)) = U.V cos(2t0) + 0.5 (V.V - U.U) sin(2t0)\r\n * implies sin(2t0) / cos(2t0) = 2 U.V / (U.U - V.V), i.e., t0 can be computed given the three dot products on the RHS.\r\n * @param dotUU dot product of vectorU with itself\r\n * @param dotVV dot product of vectorV with itself\r\n * @param dotUV dot product of vectorU with vectorV\r\n */\r\n public static dotProductsToHalfAngleTrigValues(dotUU: number, dotVV: number, dotUV: number, favorZero: boolean = true): TrigValues {\r\n const cos2t0 = dotUU - dotVV;\r\n const sin2t0 = 2.0 * dotUV;\r\n if (favorZero && Math.abs(sin2t0) < Geometry.smallAngleRadians * (Math.abs(dotUU) + Math.abs(dotVV)))\r\n return { c: 1.0, s: 0.0, radians: 0.0 };\r\n return Angle.trigValuesToHalfAngleTrigValues(cos2t0, sin2t0);\r\n }\r\n /**\r\n * * Returns the angle between two vectors, with the vectors given as xyz components\r\n * * The returned angle is between 0 and PI\r\n *\r\n * @param ux x component of vector u\r\n * @param uy y component of vector u\r\n * @param uz z component of vector u\r\n * @param vx x component of vector v\r\n * @param vy y component of vector v\r\n * @param vz z component of vector v\r\n */\r\n public static radiansBetweenVectorsXYZ(ux: number, uy: number, uz: number, vx: number, vy: number, vz: number): number {\r\n const uDotV = ux * vx + uy * vy + uz * vz;\r\n return Math.atan2(Geometry.crossProductMagnitude(ux, uy, uz, vx, vy, vz), uDotV);\r\n }\r\n /**\r\n * Add a multiple of a full circle angle (360 degrees, 2PI) in place.\r\n * @param multiple multiplier factor\r\n */\r\n public addMultipleOf2PiInPlace(multiple: number) {\r\n if (this._degrees !== undefined) {\r\n this._degrees += multiple * 360.0;\r\n this._radians = Angle.degreesToRadians(this._degrees);\r\n } else {\r\n this._radians += multiple * Angle.pi2Radians;\r\n }\r\n }\r\n}\r\n"]}
|