altium-toolkit 1.0.9 → 1.1.0
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/docs/api.md +6 -2
- package/docs/model-format.md +29 -4
- package/docs/schemas/altium_toolkit/ci_artifact_bundle_a1.schema.json +80 -0
- package/docs/schemas/altium_toolkit/contract_gate_a1.schema.json +34 -0
- package/docs/schemas/altium_toolkit/draftsman_board_view_cache_a1.schema.json +115 -0
- package/docs/schemas/altium_toolkit/draftsman_digest_a1.schema.json +166 -0
- package/docs/schemas/altium_toolkit/host_capabilities_a1.schema.json +39 -0
- package/docs/schemas/altium_toolkit/library_merge_plan_a1.schema.json +56 -0
- package/docs/schemas/altium_toolkit/library_qa_a1.schema.json +70 -0
- package/docs/schemas/altium_toolkit/netlist_a1.schema.json +6 -0
- package/docs/schemas/altium_toolkit/normalized_model_a1.schema.json +856 -7
- package/docs/schemas/altium_toolkit/parser_compatibility_fuzz_a1.schema.json +25 -0
- package/docs/schemas/altium_toolkit/pcb_bom_profile_a1.schema.json +48 -0
- package/docs/schemas/altium_toolkit/pcb_layer_stack_a1.schema.json +98 -0
- package/docs/schemas/altium_toolkit/pcb_layer_stack_fidelity_a1.schema.json +66 -0
- package/docs/schemas/altium_toolkit/pcb_placed_footprint_extraction_a1.schema.json +31 -0
- package/docs/schemas/altium_toolkit/pcb_review_metadata_a1.schema.json +62 -0
- package/docs/schemas/altium_toolkit/pcb_rigid_flex_topology_a1.schema.json +52 -0
- package/docs/schemas/altium_toolkit/pcb_svg_semantics_a1.schema.json +27 -0
- package/docs/schemas/altium_toolkit/pcblib_parity_a1.schema.json +24 -0
- package/docs/schemas/altium_toolkit/project_bom_pnp_reconciliation_a1.schema.json +63 -0
- package/docs/schemas/altium_toolkit/project_bundle_a1.schema.json +6 -0
- package/docs/schemas/altium_toolkit/project_document_graph_a1.schema.json +33 -0
- package/docs/schemas/altium_toolkit/project_outjob_digest_a1.schema.json +46 -0
- package/docs/schemas/altium_toolkit/project_script_a1.schema.json +50 -0
- package/docs/schemas/altium_toolkit/schematic_render_ops_a1.schema.json +55 -0
- package/docs/schemas/altium_toolkit/schematic_template_extraction_a1.schema.json +37 -0
- package/docs/schemas/altium_toolkit/svg_model_cross_link_a1.schema.json +39 -0
- package/package.json +1 -1
- package/src/core/altium/AltiumParser.mjs +12 -2
- package/src/core/altium/CiArtifactBundleBuilder.mjs +213 -0
- package/src/core/altium/ContractGateReportBuilder.mjs +351 -0
- package/src/core/altium/DraftsmanBoardViewMetadataBuilder.mjs +653 -0
- package/src/core/altium/DraftsmanDigestParser.mjs +928 -0
- package/src/core/altium/DraftsmanImagePayloadManifestBuilder.mjs +178 -0
- package/src/core/altium/HostCapabilityDiagnosticsBuilder.mjs +271 -0
- package/src/core/altium/LibraryQaReportBuilder.mjs +504 -0
- package/src/core/altium/LibraryRenderManifestBuilder.mjs +172 -2
- package/src/core/altium/ParserCompatibilityFuzzer.mjs +192 -0
- package/src/core/altium/PcbBomProfileBuilder.mjs +263 -0
- package/src/core/altium/PcbComponentKindPolicy.mjs +146 -0
- package/src/core/altium/PcbLayerStackFidelityReportBuilder.mjs +141 -0
- package/src/core/altium/PcbLayerStackInterchangeParser.mjs +453 -0
- package/src/core/altium/PcbLayerStackQueryHelper.mjs +195 -0
- package/src/core/altium/PcbLayerStackReadModelBuilder.mjs +906 -0
- package/src/core/altium/PcbLayerStackSourceMetadataParser.mjs +488 -0
- package/src/core/altium/PcbLibModelParser.mjs +2 -0
- package/src/core/altium/PcbLibParityReportBuilder.mjs +242 -0
- package/src/core/altium/PcbModelParser.mjs +211 -22
- package/src/core/altium/PcbPadStackParser.mjs +171 -2
- package/src/core/altium/PcbPickPlacePositionResolver.mjs +11 -1
- package/src/core/altium/PcbPlacedFootprintManifestBuilder.mjs +338 -0
- package/src/core/altium/PcbPolygonRecordParser.mjs +120 -0
- package/src/core/altium/PcbRegionPrimitiveParser.mjs +71 -2
- package/src/core/altium/PcbReviewDrillMetadataBuilder.mjs +301 -0
- package/src/core/altium/PcbReviewMetadataBuilder.mjs +373 -0
- package/src/core/altium/PcbReviewPolygonRealizationBuilder.mjs +269 -0
- package/src/core/altium/PcbReviewRouteHighlightProfileBuilder.mjs +298 -0
- package/src/core/altium/PcbRigidFlexTopologyBuilder.mjs +171 -0
- package/src/core/altium/PcbRouteAnalysisBuilder.mjs +730 -0
- package/src/core/altium/PcbStatisticsBuilder.mjs +9 -0
- package/src/core/altium/PrintableTextDecoder.mjs +70 -6
- package/src/core/altium/PrjPcbModelParser.mjs +69 -2
- package/src/core/altium/PrjScrModelParser.mjs +386 -0
- package/src/core/altium/ProjectBomPnpReconciliationBuilder.mjs +237 -0
- package/src/core/altium/ProjectDesignBundleBuilder.mjs +76 -2
- package/src/core/altium/ProjectDocumentGraphBuilder.mjs +280 -0
- package/src/core/altium/ProjectNetlistExporter.mjs +5 -1
- package/src/core/altium/ProjectOutJobDigestBuilder.mjs +424 -13
- package/src/core/altium/SvgModelCrossLinkValidator.mjs +435 -0
- package/src/core/circuit-json/CircuitJsonModelAdapter.mjs +300 -96
- package/src/core/circuit-json/CircuitJsonModelAdapterPcbElements.mjs +244 -0
- package/src/core/circuit-json/CircuitJsonModelSchema.mjs +1 -1
- package/src/parser.mjs +21 -0
- package/src/ui/PcbFootprintPrimitiveSelector.mjs +13 -1
- package/src/ui/PcbScene3dBuilder.mjs +26 -4
- package/src/ui/PcbSvgRenderer.mjs +65 -0
- package/src/ui/SchematicRenderOpsSidecarBuilder.mjs +554 -0
- package/src/ui/SchematicSvgRenderer.mjs +48 -2
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
// SPDX-FileCopyrightText: 2026 André Fiedler
|
|
2
|
+
//
|
|
3
|
+
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
4
|
+
|
|
5
|
+
import { CircuitJsonModelAdapterPrimitives } from './CircuitJsonModelAdapterPrimitives.mjs'
|
|
6
|
+
|
|
7
|
+
const Primitives = CircuitJsonModelAdapterPrimitives
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Builds upstream-compatible Circuit JSON PCB element records.
|
|
11
|
+
*/
|
|
12
|
+
export class CircuitJsonModelAdapterPcbElements {
|
|
13
|
+
/**
|
|
14
|
+
* Builds an upstream-compatible SMT pad element.
|
|
15
|
+
* @param {string} idScope
|
|
16
|
+
* @param {Record<string, unknown>} pad
|
|
17
|
+
* @param {number} padIndex
|
|
18
|
+
* @param {string} pcbComponentId
|
|
19
|
+
* @param {string} pcbPortId
|
|
20
|
+
* @param {{ x: number, y: number }} center
|
|
21
|
+
* @param {string} layer
|
|
22
|
+
* @param {string[]} portHints
|
|
23
|
+
* @returns {object}
|
|
24
|
+
*/
|
|
25
|
+
static smtPad(
|
|
26
|
+
idScope,
|
|
27
|
+
pad,
|
|
28
|
+
padIndex,
|
|
29
|
+
pcbComponentId,
|
|
30
|
+
pcbPortId,
|
|
31
|
+
center,
|
|
32
|
+
layer,
|
|
33
|
+
portHints
|
|
34
|
+
) {
|
|
35
|
+
const shape = Primitives.padShape(pad)
|
|
36
|
+
const width = Primitives.milNumber(
|
|
37
|
+
pad.sizeTopX || pad.sizeX || pad.width,
|
|
38
|
+
0
|
|
39
|
+
)
|
|
40
|
+
const height = Primitives.milNumber(
|
|
41
|
+
pad.sizeTopY || pad.sizeY || pad.height,
|
|
42
|
+
0
|
|
43
|
+
)
|
|
44
|
+
const rotation = Primitives.number(pad.rotation || pad.holeRotation, 0)
|
|
45
|
+
const base = {
|
|
46
|
+
type: 'pcb_smtpad',
|
|
47
|
+
pcb_smtpad_id: Primitives.id(idScope, ['pcb_smtpad', padIndex]),
|
|
48
|
+
pcb_component_id: pcbComponentId,
|
|
49
|
+
pcb_port_id: pcbPortId,
|
|
50
|
+
x: center.x,
|
|
51
|
+
y: center.y,
|
|
52
|
+
layer,
|
|
53
|
+
port_hints: portHints
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (shape === 'circle') {
|
|
57
|
+
return {
|
|
58
|
+
...base,
|
|
59
|
+
shape,
|
|
60
|
+
radius: Primitives.round(Math.max(width, height) / 2)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (shape === 'pill') {
|
|
65
|
+
return {
|
|
66
|
+
...base,
|
|
67
|
+
shape: CircuitJsonModelAdapterPcbElements.#hasRotation(rotation)
|
|
68
|
+
? 'rotated_pill'
|
|
69
|
+
: 'pill',
|
|
70
|
+
width,
|
|
71
|
+
height,
|
|
72
|
+
radius: Primitives.round(Math.min(width, height) / 2),
|
|
73
|
+
...CircuitJsonModelAdapterPcbElements.#ccwRotationField(
|
|
74
|
+
rotation
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
return {
|
|
80
|
+
...base,
|
|
81
|
+
shape: CircuitJsonModelAdapterPcbElements.#hasRotation(rotation)
|
|
82
|
+
? 'rotated_rect'
|
|
83
|
+
: 'rect',
|
|
84
|
+
width,
|
|
85
|
+
height,
|
|
86
|
+
...CircuitJsonModelAdapterPcbElements.#ccwRotationField(rotation)
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Builds an upstream-compatible non-plated hole element.
|
|
92
|
+
* @param {string} idScope
|
|
93
|
+
* @param {Record<string, unknown>} pad
|
|
94
|
+
* @param {number} padIndex
|
|
95
|
+
* @param {string} pcbComponentId
|
|
96
|
+
* @param {{ x: number, y: number }} center
|
|
97
|
+
* @returns {object}
|
|
98
|
+
*/
|
|
99
|
+
static hole(idScope, pad, padIndex, pcbComponentId, center) {
|
|
100
|
+
const shape = Primitives.padShape(pad)
|
|
101
|
+
const width = Primitives.milNumber(
|
|
102
|
+
pad.sizeTopX || pad.sizeX || pad.width || pad.diameter,
|
|
103
|
+
0
|
|
104
|
+
)
|
|
105
|
+
const height = Primitives.milNumber(
|
|
106
|
+
pad.sizeTopY || pad.sizeY || pad.height || pad.diameter,
|
|
107
|
+
0
|
|
108
|
+
)
|
|
109
|
+
const holeDiameter = Primitives.milNumber(pad.holeDiameter, 0)
|
|
110
|
+
const base = {
|
|
111
|
+
type: 'pcb_hole',
|
|
112
|
+
pcb_hole_id: Primitives.id(idScope, ['pcb_hole', padIndex]),
|
|
113
|
+
pcb_component_id: pcbComponentId,
|
|
114
|
+
x: center.x,
|
|
115
|
+
y: center.y
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (shape === 'circle') {
|
|
119
|
+
return {
|
|
120
|
+
...base,
|
|
121
|
+
hole_shape: 'circle',
|
|
122
|
+
hole_diameter: holeDiameter
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
return {
|
|
127
|
+
...base,
|
|
128
|
+
hole_shape: shape === 'pill' ? 'pill' : 'rect',
|
|
129
|
+
hole_width: holeDiameter || width,
|
|
130
|
+
hole_height: holeDiameter || height
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Builds an upstream-compatible plated hole element.
|
|
136
|
+
* @param {string} idScope
|
|
137
|
+
* @param {Record<string, unknown>} pad
|
|
138
|
+
* @param {number} padIndex
|
|
139
|
+
* @param {string} pcbComponentId
|
|
140
|
+
* @param {string} pcbPortId
|
|
141
|
+
* @param {{ x: number, y: number }} center
|
|
142
|
+
* @param {string[]} portHints
|
|
143
|
+
* @returns {object}
|
|
144
|
+
*/
|
|
145
|
+
static platedHole(
|
|
146
|
+
idScope,
|
|
147
|
+
pad,
|
|
148
|
+
padIndex,
|
|
149
|
+
pcbComponentId,
|
|
150
|
+
pcbPortId,
|
|
151
|
+
center,
|
|
152
|
+
portHints
|
|
153
|
+
) {
|
|
154
|
+
const shape = Primitives.padShape(pad)
|
|
155
|
+
const width = Primitives.milNumber(
|
|
156
|
+
pad.sizeTopX || pad.sizeX || pad.width || pad.diameter,
|
|
157
|
+
0
|
|
158
|
+
)
|
|
159
|
+
const height = Primitives.milNumber(
|
|
160
|
+
pad.sizeTopY || pad.sizeY || pad.height || pad.diameter,
|
|
161
|
+
0
|
|
162
|
+
)
|
|
163
|
+
const holeDiameter = Primitives.milNumber(pad.holeDiameter, 0)
|
|
164
|
+
const rotation = Primitives.number(pad.rotation || pad.holeRotation, 0)
|
|
165
|
+
const base = {
|
|
166
|
+
type: 'pcb_plated_hole',
|
|
167
|
+
pcb_plated_hole_id: Primitives.id(idScope, [
|
|
168
|
+
'pcb_plated_hole',
|
|
169
|
+
padIndex
|
|
170
|
+
]),
|
|
171
|
+
pcb_component_id: pcbComponentId,
|
|
172
|
+
pcb_port_id: pcbPortId,
|
|
173
|
+
x: center.x,
|
|
174
|
+
y: center.y,
|
|
175
|
+
layers: ['top', 'bottom'],
|
|
176
|
+
port_hints: portHints
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
if (shape === 'circle') {
|
|
180
|
+
return {
|
|
181
|
+
...base,
|
|
182
|
+
shape,
|
|
183
|
+
outer_diameter: Primitives.round(Math.max(width, height)),
|
|
184
|
+
hole_diameter: holeDiameter
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (shape === 'pill') {
|
|
189
|
+
return {
|
|
190
|
+
...base,
|
|
191
|
+
shape,
|
|
192
|
+
outer_width: width,
|
|
193
|
+
outer_height: height,
|
|
194
|
+
hole_width: holeDiameter,
|
|
195
|
+
hole_height: holeDiameter,
|
|
196
|
+
ccw_rotation: rotation
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return {
|
|
201
|
+
...base,
|
|
202
|
+
shape: 'circular_hole_with_rect_pad',
|
|
203
|
+
hole_shape: 'circle',
|
|
204
|
+
pad_shape: 'rect',
|
|
205
|
+
hole_diameter: holeDiameter,
|
|
206
|
+
rect_pad_width: width,
|
|
207
|
+
rect_pad_height: height,
|
|
208
|
+
...CircuitJsonModelAdapterPcbElements.#rectCcwRotationField(
|
|
209
|
+
rotation
|
|
210
|
+
)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Returns true when a rotation value should use a rotated pad shape.
|
|
216
|
+
* @param {number | null} rotation
|
|
217
|
+
* @returns {boolean}
|
|
218
|
+
*/
|
|
219
|
+
static #hasRotation(rotation) {
|
|
220
|
+
return Math.abs(rotation || 0) > 0.000001
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Returns an optional counter-clockwise rotation field.
|
|
225
|
+
* @param {number | null} rotation
|
|
226
|
+
* @returns {{ ccw_rotation?: number }}
|
|
227
|
+
*/
|
|
228
|
+
static #ccwRotationField(rotation) {
|
|
229
|
+
return CircuitJsonModelAdapterPcbElements.#hasRotation(rotation)
|
|
230
|
+
? { ccw_rotation: rotation || 0 }
|
|
231
|
+
: {}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Returns an optional rectangular pad rotation field.
|
|
236
|
+
* @param {number | null} rotation
|
|
237
|
+
* @returns {{ rect_ccw_rotation?: number }}
|
|
238
|
+
*/
|
|
239
|
+
static #rectCcwRotationField(rotation) {
|
|
240
|
+
return CircuitJsonModelAdapterPcbElements.#hasRotation(rotation)
|
|
241
|
+
? { rect_ccw_rotation: rotation || 0 }
|
|
242
|
+
: {}
|
|
243
|
+
}
|
|
244
|
+
}
|
package/src/parser.mjs
CHANGED
|
@@ -9,21 +9,31 @@ export { OleDirectoryEntry } from './core/ole/OleDirectoryEntry.mjs'
|
|
|
9
9
|
export { AltiumParser } from './core/altium/AltiumParser.mjs'
|
|
10
10
|
export { AltiumLayoutParser } from './core/altium/AltiumLayoutParser.mjs'
|
|
11
11
|
export { AsciiRecordParser } from './core/altium/AsciiRecordParser.mjs'
|
|
12
|
+
export { HostCapabilityDiagnosticsBuilder } from './core/altium/HostCapabilityDiagnosticsBuilder.mjs'
|
|
12
13
|
export { IntLibModelParser } from './core/altium/IntLibModelParser.mjs'
|
|
13
14
|
export { IntLibStreamExtractor } from './core/altium/IntLibStreamExtractor.mjs'
|
|
14
15
|
export { EmbeddedFileInventoryBuilder } from './core/altium/EmbeddedFileInventoryBuilder.mjs'
|
|
16
|
+
export { CiArtifactBundleBuilder } from './core/altium/CiArtifactBundleBuilder.mjs'
|
|
17
|
+
export { ContractGateReportBuilder } from './core/altium/ContractGateReportBuilder.mjs'
|
|
18
|
+
export { DraftsmanBoardViewMetadataBuilder } from './core/altium/DraftsmanBoardViewMetadataBuilder.mjs'
|
|
19
|
+
export { DraftsmanDigestParser } from './core/altium/DraftsmanDigestParser.mjs'
|
|
15
20
|
export { LibraryRenderManifestBuilder } from './core/altium/LibraryRenderManifestBuilder.mjs'
|
|
21
|
+
export { LibraryQaReportBuilder } from './core/altium/LibraryQaReportBuilder.mjs'
|
|
16
22
|
export { LibrarySearchIndex } from './core/altium/LibrarySearchIndex.mjs'
|
|
17
23
|
export { ParserUtils } from './core/altium/ParserUtils.mjs'
|
|
24
|
+
export { ParserCompatibilityFuzzer } from './core/altium/ParserCompatibilityFuzzer.mjs'
|
|
18
25
|
export { NormalizedModelSchema } from './core/altium/NormalizedModelSchema.mjs'
|
|
19
26
|
export { ProjectDesignBundleBuilder } from './core/altium/ProjectDesignBundleBuilder.mjs'
|
|
27
|
+
export { ProjectDocumentGraphBuilder } from './core/altium/ProjectDocumentGraphBuilder.mjs'
|
|
20
28
|
export { ProjectAnnotationParser } from './core/altium/ProjectAnnotationParser.mjs'
|
|
21
29
|
export { ProjectNetlistExporter } from './core/altium/ProjectNetlistExporter.mjs'
|
|
22
30
|
export { ProjectVariantViewBuilder } from './core/altium/ProjectVariantViewBuilder.mjs'
|
|
23
31
|
export { CircuitJsonModelSchema } from './core/circuit-json/CircuitJsonModelSchema.mjs'
|
|
24
32
|
export { CircuitJsonModelAdapter } from './core/circuit-json/CircuitJsonModelAdapter.mjs'
|
|
25
33
|
export { PcbBinaryPrimitiveParser } from './core/altium/PcbBinaryPrimitiveParser.mjs'
|
|
34
|
+
export { PcbBomProfileBuilder } from './core/altium/PcbBomProfileBuilder.mjs'
|
|
26
35
|
export { PcbBoardRegionSemanticsParser } from './core/altium/PcbBoardRegionSemanticsParser.mjs'
|
|
36
|
+
export { PcbComponentKindPolicy } from './core/altium/PcbComponentKindPolicy.mjs'
|
|
27
37
|
export { PcbComponentPrimitiveIndexer } from './core/altium/PcbComponentPrimitiveIndexer.mjs'
|
|
28
38
|
export { PcbCustomPadShapeParser } from './core/altium/PcbCustomPadShapeParser.mjs'
|
|
29
39
|
export { PcbDimensionParser } from './core/altium/PcbDimensionParser.mjs'
|
|
@@ -32,7 +42,11 @@ export { PcbEmbeddedModelExtractor } from './core/altium/PcbEmbeddedModelExtract
|
|
|
32
42
|
export { PcbExtendedPrimitiveInformationParser } from './core/altium/PcbExtendedPrimitiveInformationParser.mjs'
|
|
33
43
|
export { PcbFontMetricsParser } from './core/altium/PcbFontMetricsParser.mjs'
|
|
34
44
|
export { PcbLayerIdCodec } from './core/altium/PcbLayerIdCodec.mjs'
|
|
45
|
+
export { PcbLayerStackFidelityReportBuilder } from './core/altium/PcbLayerStackFidelityReportBuilder.mjs'
|
|
46
|
+
export { PcbLayerStackInterchangeParser } from './core/altium/PcbLayerStackInterchangeParser.mjs'
|
|
47
|
+
export { PcbLayerStackQueryHelper } from './core/altium/PcbLayerStackQueryHelper.mjs'
|
|
35
48
|
export { PcbLibModelParser } from './core/altium/PcbLibModelParser.mjs'
|
|
49
|
+
export { PcbLibParityReportBuilder } from './core/altium/PcbLibParityReportBuilder.mjs'
|
|
36
50
|
export { PcbLibStreamExtractor } from './core/altium/PcbLibStreamExtractor.mjs'
|
|
37
51
|
export { PcbMechanicalLayerPairParser } from './core/altium/PcbMechanicalLayerPairParser.mjs'
|
|
38
52
|
export { PcbModelParser } from './core/altium/PcbModelParser.mjs'
|
|
@@ -40,8 +54,12 @@ export { PcbOutlineRasterizer } from './core/altium/PcbOutlineRasterizer.mjs'
|
|
|
40
54
|
export { PcbOutlineRecovery } from './core/altium/PcbOutlineRecovery.mjs'
|
|
41
55
|
export { PcbOwnershipGraphBuilder } from './core/altium/PcbOwnershipGraphBuilder.mjs'
|
|
42
56
|
export { PcbPadStackParser } from './core/altium/PcbPadStackParser.mjs'
|
|
57
|
+
export { PcbPlacedFootprintManifestBuilder } from './core/altium/PcbPlacedFootprintManifestBuilder.mjs'
|
|
43
58
|
export { PcbPickPlacePositionResolver } from './core/altium/PcbPickPlacePositionResolver.mjs'
|
|
59
|
+
export { PcbPolygonRecordParser } from './core/altium/PcbPolygonRecordParser.mjs'
|
|
44
60
|
export { PcbRawRecordRegistry } from './core/altium/PcbRawRecordRegistry.mjs'
|
|
61
|
+
export { PcbReviewMetadataBuilder } from './core/altium/PcbReviewMetadataBuilder.mjs'
|
|
62
|
+
export { PcbRouteAnalysisBuilder } from './core/altium/PcbRouteAnalysisBuilder.mjs'
|
|
45
63
|
export { PcbRuleParser } from './core/altium/PcbRuleParser.mjs'
|
|
46
64
|
export { PcbSidecarRecordParser } from './core/altium/PcbSidecarRecordParser.mjs'
|
|
47
65
|
export { PcbSpecialStringResolver } from './core/altium/PcbSpecialStringResolver.mjs'
|
|
@@ -52,6 +70,8 @@ export { PcbViaStackParser } from './core/altium/PcbViaStackParser.mjs'
|
|
|
52
70
|
export { PcbViaStructureParser } from './core/altium/PcbViaStructureParser.mjs'
|
|
53
71
|
export { PrintableTextDecoder } from './core/altium/PrintableTextDecoder.mjs'
|
|
54
72
|
export { PrjPcbModelParser } from './core/altium/PrjPcbModelParser.mjs'
|
|
73
|
+
export { PrjScrModelParser } from './core/altium/PrjScrModelParser.mjs'
|
|
74
|
+
export { ProjectBomPnpReconciliationBuilder } from './core/altium/ProjectBomPnpReconciliationBuilder.mjs'
|
|
55
75
|
export { SchematicMultipartOwnerMatcher } from './core/altium/SchematicMultipartOwnerMatcher.mjs'
|
|
56
76
|
export { SchematicCrossSheetConnectorParser } from './core/altium/SchematicCrossSheetConnectorParser.mjs'
|
|
57
77
|
export { SchematicHarnessParser } from './core/altium/SchematicHarnessParser.mjs'
|
|
@@ -63,3 +83,4 @@ export { SchematicRecordTypeRegistry } from './core/altium/SchematicRecordTypeRe
|
|
|
63
83
|
export { SchematicRepeatedChannelParser } from './core/altium/SchematicRepeatedChannelParser.mjs'
|
|
64
84
|
export { SchematicTemplateParser } from './core/altium/SchematicTemplateParser.mjs'
|
|
65
85
|
export { SchematicStandaloneCalloutNormalizer } from './core/altium/SchematicStandaloneCalloutNormalizer.mjs'
|
|
86
|
+
export { SvgModelCrossLinkValidator } from './core/altium/SvgModelCrossLinkValidator.mjs'
|
|
@@ -141,9 +141,21 @@ export class PcbFootprintPrimitiveSelector {
|
|
|
141
141
|
* @returns {boolean}
|
|
142
142
|
*/
|
|
143
143
|
static #includesLayerName(layerName, needle) {
|
|
144
|
+
return PcbFootprintPrimitiveSelector.#compactLayerName(
|
|
145
|
+
layerName
|
|
146
|
+
).includes(PcbFootprintPrimitiveSelector.#compactLayerName(needle))
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Normalizes layer labels so compact names such as TopOverlay match
|
|
151
|
+
* spaced Altium labels such as Top Overlay.
|
|
152
|
+
* @param {string} layerName
|
|
153
|
+
* @returns {string}
|
|
154
|
+
*/
|
|
155
|
+
static #compactLayerName(layerName) {
|
|
144
156
|
return String(layerName || '')
|
|
145
157
|
.trim()
|
|
146
158
|
.toUpperCase()
|
|
147
|
-
.
|
|
159
|
+
.replace(/[^A-Z0-9]/g, '')
|
|
148
160
|
}
|
|
149
161
|
}
|
|
@@ -986,16 +986,38 @@ export class PcbScene3dBuilder {
|
|
|
986
986
|
return new Set(
|
|
987
987
|
(Array.isArray(primitiveLayers) ? primitiveLayers : [])
|
|
988
988
|
.filter((layer) =>
|
|
989
|
-
|
|
990
|
-
.trim()
|
|
991
|
-
.toUpperCase()
|
|
992
|
-
.includes(needle)
|
|
989
|
+
PcbScene3dBuilder.#includesLayerName(layer?.name, needle)
|
|
993
990
|
)
|
|
994
991
|
.map((layer) => Number(layer.layerId))
|
|
995
992
|
.filter((layerId) => Number.isInteger(layerId))
|
|
996
993
|
)
|
|
997
994
|
}
|
|
998
995
|
|
|
996
|
+
/**
|
|
997
|
+
* Returns true when one layer name matches a spaced or compact target.
|
|
998
|
+
* @param {string} layerName
|
|
999
|
+
* @param {string} needle
|
|
1000
|
+
* @returns {boolean}
|
|
1001
|
+
*/
|
|
1002
|
+
static #includesLayerName(layerName, needle) {
|
|
1003
|
+
return PcbScene3dBuilder.#compactLayerName(layerName).includes(
|
|
1004
|
+
PcbScene3dBuilder.#compactLayerName(needle)
|
|
1005
|
+
)
|
|
1006
|
+
}
|
|
1007
|
+
|
|
1008
|
+
/**
|
|
1009
|
+
* Normalizes layer labels so compact names such as TopOverlay match
|
|
1010
|
+
* spaced Altium labels such as Top Overlay.
|
|
1011
|
+
* @param {string} layerName
|
|
1012
|
+
* @returns {string}
|
|
1013
|
+
*/
|
|
1014
|
+
static #compactLayerName(layerName) {
|
|
1015
|
+
return String(layerName || '')
|
|
1016
|
+
.trim()
|
|
1017
|
+
.toUpperCase()
|
|
1018
|
+
.replace(/[^A-Z0-9]/g, '')
|
|
1019
|
+
}
|
|
1020
|
+
|
|
999
1021
|
/**
|
|
1000
1022
|
* Normalizes one Altium overlay text into the runtime stroke-text shape.
|
|
1001
1023
|
* @param {{ text?: string, value?: string, x?: number, y?: number, height?: number, strokeWidth?: number, rotation?: number, mirrored?: boolean | number | string, isMirrored?: boolean | number | string, mirrorFlag?: boolean | number | string, Mirrored?: boolean | number | string, IsMirrored?: boolean | number | string, MirrorFlag?: boolean | number | string, layerId?: number }} text
|
|
@@ -829,6 +829,7 @@ export class PcbSvgRenderer {
|
|
|
829
829
|
return {
|
|
830
830
|
schema: PcbSvgRenderer.#SEMANTIC_SCHEMA,
|
|
831
831
|
view: PcbSvgRenderer.#buildViewMetadata(pcb, semanticContext),
|
|
832
|
+
lookups: PcbSvgRenderer.#buildSemanticLookups(pcb, semanticContext),
|
|
832
833
|
boardOutline: {
|
|
833
834
|
feature: 'board-outline',
|
|
834
835
|
elementKeys: ['pcb-board-outline', 'pcb-board-outline-stroke']
|
|
@@ -887,6 +888,70 @@ export class PcbSvgRenderer {
|
|
|
887
888
|
}
|
|
888
889
|
}
|
|
889
890
|
|
|
891
|
+
/**
|
|
892
|
+
* Builds stable lookup maps for semantic SVG consumers.
|
|
893
|
+
* @param {object} pcb Normalized PCB model.
|
|
894
|
+
* @param {object} semanticContext Semantic lookup context.
|
|
895
|
+
* @returns {object}
|
|
896
|
+
*/
|
|
897
|
+
static #buildSemanticLookups(pcb, semanticContext) {
|
|
898
|
+
const netsByIndex = {}
|
|
899
|
+
const netIndexByName = {}
|
|
900
|
+
const netClassesByName = {}
|
|
901
|
+
const componentsByIndex = {}
|
|
902
|
+
const componentIndexByDesignator = {}
|
|
903
|
+
const layersByKey = {}
|
|
904
|
+
const layerKeyByDisplayName = {}
|
|
905
|
+
|
|
906
|
+
for (const net of pcb?.nets || []) {
|
|
907
|
+
const netIndex = Number(net?.netIndex)
|
|
908
|
+
if (Number.isInteger(netIndex) && net?.name) {
|
|
909
|
+
netsByIndex[netIndex] = net.name
|
|
910
|
+
netIndexByName[net.name] = netIndex
|
|
911
|
+
}
|
|
912
|
+
}
|
|
913
|
+
|
|
914
|
+
for (const [
|
|
915
|
+
netName,
|
|
916
|
+
classNames
|
|
917
|
+
] of semanticContext.netClassNamesByNetName) {
|
|
918
|
+
netClassesByName[netName] = [...classNames].sort((left, right) =>
|
|
919
|
+
left.localeCompare(right, undefined, { numeric: true })
|
|
920
|
+
)
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
for (const [
|
|
924
|
+
componentIndex,
|
|
925
|
+
component
|
|
926
|
+
] of semanticContext.componentsByIndex) {
|
|
927
|
+
componentsByIndex[componentIndex] =
|
|
928
|
+
PcbSvgRenderer.#stripEmptySemanticObject({
|
|
929
|
+
designator: component.designator,
|
|
930
|
+
uniqueId: component.uniqueId,
|
|
931
|
+
pattern: component.pattern
|
|
932
|
+
})
|
|
933
|
+
if (component.designator) {
|
|
934
|
+
componentIndexByDesignator[component.designator] =
|
|
935
|
+
componentIndex
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
for (const layer of semanticContext.layerDescriptors) {
|
|
940
|
+
layersByKey[layer.layerKey] = layer
|
|
941
|
+
layerKeyByDisplayName[layer.displayName] = layer.layerKey
|
|
942
|
+
}
|
|
943
|
+
|
|
944
|
+
return {
|
|
945
|
+
netsByIndex,
|
|
946
|
+
netIndexByName,
|
|
947
|
+
netClassesByName,
|
|
948
|
+
componentsByIndex,
|
|
949
|
+
componentIndexByDesignator,
|
|
950
|
+
layersByKey,
|
|
951
|
+
layerKeyByDisplayName
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
|
|
890
955
|
/**
|
|
891
956
|
* Builds metadata for the rendered PCB view.
|
|
892
957
|
* @param {object} pcb Normalized PCB model.
|