2026-05-24-16-28-58 修正可见构件导出与高精度映射
This commit is contained in:
@@ -981,7 +981,9 @@ export default function ProjectLibrary({
|
||||
const savedSegmentationResults = selectedProject?.segmentationResults ?? [];
|
||||
const latestSegmentationResult = savedSegmentationResults[savedSegmentationResults.length - 1];
|
||||
const latestResultPose = latestSegmentationResult ? resultPose : modelPose;
|
||||
const latestResultStyles = latestSegmentationResult?.moduleStyles ?? moduleStyles;
|
||||
const latestResultStyles = latestSegmentationResult
|
||||
? { ...latestSegmentationResult.moduleStyles, ...moduleStyles }
|
||||
: moduleStyles;
|
||||
const resultMaxSlice = Math.max((selectedProject?.dicomCount ?? 1) - 1, 0);
|
||||
const resultMappingSlice = Math.max(0, Math.min(resultMaxSlice, resultPreviewSlice));
|
||||
const resultDisplayOption = reverseDisplayOptions.find((option) => option.id === 'fine') ?? reverseDisplayOptions[0];
|
||||
@@ -1030,6 +1032,7 @@ export default function ProjectLibrary({
|
||||
pose: latestSegmentationResult?.pose ?? modelPose,
|
||||
segmentationScope: maskSegmentationScope,
|
||||
segmentationExportMode: maskSegmentationExportMode,
|
||||
moduleStyles,
|
||||
});
|
||||
window.setTimeout(() => setMaskExporting(false), 900);
|
||||
setShowMaskExportMenu(false);
|
||||
@@ -1163,7 +1166,10 @@ export default function ProjectLibrary({
|
||||
const maxIndex = Math.max((selectedProject?.dicomCount ?? 1) - 1, 0);
|
||||
const next: Record<string, ModuleStyle> = {};
|
||||
stlFiles.forEach((fileName, index) => {
|
||||
next[fileName] = makeDefaultModuleStyle(index, latestResult?.moduleStyles?.[fileName] ?? selectedProject?.moduleStyles?.[fileName] ?? moduleStyles[fileName]);
|
||||
next[fileName] = makeDefaultModuleStyle(index, {
|
||||
...(latestResult?.moduleStyles?.[fileName] ?? {}),
|
||||
...(selectedProject?.moduleStyles?.[fileName] ?? {}),
|
||||
});
|
||||
});
|
||||
setModuleStyles(next);
|
||||
setSliceIndex(0);
|
||||
|
||||
@@ -2171,7 +2171,9 @@ export function VoxelizationMappingView({
|
||||
const maxSlice = Math.max(totalSlices - 1, 0);
|
||||
const safeSlice = clamp(slice, 0, maxSlice);
|
||||
const stlFiles = project?.stlFiles ?? [];
|
||||
const visibleModuleCount = stlFiles.filter((fileName) => moduleStyles[fileName]?.visible !== false).length;
|
||||
const visibleStlFiles = stlFiles.filter((fileName) => moduleStyles[fileName]?.visible !== false);
|
||||
const visibleStlFileSignature = visibleStlFiles.join('|');
|
||||
const visibleModuleCount = visibleStlFiles.length;
|
||||
const isLibraryVariant = variant === 'library';
|
||||
const activeOverlayPlacement = overlayPlacement ?? (isLibraryVariant ? 'side' : 'bottom');
|
||||
|
||||
@@ -2206,16 +2208,16 @@ export function VoxelizationMappingView({
|
||||
}, [project?.id, project?.dicomCount, safeSlice, displayMode]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!project || !stlFiles.length) {
|
||||
if (!project || !visibleStlFiles.length) {
|
||||
setModelPreviews({});
|
||||
setOverlayStatus('当前项目没有 STL 构件');
|
||||
setOverlayStatus(stlFiles.length ? '当前没有可见 STL 构件' : '当前项目没有 STL 构件');
|
||||
return;
|
||||
}
|
||||
|
||||
let disposed = false;
|
||||
setOverlayStatus('正在载入 STL 构件层级...');
|
||||
Promise.allSettled(stlFiles.map((fileName) => (
|
||||
getCachedModelPreview(project.id, fileName, Math.max(detailLimit, 200000))
|
||||
setOverlayStatus('正在载入可见 STL 构件层级...');
|
||||
Promise.allSettled(visibleStlFiles.map((fileName) => (
|
||||
getCachedModelPreview(project.id, fileName, Math.max(detailLimit, 500000))
|
||||
.then((payload) => ({ fileName, payload }))
|
||||
))).then((results) => {
|
||||
if (disposed) return;
|
||||
@@ -2232,7 +2234,7 @@ export function VoxelizationMappingView({
|
||||
return () => {
|
||||
disposed = true;
|
||||
};
|
||||
}, [project?.id, stlFiles.join('|'), detailLimit]);
|
||||
}, [project?.id, stlFiles.length, visibleStlFileSignature, detailLimit]);
|
||||
|
||||
useEffect(() => {
|
||||
const canvas = baseCanvasRef.current;
|
||||
@@ -2251,7 +2253,7 @@ export function VoxelizationMappingView({
|
||||
const stats = drawVoxelOverlayLayer(
|
||||
canvas,
|
||||
dicomPreview,
|
||||
stlFiles,
|
||||
visibleStlFiles,
|
||||
modelPreviews,
|
||||
moduleStyles,
|
||||
modelPose,
|
||||
@@ -2264,7 +2266,7 @@ export function VoxelizationMappingView({
|
||||
return () => window.cancelAnimationFrame(frame);
|
||||
}, [
|
||||
dicomPreview,
|
||||
stlFiles.join('|'),
|
||||
visibleStlFileSignature,
|
||||
modelPreviews,
|
||||
JSON.stringify(moduleStyles),
|
||||
modelPose.rotateX,
|
||||
@@ -2638,6 +2640,7 @@ export default function ReverseWorkspace({
|
||||
pose: modelPose,
|
||||
segmentationScope: segmentationExportScope,
|
||||
segmentationExportMode,
|
||||
moduleStyles,
|
||||
});
|
||||
window.setTimeout(() => setExporting(false), 900);
|
||||
setShowExportMenu(false);
|
||||
@@ -2947,7 +2950,10 @@ export default function ReverseWorkspace({
|
||||
setPoseValueDrafts(formatPoseDraftValues(restoredPose));
|
||||
const nextStyles: Record<string, ModuleStyle> = {};
|
||||
(item.stlFiles ?? []).forEach((fileName, index) => {
|
||||
nextStyles[fileName] = makeDefaultModuleStyle(index, latestResult?.moduleStyles?.[fileName] ?? item.moduleStyles?.[fileName]);
|
||||
nextStyles[fileName] = makeDefaultModuleStyle(index, {
|
||||
...(latestResult?.moduleStyles?.[fileName] ?? {}),
|
||||
...(item.moduleStyles?.[fileName] ?? {}),
|
||||
});
|
||||
});
|
||||
setModuleStyles(nextStyles);
|
||||
setSavedPoses(nextPoses);
|
||||
|
||||
@@ -203,7 +203,13 @@ export async function downloadMask(projectId: string, format: 'nii' | 'nii.gz' =
|
||||
triggerFileDownload(`/api/projects/${projectId}/export-mask?${params.toString()}`);
|
||||
}
|
||||
|
||||
export async function downloadProjectExport(projectId: string, target: ProjectExportTarget, format: 'nii' | 'nii.gz' = 'nii.gz', options: { pose?: ModelPose; segmentationScope?: SegmentationExportScope; segmentationExportMode?: SegmentationExportMode } = {}) {
|
||||
function appendModuleStyles(params: URLSearchParams, moduleStyles?: Record<string, ModuleStyle>) {
|
||||
if (moduleStyles) {
|
||||
params.set('moduleStyles', JSON.stringify(moduleStyles));
|
||||
}
|
||||
}
|
||||
|
||||
export async function downloadProjectExport(projectId: string, target: ProjectExportTarget, format: 'nii' | 'nii.gz' = 'nii.gz', options: { pose?: ModelPose; segmentationScope?: SegmentationExportScope; segmentationExportMode?: SegmentationExportMode; moduleStyles?: Record<string, ModuleStyle> } = {}) {
|
||||
const params = new URLSearchParams({ target, format });
|
||||
if (target === 'segmentation' || target === 'pose') {
|
||||
appendPose(params, options.pose);
|
||||
@@ -211,11 +217,12 @@ export async function downloadProjectExport(projectId: string, target: ProjectEx
|
||||
if (target === 'segmentation') {
|
||||
params.set('segmentationScope', options.segmentationScope ?? 'visible');
|
||||
params.set('segmentationExportMode', options.segmentationExportMode ?? 'combined');
|
||||
appendModuleStyles(params, options.moduleStyles);
|
||||
}
|
||||
triggerFileDownload(`/api/projects/${projectId}/export-nifti?${params.toString()}`);
|
||||
}
|
||||
|
||||
export async function downloadProjectExportBundle(projectId: string, targets: ProjectExportTarget[], format: 'nii' | 'nii.gz' = 'nii.gz', options: { pose?: ModelPose; segmentationScope?: SegmentationExportScope; segmentationExportMode?: SegmentationExportMode } = {}) {
|
||||
export async function downloadProjectExportBundle(projectId: string, targets: ProjectExportTarget[], format: 'nii' | 'nii.gz' = 'nii.gz', options: { pose?: ModelPose; segmentationScope?: SegmentationExportScope; segmentationExportMode?: SegmentationExportMode; moduleStyles?: Record<string, ModuleStyle> } = {}) {
|
||||
const params = new URLSearchParams({
|
||||
targets: targets.join(','),
|
||||
format,
|
||||
@@ -223,6 +230,7 @@ export async function downloadProjectExportBundle(projectId: string, targets: Pr
|
||||
segmentationExportMode: options.segmentationExportMode ?? 'combined',
|
||||
});
|
||||
appendPose(params, options.pose);
|
||||
appendModuleStyles(params, options.moduleStyles);
|
||||
triggerFileDownload(`/api/projects/${projectId}/export-bundle?${params.toString()}`);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user