@itwin/core-geometry 3.3.0-dev.76 → 3.3.0-dev.79

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 (37) hide show
  1. package/lib/cjs/curve/spiral/DirectSpiral3d.js +1 -1
  2. package/lib/cjs/curve/spiral/DirectSpiral3d.js.map +1 -1
  3. package/lib/cjs/geometry3d/GrowableBlockedArray.d.ts +32 -3
  4. package/lib/cjs/geometry3d/GrowableBlockedArray.d.ts.map +1 -1
  5. package/lib/cjs/geometry3d/GrowableBlockedArray.js +63 -14
  6. package/lib/cjs/geometry3d/GrowableBlockedArray.js.map +1 -1
  7. package/lib/cjs/geometry3d/GrowableFloat64Array.d.ts +24 -8
  8. package/lib/cjs/geometry3d/GrowableFloat64Array.d.ts.map +1 -1
  9. package/lib/cjs/geometry3d/GrowableFloat64Array.js +72 -54
  10. package/lib/cjs/geometry3d/GrowableFloat64Array.js.map +1 -1
  11. package/lib/cjs/geometry3d/GrowableXYArray.d.ts +51 -26
  12. package/lib/cjs/geometry3d/GrowableXYArray.d.ts.map +1 -1
  13. package/lib/cjs/geometry3d/GrowableXYArray.js +136 -116
  14. package/lib/cjs/geometry3d/GrowableXYArray.js.map +1 -1
  15. package/lib/cjs/geometry3d/GrowableXYZArray.d.ts +35 -21
  16. package/lib/cjs/geometry3d/GrowableXYZArray.d.ts.map +1 -1
  17. package/lib/cjs/geometry3d/GrowableXYZArray.js +124 -137
  18. package/lib/cjs/geometry3d/GrowableXYZArray.js.map +1 -1
  19. package/lib/esm/curve/spiral/DirectSpiral3d.js +1 -1
  20. package/lib/esm/curve/spiral/DirectSpiral3d.js.map +1 -1
  21. package/lib/esm/geometry3d/GrowableBlockedArray.d.ts +32 -3
  22. package/lib/esm/geometry3d/GrowableBlockedArray.d.ts.map +1 -1
  23. package/lib/esm/geometry3d/GrowableBlockedArray.js +63 -14
  24. package/lib/esm/geometry3d/GrowableBlockedArray.js.map +1 -1
  25. package/lib/esm/geometry3d/GrowableFloat64Array.d.ts +24 -8
  26. package/lib/esm/geometry3d/GrowableFloat64Array.d.ts.map +1 -1
  27. package/lib/esm/geometry3d/GrowableFloat64Array.js +72 -54
  28. package/lib/esm/geometry3d/GrowableFloat64Array.js.map +1 -1
  29. package/lib/esm/geometry3d/GrowableXYArray.d.ts +51 -26
  30. package/lib/esm/geometry3d/GrowableXYArray.d.ts.map +1 -1
  31. package/lib/esm/geometry3d/GrowableXYArray.js +136 -116
  32. package/lib/esm/geometry3d/GrowableXYArray.js.map +1 -1
  33. package/lib/esm/geometry3d/GrowableXYZArray.d.ts +35 -21
  34. package/lib/esm/geometry3d/GrowableXYZArray.d.ts.map +1 -1
  35. package/lib/esm/geometry3d/GrowableXYZArray.js +124 -137
  36. package/lib/esm/geometry3d/GrowableXYZArray.js.map +1 -1
  37. package/package.json +4 -4
@@ -16,59 +16,81 @@ import { Transform } from "./Transform";
16
16
  */
17
17
  export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
18
18
  /** Construct a new GrowablePoint3d array.
19
- * @param numPoints [in] initial capacity.
19
+ * @param numPoints initial capacity in xyz triples (default 8)
20
+ * @param growthFactor used by ensureCapacity to expand requested reallocation size (default 1.5)
20
21
  */
