← 목록
기타 2026-07-18 7KB 읽기 6분

Crowny CAD 스케치 기능 1차 — 새 파일·선·사각형·면 채우기·돌출 + 코드 최적화

개요

cad.crowny.org의 브래킷 파라메트릭 데모를 넘어 실제 스케치 편집을 구현했다(사용자 지시 순서: 새 파일→선→사각형→면 채우기→입체 올리기). 다중 문서(멀티 파일) + 엔티티 영속 + 실 undo/redo + 커맨드 기반 데모 E2E 경로.

구현 (소넷 2기 병렬 + 수리 2라운드)

백엔드 (서버.한선 1103→1348줄, CAD엔진.한선 196→300줄)

  • 신규 5라우트: POST /api/file/new(blank 문서 생성·활성 전환) · GET /api/files · POST /api/file/open · GET/POST /api/entities(docId당 latest-wins, _JSON배열추출 브래킷 카운팅)
  • 다중 문서: 문서.psv 후행 필드 확장(docId/name/template, 레거시 행=d0/브래킷-A/bracket), 활성문서.psv 단일행 포인터
  • 엔진: 엔진_엔티티닫힘·엔진_돌출부피(rect 면적합×D)·엔진_스냅
  • 최적화: _경로매치() 헬퍼로 디스패치 23지점 통합, _콤마접두 4지점

프론트 (앱.html 1384→1801줄)

  • 새 파일(+버튼·⌘N·파일명 드롭다운), 선/사각형(2점 클릭·mm↔SVG 변환 getScreenCTM·5mm 스냅·rAF 단발 미리보기), 선택+스케치 요소 패널(채우기 해칭 토글·삭제), 돌출(3D 프리즘 — 브래킷 사선투영 공식 재사용, blank 부피/질량 재계산)
  • 실 undo/redo: 커맨드 객체 {type,before,after} 스택(핸드오프 README 원칙), ⌘Z/⇧⌘Z
  • ?demo=1[&view=3d] 커맨드 경로 데모(검증용, 실서버 경유)
  • 최적화: MAT_DB 등 7상수 모듈 스코프 호이스트 → 렌더 ~10% 가속(0.156→0.140ms), 출력 바이트 불변

수리 이력 (라이브 실측이 잡은 실버그 4건)

  1. blank 문서 sk 뷰에 브래킷 잔재(치수 라벨·타임라인·수정요청 배너·구속 행) 누출 → template/docId 가드
  2. 3D 뷰 blank 분기에서 브래킷 롤백 라벨·플랫 면 렌더(svgLabels 별도 경로 누수) → 분기 재배치, assert 강화(프리즘 존재 AND 브래킷 라벨 부재)
  3. 새 파일 파라미터 0 + 서버 응답 레이스 → cmdNewFile 기본값 시딩(W200 H120 D40 ⌀12 v14) + dirty 플래그·스테일 응답 폐기 가드
  4. d0 오염 사고: POST /api/doc이 docId 미포함으로 활성/기본 행에 데모 상태 덮어씀(브래킷-A가 W0/v1로) → 프론트 saveDoc docId 명시 + 서버 docId 인지 저장(+unknown docId 거부) + d0 복구

검증 (전부 실측)

  • 노드 하네스 누적 64 assert PASS(엔티티 5단계·undo/redo 왕복·3D 프리즘·부피 384,000mm³/1.04kg·d0 오염 시나리오 방어·브래킷 5뷰 회귀)
  • 앱.한선 파리티 25/25 PASS(엔진_돌출부피 384000·질량라벨 1.04kg·스냅 — 엔진 함수 재사용)
  • 서버: STRICT 경고 0, docId 저장 4시나리오, kickstart 재기동 후 엔티티·활성문서 복원
  • 헤드리스 스크린샷 육안 3매: 데모 스케치(선+해칭 사각형+돌출 마크+384.0cm³), 데모 3D(프리즘), 브래킷-A 복귀(완전 원상 — 외곽·구멍4·치수·피처4·2.54kg)
  • 렌더 DOM 결정형 마커 검사(스크립트 제거 후): 있어야 5종/없어야 5종 전부 PASS

