@kitware/vtk.js 34.10.0 → 34.11.0

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.
@@ -81,6 +81,14 @@ export interface vtkPoints extends vtkDataArray {
81
81
  * @returns {Number} Index of the inserted point.
82
82
  */
83
83
  insertNextPoint(x: number, y: number, z: number): number;
84
+
85
+ /**
86
+ * Insert the [x,y,z] coordinates of a point at the given index.
87
+ * @param {Number} ptId The index of point.
88
+ * @param {Number[]} point The [x, y, z] coordinates of the point.
89
+ * @returns {Number} The index of the inserted point.
90
+ */
91
+ insertPoint(ptId: number, point: number[]): number;
84
92
  }
85
93
 
86
94
  /**
@@ -35,6 +35,7 @@ function vtkPoints(publicAPI, model) {
35
35
  publicAPI.getPoint = publicAPI.getTuple;
36
36
  publicAPI.findPoint = publicAPI.findTuple;
37
37
  publicAPI.insertNextPoint = (x, y, z) => publicAPI.insertNextTuple([x, y, z]);
38
+ publicAPI.insertPoint = (ptId, point) => publicAPI.insertTuple(ptId, point);
38
39
  publicAPI.getBounds = () => {
39
40
  if (publicAPI.getNumberOfComponents() === 3) {
40
41
  const xRange = publicAPI.getRange(0);
@@ -49,8 +50,7 @@ function vtkPoints(publicAPI, model) {
49
50
  return model.bounds;
50
51
  }
51
52
  if (publicAPI.getNumberOfComponents() !== 2) {
52
- vtkErrorMacro(`getBounds called on an array with components of
53
- ${publicAPI.getNumberOfComponents()}`);
53
+ vtkErrorMacro(`getBounds called on an array with components of ${publicAPI.getNumberOfComponents()}`);
54
54
  return INVALID_BOUNDS;
55
55
  }
56
56
  const xRange = publicAPI.getRange(0);
@@ -1,6 +1,6 @@
1
1
  import { vtkObject } from './../../interfaces';
2
2
  import { Bounds } from './../../types';
3
- import { ILocatorInitialValues } from './Locator';
3
+ import vtkLocator, { ILocatorInitialValues } from './Locator';
4
4
 
5
5
  /**
6
6
  *
@@ -11,7 +11,7 @@ export interface IAbstractPointLocatorInitialValues
11
11
  numberOfBuckets: number;
12
12
  }
13
13
 
14
- export interface vtkAbstractPointLocator extends vtkObject {
14
+ export interface vtkAbstractPointLocator extends vtkLocator {
15
15
  /**
16
16
  * Set the bounds of this object.
17
17
  * @param {Bounds} input
@@ -325,6 +325,37 @@ export function cutWithPlane(
325
325
  normal: Vector3
326
326
  ): boolean;
327
327
 
328
+ /**
329
+ * Clamp the divisions to ensure the total number doesn't exceed targetBins
330
+ * @param {Number} targetBins - Maximum number of bins allowed
331
+ * @param {Number[]} divs - Divisions array to adjust [divX, divY, divZ]
332
+ */
333
+ export function clampDivisions(targetBins: number, divs: number[]): void;
334
+
335
+ /**
336
+ * Compute the number of divisions given the current bounding box and a
337
+ * target number of buckets/bins. Handles degenerate bounding boxes properly.
338
+ * @param {Bounds} bounds - The bounding box
339
+ * @param {Number} totalBins - Target number of bins
340
+ * @param {Number[]} divs - Output array to store divisions [divX, divY, divZ]
341
+ * @param {Bounds} [adjustedBounds] - Output array to store adjusted bounds if needed
342
+ * @returns {Number} The actual total number of bins
343
+ */
344
+ export function computeDivisions(
345
+ bounds: Bounds,
346
+ totalBins: number,
347
+ divs: number[],
348
+ adjustedBounds?: Bounds
349
+ ): number;
350
+
351
+ /**
352
+ * Calculate the squared distance from point x to the specified bounds.
353
+ * @param {Vector3} x The point coordinates
354
+ * @param {Bounds} bounds The bounding box coordinates
355
+ * @returns {Number} The squared distance to the bounds
356
+ */
357
+ export function distance2ToBounds(x: Vector3, bounds: Bounds): number;
358
+
328
359
  declare class BoundingBox {
329
360
  getBounds(): Bounds;
330
361
  /**
@@ -409,10 +440,9 @@ declare class BoundingBox {
409
440
 
410
441
  /**
411
442
  * Inflates a bounding box.
412
- * @param {Bounds} bounds
413
- * @param {number} delta
443
+ * @param {number} [delta] The amount to inflate the bounding box by.
414
444
  */
415
- inflate(bounds: Bounds, delta: number): Bounds;
445
+ inflate(delta?: number): Bounds;
416
446
 
417
447
  /**
418
448
  * Scales a bounding box.
@@ -611,6 +641,14 @@ declare class BoundingBox {
611
641
  * @param {Vector3} normal
612
642
  */
613
643
  cutWithPlane(bounds: Bounds, origin: Vector3, normal: Vector3): boolean;
644
+
645
+ /**
646
+ * Calculate the squared distance from point x to the specified bounds.
647
+ * @param {Vector3} x The point coordinates
648
+ * @param {Bounds} bounds The bounding box coordinates
649
+ * @returns {Number} The squared distance to the bounds
650
+ */
651
+ distance2ToBounds(x: Vector3, bounds: Bounds): number;
614
652
  }
