pcb-scene3d-viewer 1.1.18 → 1.1.19
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
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
* Resolves camera presets and basic rig state for the PCB 3D scene.
|
|
3
3
|
*/
|
|
4
4
|
export class PcbScene3dCameraRig {
|
|
5
|
+
static #INSPECTION_PROJECTION_STATE_KEY = 'scene3dInspectionProjection'
|
|
6
|
+
|
|
5
7
|
/**
|
|
6
8
|
* Resolves the initial camera radius from the board size.
|
|
7
9
|
* @param {{ board?: { widthMil?: number, heightMil?: number }, sourceFormat?: string }} sceneDescription
|
|
@@ -111,6 +113,15 @@ export class PcbScene3dCameraRig {
|
|
|
111
113
|
camera?.lookAt?.(pose.target.x, pose.target.y, pose.target.z)
|
|
112
114
|
controls?.update?.()
|
|
113
115
|
camera?.updateProjectionMatrix?.()
|
|
116
|
+
if (normalizedPreset === 'top' || normalizedPreset === 'bottom') {
|
|
117
|
+
PcbScene3dCameraRig.#applyInspectionProjection(
|
|
118
|
+
camera,
|
|
119
|
+
controls,
|
|
120
|
+
pose
|
|
121
|
+
)
|
|
122
|
+
} else {
|
|
123
|
+
PcbScene3dCameraRig.#restoreProjection(camera, controls)
|
|
124
|
+
}
|
|
114
125
|
|
|
115
126
|
return pose
|
|
116
127
|
}
|
|
@@ -166,6 +177,174 @@ export class PcbScene3dCameraRig {
|
|
|
166
177
|
}
|
|
167
178
|
}
|
|
168
179
|
|
|
180
|
+
/**
|
|
181
|
+
* Replaces perspective projection with orthographic projection for
|
|
182
|
+
* top/bottom inspection views.
|
|
183
|
+
* @param {object} camera Three.js perspective camera.
|
|
184
|
+
* @param {object} controls OrbitControls-like instance.
|
|
185
|
+
* @param {object} pose Resolved camera pose.
|
|
186
|
+
* @returns {void}
|
|
187
|
+
*/
|
|
188
|
+
static #applyInspectionProjection(camera, controls, pose) {
|
|
189
|
+
if (!camera || !pose?.target || !pose?.radius) {
|
|
190
|
+
return
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
const state = PcbScene3dCameraRig.#captureProjectionState(
|
|
194
|
+
camera,
|
|
195
|
+
controls
|
|
196
|
+
)
|
|
197
|
+
const radius = Math.max(Number(pose.radius || 0), 1)
|
|
198
|
+
const fovRadians = (Number(camera.fov || 38) * Math.PI) / 180
|
|
199
|
+
|
|
200
|
+
state.active = true
|
|
201
|
+
state.orthographicHeight = 2 * radius * Math.tan(fovRadians / 2)
|
|
202
|
+
PcbScene3dCameraRig.#applyOrthographicProjection(camera, state)
|
|
203
|
+
controls?.update?.()
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/**
|
|
207
|
+
* Captures the first unmodified projection settings for a camera.
|
|
208
|
+
* @param {object} camera Three.js camera.
|
|
209
|
+
* @param {object} controls OrbitControls-like instance.
|
|
210
|
+
* @returns {object}
|
|
211
|
+
*/
|
|
212
|
+
static #captureProjectionState(camera, controls) {
|
|
213
|
+
const userData = PcbScene3dCameraRig.#userData(camera)
|
|
214
|
+
const stateKey = PcbScene3dCameraRig.#INSPECTION_PROJECTION_STATE_KEY
|
|
215
|
+
|
|
216
|
+
if (!userData[stateKey]) {
|
|
217
|
+
userData[stateKey] = {
|
|
218
|
+
active: false,
|
|
219
|
+
orthographicHeight: 0,
|
|
220
|
+
originalUpdateProjectionMatrix:
|
|
221
|
+
camera.updateProjectionMatrix?.bind?.(camera) || null,
|
|
222
|
+
isPerspectiveCamera: camera.isPerspectiveCamera,
|
|
223
|
+
isOrthographicCamera: camera.isOrthographicCamera,
|
|
224
|
+
left: camera.left,
|
|
225
|
+
right: camera.right,
|
|
226
|
+
top: camera.top,
|
|
227
|
+
bottom: camera.bottom,
|
|
228
|
+
zoom: Number(camera?.zoom || 1),
|
|
229
|
+
near: Number(camera?.near || 0),
|
|
230
|
+
far: Number(camera?.far || 0),
|
|
231
|
+
maxDistance: Number(controls?.maxDistance || 0)
|
|
232
|
+
}
|
|
233
|
+
PcbScene3dCameraRig.#patchCameraProjectionUpdater(camera)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
return userData[stateKey]
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
/**
|
|
240
|
+
* Patches projection updates so orthographic inspection survives resizes.
|
|
241
|
+
* @param {object} camera Three.js camera.
|
|
242
|
+
* @returns {void}
|
|
243
|
+
*/
|
|
244
|
+
static #patchCameraProjectionUpdater(camera) {
|
|
245
|
+
const state =
|
|
246
|
+
camera.userData[
|
|
247
|
+
PcbScene3dCameraRig.#INSPECTION_PROJECTION_STATE_KEY
|
|
248
|
+
]
|
|
249
|
+
|
|
250
|
+
if (!state?.originalUpdateProjectionMatrix) {
|
|
251
|
+
return
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
camera.updateProjectionMatrix = () => {
|
|
255
|
+
state.originalUpdateProjectionMatrix()
|
|
256
|
+
if (state.active) {
|
|
257
|
+
PcbScene3dCameraRig.#applyOrthographicProjection(camera, state)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Applies an orthographic projection matrix to the existing camera.
|
|
264
|
+
* @param {object} camera Three.js camera.
|
|
265
|
+
* @param {object} state Captured camera state.
|
|
266
|
+
* @returns {void}
|
|
267
|
+
*/
|
|
268
|
+
static #applyOrthographicProjection(camera, state) {
|
|
269
|
+
const zoom = Math.max(Number(camera.zoom || 1), 0.0001)
|
|
270
|
+
const height = Math.max(Number(state.orthographicHeight || 0) / zoom, 1)
|
|
271
|
+
const width = height * Math.max(Number(camera.aspect || 1), 0.0001)
|
|
272
|
+
const left = -width / 2
|
|
273
|
+
const right = width / 2
|
|
274
|
+
const top = height / 2
|
|
275
|
+
const bottom = -height / 2
|
|
276
|
+
|
|
277
|
+
camera.left = left
|
|
278
|
+
camera.right = right
|
|
279
|
+
camera.top = top
|
|
280
|
+
camera.bottom = bottom
|
|
281
|
+
camera.isPerspectiveCamera = false
|
|
282
|
+
camera.isOrthographicCamera = true
|
|
283
|
+
camera.projectionMatrix?.makeOrthographic?.(
|
|
284
|
+
left,
|
|
285
|
+
right,
|
|
286
|
+
top,
|
|
287
|
+
bottom,
|
|
288
|
+
camera.near,
|
|
289
|
+
camera.far
|
|
290
|
+
)
|
|
291
|
+
camera.projectionMatrixInverse
|
|
292
|
+
?.copy?.(camera.projectionMatrix)
|
|
293
|
+
?.invert?.()
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Restores perspective settings after leaving top/bottom inspection views.
|
|
298
|
+
* @param {object} camera Three.js camera.
|
|
299
|
+
* @param {object} controls OrbitControls-like instance.
|
|
300
|
+
* @returns {void}
|
|
301
|
+
*/
|
|
302
|
+
static #restoreProjection(camera, controls) {
|
|
303
|
+
const state =
|
|
304
|
+
camera?.userData?.[
|
|
305
|
+
PcbScene3dCameraRig.#INSPECTION_PROJECTION_STATE_KEY
|
|
306
|
+
]
|
|
307
|
+
|
|
308
|
+
if (!state) {
|
|
309
|
+
return
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
if ('zoom' in camera) {
|
|
313
|
+
camera.zoom = state.zoom
|
|
314
|
+
}
|
|
315
|
+
if ('near' in camera && state.near > 0) {
|
|
316
|
+
camera.near = state.near
|
|
317
|
+
}
|
|
318
|
+
if ('far' in camera && state.far > 0) {
|
|
319
|
+
camera.far = state.far
|
|
320
|
+
}
|
|
321
|
+
camera.isPerspectiveCamera = state.isPerspectiveCamera
|
|
322
|
+
camera.isOrthographicCamera = state.isOrthographicCamera
|
|
323
|
+
camera.left = state.left
|
|
324
|
+
camera.right = state.right
|
|
325
|
+
camera.top = state.top
|
|
326
|
+
camera.bottom = state.bottom
|
|
327
|
+
if (controls && 'maxDistance' in controls && state.maxDistance > 0) {
|
|
328
|
+
controls.maxDistance = state.maxDistance
|
|
329
|
+
}
|
|
330
|
+
state.active = false
|
|
331
|
+
controls?.update?.()
|
|
332
|
+
camera.updateProjectionMatrix?.()
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Ensures a mutable user-data object exists on the camera.
|
|
337
|
+
* @param {object} camera Three.js camera.
|
|
338
|
+
* @returns {object}
|
|
339
|
+
*/
|
|
340
|
+
static #userData(camera) {
|
|
341
|
+
if (!camera.userData) {
|
|
342
|
+
camera.userData = {}
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
return camera.userData
|
|
346
|
+
}
|
|
347
|
+
|
|
169
348
|
/**
|
|
170
349
|
* Resolves screen-up for bottom views from the scene coordinate contract.
|
|
171
350
|
* @param {{ coordinateSystem?: string }} sceneDescription Scene metadata.
|