altium-toolkit 1.1.35 → 1.1.37

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 (35) hide show
  1. package/AGENTS.md +17 -2
  2. package/package.json +1 -1
  3. package/src/core/altium/PrintableTextDecoder.mjs +20 -1
  4. package/src/core/altium/SchematicMultipartOwnerMatcher.mjs +288 -7
  5. package/src/core/altium/SchematicTextParser.mjs +18 -253
  6. package/src/core/altium/SchematicTitleBlockParser.mjs +410 -0
  7. package/src/core/altium/SelectedPartAltiumExportAdapter.mjs +215 -0
  8. package/src/parser.mjs +1 -0
  9. package/src/ui/AltiumScene3dAuthoredBodyAnchorAdapter.mjs +245 -12
  10. package/src/ui/AltiumScene3dAuthoredConnectorYawPolicy.mjs +176 -0
  11. package/src/ui/AltiumScene3dBottomSourceHalfTurnPolicy.mjs +93 -0
  12. package/src/ui/AltiumScene3dDisplayModuleYawPolicy.mjs +284 -0
  13. package/src/ui/AltiumScene3dExternalPlacementAdapter.mjs +521 -23
  14. package/src/ui/AltiumScene3dPlacementRotationPolicy.mjs +766 -19
  15. package/src/ui/AltiumScene3dQfnFootprintDetector.mjs +307 -0
  16. package/src/ui/AltiumScene3dRepeatedFullFootprintBodyCollapse.mjs +518 -0
  17. package/src/ui/AltiumScene3dRepeatedModelOwnerRepair.mjs +121 -17
  18. package/src/ui/AltiumScene3dShapeStackOwnerAdapter.mjs +286 -135
  19. package/src/ui/AltiumScene3dShapeStackOwnerConflictPolicy.mjs +299 -0
  20. package/src/ui/PcbScene3dBoardOutlineRefiner.mjs +22 -0
  21. package/src/ui/PcbScene3dBuilder.mjs +613 -117
  22. package/src/ui/PcbScene3dModelRegistry.mjs +222 -10
  23. package/src/ui/PcbScene3dPackages.mjs +16 -1
  24. package/src/ui/PcbScene3dPlacementSideResolver.mjs +262 -22
  25. package/src/ui/PcbScene3dStaticBodyOwnerPromotion.mjs +984 -0
  26. package/src/ui/PcbScene3dStaticBodyPadOwnerPromotion.mjs +378 -0
  27. package/src/ui/PcbScene3dStaticBodyPlacementBuilder.mjs +169 -23
  28. package/src/ui/PcbScene3dStaticBodyPrototypeRecovery.mjs +445 -0
  29. package/src/ui/PcbScene3dStaticBodyRecovery.mjs +7 -1
  30. package/src/ui/PcbScene3dStaticBodySelectionKeyBuilder.mjs +199 -2
  31. package/src/ui/PcbScene3dStaticBodySymmetricOwnerPromotion.mjs +439 -0
  32. package/src/ui/PcbScene3dStaticBodySymmetryRecovery.mjs +23 -2
  33. package/src/ui/SchematicColorResolver.mjs +44 -0
  34. package/src/ui/SchematicLineColorResolver.mjs +1 -1
  35. package/src/ui/SchematicShapeRenderer.mjs +13 -13
