@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.
Files changed (52) hide show
  1. package/lib/cjs/Geometry.d.ts +5 -5
  2. package/lib/cjs/Geometry.d.ts.map +1 -1
  3. package/lib/cjs/Geometry.js +15 -9
  4. package/lib/cjs/Geometry.js.map +1 -1
  5. package/lib/cjs/bspline/BSplineCurve.d.ts +3 -7
  6. package/lib/cjs/bspline/BSplineCurve.d.ts.map +1 -1
  7. package/lib/cjs/bspline/BSplineCurve.js +15 -14
  8. package/lib/cjs/bspline/BSplineCurve.js.map +1 -1
  9. package/lib/cjs/curve/Arc3d.d.ts +2 -2
  10. package/lib/cjs/curve/Arc3d.d.ts.map +1 -1
  11. package/lib/cjs/curve/Arc3d.js +2 -2
  12. package/lib/cjs/curve/Arc3d.js.map +1 -1
  13. package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts +9 -5
  14. package/lib/cjs/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
  15. package/lib/cjs/curve/CurveChainWithDistanceIndex.js +9 -18
  16. package/lib/cjs/curve/CurveChainWithDistanceIndex.js.map +1 -1
  17. package/lib/cjs/geometry3d/Angle.d.ts +46 -32
  18. package/lib/cjs/geometry3d/Angle.d.ts.map +1 -1
  19. package/lib/cjs/geometry3d/Angle.js +171 -84
  20. package/lib/cjs/geometry3d/Angle.js.map +1 -1
  21. package/lib/cjs/geometry3d/AngleSweep.d.ts +102 -60
  22. package/lib/cjs/geometry3d/AngleSweep.d.ts.map +1 -1
  23. package/lib/cjs/geometry3d/AngleSweep.js +191 -106
  24. package/lib/cjs/geometry3d/AngleSweep.js.map +1 -1
  25. package/lib/cjs/geometry3d/Point2dArrayCarrier.js +1 -1
  26. package/lib/cjs/geometry3d/Point2dArrayCarrier.js.map +1 -1
  27. package/lib/esm/Geometry.d.ts +5 -5
  28. package/lib/esm/Geometry.d.ts.map +1 -1
  29. package/lib/esm/Geometry.js +15 -9
  30. package/lib/esm/Geometry.js.map +1 -1
  31. package/lib/esm/bspline/BSplineCurve.d.ts +3 -7
  32. package/lib/esm/bspline/BSplineCurve.d.ts.map +1 -1
  33. package/lib/esm/bspline/BSplineCurve.js +15 -14
  34. package/lib/esm/bspline/BSplineCurve.js.map +1 -1
  35. package/lib/esm/curve/Arc3d.d.ts +2 -2
  36. package/lib/esm/curve/Arc3d.d.ts.map +1 -1
  37. package/lib/esm/curve/Arc3d.js +2 -2
  38. package/lib/esm/curve/Arc3d.js.map +1 -1
  39. package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts +9 -5
  40. package/lib/esm/curve/CurveChainWithDistanceIndex.d.ts.map +1 -1
  41. package/lib/esm/curve/CurveChainWithDistanceIndex.js +9 -18
  42. package/lib/esm/curve/CurveChainWithDistanceIndex.js.map +1 -1
  43. package/lib/esm/geometry3d/Angle.d.ts +46 -32
  44. package/lib/esm/geometry3d/Angle.d.ts.map +1 -1
  45. package/lib/esm/geometry3d/Angle.js +171 -84
  46. package/lib/esm/geometry3d/Angle.js.map +1 -1
  47. package/lib/esm/geometry3d/AngleSweep.d.ts +102 -60
  48. package/lib/esm/geometry3d/AngleSweep.d.ts.map +1 -1
  49. package/lib/esm/geometry3d/AngleSweep.js +191 -106
  50. package/lib/esm/geometry3d/AngleSweep.js.map +1 -1
  51. package/lib/esm/geometry3d/Point2dArrayCarrier.js.map +1 -1
  52. package/package.json +4 -4
@@ -10,19 +10,20 @@ import { Angle } from "./Angle";
10
10
  /**
11
11
  * An `AngleSweep` is a pair of angles at start and end of an interval.
12
12
  *
13
- * * For stroking purposes, the "included interval" is all angles numerically reached by theta = start + f*(end-start), where f is between 0 and 1.
13
+ * * For stroking purposes, the "included interval" is all angles numerically reached
14
+ * by theta = start + f*(end-start), where f is between 0 and 1.
14
15
  * * This stroking formula is simple numbers -- 2PI shifts are not involved.
15
16
  * * 2PI shifts do become important in the reverse mapping of an angle to a fraction.
16
- * * If (start < end) the angle proceeds CCW around the unit circle.
17
- * * If (end < start) the angle proceeds CW around the unit circle.
17
+ * * If "start < end" the angle proceeds CCW around the unit circle.
18
+ * * If "end < start" the angle proceeds CW around the unit circle.
18
19
  * * Angles beyond 360 are fine as endpoints.
19
- * * (350,370) covers the same unit angles as (-10,10).
20
- * * (370,350) covers the same unit angles as (10,-10).
20
+ * * (350,370) covers the same unit angles as (-10,10).
21
+ * * (370,350) covers the same unit angles as (10,-10).
21
22
  * @public
22
23
  */
23
24
  export class AngleSweep {
24
25
  /** (private) constructor with start and end angles in radians.
25
- * * Use explicitly named static methods to clarify intent and units of inputs:
26
+ * * Use explicitly named static methods to clarify intent and units of inputs:
26
27
  *
27
28
  * * createStartEndRadians (startRadians:number, endRadians:number)
28
29
  * * createStartEndDegrees (startDegrees:number, endDegrees:number)
@@ -31,23 +32,42 @@ export class AngleSweep {
31
32
  * * createStartSweepDegrees (startDegrees:number, sweepDegrees:number)
32
33
  * * createStartSweep (startAngle:Angle, sweepAngle:Angle)
33
34
  */
34
- constructor(startRadians = 0, endRadians = 0) { this._radians0 = startRadians; this._radians1 = endRadians; }
35
+ constructor(startRadians = 0, endRadians = 0) {
36
+ this._radians0 = startRadians;
37
+ this._radians1 = endRadians;
38
+ }
35
39
  /** Read-property for degrees at the start of this AngleSweep. */
36
- get startDegrees() { return Angle.radiansToDegrees(this._radians0); }
40
+ get startDegrees() {
41
+ return Angle.radiansToDegrees(this._radians0);
42
+ }
37
43
  /** Read-property for degrees at the end of this AngleSweep. */
38
- get endDegrees() { return Angle.radiansToDegrees(this._radians1); }
44
+ get endDegrees() {
45
+ return Angle.radiansToDegrees(this._radians1);
46
+ }
39
47
  /** Read-property for signed start-to-end sweep in degrees. */
40
- get sweepDegrees() { return Angle.radiansToDegrees(this._radians1 - this._radians0); }
48
+ get sweepDegrees() {
49
+ return Angle.radiansToDegrees(this._radians1 - this._radians0);
50
+ }
41
51
  /** Read-property for degrees at the start of this AngleSweep. */
42
- get startRadians() { return this._radians0; }
52
+ get startRadians() {
53
+ return this._radians0;
54
+ }
43
55
  /** Read-property for degrees at the end of this AngleSweep. */
44
- get endRadians() { return this._radians1; }
56
+ get endRadians() {
57
+ return this._radians1;
58
+ }
45
59
  /** Read-property for signed start-to-end sweep in radians. */
46
- get sweepRadians() { return this._radians1 - this._radians0; }
60
+ get sweepRadians() {
61
+ return this._radians1 - this._radians0;
62
+ }
47
63
  /** Return the (strongly typed) start angle */
48
- get startAngle() { return Angle.createRadians(this._radians0); }
64
+ get startAngle() {
65
+ return Angle.createRadians(this._radians0);
66
+ }
49
67
  /** Return the (strongly typed) end angle */
50
- get endAngle() { return Angle.createRadians(this._radians1); }
68
+ get endAngle() {
69
+ return Angle.createRadians(this._radians1);
70
+ }
51
71
  /** Create a sweep as one of
52
72
  * * A clone of a given sweep
53
73
  * * 0 to given angle
@@ -60,14 +80,35 @@ export class AngleSweep {
60
80
  return new AngleSweep(0, data.radians);
61
81
  return AngleSweep.create360();
62
82
  }
63
- /** create an AngleSweep from start and end angles given in radians. */
83
+ /**
84
+ * directly set the start and end angles in radians
85
+ * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.
86
+ * */
87
+ setStartEndRadians(startRadians = 0, endRadians = 2.0 * Math.PI) {
88
+ const delta = endRadians - startRadians;
89
+ if (Angle.isFullCircleRadians(delta)) {
90
+ endRadians = startRadians + (delta > 0 ? 2.0 : -2.0) * Math.PI;
91
+ }
92
+ this._radians0 = startRadians;
93
+ this._radians1 = endRadians;
94
+ }
95
+ /** directly set the start and end angles in degrees */
96
+ setStartEndDegrees(startDegrees = 0, endDegrees = 360.0) {
97
+ this.setStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees));
98
+ }
99
+ /**
100
+ * create an AngleSweep from start and end angles given in radians.
101
+ * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.
102
+ * */
64
103
  static createStartEndRadians(startRadians = 0, endRadians = 2.0 * Math.PI, result) {
65
104
  result = result ? result : new AngleSweep();
66
105
  result.setStartEndRadians(startRadians, endRadians);
67
106
  return result;
68
107
  }
