altium-toolkit 1.1.35 → 1.1.36
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.
- package/AGENTS.md +2 -2
- package/package.json +1 -1
- package/src/core/altium/PrintableTextDecoder.mjs +20 -1
- package/src/core/altium/SchematicMultipartOwnerMatcher.mjs +288 -7
- package/src/core/altium/SchematicTextParser.mjs +18 -253
- package/src/core/altium/SchematicTitleBlockParser.mjs +410 -0
- package/src/core/altium/SelectedPartAltiumExportAdapter.mjs +215 -0
- package/src/parser.mjs +1 -0
- package/src/ui/AltiumScene3dShapeStackOwnerAdapter.mjs +149 -20
- package/src/ui/PcbScene3dPackages.mjs +16 -1
- package/src/ui/PcbScene3dStaticBodyOwnerPromotion.mjs +899 -0
- package/src/ui/PcbScene3dStaticBodyPlacementBuilder.mjs +138 -8
- package/src/ui/PcbScene3dStaticBodyPrototypeRecovery.mjs +445 -0
- package/src/ui/PcbScene3dStaticBodyRecovery.mjs +7 -1
- package/src/ui/PcbScene3dStaticBodySelectionKeyBuilder.mjs +199 -2
- package/src/ui/PcbScene3dStaticBodySymmetricOwnerPromotion.mjs +438 -0
- package/src/ui/PcbScene3dStaticBodySymmetryRecovery.mjs +23 -2
- package/src/ui/SchematicColorResolver.mjs +44 -0
- package/src/ui/SchematicLineColorResolver.mjs +1 -1
- package/src/ui/SchematicShapeRenderer.mjs +13 -13
|
@@ -10,6 +10,8 @@ export class AltiumScene3dShapeStackOwnerAdapter {
|
|
|
10
10
|
static #EXACT_OWNER_TOLERANCE_MIL = 1
|
|
11
11
|
static #STACK_BODY_RADIUS_MIL = 220
|
|
12
12
|
static #HEIGHT_TOLERANCE_MIL = 0.1
|
|
13
|
+
static #TIMING_PARAMETER_NAME_PATTERN =
|
|
14
|
+
/(?:^|[^a-z0-9])(?:comment|description|device|function|part|type|value)(?:$|[^a-z0-9])/i
|
|
13
15
|
|
|
14
16
|
/**
|
|
15
17
|
* Applies authored stack ownership to static and external placements.
|
|
@@ -169,21 +171,103 @@ export class AltiumScene3dShapeStackOwnerAdapter {
|
|
|
169
171
|
return placement
|
|
170
172
|
}
|
|
171
173
|
|
|
172
|
-
return
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
placement?.positionMil,
|
|
178
|
-
assignment.owner,
|
|
179
|
-
board
|
|
180
|
-
),
|
|
181
|
-
coLocatedVariantGroupKey: assignment.groupKey
|
|
182
|
-
}
|
|
174
|
+
return AltiumScene3dShapeStackOwnerAdapter.#withStaticOwner(
|
|
175
|
+
placement,
|
|
176
|
+
assignment,
|
|
177
|
+
board
|
|
178
|
+
)
|
|
183
179
|
}
|
|
184
180
|
)
|
|
185
181
|
}
|
|
186
182
|
|
|
183
|
+
/**
|
|
184
|
+
* Applies one stack owner to a repaired static carrier body.
|
|
185
|
+
* @param {object} placement Static body placement.
|
|
186
|
+
* @param {{ owner: object, groupKey: string }} assignment Stack assignment.
|
|
187
|
+
* @param {object | undefined} board Scene board metadata.
|
|
188
|
+
* @returns {object}
|
|
189
|
+
*/
|
|
190
|
+
static #withStaticOwner(placement, assignment, board) {
|
|
191
|
+
const ownerDesignator = String(assignment?.owner?.designator || '')
|
|
192
|
+
const mountSide =
|
|
193
|
+
AltiumScene3dShapeStackOwnerAdapter.#mountSide(assignment?.owner) ||
|
|
194
|
+
placement?.mountSide
|
|
195
|
+
const sidePlacement =
|
|
196
|
+
AltiumScene3dShapeStackOwnerAdapter.#withStaticMountSide(
|
|
197
|
+
placement,
|
|
198
|
+
mountSide
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
return {
|
|
202
|
+
...sidePlacement,
|
|
203
|
+
designator: ownerDesignator,
|
|
204
|
+
selectionKey: ownerDesignator || sidePlacement.selectionKey,
|
|
205
|
+
positionMil: AltiumScene3dShapeStackOwnerAdapter.#withOwnerAnchor(
|
|
206
|
+
sidePlacement?.positionMil,
|
|
207
|
+
assignment.owner,
|
|
208
|
+
board
|
|
209
|
+
),
|
|
210
|
+
coLocatedVariantGroupKey: assignment.groupKey
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Applies a static placement side while preserving its height magnitude.
|
|
216
|
+
* @param {object} placement Static body placement.
|
|
217
|
+
* @param {string | undefined} mountSide Owner mount side.
|
|
218
|
+
* @returns {object}
|
|
219
|
+
*/
|
|
220
|
+
static #withStaticMountSide(placement, mountSide) {
|
|
221
|
+
const currentSide =
|
|
222
|
+
AltiumScene3dShapeStackOwnerAdapter.#normalizeMountSide(
|
|
223
|
+
placement?.mountSide
|
|
224
|
+
)
|
|
225
|
+
const side = AltiumScene3dShapeStackOwnerAdapter.#normalizeMountSide(
|
|
226
|
+
mountSide || currentSide
|
|
227
|
+
)
|
|
228
|
+
const z = Math.abs(Number(placement?.positionMil?.z || 0))
|
|
229
|
+
|
|
230
|
+
return {
|
|
231
|
+
...placement,
|
|
232
|
+
mountSide: side,
|
|
233
|
+
positionMil: {
|
|
234
|
+
...(placement?.positionMil || {}),
|
|
235
|
+
z: side === 'bottom' ? -z : z
|
|
236
|
+
},
|
|
237
|
+
geometry:
|
|
238
|
+
currentSide === side
|
|
239
|
+
? placement?.geometry
|
|
240
|
+
: AltiumScene3dShapeStackOwnerAdapter.#mirrorStaticGeometry(
|
|
241
|
+
placement
|
|
242
|
+
)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Mirrors source-coordinate static geometry for the opposite board side.
|
|
248
|
+
* @param {{ sourceCoordinateFrame?: boolean, geometry?: object }} placement Static body placement.
|
|
249
|
+
* @returns {object | undefined}
|
|
250
|
+
*/
|
|
251
|
+
static #mirrorStaticGeometry(placement) {
|
|
252
|
+
const geometry = placement?.geometry
|
|
253
|
+
if (
|
|
254
|
+
!placement?.sourceCoordinateFrame ||
|
|
255
|
+
!Array.isArray(geometry?.verticesMil)
|
|
256
|
+
) {
|
|
257
|
+
return geometry
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
return {
|
|
261
|
+
...geometry,
|
|
262
|
+
verticesMil: geometry.verticesMil.map((vertex) => ({
|
|
263
|
+
x: AltiumScene3dShapeStackOwnerAdapter.#round(vertex?.x || 0),
|
|
264
|
+
y: AltiumScene3dShapeStackOwnerAdapter.#round(
|
|
265
|
+
-Number(vertex?.y || 0)
|
|
266
|
+
)
|
|
267
|
+
}))
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
187
271
|
/**
|
|
188
272
|
* Re-anchors a repaired static carrier on the owning component position.
|
|
189
273
|
* @param {object | undefined} position Existing render position.
|
|
@@ -630,15 +714,9 @@ export class AltiumScene3dShapeStackOwnerAdapter {
|
|
|
630
714
|
return (
|
|
631
715
|
TIMING_DESIGNATOR_PATTERN.test(designator) ||
|
|
632
716
|
TIMING_PACKAGE_PATTERN.test(
|
|
633
|
-
|
|
634
|
-
component
|
|
635
|
-
|
|
636
|
-
component?.description,
|
|
637
|
-
component?.provenance?.footprintDescription,
|
|
638
|
-
...Object.values(component?.parameters || {})
|
|
639
|
-
]
|
|
640
|
-
.map((value) => String(value || ''))
|
|
641
|
-
.join(' ')
|
|
717
|
+
AltiumScene3dShapeStackOwnerAdapter.#timingIdentityText(
|
|
718
|
+
component
|
|
719
|
+
)
|
|
642
720
|
)
|
|
643
721
|
)
|
|
644
722
|
}
|
|
@@ -691,6 +769,19 @@ export class AltiumScene3dShapeStackOwnerAdapter {
|
|
|
691
769
|
return layer.includes('BOTTOM') || layer === 'BOT' ? 'bottom' : 'top'
|
|
692
770
|
}
|
|
693
771
|
|
|
772
|
+
/**
|
|
773
|
+
* Normalizes a static placement side token.
|
|
774
|
+
* @param {string | undefined} mountSide Candidate mount side.
|
|
775
|
+
* @returns {'top' | 'bottom'}
|
|
776
|
+
*/
|
|
777
|
+
static #normalizeMountSide(mountSide) {
|
|
778
|
+
return String(mountSide || 'top')
|
|
779
|
+
.trim()
|
|
780
|
+
.toLowerCase() === 'bottom'
|
|
781
|
+
? 'bottom'
|
|
782
|
+
: 'top'
|
|
783
|
+
}
|
|
784
|
+
|
|
694
785
|
/**
|
|
695
786
|
* Resolves one board face Z coordinate.
|
|
696
787
|
* @param {string} mountSide Mount side.
|
|
@@ -770,6 +861,44 @@ export class AltiumScene3dShapeStackOwnerAdapter {
|
|
|
770
861
|
.join(' ')
|
|
771
862
|
}
|
|
772
863
|
|
|
864
|
+
/**
|
|
865
|
+
* Builds timing-relevant identity text without material metadata.
|
|
866
|
+
* @param {object} component Source component.
|
|
867
|
+
* @returns {string}
|
|
868
|
+
*/
|
|
869
|
+
static #timingIdentityText(component) {
|
|
870
|
+
return [
|
|
871
|
+
component?.pattern,
|
|
872
|
+
component?.source,
|
|
873
|
+
component?.description,
|
|
874
|
+
component?.provenance?.footprintDescription,
|
|
875
|
+
...AltiumScene3dShapeStackOwnerAdapter.#timingParameterValues(
|
|
876
|
+
component?.parameters
|
|
877
|
+
)
|
|
878
|
+
]
|
|
879
|
+
.map((value) => String(value || ''))
|
|
880
|
+
.join(' ')
|
|
881
|
+
}
|
|
882
|
+
|
|
883
|
+
/**
|
|
884
|
+
* Returns parameter values whose names describe component identity.
|
|
885
|
+
* @param {object | undefined} parameters Source component parameters.
|
|
886
|
+
* @returns {unknown[]}
|
|
887
|
+
*/
|
|
888
|
+
static #timingParameterValues(parameters) {
|
|
889
|
+
if (!parameters || typeof parameters !== 'object') {
|
|
890
|
+
return []
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
return Object.entries(parameters)
|
|
894
|
+
.filter(([key]) =>
|
|
895
|
+
AltiumScene3dShapeStackOwnerAdapter.#TIMING_PARAMETER_NAME_PATTERN.test(
|
|
896
|
+
String(key || '')
|
|
897
|
+
)
|
|
898
|
+
)
|
|
899
|
+
.map(([, value]) => value)
|
|
900
|
+
}
|
|
901
|
+
|
|
773
902
|
/**
|
|
774
903
|
* Rounds one mil value for stable scene output.
|
|
775
904
|
* @param {number} value Candidate value.
|
|
@@ -54,7 +54,7 @@ export class PcbScene3dPackages {
|
|
|
54
54
|
static #resolveFamily(pattern) {
|
|
55
55
|
const normalized = String(pattern || '').toUpperCase()
|
|
56
56
|
|
|
57
|
-
if (
|
|
57
|
+
if (PcbScene3dPackages.#hasChipPackageCode(normalized)) {
|
|
58
58
|
return 'chip'
|
|
59
59
|
}
|
|
60
60
|
|
|
@@ -97,6 +97,15 @@ export class PcbScene3dPackages {
|
|
|
97
97
|
return 'generic'
|
|
98
98
|
}
|
|
99
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Checks whether a footprint pattern contains a compact chip package code.
|
|
102
|
+
* @param {string} normalized Uppercase footprint pattern.
|
|
103
|
+
* @returns {boolean}
|
|
104
|
+
*/
|
|
105
|
+
static #hasChipPackageCode(normalized) {
|
|
106
|
+
return /(01005|0201|0402|0603|0805|1206|C0805|C0603)/.test(normalized)
|
|
107
|
+
}
|
|
108
|
+
|
|
100
109
|
/**
|
|
101
110
|
* Resolves one default body size for the chosen family.
|
|
102
111
|
* @param {string} family
|
|
@@ -107,6 +116,12 @@ export class PcbScene3dPackages {
|
|
|
107
116
|
const normalized = String(pattern || '').toUpperCase()
|
|
108
117
|
|
|
109
118
|
if (family === 'chip') {
|
|
119
|
+
if (normalized.includes('01005')) {
|
|
120
|
+
return { width: 16, depth: 8, height: 8 }
|
|
121
|
+
}
|
|
122
|
+
if (normalized.includes('0201')) {
|
|
123
|
+
return { width: 24, depth: 12, height: 14 }
|
|
124
|
+
}
|
|
110
125
|
if (normalized.includes('0402')) {
|
|
111
126
|
return { width: 24, depth: 12, height: 14 }
|
|
112
127
|
}
|