21
- constructor(numPoints = 8) {
22
+ constructor(numPoints = 8, growthFactor) {
22
23
  super();
23
- this._data = new Float64Array(numPoints * 3); // 8 Points to start (3 values each)
24
+ this._data = new Float64Array(numPoints * 3); // 3 values per point
24
25
  this._xyzInUse = 0;
25
26
  this._xyzCapacity = numPoints;
27
+ this._growthFactor = (undefined !== growthFactor && growthFactor >= 1.0) ? growthFactor : 1.5;
28
+ }
29
+ /** Copy xyz points from source array. Does not reallocate or change active point count.
30
+ * @param source array to copy from
31
+ * @param sourceCount copy the first sourceCount points; all points if undefined
32
+ * @param destOffset copy to instance array starting at this point index; zero if undefined
33
+ * @return count and offset of points copied
34
+ */
35
+ copyData(source, sourceCount, destOffset) {
36
+ // validate inputs and convert from points to entries
37
+ let myOffset = (undefined !== destOffset) ? destOffset * 3 : 0;
38
+ if (myOffset < 0)
39
+ myOffset = 0;
40
+ if (myOffset >= this._data.length)
41
+ return { count: 0, offset: 0 };
42
+ let myCount = (undefined !== sourceCount) ? sourceCount * 3 : source.length;
43
+ if (myCount > 0) {
44
+ if (myCount > source.length)
45
+ myCount = source.length;
46
+ if (myOffset + myCount > this._data.length)
47
+ myCount = this._data.length - myOffset;
48
+ if (myCount % 3 !== 0)
49
+ myCount -= myCount % 3;
50
+ }
51
+ if (myCount <= 0)
52
+ return { count: 0, offset: 0 };
53
+ if (myCount === source.length)
54
+ this._data.set(source, myOffset);
55
+ else if (source instanceof Float64Array)
56
+ this._data.set(source.subarray(0, myCount), myOffset);
57
+ else
58
+ this._data.set(source.slice(0, myCount), myOffset);
59
+ return { count: myCount / 3, offset: myOffset / 3 };
26
60
  }
27
61
  /** The number of points in use. When the length is increased, the array is padded with zeroes. */
28
62
  get length() { return this._xyzInUse; }
29
- set length(newLength) {
30
- let oldLength = this.length;
31
- if (newLength < oldLength) {
32
- this._xyzInUse = newLength;
33
- }
34
- else if (newLength > oldLength) {
35
- this.ensureCapacity(newLength);
36
- while (oldLength++ < newLength)
37
- this.pushXYZ(0, 0, 0);
38
- }
39
- }
63
+ set length(newLength) { this.resize(newLength, true); }
40
64
  /** Return the number of float64 in use. */
41
65
  get float64Length() { return this._xyzInUse * 3; }
42
66
  /** Return the raw packed data.
43
67
  * * Note that the length of the returned Float64Array is a count of doubles, and includes the excess capacity
44
68
  */
45
69
  float64Data() { return this._data; }
46
- /** If necessary, increase the capacity to a new pointCount. Current coordinates and point count (length) are unchanged. */
47
- ensureCapacity(pointCapacity) {
70
+ /** If necessary, increase the capacity to the new number of points. Current coordinates and point count (length) are unchanged. */
71
+ ensureCapacity(pointCapacity, applyGrowthFactor = true) {
48
72
  if (pointCapacity > this._xyzCapacity) {
49
- const newData = new Float64Array(pointCapacity * 3);
50
- const numCopy = this.length * 3;
51
- for (let i = 0; i < numCopy; i++)
52
- newData[i] = this._data[i];
53
- this._data = newData;
73
+ if (applyGrowthFactor)
74
+ pointCapacity *= this._growthFactor;
75
+ const prevData = this._data;
76
+ this._data = new Float64Array(pointCapacity * 3);
77
+ this.copyData(prevData, this._xyzInUse);
54
78
  this._xyzCapacity = pointCapacity;
55
79
  }
56
80
  }
57
- /** Resize the actual point count, preserving excess capacity. */
58
- resize(pointCount) {
59
- if (pointCount < this.length) {
60
- this._xyzInUse = pointCount >= 0 ? pointCount : 0;
61
- }
62
- else if (pointCount > this._xyzCapacity) {
63
- const newArray = new Float64Array(pointCount * 3);
64
- // Copy contents
65
- for (let i = 0; i < this._data.length; i += 3) {
66
- newArray[i] = this._data[i];
67
- newArray[i + 1] = this._data[i + 1];
68
- newArray[i + 2] = this._data[i + 2];
69
- }
70
- this._data = newArray;
71
- this._xyzCapacity = pointCount;
81
+ /**
82
+ * * If pointCount is less than current length, just reset current length to pointCount, effectively trimming active points but preserving original capacity.
83
+ * * If pointCount is greater than current length, reallocate to exactly pointCount, copy existing points, and optionally pad excess with zero.
84
+ * @param pointCount new number of active points in array
85
+ * @param padWithZero when increasing point count, whether to zero out new points (default false)
86
+ */
87
+ resize(pointCount, padWithZero) {
88
+ if (pointCount >= 0 && pointCount < this._xyzInUse)
89
+ this._xyzInUse = pointCount;
90
+ else if (pointCount > this._xyzInUse) {
91
+ this.ensureCapacity(pointCount, false);
92
+ if (padWithZero !== null && padWithZero !== void 0 ? padWithZero : false)
93
+ this._data.fill(0, this._xyzInUse * 3);
72
94
  this._xyzInUse = pointCount;
73
95
  }
74
96
  }
@@ -77,17 +99,14 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
77
99
  * (The clone does NOT get excess capacity)
78
100
  */
79
101
  clone(result) {
80
- const numValue = this.length * 3;
81
102
  if (!result)
82
103
  result = new GrowableXYZArray(this.length);
83
104
  else {
84
- result.clear();
85
- result.ensureCapacity(this.length);
105
+ if (result.length !== this.length)
106
+ result.clear(); // force resize to trim excess capacity
107
+ result.resize(this.length);
86
108
  }
87
- const newData = result._data;
88
- const data = this._data;
89
- for (let i = 0; i < numValue; i++)
90
- newData[i] = data[i];
109
+ result.copyData(this._data, this.length);
91
110
  result._xyzInUse = this.length;
92
111
  return result;
93
112
  }
@@ -122,6 +141,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
122
141
  }
123
142
  /** push all points of an array */
124
143
  pushAll(points) {
144
+ this.ensureCapacity(this._xyzInUse + points.length, false);
125
145
  for (const p of points)
126
146
  this.push(p);
127
147
  }
@@ -136,7 +156,6 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
136
156
  * * Any json object satisfying Point3d.isXAndY
137
157
  * * A Float64Array of doubles, interpreted as xyzxyz
138
158
  * * An array of any of the above
139
- * @returns the number of points added.
140
159
  */
141
160
  pushFrom(p) {
142
161
  if (p instanceof Point3d)
@@ -145,10 +164,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
145
164
  this.pushFromGrowableXYZArray(p);
146
165
  else if (p instanceof Point2d)
147
166
  this.pushXYZ(p.x, p.y, 0.0);
148
- else if (Geometry.isNumberArray(p, 4)) {
149
- const n = p.length;
150
- for (let i = 0; i + 2 < n; i += 3)
151
- this.pushXYZ(p[i], p[i + 1], p[i + 2]);
167
+ else if (Geometry.isNumberArray(p, 4) || p instanceof Float64Array) {
168
+ const xyzToAdd = Math.trunc(p.length / 3);
169
+ this.ensureCapacity(this._xyzInUse + xyzToAdd, false);
170
+ this.copyData(p, xyzToAdd, this._xyzInUse);
171
+ this._xyzInUse += xyzToAdd;
152
172
  }
153
173
  else if (Geometry.isNumberArray(p, 3))
154
174
  this.pushXYZ(p[0], p[1], p[2]);
@@ -163,13 +183,10 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
163
183
  this.pushXYZ(p.x, p.y, p.z);
164
184
  else if (Point3d.isXAndY(p))
165
185
  this.pushXYZ(p.x, p.y, 0.0);
166
- else if (p instanceof Float64Array) {
167
- const n = p.length;
168
- for (let i = 0; i + 2 < n; i += 3)
169
- this.pushXYZ(p[i], p[i + 1], p[i + 2]);
170
- }
171
186
  else if (p instanceof IndexedXYZCollection) {
172
- for (let i = 0; i < p.length; i++)
187
+ const n = p.length;
188
+ this.ensureCapacity(this._xyzInUse + n, false);
189
+ for (let i = 0; i < n; i++)
173
190
  this.pushXYZ(p.getXAtUncheckedPointIndex(i), p.getYAtUncheckedPointIndex(i), p.getZAtUncheckedPointIndex(i));
174
191
  }
175
192
  }
@@ -178,19 +195,18 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
178
195
  * @param numWrap number of xyz values to replicate
179
196
  */
180
197
  pushWrap(numWrap) {
181
- if (this._xyzInUse > 0) {
182
- let k;
198
+ if (this._xyzInUse >= numWrap) {
199
+ this.ensureCapacity(this._xyzInUse + numWrap, false);
183
200
  for (let i = 0; i < numWrap; i++) {
184
- k = 3 * i;
201
+ const k = 3 * i;
185
202
  this.pushXYZ(this._data[k], this._data[k + 1], this._data[k + 2]);
186
203
  }
187
204
  }
188
205
  }
189
206
  /** append a new point with given x,y,z */
190
207
  pushXYZ(x, y, z) {
208
+ this.ensureCapacity(this._xyzInUse + 1);
191
209
  const index = this._xyzInUse * 3;
192
- if (index >= this._data.length)
193
- this.ensureCapacity(this.length === 0 ? 4 : this.length * 2);
194
210
  this._data[index] = x;
195
211
  this._data[index + 1] = y;
196
212
  this._data[index + 2] = z;
@@ -203,11 +219,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
203
219
  shiftForward(numPoints) {
204
220
  if (numPoints <= 0)
205
221
  return;
206
- let newCapacity = this.length + numPoints; // in POINTS
207
- if (newCapacity > this._xyzCapacity) {
208
- newCapacity = Math.max(4, 2 * this._xyzCapacity);
209
- this.ensureCapacity(newCapacity);
210
- }
222
+ this.ensureCapacity(this._xyzInUse + numPoints);
211
223
  const numAddedDouble = 3 * numPoints;
212
224
  const lastIndex = this._xyzInUse * 3;
213
225
  this._data.copyWithin(numAddedDouble, 0, lastIndex);
@@ -283,14 +295,9 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
283
295
  }
284
296
  /** copy xyz into strongly typed Point3d */
285
297
  getPoint3dAtCheckedPointIndex(pointIndex, result) {
286
- const index = 3 * pointIndex;
287
298
  if (this.isIndexValid(pointIndex)) {
288
- if (!result)
289
- result = Point3d.create();
290
- result.x = this._data[index];
291
- result.y = this._data[index + 1];
292
- result.z = this._data[index + 2];
293
- return result;
299
+ const index = 3 * pointIndex;
300
+ return Point3d.create(this._data[index], this._data[index + 1], this._data[index + 2], result);
294
301
  }
295
302
  return undefined;
296
303
  }
@@ -311,26 +318,17 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
311
318
  }
312
319
  /** copy xy into strongly typed Point2d */
313
320
  getPoint2dAtCheckedPointIndex(pointIndex, result) {
314
- const index = 3 * pointIndex;
315
321
  if (this.isIndexValid(pointIndex)) {
316
- if (!result)
317
- result = Point2d.create();
318
- result.x = this._data[index];
319
- result.y = this._data[index + 1];
320
- return result;
322
+ const index = 3 * pointIndex;
323
+ return Point2d.create(this._data[index], this._data[index + 1], result);
321
324
  }
322
325
  return undefined;
323
326
  }
324
327
  /** copy xyz into strongly typed Vector3d */
325
328
  getVector3dAtCheckedVectorIndex(vectorIndex, result) {
326
- const index = 3 * vectorIndex;
327
- if (vectorIndex >= 0 && vectorIndex < this._xyzInUse) {
328
- if (!result)
329
- result = Vector3d.create();
330
- result.x = this._data[index];
331
- result.y = this._data[index + 1];
332
- result.z = this._data[index + 2];
333
- return result;
329
+ if (this.isIndexValid(vectorIndex)) {
330
+ const index = 3 * vectorIndex;
331
+ return Vector3d.create(this._data[index], this._data[index + 1], this._data[index + 2], result);
334
332
  }
335
333
  return undefined;
336
334
  }
@@ -362,11 +360,8 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
362
360
  // full array push . . .
363
361
  if (sourceIndex === undefined) {
364
362
  const numXYZAdd = source.length;
365
- this.ensureCapacity(this.length + numXYZAdd);
366
- const nXAdd = source.length * 3;
367
- const i0 = this._xyzInUse * 3;
368
- for (let i = 0; i < nXAdd; i++)
369
- this._data[i0 + i] = source._data[i];
363
+ this.ensureCapacity(this.length + numXYZAdd, false);
364
+ this.copyData(source._data, numXYZAdd, this.length);
370
365
  this._xyzInUse += numXYZAdd;
371
366
  return numXYZAdd;
372
367
  }
@@ -428,12 +423,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
428
423
  * Copy all points into a simple array of Point3d
429
424
  */
430
425
  getPoint3dArray() {
426
+ const n = 3 * this._xyzInUse;
431
427
  const result = [];
432
428
  const data = this._data;
433
- const n = this.length;
434
- for (let i = 0; i < n; i++) {
435
- result.push(Point3d.create(data[i * 3], data[i * 3 + 1], data[i * 3 + 2]));
436
- }
429
+ for (let i = 0; i < n; i += 3)
430
+ result.push(Point3d.create(data[i], data[i + 1], data[i + 2]));
437
431
  return result;
438
432
  }
439
433
  /** multiply each point by the transform, replace values. */
@@ -586,7 +580,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
586
580
  let x = 0;
587
581
  let y = 0;
588
582
  let z = 0;
589
- for (let i = 0; i + 3 <= nDouble; i += 3) {
583
+ for (let i = 0; i + 2 < nDouble; i += 3) {
590
584
  x = data[i] - x0;
591
585
  y = data[i + 1] - y0;
592
586
  z = data[i + 2] - z0;
@@ -601,11 +595,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
601
595
  const numDouble = this.float64Length;
602
596
  const data = this._data;
603
597
  if (transform) {
604
- for (let i = 0; i + 3 <= numDouble; i += 3)
598
+ for (let i = 0; i + 2 < numDouble; i += 3)
605
599
  rangeToExtend.extendTransformedXYZ(transform, data[i], data[i + 1], data[i + 2]);
606
600
  }
607
601
  else {
608
- for (let i = 0; i + 3 <= numDouble; i += 3)
602
+ for (let i = 0; i + 2 < numDouble; i += 3)
609
603
  rangeToExtend.extendXYZ(data[i], data[i + 1], data[i + 2]);
610
604
  }
611
605
  }
@@ -716,15 +710,10 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
716
710
  vectorIndexIndex(i, j, result) {
717
711
  if (!this.isIndexValid(i) || !this.isIndexValid(j))
718
712
  return undefined;
719
- if (!result)
720
- result = Vector3d.create();
721
713
  const data = this._data;
722
714
  i = 3 * i;
723
715
  j = 3 * j;
724
- result.x = data[j] - data[i];
725
- result.y = data[j + 1] - data[i + 1];
726
- result.z = data[j + 2] - data[i + 2];
727
- return result;
716
+ return Vector3d.create(data[j] - data[i], data[j + 1] - data[i + 1], data[j + 2] - data[i + 2], result);
728
717
  }
729
718
  /** Compute a vector from origin to indexed target j */
730
719
  vectorXYAndZIndex(origin, j, result) {
@@ -737,12 +726,13 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
737
726
  }
738
727
  /** Compute the cross product of vectors from from indexed origin to indexed targets i and j */
739
728
  crossProductIndexIndexIndex(originIndex, targetAIndex, targetBIndex, result) {
740
- const i = originIndex * 3;
741
- const j = targetAIndex * 3;
742
- const k = targetBIndex * 3;
743
- const data = this._data;
744
- if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex))
729
+ if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
730
+ const i = originIndex * 3;
731
+ const j = targetAIndex * 3;
732
+ const k = targetBIndex * 3;
733
+ const data = this._data;
745
734
  return Geometry.crossProductXYZXYZ(data[j] - data[i], data[j + 1] - data[i + 1], data[j + 2] - data[i + 2], data[k] - data[i], data[k + 1] - data[i + 1], data[k + 2] - data[i + 2], result);
735
+ }
746
736
  return undefined;
747
737
  }
748
738
  /** Compute the dot product of pointIndex with [x,y,z] */
@@ -762,22 +752,22 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
762
752
  * * accumulate it to the result.
763
753
  */
764
754
  accumulateCrossProductIndexIndexIndex(originIndex, targetAIndex, targetBIndex, result) {
765
- const i = originIndex * 3;
766
- const j = targetAIndex * 3;
767
- const k = targetBIndex * 3;
768
- const data = this._data;
769
- if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex))
755
+ if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
756
+ const i = originIndex * 3;
757
+ const j = targetAIndex * 3;
758
+ const k = targetBIndex * 3;
759
+ const data = this._data;
770
760
  result.addCrossProductToTargetsInPlace(data[i], data[i + 1], data[i + 2], data[j], data[j + 1], data[j + 2], data[k], data[k + 1], data[k + 2]);
771
- return undefined;
761
+ }
772
762
  }
773
763
  /**
774
764
  * * compute the cross product from indexed origin t indexed targets targetAIndex and targetB index.
775
765
  * * accumulate it to the result.
776
766
  */
777
767
  accumulateScaledXYZ(index, scale, sum) {
778
- const i = index * 3;
779
- const data = this._data;
780
768
  if (this.isIndexValid(index)) {
769
+ const i = index * 3;
770
+ const data = this._data;
781
771
  sum.x += scale * data[i];
782
772
  sum.y += scale * data[i + 1];
783
773
  sum.z += scale * data[i + 2];
@@ -785,16 +775,17 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
785
775
  }
786
776
  /** Compute the cross product of vectors from from origin to indexed targets i and j */
787
777
  crossProductXYAndZIndexIndex(origin, targetAIndex, targetBIndex, result) {
788
- const j = targetAIndex * 3;
789
- const k = targetBIndex * 3;
790
- const data = this._data;
791
- if (this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex))
778
+ if (this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
779
+ const j = targetAIndex * 3;
780
+ const k = targetBIndex * 3;
781
+ const data = this._data;
792
782
  return Geometry.crossProductXYZXYZ(data[j] - origin.x, data[j + 1] - origin.y, data[j + 2] - origin.z, data[k] - origin.x, data[k + 1] - origin.y, data[k + 2] - origin.z, result);
783
+ }
793
784
  return undefined;
794
785
  }
795
786
  /** Return the distance between an array point and the input point. */
796
787
  distanceIndexToPoint(i, spacePoint) {
797
- if (i >= 0 && i < this._xyzInUse) {
788
+ if (this.isIndexValid(i)) {
798
789
  const i0 = 3 * i;
799
790
  return Geometry.hypotenuseXYZ(spacePoint.x - this._data[i0], spacePoint.y - this._data[i0 + 1], spacePoint.z - this._data[i0 + 2]);
800
791
  }
@@ -802,14 +793,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
802
793
  }
803
794
  /**
804
795
  * Return distance squared between indicated points.
805
- * * Concrete classes may be able to implement this without creating a temporary.
806
- * @param index0 first point index
807
- * @param index1 second point index
808
- * @param defaultDistanceSquared distance squared to return if either point index is invalid.
809
- *
796
+ * @param i first point index
797
+ * @param j second point index
810
798
  */
811
799
  distanceSquaredIndexIndex(i, j) {
812
- if (i >= 0 && i < this._xyzInUse && j >= 0 && j <= this._xyzInUse) {
800
+ if (this.isIndexValid(i) && this.isIndexValid(j)) {
813
801
  const i0 = 3 * i;
814
802
  const j0 = 3 * j;
815
803
  return Geometry.hypotenuseSquaredXYZ(this._data[j0] - this._data[i0], this._data[j0 + 1] - this._data[i0 + 1], this._data[j0 + 2] - this._data[i0 + 2]);
@@ -818,13 +806,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
818
806
  }
819
807
  /**
820
808
  * Return distance between indicated points.
821
- * * Concrete classes may be able to implement this without creating a temporary.
822
- * @param index0 first point index
823
- * @param index1 second point index
824
- * @param defaultDistanceSquared distance squared to return if either point index is invalid.
809
+ * @param i first point index
810
+ * @param j second point index
825
811
  */
826
812
  distanceIndexIndex(i, j) {
827
- if (i >= 0 && i < this._xyzInUse && j >= 0 && j <= this._xyzInUse) {
813
+ if (this.isIndexValid(i) && this.isIndexValid(j)) {
828
814
  const i0 = 3 * i;
829
815
  const j0 = 3 * j;
830
816
  return Geometry.hypotenuseXYZ(this._data[j0] - this._data[i0], this._data[j0 + 1] - this._data[i0 + 1], this._data[j0 + 2] - this._data[i0 + 2]);
@@ -833,7 +819,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
833
819
  }
834
820
  /** Return the distance between points in distinct arrays. */
835
821
  static distanceBetweenPointsIn2Arrays(arrayA, i, arrayB, j) {
836
- if (i >= 0 && i < arrayA._xyzInUse && j >= 0 && j <= arrayB._xyzInUse) {
822
+ if (arrayA.isIndexValid(i) && arrayB.isIndexValid(j)) {
837
823
  const i0 = 3 * i;
838
824
  const j0 = 3 * j;
839
825
  return Geometry.hypotenuseXYZ(arrayB._data[j0] - arrayA._data[i0], arrayB._data[j0 + 1] - arrayA._data[i0 + 1], arrayB._data[j0 + 2] - arrayA._data[i0 + 2]);
@@ -897,6 +883,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
897
883
  let b0 = pointIndex0 * 3;
898
884
  const nb = other.length * 3;
899
885
  let numAdded = 0;
886
+ this.ensureCapacity(this._xyzInUse + numAdd, false);
900
887
  while (b0 >= 0 && b0 + 2 < nb && numAdded < numAdd) {
901
888
  this.pushXYZ(dataB[b0], dataB[b0 + 1], dataB[b0 + 2]);
902
889
  b0 += step * 3;
@@ -932,11 +919,11 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
932
919
  points.pop();
933
920
  }
934
921
  /**
935
- * * Triangle for (unchecked!) for three points identified by index
922
+ * Compute frame for a triangle formed by three (unchecked!) points identified by index.
936
923
  * * z direction of frame is 001.
937
- * * Transform axes from origin to targetX and targetY
924
+ * * Transform axes from origin to targetA and targetB
938
925
  * * in local coordinates (u,v,w) the xy interior of the triangle is `u>=0, v>= 0, w>= 0, u+v+w<1`
939
- * * Return undefined if transform is invertible (i.e. points are not in a vertical plane.)
926
+ * * Return undefined if transform is not invertible, e.g. if points are in a vertical plane.
940
927
  */
941
928
  fillLocalXYTriangleFrame(originIndex, targetAIndex, targetBIndex, result) {
942
929
  if (this.isIndexValid(originIndex) && this.isIndexValid(targetAIndex) && this.isIndexValid(targetBIndex)) {
@@ -959,7 +946,7 @@ export class GrowableXYZArray extends IndexedReadWriteXYZCollection {
959
946
  return undefined;
960
947
  }
961
948
  /**
962
- * Pass the (x,y,z) of each point to a function which returns a replacement for of of the 3 components.
949
+ * Pass the (x,y,z) of each point to a function which returns a replacement for one of the 3 components.
963
950
  * @param componentIndex Index (0,1,2) of component to be replaced.
964
951
  * @param func function to be called as `func(x,y,z)`, returning a replacement value for componentIndex
965
952
  */