69
108
  /** Return the angle obtained by subtracting radians from this angle. */
70
- cloneMinusRadians(radians) { return new AngleSweep(this._radians0 - radians, this._radians1 - radians); }
109
+ cloneMinusRadians(radians) {
110
+ return new AngleSweep(this._radians0 - radians, this._radians1 - radians);
111
+ }
71
112
  /** create an AngleSweep from start and end angles given in degrees. */
72
113
  static createStartEndDegrees(startDegrees = 0, endDegrees = 360, result) {
73
114
  return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees), result);
@@ -78,14 +119,6 @@ export class AngleSweep {
78
119
  result.setStartEndRadians(startAngle.radians, endAngle.radians);
79
120
  return result;
80
121
  }
81
- /** Create an angle sweep with limits given as (strongly typed) angles for start and sweep */
82
- static createStartSweep(startAngle, sweepAngle, result) {
83
- return AngleSweep.createStartSweepRadians(startAngle.radians, sweepAngle.radians, result);
84
- }
85
- /** Return a sweep with limits interpolated between this and other. */
86
- interpolate(fraction, other) {
87
- return new AngleSweep(Geometry.interpolate(this._radians0, fraction, other._radians0), Geometry.interpolate(this._radians1, fraction, other._radians1));
88
- }
89
122
  /** create an AngleSweep from start and end angles given in radians. */
90
123
  static createStartSweepRadians(startRadians = 0, sweepRadians = Math.PI, result) {
91
124
  result = result ? result : new AngleSweep();
@@ -96,32 +129,36 @@ export class AngleSweep {
96
129
  static createStartSweepDegrees(startDegrees = 0, sweepDegrees = 360, result) {
97
130
  return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(startDegrees + sweepDegrees), result);
98
131
  }
99
- /** directly set the start and end angles in radians */
100
- setStartEndRadians(startRadians = 0, endRadians = 2.0 * Math.PI) {
101
- const delta = endRadians - startRadians;
102
- if (Angle.isFullCircleRadians(delta)) {
103
- endRadians = startRadians + (delta > 0 ? 2.0 : -2.0) * Math.PI;
104
- }
105
- this._radians0 = startRadians;
106
- this._radians1 = endRadians;
132
+ /** Create an angle sweep with limits given as (strongly typed) angles for start and sweep */
133
+ static createStartSweep(startAngle, sweepAngle, result) {
134
+ return AngleSweep.createStartSweepRadians(startAngle.radians, sweepAngle.radians, result);
107
135
  }
108
- /** directly set the start and end angles in degrees */
109
- setStartEndDegrees(startDegrees = 0, endDegrees = 360.0) {
110
- this.setStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees));
136
+ /** Return a sweep with limits interpolated between this and other. */
137
+ interpolate(fraction, other) {
138
+ return new AngleSweep(Geometry.interpolate(this._radians0, fraction, other._radians0), Geometry.interpolate(this._radians1, fraction, other._radians1));
111
139
  }
112
140
  /** copy from other AngleSweep. */
113
- setFrom(other) { this._radians0 = other._radians0; this._radians1 = other._radians1; }
141
+ setFrom(other) {
142
+ this._radians0 = other._radians0;
143
+ this._radians1 = other._radians1;
144
+ }
114
145
  /** create a full circle sweep (CCW). startRadians defaults to 0 */
115
146
  static create360(startRadians) {
116
147
  startRadians = startRadians ? startRadians : 0.0;
117
148
  return new AngleSweep(startRadians, startRadians + 2.0 * Math.PI);
118
149
  }
119
- /** create a sweep from the south pole to the north pole. */
120
- static createFullLatitude() { return AngleSweep.createStartEndRadians(-0.5 * Math.PI, 0.5 * Math.PI); }
150
+ /** create a sweep from the south pole to the north pole (-90 to +90). */
151
+ static createFullLatitude() {
152
+ return AngleSweep.createStartEndRadians(-0.5 * Math.PI, 0.5 * Math.PI);
153
+ }
121
154
  /** Reverse the start and end angle in place. */
122
- reverseInPlace() { const a = this._radians0; this._radians0 = this._radians1; this._radians1 = a; }
123
- /** return a sweep for the "other" part of the circe.
124
- * @param reverseDirection true to retain the start and move backwards, false to more forwards.
155
+ reverseInPlace() {
156
+ const tmp = this._radians0;
157
+ this._radians0 = this._radians1;
158
+ this._radians1 = tmp;
159
+ }
160
+ /** return a sweep for the "other" part of the circle.
161
+ * @param reverseDirection true to move backwards (CW) from start to end, false to more forwards (CCW) from start to end.
125
162
  */
126
163
  cloneComplement(reverseDirection = false, result) {
127
164
  const s = this.sweepRadians >= 0 ? 2.0 : -2.0;
@@ -130,16 +167,22 @@ export class AngleSweep {
130
167
  else
131
168
  return AngleSweep.createStartEndRadians(this.endRadians, this.startRadians + s * Math.PI, result);
132
169
  }
133
- /** Restrict start and end angles into the range (-90,+90) in degrees. */
170
+ /**
171
+ * Restrict start and end angles into the range (-90,+90) in degrees.
172
+ * */
134
173
  capLatitudeInPlace() {
135
174
  const limit = 0.5 * Math.PI;
136
175
  this._radians0 = Geometry.clampToStartEnd(this._radians0, -limit, limit);
137
176
  this._radians1 = Geometry.clampToStartEnd(this._radians1, -limit, limit);
138
177
  }
139
178
  /** Ask if the sweep is counterclockwise, i.e. positive sweep */
140
- get isCCW() { return this._radians1 >= this._radians0; }
179
+ get isCCW() {
180
+ return this._radians1 >= this._radians0;
181
+ }
141
182
  /** Ask if the sweep is a full circle. */
142
- get isFullCircle() { return Angle.isFullCircleRadians(this.sweepRadians); }
183
+ get isFullCircle() {
184
+ return Angle.isFullCircleRadians(this.sweepRadians);
185
+ }
143
186
  /** Ask if the sweep is a full sweep from south pole to north pole. */
144
187
  get isFullLatitudeSweep() {
145
188
  const a = Math.PI * 0.5;
@@ -147,62 +190,49 @@ export class AngleSweep {
147
190
  && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1, a);
148
191
  }
149
192
  /** return a clone of this sweep. */
150
- clone() { return new AngleSweep(this._radians0, this._radians1); }
193
+ clone() {
194
+ return new AngleSweep(this._radians0, this._radians1);
195
+ }
151
196
  /** Convert fractional position in the sweep to radians. */
152
197
  fractionToRadians(fraction) {
153
198
  return fraction < 0.5 ?
154
- this._radians0 + fraction * (this._radians1 - this._radians0)
155
- : this._radians1 + (fraction - 1.0) * (this._radians1 - this._radians0);
199
+ this._radians0 + fraction * (this._radians1 - this._radians0) :
200
+ this._radians1 + (fraction - 1.0) * (this._radians1 - this._radians0);
156
201
  }
157
202
  /** Convert fractional position in the sweep to strongly typed Angle object. */
158
203
  fractionToAngle(fraction) {
159
204
  return Angle.createRadians(this.fractionToRadians(fraction));
160
205
  }
161
206
  /** return 2PI divided by the sweep radians (i.e. 360 degrees divided by sweep angle).
162
- * This is the number of fractional intervals required to cover a whole circle.
207
+ * * This is the number of fractional intervals required to cover a whole circle.
163
208
  */
164
209
  fractionPeriod() {
165
210
  return Geometry.safeDivideFraction(Math.PI * 2.0, Math.abs(this._radians1 - this._radians0), 1.0);
166
211
  }
167
- /** return the fractionalized position of the angle,
168
- * computed without consideration of 2PI period.
169
- * That is, an angle that is numerically much beyond than the end angle
170
- * will produce a large fraction and an angle much beyond the start angle
171
- * will produce a large negative fraction.
212
+ /** return the fractionalized position of the given angle (as Angle) computed without consideration of
213
+ * 2PI period and without consideration of angle sweep direction (CW or CCW).
172
214
  *
215
+ * * the start angle is at fraction 0
216
+ * * the end angle is at fraction 1
217
+ * * interior angles are between 0 and 1
218
+ * * negative fraction for angles "before" the start angle if start < end
219
+ * * fraction larger than one for angles "after" the end angle if start < end
220
+ * * fraction larger than one for angles "before" the start angle if start > end
221
+ * * negative fraction for angles "after" the end angle if start > end
222
+ * * does not allow period shift
173
223
  */
174
224
  angleToUnboundedFraction(theta) {
175
225
  return Geometry.safeDivideFraction(theta.radians - this._radians0, this._radians1 - this._radians0, 1.0);
176
226
  }
177
- /** map an angle to a fractional coordinate which is:
227
+ /** return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.
178
228
  *
229
+ * * consider radians0 as `start` angle of the sweep and radians1 as `end` angle of the sweep
230
+ * * fraction is always positive
179
231
  * * the start angle is at fraction 0
180
232
  * * the end angle is at fraction 1
181
233
  * * interior angles are between 0 and 1
182
234
  * * all exterior angles are at fractions greater than 1
183
- * * the periodic jump is at full wraparound to the start angle
184
- */
185
- angleToPositivePeriodicFraction(theta) { return this.radiansToPositivePeriodicFraction(theta.radians); }
186
- /**
187
- * Convert each value in an array from radians to fraction.
188
- * @param data array that is input as radians, output as fractions
189
- */
190
- radiansArrayToPositivePeriodicFractions(data) {
191
- const n = data.length;
192
- for (let i = 0; i < n; i++) {
193
- data.reassign(i, this.radiansToPositivePeriodicFraction(data.atUncheckedIndex(i)));
194
- }
195
- }
196
- /**
197
- * Convert a radians value to a fraction that is always positive and can wrap. See `angleToPositivePeriodicFraction` for detailed description.
198
- * @param radians
199
- */
200
- radiansToPositivePeriodicFraction(radians, zeroSweepDefault = 0.0) {
201
- return AngleSweep.radiansToPositivePeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);
202
- }
203
- /**
204
- * Convert a radians value to a fraction that is always positive and can wrap. See `angleToPositivePeriodicFraction` for detailed description.
205
- * @param radians
235
+ * * allows period shift
206
236
  */
207
237
  static radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, zeroSweepDefault = 0.0) {
208
238
  if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0))
