Fix DICOM UPP model pivot
This commit is contained in:
@@ -94,6 +94,8 @@ const state = {
|
|||||||
modelMeshes: [],
|
modelMeshes: [],
|
||||||
stlSignature: "",
|
stlSignature: "",
|
||||||
baseModelScale: 1,
|
baseModelScale: 1,
|
||||||
|
modelBoundsFrame: null,
|
||||||
|
modelLocalBounds: null,
|
||||||
dicomSceneBox: null,
|
dicomSceneBox: null,
|
||||||
mappingViewport: { scale: 1, offsetX: 0, offsetY: 0, rotation: 0 },
|
mappingViewport: { scale: 1, offsetX: 0, offsetY: 0, rotation: 0 },
|
||||||
mappingDrag: null,
|
mappingDrag: null,
|
||||||
@@ -1018,6 +1020,8 @@ function clearFusion() {
|
|||||||
state.dicomPlane = null;
|
state.dicomPlane = null;
|
||||||
state.dicomPoints = null;
|
state.dicomPoints = null;
|
||||||
state.dicomSlicePlanes = [];
|
state.dicomSlicePlanes = [];
|
||||||
|
state.modelBoundsFrame = null;
|
||||||
|
state.modelLocalBounds = null;
|
||||||
$("fusionMeta").textContent = "DICOM - · STL -";
|
$("fusionMeta").textContent = "DICOM - · STL -";
|
||||||
$("fusionStatus").textContent = "等待选择 DICOM 与 STL";
|
$("fusionStatus").textContent = "等待选择 DICOM 与 STL";
|
||||||
updateSliceControl();
|
updateSliceControl();
|
||||||
@@ -1449,6 +1453,7 @@ async function buildDicomVolume(volume) {
|
|||||||
const centerIndex = Number(volume.center || 0);
|
const centerIndex = Number(volume.center || 0);
|
||||||
const total = Math.max(1, Number(volume.total || 1));
|
const total = Math.max(1, Number(volume.total || 1));
|
||||||
const indices = volume.indices || [];
|
const indices = volume.indices || [];
|
||||||
|
const frames = volume.frames || [];
|
||||||
const centerPosition = indices.length ? Math.floor(indices.length / 2) : 0;
|
const centerPosition = indices.length ? Math.floor(indices.length / 2) : 0;
|
||||||
state.volumeScene = {
|
state.volumeScene = {
|
||||||
width,
|
width,
|
||||||
@@ -1477,7 +1482,7 @@ async function buildDicomVolume(volume) {
|
|||||||
const rangeDepth = Math.max(0.015, Math.abs(sliceToSceneZ(localEnd) - sliceToSceneZ(localStart)));
|
const rangeDepth = Math.max(0.015, Math.abs(sliceToSceneZ(localEnd) - sliceToSceneZ(localStart)));
|
||||||
const rangeBox = new THREE.LineSegments(
|
const rangeBox = new THREE.LineSegments(
|
||||||
new THREE.EdgesGeometry(new THREE.BoxGeometry(width * 0.94, height * 0.94, rangeDepth)),
|
new THREE.EdgesGeometry(new THREE.BoxGeometry(width * 0.94, height * 0.94, rangeDepth)),
|
||||||
new THREE.LineBasicMaterial({ color: 0xfacc15, transparent: true, opacity: 0.56 }),
|
new THREE.LineBasicMaterial({ color: 0x38bdf8, transparent: true, opacity: 0.24 }),
|
||||||
);
|
);
|
||||||
rangeBox.position.z = (sliceToSceneZ(localStart) + sliceToSceneZ(localEnd)) / 2;
|
rangeBox.position.z = (sliceToSceneZ(localStart) + sliceToSceneZ(localEnd)) / 2;
|
||||||
state.dicomGroup.add(rangeBox);
|
state.dicomGroup.add(rangeBox);
|
||||||
@@ -1527,7 +1532,6 @@ async function buildDicomVolume(volume) {
|
|||||||
|
|
||||||
const pointPositions = [];
|
const pointPositions = [];
|
||||||
const pointColors = [];
|
const pointColors = [];
|
||||||
const frames = volume.frames || [];
|
|
||||||
for (const [index, frame] of frames.entries()) {
|
for (const [index, frame] of frames.entries()) {
|
||||||
const image = await loadImageData(frame, 180);
|
const image = await loadImageData(frame, 180);
|
||||||
const stride = Math.max(2, Math.round(Math.max(image.width, image.height) / fusionDetail.pointGrid));
|
const stride = Math.max(2, Math.round(Math.max(image.width, image.height) / fusionDetail.pointGrid));
|
||||||
@@ -1578,6 +1582,8 @@ async function buildStlModels(volume, onProgress = null) {
|
|||||||
}
|
}
|
||||||
clearGroup(state.rawModelGroup);
|
clearGroup(state.rawModelGroup);
|
||||||
state.modelMeshes = [];
|
state.modelMeshes = [];
|
||||||
|
state.modelBoundsFrame = null;
|
||||||
|
state.modelLocalBounds = null;
|
||||||
state.stlSignature = signature;
|
state.stlSignature = signature;
|
||||||
const files = state.stlFiles.filter((file) => state.selectedStlIds.has(Number(file.id)));
|
const files = state.stlFiles.filter((file) => state.selectedStlIds.has(Number(file.id)));
|
||||||
if (!files.length) {
|
if (!files.length) {
|
||||||
@@ -1618,8 +1624,33 @@ async function buildStlModels(volume, onProgress = null) {
|
|||||||
}
|
}
|
||||||
const bbox = new THREE.Box3().setFromObject(state.rawModelGroup);
|
const bbox = new THREE.Box3().setFromObject(state.rawModelGroup);
|
||||||
const center = new THREE.Vector3();
|
const center = new THREE.Vector3();
|
||||||
|
const size = new THREE.Vector3();
|
||||||
bbox.getCenter(center);
|
bbox.getCenter(center);
|
||||||
state.rawModelGroup.position.set(-center.x, -center.y, -center.z);
|
bbox.getSize(size);
|
||||||
|
state.rawModelGroup.position.set(0, 0, 0);
|
||||||
|
state.rawModelGroup.traverse((object) => {
|
||||||
|
if (!object.geometry) return;
|
||||||
|
object.geometry.translate(-center.x, -center.y, -center.z);
|
||||||
|
object.geometry.computeBoundingBox?.();
|
||||||
|
object.geometry.computeBoundingSphere?.();
|
||||||
|
object.geometry.computeVertexNormals?.();
|
||||||
|
});
|
||||||
|
const maxModelSize = Math.max(size.x, size.y, size.z, 1);
|
||||||
|
const volumeSize = state.volumeScene
|
||||||
|
? Math.max(state.volumeScene.width, state.volumeScene.height, state.volumeScene.depth, 1)
|
||||||
|
: 4.8;
|
||||||
|
state.baseModelScale = (volumeSize / maxModelSize) * 0.92;
|
||||||
|
state.modelLocalBounds = {
|
||||||
|
center: { x: center.x, y: center.y, z: center.z },
|
||||||
|
size: { x: size.x, y: size.y, z: size.z },
|
||||||
|
};
|
||||||
|
const modelBounds = new THREE.LineSegments(
|
||||||
|
new THREE.EdgesGeometry(new THREE.BoxGeometry(size.x, size.y, size.z)),
|
||||||
|
new THREE.LineBasicMaterial({ color: 0xfacc15, transparent: true, opacity: 0.78 }),
|
||||||
|
);
|
||||||
|
modelBounds.name = "model-bounds";
|
||||||
|
state.rawModelGroup.add(modelBounds);
|
||||||
|
state.modelBoundsFrame = modelBounds;
|
||||||
applyPose();
|
applyPose();
|
||||||
scheduleMappingDraw();
|
scheduleMappingDraw();
|
||||||
onProgress?.(100);
|
onProgress?.(100);
|
||||||
|
|||||||
Reference in New Issue
Block a user