|
|
|
|
@@ -122,6 +122,11 @@ const zeroBasePoint: PreviewResolvedBasePoint = {
|
|
|
|
|
ry: 0,
|
|
|
|
|
rz: 0
|
|
|
|
|
};
|
|
|
|
|
const RAD_TO_DEG = 180 / Math.PI;
|
|
|
|
|
const DEG_TO_RAD = Math.PI / 180;
|
|
|
|
|
const BASE_POINT_DECIMAL_PLACES = 3;
|
|
|
|
|
const THUMBNAIL_WIDTH = 512;
|
|
|
|
|
const THUMBNAIL_HEIGHT = 384;
|
|
|
|
|
|
|
|
|
|
const previewEnvironmentUrl = "/DayCityOutdoor.exr";
|
|
|
|
|
const DEFAULT_PREVIEW_FRAME_INTERVAL_MS = 20;
|
|
|
|
|
@@ -179,12 +184,12 @@ export function openModelPreview(
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="preview-basepoint-grid">
|
|
|
|
|
<label><span>X</span><input name="baseX" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>Y</span><input name="baseY" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>Z</span><input name="baseZ" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>RX</span><input name="baseRx" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>RY</span><input name="baseRy" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>RZ</span><input name="baseRz" type="number" value="0" step="0.001" /></label>
|
|
|
|
|
<label><span>X(mm)</span><input name="baseX" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
<label><span>Y(mm)</span><input name="baseY" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
<label><span>Z(mm)</span><input name="baseZ" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
<label><span>RX(°)</span><input name="baseRx" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
<label><span>RY(°)</span><input name="baseRy" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
<label><span>RZ(°)</span><input name="baseRz" type="number" value="0.000" step="0.001" /></label>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -245,7 +250,7 @@ export function setPreviewBasePoint(basePoint: PreviewBasePoint, enabled = true)
|
|
|
|
|
for (const [key, name] of fieldMap) {
|
|
|
|
|
const input = document.querySelector<HTMLInputElement>(`.preview-basepoint-grid input[name="${name}"]`);
|
|
|
|
|
if (input && basePoint[key] !== undefined) {
|
|
|
|
|
input.value = String(basePoint[key]);
|
|
|
|
|
input.value = formatBasePointDisplayValue(key, basePoint[key]);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -596,15 +601,31 @@ async function screenshotModel(modelId: number, onThumbnailSaved?: () => Promise
|
|
|
|
|
controls.update();
|
|
|
|
|
const oldBackground = scene.background;
|
|
|
|
|
const oldClearAlpha = renderer.getClearAlpha();
|
|
|
|
|
if (transparent) {
|
|
|
|
|
scene.background = null;
|
|
|
|
|
renderer.setClearColor(0x000000, 0);
|
|
|
|
|
}
|
|
|
|
|
renderer.render(scene, camera);
|
|
|
|
|
const thumbnail = renderer.domElement.toDataURL("image/png");
|
|
|
|
|
if (transparent) {
|
|
|
|
|
scene.background = oldBackground;
|
|
|
|
|
renderer.setClearAlpha(oldClearAlpha);
|
|
|
|
|
const oldPixelRatio = renderer.getPixelRatio();
|
|
|
|
|
const oldWidth = renderer.domElement.width / oldPixelRatio;
|
|
|
|
|
const oldHeight = renderer.domElement.height / oldPixelRatio;
|
|
|
|
|
const oldAspect = camera.aspect;
|
|
|
|
|
let thumbnail = "";
|
|
|
|
|
try {
|
|
|
|
|
if (transparent) {
|
|
|
|
|
scene.background = null;
|
|
|
|
|
renderer.setClearColor(0x000000, 0);
|
|
|
|
|
}
|
|
|
|
|
renderer.setPixelRatio(1);
|
|
|
|
|
renderer.setSize(THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT, false);
|
|
|
|
|
camera.aspect = THUMBNAIL_WIDTH / THUMBNAIL_HEIGHT;
|
|
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
renderer.render(scene, camera);
|
|
|
|
|
thumbnail = renderer.domElement.toDataURL("image/png");
|
|
|
|
|
} finally {
|
|
|
|
|
camera.aspect = oldAspect;
|
|
|
|
|
camera.updateProjectionMatrix();
|
|
|
|
|
renderer.setPixelRatio(oldPixelRatio);
|
|
|
|
|
renderer.setSize(oldWidth, oldHeight, false);
|
|
|
|
|
if (transparent) {
|
|
|
|
|
scene.background = oldBackground;
|
|
|
|
|
renderer.setClearAlpha(oldClearAlpha);
|
|
|
|
|
}
|
|
|
|
|
renderer.render(scene, camera);
|
|
|
|
|
}
|
|
|
|
|
await api(`/api/models/${modelId}/thumbnail`, {
|
|
|
|
|
@@ -626,12 +647,12 @@ function getSelectedOperation(operations: PreviewOperation[]) {
|
|
|
|
|
|
|
|
|
|
function readPreviewBasePoint(): PreviewResolvedBasePoint {
|
|
|
|
|
return resolveBasePoint({
|
|
|
|
|
x: readNumberInput("baseX"),
|
|
|
|
|
y: readNumberInput("baseY"),
|
|
|
|
|
z: readNumberInput("baseZ"),
|
|
|
|
|
rx: readNumberInput("baseRx"),
|
|
|
|
|
ry: readNumberInput("baseRy"),
|
|
|
|
|
rz: readNumberInput("baseRz")
|
|
|
|
|
x: roundBasePointValue(readNumberInput("baseX")),
|
|
|
|
|
y: roundBasePointValue(readNumberInput("baseY")),
|
|
|
|
|
z: roundBasePointValue(readNumberInput("baseZ")),
|
|
|
|
|
rx: degreesToRadians(readNumberInput("baseRx")),
|
|
|
|
|
ry: degreesToRadians(readNumberInput("baseRy")),
|
|
|
|
|
rz: degreesToRadians(readNumberInput("baseRz"))
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -641,6 +662,30 @@ function readNumberInput(name: string) {
|
|
|
|
|
return Number.isFinite(numberValue) ? numberValue : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatBasePointDisplayValue(key: keyof PreviewResolvedBasePoint, value: number) {
|
|
|
|
|
const displayValue = key === "rx" || key === "ry" || key === "rz"
|
|
|
|
|
? radiansToDegrees(value)
|
|
|
|
|
: value;
|
|
|
|
|
return formatBasePointNumber(displayValue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function radiansToDegrees(value: number) {
|
|
|
|
|
return roundBasePointValue(value * RAD_TO_DEG);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function degreesToRadians(value: number) {
|
|
|
|
|
return Number.isFinite(value) ? value * DEG_TO_RAD : 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function roundBasePointValue(value: number) {
|
|
|
|
|
if (!Number.isFinite(value)) return 0;
|
|
|
|
|
return Number(value.toFixed(BASE_POINT_DECIMAL_PLACES));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function formatBasePointNumber(value: number) {
|
|
|
|
|
return roundBasePointValue(value).toFixed(BASE_POINT_DECIMAL_PLACES);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function bindImportScene(
|
|
|
|
|
model: ModelItem,
|
|
|
|
|
operations: PreviewOperation[],
|
|
|
|
|
|