@@ -220,20 +250,54 @@ export class AngleSweep {
220
250
  const fraction2 = Geometry.safeDivideFraction(delta2, -sweep, zeroSweepDefault);
221
251
  return fraction2;
222
252
  }
223
- /** map an angle to a fractional coordinate which is:
253
+ /** return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.
224
254
  *
255
+ * * fraction is always positive
225
256
  * * the start angle is at fraction 0
226
257
  * * the end angle is at fraction 1
227
258
  * * interior angles are between 0 and 1
228
- * * small negative for angles just "before" the start angle
229
- * * more than one for angles just "after" the end angle
230
- * * the periodic jump is at the middle of the "outside" interval
259
+ * * all exterior angles are at fractions greater than 1
260
+ * * allows period shift
231
261
  */
232
- angleToSignedPeriodicFraction(theta) {
233
- return this.radiansToSignedPeriodicFraction(theta.radians);
262
+ radiansToPositivePeriodicFraction(radians, zeroSweepDefault = 0.0) {
263
+ return AngleSweep.radiansToPositivePeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);
234
264
  }
235
- /**
236
- * Convert a radians value to a fraction, allowing wraparound. See `angleToSignedPeriodicFraction` for detailed description.
265
+ /** return the fractionalized position of the given angle (as Angle), computed with consideration of 2PI period.
266
+ *
267
+ * * fraction is always positive
268
+ * * the start angle is at fraction 0
269
+ * * the end angle is at fraction 1
270
+ * * interior angles are between 0 and 1
271
+ * * all exterior angles are at fractions greater than 1
272
+ * * allows period shift
273
+ */
274
+ angleToPositivePeriodicFraction(theta) {
275
+ return this.radiansToPositivePeriodicFraction(theta.radians);
276
+ }
277
+ /** return the fractionalized position of the given array of angles (as radian), computed with consideration of 2PI period.
278
+ *
279
+ * * fraction is always positive
280
+ * * the start angle is at fraction 0
281
+ * * the end angle is at fraction 1
282
+ * * interior angles are between 0 and 1
283
+ * * all exterior angles are at fractions greater than 1
284
+ * * allows period shift
285
+ */
286
+ radiansArrayToPositivePeriodicFractions(data) {
287
+ const n = data.length;
288
+ for (let i = 0; i < n; i++) {
289
+ data.reassign(i, this.radiansToPositivePeriodicFraction(data.atUncheckedIndex(i)));
290
+ }
291
+ }
292
+ /** return the fractionalized position of the given angle (as radian) computed with consideration of
293
+ * 2PI period and with consideration of angle sweep direction (CW or CCW).
294
+ *
295
+ * * the start angle is at fraction 0
296
+ * * the end angle is at fraction 1
297
+ * * interior angles are between 0 and 1
298
+ * * negative fraction for angles "before" the start angle
299
+ * * fraction larger than one for angles "after" the end angle
300
+ * * allows period shift
237
301
  */
238
302
  radiansToSignedPeriodicFraction(radians) {
239
303
  if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians0))
@@ -241,8 +305,7 @@ export class AngleSweep {
241
305
  if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians1))
242
306
  return 1.0;
243
307
  const sweep = this._radians1 - this._radians0;
244
- // measure from middle of interval ...
245
- const delta = radians - this._radians0 - 0.5 * sweep;
308
+ const delta = radians - this._radians0 - 0.5 * sweep; // measure from middle of interval
246
309
  if (sweep > 0) {
247
310
  const delta1 = Angle.adjustRadiansMinusPiPlusPi(delta);
248
311
  const fraction1 = 0.5 + Geometry.safeDivideFraction(delta1, sweep, 0.0);
@@ -252,15 +315,21 @@ export class AngleSweep {
252
315
  const fraction = 0.5 + Geometry.safeDivideFraction(delta2, -sweep, 0.0);
253
316
  return fraction;
254
317
  }
255
- /** test if an angle is within the sweep */
256
- isAngleInSweep(angle) { return this.isRadiansInSweep(angle.radians); }
257
- /** test if radians are within sweep */
258
- isRadiansInSweep(radians, allowPeriodShift = true) {
259
- return AngleSweep.isRadiansInStartEnd(radians, this.startRadians, this.endRadians, allowPeriodShift);
318
+ /** return the fractionalized position of the given angle (as Angle) computed with consideration of
319
+ * 2PI period and with consideration of angle sweep direction (CW or CCW).
320
+ *
321
+ * * the start angle is at fraction 0
322
+ * * the end angle is at fraction 1
323
+ * * interior angles are between 0 and 1
324
+ * * negative fraction for angles "before" the start angle
325
+ * * fraction larger than one for angles "after" the end angle
326
+ * * allows period shift
327
+ */
328
+ angleToSignedPeriodicFraction(theta) {
329
+ return this.radiansToSignedPeriodicFraction(theta.radians);
260
330
  }
261
- /** test if radians are within sweep */
331
+ /** test if the given angle (as radians) is within sweep (between radians0 and radians1) */
262
332
  static isRadiansInStartEnd(radians, radians0, radians1, allowPeriodShift = true) {
263
- // quick out for simple inside ...
264
333
  const delta0 = radians - radians0;
265
334
  const delta1 = radians - radians1;
266
335
  if (delta0 * delta1 <= 0.0)
@@ -269,13 +338,22 @@ export class AngleSweep {
269
338
  return allowPeriodShift ? Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0) : Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians0);
270
339
  return allowPeriodShift ? this.radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, 1000.0) <= 1.0 : false;
271
340
  }
