altium-toolkit 1.1.2 → 1.1.22

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 (57) hide show
  1. package/docs/api.md +37 -0
  2. package/docs/model-format.md +18 -0
  3. package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +2 -2
  4. package/docs/testing.md +5 -0
  5. package/package.json +1 -1
  6. package/spec/library-scope.md +5 -0
  7. package/src/core/altium/AltiumLayoutParser.mjs +275 -13
  8. package/src/core/altium/AltiumLibraryBatchExporter.mjs +206 -0
  9. package/src/core/altium/AltiumLibraryRecordBuilder.mjs +293 -0
  10. package/src/core/altium/AltiumParser.mjs +245 -10
  11. package/src/core/altium/AltiumPcbLibExporter.mjs +101 -0
  12. package/src/core/altium/AltiumSchLibExporter.mjs +57 -0
  13. package/src/core/altium/AsciiRecordParser.mjs +43 -11
  14. package/src/core/altium/PcbComponentKindPolicy.mjs +9 -9
  15. package/src/core/altium/PcbEmbeddedFontExtractor.mjs +186 -43
  16. package/src/core/altium/PcbEmbeddedModelExtractor.mjs +22 -3
  17. package/src/core/altium/PcbOutlineRecovery.mjs +94 -0
  18. package/src/core/altium/PrintableTextDecoder.mjs +133 -13
  19. package/src/core/altium/SchematicComponentOwnerTextResolver.mjs +13 -0
  20. package/src/core/altium/SchematicComponentTextResolver.mjs +40 -1
  21. package/src/core/altium/SchematicDirectiveParser.mjs +5 -17
  22. package/src/core/altium/SchematicImageParser.mjs +291 -6
  23. package/src/core/altium/SchematicMultipartDesignatorNormalizer.mjs +164 -0
  24. package/src/core/altium/SchematicMultipartOwnerMatcher.mjs +2 -0
  25. package/src/core/altium/SchematicNoErcSymbolResolver.mjs +36 -0
  26. package/src/core/altium/SchematicPinParser.mjs +262 -24
  27. package/src/core/altium/SchematicPrimitiveParser.mjs +116 -8
  28. package/src/core/altium/SchematicSheetStyleResolver.mjs +38 -0
  29. package/src/core/altium/SchematicStreamExtractor.mjs +62 -15
  30. package/src/core/altium/SchematicTextParser.mjs +125 -11
  31. package/src/core/altium/SchematicTextPostProcessor.mjs +146 -102
  32. package/src/core/altium/SourceBundleExporter.mjs +156 -0
  33. package/src/core/altium/SourceComponentBundleNormalizer.mjs +295 -0
  34. package/src/core/altium/SourceComponentClient.mjs +239 -0
  35. package/src/core/ole/OleCompoundDocumentWriter.mjs +449 -0
  36. package/src/parser.mjs +8 -0
  37. package/src/styles/altium-renderers.css +6 -6
  38. package/src/ui/PcbArcUtils.mjs +19 -2
  39. package/src/ui/PcbScene3dBuilder.mjs +202 -20
  40. package/src/ui/PcbScene3dModelRegistry.mjs +28 -18
  41. package/src/ui/PcbScene3dPlacementSideResolver.mjs +48 -6
  42. package/src/ui/SchematicColorResolver.mjs +263 -0
  43. package/src/ui/SchematicContentLayout.mjs +58 -1
  44. package/src/ui/SchematicDirectiveRenderer.mjs +133 -22
  45. package/src/ui/SchematicImageRenderer.mjs +125 -10
  46. package/src/ui/SchematicJunctionRenderer.mjs +1 -1
  47. package/src/ui/SchematicLineColorResolver.mjs +88 -0
  48. package/src/ui/SchematicNativeFooterPartitioner.mjs +275 -0
  49. package/src/ui/SchematicNoteRenderer.mjs +87 -7
  50. package/src/ui/SchematicOwnerPinLabelLayout.mjs +560 -10
  51. package/src/ui/SchematicOwnerPinMarkerLineThemer.mjs +155 -0
  52. package/src/ui/SchematicPinSvgRenderer.mjs +397 -48
  53. package/src/ui/SchematicPowerDiagramImageProcessor.mjs +970 -0
  54. package/src/ui/SchematicPowerDiagramLineMasks.mjs +631 -0
  55. package/src/ui/SchematicPowerPortRenderer.mjs +1 -1
  56. package/src/ui/SchematicShapeRenderer.mjs +109 -24
  57. package/src/ui/SchematicSvgRenderer.mjs +1210 -71
