pcb-scene3d-viewer 1.0.1
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/AGENTS.md +67 -0
- package/COMMERCIAL-LICENSE.md +15 -0
- package/CONTRIBUTING.md +14 -0
- package/LICENSE +19 -0
- package/LICENSES/AGPL-3.0-or-later.txt +235 -0
- package/LICENSES/CC-BY-SA-4.0.txt +170 -0
- package/LICENSES/LGPL-2.1-or-later.txt +176 -0
- package/LICENSES/LicenseRef-PolyForm-Noncommercial-1.0.0.txt +131 -0
- package/NOTICE.md +36 -0
- package/README.md +128 -0
- package/REUSE.toml +16 -0
- package/docs/api.md +148 -0
- package/docs/circuitjson.md +190 -0
- package/docs/model-format.md +117 -0
- package/docs/testing.md +23 -0
- package/package.json +65 -0
- package/spec/library-scope.md +36 -0
- package/src/PcbModelArchiveExporter.mjs +320 -0
- package/src/PcbScene3dArcUtils.mjs +27 -0
- package/src/PcbScene3dBoardAssemblyPlacement.mjs +36 -0
- package/src/PcbScene3dBoardAssemblyPresentation.mjs +859 -0
- package/src/PcbScene3dBoardEdgeCutoutBuilder.mjs +537 -0
- package/src/PcbScene3dBoardMaterialPalette.mjs +40 -0
- package/src/PcbScene3dBoardShapeFactory.mjs +895 -0
- package/src/PcbScene3dBoardSolderMaskFactory.mjs +613 -0
- package/src/PcbScene3dCameraRig.mjs +168 -0
- package/src/PcbScene3dCircuitJsonAdapter.mjs +545 -0
- package/src/PcbScene3dController.mjs +956 -0
- package/src/PcbScene3dCopperDetailFilter.mjs +490 -0
- package/src/PcbScene3dCopperFactory.mjs +559 -0
- package/src/PcbScene3dCopperTextFactory.mjs +534 -0
- package/src/PcbScene3dCutoutGeometryFilter.mjs +873 -0
- package/src/PcbScene3dDetailCoordinateNormalizer.mjs +65 -0
- package/src/PcbScene3dDrillCutoutFilter.mjs +224 -0
- package/src/PcbScene3dDrillPathFactory.mjs +362 -0
- package/src/PcbScene3dDrillVoidFactory.mjs +268 -0
- package/src/PcbScene3dExternalModelLoadOrder.mjs +54 -0
- package/src/PcbScene3dExternalModels.mjs +968 -0
- package/src/PcbScene3dFallbackVisibility.mjs +82 -0
- package/src/PcbScene3dInteractionHints.mjs +56 -0
- package/src/PcbScene3dMountRig.mjs +53 -0
- package/src/PcbScene3dOutlineBuilder.mjs +210 -0
- package/src/PcbScene3dPadFactory.mjs +553 -0
- package/src/PcbScene3dPresetState.mjs +48 -0
- package/src/PcbScene3dRenderGroupVisibility.mjs +134 -0
- package/src/PcbScene3dRuntime.mjs +996 -0
- package/src/PcbScene3dRuntimeBoardMeshes.mjs +99 -0
- package/src/PcbScene3dSelectionStyler.mjs +252 -0
- package/src/PcbScene3dShapePathFactory.mjs +220 -0
- package/src/PcbScene3dShellRenderer.mjs +131 -0
- package/src/PcbScene3dSilkscreenFactory.mjs +854 -0
- package/src/PcbScene3dSilkscreenStrokeWidthResolver.mjs +81 -0
- package/src/PcbScene3dStepLoader.mjs +611 -0
- package/src/PcbScene3dStrokeFont.mjs +671 -0
- package/src/PcbScene3dStrokeGeometryBuilder.mjs +322 -0
- package/src/PcbScene3dText.mjs +99 -0
- package/src/PcbScene3dTrueTypeTextFactory.mjs +885 -0
- package/src/PcbScene3dViaFactory.mjs +176 -0
- package/src/PcbScene3dViewCompensation.mjs +109 -0
- package/src/PcbScene3dViewScale.mjs +24 -0
- package/src/PcbScene3dViewportResize.mjs +35 -0
- package/src/PcbScene3dWorkerClient.mjs +123 -0
- package/src/index.mjs +1 -0
- package/src/scene3d.mjs +44 -0
- package/src/styles/scene3d.css +295 -0
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolves camera presets and basic rig state for the PCB 3D scene.
|
|
3
|
+
*/
|
|
4
|
+
export class PcbScene3dCameraRig {
|
|
5
|
+
/**
|
|
6
|
+
* Resolves the initial camera radius from the board size.
|
|
7
|
+
* @param {{ board?: { widthMil?: number, heightMil?: number }, sourceFormat?: string }} sceneDescription
|
|
8
|
+
* @returns {number}
|
|
9
|
+
*/
|
|
10
|
+
static resolveInitialRadius(sceneDescription) {
|
|
11
|
+
const width = Number(sceneDescription?.board?.widthMil || 0)
|
|
12
|
+
const height = Number(sceneDescription?.board?.heightMil || 0)
|
|
13
|
+
return Math.max(width, height, 800) * 1.9
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Resolves one named camera preset into a z-up camera pose.
|
|
18
|
+
* @param {string} preset
|
|
19
|
+
* @param {{ board?: { widthMil?: number, heightMil?: number }, sourceFormat?: string }} sceneDescription
|
|
20
|
+
* @param {{ radius?: number, target?: { x?: number, y?: number, z?: number } }} [options]
|
|
21
|
+
* @returns {{ radius: number, target: { x: number, y: number, z: number }, up: { x: number, y: number, z: number }, position: { x: number, y: number, z: number } }}
|
|
22
|
+
*/
|
|
23
|
+
static resolvePreset(preset, sceneDescription, options = {}) {
|
|
24
|
+
const normalizedPreset = String(preset || 'isometric').toLowerCase()
|
|
25
|
+
const radius =
|
|
26
|
+
Number(options.radius) ||
|
|
27
|
+
PcbScene3dCameraRig.resolveInitialRadius(sceneDescription)
|
|
28
|
+
const target = {
|
|
29
|
+
x: Number(options.target?.x || 0),
|
|
30
|
+
y: Number(options.target?.y || 0),
|
|
31
|
+
z: Number(options.target?.z || 0)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (normalizedPreset === 'top') {
|
|
35
|
+
return {
|
|
36
|
+
radius,
|
|
37
|
+
target,
|
|
38
|
+
up: { x: 0, y: 1, z: 0 },
|
|
39
|
+
position: {
|
|
40
|
+
x: target.x,
|
|
41
|
+
y: target.y,
|
|
42
|
+
z: target.z + radius
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (normalizedPreset === 'bottom') {
|
|
48
|
+
return {
|
|
49
|
+
radius,
|
|
50
|
+
target,
|
|
51
|
+
up: { x: 0, y: -1, z: 0 },
|
|
52
|
+
position: {
|
|
53
|
+
x: target.x,
|
|
54
|
+
y: target.y,
|
|
55
|
+
z: target.z - radius
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
const theta = -Math.PI / 4
|
|
61
|
+
const phi = Math.PI / 3.3
|
|
62
|
+
|
|
63
|
+
return {
|
|
64
|
+
radius,
|
|
65
|
+
target,
|
|
66
|
+
up: { x: 0, y: 0, z: 1 },
|
|
67
|
+
position: PcbScene3dCameraRig.#resolvePosition(
|
|
68
|
+
theta,
|
|
69
|
+
phi,
|
|
70
|
+
radius,
|
|
71
|
+
target
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Applies one preset to a Three camera and optional OrbitControls instance.
|
|
78
|
+
* @param {{ position?: { set?: (x: number, y: number, z: number) => void }, up?: { set?: (x: number, y: number, z: number) => void }, lookAt?: (x: number, y: number, z: number) => void, updateProjectionMatrix?: () => void }} camera
|
|
79
|
+
* @param {{ target?: { x?: number, y?: number, z?: number, set?: (x: number, y: number, z: number) => void }, update?: () => void }} [controls]
|
|
80
|
+
* @param {string} preset
|
|
81
|
+
* @param {{ board?: { widthMil?: number, heightMil?: number }, sourceFormat?: string }} sceneDescription
|
|
82
|
+
* @returns {{ radius: number, target: { x: number, y: number, z: number }, up: { x: number, y: number, z: number }, position: { x: number, y: number, z: number } }}
|
|
83
|
+
*/
|
|
84
|
+
static applyPreset(camera, controls, preset, sceneDescription) {
|
|
85
|
+
const normalizedPreset = String(preset || 'isometric').toLowerCase()
|
|
86
|
+
const resetsView =
|
|
87
|
+
normalizedPreset === 'isometric' || normalizedPreset === 'reset'
|
|
88
|
+
const pose = PcbScene3dCameraRig.resolvePreset(
|
|
89
|
+
normalizedPreset,
|
|
90
|
+
sceneDescription,
|
|
91
|
+
{
|
|
92
|
+
radius: resetsView
|
|
93
|
+
? PcbScene3dCameraRig.resolveInitialRadius(sceneDescription)
|
|
94
|
+
: PcbScene3dCameraRig.#resolveCurrentRadius(
|
|
95
|
+
camera,
|
|
96
|
+
controls
|
|
97
|
+
),
|
|
98
|
+
target: resetsView
|
|
99
|
+
? { x: 0, y: 0, z: 0 }
|
|
100
|
+
: PcbScene3dCameraRig.#resolveCurrentTarget(controls)
|
|
101
|
+
}
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
camera?.up?.set?.(pose.up.x, pose.up.y, pose.up.z)
|
|
105
|
+
controls?.target?.set?.(pose.target.x, pose.target.y, pose.target.z)
|
|
106
|
+
camera?.position?.set?.(
|
|
107
|
+
pose.position.x,
|
|
108
|
+
pose.position.y,
|
|
109
|
+
pose.position.z
|
|
110
|
+
)
|
|
111
|
+
camera?.lookAt?.(pose.target.x, pose.target.y, pose.target.z)
|
|
112
|
+
controls?.update?.()
|
|
113
|
+
camera?.updateProjectionMatrix?.()
|
|
114
|
+
|
|
115
|
+
return pose
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Resolves one camera position from spherical coordinates in a z-up world.
|
|
120
|
+
* @param {number} theta
|
|
121
|
+
* @param {number} phi
|
|
122
|
+
* @param {number} radius
|
|
123
|
+
* @param {{ x: number, y: number, z: number }} target
|
|
124
|
+
* @returns {{ x: number, y: number, z: number }}
|
|
125
|
+
*/
|
|
126
|
+
static #resolvePosition(theta, phi, radius, target) {
|
|
127
|
+
const sinPhi = Math.sin(phi)
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
x: target.x + radius * sinPhi * Math.cos(theta),
|
|
131
|
+
y: target.y + radius * sinPhi * Math.sin(theta),
|
|
132
|
+
z: target.z + radius * Math.cos(phi)
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* Resolves the current camera radius from the camera-target distance.
|
|
138
|
+
* @param {{ position?: { x?: number, y?: number, z?: number } }} [camera]
|
|
139
|
+
* @param {{ target?: { x?: number, y?: number, z?: number } }} [controls]
|
|
140
|
+
* @returns {number}
|
|
141
|
+
*/
|
|
142
|
+
static #resolveCurrentRadius(camera, controls) {
|
|
143
|
+
const position = camera?.position || {}
|
|
144
|
+
const target = controls?.target || {}
|
|
145
|
+
|
|
146
|
+
return Math.max(
|
|
147
|
+
Math.hypot(
|
|
148
|
+
Number(position.x || 0) - Number(target.x || 0),
|
|
149
|
+
Number(position.y || 0) - Number(target.y || 0),
|
|
150
|
+
Number(position.z || 0) - Number(target.z || 0)
|
|
151
|
+
),
|
|
152
|
+
1
|
|
153
|
+
)
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/**
|
|
157
|
+
* Resolves the current controls target into a plain object.
|
|
158
|
+
* @param {{ target?: { x?: number, y?: number, z?: number } }} [controls]
|
|
159
|
+
* @returns {{ x: number, y: number, z: number }}
|
|
160
|
+
*/
|
|
161
|
+
static #resolveCurrentTarget(controls) {
|
|
162
|
+
return {
|
|
163
|
+
x: Number(controls?.target?.x || 0),
|
|
164
|
+
y: Number(controls?.target?.y || 0),
|
|
165
|
+
z: Number(controls?.target?.z || 0)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|