qcast-front/docs/외벽선 확정(handleFix) 흐름.md
sangwook yoo 2e7c8769aa ```
docs(outerline): 외벽선 확정(handleFix) 흐름 및 PDF 자동 확정 가이드 문서 추가
```
- 외벽선 확정 (`handleFix`) 로직의 상세 흐름과 확정 후 캔버스/Recoil 불변 조건을 문서화합니다.
- PDF 도면 분석을 통한 외벽선 자동 확정 기능 구현 시 참고할 설계 가이드와 체크리스트를 포함합니다.
- `handleFix` 본체와 `useEffect`, `ccwCheck` 등 관련 로직의 역할 및 주의사항을 명확히 합니다.
```
2026-06-22 10:48:29 +09:00

12 KiB
Raw Blame History

외벽선 확정 (handleFix) 흐름

Q.CAST Floor Plan — 지붕덮개 → 외벽선 그리기 모달의 「외벽선 확정」 버튼이 호출하는 로직 정리. PDF/Gemini 도면 분석 후 캔버스에 외벽선을 그린 뒤, 옵션에 따라 이 확정 단계를 자동 실행할 때 참고한다.

코드 단일 진실 공급원:

역할 경로
UI (버튼) src/components/floor-plan/modal/outerlinesetting/WallLineSetting.jsx
핵심 로직 src/hooks/roofcover/useOuterLineWall.jshandleFix, ccwCheck, points useEffect
상태 src/store/outerLineAtom.jsouterLinePointsState, outerLineFixState
라인 생성 src/hooks/useLine.jsaddLine (QLine + attributes.planeSize)
PDF 임포트 대응 구현 src/hooks/pdf-import/usePdfImport.jsapplyOuterline
확정 후 다음 단계 src/components/floor-plan/modal/roofShape/RoofShapeSetting.jsx

0. 한눈에 보기

[외벽선 그리기 메뉴] → WallLineSetting 모달
        ↓ (클릭/Enter)
  SweetAlert 확인 (modal.cover.outline.fix.confirm)
        ↓ confirm
  handleFix()  — 닫힘 정점 추가 + isFix.current = true
        ↓ (points useEffect)
  outerLine QLine 재생성 + outerLinePoint circle
        ↓ isFix.current === true
  outerLineFix 플래그 ON → 모달 닫기 → ccwCheck → 지붕형상 설정 모달 오픈

확정 직후 캔버스/Recoil이 만족해야 하는 불변 조건 (PDF 자동 확정도 동일):

  1. canvas 객체 중 name === 'outerLine' 인 QLine ≥ 2 (닫힌 다각형)
  2. name === 'outerLinePoint' 인 fabric.Circle (정점, visible: false)
  3. canvas.outerLineFix === true Recoil outerLineFixState === true
  4. 외벽선 정점 순서는 반시계(CCW)ccwCheck 또는 동등 전처리
  5. QLine 은 반드시 useLine.addLine 경유 — attributes.planeSize, fontSize 없으면 지붕형상·처마/케라바·저장 복원 깨짐
  6. 좌표에 축소 scale 을 곱하지 않음QLine.length × 10 = 표시 mm 불변식 유지

1. UI 진입점

1-1. 모달·버튼

  • 컴포넌트: WallLineSetting (WithDraggable, class r)
  • 메뉴 진입: useMenucurrentMenu === EXTERIOR_WALL_LINEaddPopup(..., <WallLineSetting />)
  • 버튼 DOM: div.grid-btn-wrap > button.btn-frame.modal.act
  • i18n 키: modal.cover.outline.fix (ko: 「외벽선 확정」)

1-2. 클릭 핸들러

확정 버튼은 즉시 handleFix 를 부르지 않고, 확인 다이얼로그를 거친다.

// WallLineSetting.jsx
swalFire({
  type: 'confirm',
  text: getMessage('modal.cover.outline.fix.confirm'),
  confirmFn: handleFix,
})

동일 확인은 useOuterLineWall.enterCheck (Enter 키) 에서도 사용한다.

자동 확정 구현 시: 사용자 확인이 필요 없으면 swalFire 를 생략하고 handleFix 또는 아래 §5 의 「확정 후처리」만 직접 호출하면 된다.


2. handleFix 본체

파일: useOuterLineWall.js

2-1. 사전 조건·검증

단계 조건 실패 시
1 points.length >= 3 return (무발화)
2 모든 꼭짓점이 첫 점 기준 직각(각도 % 90 === 0) return — 축정렬 직사각형만으로 닫힌 경우 확정 불가

검증 통과 후:

setPoints((prev) => [...prev, { x: prev[0].x, y: prev[0].y }]) // 폐곡선: 마지막 = 첫 점
isFix.current = true
  • points 는 Recoil outerLinePointsState
  • isFix.current 는 ref — 다음 points useEffect 한 번에서만 소비된다 (자동으로 false 로 리셋되지 않음; 훅 unmount 전까지 true 유지)

2-2. handleFix 가 직접 하지 않는

다음은 모두 useEffect([points])ccwCheck 에 위임된다.

  • Fabric outerLine / outerLinePoint 생성
  • outerLineFixState / canvas.outerLineFix 설정
  • 마우스·키보드 이벤트 해제
  • WallLineSetting 모달 닫기
  • RoofShapeSetting 모달 열기

3. points 변경 시 useEffect (확정의 실질 후처리)

points 가 바뀔 때마다 실행된다. 확정 이전에도 그리기 미리보기 역할을 한다.

3-1. 공통 (매 points 변경)

  1. 기존 outerLine, helpGuideLine 제거 (removeLine)
  2. startPoint 제거
  3. points.length === 0setOuterLineFix(true) 후 return (초기화 경로)
  4. points.length === 1 → 시작점 빨간 circle (startPoint)
  5. points.length >= 2:
    • setOuterLineFix(false)그리는 중에는 미확정
    • outerLinePoint circle 생성 (visible: false)
    • 인접 정점 쌍마다 drawLineaddLine (name: 'outerLine', strokeWidth: 3, …)
    • 3점 이상이면 닫힘 가이드 (helpGuideLine, 회색 점선)

3-2. 확정 분기 (isFix.current === true)

if (isFix.current) {
  removeAllMouseEventListeners()
  removeAllDocumentEventListeners()
  canvas?.renderAll()
  setOuterLineFix(true)
  canvas.outerLineFix = true
  closePopup(id)                    // WallLineSetting 닫기
  ccwCheck()                        // §4
  addPopup(propertiesId, 1, <RoofShapeSetting id={propertiesId} />)
}

수동 플로우 확정 후 사용자가 보는 화면: 외벽선 그리기 모달 종료 → 지붕형상 설정 모달 자동 오픈.


4. ccwCheck — 정점 순서 보정

확정 직후 호출. 외벽선이 시계 방향이면 반시계로 뒤집는다.

  1. canvas.getObjects() 에서 name === 'outerLine' 필터
  2. outerLines.length < 2wall.line.not.found 알림 후 return
  3. Shoelace signed area 로 CCW 판별 (signedArea > 0 → CW)
  4. CW 이면 각 라인을 [x2,y2,x1,y1]역방향 재생성 (addLine + 기존 line remove)

PDF 임포트(usePdfImport.ensureCounterClockwise)는 정점 배열 단계에서 동일 목적을 수행한다. 캔버스에 이미 그려진 뒤라면 ccwCheck 와 결과가 같아야 한다.


5. PDF 자동 확정 — handleFix 와의 대응

현재 usePdfImport.applyOuterline수동 확정 직후 캔버스 상태까지는 맞추지만, handleFix 전체를 호출하지는 않는다.

수동 handleFix applyOuterline 현재 자동 확정 옵션 추가 시
SweetAlert 확인 PDF 덮어쓰기 확인만 옵션으로 생략/유지 선택
points 에 닫힘점 추가 closedPoints = [...pts, pts[0]] + setOuterLinePoints 동일
useEffect 로 QLine 재그리기 drawOuterLines (addLine 동일 옵션) 동일
outerLinePoint circle drawOuterLinePoints 동일
canvas.outerLineFix + outerLineFixState 설정함 필수
ccwCheck ensureCounterClockwise (정점 단계) 라인 그린 뒤 CW 이면 ccwCheck 또는 정점 보정
closePopup(WallLineSetting) 해당 모달 없음 불필요
RoofShapeSetting 모달 오픈 안 함 옵션 autoFix: trueaddPopup 으로 직행
fitViewport + canvasZoomState PDF 전용 수동 확정에는 없음 — PDF 유지
마우스 리스너 제거 그리기 모드 미사용 불필요

PlacementShapeSetting PDF 분기는 메뉴만 ROOF_SHAPE_SETTINGS 로 보내고, 지붕형상 모달 자동 오픈은 하지 않는다 — 자동 확정 옵션은 별도 구현이 필요하다.

참고: CLAUDE.md PDF 임포트 절 — 「수동 외벽선 확정(useOuterLineWall.handleFix) 직후와 동일한 상태」.


6. 자동 확정 구현 가이드 (권장)

6-1. handleFix 를 그대로 호출하지

handleFixuseOuterLineWall 훅 내부에 묶여 있고, 전제 조건이 다르다.

  • Recoil outerLinePointsState미닫힌 정점 배열이어야 함 (마지막 ≠ 첫 점)
  • WallLineSetting 모달이 마ounted 되어 propertiesIdRoofShapeSetting 을 열어야 함
  • 직각-only 다각형이면 조용히 실패

PDF 경로는 이미 닫힌 폴리곤 + 라인 객체가 있으므로, 훅 밖에서 후처리하는 편이 안전하다.

6-2. 권장: 공통 「확정 후처리」 추출 (미래 리팩터)

아래를 finalizeOuterLine({ canvas, points, options }) 같은 유틸/훅으로 묶으면 수동·PDF·자동 옵션이 한 경로를 탄다.

입력: closedPoints (첫점=끝점 포함 가능, drawOuterLines 기준 인접쌍)
1. clearExisting outerLine / outerLinePoint (필요 시)
2. drawOuterLines(closedPoints)      // useLine.addLine
3. drawOuterLinePoints(closedPoints)
4. CCW 보정 (정점 또는 ccwCheck)
5. canvas.outerLineFix = true; setOuterLineFix(true)
6. canvas.renderAll()
7. [옵션] fitViewport
8. [옵션] addPopup(RoofShapeSetting)

6-3. 최소 변경 (현재 코드베이스)

applyOuterlineproceed() 끝에 옵션 분기만 추가:

// options.autoOpenRoofShape === true 일 때
const roofShapeId = uuidv4()
addPopup(roofShapeId, 1, <RoofShapeSetting id={roofShapeId} pos={{ x: 50, y: 230 }} />)
setCurrentMenu(MENU.ROOF_COVERING.ROOF_SHAPE_SETTINGS) // 메뉴 탭 동기화

usePopup / useMenu 의존은 usePdfImport 또는 호출측(PdfImportModal, PlacementShapeSetting)에서 주입.

6-4. 검증 체크리스트 (자동 확정 후)

  • canvas.getObjects().filter(o => o.name === 'outerLine').length >= 3
  • 각 QLine 에 attributes.planeSize 존재
  • canvas.outerLineFix === true
  • useRoofShapeSetting 마운트 시 wall.line.not.found 미발생
  • 치수 라벨(mm)이 실측과 일치 (scale 미적용)
  • 외벽선 그리기 메뉴 재진입 시 setOuterLineFix(false)재편집 모드로 떨어지지 않도록 — PDF 플로우는 ROOF_SHAPE_SETTINGS 메뉴 유지 (PlacementShapeSetting 참고)

7. 관련 Recoil / Canvas 플래그

타입 확정 전 (그리기 중) 확정 후
outerLinePointsState {x,y}[] 미닫힘 정점들 닫힘(마지막=첫점) 또는 동일 좌표의 closed ring
outerLineFixState boolean false (2점 이상) true
canvas.outerLineFix boolean (canvas 커스텀) false true — 직렬화/가드에 사용 (common.js 'outerLineFix')

canvasAtom 의 selector 는 outerLineFix === false 이거나 points 비어 있으면 특정 UI를 잠근다.


8. 확정 이후 파이프라인

handleFix 완료
    → RoofShapeSetting (useRoofShapeSetting)
        → WALL/ROOF 폴리곤 생성, pitchText, 처마/케라바 타입
    → (이후) 보조선, 처마·케라바 편집, 배치면 …

useRoofShapeSetting 진입 가드:

if (!canvas.outerLineFix || outerLines.length === 0) {
  swalFire({ text: getMessage('wall.line.not.found') })
  closePopup(id)
}

자동 확정 없이 outerLineFix 만 켜 두면 메뉴는 지붕형상으로 가도 모달을 열어 주지 않으면 사용자는 수동으로 메뉴를 눌러야 한다.


9. 유사 이름 주의 (handleFix 동명이인)

용도
useOuterLineWall.handleFix 본 문서 대상 — 외벽선 그리기 확정
usePropertiesSetting.handleFix 외벽선 속성(처마/케라바) 확정 — 다른 모달
usePlacementShapeDrawing.handleFix 배치면 그리기 확정
useRoofLinePropertySetting.handleFix 지붕선 속성 확정
useAuxiliaryDrawing.handleFix 보조선 확정

DOM class btn-frame modal act + 「외벽선 확定/외벽선 확정」은 WallLineSettingPlacementShapeDrawing 등에서 공유 메시지 키를 쓸 수 있다. DOM path modal-pop-wrap r + useOuterLineWall 이면 본 문서 대상이다.


10. 참고 문서·코드

  • docs/PDF Gemini 평면도 분석 기능 구현 계획.md — PDF → 캔버스 반영 전체
  • docs/Canvas Status.md — §2.1 외벽선 그리기, §2.2 지붕형상 설정
  • CLAUDE.md — PDF 임포트 불변식 (scale, addLine, outerLineFix)

작성: 2026-06-19 — PDF 자동 외벽선 확정 기능 설계용