altium-toolkit 1.4.13 → 1.4.15

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.
@@ -0,0 +1,94 @@
1
+ // SPDX-FileCopyrightText: 2026 André Fiedler
2
+ // SPDX-License-Identifier: GPL-3.0-or-later
3
+
4
+ /**
5
+ * Builds compact reusable indexes for late Altium 3D owner recovery.
6
+ */
7
+ export class AltiumScene3dRecoverySpatialIndex {
8
+ /**
9
+ * Groups source pads by numeric component owner.
10
+ * @param {object[]} pads Source PCB pads.
11
+ * @returns {Map<number, object[]>}
12
+ */
13
+ static padsByComponent(pads) {
14
+ const index = new Map()
15
+ for (const pad of pads) {
16
+ const componentIndex = Number(pad?.componentIndex)
17
+ if (!Number.isFinite(componentIndex)) continue
18
+ index.set(componentIndex, [
19
+ ...(index.get(componentIndex) || []),
20
+ pad
21
+ ])
22
+ }
23
+ return index
24
+ }
25
+
26
+ /**
27
+ * Indexes arbitrary values by a point selected from each value.
28
+ * @param {object[]} values Values to index.
29
+ * @param {number} cellSize Bucket size.
30
+ * @param {(value: object) => object} pointSelector Point selector.
31
+ * @returns {Map<string, object[]>}
32
+ */
33
+ static create(values, cellSize, pointSelector) {
34
+ const index = new Map()
35
+ for (const value of values) {
36
+ const point = pointSelector(value)
37
+ const x = Number(point?.x)
38
+ const y = Number(point?.y)
39
+ if (!Number.isFinite(x) || !Number.isFinite(y)) continue
40
+ const key = AltiumScene3dRecoverySpatialIndex.#key(
41
+ Math.floor(x / cellSize),
42
+ Math.floor(y / cellSize)
43
+ )
44
+ index.set(key, [...(index.get(key) || []), value])
45
+ }
46
+ return index
47
+ }
48
+
49
+ /**
50
+ * Reads values from square neighboring spatial buckets.
51
+ * @param {Map<string, object[]>} index Spatial index.
52
+ * @param {object} point Query point.
53
+ * @param {number} cellSize Bucket size.
54
+ * @param {number} radiusCells Query radius in buckets.
55
+ * @returns {object[]}
56
+ */
57
+ static nearby(index, point, cellSize, radiusCells) {
58
+ const centerX = Math.floor(Number(point?.x) / cellSize)
59
+ const centerY = Math.floor(Number(point?.y) / cellSize)
60
+ if (!Number.isFinite(centerX) || !Number.isFinite(centerY)) return []
61
+ const values = []
62
+ for (
63
+ let x = centerX - radiusCells;
64
+ x <= centerX + radiusCells;
65
+ x += 1
66
+ ) {
67
+ for (
68
+ let y = centerY - radiusCells;
69
+ y <= centerY + radiusCells;
70
+ y += 1
71
+ ) {
72
+ values.push(
73
+ ...(index.get(
74
+ AltiumScene3dRecoverySpatialIndex.#key(x, y)
75
+ ) || [])
76
+ )
77
+ }
78
+ }
79
+ return values
80
+ }
81
+
82
+ /**
83
+ * Builds a stable spatial bucket key.
84
+ * @param {number} x X bucket.
85
+ * @param {number} y Y bucket.
86
+ * @returns {string}
87
+ */
88
+ static #key(x, y) {
89
+ return `${x}:${y}`
90
+ }
91
+ }
92
+
93
+ Object.freeze(AltiumScene3dRecoverySpatialIndex.prototype)
94
+ Object.freeze(AltiumScene3dRecoverySpatialIndex)