341
+ /** test if the given angle (as radians) is within sweep */
342
+ isRadiansInSweep(radians, allowPeriodShift = true) {
343
+ return AngleSweep.isRadiansInStartEnd(radians, this.startRadians, this.endRadians, allowPeriodShift);
344
+ }
345
+ /** test if the given angle (as Angle) is within the sweep */
346
+ isAngleInSweep(angle) {
347
+ return this.isRadiansInSweep(angle.radians);
348
+ }
272
349
  /** set this AngleSweep from various sources:
273
350
  *
274
351
  * * if json is undefined, a full-circle sweep is returned.
275
- * * If json is an AngleSweep object it is cloned
352
+ * * If json is an AngleSweep object, it is cloned
276
353
  * * If json is an array of 2 numbers, those numbers are start and end angles in degrees.
277
354
  * * If `json.degrees` is an array of 2 numbers, those numbers are start and end angles in degrees.
278
355
  * * If `json.radians` is an array of 2 numbers, those numbers are start and end angles in radians.
356
+ * * Otherwise, a full-circle sweep is returned.
279
357
  */
280
358
  setFromJSON(json) {
281
359
  if (!json)
@@ -288,6 +366,8 @@ export class AngleSweep {
288
366
  this.setStartEndRadians(json.radians[0], json.radians[1]);
289
367
  else if (Geometry.isNumberArray(json, 2))
290
368
  this.setStartEndDegrees(json[0], json[1]);
369
+ else
370
+ this.setStartEndRadians(); // default full circle
291
371
  }
292
372
  /** create an AngleSweep from a json object. */
293
373
  static fromJSON(json) {
@@ -300,26 +380,31 @@ export class AngleSweep {
300
380
  * @return {*} {degrees: [startAngleInDegrees, endAngleInDegrees}
301
381
  */
302
382
  toJSON() {
303
- // return { degrees: [this.startDegrees, this.endDegrees] };
304
383
  return [this.startDegrees, this.endDegrees];
305
384
  }
306
- /** test if start and end angles match, with explicit name to clarify that there is no test for 360-degree shifts. */
385
+ /** test if this angle sweep and other angle sweep match with radians tolerance.
386
+ * * Period shifts are allowed.
387
+ */
307
388
  isAlmostEqualAllowPeriodShift(other) {
389
+ // We compare angle sweeps by checking if start angle and sweep match. We cannot compare start and end because for
390
+ // example (0, 90) and (360, 90) have the same start (we allow period shift) and end but are not same angle sweeps.
308
391
  return Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians0, other._radians0)
309
- && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);
392
+ && Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);
310
393
  }
311
- /** test if start and end angles match, explicit name to clarify that 360-degree shifts are allowed. */
394
+ /** test if this angle sweep and other angle sweep match with radians tolerance.
395
+ * * Period shifts are not allowed.
396
+ */
312
397
  isAlmostEqualNoPeriodShift(other) {
313
398
  return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, other._radians0)
314
399
  && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);
315
400
  }
316
401
  /** test if start and end angles match with radians tolerance.
317
- * * This is equivalent to isAlmostEqualNoPeriodShift.
318
- * * it is present for consistency with other classes
319
- * * It is recommended that all callers use one of he longer names to be clear of their intentions:
320
- * * * isAlmostEqualAllowPeriodShift
321
- * * * isAlmostEqualRadiansNoPeriodShift
402
+ * * Period shifts are not allowed.
403
+ * * This function is equivalent to isAlmostEqualNoPeriodShift. It is present for consistency with other classes.
404
+ * However, it is recommended to use isAlmostEqualNoPeriodShift which has a clearer name.
322
405
  */
323
- isAlmostEqual(other) { return this.isAlmostEqualNoPeriodShift(other); }
406
+ isAlmostEqual(other) {
407
+ return this.isAlmostEqualNoPeriodShift(other);
408
+ }
324
409
  }
