2026-05-24-18-59-49 修正薄壳构件实体化映射
This commit is contained in:
@@ -142,7 +142,7 @@ const dicomVolumeCache = new Map<string, {
|
||||
}>();
|
||||
const modelPreviewCache = new Map<string, unknown>();
|
||||
const defaultModuleColors = ['#3b82f6', '#22c55e', '#f59e0b', '#ef4444', '#8b5cf6', '#14b8a6', '#f97316', '#64748b', '#ec4899'];
|
||||
const maxPreviewTriangles = 500000;
|
||||
const maxPreviewTriangles = 800000;
|
||||
const defaultModelPose: ModelPoseValue = {
|
||||
rotateX: 0,
|
||||
rotateY: 0,
|
||||
@@ -1288,7 +1288,76 @@ function closeExportMaskGaps(mask: Uint8Array, width: number, height: number, ma
|
||||
return toFill.size;
|
||||
}
|
||||
|
||||
function fillExportRows(data: Buffer, width: number, height: number, slice: number, rows: number[][], label: number) {
|
||||
function exportSolidStrokeRadius(width: number, height: number) {
|
||||
return Math.max(2.2, Math.min(5.5, Math.max(width, height) * 0.006));
|
||||
}
|
||||
|
||||
function paintExportMaskPixel(mask: Uint8Array, width: number, height: number, x: number, y: number) {
|
||||
if (x < 0 || x >= width || y < 0 || y >= height) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const index = y * width + x;
|
||||
if (mask[index]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mask[index] = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
function fillExportSegmentCapsules(
|
||||
mask: Uint8Array,
|
||||
width: number,
|
||||
height: number,
|
||||
segments: PlaneSegmentRecord[],
|
||||
radius: number,
|
||||
) {
|
||||
let paintedPixels = 0;
|
||||
const radiusSquared = radius * radius;
|
||||
|
||||
segments.forEach(({ a, b }) => {
|
||||
if (!Number.isFinite(a.x) || !Number.isFinite(a.y) || !Number.isFinite(b.x) || !Number.isFinite(b.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const dx = b.x - a.x;
|
||||
const dy = b.y - a.y;
|
||||
const lengthSquared = dx * dx + dy * dy;
|
||||
const minX = clampNumber(Math.floor(Math.min(a.x, b.x) - radius), 0, width - 1);
|
||||
const maxX = clampNumber(Math.ceil(Math.max(a.x, b.x) + radius), 0, width - 1);
|
||||
const minY = clampNumber(Math.floor(Math.min(a.y, b.y) - radius), 0, height - 1);
|
||||
const maxY = clampNumber(Math.ceil(Math.max(a.y, b.y) + radius), 0, height - 1);
|
||||
|
||||
for (let y = minY; y <= maxY; y += 1) {
|
||||
for (let x = minX; x <= maxX; x += 1) {
|
||||
const px = x + 0.5;
|
||||
const py = y + 0.5;
|
||||
const t = lengthSquared <= 1e-6
|
||||
? 0
|
||||
: clampNumber(((px - a.x) * dx + (py - a.y) * dy) / lengthSquared, 0, 1);
|
||||
const closestX = a.x + dx * t;
|
||||
const closestY = a.y + dy * t;
|
||||
const distanceSquared = (px - closestX) ** 2 + (py - closestY) ** 2;
|
||||
if (distanceSquared <= radiusSquared) {
|
||||
paintedPixels += paintExportMaskPixel(mask, width, height, x, y);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return paintedPixels;
|
||||
}
|
||||
|
||||
function fillExportRows(
|
||||
data: Buffer,
|
||||
width: number,
|
||||
height: number,
|
||||
slice: number,
|
||||
rows: number[][],
|
||||
label: number,
|
||||
solidSegments: PlaneSegmentRecord[] = [],
|
||||
) {
|
||||
const mask = new Uint8Array(width * height);
|
||||
let filledPixels = 0;
|
||||
|
||||
@@ -1325,11 +1394,15 @@ function fillExportRows(data: Buffer, width: number, height: number, slice: numb
|
||||
}
|
||||
});
|
||||
|
||||
if (solidSegments.length) {
|
||||
filledPixels += fillExportSegmentCapsules(mask, width, height, solidSegments, exportSolidStrokeRadius(width, height));
|
||||
}
|
||||
|
||||
if (filledPixels === 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
filledPixels += closeExportMaskGaps(mask, width, height);
|
||||
filledPixels += closeExportMaskGaps(mask, width, height, 3);
|
||||
filledPixels += fillExportInternalHoles(mask, width, height);
|
||||
const sliceOffset = slice * width * height;
|
||||
for (let index = 0; index < mask.length; index += 1) {
|
||||
@@ -1527,11 +1600,11 @@ function createSegmentationData(
|
||||
});
|
||||
|
||||
slicesByIndex.forEach(({ segments }, slice) => {
|
||||
groupExportSegmentsByConnectivity(segments).forEach((group) => {
|
||||
groupExportSegmentsByConnectivity(segments, exportSolidStrokeRadius(volume.width, volume.height) * 1.15).forEach((group) => {
|
||||
const rows = Array.from({ length: volume.height }, () => [] as number[]);
|
||||
group.forEach((segment) => addExportSegmentToRows(rows, volume.width, volume.height, segment));
|
||||
const filledPixels = fillExportRows(data, volume.width, volume.height, slice, rows, label);
|
||||
if (filledPixels < Math.max(12, Math.round(group.length * 0.45)) && group.length >= 3) {
|
||||
const filledPixels = fillExportRows(data, volume.width, volume.height, slice, rows, label, group);
|
||||
if (filledPixels < Math.max(20, Math.round(group.length * 0.5)) && group.length >= 3) {
|
||||
fillExportFallbackClosedRegion(data, volume.width, volume.height, slice, group, label);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user