pcb-scene3d-viewer 1.1.21 → 1.1.31
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 +3 -2
- package/docs/api.md +27 -1
- package/docs/circuitjson.md +63 -18
- package/docs/model-format.md +13 -2
- package/package.json +1 -1
- package/spec/library-scope.md +2 -2
- package/src/PcbAssemblyBoardSubstrateBuilder.mjs +25 -5
- package/src/PcbAssemblyComponentMeshBuilder.mjs +762 -0
- package/src/PcbAssemblyFillGeometryResolver.mjs +579 -0
- package/src/PcbAssemblyFillRingNormalizer.mjs +209 -0
- package/src/PcbAssemblyGeometryBuilder.mjs +41 -301
- package/src/PcbAssemblyGltfModelMeshParser.mjs +912 -0
- package/src/PcbAssemblyGltfValidator.mjs +460 -0
- package/src/PcbAssemblyGltfWriter.mjs +801 -0
- package/src/PcbAssemblyMeshUtils.mjs +117 -0
- package/src/PcbAssemblyModelMeshLoader.mjs +18 -0
- package/src/PcbAssemblyPadMeshBuilder.mjs +394 -0
- package/src/PcbAssemblyStepWriter.mjs +24 -2
- package/src/PcbAssemblyTextModelMeshParser.mjs +602 -0
- package/src/PcbModelArchiveExporter.mjs +521 -7
- package/src/PcbScene3dCircuitJsonAdapter.mjs +409 -7
- package/src/PcbScene3dCircuitJsonModelTransform.mjs +232 -0
- package/src/PcbScene3dCompanionBasePlacementAdjuster.mjs +242 -0
- package/src/PcbScene3dComponentVisibility.mjs +100 -5
- package/src/PcbScene3dController.mjs +25 -55
- package/src/PcbScene3dCopperDetailFilter.mjs +86 -9
- package/src/PcbScene3dCopperDetailGroupBuilder.mjs +186 -15
- package/src/PcbScene3dCopperDrillCutoutBuilder.mjs +258 -0
- package/src/PcbScene3dCopperFactory.mjs +99 -85
- package/src/PcbScene3dCopperFillMeshBuilder.mjs +393 -0
- package/src/PcbScene3dCopperLayerFilter.mjs +32 -3
- package/src/PcbScene3dCutoutGeometryFilter.mjs +17 -14
- package/src/PcbScene3dExternalCompanionFallback.mjs +202 -0
- package/src/PcbScene3dExternalModelCenteringPolicy.mjs +21 -0
- package/src/PcbScene3dExternalModelOpacity.mjs +51 -0
- package/src/PcbScene3dExternalModelPlacementRepair.mjs +5 -2
- package/src/PcbScene3dExternalModelSourceOriginPolicy.mjs +41 -0
- package/src/PcbScene3dExternalModels.mjs +16 -7
- package/src/PcbScene3dFallbackBodyFactory.mjs +105 -0
- package/src/PcbScene3dFallbackVisibility.mjs +58 -1
- package/src/PcbScene3dMaskCoveredCopperSideGroupBuilder.mjs +68 -0
- package/src/PcbScene3dPadFactory.mjs +35 -2
- package/src/PcbScene3dRenderGroupVisibility.mjs +8 -1
- package/src/PcbScene3dRuntime.mjs +94 -100
- package/src/PcbScene3dRuntimeHelpers.mjs +39 -0
- package/src/PcbScene3dSelectionIndexBuilder.mjs +87 -0
- package/src/PcbScene3dSelectionInspectorRenderer.mjs +50 -11
- package/src/PcbScene3dSelectionMarkerFactory.mjs +333 -0
- package/src/PcbScene3dSelectionMarkerOverlay.mjs +70 -0
- package/src/PcbScene3dSelectionStyler.mjs +52 -2
- package/src/PcbScene3dStaticBodyFactory.mjs +263 -0
- package/src/PcbScene3dText.mjs +1 -0
- package/src/PcbScene3dTransparentMeshSplitter.mjs +623 -0
- package/src/PcbScene3dViaFactory.mjs +27 -7
- package/src/scene3d.mjs +3 -0
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
import { PcbScene3dComponentAdjustment } from './PcbScene3dComponentAdjustment.mjs'
|
|
2
|
+
import { PcbScene3dMountRig } from './PcbScene3dMountRig.mjs'
|
|
3
|
+
import { PcbScene3dTransparentMeshSplitter } from './PcbScene3dTransparentMeshSplitter.mjs'
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Builds authored static component-body render roots.
|
|
7
|
+
*/
|
|
8
|
+
export class PcbScene3dStaticBodyFactory {
|
|
9
|
+
static #DEFAULT_COLOR = 0x808080
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Builds all renderable static body roots.
|
|
13
|
+
* @param {any} THREE Three.js namespace.
|
|
14
|
+
* @param {object[]} placements Static body placements.
|
|
15
|
+
* @returns {{ rootGroup: any, adjustmentGroup: any, placement: object }[]}
|
|
16
|
+
*/
|
|
17
|
+
static buildMany(THREE, placements) {
|
|
18
|
+
return (Array.isArray(placements) ? placements : [])
|
|
19
|
+
.map((placement) =>
|
|
20
|
+
PcbScene3dStaticBodyFactory.build(THREE, placement)
|
|
21
|
+
)
|
|
22
|
+
.filter(Boolean)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Builds one authored static body root.
|
|
27
|
+
* @param {any} THREE Three.js namespace.
|
|
28
|
+
* @param {{ designator?: string, selectionKey?: string, mountSide?: string, rotationDeg?: number, positionMil?: { x?: number, y?: number, z?: number }, geometry?: object, bodyColor?: object, bodyOpacity?: number }} placement Static body placement.
|
|
29
|
+
* @returns {{ rootGroup: any, adjustmentGroup: any, placement: object } | null}
|
|
30
|
+
*/
|
|
31
|
+
static build(THREE, placement) {
|
|
32
|
+
const geometry = PcbScene3dStaticBodyFactory.#buildGeometry(
|
|
33
|
+
THREE,
|
|
34
|
+
placement?.geometry
|
|
35
|
+
)
|
|
36
|
+
if (!geometry) {
|
|
37
|
+
return null
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
const opacity = PcbScene3dStaticBodyFactory.#resolveOpacity(placement)
|
|
41
|
+
const transparent = opacity < 1
|
|
42
|
+
const material = new THREE.MeshStandardMaterial({
|
|
43
|
+
color: PcbScene3dStaticBodyFactory.#resolveColor(placement),
|
|
44
|
+
roughness: 0.7,
|
|
45
|
+
metalness: 0.08,
|
|
46
|
+
transparent,
|
|
47
|
+
opacity,
|
|
48
|
+
depthWrite: !transparent
|
|
49
|
+
})
|
|
50
|
+
const mesh = new THREE.Mesh(geometry, material)
|
|
51
|
+
const renderObject = transparent
|
|
52
|
+
? PcbScene3dTransparentMeshSplitter.build(THREE, mesh)
|
|
53
|
+
: mesh
|
|
54
|
+
const mountRig = PcbScene3dMountRig.create(THREE, placement)
|
|
55
|
+
const adjustmentGroup =
|
|
56
|
+
PcbScene3dStaticBodyFactory.#buildAdjustmentGroup(THREE, placement)
|
|
57
|
+
const selectionKey =
|
|
58
|
+
PcbScene3dStaticBodyFactory.resolveSelectionKey(placement)
|
|
59
|
+
|
|
60
|
+
mountRig.rootGroup.userData.scene3dSelection = {
|
|
61
|
+
designator: selectionKey,
|
|
62
|
+
displayDesignator: String(
|
|
63
|
+
placement?.designator || selectionKey || 'static-body'
|
|
64
|
+
),
|
|
65
|
+
sourceType: 'static-body'
|
|
66
|
+
}
|
|
67
|
+
PcbScene3dStaticBodyFactory.#applyVariantMetadata(
|
|
68
|
+
mountRig.rootGroup,
|
|
69
|
+
placement
|
|
70
|
+
)
|
|
71
|
+
adjustmentGroup.add(renderObject)
|
|
72
|
+
mountRig.faceGroup.add(adjustmentGroup)
|
|
73
|
+
|
|
74
|
+
return {
|
|
75
|
+
rootGroup: mountRig.rootGroup,
|
|
76
|
+
adjustmentGroup,
|
|
77
|
+
placement
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Resolves the selectable key for one static body placement.
|
|
83
|
+
* @param {{ designator?: string, selectionKey?: string }} placement Static body placement.
|
|
84
|
+
* @returns {string}
|
|
85
|
+
*/
|
|
86
|
+
static resolveSelectionKey(placement) {
|
|
87
|
+
return String(
|
|
88
|
+
placement?.selectionKey || placement?.designator || 'static-body'
|
|
89
|
+
).trim()
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Builds the geometry for one supported static body.
|
|
94
|
+
* @param {any} THREE Three.js namespace.
|
|
95
|
+
* @param {{ kind?: string, verticesMil?: { x?: number, y?: number }[], heightMil?: number, radiusMil?: number }} geometry Static body geometry.
|
|
96
|
+
* @returns {any | null}
|
|
97
|
+
*/
|
|
98
|
+
static #buildGeometry(THREE, geometry) {
|
|
99
|
+
const kind = String(geometry?.kind || '').toLowerCase()
|
|
100
|
+
if (kind === 'extruded-polygon') {
|
|
101
|
+
return PcbScene3dStaticBodyFactory.#buildExtrudedPolygon(
|
|
102
|
+
THREE,
|
|
103
|
+
geometry
|
|
104
|
+
)
|
|
105
|
+
}
|
|
106
|
+
if (kind === 'cylinder') {
|
|
107
|
+
return PcbScene3dStaticBodyFactory.#buildCylinder(THREE, geometry)
|
|
108
|
+
}
|
|
109
|
+
if (kind === 'cone') {
|
|
110
|
+
return PcbScene3dStaticBodyFactory.#buildCone(THREE, geometry)
|
|
111
|
+
}
|
|
112
|
+
if (kind === 'sphere') {
|
|
113
|
+
return PcbScene3dStaticBodyFactory.#buildSphere(THREE, geometry)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
return null
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* Builds an extruded polygon geometry centered on its authored Z midpoint.
|
|
121
|
+
* @param {any} THREE Three.js namespace.
|
|
122
|
+
* @param {{ verticesMil?: { x?: number, y?: number }[], heightMil?: number }} geometry Static body geometry.
|
|
123
|
+
* @returns {any | null}
|
|
124
|
+
*/
|
|
125
|
+
static #buildExtrudedPolygon(THREE, geometry) {
|
|
126
|
+
const vertices = Array.isArray(geometry?.verticesMil)
|
|
127
|
+
? geometry.verticesMil
|
|
128
|
+
: []
|
|
129
|
+
const heightMil = Number(geometry?.heightMil || 0)
|
|
130
|
+
if (vertices.length < 3 || !(heightMil > 0)) {
|
|
131
|
+
return null
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const shape = new THREE.Shape()
|
|
135
|
+
shape.moveTo(Number(vertices[0].x || 0), Number(vertices[0].y || 0))
|
|
136
|
+
vertices.slice(1).forEach((vertex) => {
|
|
137
|
+
shape.lineTo(Number(vertex.x || 0), Number(vertex.y || 0))
|
|
138
|
+
})
|
|
139
|
+
shape.closePath()
|
|
140
|
+
|
|
141
|
+
const extrudedGeometry = new THREE.ExtrudeGeometry(shape, {
|
|
142
|
+
depth: heightMil,
|
|
143
|
+
bevelEnabled: false
|
|
144
|
+
})
|
|
145
|
+
extrudedGeometry.translate?.(0, 0, -heightMil / 2)
|
|
146
|
+
return extrudedGeometry
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* Builds a cylinder body geometry.
|
|
151
|
+
* @param {any} THREE Three.js namespace.
|
|
152
|
+
* @param {{ radiusMil?: number, heightMil?: number }} geometry Static body geometry.
|
|
153
|
+
* @returns {any | null}
|
|
154
|
+
*/
|
|
155
|
+
static #buildCylinder(THREE, geometry) {
|
|
156
|
+
const radiusMil = Number(geometry?.radiusMil || 0)
|
|
157
|
+
const heightMil = Number(geometry?.heightMil || 0)
|
|
158
|
+
if (!(radiusMil > 0) || !(heightMil > 0)) {
|
|
159
|
+
return null
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
return new THREE.CylinderGeometry(radiusMil, radiusMil, heightMil, 32)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
/**
|
|
166
|
+
* Builds a cone body geometry.
|
|
167
|
+
* @param {any} THREE Three.js namespace.
|
|
168
|
+
* @param {{ radiusMil?: number, heightMil?: number }} geometry Static body geometry.
|
|
169
|
+
* @returns {any | null}
|
|
170
|
+
*/
|
|
171
|
+
static #buildCone(THREE, geometry) {
|
|
172
|
+
const radiusMil = Number(geometry?.radiusMil || 0)
|
|
173
|
+
const heightMil = Number(geometry?.heightMil || 0)
|
|
174
|
+
if (!(radiusMil > 0) || !(heightMil > 0)) {
|
|
175
|
+
return null
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
if (typeof THREE.ConeGeometry === 'function') {
|
|
179
|
+
return new THREE.ConeGeometry(radiusMil, heightMil, 32)
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return new THREE.CylinderGeometry(0, radiusMil, heightMil, 32)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/**
|
|
186
|
+
* Builds a sphere body geometry.
|
|
187
|
+
* @param {any} THREE Three.js namespace.
|
|
188
|
+
* @param {{ radiusMil?: number }} geometry Static body geometry.
|
|
189
|
+
* @returns {any | null}
|
|
190
|
+
*/
|
|
191
|
+
static #buildSphere(THREE, geometry) {
|
|
192
|
+
const radiusMil = Number(geometry?.radiusMil || 0)
|
|
193
|
+
if (!(radiusMil > 0) || typeof THREE.SphereGeometry !== 'function') {
|
|
194
|
+
return null
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
return new THREE.SphereGeometry(radiusMil, 32, 16)
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Builds the transform node used by live component adjustments.
|
|
202
|
+
* @param {any} THREE Three.js namespace.
|
|
203
|
+
* @param {{ designator?: string, selectionKey?: string }} placement Static body placement.
|
|
204
|
+
* @returns {any}
|
|
205
|
+
*/
|
|
206
|
+
static #buildAdjustmentGroup(THREE, placement) {
|
|
207
|
+
const adjustmentGroup = new THREE.Group()
|
|
208
|
+
adjustmentGroup.userData.scene3dAdjustmentTarget = true
|
|
209
|
+
adjustmentGroup.userData.scene3dAdjustmentDesignator = String(
|
|
210
|
+
PcbScene3dStaticBodyFactory.resolveSelectionKey(placement)
|
|
211
|
+
)
|
|
212
|
+
adjustmentGroup.userData.scene3dAdjustmentBaseline =
|
|
213
|
+
PcbScene3dComponentAdjustment.neutral()
|
|
214
|
+
return adjustmentGroup
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* Copies authored variant grouping metadata onto the selectable root.
|
|
219
|
+
* @param {any} rootGroup Static body root group.
|
|
220
|
+
* @param {{ coLocatedVariantGroupKey?: string }} placement Static body placement.
|
|
221
|
+
* @returns {void}
|
|
222
|
+
*/
|
|
223
|
+
static #applyVariantMetadata(rootGroup, placement) {
|
|
224
|
+
const groupKey = String(
|
|
225
|
+
placement?.coLocatedVariantGroupKey || ''
|
|
226
|
+
).trim()
|
|
227
|
+
if (groupKey) {
|
|
228
|
+
rootGroup.userData.scene3dVariantGroupKey = groupKey
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Resolves static body display color.
|
|
234
|
+
* @param {{ bodyColor?: object, geometry?: object }} placement Static body placement.
|
|
235
|
+
* @returns {number}
|
|
236
|
+
*/
|
|
237
|
+
static #resolveColor(placement) {
|
|
238
|
+
const rawColor = Number(
|
|
239
|
+
placement?.bodyColor?.raw ??
|
|
240
|
+
placement?.geometry?.bodyColor?.raw ??
|
|
241
|
+
placement?.geometry?.color
|
|
242
|
+
)
|
|
243
|
+
return Number.isInteger(rawColor)
|
|
244
|
+
? rawColor
|
|
245
|
+
: PcbScene3dStaticBodyFactory.#DEFAULT_COLOR
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Resolves static body opacity.
|
|
250
|
+
* @param {{ bodyOpacity?: number, geometry?: object }} placement Static body placement.
|
|
251
|
+
* @returns {number}
|
|
252
|
+
*/
|
|
253
|
+
static #resolveOpacity(placement) {
|
|
254
|
+
const opacity = Number(
|
|
255
|
+
placement?.bodyOpacity ?? placement?.geometry?.bodyOpacity
|
|
256
|
+
)
|
|
257
|
+
if (!Number.isFinite(opacity)) {
|
|
258
|
+
return 1
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
return Math.min(1, Math.max(0, opacity))
|
|
262
|
+
}
|
|
263
|
+
}
|
package/src/PcbScene3dText.mjs
CHANGED
|
@@ -49,6 +49,7 @@ const FALLBACK_MESSAGES = {
|
|
|
49
49
|
'scene3d.skipped': 'Skipped',
|
|
50
50
|
'scene3d.source': 'Source',
|
|
51
51
|
'scene3d.startFailed': '3D preview could not start:',
|
|
52
|
+
'scene3d.staticBody': 'Static body',
|
|
52
53
|
'scene3d.stillPreparing': '3D scene is still preparing.',
|
|
53
54
|
'scene3d.title': '3D preview',
|
|
54
55
|
'scene3d.to': 'to',
|