325
410
  //# sourceMappingURL=AngleSweep.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"AngleSweep.js","sourceRoot":"","sources":["../../../src/geometry3d/AngleSweep.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 { AngleSweepProps, BeJSONFunctions, Geometry } from \"../Geometry\";\r\nimport { Angle } from \"./Angle\";\r\nimport { GrowableFloat64Array } from \"./GrowableFloat64Array\";\r\n\r\n/**\r\n * An `AngleSweep` is a pair of angles at start and end of an interval.\r\n *\r\n * * For stroking purposes, the \"included interval\" is all angles numerically reached by theta = start + f*(end-start), where f is between 0 and 1.\r\n * * This stroking formula is simple numbers -- 2PI shifts are not involved.\r\n * * 2PI shifts do become important in the reverse mapping of an angle to a fraction.\r\n * * If (start < end) the angle proceeds CCW around the unit circle.\r\n * * If (end < start) the angle proceeds CW around the unit circle.\r\n * * Angles beyond 360 are fine as endpoints.\r\n * * (350,370) covers the same unit angles as (-10,10).\r\n * * (370,350) covers the same unit angles as (10,-10).\r\n * @public\r\n */\r\nexport class AngleSweep implements BeJSONFunctions {\r\n private _radians0: number;\r\n private _radians1: number;\r\n /** Read-property for degrees at the start of this AngleSweep. */\r\n public get startDegrees() { return Angle.radiansToDegrees(this._radians0); }\r\n /** Read-property for degrees at the end of this AngleSweep. */\r\n public get endDegrees() { return Angle.radiansToDegrees(this._radians1); }\r\n /** Read-property for signed start-to-end sweep in degrees. */\r\n public get sweepDegrees() { return Angle.radiansToDegrees(this._radians1 - this._radians0); }\r\n /** Read-property for degrees at the start of this AngleSweep. */\r\n public get startRadians() { return this._radians0; }\r\n /** Read-property for degrees at the end of this AngleSweep. */\r\n public get endRadians() { return this._radians1; }\r\n /** Read-property for signed start-to-end sweep in radians. */\r\n public get sweepRadians() { return this._radians1 - this._radians0; }\r\n /** Return the (strongly typed) start angle */\r\n public get startAngle() { return Angle.createRadians(this._radians0); }\r\n /** Return the (strongly typed) end angle */\r\n public get endAngle() { return Angle.createRadians(this._radians1); }\r\n /** Create a sweep as one of\r\n * * A clone of a given sweep\r\n * * 0 to given angle\r\n * * full circle if no arg given (sweep 0 to 360 degrees)\r\n */\r\n public static create(data?: AngleSweep | Angle): AngleSweep {\r\n if (data instanceof AngleSweep)\r\n return data.clone();\r\n if (data instanceof Angle)\r\n return new AngleSweep(0, data.radians);\r\n return AngleSweep.create360();\r\n }\r\n /** (private) constructor with start and end angles in radians.\r\n * * Use explicitly named static methods to clarify intent and units of inputs:\r\n *\r\n * * createStartEndRadians (startRadians:number, endRadians:number)\r\n * * createStartEndDegrees (startDegrees:number, endDegrees:number)\r\n * * createStartEnd (startAngle:Angle, endAngle:Angle)\r\n * * createStartSweepRadians (startRadians:number, sweepRadians:number)\r\n * * createStartSweepDegrees (startDegrees:number, sweepDegrees:number)\r\n * * createStartSweep (startAngle:Angle, sweepAngle:Angle)\r\n */\r\n private constructor(startRadians: number = 0, endRadians: number = 0) { this._radians0 = startRadians; this._radians1 = endRadians; }\r\n /** create an AngleSweep from start and end angles given in radians. */\r\n public static createStartEndRadians(startRadians: number = 0, endRadians: number = 2.0 * Math.PI, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startRadians, endRadians);\r\n return result;\r\n }\r\n /** Return the angle obtained by subtracting radians from this angle. */\r\n public cloneMinusRadians(radians: number): AngleSweep { return new AngleSweep(this._radians0 - radians, this._radians1 - radians); }\r\n /** create an AngleSweep from start and end angles given in degrees. */\r\n public static createStartEndDegrees(startDegrees: number = 0, endDegrees: number = 360, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees), result);\r\n }\r\n /** create an angle sweep from strongly typed start and end angles */\r\n public static createStartEnd(startAngle: Angle, endAngle: Angle, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startAngle.radians, endAngle.radians);\r\n return result;\r\n }\r\n /** Create an angle sweep with limits given as (strongly typed) angles for start and sweep */\r\n public static createStartSweep(startAngle: Angle, sweepAngle: Angle, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartSweepRadians(startAngle.radians, sweepAngle.radians, result);\r\n }\r\n /** Return a sweep with limits interpolated between this and other. */\r\n public interpolate(fraction: number, other: AngleSweep): AngleSweep {\r\n return new AngleSweep(Geometry.interpolate(this._radians0, fraction, other._radians0), Geometry.interpolate(this._radians1, fraction, other._radians1));\r\n }\r\n /** create an AngleSweep from start and end angles given in radians. */\r\n public static createStartSweepRadians(startRadians: number = 0, sweepRadians: number = Math.PI, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startRadians, startRadians + sweepRadians);\r\n return result;\r\n }\r\n /** create an AngleSweep from start and sweep given in degrees. */\r\n public static createStartSweepDegrees(startDegrees: number = 0, sweepDegrees: number = 360, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(startDegrees + sweepDegrees), result);\r\n }\r\n /** directly set the start and end angles in radians */\r\n public setStartEndRadians(startRadians: number = 0, endRadians: number = 2.0 * Math.PI) {\r\n const delta = endRadians - startRadians;\r\n if (Angle.isFullCircleRadians(delta)) {\r\n endRadians = startRadians + (delta > 0 ? 2.0 : -2.0) * Math.PI;\r\n }\r\n this._radians0 = startRadians;\r\n this._radians1 = endRadians;\r\n }\r\n /** directly set the start and end angles in degrees */\r\n public setStartEndDegrees(startDegrees: number = 0, endDegrees: number = 360.0) {\r\n this.setStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees));\r\n }\r\n /** copy from other AngleSweep. */\r\n public setFrom(other: AngleSweep) { this._radians0 = other._radians0; this._radians1 = other._radians1; }\r\n /** create a full circle sweep (CCW). startRadians defaults to 0 */\r\n public static create360(startRadians?: number): AngleSweep {\r\n startRadians = startRadians ? startRadians : 0.0;\r\n return new AngleSweep(startRadians, startRadians + 2.0 * Math.PI);\r\n }\r\n /** create a sweep from the south pole to the north pole. */\r\n public static createFullLatitude() { return AngleSweep.createStartEndRadians(-0.5 * Math.PI, 0.5 * Math.PI); }\r\n /** Reverse the start and end angle in place. */\r\n public reverseInPlace() { const a = this._radians0; this._radians0 = this._radians1; this._radians1 = a; }\r\n /** return a sweep for the \"other\" part of the circe.\r\n * @param reverseDirection true to retain the start and move backwards, false to more forwards.\r\n */\r\n public cloneComplement(reverseDirection: boolean = false, result?: AngleSweep): AngleSweep {\r\n const s = this.sweepRadians >= 0 ? 2.0 : -2.0;\r\n if (reverseDirection)\r\n return AngleSweep.createStartEndRadians(this.startRadians, this.endRadians - s * Math.PI, result);\r\n else\r\n return AngleSweep.createStartEndRadians(this.endRadians, this.startRadians + s * Math.PI, result);\r\n }\r\n /** Restrict start and end angles into the range (-90,+90) in degrees. */\r\n public capLatitudeInPlace() {\r\n const limit = 0.5 * Math.PI;\r\n this._radians0 = Geometry.clampToStartEnd(this._radians0, -limit, limit);\r\n this._radians1 = Geometry.clampToStartEnd(this._radians1, -limit, limit);\r\n }\r\n /** Ask if the sweep is counterclockwise, i.e. positive sweep */\r\n public get isCCW(): boolean { return this._radians1 >= this._radians0; }\r\n /** Ask if the sweep is a full circle. */\r\n public get isFullCircle(): boolean { return Angle.isFullCircleRadians(this.sweepRadians); }\r\n /** Ask if the sweep is a full sweep from south pole to north pole. */\r\n public get isFullLatitudeSweep(): boolean {\r\n const a = Math.PI * 0.5;\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, -a)\r\n && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1, a);\r\n }\r\n /** return a clone of this sweep. */\r\n public clone(): AngleSweep { return new AngleSweep(this._radians0, this._radians1); }\r\n /** Convert fractional position in the sweep to radians. */\r\n public fractionToRadians(fraction: number) {\r\n return fraction < 0.5 ?\r\n this._radians0 + fraction * (this._radians1 - this._radians0)\r\n : this._radians1 + (fraction - 1.0) * (this._radians1 - this._radians0);\r\n }\r\n /** Convert fractional position in the sweep to strongly typed Angle object. */\r\n public fractionToAngle(fraction: number) {\r\n return Angle.createRadians(this.fractionToRadians(fraction));\r\n }\r\n /** return 2PI divided by the sweep radians (i.e. 360 degrees divided by sweep angle).\r\n * This is the number of fractional intervals required to cover a whole circle.\r\n */\r\n public fractionPeriod(): number {\r\n return Geometry.safeDivideFraction(Math.PI * 2.0, Math.abs(this._radians1 - this._radians0), 1.0);\r\n }\r\n /** return the fractionalized position of the angle,\r\n * computed without consideration of 2PI period.\r\n * That is, an angle that is numerically much beyond than the end angle\r\n * will produce a large fraction and an angle much beyond the start angle\r\n * will produce a large negative fraction.\r\n *\r\n */\r\n public angleToUnboundedFraction(theta: Angle): number {\r\n return Geometry.safeDivideFraction(theta.radians - this._radians0, this._radians1 - this._radians0, 1.0);\r\n }\r\n /** map an angle to a fractional coordinate which is:\r\n *\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * all exterior angles are at fractions greater than 1\r\n * * the periodic jump is at full wraparound to the start angle\r\n */\r\n public angleToPositivePeriodicFraction(theta: Angle): number { return this.radiansToPositivePeriodicFraction(theta.radians); }\r\n /**\r\n * Convert each value in an array from radians to fraction.\r\n * @param data array that is input as radians, output as fractions\r\n */\r\n public radiansArrayToPositivePeriodicFractions(data: GrowableFloat64Array) {\r\n const n = data.length;\r\n for (let i = 0; i < n; i++) {\r\n data.reassign(i, this.radiansToPositivePeriodicFraction(data.atUncheckedIndex(i)));\r\n }\r\n }\r\n /**\r\n * Convert a radians value to a fraction that is always positive and can wrap. See `angleToPositivePeriodicFraction` for detailed description.\r\n * @param radians\r\n */\r\n public radiansToPositivePeriodicFraction(radians: number, zeroSweepDefault: number = 0.0): number {\r\n return AngleSweep.radiansToPositivePeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);\r\n }\r\n /**\r\n * Convert a radians value to a fraction that is always positive and can wrap. See `angleToPositivePeriodicFraction` for detailed description.\r\n * @param radians\r\n */\r\n public static radiansToPositivePeriodicFractionStartEnd(radians: number, radians0: number, radians1: number, zeroSweepDefault: number = 0.0): number {\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0))\r\n return 0.0;\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians1))\r\n return 1.0;\r\n const sweep = radians1 - radians0;\r\n const delta = radians - radians0;\r\n if (sweep > 0) {\r\n const delta1 = Angle.adjustRadians0To2Pi(delta);\r\n const fraction1 = Geometry.safeDivideFraction(delta1, sweep, zeroSweepDefault);\r\n return fraction1;\r\n }\r\n const delta2 = Angle.adjustRadians0To2Pi(-delta);\r\n const fraction2 = Geometry.safeDivideFraction(delta2, -sweep, zeroSweepDefault);\r\n return fraction2;\r\n }\r\n /** map an angle to a fractional coordinate which is:\r\n *\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * small negative for angles just \"before\" the start angle\r\n * * more than one for angles just \"after\" the end angle\r\n * * the periodic jump is at the middle of the \"outside\" interval\r\n */\r\n public angleToSignedPeriodicFraction(theta: Angle): number {\r\n return this.radiansToSignedPeriodicFraction(theta.radians);\r\n }\r\n /**\r\n * Convert a radians value to a fraction, allowing wraparound. See `angleToSignedPeriodicFraction` for detailed description.\r\n */\r\n public radiansToSignedPeriodicFraction(radians: number): number {\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians0))\r\n return 0.0;\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians1))\r\n return 1.0;\r\n const sweep = this._radians1 - this._radians0;\r\n // measure from middle of interval ...\r\n const delta = radians - this._radians0 - 0.5 * sweep;\r\n if (sweep > 0) {\r\n const delta1 = Angle.adjustRadiansMinusPiPlusPi(delta);\r\n const fraction1 = 0.5 + Geometry.safeDivideFraction(delta1, sweep, 0.0);\r\n return fraction1;\r\n }\r\n const delta2 = Angle.adjustRadiansMinusPiPlusPi(-delta);\r\n const fraction = 0.5 + Geometry.safeDivideFraction(delta2, -sweep, 0.0);\r\n return fraction;\r\n }\r\n /** test if an angle is within the sweep */\r\n public isAngleInSweep(angle: Angle): boolean { return this.isRadiansInSweep(angle.radians); }\r\n /** test if radians are within sweep */\r\n public isRadiansInSweep(radians: number, allowPeriodShift: boolean = true): boolean {\r\n return AngleSweep.isRadiansInStartEnd(radians, this.startRadians, this.endRadians, allowPeriodShift);\r\n }\r\n /** test if radians are within sweep */\r\n public static isRadiansInStartEnd(radians: number, radians0: number, radians1: number, allowPeriodShift: boolean = true): boolean {\r\n // quick out for simple inside ...\r\n const delta0 = radians - radians0;\r\n const delta1 = radians - radians1;\r\n if (delta0 * delta1 <= 0.0)\r\n return true;\r\n\r\n if (radians0 === radians1)\r\n return allowPeriodShift ? Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0) : Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians0);\r\n return allowPeriodShift ? this.radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, 1000.0) <= 1.0 : false;\r\n }\r\n\r\n /** set this AngleSweep from various sources:\r\n *\r\n * * if json is undefined, a full-circle sweep is returned.\r\n * * If json is an AngleSweep object it is cloned\r\n * * If json is an array of 2 numbers, those numbers are start and end angles in degrees.\r\n * * If `json.degrees` is an array of 2 numbers, those numbers are start and end angles in degrees.\r\n * * If `json.radians` is an array of 2 numbers, those numbers are start and end angles in radians.\r\n */\r\n public setFromJSON(json?: any) {\r\n if (!json)\r\n this.setStartEndRadians(); // default full circle\r\n else if (json instanceof AngleSweep)\r\n this.setFrom(json);\r\n else if (Geometry.isNumberArray(json.degrees, 2))\r\n this.setStartEndDegrees(json.degrees[0], json.degrees[1]);\r\n else if (Geometry.isNumberArray(json.radians, 2))\r\n this.setStartEndRadians(json.radians[0], json.radians[1]);\r\n else if (Geometry.isNumberArray(json, 2))\r\n this.setStartEndDegrees(json[0], json[1]);\r\n }\r\n /** create an AngleSweep from a json object. */\r\n public static fromJSON(json?: AngleSweepProps) {\r\n const result = AngleSweep.create360();\r\n result.setFromJSON(json);\r\n return result;\r\n }\r\n /**\r\n * Convert an AngleSweep to a JSON object.\r\n * @return {*} {degrees: [startAngleInDegrees, endAngleInDegrees}\r\n */\r\n public toJSON(): any {\r\n // return { degrees: [this.startDegrees, this.endDegrees] };\r\n return [this.startDegrees, this.endDegrees];\r\n }\r\n /** test if start and end angles match, with explicit name to clarify that there is no test for 360-degree shifts. */\r\n public isAlmostEqualAllowPeriodShift(other: AngleSweep): boolean {\r\n return Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians0, other._radians0)\r\n && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);\r\n }\r\n /** test if start and end angles match, explicit name to clarify that 360-degree shifts are allowed. */\r\n public isAlmostEqualNoPeriodShift(other: AngleSweep): boolean {\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, other._radians0)\r\n && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);\r\n }\r\n /** test if start and end angles match with radians tolerance.\r\n * * This is equivalent to isAlmostEqualNoPeriodShift.\r\n * * it is present for consistency with other classes\r\n * * It is recommended that all callers use one of he longer names to be clear of their intentions:\r\n * * * isAlmostEqualAllowPeriodShift\r\n * * * isAlmostEqualRadiansNoPeriodShift\r\n */\r\n public isAlmostEqual(other: AngleSweep): boolean { return this.isAlmostEqualNoPeriodShift(other); }\r\n}\r\n"]}
