2026-05-24-20-06-08 修正可见构件映射错位
This commit is contained in:
@@ -2110,6 +2110,8 @@ function drawVoxelOverlayLayer(
|
||||
preview: DicomPreview,
|
||||
files: string[],
|
||||
previews: Record<string, ModelPreviewPayload>,
|
||||
metricFiles: string[],
|
||||
metricPreviews: Record<string, ModelPreviewPayload>,
|
||||
moduleStyles: Record<string, ModuleStyle>,
|
||||
modelPose: ModelPose,
|
||||
slice: number,
|
||||
@@ -2124,7 +2126,8 @@ function drawVoxelOverlayLayer(
|
||||
}
|
||||
|
||||
context.clearRect(0, 0, fovCanvas.width, fovCanvas.height);
|
||||
const metrics = getModelSceneMetrics(files, previews, preview, totalSlices);
|
||||
const metrics = getModelSceneMetrics(metricFiles, metricPreviews, preview, totalSlices)
|
||||
?? getModelSceneMetrics(files, previews, preview, totalSlices);
|
||||
if (!metrics) {
|
||||
return { activeModules: 0, filledPixels: 0, segmentCount: 0, modules: [] };
|
||||
}
|
||||
@@ -2243,6 +2246,8 @@ export function VoxelizationMappingView({
|
||||
const mappingViewportRef = useRef<HTMLDivElement | null>(null);
|
||||
const [dicomPreview, setDicomPreview] = useState<DicomPreview | null>(null);
|
||||
const [modelPreviews, setModelPreviews] = useState<Record<string, ModelPreviewPayload>>({});
|
||||
const [metricPreviews, setMetricPreviews] = useState<Record<string, ModelPreviewPayload>>({});
|
||||
const [metricPreviewsLoaded, setMetricPreviewsLoaded] = useState(false);
|
||||
const [dicomStatus, setDicomStatus] = useState('等待 DICOM 切片');
|
||||
const [overlayStatus, setOverlayStatus] = useState('等待 STL 映射');
|
||||
const [overlayStats, setOverlayStats] = useState<OverlayStats>({ activeModules: 0, filledPixels: 0, segmentCount: 0, modules: [] });
|
||||
@@ -2259,9 +2264,11 @@ export function VoxelizationMappingView({
|
||||
const maxSlice = Math.max(totalSlices - 1, 0);
|
||||
const safeSlice = clamp(slice, 0, maxSlice);
|
||||
const stlFiles = project?.stlFiles ?? [];
|
||||
const stlFileSignature = stlFiles.join('|');
|
||||
const visibleStlFiles = stlFiles.filter((fileName) => moduleStyles[fileName]?.visible !== false);
|
||||
const visibleStlFileSignature = visibleStlFiles.join('|');
|
||||
const visibleModuleCount = visibleStlFiles.length;
|
||||
const metricPreviewsReady = !stlFiles.length || metricPreviewsLoaded;
|
||||
const isLibraryVariant = variant === 'library';
|
||||
const activeOverlayPlacement = overlayPlacement ?? (isLibraryVariant ? 'side' : 'bottom');
|
||||
|
||||
@@ -2295,6 +2302,36 @@ export function VoxelizationMappingView({
|
||||
};
|
||||
}, [project?.id, project?.dicomCount, safeSlice, displayMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!project || !stlFiles.length) {
|
||||
setMetricPreviews({});
|
||||
setMetricPreviewsLoaded(true);
|
||||
return;
|
||||
}
|
||||
|
||||
let disposed = false;
|
||||
setMetricPreviews({});
|
||||
setMetricPreviewsLoaded(false);
|
||||
Promise.allSettled(stlFiles.map((fileName) => (
|
||||
getCachedModelPreview(project.id, fileName, 1000)
|
||||
.then((payload) => ({ fileName, payload }))
|
||||
))).then((results) => {
|
||||
if (disposed) return;
|
||||
const nextPreviews: Record<string, ModelPreviewPayload> = {};
|
||||
results.forEach((result) => {
|
||||
if (result.status === 'fulfilled') {
|
||||
nextPreviews[result.value.fileName] = result.value.payload;
|
||||
}
|
||||
});
|
||||
setMetricPreviews(nextPreviews);
|
||||
setMetricPreviewsLoaded(true);
|
||||
});
|
||||
|
||||
return () => {
|
||||
disposed = true;
|
||||
};
|
||||
}, [project?.id, stlFileSignature]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!project || !visibleStlFiles.length) {
|
||||
setModelPreviews({});
|
||||
@@ -2346,7 +2383,7 @@ export function VoxelizationMappingView({
|
||||
return () => {
|
||||
disposed = true;
|
||||
};
|
||||
}, [project?.id, stlFiles.length, visibleStlFileSignature, detailLimit]);
|
||||
}, [project?.id, stlFileSignature, visibleStlFileSignature, detailLimit]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = baseCanvasRef.current;
|
||||
@@ -2361,12 +2398,21 @@ export function VoxelizationMappingView({
|
||||
if (!canvas || !dicomPreview) {
|
||||
return;
|
||||
}
|
||||
if (!metricPreviewsReady) {
|
||||
const context = canvas.getContext('2d');
|
||||
context?.clearRect(0, 0, canvas.width, canvas.height);
|
||||
setOverlayStats({ activeModules: 0, filledPixels: 0, segmentCount: 0, modules: [] });
|
||||
setOverlayStatus('正在计算全局模型边界...');
|
||||
return;
|
||||
}
|
||||
const frame = window.requestAnimationFrame(() => {
|
||||
const stats = drawVoxelOverlayLayer(
|
||||
canvas,
|
||||
dicomPreview,
|
||||
visibleStlFiles,
|
||||
modelPreviews,
|
||||
stlFiles,
|
||||
metricPreviews,
|
||||
moduleStyles,
|
||||
modelPose,
|
||||
safeSlice,
|
||||
@@ -2378,8 +2424,11 @@ export function VoxelizationMappingView({
|
||||
return () => window.cancelAnimationFrame(frame);
|
||||
}, [
|
||||
dicomPreview,
|
||||
stlFileSignature,
|
||||
visibleStlFileSignature,
|
||||
modelPreviews,
|
||||
metricPreviews,
|
||||
metricPreviewsReady,
|
||||
JSON.stringify(moduleStyles),
|
||||
modelPose.rotateX,
|
||||
modelPose.rotateY,
|
||||
|
||||
Reference in New Issue
Block a user