pcb-scene3d-viewer 1.1.2 → 1.1.10
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/package.json +1 -1
- package/src/PcbScene3dArcUtils.mjs +18 -0
- package/src/PcbScene3dBoardAssemblyPresentation.mjs +3 -0
- package/src/PcbScene3dBoardSolderMaskFactory.mjs +2 -2
- package/src/PcbScene3dCameraRig.mjs +16 -1
- package/src/PcbScene3dCopperDetailFilter.mjs +73 -1
- package/src/PcbScene3dCopperDetailGroupBuilder.mjs +120 -0
- package/src/PcbScene3dCopperFactory.mjs +465 -33
- package/src/PcbScene3dCopperTextFactory.mjs +6 -3
- package/src/PcbScene3dGeometryZCompressor.mjs +48 -0
- package/src/PcbScene3dMaskCoveredCopperMaterial.mjs +75 -0
- package/src/PcbScene3dMaterialFinish.mjs +49 -0
- package/src/PcbScene3dRuntime.mjs +11 -64
- package/src/PcbScene3dRuntimeBoardMeshes.mjs +8 -3
- package/src/PcbScene3dSilkscreenFactory.mjs +25 -13
- package/src/PcbScene3dStrokeGeometryBuilder.mjs +7 -6
- package/src/PcbScene3dTrueTypeTextFactory.mjs +8 -3
package/package.json
CHANGED
|
@@ -4,6 +4,24 @@
|
|
|
4
4
|
export class PcbScene3dArcUtils {
|
|
5
5
|
static #FULL_CIRCLE_EPSILON = 0.001
|
|
6
6
|
|
|
7
|
+
/**
|
|
8
|
+
* Resolves one arc record's sweep, preserving explicit long-arc sweeps.
|
|
9
|
+
* @param {{ startAngle?: number, endAngle?: number, sweepAngle?: number }} arc
|
|
10
|
+
* Arc record.
|
|
11
|
+
* @returns {number}
|
|
12
|
+
*/
|
|
13
|
+
static resolveArcSweepDelta(arc) {
|
|
14
|
+
const sweepAngle = Number(arc?.sweepAngle)
|
|
15
|
+
if (Number.isFinite(sweepAngle)) {
|
|
16
|
+
return sweepAngle
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return PcbScene3dArcUtils.resolveSweepDelta(
|
|
20
|
+
Number(arc?.startAngle || 0),
|
|
21
|
+
Number(arc?.endAngle || 0)
|
|
22
|
+
)
|
|
23
|
+
}
|
|
24
|
+
|
|
7
25
|
/**
|
|
8
26
|
* Normalizes one PCB arc delta to the intended short wrapped sweep.
|
|
9
27
|
* @param {number} startAngle Start angle in degrees.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { PcbScene3dBoardMaterialPalette } from './PcbScene3dBoardMaterialPalette.mjs'
|
|
2
|
+
import { PcbScene3dMaterialFinish } from './PcbScene3dMaterialFinish.mjs'
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Applies display-only material adjustments to full-board assembly models.
|
|
@@ -155,6 +156,7 @@ export class PcbScene3dBoardAssemblyPresentation {
|
|
|
155
156
|
object?.material,
|
|
156
157
|
surfaceColor
|
|
157
158
|
)
|
|
159
|
+
PcbScene3dMaterialFinish.applySemiMatteSolderMask(object?.material)
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
/**
|
|
@@ -192,6 +194,7 @@ export class PcbScene3dBoardAssemblyPresentation {
|
|
|
192
194
|
surfaceMaterial,
|
|
193
195
|
surfaceColor
|
|
194
196
|
)
|
|
197
|
+
PcbScene3dMaterialFinish.applySemiMatteSolderMask(surfaceMaterial)
|
|
195
198
|
PcbScene3dBoardAssemblyPresentation.#applyMaterialColor(
|
|
196
199
|
edgeMaterial,
|
|
197
200
|
edgeColor
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { PcbScene3dBoardMaterialPalette } from './PcbScene3dBoardMaterialPalette.mjs'
|
|
2
2
|
import { PcbScene3dCutoutGeometryFilter } from './PcbScene3dCutoutGeometryFilter.mjs'
|
|
3
3
|
import { PcbScene3dDrillPathFactory } from './PcbScene3dDrillPathFactory.mjs'
|
|
4
|
+
import { PcbScene3dMaterialFinish } from './PcbScene3dMaterialFinish.mjs'
|
|
4
5
|
import { PcbScene3dOutlineBuilder } from './PcbScene3dOutlineBuilder.mjs'
|
|
5
6
|
|
|
6
7
|
/**
|
|
@@ -602,8 +603,7 @@ export class PcbScene3dBoardSolderMaskFactory {
|
|
|
602
603
|
color: PcbScene3dBoardMaterialPalette.resolveSurfaceColor(board, {
|
|
603
604
|
hasBoardAssemblyModel: true
|
|
604
605
|
}),
|
|
605
|
-
|
|
606
|
-
metalness: 0.08,
|
|
606
|
+
...PcbScene3dMaterialFinish.semiMatteSolderMaskProperties(),
|
|
607
607
|
polygonOffset: true,
|
|
608
608
|
polygonOffsetFactor: -1,
|
|
609
609
|
polygonOffsetUnits: -1,
|
|
@@ -48,7 +48,7 @@ export class PcbScene3dCameraRig {
|
|
|
48
48
|
return {
|
|
49
49
|
radius,
|
|
50
50
|
target,
|
|
51
|
-
up:
|
|
51
|
+
up: PcbScene3dCameraRig.#bottomUpVector(sceneDescription),
|
|
52
52
|
position: {
|
|
53
53
|
x: target.x,
|
|
54
54
|
y: target.y,
|
|
@@ -165,4 +165,19 @@ export class PcbScene3dCameraRig {
|
|
|
165
165
|
z: Number(controls?.target?.z || 0)
|
|
166
166
|
}
|
|
167
167
|
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Resolves screen-up for bottom views from the scene coordinate contract.
|
|
171
|
+
* @param {{ coordinateSystem?: string }} sceneDescription Scene metadata.
|
|
172
|
+
* @returns {{ x: number, y: number, z: number }}
|
|
173
|
+
*/
|
|
174
|
+
static #bottomUpVector(sceneDescription) {
|
|
175
|
+
const coordinateSystem = String(
|
|
176
|
+
sceneDescription?.coordinateSystem || ''
|
|
177
|
+
).toLowerCase()
|
|
178
|
+
|
|
179
|
+
return coordinateSystem === 'kicad-3d-y-up'
|
|
180
|
+
? { x: 0, y: 1, z: 0 }
|
|
181
|
+
: { x: 0, y: -1, z: 0 }
|
|
182
|
+
}
|
|
168
183
|
}
|
|
@@ -39,6 +39,41 @@ export class PcbScene3dCopperDetailFilter {
|
|
|
39
39
|
}
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Resolves trace-like copper that should be visible through solder mask.
|
|
44
|
+
* @param {object} sceneDescription 3D scene description.
|
|
45
|
+
* @returns {{ tracks: any[], arcs: any[], copperTexts: any[], vias: any[] }}
|
|
46
|
+
*/
|
|
47
|
+
static resolveCoveredByMask(sceneDescription) {
|
|
48
|
+
const detail = sceneDescription?.detail || {}
|
|
49
|
+
|
|
50
|
+
if (
|
|
51
|
+
!PcbScene3dCopperDetailFilter.#usesRealisticMasking(
|
|
52
|
+
sceneDescription
|
|
53
|
+
)
|
|
54
|
+
) {
|
|
55
|
+
return { tracks: [], arcs: [], copperTexts: [], vias: [] }
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
const defaultCovered =
|
|
59
|
+
PcbScene3dCopperDetailFilter.#usesDefaultCoveredCopper(
|
|
60
|
+
sceneDescription
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
tracks: PcbScene3dCopperDetailFilter.#filterMaskCoveredPrimitives(
|
|
65
|
+
detail.tracks,
|
|
66
|
+
defaultCovered
|
|
67
|
+
),
|
|
68
|
+
arcs: PcbScene3dCopperDetailFilter.#filterMaskCoveredPrimitives(
|
|
69
|
+
detail.arcs,
|
|
70
|
+
defaultCovered
|
|
71
|
+
),
|
|
72
|
+
copperTexts: [],
|
|
73
|
+
vias: []
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
42
77
|
/**
|
|
43
78
|
* Checks whether standalone via annuli should be rendered.
|
|
44
79
|
* @param {object} sceneDescription 3D scene description.
|
|
@@ -101,6 +136,24 @@ export class PcbScene3dCopperDetailFilter {
|
|
|
101
136
|
)
|
|
102
137
|
}
|
|
103
138
|
|
|
139
|
+
/**
|
|
140
|
+
* Checks whether tracks are considered mask-covered without per-primitive
|
|
141
|
+
* mask metadata.
|
|
142
|
+
* @param {object} sceneDescription 3D scene description.
|
|
143
|
+
* @returns {boolean}
|
|
144
|
+
*/
|
|
145
|
+
static #usesDefaultCoveredCopper(sceneDescription) {
|
|
146
|
+
const sourceFormat = String(sceneDescription?.sourceFormat || '')
|
|
147
|
+
.trim()
|
|
148
|
+
.toLowerCase()
|
|
149
|
+
|
|
150
|
+
return (
|
|
151
|
+
sourceFormat === 'altium' ||
|
|
152
|
+
sourceFormat === 'kicad' ||
|
|
153
|
+
sceneDescription?.coordinateSystem === 'kicad-3d-y-up'
|
|
154
|
+
)
|
|
155
|
+
}
|
|
156
|
+
|
|
104
157
|
/**
|
|
105
158
|
* Checks whether parsed copper detail carries explicit solder-mask data.
|
|
106
159
|
* @param {object | undefined} detail Scene detail.
|
|
@@ -132,6 +185,25 @@ export class PcbScene3dCopperDetailFilter {
|
|
|
132
185
|
)
|
|
133
186
|
}
|
|
134
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Keeps trace-like copper primitives that are covered by solder mask.
|
|
190
|
+
* @param {any[] | undefined} primitives Copper primitive list.
|
|
191
|
+
* @param {boolean} defaultCovered Whether missing metadata means covered.
|
|
192
|
+
* @returns {any[]}
|
|
193
|
+
*/
|
|
194
|
+
static #filterMaskCoveredPrimitives(primitives, defaultCovered) {
|
|
195
|
+
return (primitives || []).filter((primitive) => {
|
|
196
|
+
if (PcbScene3dCopperDetailFilter.#hasMaskOpening(primitive)) {
|
|
197
|
+
return false
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
return (
|
|
201
|
+
defaultCovered ||
|
|
202
|
+
PcbScene3dCopperDetailFilter.#hasMaskMetadata(primitive)
|
|
203
|
+
)
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
|
|
135
207
|
/**
|
|
136
208
|
* Keeps vias only when they are explicitly not tented.
|
|
137
209
|
* @param {any[] | undefined} vias Via list.
|
|
@@ -243,7 +315,7 @@ export class PcbScene3dCopperDetailFilter {
|
|
|
243
315
|
* @returns {boolean}
|
|
244
316
|
*/
|
|
245
317
|
static #hasMaskOpening(primitive, maskMatcher = null) {
|
|
246
|
-
if (primitive?.hasSolderMask ===
|
|
318
|
+
if (primitive?.hasSolderMask === false) {
|
|
247
319
|
return true
|
|
248
320
|
}
|
|
249
321
|
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { PcbScene3dBoardMaterialPalette } from './PcbScene3dBoardMaterialPalette.mjs'
|
|
2
|
+
import { PcbScene3dCopperDetailFilter } from './PcbScene3dCopperDetailFilter.mjs'
|
|
3
|
+
import { PcbScene3dCopperFactory } from './PcbScene3dCopperFactory.mjs'
|
|
4
|
+
import { PcbScene3dViaFactory } from './PcbScene3dViaFactory.mjs'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Builds deferred copper-detail groups for the 3D runtime.
|
|
8
|
+
*/
|
|
9
|
+
export class PcbScene3dCopperDetailGroupBuilder {
|
|
10
|
+
/**
|
|
11
|
+
* Builds visible exposed and mask-covered copper detail.
|
|
12
|
+
* @param {any} THREE Three.js namespace.
|
|
13
|
+
* @param {object} sceneDescription Scene description.
|
|
14
|
+
* @param {number} topZ Top copper center Z.
|
|
15
|
+
* @param {(x: number, y: number) => { x: number, y: number }} normalizePoint
|
|
16
|
+
* @returns {any}
|
|
17
|
+
*/
|
|
18
|
+
static build(THREE, sceneDescription, topZ, normalizePoint) {
|
|
19
|
+
const group = new THREE.Group()
|
|
20
|
+
const coveredGroup =
|
|
21
|
+
PcbScene3dCopperDetailGroupBuilder.#buildCoveredGroup(
|
|
22
|
+
THREE,
|
|
23
|
+
sceneDescription,
|
|
24
|
+
topZ,
|
|
25
|
+
normalizePoint
|
|
26
|
+
)
|
|
27
|
+
const exposedGroup =
|
|
28
|
+
PcbScene3dCopperDetailGroupBuilder.#buildExposedGroup(
|
|
29
|
+
THREE,
|
|
30
|
+
sceneDescription,
|
|
31
|
+
topZ,
|
|
32
|
+
normalizePoint
|
|
33
|
+
)
|
|
34
|
+
const viaGroup = PcbScene3dCopperDetailGroupBuilder.#buildViaGroup(
|
|
35
|
+
THREE,
|
|
36
|
+
sceneDescription,
|
|
37
|
+
normalizePoint
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
;[coveredGroup, exposedGroup, viaGroup]
|
|
41
|
+
.filter((child) => child.children.length)
|
|
42
|
+
.forEach((child) => group.add(child))
|
|
43
|
+
|
|
44
|
+
return group
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Builds traces covered by solder mask.
|
|
49
|
+
* @param {any} THREE Three.js namespace.
|
|
50
|
+
* @param {object} sceneDescription Scene description.
|
|
51
|
+
* @param {number} topZ Top copper center Z.
|
|
52
|
+
* @param {(x: number, y: number) => { x: number, y: number }} normalizePoint
|
|
53
|
+
* @returns {any}
|
|
54
|
+
*/
|
|
55
|
+
static #buildCoveredGroup(THREE, sceneDescription, topZ, normalizePoint) {
|
|
56
|
+
return PcbScene3dCopperFactory.buildMaskCoveredGroup(
|
|
57
|
+
THREE,
|
|
58
|
+
PcbScene3dCopperDetailFilter.resolveCoveredByMask(sceneDescription),
|
|
59
|
+
topZ,
|
|
60
|
+
-topZ,
|
|
61
|
+
normalizePoint,
|
|
62
|
+
{
|
|
63
|
+
solderMaskColor:
|
|
64
|
+
PcbScene3dBoardMaterialPalette.resolveSurfaceColor(
|
|
65
|
+
sceneDescription?.board,
|
|
66
|
+
{
|
|
67
|
+
hasBoardAssemblyModel: Boolean(
|
|
68
|
+
sceneDescription?.boardAssemblyModel
|
|
69
|
+
)
|
|
70
|
+
}
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
)
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Builds exposed copper detail.
|
|
78
|
+
* @param {any} THREE Three.js namespace.
|
|
79
|
+
* @param {object} sceneDescription Scene description.
|
|
80
|
+
* @param {number} topZ Top copper center Z.
|
|
81
|
+
* @param {(x: number, y: number) => { x: number, y: number }} normalizePoint
|
|
82
|
+
* @returns {any}
|
|
83
|
+
*/
|
|
84
|
+
static #buildExposedGroup(THREE, sceneDescription, topZ, normalizePoint) {
|
|
85
|
+
return PcbScene3dCopperFactory.buildGroup(
|
|
86
|
+
THREE,
|
|
87
|
+
PcbScene3dCopperDetailFilter.resolve(sceneDescription),
|
|
88
|
+
topZ,
|
|
89
|
+
-topZ,
|
|
90
|
+
normalizePoint,
|
|
91
|
+
{ coordinateSystem: sceneDescription?.coordinateSystem }
|
|
92
|
+
)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
/**
|
|
96
|
+
* Builds exposed via and through-hole barrel detail.
|
|
97
|
+
* @param {any} THREE Three.js namespace.
|
|
98
|
+
* @param {object} sceneDescription Scene description.
|
|
99
|
+
* @param {(x: number, y: number) => { x: number, y: number }} normalizePoint
|
|
100
|
+
* @returns {any}
|
|
101
|
+
*/
|
|
102
|
+
static #buildViaGroup(THREE, sceneDescription, normalizePoint) {
|
|
103
|
+
if (
|
|
104
|
+
!PcbScene3dCopperDetailFilter.shouldRenderStandaloneVias(
|
|
105
|
+
sceneDescription
|
|
106
|
+
)
|
|
107
|
+
) {
|
|
108
|
+
return new THREE.Group()
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
return PcbScene3dViaFactory.buildGroup(
|
|
112
|
+
THREE,
|
|
113
|
+
PcbScene3dCopperDetailFilter.resolveStandaloneVias(
|
|
114
|
+
sceneDescription
|
|
115
|
+
),
|
|
116
|
+
sceneDescription?.board?.thicknessMil,
|
|
117
|
+
normalizePoint
|
|
118
|
+
)
|
|
119
|
+
}
|
|
120
|
+
}
|