diff --git a/src/hooks/roofcover/useEavesGableEdit.js b/src/hooks/roofcover/useEavesGableEdit.js index eb0938d7..c2e73567 100644 --- a/src/hooks/roofcover/useEavesGableEdit.js +++ b/src/hooks/roofcover/useEavesGableEdit.js @@ -365,9 +365,33 @@ export function useEavesGableEdit(id) { } const labelOf = (line) => (line ? labelByLine.get(line) || '?' : null) // [KERAB-WLINE-T1T2 2026-06-04] wLine 이동 후 선택된 target 은 이동 전 wallLine. - // 이동된 실제 위치는 wall.baseLines 중 wallId 가 일치하는 baseLine 에 있다. + // 이동된 실제 위치는 wall.baseLines 에 있다. + // wallId 매칭은 이동 후 인덱스 재정렬로 잘못된 baseLine 반환 → 기하학적 매칭으로 교체. + // 같은 방향(수직/수평) + target 의 고정 끝점(이동 안 된 쪽) 공유 여부로 식별. const _wall = canvas.getObjects().find((o) => o.name === POLYGON_TYPE.WALL && o.attributes?.roofId === target.attributes?.roofId) - const _matchedBase = _wall?.baseLines?.find((bl) => bl.attributes?.wallId === target.attributes?.wallId) + const _BL_TOL = 5 + const _tIsV = Math.abs(target.x1 - target.x2) < 0.5 + const _tIsH = Math.abs(target.y1 - target.y2) < 0.5 + const _matchedBase = _wall?.baseLines?.find((bl) => { + if (_tIsV) { + if (Math.abs(bl.x1 - bl.x2) >= 0.5) return false // bl 방향 불일치 + if (Math.abs(bl.x1 - target.x1) >= _BL_TOL) return false // 다른 수직선 + return ( + Math.abs(bl.y1 - target.y1) < _BL_TOL || Math.abs(bl.y1 - target.y2) < _BL_TOL || + Math.abs(bl.y2 - target.y1) < _BL_TOL || Math.abs(bl.y2 - target.y2) < _BL_TOL + ) + } + if (_tIsH) { + if (Math.abs(bl.y1 - bl.y2) >= 0.5) return false // bl 방향 불일치 + if (Math.abs(bl.y1 - target.y1) >= _BL_TOL) return false // 다른 수평선 + return ( + Math.abs(bl.x1 - target.x1) < _BL_TOL || Math.abs(bl.x1 - target.x2) < _BL_TOL || + Math.abs(bl.x2 - target.x1) < _BL_TOL || Math.abs(bl.x2 - target.x2) < _BL_TOL + ) + } + // 대각선: wallId fallback + return bl.attributes?.wallId === target.attributes?.wallId + }) const t1 = _matchedBase ? { x: _matchedBase.x1, y: _matchedBase.y1 } : { x: target.x1, y: target.y1 } const t2 = _matchedBase ? { x: _matchedBase.x2, y: _matchedBase.y2 } : { x: target.x2, y: target.y2 } const h1Match = findHipAtEndpoint(roof, t1) diff --git a/src/util/skeleton-utils.js b/src/util/skeleton-utils.js index 79b75182..e283c472 100644 --- a/src/util/skeleton-utils.js +++ b/src/util/skeleton-utils.js @@ -2013,6 +2013,16 @@ const createInnerLinesFromSkeleton = (roofId, canvas, skeleton, textMode, isOver return } + // [KERAB-SKIP 2026-06-04] 순수 케라바 변(GABLE/GABLE_LEFT/GABLE_RIGHT/JERKINHEAD)은 + // 처마처럼 wall→roof 사이에 hip이 없으므로 eaveHelpLine 불필요. + // 적용 시 SK 오염. HIPANDGABLE은 처마+케라바 혼합(hip 있음)이므로 제외하지 않음. + if ([ + LINE_TYPE.WALLLINE.GABLE, + LINE_TYPE.WALLLINE.GABLE_LEFT, + LINE_TYPE.WALLLINE.GABLE_RIGHT, + LINE_TYPE.WALLLINE.JERKINHEAD, + ].includes(wallBaseLine.attributes?.type)) return + // [진단] sortWallLines ↔ sortWallBaseLines 페어링 검증 // collapse 시 ensureCounterClockwiseLines 시작점이 달라지면 인덱스가 어긋남 // 정상: 같은 물리 벽 → 적어도 한쪽 끝점 공유 또는 방향 동일(수직/수평) @@ -3136,8 +3146,8 @@ function findMatchingLine(edgePolygon, roof, roofPoints) { */ function processGableEdge(edgeResult, baseLines, skeletonLines, selectBaseLine, lastSkeletonLines) { const edgePoints = edgeResult.Polygon.map(p => ({ x: p.X, y: p.Y })); - //const polygons = createPolygonsFromSkeletonLines(skeletonLines, selectBaseLine); - //logger.log("edgePoints::::::", edgePoints) + + // 1. Initialize processedLines with a deep copy of lastSkeletonLines let processedLines = [] // 1. 케라바 면과 관련된 불필요한 스켈레톤 선을 제거합니다.