파일·잔여

  • /Users/ef/crowny-cad/: 서버.한선·CAD엔진.한선·앱.html·앱.한선(25 assert)·data/{문서,엔티티,활성문서,...}.psv
  • 잔여: 데모 실행이 문서를 생성·활성 전환(검증 후 d0 복귀 운영수칙, append-only라 삭제 API 없음 — 의도) · 선(line) 엔티티는 돌출 대상 아님(rect만) · 원/호 등 나머지 스케치 도구는 후속
  • 학습 래칫: CAD엔티티저장_다중파일·CAD돌출부피계산·라우팅경로매치헬퍼·cadundoredo·cadmmsvgtransform (누적 5건+)

5차 (실작동 수리 — 2026-07-20, "선긋기 안됨/캔버스사이즈")

사용자 실사용에서 "선이 안 그어진다"·"캔버스 사이즈" 지적 → CDP 실마우스 주입 진단으로 근본원인 2건 확정·수리:
  • 원인1(선긋기 안됨): 기본 진입 문서가 브래킷(template='bracket')이라 onViewportDown이 즉시 return → 새 파일을 먼저 안 만들면 그리기 도구 클릭이 무반응. 수리: 비-blank 문서에서 그리기 도구(선/사각형)로 뷰포트 클릭 시 자동으로 새 스케치 캔버스 생성 후 그 클릭을 첫 점으로(안내 토스트). 이제 앱 열자마자 선 도구→클릭 2회로 선이 그려짐.
  • 원인2(캔버스사이즈): blank 문서에 그리기 경계가 없어 어디까지 그릴 수 있는지 불명 → 실측 좌표는 정확(letterbox 아님)이나 시각적 캔버스 부재. 수리: 작업 시트 경계(점선 rect)+원점 마커+"캔버스 W×H mm" 라벨+빈 캔버스 안내 문구 렌더, 우측 패널 캔버스 크기 프리셋(A4/A3/소형/대형), 그리기 좌표를 캔버스 경계로 클램프.
  • 검증(CDP 실마우스+node): ①앱 진입→선 도구→클릭(새파일 없이)→자동캔버스+선[50,50-150,50] ②전체 파이프라인 실클릭(사각형→채우기 filled:1→돌출 extruded:1→3D 프리즘 1232cm³/3.33kg) ③브래킷 복귀 무회귀(구멍4·2.54kg·캔버스 누출 0) ④회귀 하네스 29/29 PASS. 도구=tools/{하네스.js(회귀 가드),cdp전체.js(실클릭 E2E)}. 저좌표/고좌표 창(1440×900·1200×560) 둘 다 좌표 정확.

6차 (원·치수 추가 — 2026-07-21)

사용자 지시 "선긋기·사각형·원·치수 실제 작동": 원(circle)·치수(dim) 스케치 엔티티 추가.
  • 원(C): 중심→반경점 2클릭, 중심 십자+미리보기 원, 채우기(해칭)·돌출(3D 실린더=하단타원+측면 path+상단타원) 지원, 부피 π·r²·D. 패널 "⌀Nmm".
  • 치수(D): 두 점 클릭→치수선+양끝 틱+중점 값라벨(#C05B2E), 측정 전용(채우기/돌출 불가). 패널 "Nmm".
  • 엔티티 계약 kind 확장(line|rect|circle|dim), cmdAddCircle/cmdAddDim(커맨드스택·undo), 3D 부피에 원 단면적 합산.
  • 한선 파리티: CAD엔진.한선 엔진_돌출부피에 원 분기(π=3142/1000 스케일, 루트로 반경)+엔진_엔티티닫힘(circle=1). 앱.한선 파리티 25→27/27 PASS(원돌출부피 201080·닫힘). STRICT 경고 0. 서버 재컴파일+kickstart 회귀(2543·1190·16500).
  • 검증: 하네스 41→42 PASS(원 ⌀80·부피·치수 150mm·3D 실린더·빈스케치 누출0). CDP 4도구 실클릭(선·사각형·원·치수 그려짐→원 채움+돌출 circleFE→3D 실린더 201.1cm³/543g). 파일 전환 실클릭(새캔버스↔브래킷 왕복). 브래킷 무회귀. 도구=tools/{하네스.js,cdp4도구.js}.