@@ -8,6 +8,7 @@ import { SchematicTypography } from './SchematicTypography.mjs'
8
8
 
9
9
  const { escapeHtml, formatNumber, projectSchematicY } = SchematicSvgUtils
10
10
  const MINIMUM_NOTE_TEXT_SIZE = 4
11
+ const COMPACT_SINGLE_LINE_HEIGHT_RATIO = 1.6
11
12
 
12
13
  /**
13
14
  * Renders boxed schematic notes recovered from Altium note records.
@@ -15,7 +16,7 @@ const MINIMUM_NOTE_TEXT_SIZE = 4
15
16
  export class SchematicNoteRenderer {
16
17
  /**
17
18
  * Builds one boxed schematic note/callout with wrapped text rows.
18
- * @param {{ x: number, y: number, color: string, fontSize?: number, fontFamily?: string, fontWeight?: number, fontStyle?: string, cornerX?: number, cornerY?: number, fill?: string, borderColor?: string, lineWidth?: number, isSolid?: boolean, showBorder?: boolean, textMargin?: number, noteLines?: string[] }} text
19
+ * @param {{ x: number, y: number, color: string, fontSize?: number, fontFamily?: string, fontWeight?: number, fontStyle?: string, anchor?: 'start' | 'middle' | 'end', cornerX?: number, cornerY?: number, fill?: string, borderColor?: string, lineWidth?: number, isSolid?: boolean, showBorder?: boolean, textMargin?: number, noteLines?: string[] }} text
19
20
  * @param {number} sheetHeight
20
21
  * @returns {string}
21
22
  */
@@ -59,6 +60,10 @@ export class SchematicNoteRenderer {
59
60
  height,
60
61
  requestedTextSize
61
62
  )
63
+ const compactMarkerNote = SchematicNoteRenderer.#isCompactMarkerNote(
64
+ noteSourceLines,
65
+ compactSingleLineNote
66
+ )
62
67
  const horizontalTextMargin =
63
68
  SchematicNoteRenderer.#resolveHorizontalTextMargin(
64
69
  textMargin,
@@ -94,6 +99,7 @@ export class SchematicNoteRenderer {
94
99
  lineHeight,
95
100
  textSize,
96
101
  compactSingleLineNote,
102
+ compactMarkerNote,
97
103
  text
98
104
  )
99
105
  )
@@ -323,7 +329,10 @@ export class SchematicNoteRenderer {
323
329
  String(line || '').trim()
324
330
  ).length
325
331
 
326
- return visibleLineCount === 1 && height <= requestedTextSize * 1.5
332
+ return (
333
+ visibleLineCount === 1 &&
334
+ height <= requestedTextSize * COMPACT_SINGLE_LINE_HEIGHT_RATIO
335
+ )
327
336
  }
328
337
 
329
338
  /**
@@ -462,7 +471,8 @@ export class SchematicNoteRenderer {
462
471
  * @param {number} lineHeight
463
472
  * @param {number} textSize
464
473
  * @param {boolean} compactSingleLineNote
465
- * @param {{ color: string, fontFamily?: string, fontWeight?: number, fontStyle?: string }} text
474
+ * @param {boolean} compactMarkerNote
475
+ * @param {{ color: string, fontFamily?: string, fontWeight?: number, fontStyle?: string, anchor?: 'start' | 'middle' | 'end' }} text
466
476
  * @returns {string}
467
477
  */
468
478
  static #buildNoteLineMarkup(