1
+ {"version":3,"file":"AngleSweep.js","sourceRoot":"","sources":["../../../src/geometry3d/AngleSweep.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 { AngleSweepProps, BeJSONFunctions, Geometry } from \"../Geometry\";\r\nimport { Angle } from \"./Angle\";\r\nimport { GrowableFloat64Array } from \"./GrowableFloat64Array\";\r\n\r\n/**\r\n * An `AngleSweep` is a pair of angles at start and end of an interval.\r\n *\r\n * * For stroking purposes, the \"included interval\" is all angles numerically reached\r\n * by theta = start + f*(end-start), where f is between 0 and 1.\r\n * * This stroking formula is simple numbers -- 2PI shifts are not involved.\r\n * * 2PI shifts do become important in the reverse mapping of an angle to a fraction.\r\n * * If \"start < end\" the angle proceeds CCW around the unit circle.\r\n * * If \"end < start\" the angle proceeds CW around the unit circle.\r\n * * Angles beyond 360 are fine as endpoints.\r\n * * (350,370) covers the same unit angles as (-10,10).\r\n * * (370,350) covers the same unit angles as (10,-10).\r\n * @public\r\n */\r\nexport class AngleSweep implements BeJSONFunctions {\r\n private _radians0: number;\r\n private _radians1: number;\r\n /** Read-property for degrees at the start of this AngleSweep. */\r\n public get startDegrees() {\r\n return Angle.radiansToDegrees(this._radians0);\r\n }\r\n /** Read-property for degrees at the end of this AngleSweep. */\r\n public get endDegrees() {\r\n return Angle.radiansToDegrees(this._radians1);\r\n }\r\n /** Read-property for signed start-to-end sweep in degrees. */\r\n public get sweepDegrees() {\r\n return Angle.radiansToDegrees(this._radians1 - this._radians0);\r\n }\r\n /** Read-property for degrees at the start of this AngleSweep. */\r\n public get startRadians() {\r\n return this._radians0;\r\n }\r\n /** Read-property for degrees at the end of this AngleSweep. */\r\n public get endRadians() {\r\n return this._radians1;\r\n }\r\n /** Read-property for signed start-to-end sweep in radians. */\r\n public get sweepRadians() {\r\n return this._radians1 - this._radians0;\r\n }\r\n /** Return the (strongly typed) start angle */\r\n public get startAngle() {\r\n return Angle.createRadians(this._radians0);\r\n }\r\n /** Return the (strongly typed) end angle */\r\n public get endAngle() {\r\n return Angle.createRadians(this._radians1);\r\n }\r\n /** Create a sweep as one of\r\n * * A clone of a given sweep\r\n * * 0 to given angle\r\n * * full circle if no arg given (sweep 0 to 360 degrees)\r\n */\r\n public static create(data?: AngleSweep | Angle): AngleSweep {\r\n if (data instanceof AngleSweep)\r\n return data.clone();\r\n if (data instanceof Angle)\r\n return new AngleSweep(0, data.radians);\r\n return AngleSweep.create360();\r\n }\r\n /** (private) constructor with start and end angles in radians.\r\n * * Use explicitly named static methods to clarify intent and units of inputs:\r\n *\r\n * * createStartEndRadians (startRadians:number, endRadians:number)\r\n * * createStartEndDegrees (startDegrees:number, endDegrees:number)\r\n * * createStartEnd (startAngle:Angle, endAngle:Angle)\r\n * * createStartSweepRadians (startRadians:number, sweepRadians:number)\r\n * * createStartSweepDegrees (startDegrees:number, sweepDegrees:number)\r\n * * createStartSweep (startAngle:Angle, sweepAngle:Angle)\r\n */\r\n private constructor(startRadians: number = 0, endRadians: number = 0) {\r\n this._radians0 = startRadians;\r\n this._radians1 = endRadians;\r\n }\r\n /**\r\n * directly set the start and end angles in radians\r\n * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.\r\n * */\r\n public setStartEndRadians(startRadians: number = 0, endRadians: number = 2.0 * Math.PI) {\r\n const delta = endRadians - startRadians;\r\n if (Angle.isFullCircleRadians(delta)) {\r\n endRadians = startRadians + (delta > 0 ? 2.0 : -2.0) * Math.PI;\r\n }\r\n this._radians0 = startRadians;\r\n this._radians1 = endRadians;\r\n }\r\n /** directly set the start and end angles in degrees */\r\n public setStartEndDegrees(startDegrees: number = 0, endDegrees: number = 360.0) {\r\n this.setStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees));\r\n }\r\n /**\r\n * create an AngleSweep from start and end angles given in radians.\r\n * * If the difference between startRadians and endRadians is greater than 360, the function limits the angle sweep to 360.\r\n * */\r\n public static createStartEndRadians(startRadians: number = 0, endRadians: number = 2.0 * Math.PI, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startRadians, endRadians);\r\n return result;\r\n }\r\n /** Return the angle obtained by subtracting radians from this angle. */\r\n public cloneMinusRadians(radians: number): AngleSweep {\r\n return new AngleSweep(this._radians0 - radians, this._radians1 - radians);\r\n }\r\n /** create an AngleSweep from start and end angles given in degrees. */\r\n public static createStartEndDegrees(startDegrees: number = 0, endDegrees: number = 360, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(endDegrees), result);\r\n }\r\n /** create an angle sweep from strongly typed start and end angles */\r\n public static createStartEnd(startAngle: Angle, endAngle: Angle, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startAngle.radians, endAngle.radians);\r\n return result;\r\n }\r\n /** create an AngleSweep from start and end angles given in radians. */\r\n public static createStartSweepRadians(startRadians: number = 0, sweepRadians: number = Math.PI, result?: AngleSweep): AngleSweep {\r\n result = result ? result : new AngleSweep();\r\n result.setStartEndRadians(startRadians, startRadians + sweepRadians);\r\n return result;\r\n }\r\n /** create an AngleSweep from start and sweep given in degrees. */\r\n public static createStartSweepDegrees(startDegrees: number = 0, sweepDegrees: number = 360, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartEndRadians(Angle.degreesToRadians(startDegrees), Angle.degreesToRadians(startDegrees + sweepDegrees), result);\r\n }\r\n /** Create an angle sweep with limits given as (strongly typed) angles for start and sweep */\r\n public static createStartSweep(startAngle: Angle, sweepAngle: Angle, result?: AngleSweep): AngleSweep {\r\n return AngleSweep.createStartSweepRadians(startAngle.radians, sweepAngle.radians, result);\r\n }\r\n /** Return a sweep with limits interpolated between this and other. */\r\n public interpolate(fraction: number, other: AngleSweep): AngleSweep {\r\n return new AngleSweep(\r\n Geometry.interpolate(this._radians0, fraction, other._radians0),\r\n Geometry.interpolate(this._radians1, fraction, other._radians1)\r\n );\r\n }\r\n /** copy from other AngleSweep. */\r\n public setFrom(other: AngleSweep) {\r\n this._radians0 = other._radians0;\r\n this._radians1 = other._radians1;\r\n }\r\n /** create a full circle sweep (CCW). startRadians defaults to 0 */\r\n public static create360(startRadians?: number): AngleSweep {\r\n startRadians = startRadians ? startRadians : 0.0;\r\n return new AngleSweep(startRadians, startRadians + 2.0 * Math.PI);\r\n }\r\n /** create a sweep from the south pole to the north pole (-90 to +90). */\r\n public static createFullLatitude() {\r\n return AngleSweep.createStartEndRadians(-0.5 * Math.PI, 0.5 * Math.PI);\r\n }\r\n /** Reverse the start and end angle in place. */\r\n public reverseInPlace() {\r\n const tmp = this._radians0;\r\n this._radians0 = this._radians1;\r\n this._radians1 = tmp;\r\n }\r\n /** return a sweep for the \"other\" part of the circle.\r\n * @param reverseDirection true to move backwards (CW) from start to end, false to more forwards (CCW) from start to end.\r\n */\r\n public cloneComplement(reverseDirection: boolean = false, result?: AngleSweep): AngleSweep {\r\n const s = this.sweepRadians >= 0 ? 2.0 : -2.0;\r\n if (reverseDirection)\r\n return AngleSweep.createStartEndRadians(this.startRadians, this.endRadians - s * Math.PI, result);\r\n else\r\n return AngleSweep.createStartEndRadians(this.endRadians, this.startRadians + s * Math.PI, result);\r\n }\r\n /**\r\n * Restrict start and end angles into the range (-90,+90) in degrees.\r\n * */\r\n public capLatitudeInPlace() {\r\n const limit = 0.5 * Math.PI;\r\n this._radians0 = Geometry.clampToStartEnd(this._radians0, -limit, limit);\r\n this._radians1 = Geometry.clampToStartEnd(this._radians1, -limit, limit);\r\n }\r\n /** Ask if the sweep is counterclockwise, i.e. positive sweep */\r\n public get isCCW(): boolean {\r\n return this._radians1 >= this._radians0;\r\n }\r\n /** Ask if the sweep is a full circle. */\r\n public get isFullCircle(): boolean {\r\n return Angle.isFullCircleRadians(this.sweepRadians);\r\n }\r\n /** Ask if the sweep is a full sweep from south pole to north pole. */\r\n public get isFullLatitudeSweep(): boolean {\r\n const a = Math.PI * 0.5;\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, -a)\r\n && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1, a);\r\n }\r\n /** return a clone of this sweep. */\r\n public clone(): AngleSweep {\r\n return new AngleSweep(this._radians0, this._radians1);\r\n }\r\n /** Convert fractional position in the sweep to radians. */\r\n public fractionToRadians(fraction: number): number {\r\n return fraction < 0.5 ?\r\n this._radians0 + fraction * (this._radians1 - this._radians0) :\r\n this._radians1 + (fraction - 1.0) * (this._radians1 - this._radians0);\r\n }\r\n /** Convert fractional position in the sweep to strongly typed Angle object. */\r\n public fractionToAngle(fraction: number) {\r\n return Angle.createRadians(this.fractionToRadians(fraction));\r\n }\r\n /** return 2PI divided by the sweep radians (i.e. 360 degrees divided by sweep angle).\r\n * * This is the number of fractional intervals required to cover a whole circle.\r\n */\r\n public fractionPeriod(): number {\r\n return Geometry.safeDivideFraction(Math.PI * 2.0, Math.abs(this._radians1 - this._radians0), 1.0);\r\n }\r\n /** return the fractionalized position of the given angle (as Angle) computed without consideration of\r\n * 2PI period and without consideration of angle sweep direction (CW or CCW).\r\n *\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * negative fraction for angles \"before\" the start angle if start < end\r\n * * fraction larger than one for angles \"after\" the end angle if start < end\r\n * * fraction larger than one for angles \"before\" the start angle if start > end\r\n * * negative fraction for angles \"after\" the end angle if start > end\r\n * * does not allow period shift\r\n */\r\n public angleToUnboundedFraction(theta: Angle): number {\r\n return Geometry.safeDivideFraction(theta.radians - this._radians0, this._radians1 - this._radians0, 1.0);\r\n }\r\n /** return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.\r\n *\r\n * * consider radians0 as `start` angle of the sweep and radians1 as `end` angle of the sweep\r\n * * fraction is always positive\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * all exterior angles are at fractions greater than 1\r\n * * allows period shift\r\n */\r\n public static radiansToPositivePeriodicFractionStartEnd(radians: number, radians0: number, radians1: number, zeroSweepDefault: number = 0.0): number {\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0))\r\n return 0.0;\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians1))\r\n return 1.0;\r\n const sweep = radians1 - radians0;\r\n const delta = radians - radians0;\r\n if (sweep > 0) {\r\n const delta1 = Angle.adjustRadians0To2Pi(delta);\r\n const fraction1 = Geometry.safeDivideFraction(delta1, sweep, zeroSweepDefault);\r\n return fraction1;\r\n }\r\n const delta2 = Angle.adjustRadians0To2Pi(-delta);\r\n const fraction2 = Geometry.safeDivideFraction(delta2, -sweep, zeroSweepDefault);\r\n return fraction2;\r\n }\r\n /** return the fractionalized position of the given angle (as radians), computed with consideration of 2PI period.\r\n *\r\n * * fraction is always positive\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * all exterior angles are at fractions greater than 1\r\n * * allows period shift\r\n */\r\n public radiansToPositivePeriodicFraction(radians: number, zeroSweepDefault: number = 0.0): number {\r\n return AngleSweep.radiansToPositivePeriodicFractionStartEnd(radians, this._radians0, this._radians1, zeroSweepDefault);\r\n }\r\n /** return the fractionalized position of the given angle (as Angle), computed with consideration of 2PI period.\r\n *\r\n * * fraction is always positive\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * all exterior angles are at fractions greater than 1\r\n * * allows period shift\r\n */\r\n public angleToPositivePeriodicFraction(theta: Angle): number {\r\n return this.radiansToPositivePeriodicFraction(theta.radians);\r\n }\r\n /** return the fractionalized position of the given array of angles (as radian), computed with consideration of 2PI period.\r\n *\r\n * * fraction is always positive\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * all exterior angles are at fractions greater than 1\r\n * * allows period shift\r\n */\r\n public radiansArrayToPositivePeriodicFractions(data: GrowableFloat64Array) {\r\n const n = data.length;\r\n for (let i = 0; i < n; i++) {\r\n data.reassign(i, this.radiansToPositivePeriodicFraction(data.atUncheckedIndex(i)));\r\n }\r\n }\r\n /** return the fractionalized position of the given angle (as radian) computed with consideration of\r\n * 2PI period and with consideration of angle sweep direction (CW or CCW).\r\n *\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * negative fraction for angles \"before\" the start angle\r\n * * fraction larger than one for angles \"after\" the end angle\r\n * * allows period shift\r\n */\r\n public radiansToSignedPeriodicFraction(radians: number): number {\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians0))\r\n return 0.0;\r\n if (Angle.isAlmostEqualRadiansAllowPeriodShift(radians, this._radians1))\r\n return 1.0;\r\n const sweep = this._radians1 - this._radians0;\r\n const delta = radians - this._radians0 - 0.5 * sweep; // measure from middle of interval\r\n if (sweep > 0) {\r\n const delta1 = Angle.adjustRadiansMinusPiPlusPi(delta);\r\n const fraction1 = 0.5 + Geometry.safeDivideFraction(delta1, sweep, 0.0);\r\n return fraction1;\r\n }\r\n const delta2 = Angle.adjustRadiansMinusPiPlusPi(-delta);\r\n const fraction = 0.5 + Geometry.safeDivideFraction(delta2, -sweep, 0.0);\r\n return fraction;\r\n }\r\n /** return the fractionalized position of the given angle (as Angle) computed with consideration of\r\n * 2PI period and with consideration of angle sweep direction (CW or CCW).\r\n *\r\n * * the start angle is at fraction 0\r\n * * the end angle is at fraction 1\r\n * * interior angles are between 0 and 1\r\n * * negative fraction for angles \"before\" the start angle\r\n * * fraction larger than one for angles \"after\" the end angle\r\n * * allows period shift\r\n */\r\n public angleToSignedPeriodicFraction(theta: Angle): number {\r\n return this.radiansToSignedPeriodicFraction(theta.radians);\r\n }\r\n /** test if the given angle (as radians) is within sweep (between radians0 and radians1) */\r\n public static isRadiansInStartEnd(radians: number, radians0: number, radians1: number, allowPeriodShift: boolean = true): boolean {\r\n const delta0 = radians - radians0;\r\n const delta1 = radians - radians1;\r\n if (delta0 * delta1 <= 0.0)\r\n return true;\r\n if (radians0 === radians1)\r\n return allowPeriodShift ? Angle.isAlmostEqualRadiansAllowPeriodShift(radians, radians0) : Angle.isAlmostEqualRadiansNoPeriodShift(radians, radians0);\r\n return allowPeriodShift ? this.radiansToPositivePeriodicFractionStartEnd(radians, radians0, radians1, 1000.0) <= 1.0 : false;\r\n }\r\n /** test if the given angle (as radians) is within sweep */\r\n public isRadiansInSweep(radians: number, allowPeriodShift: boolean = true): boolean {\r\n return AngleSweep.isRadiansInStartEnd(radians, this.startRadians, this.endRadians, allowPeriodShift);\r\n }\r\n /** test if the given angle (as Angle) is within the sweep */\r\n public isAngleInSweep(angle: Angle): boolean {\r\n return this.isRadiansInSweep(angle.radians);\r\n }\r\n /** set this AngleSweep from various sources:\r\n *\r\n * * if json is undefined, a full-circle sweep is returned.\r\n * * If json is an AngleSweep object, it is cloned\r\n * * If json is an array of 2 numbers, those numbers are start and end angles in degrees.\r\n * * If `json.degrees` is an array of 2 numbers, those numbers are start and end angles in degrees.\r\n * * If `json.radians` is an array of 2 numbers, those numbers are start and end angles in radians.\r\n * * Otherwise, a full-circle sweep is returned.\r\n */\r\n public setFromJSON(json?: any) {\r\n if (!json)\r\n this.setStartEndRadians(); // default full circle\r\n else if (json instanceof AngleSweep)\r\n this.setFrom(json);\r\n else if (Geometry.isNumberArray(json.degrees, 2))\r\n this.setStartEndDegrees(json.degrees[0], json.degrees[1]);\r\n else if (Geometry.isNumberArray(json.radians, 2))\r\n this.setStartEndRadians(json.radians[0], json.radians[1]);\r\n else if (Geometry.isNumberArray(json, 2))\r\n this.setStartEndDegrees(json[0], json[1]);\r\n else\r\n this.setStartEndRadians(); // default full circle\r\n }\r\n /** create an AngleSweep from a json object. */\r\n public static fromJSON(json?: AngleSweepProps): AngleSweep {\r\n const result = AngleSweep.create360();\r\n result.setFromJSON(json);\r\n return result;\r\n }\r\n /**\r\n * Convert an AngleSweep to a JSON object.\r\n * @return {*} {degrees: [startAngleInDegrees, endAngleInDegrees}\r\n */\r\n public toJSON(): any {\r\n return [this.startDegrees, this.endDegrees];\r\n }\r\n /** test if this angle sweep and other angle sweep match with radians tolerance.\r\n * * Period shifts are allowed.\r\n */\r\n public isAlmostEqualAllowPeriodShift(other: AngleSweep): boolean {\r\n // We compare angle sweeps by checking if start angle and sweep match. We cannot compare start and end because for\r\n // example (0, 90) and (360, 90) have the same start (we allow period shift) and end but are not same angle sweeps.\r\n return Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians0, other._radians0)\r\n && Angle.isAlmostEqualRadiansAllowPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);\r\n }\r\n /** test if this angle sweep and other angle sweep match with radians tolerance.\r\n * * Period shifts are not allowed.\r\n */\r\n public isAlmostEqualNoPeriodShift(other: AngleSweep): boolean {\r\n return Angle.isAlmostEqualRadiansNoPeriodShift(this._radians0, other._radians0)\r\n && Angle.isAlmostEqualRadiansNoPeriodShift(this._radians1 - this._radians0, other._radians1 - other._radians0);\r\n }\r\n /** test if start and end angles match with radians tolerance.\r\n * * Period shifts are not allowed.\r\n * * This function is equivalent to isAlmostEqualNoPeriodShift. It is present for consistency with other classes.\r\n * However, it is recommended to use isAlmostEqualNoPeriodShift which has a clearer name.\r\n */\r\n public isAlmostEqual(other: AngleSweep): boolean {\r\n return this.isAlmostEqualNoPeriodShift(other);\r\n }\r\n}\r\n"]}