615
653
 
616
654
  export interface IBoundingBoxInitialValues {
@@ -653,6 +691,7 @@ declare const vtkBoundingBox: {
653
691
  intersects: typeof intersects;
654
692
  containsPoint: typeof containsPoint;
655
693
  contains: typeof contains;
694
+ distance2ToBounds: typeof distance2ToBounds;
656
695
  INIT_BOUNDS: Bounds;
657
696
  };
658
697
 
@@ -96,6 +96,10 @@ function setMaxPoint(bounds, x, y, z) {
96
96
  return xMax !== x || yMax !== y || zMax !== z;
97
97
  }
98
98
  function inflate(bounds, delta) {
99
+ if (delta == null) {
100
+ // eslint-disable-next-line no-use-before-define
101
+ return minInflate(bounds);
102
+ }
99
103
  bounds[0] -= delta;
100
104
  bounds[1] += delta;
101
105
  bounds[2] -= delta;
@@ -104,6 +108,33 @@ function inflate(bounds, delta) {
104
108
  bounds[5] += delta;
105
109
  return bounds;
106
110
  }
111
+ function minInflate(bounds) {
112
+ const nonZero = [0, 0, 0];
113
+ let maxIdx = -1;
114
+ let max = 0.0;
115
+ let w = 0.0;
116
+ for (let i = 0; i < 3; ++i) {
117
+ w = bounds[i * 2 + 1] - bounds[i * 2];
118
+ if (w > max) {
119
+ max = w;
120
+ maxIdx = i;
121
+ }
122
+ nonZero[i] = w > 0.0 ? 1 : 0;
123
+ }
124
+ if (maxIdx < 0) {
125
+ return inflate(bounds, 0.5);
126
+ }
127
+
128
+ // Any zero width sides are bumped out 1% of max side
129
+ for (let i = 0; i < 3; ++i) {
130
+ if (!nonZero[i]) {
131
+ const d = 0.005 * max;
132
+ bounds[i * 2] -= d;
133
+ bounds[i * 2 + 1] += d;
134
+ }
135
+ }
136
+ return bounds;
137
+ }
107
138
  function scale(bounds, sx, sy, sz) {
108
139
  if (!isValid(bounds)) {
109
140
  return false;
@@ -513,6 +544,145 @@ function cutWithPlane(bounds, origin, normal) {
513
544
  return true;
514
545
  }
515
546
 
547
+ /**
548
+ * Clamp the divisions to ensure the total number doesn't exceed targetBins
549
+ * @param {Number} targetBins - Maximum number of bins allowed
550
+ * @param {Array} divs - Divisions array to adjust [divX, divY, divZ]
551
+ */
552
+ function clampDivisions(targetBins, divs) {
553
+ for (let i = 0; i < 3; ++i) {
554
+ divs[i] = divs[i] < 1 ? 1 : divs[i];
555
+ }
556
+ let numBins = divs[0] * divs[1] * divs[2];
557
+ while (numBins > targetBins) {
558
+ for (let i = 0; i < 3; ++i) {
559
+ divs[i] = divs[i] > 1 ? divs[i] - 1 : 1;
560
+ }
561
+ numBins = divs[0] * divs[1] * divs[2];
562
+ }
563
+ }
564
+
565
+ /**
566
+ * Compute the number of divisions given the current bounding box and a
567
+ * target number of buckets/bins. Handles degenerate bounding boxes properly.
568
+ * @param {Bounds} bounds - The bounding box
569
+ * @param {Number} totalBins - Target number of bins
570
+ * @param {Array} divs - Output array to store divisions [divX, divY, divZ]
571
+ * @param {Array} [adjustedBounds] - Output array to store adjusted bounds if needed
572
+ * @returns {Number} The actual total number of bins
573
+ */
574
+ function computeDivisions(bounds, totalBins, divs) {
575
+ let adjustedBounds = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
576
+ // This will always produce at least one bin
577
+ // eslint-disable-next-line no-param-reassign
578
+ totalBins = totalBins <= 0 ? 1 : totalBins;
579
+
580
+ // First determine the maximum length of the side of the bounds. Keep track
581
+ // of zero width sides of the bounding box.
582
+ let numNonZero = 0;
583
+ const nonZero = [0, 0, 0];
584
+ let maxIdx = -1;
585
+ let max = 0.0;
586
+ const lengths = getLengths(bounds);
587
+
588
+ // Use a finite tolerance when detecting zero width sides
589
+ const totLen = lengths[0] + lengths[1] + lengths[2];
590
+ const zeroDetectionTolerance = totLen * (0.001 / 3.0);
591
+ for (let i = 0; i < 3; ++i) {
592
+ if (lengths[i] > max) {
593
+ maxIdx = i;
594
+ max = lengths[i];
595
+ }
596
+ if (lengths[i] > zeroDetectionTolerance) {
597
+ nonZero[i] = 1;
598
+ numNonZero++;
599
+ } else {
600
+ nonZero[i] = 0;
601
+ }
602
+ }
603
+
604
+ // Get min and max points
605
+ const minPoint = getMinPoint(bounds);
606
+ const maxPoint = getMaxPoint(bounds);
607
+
608
+ // If the bounding box is degenerate, then one bin of arbitrary size
609
+ if (numNonZero < 1) {
610
+ divs[0] = 1;
611
+ divs[1] = 1;
612
+ divs[2] = 1;
613
+ adjustedBounds[0] = minPoint[0] - 0.5;
614
+ adjustedBounds[1] = maxPoint[0] + 0.5;
615
+ adjustedBounds[2] = minPoint[1] - 0.5;
616
+ adjustedBounds[3] = maxPoint[1] + 0.5;
617
+ adjustedBounds[4] = minPoint[2] - 0.5;
618
+ adjustedBounds[5] = maxPoint[2] + 0.5;
619
+ return 1;
620
+ }
621
+
622
+ // Compute the divisions roughly in proportion to the bounding box edge lengths
623
+ let f = totalBins;
624
+ f /= nonZero[0] ? lengths[0] / totLen : 1.0;
625
+ f /= nonZero[1] ? lengths[1] / totLen : 1.0;
626
+ f /= nonZero[2] ? lengths[2] / totLen : 1.0;
627
+ f **= 1.0 / numNonZero;
628
+ for (let i = 0; i < 3; ++i) {
629
+ divs[i] = nonZero[i] ? Math.floor(f * lengths[i] / totLen) : 1;
630
+ divs[i] = divs[i] < 1 ? 1 : divs[i];
631
+ }
632
+
633
+ // Make sure that we do not exceed the totalBins
634
+ clampDivisions(totalBins, divs);
635
+
636
+ // Now compute the final bounds, making sure it is a non-zero volume
637
+ const delta = 0.5 * lengths[maxIdx] / divs[maxIdx];
638
+ for (let i = 0; i < 3; ++i) {
639
+ if (nonZero[i]) {
640
+ adjustedBounds[2 * i] = minPoint[i];
641
+ adjustedBounds[2 * i + 1] = maxPoint[i];
642
+ } else {
643
+ adjustedBounds[2 * i] = minPoint[i] - delta;
644
+ adjustedBounds[2 * i + 1] = maxPoint[i] + delta;
645
+ }
646
+ }
647
+ return divs[0] * divs[1] * divs[2];
648
+ }
649
+
650
+ /**
651
+ * Calculate the squared distance from point x to the specified bounds.
652
+ * @param {Vector3} x The point coordinates
653
+ * @param {Bounds} bounds The bounding box coordinates
654
+ * @returns {Number} The squared distance to the bounds
655
+ */
656
+ function distance2ToBounds(x, bounds) {
657
+ // Are we within the bounds?
658
+ if (x[0] >= bounds[0] && x[0] <= bounds[1] && x[1] >= bounds[2] && x[1] <= bounds[3] && x[2] >= bounds[4] && x[2] <= bounds[5]) {
659
+ return 0.0;
660
+ }
661
+ const deltas = [0.0, 0.0, 0.0];
662
+
663
+ // dx
664
+ if (x[0] < bounds[0]) {
665
+ deltas[0] = bounds[0] - x[0];
666
+ } else if (x[0] > bounds[1]) {
667
+ deltas[0] = x[0] - bounds[1];
668
+ }
669
+
670
+ // dy
671
+ if (x[1] < bounds[2]) {
672
+ deltas[1] = bounds[2] - x[1];
673
+ } else if (x[1] > bounds[3]) {
674
+ deltas[1] = x[1] - bounds[3];
675
+ }
676
+
677
+ // dz
678
+ if (x[2] < bounds[4]) {
679
+ deltas[2] = bounds[4] - x[2];
680
+ } else if (x[2] > bounds[5]) {
681
+ deltas[2] = x[2] - bounds[5];
682
+ }
683
+ return dot(deltas, deltas);
684
+ }
685
+
516
686
  // ----------------------------------------------------------------------------
517
687
  // Light Weight class
518
688
  // ----------------------------------------------------------------------------
@@ -630,6 +800,13 @@ class BoundingBox {
630
800
  contains(otherBounds) {
631
801
  return intersects(this.bounds, otherBounds);
632
802
  }
803
+ computeDivisions(totalBins, divs) {
804
+ let adjustedBounds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
805
+ return computeDivisions(this.bounds, totalBins, divs, adjustedBounds);
806
+ }
807
+ distance2ToBounds(x) {
808
+ return distance2ToBounds(x, this.bounds);
809
+ }
633
810
  }
634
811
  function newInstance(initialValues) {
635
812
  const bounds = initialValues && initialValues.bounds;
@@ -675,6 +852,9 @@ const STATIC = {
675
852
  intersects,
676
853
  containsPoint,
677
854
  contains,
855
+ computeDivisions,
856
+ clampDivisions,
857
+ distance2ToBounds,
678
858
  INIT_BOUNDS
679
859
  };
680
860
  var vtkBoundingBox = {
@@ -682,4 +862,4 @@ var vtkBoundingBox = {
682
862
  ...STATIC
683
863
  };
684
864
 
685
- export { STATIC, addBounds, addPoint, addPoints, computeCornerPoints, computeLocalBounds, computeScale3, contains, containsPoint, cutWithPlane, vtkBoundingBox as default, equals, getCenter, getCorners, getDiagonalLength, getLength, getLengths, getMaxLength, getMaxPoint, getMinPoint, getXRange, getYRange, getZRange, inflate, intersect, intersectBox, intersectPlane, intersects, isValid, reset, scale, scaleAboutCenter, setBounds, setMaxPoint, setMinPoint, transformBounds };
865
+ export { STATIC, addBounds, addPoint, addPoints, clampDivisions, computeCornerPoints, computeDivisions, computeLocalBounds, computeScale3, contains, containsPoint, cutWithPlane, vtkBoundingBox as default, distance2ToBounds, equals, getCenter, getCorners, getDiagonalLength, getLength, getLengths, getMaxLength, getMaxPoint, getMinPoint, getXRange, getYRange, getZRange, intersect, intersectBox, intersectPlane, intersects, isValid, reset, scale, scaleAboutCenter, setBounds, setMaxPoint, setMinPoint, transformBounds };
@@ -1,10 +1,11 @@
1
1
  import { vtkObject } from './../../interfaces';
2
+ import vtkDataSet from './DataSet';
2
3
 
3
4
  /**
4
5
  *
5
6
  */
6
7
  export interface ILocatorInitialValues {
7
- dataSet?: number[];
8
+ dataSet?: vtkDataSet;
8
9
  maxLevel?: number;
9
10
  level?: number;
10
11
  automatic?: boolean;
@@ -12,7 +13,97 @@ export interface ILocatorInitialValues {
12
13
  useExistingSearchStructure?: boolean;
13
14
  }
14
15
 
15
- export interface vtkLocator extends vtkObject {}
16
+ export interface vtkLocator extends vtkObject {
17
+ /**
18
+ * Get whether locator depth/resolution of locator is computed automatically
19
+ * from average number of entities in bucket.
20
+ */
21
+ getAutomatic(): boolean;
22
+
23
+ /**
24
+ * Get the dataset associated with this locator.
25
+ *
26
+ * @returns {vtkDataSet} The dataset associated with this locator.
27
+ */
28
+ getDataSet(): vtkDataSet;
29
+
30
+ /**
31
+ * Get the current level of the locator.
32
+ *
33
+ * @returns {Number} The current level of the locator.
34
+ */
35
+ getLevel(): number;
36
+
37
+ /**
38
+ * Get the maximum level of the locator.
39
+ *
40
+ * @returns {Number} The maximum level of the locator.
41
+ */
42
+ getMaxLevel(): number;
43
+
44
+ /**
45
+ * Get the tolerance used for the locator.
46
+ *
47
+ * @returns {Number} The tolerance value.
48
+ */
49
+ getTolerance(): number;
50
+
51
+ /**
52
+ * Get whether to use an existing search structure.
53
+ *
54
+ * @returns {Boolean} Whether an existing search structure is used.
55
+ */
56
+ getUseExistingSearchStructure(): boolean;
57
+
58
+ /**
59
+ * Set whether locator depth/resolution of locator is computed automatically
60
+ * from average number of entities in bucket.
61
+ *
62
+ * @param {Boolean} automatic - The automatic flag.
63
+ * @returns {Boolean} Whether the operation was successful.
64
+ */
65
+ setAutomatic(automatic: boolean): boolean;
66
+
67
+ /**
68
+ * Set the dataset associated with this locator.
69
+ *
70
+ * @param {vtkDataSet} dataSet - The dataset to associate with this locator.
71
+ * @returns {Boolean} Whether the operation was successful.
72
+ */
73
+ setDataSet(dataSet: vtkDataSet): boolean;
74
+
75
+ /**
76
+ * Set the current level of the locator.
77
+ *
78
+ * @param {Number} level - The level to set.
79
+ * @returns {Boolean} Whether the operation was successful.
80
+ */
81
+ setLevel(level: number): boolean;
82
+
83
+ /**
84
+ * Set the maximum level of the locator.
85
+ *
86
+ * @param {Number} maxLevel - The maximum level to set.
87
+ * @returns {Boolean} Whether the operation was successful.
88
+ */
89
+ setMaxLevel(maxLevel: number): boolean;
90
+
91
+ /**
92
+ * Set the tolerance used for the locator.
93
+ *
94
+ * @param {Number} tolerance - The tolerance value to set.
95
+ * @returns {Boolean} Whether the operation was successful.
96
+ */
97
+ setTolerance(tolerance: number): boolean;
98
+
99
+ /**
100
+ * Set whether to use an existing search structure.
101
+ *
102
+ * @param {Boolean} useExistingSearchStructure - Whether to use an existing search structure.
103
+ * @returns {Boolean} Whether the operation was successful.
104
+ */
105
+ setUseExistingSearchStructure(useExistingSearchStructure: boolean): boolean;
106
+ }
16
107
 
17
108
  // ----------------------------------------------------------------------------
18
109
  // Static API
@@ -31,10 +122,11 @@ export function extend(
31
122
  initialValues?: ILocatorInitialValues
32
123
  ): void;
33
124
 
34
- // ----------------------------------------------------------------------------
35
-
36
125
  /**
37
- * vtkLocator
126
+ * vtkLocator is an abstract base class for spatial search objects, or locators.
127
+ * The principle behind locators is that they divide 3-space into small regions
128
+ * (or "buckets") that can be quickly found in response to queries about point
129
+ * location, line intersection, or object-object intersection.
38
130
  */
39
131
  export declare const vtkLocator: {
40
132
  extend: typeof extend;
@@ -0,0 +1,64 @@
1
+ import { Vector3 } from './../../types';
2
+ import vtkPointLocator, {
3
+ IInsertPointResult,
4
+ IPointLocatorInitialValues,
5
+ } from './PointLocator';
6
+
7
+ /**
8
+ * Initial values for vtkMergePoints.
9
+ */
10
+ export interface IMergePointsInitialValues extends IPointLocatorInitialValues {
11
+ bucketSize?: number;
12
+ }
13
+
14
+ export interface vtkMergePoints extends vtkPointLocator {
15
+ /**
16
+ * Check if a point is already inserted in the merge points structure.
17
+ *
18
+ * @param {Vector3} x The point to check.
19
+ * @returns {Number} The ID of the point if it exists, otherwise -1.
20
+ */
21
+ isInsertedPoint(x: Vector3): number;
22
+
23
+ /**
24
+ * Insert a point into the merge points structure.
25
+ * If the point is already present, it returns the existing ID.
26
+ * Otherwise, it inserts the point and returns a new ID.
27
+ *
28
+ * @param {Vector3} x The point to insert as an array of 3 numbers.
29
+ * @returns {IInsertPointResult} An object indicating if the point was inserted and its ID.
30
+ */
31
+ insertUniquePoint(x: Vector3): IInsertPointResult;
32
+ }
33
+
34
+ /**
35
+ * Method used to decorate a given object (publicAPI+model) with vtkMergePoints characteristics.
36
+ *
37
+ * @param publicAPI object on which methods will be bounds (public)
38
+ * @param model object on which data structure will be bounds (protected)
39
+ * @param {IMergePointsInitialValues} [initialValues] (default: {})
40
+ */
41
+ export function extend(
42
+ publicAPI: object,
43
+ model: object,
44
+ initialValues?: IMergePointsInitialValues
45
+ ): void;
46
+
47
+ /**
48
+ * Method used to create a new instance of vtkMergePoints.
49
+ * @param {IMergePointsInitialValues} [initialValues] for pre-setting some of its content
50
+ */
51
+ export function newInstance(
52
+ initialValues?: IMergePointsInitialValues
53
+ ): vtkMergePoints;
54
+
55
+ /**
56
+ * vtkMergePoints merge exactly coincident points.
57
+ *
58
+ * vtkMergePoints is a locator object to quickly locate points in 3D.
59
+ */
60
+ export declare const vtkMergePoints: {
61
+ newInstance: typeof newInstance;
62
+ extend: typeof extend;
63
+ };
64
+ export default vtkMergePoints;
@@ -0,0 +1,130 @@
1
+ import { m as macro } from '../../macros2.js';
2
+ import vtkPointLocator from './PointLocator.js';
3
+
4
+ const {
5
+ vtkErrorMacro
6
+ } = macro;
7
+
8
+ /**
9
+ * Search for a point in the array using indices from bucketIds
10
+ * @param {Number[]} bucketIds - The list of point IDs in the bucket.
11
+ * @param {vtkPoints} points - The vtkPoints object containing the points.
12
+ * @param {Vector3} x - The point to check.
13
+ * @returns {Number} - The ID of the point if it exists, otherwise -1.
14
+ */
15
+ function findPointInBucket(bucketIds, points, x) {
16
+ const data = points.getData();
17
+ for (let i = 0; i < bucketIds.length; ++i) {
18
+ const ptId = bucketIds[i];
19
+ const idx = ptId * 3;
20
+ if (x[0] === data[idx] && x[1] === data[idx + 1] && x[2] === data[idx + 2]) {
21
+ return ptId;
22
+ }
23
+ }
24
+ return -1;
25
+ }
26
+
27
+ // ----------------------------------------------------------------------------
28
+ // vtkMergePoints methods
29
+ // ----------------------------------------------------------------------------
30
+
31
+ function vtkMergePoints(publicAPI, model) {
32
+ // Set our className
33
+ model.classHierarchy.push('vtkMergePoints');
34
+
35
+ /**
36
+ * Check if a point is already inserted in the merge points structure.
37
+ *
38
+ * @param {Vector3} x The point to check.
39
+ * @returns {Number} The ID of the point if it exists, otherwise -1.
40
+ */
41
+ publicAPI.isInsertedPoint = x => {
42
+ const idx = publicAPI.getBucketIndex(x);
43
+ const bucketIds = model.hashTable.get(idx);
44
+ if (bucketIds) {
45
+ return findPointInBucket(bucketIds, model.points, x);
46
+ }
47
+ return -1;
48
+ };
49
+
50
+ /**
51
+ * Insert a point into the merge points structure.
52
+ * If the point is already present, it returns the existing ID.
53
+ * Otherwise, it inserts the point and returns a new ID.
54
+ *
55
+ * @param {Vector3} x The point to insert as an array of 3 numbers.
56
+ * @returns {IInsertPointResult} An object indicating if the point was inserted and its ID.
57
+ */
58
+ publicAPI.insertUniquePoint = x => {
59
+ if (!x || x.length !== 3) {
60
+ vtkErrorMacro('Point must be a Vector3.');
61
+ return {
62
+ inserted: false,
63
+ id: -1
64
+ };
65
+ }
66
+ const idx = publicAPI.getBucketIndex(x);
67
+ let bucketIds = model.hashTable.get(idx);
68
+ let id = null;
69
+ if (bucketIds !== undefined) {
70
+ const ptId = findPointInBucket(bucketIds, model.points, x);
71
+ if (ptId !== -1) {
72
+ id = ptId;
73
+ return {
74
+ inserted: false,
75
+ id
76
+ };
77
+ }
78
+ } else {
79
+ bucketIds = [];
80
+ model.hashTable.set(idx, bucketIds);
81
+ }
82
+
83
+ // Insert new point
84
+ bucketIds.push(model.insertionPointId);
85
+ model.points.insertNextPoint(...x);
86
+ id = model.insertionPointId++;
87
+ return {
88
+ inserted: true,
89
+ id
90
+ };
91
+ };
92
+ }
93
+
94
+ // ----------------------------------------------------------------------------
95
+ // Object factory
96
+ // ----------------------------------------------------------------------------
97
+
98
+ function defaultValues(initialValues) {
99
+ return {
100
+ // points: null,
101
+ // hashTable: null,
102
+ ...initialValues
103
+ };
104
+ }
105
+
106
+ // ----------------------------------------------------------------------------
107
+
108
+ function extend(publicAPI, model) {
109
+ let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
110
+ vtkPointLocator.extend(publicAPI, model, defaultValues(initialValues));
111
+
112
+ // Make this a VTK object
113
+ macro.obj(publicAPI, model);
114
+
115
+ // Object specific methods
116
+ vtkMergePoints(publicAPI, model);
117
+ }
118
+
119
+ // ----------------------------------------------------------------------------
120
+
121
+ const newInstance = macro.newInstance(extend, 'vtkMergePoints');
122
+
123
+ // ----------------------------------------------------------------------------
124
+
125
+ var index = {
126
+ newInstance,
127
+ extend
128
+ };
129
+
130
+ export { index as default, extend, newInstance };