@@ -643,10 +643,31 @@ export class PcbScene3dStaticBodySymmetryRecovery {
643
643
  */
644
644
  static #bodyFamilyKey(componentBody) {
645
645
  const geometry = componentBody?.staticGeometry || {}
646
+ const identityKey = [componentBody?.identifier, componentBody?.name]
647
+ .map((value) =>
648
+ String(value ?? '')
649
+ .trim()
650
+ .toLowerCase()
651
+ )
652
+ .filter(Boolean)
653
+ .join('|')
654
+ const anonymousModelKey = identityKey
655
+ ? ''
656
+ : [componentBody?.modelId, componentBody?.checksum]
657
+ .map((value) =>
658
+ String(value ?? '')
659
+ .trim()
660
+ .toLowerCase()
661
+ )
662
+ .filter(Boolean)
663
+ .join('|')
664
+ const bodyIdentityKey = identityKey || anonymousModelKey
665
+ if (!bodyIdentityKey) {
666
+ return ''
667
+ }
646
668
 
647
669
  return [
648
- componentBody?.identifier,
649
- componentBody?.name,
670
+ bodyIdentityKey,
650
671
  geometry.kind,
651
672
  PcbScene3dStaticBodySymmetryRecovery.#numberKey(geometry.heightMil),
652
673
  PcbScene3dStaticBodySymmetryRecovery.#numberKey(
@@ -73,6 +73,12 @@ export class SchematicColorResolver {
73
73
  fallbackVariable,
74
74
  preserveUnknown = false
75
75
  ) {
76
+ const normalized = SchematicColorResolver.#normalizeColor(color)
77
+
78
+ if (SchematicColorResolver.#isNearBlackSourceColor(normalized)) {
79
+ return SchematicColorResolver.#toVariable(fallbackVariable)
80
+ }
81
+
76
82
  const resolved = SchematicColorResolver.resolveColor(
77
83
  color,
78
84
  fallbackVariable,
@@ -127,6 +133,29 @@ export class SchematicColorResolver {
127
133
  : SchematicColorResolver.#toVariable(fallbackVariable)
128
134
  }
129
135
 
136
+ /**
137
+ * Resolves one non-text fill, using schematic ink when source artwork only
138
+ * supplies the default black text color.
139
+ * @param {string | undefined} fill
140
+ * @param {string} fallbackVariable
141
+ * @param {boolean} [preserveUnknown]
142
+ * @returns {string}
143
+ */
144
+ static resolveNonTextFill(fill, fallbackVariable, preserveUnknown = false) {
145
+ const resolved = SchematicColorResolver.resolveFill(
146
+ fill,
147
+ fallbackVariable,
148
+ preserveUnknown
149
+ )
150
+
151
+ return resolved ===
152
+ SchematicColorResolver.#toVariable('--schematic-text-color')
153
+ ? SchematicColorResolver.#toVariable(
154
+ '--schematic-default-ink-color'
155
+ )
156
+ : resolved
157
+ }
158
+
130
159
  /**
131
160
  * Resolves an explicitly authored source stroke color without mapping it to
132
161
  * a semantic theme token.
@@ -272,6 +301,21 @@ export class SchematicColorResolver {
272
301
  }
273
302
  }
274
303
 
304
+ /**
305
+ * Returns true for very dark source colors that usually mean default
306
+ * schematic text black rather than an intentional artwork color.
307
+ * @param {string} color Normalized color.
308
+ * @returns {boolean}
309
+ */
310
+ static #isNearBlackSourceColor(color) {
311
+ const rgb = SchematicColorResolver.#parseHexColor(color)
312
+ if (!rgb) {
313
+ return false
314
+ }
315
+
316
+ return Math.max(rgb.r, rgb.g, rgb.b) <= 32
317
+ }
318
+
275
319
  /**
276
320
  * Converts RGB channels to HSL.
277
321
  * @param {{ r: number, g: number, b: number }} color
@@ -35,7 +35,7 @@ export class SchematicLineColorResolver {
35
35
  )
36
36
  }
37
37
 
38
- return SchematicColorResolver.resolveColor(
38
+ return SchematicColorResolver.resolveNonTextColor(
39
39
  line?.color,
40
40
  '--schematic-default-ink-color'
41
41
  )
@@ -42,7 +42,7 @@ export class SchematicShapeRenderer {
42
42
  ) +
43
43
  '" fill="' +
44
44
  escapeHtml(
45
- SchematicColorResolver.resolveFill(
45
+ SchematicColorResolver.resolveNonTextFill(
46
46
  polygon.fill || 'none',
47
47
  '--schematic-fill-color',
48
48
  true
@@ -50,7 +50,7 @@ export class SchematicShapeRenderer {
50
50
  ) +
51
51
  '" stroke="' +
52
52
  escapeHtml(
53
- SchematicColorResolver.resolveColor(
53
+ SchematicColorResolver.resolveNonTextColor(
54
54
  polygon.color,
55
55
  '--schematic-default-ink-color'
56
56
  )
@@ -128,7 +128,7 @@ export class SchematicShapeRenderer {
128
128
  escapeHtml(path) +
129
129
  '" stroke="' +
130
130
  escapeHtml(
131
- SchematicColorResolver.resolveColor(
131
+ SchematicColorResolver.resolveNonTextColor(
132
132
  bezier.color,
133
133
  '--schematic-default-ink-color'
134
134
  )
@@ -205,7 +205,7 @@ export class SchematicShapeRenderer {
205
205
  escapeHtml(path) +
206
206
  '" fill="' +
207
207
  escapeHtml(
208
- SchematicColorResolver.resolveFill(
208
+ SchematicColorResolver.resolveNonTextFill(
209
209
  SchematicShapeRenderer.#resolveSchematicPieFill(pie),
210
210
  '--schematic-fill-color',
211
211
  true
@@ -213,7 +213,7 @@ export class SchematicShapeRenderer {
213
213
  ) +
214
214
  '" stroke="' +
215
215
  escapeHtml(
216
- SchematicColorResolver.resolveColor(
216
+ SchematicColorResolver.resolveNonTextColor(
217
217
  pie.color,
218
218
  '--schematic-default-ink-color'
219
219
  )
@@ -256,7 +256,7 @@ export class SchematicShapeRenderer {
256
256
  fill,
257
257
  '--schematic-fill-color'
258
258
  )
259
- : SchematicColorResolver.resolveFill(
259
+ : SchematicColorResolver.resolveNonTextFill(
260
260
  fill,
261
261
  '--schematic-fill-color'
262
262
  )
@@ -268,7 +268,7 @@ export class SchematicShapeRenderer {
268
268
  rectangle.color,
269
269
  '--schematic-default-ink-color'
270
270
  )
271
- : SchematicColorResolver.resolveColor(
271
+ : SchematicColorResolver.resolveNonTextColor(
272
272
  rectangle.color,
273
273
  '--schematic-default-ink-color'
274
274
  )
@@ -321,7 +321,7 @@ export class SchematicShapeRenderer {
321
321
  fill,
322
322
  '--schematic-fill-color'
323
323
  )
324
- : SchematicColorResolver.resolveFill(
324
+ : SchematicColorResolver.resolveNonTextFill(
325
325
  fill,
326
326
  '--schematic-fill-color'
327
327
  )
@@ -333,7 +333,7 @@ export class SchematicShapeRenderer {
333
333
  rectangle.color,
334
334
  '--schematic-default-ink-color'
335
335
  )
336
- : SchematicColorResolver.resolveColor(
336
+ : SchematicColorResolver.resolveNonTextColor(
337
337
  rectangle.color,
338
338
  '--schematic-default-ink-color'
339
339
  )
@@ -361,7 +361,7 @@ export class SchematicShapeRenderer {
361
361
  const x = Number(symbol?.x || 0)
362
362
  const y = projectSchematicY(sheetHeight, Number(symbol?.y || 0))
363
363
  const color = escapeHtml(
364
- SchematicColorResolver.resolveColor(
364
+ SchematicColorResolver.resolveNonTextColor(
365
365
  symbol.color,
366
366
  '--schematic-default-ink-color'
367
367
  )
@@ -422,7 +422,7 @@ export class SchematicShapeRenderer {
422
422
  path +
423
423
  '" stroke="' +
424
424
  escapeHtml(
425
- SchematicColorResolver.resolveColor(
425
+ SchematicColorResolver.resolveNonTextColor(
426
426
  arc.color,
427
427
  '--schematic-default-ink-color'
428
428
  )
@@ -451,7 +451,7 @@ export class SchematicShapeRenderer {
451
451
  formatNumber(Math.max(Number(ellipse.radiusY) || 0, 0.8)) +
452
452
  '" fill="' +
453
453
  escapeHtml(
454
- SchematicColorResolver.resolveFill(
454
+ SchematicColorResolver.resolveNonTextFill(
455
455
  SchematicShapeRenderer.#resolveSchematicEllipseFill(
456
456
  ellipse
457
457
  ),
@@ -460,7 +460,7 @@ export class SchematicShapeRenderer {
460
460
  ) +
461
461
  '" stroke="' +
462
462
  escapeHtml(
463
- SchematicColorResolver.resolveColor(
463
+ SchematicColorResolver.resolveNonTextColor(
464
464
  ellipse.color,
465
465
  '--schematic-default-ink-color'
466
466
  )