@@ -476,9 +486,21 @@ export class SchematicNoteRenderer {
476
486
  lineHeight,
477
487
  textSize,
478
488
  compactSingleLineNote,
489
+ compactMarkerNote,
479
490
  text
480
491
  ) {
481
- const x = left + horizontalTextMargin
492
+ const anchor = SchematicNoteRenderer.#resolveTextAnchor(
493
+ text,
494
+ compactMarkerNote
495
+ )
496
+ const x = SchematicNoteRenderer.#resolveLineX(
497
+ left,
498
+ right,
499
+ horizontalTextMargin,
500
+ anchor
501
+ )
502
+ const ruleLeft = left + horizontalTextMargin
503
+ const ruleRight = right - horizontalTextMargin
482
504
  const y =
483
505
  top +
484
506
  verticalTextMargin +
@@ -491,11 +513,11 @@ export class SchematicNoteRenderer {
491
513
  if (/^_+$/.test(String(line || '').trim())) {
492
514
  return (
493
515
  '<line class="schematic-note-rule" x1="' +
494
- formatNumber(x) +
516
+ formatNumber(ruleLeft) +
495
517
  '" y1="' +
496
518
  formatNumber(y - textSize * 0.35) +
497
519
  '" x2="' +
498
- formatNumber(right - horizontalTextMargin) +
520
+ formatNumber(ruleRight) +
499
521
  '" y2="' +
500
522
  formatNumber(y - textSize * 0.35) +
501
523
  '" stroke="' +
@@ -521,7 +543,9 @@ export class SchematicNoteRenderer {
521
543
  '--schematic-text-color'
522
544
  )
523
545
  ) +
524
- '" text-anchor="start" font-size="' +
546
+ '" text-anchor="' +
547
+ escapeHtml(anchor) +
548
+ '" font-size="' +
525
549
  formatNumber(textSize) +
526
550
  '" font-family="' +
527
551
  escapeHtml(text.fontFamily || 'Times New Roman') +
@@ -534,6 +558,62 @@ export class SchematicNoteRenderer {
534
558
  )
535
559
  }
536
560
 
561
+ /**
562
+ * Resolves the x coordinate for a note line from its text anchor.
563
+ * @param {number} left Note box left edge.
564
+ * @param {number} right Note box right edge.
565
+ * @param {number} horizontalTextMargin Text margin.
566
+ * @param {'start' | 'middle' | 'end'} anchor Text anchor.
567
+ * @returns {number}
568
+ */
569
+ static #resolveLineX(left, right, horizontalTextMargin, anchor) {
570
+ if (anchor === 'middle') return (left + right) / 2
571
+ if (anchor === 'end') return right - horizontalTextMargin
572
+
573
+ return left + horizontalTextMargin
574
+ }
575
+
576
+ /**
577
+ * Returns true for tight single-token marker boxes that Altium centers
578
+ * inside the authored note rectangle.
579
+ * @param {string[]} noteLines Source note rows.
580
+ * @param {boolean} compactSingleLineNote True for tight one-line note boxes.
581
+ * @returns {boolean}
582
+ */
583
+ static #isCompactMarkerNote(noteLines, compactSingleLineNote) {
584
+ if (!compactSingleLineNote) {
585
+ return false
586
+ }
587
+
588
+ const visibleLines = noteLines
589
+ .map((line) => String(line || '').trim())
590
+ .filter(Boolean)
591
+
592
+ if (visibleLines.length !== 1) {
593
+ return false
594
+ }
595
+
596
+ return /^[A-Z0-9._/-]{1,4}$/u.test(visibleLines[0])
597
+ }
598
+
599
+ /**
600
+ * Normalizes note text anchors to SVG text-anchor values.
601
+ * @param {{ anchor?: string }} text Note text.
602
+ * @param {boolean} compactMarkerNote True for centered marker notes.
603
+ * @returns {'start' | 'middle' | 'end'}
604
+ */
605
+ static #resolveTextAnchor(text, compactMarkerNote) {
606
+ if (compactMarkerNote) {
607
+ return 'middle'
608
+ }
609
+
610
+ if (text.anchor === 'middle' || text.anchor === 'end') {
611
+ return text.anchor
612
+ }
613
+
614
+ return 'start'
615
+ }
616
+
537
617
  /**
538
618
  * Builds an optional note font-style attribute.
539
619
  * @param {string | undefined} fontStyle