/** * MarchingSquares — Extract vector contours from a 2D voxel label grid. * * For each label, produces a `Path2D` whose subpaths are small per-cell * polygons. The polygons tile the region occupied by the target label; the * union (via `ctx.fill(path, 'nonzero')`) is the label's silhouette on the * voxel grid. * * Coordinate convention: * - Voxel (i, j) occupies the unit square [i, i+1] × [j, j+1] in render * space, with its center at (i+0.5, j+0.5). This matches ITK-SNAP / * standard imaging viewers and the existing `renderSliceToCanvas` * `scale(scaledW / W, scaledH / H)` mapping. * - Marching squares treats voxels as point samples at their centers: * cell (i, j) has corners at voxel centers (i+0.5, j+0.5), * (i+1.5, j+0.5), (i+1.5, j+1.5), (i+0.5, j+1.5). * - This produces 45°-cut contours (diamonds for isolated voxels, rounded * corners for connected regions) that stay within the voxel-square * bounds, so the rendered silhouette is a slightly-inset version of the * ITK-SNAP silhouette with smooth diagonals. * * Saddle cases (5 and 10) use a fixed convention: the two in-corners are * treated as disconnected within the cell (4-connectivity interpretation). */ export interface ContourBBox { /** Inclusive left voxel (0 ≤ x0 ≤ width). */ x0: number; /** Inclusive top voxel (0 ≤ y0 ≤ height). */ y0: number; /** Exclusive right voxel (x1 > x0). */ x1: number; /** Exclusive bottom voxel (y1 > y0). */ y1: number; } /** A single polygon's vertices in voxel-space coordinates. */ export type ContourPolygon = ReadonlyArray; /** * Emit polygons covering the voxels where `labels === targetLabel`. * Pure geometry function — no Canvas dependency. Consumers can build a Path2D * (see {@link extractLabelContours}) or walk the vertex arrays directly * (tests, export, stroke rendering). * * Boundary cells (marching-squares cases 1–14) emit their cut polygon as * usual. Solid interior (case 15) is **coalesced into horizontal run-length * rectangles** instead of one unit square per cell, collapsing the subpath * count from O(area) to ≈ O(perimeter + rows). The filled region is * pixel-identical (contiguous full-cell squares tile exactly into a rectangle * with the same TL→TR→BR→BL winding), which is what keeps slice-scrubbing * fast on large masks without changing the rendered silhouette. */ export declare function extractLabelPolygons(labels: Uint8Array, width: number, height: number, targetLabel: number, stride?: number, channelOffset?: number, bbox?: ContourBBox): ContourPolygon[]; /** * Extract a `Path2D` covering all voxels equal to `targetLabel`. * * @param labels Flat label array. Addressed as * `labels[(y * width + x) * stride + channelOffset]`. * @param width Grid width in voxels. * @param height Grid height in voxels. * @param targetLabel Label value to extract (1..255; 0 is background). * @param stride Bytes per voxel (default 1). Use MaskVolume.numChannels * when reading interleaved slices. * @param channelOffset Offset within each voxel's channels to sample. * Default 0 (first channel = label id). * @param bbox Optional voxel-space bbox to limit extraction. * Cells in a 1-voxel halo around the bbox are still * visited so the contour closes correctly at the bbox edges. */ export declare function extractLabelContours(labels: Uint8Array, width: number, height: number, targetLabel: number, stride?: number, channelOffset?: number, bbox?: ContourBBox): Path2D; /** * Detect the distinct non-zero labels present in a slice region. * * @param labels Flat label array (see {@link extractLabelContours}). * @param width Grid width. * @param height Grid height. * @param stride Bytes per voxel. * @param channelOffset Offset within each voxel. * @param bbox Optional region to scan (defaults to full grid). * @returns Sorted array of distinct label values (0 omitted). */ export declare function findLabelsInSlice(labels: Uint8Array, width: number, height: number, stride?: number, channelOffset?: number, bbox?: ContourBBox): number[];