pcb-scene3d-viewer 1.2.2 → 1.3.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/README.md +7 -0
- package/docs/api.md +18 -0
- package/docs/circuitjson.md +6 -4
- package/docs/release-notes-v1.3.0.md +38 -0
- package/package.json +3 -2
- package/src/CircuitJsonCadModelAssetResolver.mjs +24 -10
- package/src/PcbAssemblyGltfModelMeshParser.mjs +3 -1
- package/src/PcbAssemblyModelMeshLoader.mjs +1 -1
- package/src/PcbAssemblyTextModelMeshParser.mjs +3 -1
- package/src/PcbScene3dBoardAssemblyPresentation.mjs +1 -11
- package/src/PcbScene3dBoardMaterialPalette.mjs +12 -0
- package/src/PcbScene3dCircuitJsonAdapter.mjs +33 -85
- package/src/PcbScene3dCircuitJsonCopperTextBuilder.mjs +385 -0
- package/src/PcbScene3dCircuitJsonDocumentationArtworkBuilder.mjs +123 -22
- package/src/PcbScene3dCircuitJsonGeometry.mjs +12 -0
- package/src/PcbScene3dCircuitJsonPadCorner.mjs +72 -0
- package/src/PcbScene3dCircuitJsonSilkscreenBuilder.mjs +140 -25
- package/src/PcbScene3dCircuitJsonSilkscreenDetailBuilder.mjs +21 -0
- package/src/PcbScene3dCircuitJsonSourceLayer.mjs +124 -0
- package/src/PcbScene3dCircuitJsonTraceRouteBuilder.mjs +6 -7
- package/src/PcbScene3dCopperDetailFilter.mjs +5 -1
- package/src/PcbScene3dCopperFactory.mjs +23 -4
- package/src/PcbScene3dCopperTextFactory.mjs +105 -20
- package/src/PcbScene3dExternalModels.mjs +26 -0
- package/src/PcbScene3dMaskCoveredCopperSideGroupBuilder.mjs +16 -1
- package/src/PcbScene3dModelContent.mjs +32 -1
- package/src/PcbScene3dRuntimeBoardMeshes.mjs +2 -4
- package/src/PcbScene3dSilkscreenCopperCutoutBuilder.mjs +588 -0
- package/src/PcbScene3dStepLoader.mjs +2 -1
- package/src/PcbScene3dStrokeCutoutBuilder.mjs +98 -0
- package/src/PcbScene3dViaFactory.mjs +51 -5
- package/src/PcbScene3dViaLayerSpan.mjs +126 -0
package/README.md
CHANGED
|
@@ -22,6 +22,12 @@ factories, model loading, component picking, view presets, archive export,
|
|
|
22
22
|
GLTF/GLB assembly writing, and optional DOM shell can be reused by other
|
|
23
23
|
browser-based ECAD tools.
|
|
24
24
|
|
|
25
|
+
Version 1.3.0 renders the CircuitJSON 1.2 fidelity contract directly: exact
|
|
26
|
+
oval and rounded pads, filled and mirrored silkscreen, copper text and cutouts,
|
|
27
|
+
surface-aware blind/buried vias, collision-safe model assets, and a consistent
|
|
28
|
+
light FR-4 substrate edge. See the
|
|
29
|
+
[1.3.0 release notes](docs/release-notes-v1.3.0.md).
|
|
30
|
+
|
|
25
31
|
## CircuitJSON 1.1 convergence
|
|
26
32
|
|
|
27
33
|
Version 1.2.2 accepts the common document and prepared-context shapes returned
|
|
@@ -131,6 +137,7 @@ const controller = new PcbScene3dController(viewportNode, document)
|
|
|
131
137
|
- [API](docs/api.md)
|
|
132
138
|
- [CircuitJSON usage](docs/circuitjson.md)
|
|
133
139
|
- [1.2.2 release notes](docs/release-notes-v1.2.2.md)
|
|
140
|
+
- [1.3.0 release notes](docs/release-notes-v1.3.0.md)
|
|
134
141
|
- [1.2.1 release notes](docs/release-notes-v1.2.1.md)
|
|
135
142
|
- [1.2.0 release notes](docs/release-notes-v1.2.0.md)
|
|
136
143
|
- [Model format](docs/model-format.md)
|
package/docs/api.md
CHANGED
|
@@ -68,6 +68,24 @@ controller only and are forwarded to the runtime through
|
|
|
68
68
|
|
|
69
69
|
## CircuitJSON Input
|
|
70
70
|
|
|
71
|
+
### `PcbScene3dBoardMaterialPalette`
|
|
72
|
+
|
|
73
|
+
The `pcb-scene3d-viewer/scene3d` subpath exports the shared board-material
|
|
74
|
+
resolver used by both runtime meshes and assembly export.
|
|
75
|
+
|
|
76
|
+
- `resolveSurfaceColor(board, options?)` returns the authored or fallback
|
|
77
|
+
solder-mask face color.
|
|
78
|
+
- `resolveBoardSurfaceColor(board, options?)` returns the display-darkened
|
|
79
|
+
solder-mask face color.
|
|
80
|
+
- `resolveEdgeColor(board)` returns an authored `edgeColor` or the light FR-4
|
|
81
|
+
substrate fallback `0xc9ca78`.
|
|
82
|
+
- `isGeneratedSurfaceVisible(options?)` and
|
|
83
|
+
`isGeneratedBodyVisible(options?)` expose the generated-board visibility
|
|
84
|
+
decision.
|
|
85
|
+
|
|
86
|
+
Runtime and exported board edges call the same resolver, so a missing edge
|
|
87
|
+
color cannot produce different substrate materials in the two paths.
|
|
88
|
+
|
|
71
89
|
### `PcbScene3dCircuitJsonAdapter`
|
|
72
90
|
|
|
73
91
|
Converts a common CircuitJSON `DocumentResult`, prepared
|
package/docs/circuitjson.md
CHANGED
|
@@ -430,10 +430,12 @@ explicit false value exposes the copper:
|
|
|
430
430
|
}
|
|
431
431
|
```
|
|
432
432
|
|
|
433
|
-
Silkscreen text
|
|
434
|
-
`y`.
|
|
435
|
-
`
|
|
436
|
-
|
|
433
|
+
Silkscreen and copper text use `anchor_position` when available, falling back
|
|
434
|
+
to `x` and `y`. Independent `font_width` and `font_height`, `stroke_width`,
|
|
435
|
+
`source_anchor_alignment`, source layer/type provenance, mirroring, and hidden
|
|
436
|
+
state are honored when present. Filled silkscreen shapes retain their fill and
|
|
437
|
+
drill/copper cutouts, and bottom-side artwork is mirrored around its authored
|
|
438
|
+
anchor instead of being repositioned as top-side text.
|
|
437
439
|
|
|
438
440
|
Component model metadata can be supplied on `cad_component` elements with
|
|
439
441
|
`model_3mf_url`, `model_step_url`, `model_wrl_url`, `model_glb_url`,
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# pcb-scene3d-viewer 1.3.0
|
|
2
|
+
|
|
3
|
+
This minor release consumes CircuitJSON Toolkit 1.2 directly and restores exact
|
|
4
|
+
PCB surface fidelity without source-format or host-app adapters.
|
|
5
|
+
|
|
6
|
+
## Rendering and API changes
|
|
7
|
+
|
|
8
|
+
- Oval, rounded-rectangle, pill, polygon, and independently rotated drilled
|
|
9
|
+
pads keep their authored copper and drill geometry.
|
|
10
|
+
- Silkscreen strokes, fills, text dimensions, anchors, mirroring, source-layer
|
|
11
|
+
mapping, and surface cutouts render from canonical CircuitJSON fields.
|
|
12
|
+
- Copper text participates in the same solder-mask and cutout pipeline as other
|
|
13
|
+
copper detail.
|
|
14
|
+
- Blind and buried vias render only on the board surfaces reached by their
|
|
15
|
+
explicit layer span.
|
|
16
|
+
- `PcbScene3dBoardMaterialPalette.resolveEdgeColor(board)` is now public on the
|
|
17
|
+
`scene3d` subpath. Runtime and exported board edges share its authored-color
|
|
18
|
+
lookup and light FR-4 fallback (`0xc9ca78`).
|
|
19
|
+
|
|
20
|
+
## Models and diagnostics
|
|
21
|
+
|
|
22
|
+
- Canonical and session CAD assets preserve exact case-sensitive project-path
|
|
23
|
+
aliases. Case-insensitive fallback is accepted only when unique, preventing
|
|
24
|
+
same-name and same-stem collisions across folders.
|
|
25
|
+
- Missing-model diagnostics are deferred until resolution has actually failed;
|
|
26
|
+
retryable or externally supplied assets are not reported as unavailable
|
|
27
|
+
prematurely.
|
|
28
|
+
- STEP, WRL, GLTF, and text/binary model payload handling avoids redundant
|
|
29
|
+
copies and retains the existing opt-in network policy.
|
|
30
|
+
|
|
31
|
+
## Compatibility and performance
|
|
32
|
+
|
|
33
|
+
- The runtime baseline is `circuitjson-toolkit@^1.2.0`; the existing
|
|
34
|
+
`@sunbox/occt-import-js@^0.0.28` WASM package remains compatible and does not
|
|
35
|
+
require a coordinated rebuild.
|
|
36
|
+
- Existing scene descriptions, document envelopes, controller/runtime
|
|
37
|
+
parameters, and return shapes remain accepted. The palette method and
|
|
38
|
+
CircuitJSON fields above are additive.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pcb-scene3d-viewer",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0",
|
|
4
4
|
"description": "Reusable Three.js PCB 3D scene viewer for normalized ECAD and CircuitJSON scene descriptions",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pcb",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"docs/release-notes-v1.2.0.md",
|
|
37
37
|
"docs/release-notes-v1.2.1.md",
|
|
38
38
|
"docs/release-notes-v1.2.2.md",
|
|
39
|
+
"docs/release-notes-v1.3.0.md",
|
|
39
40
|
"docs/model-format.md",
|
|
40
41
|
"docs/testing.md",
|
|
41
42
|
"spec",
|
|
@@ -57,7 +58,7 @@
|
|
|
57
58
|
},
|
|
58
59
|
"dependencies": {
|
|
59
60
|
"@sunbox/occt-import-js": "^0.0.28",
|
|
60
|
-
"circuitjson-toolkit": "^1.
|
|
61
|
+
"circuitjson-toolkit": "^1.2.0",
|
|
61
62
|
"earcut": "3.0.2",
|
|
62
63
|
"fflate": "^0.8.2",
|
|
63
64
|
"polygon-clipping": "^0.15.7",
|
|
@@ -352,7 +352,7 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
352
352
|
* Finds the earliest indexed asset matching one CAD model URL.
|
|
353
353
|
* @param {string} url Model URL.
|
|
354
354
|
* @param {object} context Resolver context.
|
|
355
|
-
* @param {Map<string, object>} assetIndex Asset alias index.
|
|
355
|
+
* @param {{ exact: Map<string, object | symbol>, folded: Map<string, object | symbol> }} assetIndex Asset alias index.
|
|
356
356
|
* @returns {object | null}
|
|
357
357
|
*/
|
|
358
358
|
static #matchingIndexedEntry(url, context, assetIndex) {
|
|
@@ -363,7 +363,11 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
363
363
|
let match = null
|
|
364
364
|
for (const candidate of candidates) {
|
|
365
365
|
const indexed = assetIndex.exact.get(candidate)
|
|
366
|
-
if (
|
|
366
|
+
if (
|
|
367
|
+
indexed &&
|
|
368
|
+
indexed !== AMBIGUOUS_ASSET &&
|
|
369
|
+
(!match || indexed.index < match.index)
|
|
370
|
+
) {
|
|
367
371
|
match = indexed
|
|
368
372
|
}
|
|
369
373
|
}
|
|
@@ -554,12 +558,13 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
554
558
|
|
|
555
559
|
/**
|
|
556
560
|
* Resolves an exact alias or one unambiguous case-insensitive fallback.
|
|
557
|
-
* @param {{ exact: Map<string, object>, folded: Map<string, object | symbol> }} index Asset index.
|
|
561
|
+
* @param {{ exact: Map<string, object | symbol>, folded: Map<string, object | symbol> }} index Asset index.
|
|
558
562
|
* @param {string} key Exact normalized key.
|
|
559
563
|
* @returns {object | null} Indexed asset entry.
|
|
560
564
|
*/
|
|
561
565
|
static #indexedAsset(index, key) {
|
|
562
566
|
const exact = index.exact.get(key)
|
|
567
|
+
if (exact === AMBIGUOUS_ASSET) return null
|
|
563
568
|
if (exact) return exact
|
|
564
569
|
const folded = index.folded.get(key.toLowerCase())
|
|
565
570
|
return folded && folded !== AMBIGUOUS_ASSET ? folded : null
|
|
@@ -606,10 +611,10 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
606
611
|
}
|
|
607
612
|
|
|
608
613
|
/**
|
|
609
|
-
* Builds one descriptor-safe
|
|
614
|
+
* Builds one descriptor-safe asset alias index with collision rejection.
|
|
610
615
|
* @param {object[]} assets Asset rows.
|
|
611
616
|
* @param {boolean} [canonical] Whether rows use the canonical toolkit asset contract.
|
|
612
|
-
* @returns {{ exact: Map<string, object>, folded: Map<string, object | symbol> }}
|
|
617
|
+
* @returns {{ exact: Map<string, object | symbol>, folded: Map<string, object | symbol> }}
|
|
613
618
|
*/
|
|
614
619
|
static #assetIndex(assets, canonical = false) {
|
|
615
620
|
const exact = new Map()
|
|
@@ -625,7 +630,12 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
625
630
|
for (const alias of CircuitJsonCadModelAssetResolver.#assetAliases(
|
|
626
631
|
asset
|
|
627
632
|
)) {
|
|
628
|
-
|
|
633
|
+
const exactPrevious = exact.get(alias)
|
|
634
|
+
if (!exactPrevious) {
|
|
635
|
+
exact.set(alias, entry)
|
|
636
|
+
} else if (exactPrevious !== entry) {
|
|
637
|
+
exact.set(alias, AMBIGUOUS_ASSET)
|
|
638
|
+
}
|
|
629
639
|
const foldedAlias = alias.toLowerCase()
|
|
630
640
|
const previous = folded.get(foldedAlias)
|
|
631
641
|
if (!previous) {
|
|
@@ -719,6 +729,9 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
719
729
|
asset,
|
|
720
730
|
'source'
|
|
721
731
|
)
|
|
732
|
+
const explicitAliases = CircuitJsonCadModelAssetResolver.#denseArray(
|
|
733
|
+
CircuitJsonCadModelAssetResolver.#ownData(asset, 'aliases')
|
|
734
|
+
).filter((value) => typeof value === 'string')
|
|
722
735
|
return new Set(
|
|
723
736
|
[
|
|
724
737
|
CircuitJsonCadModelAssetResolver.#ownData(
|
|
@@ -742,7 +755,8 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
742
755
|
'relativePath'
|
|
743
756
|
),
|
|
744
757
|
CircuitJsonCadModelAssetResolver.#ownData(source, 'url'),
|
|
745
|
-
CircuitJsonCadModelAssetResolver.#ownData(source, 'uri')
|
|
758
|
+
CircuitJsonCadModelAssetResolver.#ownData(source, 'uri'),
|
|
759
|
+
...explicitAliases
|
|
746
760
|
]
|
|
747
761
|
.map((value) => CircuitJsonCadModelAssetResolver.#key(value))
|
|
748
762
|
.filter(Boolean)
|
|
@@ -866,10 +880,10 @@ export class CircuitJsonCadModelAssetResolver {
|
|
|
866
880
|
*/
|
|
867
881
|
static #key(value) {
|
|
868
882
|
if (typeof value !== 'string' && typeof value !== 'number') return ''
|
|
869
|
-
|
|
883
|
+
const key = String(value || '')
|
|
870
884
|
.trim()
|
|
871
885
|
.split(/[?#]/u)[0]
|
|
872
|
-
.
|
|
873
|
-
|
|
886
|
+
.replaceAll('\\', '/')
|
|
887
|
+
return /^https?:\/\//iu.test(key) ? key : key.replace(/^\/+/u, '')
|
|
874
888
|
}
|
|
875
889
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PcbScene3dModelContent } from './PcbScene3dModelContent.mjs'
|
|
2
|
+
|
|
1
3
|
const MM_TO_MIL = 1000 / 25.4
|
|
2
4
|
const GLB_MAGIC = 0x46546c67
|
|
3
5
|
const GLB_VERSION = 2
|
|
@@ -887,7 +889,7 @@ export class PcbAssemblyGltfModelMeshParser {
|
|
|
887
889
|
return bytes
|
|
888
890
|
}
|
|
889
891
|
|
|
890
|
-
throw
|
|
892
|
+
throw PcbScene3dModelContent.unavailableError(label)
|
|
891
893
|
}
|
|
892
894
|
|
|
893
895
|
/**
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { PcbScene3dModelContent } from './PcbScene3dModelContent.mjs'
|
|
2
|
+
|
|
1
3
|
const MM_TO_MIL = 1000 / 25.4
|
|
2
4
|
|
|
3
5
|
/**
|
|
@@ -548,7 +550,7 @@ export class PcbAssemblyTextModelMeshParser {
|
|
|
548
550
|
return bytes
|
|
549
551
|
}
|
|
550
552
|
|
|
551
|
-
throw
|
|
553
|
+
throw PcbScene3dModelContent.unavailableError(label)
|
|
552
554
|
}
|
|
553
555
|
|
|
554
556
|
/**
|
|
@@ -35,8 +35,7 @@ export class PcbScene3dBoardAssemblyPresentation {
|
|
|
35
35
|
board,
|
|
36
36
|
options
|
|
37
37
|
)
|
|
38
|
-
const edgeColor =
|
|
39
|
-
PcbScene3dBoardAssemblyPresentation.#resolveEdgeColor(board)
|
|
38
|
+
const edgeColor = PcbScene3dBoardMaterialPalette.resolveEdgeColor(board)
|
|
40
39
|
const importedSurfaceColor =
|
|
41
40
|
PcbScene3dBoardAssemblyPresentation.#resolveImportedSurfaceColor(
|
|
42
41
|
meshRecords
|
|
@@ -426,15 +425,6 @@ export class PcbScene3dBoardAssemblyPresentation {
|
|
|
426
425
|
})
|
|
427
426
|
}
|
|
428
427
|
|
|
429
|
-
/**
|
|
430
|
-
* Resolves the app-level substrate edge color for board assembly meshes.
|
|
431
|
-
* @param {{ edgeColor?: number } | null | undefined} board Board dimensions.
|
|
432
|
-
* @returns {number}
|
|
433
|
-
*/
|
|
434
|
-
static #resolveEdgeColor(board) {
|
|
435
|
-
return Number.isInteger(board?.edgeColor) ? board.edgeColor : 0xc9ca78
|
|
436
|
-
}
|
|
437
|
-
|
|
438
428
|
/**
|
|
439
429
|
* Applies display treatment to board substrate material.
|
|
440
430
|
* @param {any | any[]} material Material or material list.
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
export class PcbScene3dBoardMaterialPalette {
|
|
5
5
|
static #DEFAULT_SURFACE_COLOR = 0x2a5f27
|
|
6
|
+
static #DEFAULT_EDGE_COLOR = 0xc9ca78
|
|
6
7
|
static #BOARD_SURFACE_DARKEN_RATIO = 0.88
|
|
7
8
|
|
|
8
9
|
/**
|
|
@@ -39,6 +40,17 @@ export class PcbScene3dBoardMaterialPalette {
|
|
|
39
40
|
)
|
|
40
41
|
}
|
|
41
42
|
|
|
43
|
+
/**
|
|
44
|
+
* Resolves the visible substrate-core color for board edge faces.
|
|
45
|
+
* @param {{ edgeColor?: number } | null | undefined} board Board metadata.
|
|
46
|
+
* @returns {number}
|
|
47
|
+
*/
|
|
48
|
+
static resolveEdgeColor(board) {
|
|
49
|
+
return Number.isInteger(board?.edgeColor)
|
|
50
|
+
? board.edgeColor
|
|
51
|
+
: PcbScene3dBoardMaterialPalette.#DEFAULT_EDGE_COLOR
|
|
52
|
+
}
|
|
53
|
+
|
|
42
54
|
/**
|
|
43
55
|
* Returns true when the source format supplies display-stable board colors.
|
|
44
56
|
* @param {{ sourceFormat?: string }} options Scene options.
|
|
@@ -7,7 +7,8 @@ import { PcbScene3dCircuitJsonGeometry } from './PcbScene3dCircuitJsonGeometry.m
|
|
|
7
7
|
import { PcbScene3dCircuitJsonDrillDetail } from './PcbScene3dCircuitJsonDrillDetail.mjs'
|
|
8
8
|
import { PcbScene3dCircuitJsonModelTransform } from './PcbScene3dCircuitJsonModelTransform.mjs'
|
|
9
9
|
import { PcbScene3dCircuitJsonCopperPourBuilder } from './PcbScene3dCircuitJsonCopperPourBuilder.mjs'
|
|
10
|
-
import {
|
|
10
|
+
import { PcbScene3dCircuitJsonCopperTextBuilder } from './PcbScene3dCircuitJsonCopperTextBuilder.mjs'
|
|
11
|
+
import { PcbScene3dCircuitJsonSilkscreenDetailBuilder } from './PcbScene3dCircuitJsonSilkscreenDetailBuilder.mjs'
|
|
11
12
|
import { PcbScene3dFootprintBodyBuilder } from './PcbScene3dFootprintBodyBuilder.mjs'
|
|
12
13
|
import { PcbScene3dCircuitJsonLayer } from './PcbScene3dCircuitJsonLayer.mjs'
|
|
13
14
|
import { PcbScene3dCircuitJsonInput } from './PcbScene3dCircuitJsonInput.mjs'
|
|
@@ -18,6 +19,7 @@ import { PcbScene3dCircuitJsonSolderPasteBuilder } from './PcbScene3dCircuitJson
|
|
|
18
19
|
import { CircuitJsonCadModelAssetResolver } from './CircuitJsonCadModelAssetResolver.mjs'
|
|
19
20
|
import { PcbScene3dDescriptorSafeRecord } from './PcbScene3dDescriptorSafeRecord.mjs'
|
|
20
21
|
import { PcbScene3dCircuitJsonModelAsset } from './PcbScene3dCircuitJsonModelAsset.mjs'
|
|
22
|
+
import { PcbScene3dCircuitJsonPadCorner } from './PcbScene3dCircuitJsonPadCorner.mjs'
|
|
21
23
|
|
|
22
24
|
const DEFAULT_COMPONENT_HEIGHT_MIL = 60
|
|
23
25
|
const RECTANGULAR_PAD_SHAPE = 2
|
|
@@ -682,27 +684,34 @@ export class PcbScene3dCircuitJsonAdapter {
|
|
|
682
684
|
index,
|
|
683
685
|
options
|
|
684
686
|
)
|
|
687
|
+
const pads = [
|
|
688
|
+
...PcbScene3dCircuitJsonAdapter.#buildSmtPads(index),
|
|
689
|
+
...PcbScene3dCircuitJsonAdapter.#buildPlatedHoles(index),
|
|
690
|
+
...PcbScene3dCircuitJsonAdapter.#buildNonPlatedHoles(index)
|
|
691
|
+
]
|
|
692
|
+
const vias = PcbScene3dCircuitJsonTraceRouteBuilder.buildVias(index)
|
|
693
|
+
const tracks = [
|
|
694
|
+
...PcbScene3dCircuitJsonTraceRouteBuilder.buildTracks(index),
|
|
695
|
+
...PcbScene3dCircuitJsonThermalSpokeBuilder.build(index)
|
|
696
|
+
]
|
|
697
|
+
const polygons = PcbScene3dCircuitJsonCopperPourBuilder.build(index)
|
|
698
|
+
const copperTexts = PcbScene3dCircuitJsonCopperTextBuilder.build(index)
|
|
699
|
+
const silkscreen = PcbScene3dCircuitJsonSilkscreenDetailBuilder.build(
|
|
700
|
+
index,
|
|
701
|
+
{ pads, vias, tracks, polygons, copperTexts },
|
|
702
|
+
options
|
|
703
|
+
)
|
|
685
704
|
|
|
686
705
|
return {
|
|
687
|
-
pads
|
|
688
|
-
|
|
689
|
-
...PcbScene3dCircuitJsonAdapter.#buildPlatedHoles(index),
|
|
690
|
-
...PcbScene3dCircuitJsonAdapter.#buildNonPlatedHoles(index)
|
|
691
|
-
],
|
|
692
|
-
tracks: [
|
|
693
|
-
...PcbScene3dCircuitJsonTraceRouteBuilder.buildTracks(index),
|
|
694
|
-
...PcbScene3dCircuitJsonThermalSpokeBuilder.build(index)
|
|
695
|
-
],
|
|
706
|
+
pads,
|
|
707
|
+
tracks,
|
|
696
708
|
arcs: [],
|
|
697
709
|
fills: [],
|
|
698
|
-
vias
|
|
699
|
-
polygons
|
|
700
|
-
copperTexts
|
|
710
|
+
vias,
|
|
711
|
+
polygons,
|
|
712
|
+
copperTexts,
|
|
701
713
|
embeddedFonts: [],
|
|
702
|
-
silkscreen
|
|
703
|
-
index,
|
|
704
|
-
options
|
|
705
|
-
),
|
|
714
|
+
silkscreen,
|
|
706
715
|
...(paste ? { paste } : {}),
|
|
707
716
|
drillQuality: PcbScene3dCircuitJsonGeometry.normalizeDrillQuality(
|
|
708
717
|
options?.boardDrillQuality
|
|
@@ -745,11 +754,7 @@ export class PcbScene3dCircuitJsonAdapter {
|
|
|
745
754
|
holeDiameter: 0,
|
|
746
755
|
hasTopSolderMaskOpening: !isBottom && exposesCopper,
|
|
747
756
|
hasBottomSolderMaskOpening: isBottom && exposesCopper,
|
|
748
|
-
...
|
|
749
|
-
pad,
|
|
750
|
-
size,
|
|
751
|
-
isBottom
|
|
752
|
-
)
|
|
757
|
+
...PcbScene3dCircuitJsonPadCorner.metadata(pad, size, isBottom)
|
|
753
758
|
}
|
|
754
759
|
return padDetail
|
|
755
760
|
})
|
|
@@ -768,7 +773,7 @@ export class PcbScene3dCircuitJsonAdapter {
|
|
|
768
773
|
y: Number(hole?.y || 0)
|
|
769
774
|
})
|
|
770
775
|
const size =
|
|
771
|
-
|
|
776
|
+
PcbScene3dCircuitJsonGeometry.platedHoleOuterSize(geometry)
|
|
772
777
|
const center = CircuitJsonUnits.pointMmToMil({
|
|
773
778
|
x: hole?.x,
|
|
774
779
|
y: hole?.y
|
|
@@ -796,6 +801,11 @@ export class PcbScene3dCircuitJsonAdapter {
|
|
|
796
801
|
sizeMidY: size.height,
|
|
797
802
|
sizeBottomX: size.width,
|
|
798
803
|
sizeBottomY: size.height,
|
|
804
|
+
...PcbScene3dCircuitJsonPadCorner.metadata(
|
|
805
|
+
geometry,
|
|
806
|
+
size,
|
|
807
|
+
null
|
|
808
|
+
),
|
|
799
809
|
...PcbScene3dCircuitJsonDrillDetail.fields(drill),
|
|
800
810
|
holeOffsetX: drill.center.x - center.x,
|
|
801
811
|
holeOffsetY: drill.center.y - center.y,
|
|
@@ -852,68 +862,6 @@ export class PcbScene3dCircuitJsonAdapter {
|
|
|
852
862
|
height: CircuitJsonUnits.mmToMil(pad?.height, 1)
|
|
853
863
|
}
|
|
854
864
|
}
|
|
855
|
-
|
|
856
|
-
/**
|
|
857
|
-
* Builds rounded-rectangle metadata for pill-shaped SMT pads.
|
|
858
|
-
* @param {object} pad Pad element.
|
|
859
|
-
* @param {{ width: number, height: number }} size Pad copper size.
|
|
860
|
-
* @param {boolean} isBottom True when the pad is on the bottom side.
|
|
861
|
-
* @returns {object}
|
|
862
|
-
*/
|
|
863
|
-
static #roundedPadMetadata(pad, size, isBottom) {
|
|
864
|
-
if (!String(pad?.shape || '').endsWith('pill')) {
|
|
865
|
-
return {}
|
|
866
|
-
}
|
|
867
|
-
|
|
868
|
-
const cornerRadius =
|
|
869
|
-
PcbScene3dCircuitJsonAdapter.#roundedPadCornerRadiusPercent(
|
|
870
|
-
pad,
|
|
871
|
-
size
|
|
872
|
-
)
|
|
873
|
-
return {
|
|
874
|
-
hasRoundedRect: true,
|
|
875
|
-
roundedRectShapeTop: isBottom ? null : RECTANGULAR_PAD_SHAPE,
|
|
876
|
-
roundedRectShapeBottom: isBottom ? RECTANGULAR_PAD_SHAPE : null,
|
|
877
|
-
cornerRadiusTop: isBottom ? null : cornerRadius,
|
|
878
|
-
cornerRadiusBottom: isBottom ? cornerRadius : null
|
|
879
|
-
}
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
/**
|
|
883
|
-
* Resolves a pill-pad corner radius as a percent of the shortest side.
|
|
884
|
-
* @param {object} pad Pad element.
|
|
885
|
-
* @param {{ width: number, height: number }} size Pad copper size.
|
|
886
|
-
* @returns {number}
|
|
887
|
-
*/
|
|
888
|
-
static #roundedPadCornerRadiusPercent(pad, size) {
|
|
889
|
-
const width = CircuitJsonUnits.optionalLength(pad?.width)
|
|
890
|
-
const height = CircuitJsonUnits.optionalLength(pad?.height)
|
|
891
|
-
const radius = CircuitJsonUnits.optionalLength(pad?.radius)
|
|
892
|
-
if (width > 0 && height > 0 && radius > 0) {
|
|
893
|
-
return Math.min((radius / Math.min(width, height)) * 100, 50)
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
const shortestSide = Math.min(Number(size.width), Number(size.height))
|
|
897
|
-
const radiusMil = CircuitJsonUnits.mmToMil(pad?.radius, 0)
|
|
898
|
-
if (shortestSide > 0 && radiusMil > 0) {
|
|
899
|
-
return Math.min((radiusMil / shortestSide) * 100, 50)
|
|
900
|
-
}
|
|
901
|
-
|
|
902
|
-
return 50
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
/**
|
|
906
|
-
* Resolves plated-hole copper size from CircuitJSON fields.
|
|
907
|
-
* @param {object} geometry Shared drilled-primitive geometry.
|
|
908
|
-
* @returns {{ width: number, height: number }}
|
|
909
|
-
*/
|
|
910
|
-
static #platedHoleOuterSize(geometry) {
|
|
911
|
-
return {
|
|
912
|
-
width: CircuitJsonUnits.mmToMil(geometry?.width, 1),
|
|
913
|
-
height: CircuitJsonUnits.mmToMil(geometry?.height, 1)
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
|
|
917
865
|
/**
|
|
918
866
|
* Resolves the viewer pad shape code.
|
|
919
867
|
* @param {object} pad CircuitJSON pad element.
|