MCPcopy Create free account
hub / github.com/TechJeeper/Printventory / generateThumbnail

Function generateThumbnail

renderer.js:15613–15686  ·  view source on GitHub ↗
(file)

Source from the content-addressed store, hash-verified

15611}
15612
15613// NOTE: loadModel function is defined earlier in the file (around line 2840)
15614// This duplicate has been removed to use the enhanced version that checks for embedded images
15615
15616function fitCameraToObject(camera, object, scene, renderer) {
15617 // Orient first, then measure — otherwise large flat STLs (e.g. 400×420×4 plates)
15618 // get framed for the wrong bbox and often land past the camera far plane.
15619 object.rotation.x = -Math.PI / 2;
15620 object.updateMatrixWorld(true);
15621
15622 const boundingBox = new THREE.Box3().setFromObject(object);
15623 const size = boundingBox.getSize(new THREE.Vector3());
15624 const center = boundingBox.getCenter(new THREE.Vector3());
15625
15626 if (Number.isFinite(center.x) && Number.isFinite(center.y) && Number.isFinite(center.z)) {
15627 object.position.sub(center);
15628 object.updateMatrixWorld(true);
15629 }
15630
15631 const fittedBox = new THREE.Box3().setFromObject(object);
15632 const fittedSize = fittedBox.getSize(new THREE.Vector3());
15633 const maxDim = Math.max(fittedSize.x, fittedSize.y, fittedSize.z, 1e-3);
15634
15635 const fov = camera.fov * (Math.PI / 180);
15636 const tanHalfFov = Math.tan(fov / 2);
15637 let cameraZ =
15638 maxDim > 0 && tanHalfFov > 0
15639 ? Math.abs(maxDim / 2 / tanHalfFov) * 1.5
15640 : 5;
15641 if (!Number.isFinite(cameraZ) || cameraZ <= 0) cameraZ = 5;
15642
15643 // Camera sits on the (z,z,z) diagonal — keep far plane beyond that distance.
15644 const cameraDistance = cameraZ * Math.sqrt(3);
15645 camera.near = Math.max(0.01, cameraDistance / 1000);
15646 camera.far = Math.max(10000, cameraDistance * 20);
15647 camera.updateProjectionMatrix();
15648
15649 camera.position.set(cameraZ, cameraZ, cameraZ);
15650 camera.lookAt(0, 0, 0);
15651
15652 renderer.render(scene, camera);
15653}
15654
15655/** True when a thumbnail data-URL is effectively empty (transparent / clipped render). */
15656function isMostlyEmptyThumbnailDataUrl(dataUrl) {
15657 return new Promise((resolve) => {
15658 if (!dataUrl || typeof dataUrl !== 'string' || !dataUrl.startsWith('data:image')) {
15659 resolve(true);
15660 return;
15661 }
15662 const img = new Image();
15663 img.onload = () => {
15664 try {
15665 const w = Math.min(64, img.width || 64);
15666 const h = Math.min(64, img.height || 64);
15667 const canvas = document.createElement('canvas');
15668 canvas.width = w;
15669 canvas.height = h;
15670 const ctx = canvas.getContext('2d', { willReadFrequently: true });

Callers 1

processModelFunction · 0.85

Calls 3

extract3MFThumbnailFunction · 0.85
renderModelToPNGFunction · 0.85
debugLogFunction · 0.70

Tested by

no test coverage detected