From 883ece290a5274953a3d6a0b9d6e229c26327e03 Mon Sep 17 00:00:00 2001 From: Paul Elliott Date: Fri, 5 Jul 2024 12:26:00 -0400 Subject: [PATCH] fix(polygon): merge overlapping polygons better --- src/store/tools/polygons.ts | 40 +++++++++++++++++++++++++++++++++++-- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/src/store/tools/polygons.ts b/src/store/tools/polygons.ts index 3decc880..f25ecc97 100644 --- a/src/store/tools/polygons.ts +++ b/src/store/tools/polygons.ts @@ -1,5 +1,5 @@ import polybool, { Polygon } from '@velipso/polybool'; -import type { Vector3 } from '@kitware/vtk.js/types'; +import type { Vector3, Vector2 } from '@kitware/vtk.js/types'; import { computed } from 'vue'; import { ToolSelection, @@ -64,7 +64,43 @@ export const usePolygonStore = defineAnnotationToolStore('polygon', () => { const firstTool = polygons[0]; const { to3D } = getPlaneTransforms(firstTool.frameOfReference); - const points = unionPoly.regions[0].map(to3D); + // After union, regions will have shared points because we require overlap to union. + // Create one region/ring by splicing in the next region at the common point. + const pointEquals = (a: Vector2, b: Vector2) => + a[0] === b[0] && a[1] === b[1]; + const mergeRegions = (regions: Array>) => { + const [mergedRegion, ...candidates] = regions; + + while (candidates.length > 0) { + let regionIndex = 0; + let mergedCommonPointIndex = 0; + let candidateCommonPointIndex = 0; + for (let i = 0; i < candidates.length; i++) { + const candidate = candidates[i]; + let candidatePointIndex = 0; + const commonPointIndex = mergedRegion.findIndex((point) => + candidate.some((nextPoint, index) => { + candidatePointIndex = index; + return pointEquals(point, nextPoint); + }) + ); + if (commonPointIndex !== -1) { + regionIndex = i; + mergedCommonPointIndex = commonPointIndex; + candidateCommonPointIndex = candidatePointIndex; + break; + } + } + const [toMerge] = candidates.splice(regionIndex, 1); + const oldStart = toMerge.splice(0, candidateCommonPointIndex); + const startWithCommonPoint = [...toMerge, ...oldStart]; + mergedRegion.splice(mergedCommonPointIndex, 0, ...startWithCommonPoint); + } + + return mergedRegion; + }; + + const points = mergeRegions(unionPoly.regions).map(to3D); // eslint-disable-next-line @typescript-eslint/no-unused-vars const { id: _, ...toolProps } = polygons[0];