altium-toolkit 1.1.32 → 1.1.35

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 (28) hide show
  1. package/docs/model-format.md +2 -3
  2. package/package.json +1 -1
  3. package/src/core/altium/AltiumGeneratedLibraryRecordBuilder.mjs +551 -0
  4. package/src/core/altium/AltiumLibraryRecordBuilder.mjs +286 -2
  5. package/src/core/altium/AltiumPcbLibExporter.mjs +9 -2
  6. package/src/core/altium/AltiumSchLibExporter.mjs +1 -1
  7. package/src/core/altium/PcbComponentBodyPlacementNormalizer.mjs +120 -15
  8. package/src/core/altium/PcbEmbeddedModelExtractor.mjs +52 -4
  9. package/src/core/altium/PcbShapeBasedBodyGeometryParser.mjs +85 -11
  10. package/src/core/altium/SourceComponentBundleNormalizer.mjs +31 -0
  11. package/src/core/circuit-json/CircuitJsonModelSchema.mjs +1 -1
  12. package/src/ui/AltiumScene3dAuthoredBodyAnchorAdapter.mjs +30 -2
  13. package/src/ui/AltiumScene3dExternalPlacementAdapter.mjs +27 -2
  14. package/src/ui/AltiumScene3dPlacementRotationPolicy.mjs +44 -0
  15. package/src/ui/AltiumScene3dRepeatedModelOwnerRepair.mjs +171 -6
  16. package/src/ui/AltiumScene3dShapeStackOwnerAdapter.mjs +782 -0
  17. package/src/ui/AltiumScene3dTwoRowFootprintDetector.mjs +90 -0
  18. package/src/ui/PcbScene3dBuilder.mjs +595 -28
  19. package/src/ui/PcbScene3dCopperRegionDetailBuilder.mjs +280 -0
  20. package/src/ui/PcbScene3dModelRegistry.mjs +16 -0
  21. package/src/ui/PcbScene3dPackageDimensionResolver.mjs +107 -0
  22. package/src/ui/PcbScene3dPackages.mjs +15 -3
  23. package/src/ui/PcbScene3dPadYawResolver.mjs +200 -0
  24. package/src/ui/PcbScene3dPlacementSideResolver.mjs +56 -0
  25. package/src/ui/PcbScene3dStaticBodyPlacementBuilder.mjs +638 -16
  26. package/src/ui/PcbScene3dStaticBodyRecovery.mjs +891 -0
  27. package/src/ui/PcbScene3dStaticBodySelectionKeyBuilder.mjs +358 -0
  28. package/src/ui/PcbScene3dStaticBodySymmetryRecovery.mjs +876 -0
@@ -0,0 +1,90 @@
1
+ /**
2
+ * Detects two-row surface-mount footprints from normalized PCB pads.
3
+ */
4
+ export class AltiumScene3dTwoRowFootprintDetector {
5
+ /**
6
+ * Checks whether a component owns a symmetric two-row surface footprint.
7
+ * @param {object} component PCB component.
8
+ * @param {object[]} pads Source PCB pads.
9
+ * @returns {boolean}
10
+ */
11
+ static hasTwoRowSurfaceFootprint(component, pads) {
12
+ const surfacePads = AltiumScene3dTwoRowFootprintDetector.#surfacePads(
13
+ component,
14
+ pads
15
+ )
16
+ if (surfacePads.length < 6) {
17
+ return false
18
+ }
19
+
20
+ const xSpread = AltiumScene3dTwoRowFootprintDetector.#spread(
21
+ surfacePads,
22
+ 'x'
23
+ )
24
+ const ySpread = AltiumScene3dTwoRowFootprintDetector.#spread(
25
+ surfacePads,
26
+ 'y'
27
+ )
28
+ const rowAxis = xSpread >= ySpread ? 'y' : 'x'
29
+ const lineAxis = rowAxis === 'x' ? 'y' : 'x'
30
+ const rowSpread = AltiumScene3dTwoRowFootprintDetector.#spread(
31
+ surfacePads,
32
+ rowAxis
33
+ )
34
+ const lineSpread = AltiumScene3dTwoRowFootprintDetector.#spread(
35
+ surfacePads,
36
+ lineAxis
37
+ )
38
+ if (rowSpread <= 0 || lineSpread <= 0) {
39
+ return false
40
+ }
41
+
42
+ const values = surfacePads.map((pad) => Number(pad?.[rowAxis] || 0))
43
+ const midpoint = (Math.min(...values) + Math.max(...values)) / 2
44
+ const lowerCount = values.filter((value) => value <= midpoint).length
45
+ const upperCount = values.length - lowerCount
46
+
47
+ return Math.min(lowerCount, upperCount) >= 3
48
+ }
49
+
50
+ /**
51
+ * Collects surface pads owned by one component.
52
+ * @param {object} component PCB component.
53
+ * @param {object[]} pads Source PCB pads.
54
+ * @returns {object[]}
55
+ */
56
+ static #surfacePads(component, pads) {
57
+ const componentIndex = Number(component?.componentIndex)
58
+ if (!Number.isFinite(componentIndex)) {
59
+ return []
60
+ }
61
+
62
+ const ownedPads = (Array.isArray(pads) ? pads : []).filter(
63
+ (pad) => Number(pad?.componentIndex) === componentIndex
64
+ )
65
+ const bottom =
66
+ String(component?.layer || '')
67
+ .toUpperCase()
68
+ .includes('BOTTOM') ||
69
+ String(component?.layer || '').toUpperCase() === 'BOT'
70
+ const surfacePads = ownedPads.filter((pad) =>
71
+ bottom
72
+ ? Boolean(pad?.hasBottomPasteMaskOpening)
73
+ : Boolean(pad?.hasTopPasteMaskOpening)
74
+ )
75
+
76
+ return surfacePads.length ? surfacePads : ownedPads
77
+ }
78
+
79
+ /**
80
+ * Measures pad center spread on one axis.
81
+ * @param {object[]} pads Source PCB pads.
82
+ * @param {'x' | 'y'} axis Axis key.
83
+ * @returns {number}
84
+ */
85
+ static #spread(pads, axis) {
86
+ const values = pads.map((pad) => Number(pad?.[axis] || 0))
87
+
88
+ return Math.max(...values) - Math.min(...values)
89
+ }
90
+ }