--- name: 페어링 인덱스 master = roofLines 정책 description: skeleton-utils.js 라인 페어링 정렬 master 를 wallLines→roofLines 로 변경한 정책 (2026-04-27) type: project --- **정책**: `src/util/skeleton-utils.js` (~1342~1359) 의 라인 페어링 정렬에서 **roofLines 를 단일 master** 로 사용. wall.lines / wall.baseLines 는 roofLines 의 raw 인덱스 1:1 매핑으로 정렬. **Why**: - 사용자 원칙: "인덱스가 여기에는 생명이다. leftTop(최저 좌표) 꼭짓점에서 시작해 CCW 로 그려 나간다." - **사용자가 다각형을 시계방향(CW)으로 그릴 수도 있음** → 그래서 인덱스를 다시 세워야 한다. 항상 **최저 좌표(leftTop, min-Y → min-X)** 를 #1 로 놓고 CCW 로 재정렬해 정규화. 사용자의 그리는 방향(CW/CCW)에 무관하게 고유한 시작점/순서를 보장. - 종전 master 였던 `wallLines (= wall.lines)` 는 `useMode.js:1880`, `usePropertiesSetting.js:165`, `useRoofShapePassivitySetting.js:242` 에서 재할당 가능 → 시작점 산정이 흔들릴 위험. - `roofLines` 는 외곽(처마) 경계라 사용자 mutation 영향 없음 → 시작점 안정. - B-7 OVER 시 보조라인이 B-5/B-3 위치에 그려진 간헐 버그가 정렬 master 흔들림에서 비롯됐을 가능성. **How to apply**: - ensureCounterClockwiseLines 의 입력은 roofLines (master). leftTop = min-Y → tiebreak min-X 꼭짓점에서 CCW. - wall.lines, wall.baseLines 는 raw 인덱스 보존이 전제 (코드상 페어링 1:1 가정). - `_keyOfEdge` 는 좌표를 0.1 단위로 라운드 후 양 끝점 정렬 키 생성 → 부동소수점 drift 흡수. - `ensureCounterClockwiseLines` 내부 graph 키도 0.1 단위 round (2026-05-06 추가) — caller `_keyOfEdge` 와 동일 정책으로 통일. - 매핑 실패 시 fallback 으로 sortRoofLines 항목 자체를 사용 (안전망). - 추후 wall.* 가 수정될 때 raw 인덱스가 보존되는지 검증 필요. 만약 깨진다면 매핑 키를 좌표 대신 라인 ID 기반으로 변경 검토. **ensureCounterClockwiseLines drift 보강 (2026-05-06)**: - 증상: 같은 도형인데 간헐적으로 인덱스 시작점/순서가 바뀌는 현상 (사용자가 다시 그리면 정상화). - 원인: 함수 내부 `graph` Map 키가 raw 좌표 (`${line.x1},${line.y1}`) 라서 drift (e.g. 100.0 vs 100.0000001) 로 같은 점이 별개 노드로 등록 → graph 끊어짐 → traversal 중도 break → result.length < lines.length → 페어링 어긋남. - 수정 위치 (`skeleton-utils.js:3463`): 1. `:3469-3480` graph 빌드 시 endpoint 좌표 `Math.round(v*10)/10` 로 round, 이웃 객체 `{x,y}` 도 rounded 저장 (후속 `${n.x},${n.y}` 키가 graph 키와 일치) 2. `:3528` `isReversed` 비교를 정확비교 → `Math.abs(line.x1 - next.x) > 0.05` approx (round 절반 임계). raw line.x1 vs rounded next.x 불일치 false-positive 차단 - 영역 외 보존: atan2 / area 부호 / result 라인 좌표는 raw 그대로 (다운스트림 정확도 유지). - 정상 케이스 (drift 없음) 동작 변화 없음. 100.0 round = 100.0. **관련**: - `feedback_over_move_silent_skip.md` (OVER 클램핑 정책) - `project_over_move_red_helper_deferred.md` (빨강 보조선 별건 이슈) - `project_parallel_collapse_fix.md` (평행 이동 SK 붕괴) - `feedback_same_point_tolerance.md` (좌표 매칭 tolerance)