Hello!
I’m reading an rtstruct, getting the rois and then creating the contourSet in order to represent them, but I cannot make it work.
The process is to create the contourData, then add the segmentations and finally the representations to the viewport of the axial view where I want to see the contours
for (const roi of roisToBuild) {
const ringsSorted = sortRingsByZ(roi.rings);
if (!ringsSorted.length) continue;
const resampled = resampleRings(ringsSorted, 200);
if (!resampled.length) continue;
const segIndex = segmentIndexFor(roi.roiName, filename, organToAnalyze);
const surfId = `${segmentationPrefix}_${sanitizeId(roi.roiName)}_SURF_${uniqueId()}`;
const cntId = `${segmentationPrefix}_${sanitizeId(roi.roiName)}_CNT_${uniqueId()}`;
const metaForThisGeom = {
tipo: segmentationPrefix === 'GS' ? 'gs' : 'alumno',
geomId: surfId,
segIndex,
roiKey: roiKeyFor(segIndex),
};
((load_rtstruct_and_build_surfaces as any)._pendingMeta ||= []).push(metaForThisGeom);
if (segIndex > highestSegIndex) highestSegIndex = segIndex;
if (segIndex > maxSegIndex) maxSegIndex = segIndex;
// ---------- create CONTOUR geometry (axial) ----------
const rgb: Types.Point3 = [1, 0, 0];
const contourData = resampled
.map((ring) => {
const zWorld = ring[0][2];
const closest = findClosestImageIdByZ(zWorld, sopMap);
if (!closest) return null;
return {
points: ring.map(p => [p[0], p[1], p[2]] as Types.Point3), // WORLD
referencedImageId: closest.imageId, // 🔥 CLAVE
type: csCore.Enums.ContourType.CLOSED_PLANAR,
segmentIndex: segIndex,
color: rgb,
};
})
.filter(Boolean);
const contourSetData: Types.ContourSetData = {
id: cntId,
frameOfReferenceUID,
segmentIndex: segIndex,
color: rgb,
data: contourData as any,
};
await geometryLoader.createAndCacheGeometry(cntId, {
type: csCore.Enums.GeometryType.CONTOUR,
geometryData: contourSetData as any,
});
geometryIdsContour.push(cntId);
console.log('[CNT check]', {
cntGeom: geometryIdsContour[0],
firstRingRef: (contourSetData.data as any)?.[0]?.referencedImageId,
repEnum: CONTOUR_REP,
viewportExists: !!csCore.getRenderingEngine(axialRenderingEngineId)?.getViewport(viewportAxialId),
});
}
if (!geometryIdsSurface.length) {
console.warn('[Review] Ninguna SURFACE válida generada, no se crea segmentación 3D');
return;
}
// ============================================================
// 3D: registrar segmentación Surface
// ============================================================
const segmentationId = `${segmentationPrefix}_importedContours_${++importCount}`;
if (segmentationPrefix === 'GS') segmentationIdByTipo.gs = segmentationId;
else segmentationIdByTipo.alumno = segmentationId;
await segmentation.addSegmentations([
{
segmentationId,
representation: {
type: csToolsEnums.SegmentationRepresentations.Surface,
data: { geometryIds: geometryIdsSurface },
},
},
]);
const pending = (load_rtstruct_and_build_surfaces as any)._pendingMeta as GeoMeta[] || [];
GEO_BY_SEGID[segmentationId] = pending.slice();
(load_rtstruct_and_build_surfaces as any)._pendingMeta = [];
console.log(`[Review] Segmentación 3D creada: ${segmentationId}`, { surfaces: geometryIdsSurface });
await attachAndRender3D(segmentationId, viewport3DId, highestSegIndex);
// ============================================================
// AXIAL: registrar segmentación Contour en el AXIAL NUEVO
// ============================================================
if (geometryIdsContour.length && viewportAxialId) {
const contourSegId = `${segmentationPrefix}_AXCNT_${importCount}`;
// (si quieres conservar tu dummy, mantenlo, pero ojo con duplicados)
// await ensureDummy2DSegmentation(viewportAxialId);
await segmentation.addSegmentations([
{
segmentationId: contourSegId,
representation: {
type: CONTOUR_REP,
data: { geometryIds: geometryIdsContour },
},
},
]);
console.log(viewportAxialId);
await segmentation.addContourRepresentationToViewport(
viewportAxialId,
[
{
segmentationId: contourSegId,
type: CONTOUR_REP,
},
]
);
segmentation.activeSegmentation.setActiveSegmentation(viewportAxialId, contourSegId);
segmentation.config.visibility.setSegmentationVisibility?.(contourSegId, true);
for (const roi of roisToBuild) {
const segIdx = segmentIndexFor(roi.roiName, filename, organToAnalyze);
segmentation.config.visibility.setSegmentVisibility?.(contourSegId, segIdx, true);
}
// 🔥 IMPORTANTE: renderizar el ENGINE del axial review, no el viejo
const reAxial = csCore.getRenderingEngine(axialRenderingEngineId);
const vpAxial = reAxial.getViewport(viewportAxialId) as any;
reAxial?.renderViewports([viewportAxialId]);
requestAnimationFrame(() => {
reAxial?.resize(true); // recalcula tamaños
reAxial?.renderViewports([viewportAxialId]); // vuelve a renderizar con tamaño real
});
console.log('✅ [Review] Contornos añadidos a axial', {
contourSegId,
viewportAxialId,
axialRenderingEngineId,
geometryIdsContourCount: geometryIdsContour.length,
});
}
}
function findClosestImageIdByZ(
z: number,
sopMap: Map<string, { imageId: string; z: number }>
) {
let best = null;
let minDiff = Infinity;
for (const entry of sopMap.values()) {
const diff = Math.abs(entry.z - z);
if (diff < minDiff) {
minDiff = diff;
best = entry;
}
}
return best;
}
Could anybody tell me what I’m doing wrong please?