Commit Graph
572 Commits
Author SHA1 Message Date
eomsangdonandClaude Opus 5 e371c2754a feat(B05,B06): 물넘이 3D 파임 + 독립 기슭막이 횡단·3D + 포장 기본값·표준횡단 반영
2026-08-28 사용자 지시 4건.

① 물넘이 파임을 3D 코리도에도 반영
   classifyStation 이 노면·노견 조각 표고를 횡단도와 같은 산식(fordDeckElevationAt)
   으로 내린다. 노면 밖 비탈은 그대로라 노견 끝에 수직 단차가 선다. BUILD_VERSION 85.

② 표준횡단면 저장분을 포장 재계산에 싣는다
   확정 때 종단 정본 options 에 실린 standard_cross_section 을 읽어
   enforce_pavement_ranges / attach_default_designs 에 넘긴다. 없으면 config 기본값.

③ 포장 구간 기본값 10 / 5 / 5 (기슭막이와 같은 출발값).

④ 독립 기슭막이
   - 측점: is_station_planting_type() 규칙 신설(A군 + D군 구간형). 구간형은
     시작·기준·종료에 측점을 심는다 — 길이가 길수록 횡단도가 여러 장 나온다.
     구조물 재이관 차단도 같은 규칙을 본다(기타 고스트 방지).
   - 서버: B06_Section_Engine_Revetment 신설 — 구간 안 측점 전부에 section.revetment.
   - 횡단도: B06_Section_UI_Cross_Revetment 신설 — 벽 상단 = 성토면 끝(설계선-지반
     교차점), 아래로 높이 + 근입 0.5m, 전면 1:0.3(교본 7-3). 설치 측은 사용자가
     좌/우로 고른다(레지스트리 side 옵션 신설 — 자동 판정 없음).
   - 3D: 같은 폴리곤을 기준측점 전/후만큼 스윕. BUILD_VERSION 86 + 구조물 해시에
     물넘이·기슭막이 제원 추가.

검증: pytest 241 passed / 7 skipped(신규 4건). 공용 브라우저 실측 —
물넘이 240m 투입 시 3D 노면이 계획고보다 0.38~0.42m 아래(대조군 200m 정상),
기슭막이 225~255 투입 시 측점 23→25·횡단 카드 3장·3D revet 솔리드 3개(31링).
임시 데이터는 원래 정본으로 복구했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:54:45 +09:00
eomsangdonandClaude Opus 5 80c2a265f9 feat(B05,B06): 물넘이 횡단 표현 + 포장 구간 수기 지정, 경사 자동 포장 폐지
2026-08-28 사용자 확정 스펙.

물넘이포장 — 노면을 판 자리로 그린다
- 서버가 _ford_pavement_set(월류 폭·월류 높이·바닥 경사)을 만들고 물넘이만
  span 연동을 켜 **범위 안 측점 전부**에 얹는다. 깊이가 없으면 None으로 두어
  화면이 그리지 않는다(수치를 지어내지 않는다).
- 횡단도: 기존 계획고 점선 + 물넘이 바닥 실선 + 진한 회색 빗금 포장.
  깊이는 노선 중심 기준, 바닥은 유입(상단측)이 높게 기운다. 경사를 비우면
  그 측점의 노면 횡단경사를 쓴다.
- 물넘이 폼에 "바닥 경사 유입→유출(%)" 칸을 추가하고, 월류 폭 기본값
  리터럴을 config_frontend 상수로 모아 서버 값과 짝지었다.

포장 — 사용자가 구간으로 지정한다
- 구조물 레지스트리 G군 pavement_concrete 를 되살려 기준측점 + 길이 + 전/후로
  받는다(기슭막이와 같은 폼). 길이 기본값은 0 = 미지정.
- pavement_ranges/paved_at 이 구간을 판정하고, enforce_pavement_ranges 가
  저장분이 비포장이어도 구간 안이면 포장으로 다시 계산한다(사용자 조작값 승계).
- **종단경사 자동 포장 적용을 없앴다** — paved=suggested 3곳 제거. 별표1-2 상한
  초과 경고(pavement_suggested 배지·근거 문구)는 그대로 남는다.
- 포장 구간이 물넘이를 통째로 품으면 모달로 알리고 앞/뒤로 나눠 저장하고,
  끝만 걸치면 값을 고치라고 안내하고 멈춘다.

700줄 제한: _compute_default_designs 를 Router_Design 으로 옮겼다(657/306줄).

검증: pytest 238 passed / 7 skipped(신규 9건). 공용 브라우저 실측 — 물넘이 임시
투입 시 240m 카드에만 파임 3요소가 그려지고(일반 포장 박스 0), 바닥이 계획고보다
0.4m 아래·노면 전폭 4.0m에 1.5% 기울기, 220·260은 비포장 유지. 겹침 규칙은
브라우저에서 모듈을 직접 불러 3분할·안내·취소를 확인했다. 실측용 임시 관 지점은
매번 원래 정본 4건으로 복구했다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 12:16:38 +09:00
eomsangdonandClaude Opus 5 10bb43b380 feat(B05,B06): [임시저장] 버튼명을 [저장]으로 바꾼다
상태로 보면 '변경사항 저장'이 맞고 '확정 전 임시'라는 이름이 혼선을 줬다
(2026-08-28 사용자 지시). 기능 변경 없음 — 라벨·토스트 문구만 바꾼다.

- B05_Route_Btn_TempSave / B06_Profile_Btn_Save: 임시저장 -> 저장
- 토스트 4건: '임시 저장했습니다' -> '변경 내용을 저장했습니다' 등
- [편집 되돌리기] 툴팁의 '이미 임시저장한 내용은' 문구 정리

검증: tsc --noEmit 통과. 공용 브라우저 실측 — B05 하단 액션이
[초기화][저장][횡단 이동], '임시저장' 라벨 0건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 10:14:28 +09:00
eomsangdonandClaude Opus 5 41cbc0f1e9 fix(B05): 물넘이포장을 비정규 측점에서 빼고 종단 알약으로만 둔다
횡단도로 표현할 것이 없는 시설이라 측점을 만들 이유가 없다(2026-08-28 사용자 확정).
서버는 resolve_extra_stations 에서 이미 제외했고, 프론트도 맞춘다.

표시(setIrregularStations)와 서버 전송(irregularStations())에서만 뺀다 —
관 정본 대조(setPipeChainages)는 전체 목록을 써야 물넘이가 정본에서 지워지지
않으므로 pipesToStations 는 그대로 둔다. 알약 레인은 pipesToMarks 가 따로
만들므로 구조물 버튼은 그대로 남는다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 09:46:26 +09:00
eomsangdonandClaude Opus 5 0979927dfc fix(B05): 구조물 측점을 정본 파일에서 파생하는 단일 공급자를 세운다
[초기화] 후 관 지점 횡단(비정규 측점)이 통째로 사라지던 문제. 측점 정본은
longitudinal.json stations + cross_*.json 파일인데, 그 파일을 쓰는
run_section_generation 에는 공급자가 없었다. 유일한 공급자가 프론트
[임시저장]이라 초기화·반폭 재생성이 파일을 다시 쓸 때마다 측점이 날아갔다
(실측: 초기화 직후 cross 23 -> 19, irregular 4 -> 0).

- resolve_extra_stations 신설 — 관 정본(pipe_points.json) + 구조물 정본 A군에서
  매번 파생한다. 라벨 형식은 프론트 structureLabel()과 같다. 물넘이포장은
  비정규 측점으로 올리지 않는다(2026-08-28 사용자 확정).
- run_section_generation 이 generate_sections 앞에서 이 목록을 심는다. 호출자가
  넘긴 extra_stations 는 무시한다 — DB 스냅샷으로 되쓰이는 값이라 되먹이면
  B04에서 지운 관이 파일 정본을 이기고 부활한다.
- _load_pipe_anchors -> _load_pipe_points. 계획선 정착과 측점 생성이 같은 한 번의
  읽기를 쓴다. 지문 불일치 경고에 버린 건수를 남겨 침묵 실패를 없앤다.
- B06_Section_Router._extra_stations 삭제(자기참조라 늘 빈 값이었다).
  706 -> 689줄로 700줄 규칙 위반도 함께 해소.
- 격자와 같은 정수 미터인 비정규 측점은 격자로 스냅한다 — cross_*.json 파일명이
  정수 미터라 측점 수와 파일 수가 어긋났다.
- 구조물 이관 필터를 A군 6종 라벨로 넓힌다 — 서버가 심은 세월교·BOX암거 라벨을
  "기타"로 재이관하던 고스트를 막는다.

검증: pytest 229 passed / 7 skipped(신규 14건). 공용 브라우저 실측 — 초기화 직후
임시저장 없이 cross 23 / irregular 4(라벨 일치), B06 카드 23장, 반폭 재생성
20->25->20 에도 23 유지, DB cross_sections 23행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-28 08:38:58 +09:00
eomsangdonandClaude Opus 5 3a5680fd76 fix(B05): 잘린 자리 윤곽을 실좌표에서 다듬어 성토부 터짐을 막는다
유출구 쪽 성토부에 성토면도 지형도 없는 검은 쐐기가 남던 문제(2026-08-27 사용자:
"유출구에 일부 성토부에 터짐 있음").

원인 두 가지.
- dropCollinear 가 **격자 인덱스 공간**에서 공선 판정을 했다. 코리도 격자는 노선을
  따라 휘어 있어 인덱스로 직선인 구간이 실좌표에서는 곡선이다. 그걸 지우면 폴리곤이
  실제 마스크 안쪽으로 코너를 잘라먹고, 그 밖 셀은 되살릴 영역에서 빠져 구멍이 된다.
  빠진 셀이 전부 편거리가 큰 바깥 끝 열(40~46)이었던 것도 이것으로 설명된다.
- traceMaskLoops 가 갈림목에서 아무 변이나 집어(pop) walk 가 남의 고리로 새 나가고,
  막다른 길에서 끊긴 열린 사슬을 고리로 담았다. 표시용일 땐 안 보였지만 이 커브가
  되살릴 영역의 근거가 된 뒤로는 판정을 무너뜨린다.

- Cut: dropCollinear 를 실좌표(모델 XY) 기준 수직거리 1mm 판정으로 바꾸고, 고리를
  **실좌표로 옮긴 뒤** 다듬는다. traceMaskLoops 는 갈림목을 오른손 규칙(마스크를
  왼쪽에 두고 담으므로 우회전 우선)으로 가르고 **닫힌 고리만** 담는다.
- BUILD_VERSION 83 -> 84.

실측(공용 브라우저) — 도려낸 셀 중 되살릴 영역이 안 덮는 셀:
- 우측 1,447/7,941(18%) -> 109/7,941(1.4%)
- 좌측 1,292/7,021(18%) -> 14/7,021(0.2%)
- 지형 유지 삼각형 476,906 -> 478,459 (+1,553)
- cut-merged 고리 8개, 점 수 47~128 (절단선 폭증 없음)
- tsc --noEmit 0

남은 0.8%: _Corridor_Region.ts simplifyLoop 의 마디 하한 0.25m 가 셀(0.06~0.2m)보다
커서 경계를 조금 더 안쪽으로 당기는 것으로 보인다. 별도 항목으로 남긴다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 22:38:46 +09:00
eomsangdonandClaude Opus 5 5118482767 fix(B05): 원지반 재노출 영역을 실제로 도려낸 자리 윤곽(cut-merged)으로 바꾼다
구조물 자리에 원지반이 드러나지 않거나, 드러나도 날개벽 자리에 성토면도 지형도
없는 검은 슬리버가 남던 문제.

원인은 지우는 쪽과 되살리는 쪽이 **서로 다른 자료로 영역을 만든 것**이다.
- 지우는 쪽: 성토 리본 셀 마스크(slope-projected ∪ wing-box, 0.2m 격자 + 현 절단)
- 되살리는 쪽: 원본 성토 스케치 − (구조물 ∪ 변형 성토 스케치)를 **다시 조립**
구조물 고리에는 날개벽이 패널 두께 슬리버로 섞여 있어 그 자리만 covered로 빠졌고,
BOX암거에서는 변형 성토선이 원본과 collinear가 되어 영역이 통째로 공집합이었다.

이제 지우는 쪽이 남긴 자국을 그대로 쓴다 — cut-merged 는 _Corridor_Cut.ts 의
traceMaskLoops 가 셀 마스크에서 되짚은 윤곽이다. 그 안의 지형은 도려내지 않으므로
**원본 지형 메시가 그 자리에 그대로 남는다**. 새 서피스를 만들지 않는다
(2026-08-27 사용자: "원지반 오리지널 데이터에서 가져오라니까", "회색 서피스는
있는데 원지반과 같은 메시가 아니잖아. 너가 그냥 만든 거잖아").

- Clip: withStructureHoles 를 cut-merged 한 줄로 대체. slope-original/wing-box/
  structure/slope-deformed 조합과 axisLocked 분기 삭제(순 -20줄). __corridorHoles
  는 고리 수 대신 exposeLoops/exposeCells/exposeRatio 를 담는다.
- BUILD_VERSION 82 -> 83.

실측(공용 브라우저):
- cut-merged 고리 8개 = 구조물 4세트 x 좌우.
- exposeCells 23/6400(0.36%) -> 164/6400(2.56%). 7배.
- 지형 유지 삼각형 474,854 -> 476,885 (+2,031).
- tsc --noEmit 0.

폐기한 시도(같은 브랜치 2d897164 이후 작업트리에서만 존재했다):
성토 격자에 원지반 표고를 재샘플링해 역마스크로 까는 방식. 경계는 정의상
일치했으나 코리도 격자로 다시 만든 면이라 원지반 메시와 형상이 달랐다.

남은 것: 유출구 일부 성토부 터짐(사용자 확인) — 다음 작업.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 22:32:01 +09:00
eomsangdonandClaude Opus 5 2d897164cc feat(B05): BOX암거 구조물 자리 원지반을 재노출한다 (영역 뺄셈 방식)
BOX암거(측점 200.92) 자리에서 구조물이 들어와도 원지반이 드러나지 않던 문제.
원지반 재노출 공식은 `원본 성토선 − (구조물 ∪ 변형 성토선)`인데, BOX는 변형
성토선이 원본과 기본값에서 정확히 collinear가 되어 결과가 공집합이었다.

- Station_Structure: StructureSilhouette.endsAtStructure 신설, boxSilhouettes만 true.
  BOX 실루엣은 "구체 밖으로는 잇지 않는다" 원칙대로 구체 최상단에서 끊긴다.
- Plan: endsAtStructure면 slope-deformed를 trimSlopeToGround로 지반까지 외삽하지
  않는다. 종전엔 무조건 최대 30m 외삽해 원본 성토선과 겹쳤다. 기하(낙차 0.5m)로
  판정하지 않는 이유는 기슭막이 유출측 회귀 때문이다(실측 84.3 우측 5.10 -> 5.69m).
- Clip: 재노출 후보에 BOX의 wing-box(날개 사다리꼴) 추가 — 절취 소스에는 있고
  되살릴 목록에는 없어 그 자리가 성토면도 지반도 없는 구멍이었다. 세월교는 제외
  (그 자리는 되메움 패치가 덮는다). __corridorHoles에 exposeCells/exposeRatio 추가 —
  고리 수만으로는 되살릴 영역이 공집합인지 알 수 없었다.
- Structures/Structures_Box/Plan_Footprint: planOutline 표식(상판+에이프런)과
  outlineLoop 신설. BOX structure 탑뷰 커브를 부재별 7고리가 아니라 아령 외곽선
  한 줄로 낸다 — 부재별로 내면 날개벽이 패널 두께 슬리버로 남는다. 기하 불리언은
  쓰지 않는다(BOX 부재는 전부 같은 고정축 위 평행 링).
- BUILD_VERSION 80 -> 82.

실측(공용 브라우저, git stash 로 코드만 교체):
- slope-deformed bbox 200.92 좌 2.85x4.46 -> 2.44x1.02, 우 2.76x3.76 -> 2.42x0.88.
  세월교 149.73·배수관 84.3/275.71 은 소수점까지 불변 = 무회귀.
- structure 고리 200.92 좌우 각 7 -> 1(면적 5.18 = 상판 1.79 + 에이프런 3.39 정확 일치).
  슬리버 0.40x2, 0.15x2 소멸.
- __corridorHoles.original 8 -> 12, covered 44 -> 32.
- 지형 유지 삼각형 477,153 -> 477,613.
- tsc --noEmit 0.

미해결: 날개벽 안쪽 검은 슬리버가 화면에 남아 있고 면이 삐져나온다(사용자 확인).
다음 커밋에서 접근을 바꾼다 — 영역 뺄셈 대신 성토 격자의 groundZ(원지반 표고)를
역마스크로 복사해 도려낸 셀에 그대로 깐다. 이 커밋은 그 되돌림 지점이다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 22:13:26 +09:00
eomsangdonandClaude Opus 5 521fb89c30 fix(B05): 기슭막이 상단 성토면을 되메움 리본 배열에 담는다
배수관 세트(기슭막이) 구간에서 노견 → 벽 이음선 상단 성토 사면이 3D에서 통째로
비어 있었다. 포켓(FILL_CUT_APPLY)은 노견까지 파는데, 되메움 배열(fillRuns,
4a5a98fe)에는 벽 아래 다단 성토선·집수정 성토선만 담겨 그 위가 안 메워졌다.
culvertSilhouettes가 designTrim 사면선을 push(실루엣)만 하고 addRun(리본)은 하지
않은 게 원인 — 세월교·BOX암거는 각각 fillSegments·fillLine으로 담고 있어 무관하다.

새 면을 만들지 않는다. 실루엣이 이미 쓰던 designTrim.min/maxSlope 점 배열을 리본
배열에도 등록할 뿐이다.

- Station_Structure: pushTopSlope() 추가 — push + addRun을 함께 하되 측당 한 번만.
  벽 루프와 집수정 분기가 같은 designTrim 사면선을 각각 담으므로 표시가 없으면
  리본이 두 장 겹친다. 호출 3곳(벽 루프, 집수정 slope, 집수정 2점 폴백).
- Corridor: BUILD_VERSION 79 -> 80.

실측(공용 브라우저 A/B, git stash로 코드만 교체):
- 패치 리본 6 -> 10장. 늘어난 4장 전부 기슭막이 세트(측점 84.3·275.71).
- 275.71 좌측: 기존 z 531.11~535.93 바로 위에 536.85~539.92가 새로 앉았다.
  사이 0.92m는 벽 전면 — 구조물 솔리드 몫이라 원래 비는 자리.
- 84.3은 수정 전 양측 0장 — 포켓만 파고 되메움이 통째로 없었다.
- 날개형 구조물(149.73·200.92) 리본 수·z 범위 소수점까지 불변 = 무회귀.
- tsc --noEmit 0.

화면 검증은 사용자가 직접 수행(2026-08-27 사용자 지시).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 21:02:28 +09:00
eomsangdonandClaude Opus 5 a756181067 feat(B05): 세월교 변형 성토면을 절취 영역 경계에 맞춰 채우고 잘라낸다
세월교 날개 사다리꼴이 안 채워지고, 채운 판이 절취 영역 밖으로 삐져나오던 문제.
원인은 패치 리본이 "노선 프레임 수직 행 × 소유 측점 단면 한 장" 스윕이라
비스듬한 날개 부채꼴과 방향·범위가 안 맞는 것이었다. 세월교 전용으로 고친다
(`section.ford` — BOX암거·기슭막이는 종전 경로 그대로).

- 종방향: `wingSpanOnRoute` 신설. 날개 고리 점을 frameAt로 0.25m 간격 훑어 노선에
  실투영한다. 종전 직선 전방 투영은 곡선+먼 편거리(-7.85m)에서 3m 어긋나 고리
  앞부분이 범위 밖으로 밀려났다. 범위는 점유 구간 ±5m로 묶는다.
- 횡방향: `wingRangeAt`이 행 횡단선 × 주황 고리 교점의 안쪽·바깥쪽 끝을 낸다.
  바깥은 `extendRunTo`, 안쪽은 `prependRunTo`(노견 클램프). 지반 핀·스커트 유지.
- `clipRunBelow`: 바닥판 상단 Z(ford slabTopElevation)를 넘는 점을 지운다.
  종단 shift 반영, 천장 지나는 마디에 교차점 삽입.
- `patchClip`: 패치를 maskFillByPlanCurves에 한 번 더 통과시켜 **지우는 규칙의
  반대**를 건다 — 절취 영역 밖 셀은 지우고, 걸친 셀은 clipCellByChord(inside)로
  안쪽 조각만 남긴다. 두 면이 같은 경계를 공유한다.
- 700줄 초과로 날개 몫 도구를 _Corridor_Carve_Wing.ts로 분리(순수 이동).
- `__corridorScene` 노출(검증용 레이캐스트 좌표 변환).
- BUILD_VERSION 67 -> 79.

자체검증: 삐져나온 패치 셀 우 74->0(145셀 마스크+조각 198), 좌 지느러미 47->0.
BOX암거·기슭막이 masked=0(무변화). 영역 안 구멍 우 66/98% -> 39/56%.
typecheck 통과, tmp/tests 213 passed·7 skipped, 변경 파일 prettier.
남은 작업: 좌측 96% 구멍(slope-projected 전폭 절취 vs fillSegments 0.25m),
BOX 패치 리본 축퇴 원인 확인.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 20:02:00 +09:00
eomsangdonandClaude Opus 5 a864acd17d feat(B05): 변형 성토면을 지반 교차선에서 끊고 구조물 자리 원지반을 되살린다
- 패치(변형 성토면) 바깥 끝 스커트 신설(_Corridor_Skirt.ts): 지형 메시 높이를
  밑선으로 성토면 → 원지반 −1m까지 판을 세운다. 성토 빗금 메시 서피스로 그린다
  (절취 측벽은 종전대로 일반 서피스). 소유 측점 행에서 지반에 닿는 줄만 대상
  (허용 0.5m) — 벽 뒷면·구체 상단에서 끝나는 줄은 제외해 BOX암거 앞면에 없던
  서피스가 생기던 회귀를 막는다.
- 패치 행을 그 행 지반선과 직접 교차시켜 자르고 연장한다(trimSlopeToGround).
- 날개 사다리꼴 몫만큼 패치 행 범위를 넓히고(wingSpanOf), 날개벽 평면 스케치는
  트림하지 않는다. BOX암거는 행 가로 방향을 기준 측점 좌향으로 고정한다.
- 구조물 안착 자리 원지반 재노출: 원본 성토 스케치 − (구조물 ∪ 변형 성토 스케치)를
  코리도 스트립에서 빼 지형을 남긴다(PlanLoopRegion·SubtractedRegion 신설).
- BUILD_VERSION 63 → 67: 저장본을 만료시켜야 기하 수정이 화면에 반영된다.

자체검증: 스커트 3리본 56판(최대 낙차 0.92m), 원지반 +2,104 삼각형,
tmp/tests 213 passed, typecheck·prettier 통과.
남은 작업: 세월교 날개 사다리꼴 채우기(날개 축 스윕) — 다음 세션.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 18:42:15 +09:00
eomsangdonandClaude Opus 5 4a5a98fe44 feat(B05): 구조물 구간 성토면을 B06 구간 배열대로 되메운다
B06 횡단이 내는 변형 성토선을 3D 포켓에 되메운다. 다단 기슭막이면 횡단이
성토 > 구조물 > 성토 > 구조물 > 성토라 성토선이 하나가 아니다 — 합치지 않고
구간 1줄 = 리본 1장으로 낸다.

- Station_Structure: StructureSilhouette.fillRuns 추가. 31점 폴리라인을 인덱스로
  쪼개지 않고 B06 배열(outletFill/basinFill.segments, ford fillSegments, box
  fillLine)에서 바로 담는다. 벽 전면은 안 담는다 — 구조물 솔리드 몫.
- Carve: 패치 리본을 실루엣당 1장이 아니라 run당 1장. 구간 배열을 쓸 때는 벽 트림을
  걸지 않는다 — 바깥 끝 하나로 자르는 규칙이라 단 사이 구간이 아랫단 벽 바깥까지
  통째로 잘려 사라졌다(실측: 0.86m 구간 2개 전멸). 배열이 비면 리본도 없다.
- Build: FILL_PATCH_APPLY 신규(옛 CARVE_APPLY 대체). 투영 커브·절취를 다 낸 뒤
  붙인다 — 먼저 넣으면 투영선이 패치에서 z를 읽어 절취 경계가 달라진다.
- Viewer: snapCorridorEdges에서 패치 제외. B06 성토 구간은 벽 뒷면·구체 최상단에서
  끝나는 게 정상인데 지형에 스냅해 4.1m 세로 지느러미가 생겼다(실측).
- BUILD_VERSION 60 -> 63.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 16:04:51 +09:00
eomsangdonandClaude Opus 5 106536b145 fix(B05): 측벽을 본 구조물·날개 **머지 영역의 경계**로만 세운다
절취 영역은 본 구조물 스트립과 날개 사다리꼴을 **합친 것**인데, 벽은 두 스케치의
변을 따로 세우고 있었다. 그래서 한쪽 영역의 변이 다른 영역 **안쪽**을 지나는 구간
(속살)에도 벽이 섰다 — 세월교 좌측 실측: 날개 광선 1.87m·1.77m 구간이 스트립 안에
통째로 잠겨 있었다(2026-08-27 사용자 지적).

직전 커밋(86d1d6ac)은 날개가 있는 측의 끝 횡단선을 통째로 뺐는데, 그러면 날개가
못 덮는 도로 쪽 구간이 비어 반대로 모자랐다. 되돌리고 **경계 트림**으로 바꾼다.

- Plan: `trimToUnionBoundary()` 신설 — 벽 후보 변을 다른 영역 테두리와의 교점에서
  쪼개고, 조각 가운데가 다른 영역 안이면 버린다. 2cm 미만 부스러기도 버린다.
  세트마다 벽 후보(스트립 끝 횡단선 2개 + 날개 [끝선→날개→끝선])와 근거 영역을
  모아 두었다가 세트가 끝날 때 한 번에 `cut-wall`로 낸다.
- BUILD_VERSION 59 → 60.

검증(실빌드 데이터, 구간 중점 양옆 2cm 판정):
- 8개 세트·측 **전부 경계 100%** — 속살(양옆 다 안쪽) 0, 영역 밖 0.
- 구간 수 세트당 2~8(84.3 2 · 149.73 6 · 200.92 8 · 275.71 2), 벽 판 16장/측,
  삼각형 32개/측, 판 길이 0.17~11.52m, 최대 높이 3.15m.
- 노견선·성토 끝선 위 판 0 유지.
- ISO 근접 캡처: BOX·세월교 절취부 옆면이 큰 판으로 이어지고 구멍 없음.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:55:49 +09:00
eomsangdonandClaude Opus 5 86d1d6ac13 fix(B05): 날개벽이 있는 측은 스트립 끝 횡단선 벽을 빼 중복을 없앤다
날개 사다리꼴 벽면이 이미 그 자리를 막는데 스트립 끝 횡단선 벽이 같은 자리에 한 장
더 서 있었다(2026-08-27 사용자). 날개벽을 낸 측은 끝 횡단선을 안 낸다.
날개가 없는 세트(파형강관 84.3·275.71)는 종전대로 끝 횡단선이 유일한 측벽이다.

- Plan: 세트마다 `wingWallSides`를 모아, 그 측은 `cut-wall`에 끝 횡단선을 안 담는다.
- BUILD_VERSION 58 → 59.

검증(실빌드 데이터):
- 벽 판 20 → **16장**(삼각형 40 → 32), 좌·우 동일.
- 세트별 벽 자리: 149.73·200.92는 날개 6마디만, 84.3·275.71은 끝 횡단선 2마디.
- 끝선(노견·성토 끝단) 위 판 0 유지, 벽 최대 높이 3.18m 불변.
- ISO 근접 캡처에서 구멍 없음 — 겹쳐 있던 판만 사라졌다.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:07:53 +09:00
eomsangdonandClaude Opus 5 93945d356c feat(B05): 측벽을 셀이 아니라 평면 스케치에서 바로 세운다
사용자 지적: 벽이 셀 단위 조각으로 깔린다(세월교 한 세트에 96~111조각, 길이
5~20cm). 절취가 평면 스케치 기준이었으니 벽도 스케치에서 바로 만들면 된다.

- Plan: `cut-wall` 소스 신설 — 벽이 설 자리만 담은 **열린 폴리라인**이다.
  · 비탈 스트립은 **양 끝 횡단선** 2개(긴 변은 노견선·성토 끝선이라 뺀다).
  · 날개 사다리꼴은 [끝선 교점 → 날개 시작 → 날개 끝 → 끝선 교점] 하나
    (`wingBoxLoops`가 `{loops, walls}`를 돌려준다).
- Cut: `SkirtBuilder`(셀 훑기) 제거. `cut-wall` 커브 마디마다 판 하나를 세우고,
  표고는 성토 리본에서 읽는다(`sampleRibbon` — 행은 XY상 직선이라 점을 그 선분에
  투영해 서피스 z·원지반 z를 같은 자리에서 보간). 밑선은 원지반 − 1m 유지.
- Mesh: `cut-wall` 커브는 선으로 안 그린다(벽 서피스로만 나간다).
- BUILD_VERSION 57 → 58.

검증(실빌드 데이터):
- 벽 삼각형 852/824 → **40/40**(판 20장씩). 판 길이 0.17~11.52m, 중앙 2.0~2.4m
  (종전 세월교 조각 길이 중앙 5~10cm).
- 노견선·성토 끝선 위를 달리는 판 **0**(양측). 벽 최대 높이 3.18m.
- ISO 근접 캡처: BOX암거·세월교 절취부 옆면이 큰 판 몇 장으로 막힌다. 바닥은 열림.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 12:01:50 +09:00
eomsangdonandClaude Opus 5 b9938dfa18 fix(B05): 노견 쪽·성토 끝단 쪽 리본 경계에는 측벽을 세우지 않는다
거기서 잘린 게 아니라 리본이 끝난 자리다(2026-08-27 사용자).

- 통째로 지운 셀의 모서리 벽: 열 방향 이웃이 리본 밖이면 건너뛴다(`col > 0`,
  `col < cols - 2`). 행 방향(노선 앞뒤)은 종전대로.
- 걸친 셀의 교점 직선: 두 교점이 모두 안쪽 끝(노견)이나 바깥 끝(성토 끝선) 위를
  달리면 건너뛴다. 판정은 **열 좌표 기준 ±0.1열**(셀 폭의 10%) — 커브가 끝선과
  나란히 지나면 교점이 가로 모서리에 걸려 열 좌표가 3~5mm 빗나간다(실측).
- BUILD_VERSION 55 → 57.

검증(실빌드 데이터):
- 벽 삼각형 1,450/1,358 → 852/824(우/좌).
- 성토끝단선 위를 달리는 벽 구간 8/6 → **0**, 노견선 위 2/2 → **0**
  (구간 길이 3cm 이상, 선까지 거리 1cm 이내 기준).
- 벽 ↔ 절단커브 거리는 그대로 중앙값 0.000m. 리본 조각 삼각형 814/787 불변.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 11:18:32 +09:00
eomsangdonandClaude Opus 5 d70908f973 fix(B05): 측벽을 격자 계단이 아니라 실제로 잘린 선에 세운다
사용자 지적: 벽이 최종 절단면이 아니라 셀 격자를 따라간다. 실측으로 확인 —
벽 정점이 리본 격자점과 100% 일치하고, 실제 절단커브까지 거리 중앙값 5.6~5.9cm
최대 21~30cm(셀 대각선 크기)였다. 격자는 재배치 후(0.2m) 격자가 맞았고, 문제는
`pushSkirt`가 마스크 격자 윤곽을 그대로 밀어낸 것이었다.

- `clipCellByChord`가 남길 조각과 함께 **교점 직선**(chord)을 돌려준다.
- `SkirtBuilder` 신설 — 걸친 셀은 그 셀을 자른 교점 직선에, 통째로 지운 셀은
  **안 지워진 이웃 쪽 모서리**에만 벽을 세운다(걸친 셀은 조각이 모서리까지 덮으므로
  모서리 벽을 세우지 않는다). 밑선은 원지반 − 1m, 교점 위 점은 원지반을 이중선형 보간.
- `traceMaskLoops` 기반 스커트 제거(그 함수는 `cut-merged` 표시 커브에만 남는다).
- BUILD_VERSION 54 → 55.

검증(실빌드 데이터):
- 벽 ↔ 절단커브 거리: 중앙값 0.000 · p90 0.000 · 평균 0.001/0.000 · 최대 0.091/0.010m
  (종전 중앙값 0.056/0.059 · 최대 0.213/0.298).
- 격자점과 일치 100% → 71.6/71.8%(나머지는 교점 위 점 = 격자 밖).
- 벽 삼각형 360/356 → 1,450/1,358. 리본 조각 삼각형 814/787 불변.
- ISO 화면에서 절취부 테두리 계단이 사라졌다.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 11:08:19 +09:00
eomsangdonandClaude Opus 5 e9914af675 fix(B05): 절취 측벽에서 빗금을 뺀다
벽은 방향성을 표현하는 면이 아니다(2026-08-27 사용자). 성토면 빗금은 그대로 두고
벽만 단색으로 그린다.

- Mesh: 벽 재질에서 `map`(빗금 텍스처)과 uv 속성을 뺀다.
- Cut/Build: 벽이 UV를 안 쓰므로 `CorridorCutWall.uvs`와 수집 코드를 지운다.
- Corridor: 저장본에서 `uvsBase64` 제거, ENVELOPE_VERSION 4 → 5.

검증: 재빌드 후 벽 서피스 우 360·좌 356 삼각형 그대로, `uvs` 필드 없음.
ISO 화면에서 벽면이 단색, 주변 성토면 빗금은 유지. npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 10:54:04 +09:00
eomsangdonandClaude Opus 5 43804f2f5b feat(B05): 절취 측벽을 별도 서피스로 빼고 원지반 아래 1m 여유를 준다
측벽을 성토 리본 메시에 섞지 않고 **구조물처럼 별도 서피스**로 낸다(2026-08-27
사용자). UV·법선이 리본에 묶이지 않아 다음 단계(구조물 안착 바닥면·트림)에서 따로
다룰 수 있다. 밑선은 원지반에서 **1m 더 내린다** — 지반 보간 오차만큼 밑이 뜨는 걸
막고, 지형은 코리도 자리에서 이미 잘려 있어 여유분은 가려진다.

- Build: `CorridorCutWall`(삼각형 수프 + UV) 추가, 빌드 결과에 `cutWalls`로 싣는다.
- Cut: 벽 삼각형을 `trimTris`에서 분리해 `walls`로 돌려준다. `SKIRT_MARGIN_M = 1`.
- Mesh: 벽마다 메쉬를 따로 만든다(`corridor-cut-wall:{측}:{번호}`) — 색·빗금은
  성토와 같아 한 몸으로 보이되 객체는 분리.
- Corridor: 저장본에 `cutWalls` 담고 ENVELOPE_VERSION 3 → 4, BUILD_VERSION 53 → 54.
- Viewer: 검증 훅 `raw`에 `cutWalls` 추가.

검증(실빌드 데이터):
- 리본 조각 삼각형 우 814·좌 787(벽 빠짐), 벽 서피스 삼각형 우 360·좌 356.
- 벽 높이 최소 1.00m(여유분) / 평균 2.26·2.87 / 최대 3.80·6.25m — 1차 대비 정확히 +1m.
- ISO 화면: BOX·세월교 절취부 옆면이 벽으로 막히고 바닥만 열려 있다(다음 작업).
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 10:46:19 +09:00
eomsangdonandClaude Opus 5 86a20cccb4 feat(B05): 절취 윤곽을 z로 밀어내 측벽을 세우고 성토면에 머지한다
자를 때 쓴 평면 스케치(절취 윤곽)를 z축으로 밀어내 성토면 ↔ 원지반을 잇는 측벽을
세운다(2026-08-27 사용자). 벽은 성토 리본과 **같은 메쉬·같은 재질**에 담아 별도
서피스가 아니라 머지된 한 면으로 그려진다. 구조물이 안착된 성토부 방향(바닥)
서피스는 다음 작업.

- Build: 성토 리본에 격자점별 원지반 표고 `groundZ`를 싣는다(행 지반선을 rows에
  보관해 flush에서 offset으로 읽는다). 벽의 밑선이다.
- Cut: `pushSkirt()` — 절취 윤곽 모서리마다 [서피스 z → 원지반 z] 사각형을 삼각형
  둘로 세워 `trimTris`에 함께 담는다. UV는 u=누가거리/2, v=z/2로 빗금이 세로로도
  실척으로 이어진다. 높이 0인 구간(성토 끝선)은 건너뛴다.
- Corridor: BUILD_VERSION 52 → 53.

검증(실빌드 데이터):
- 벽 삼각형 우 417·좌 418(조각 삼각형 합계 1,166·1,135), groundZ 적재 확인.
- 벽 높이 우 0.001~2.80m(평균 1.08)·좌 0.003~5.25m(평균 1.61).
- ISO 화면에서 세월교·BOX암거 절취부 옆면이 청록 벽으로 막혔다. 바닥은 아직 열림.
- npm run typecheck 통과, prettier 적용.

남은 것: 벽이 격자 모서리를 타 6cm×0.2m 계단이 보인다(교점 직선으로 세우면 없어진다).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 10:35:31 +09:00
eomsangdonandClaude Opus 5 2daaf127b8 feat(B05): 날개벽 사다리꼴을 절취 영역에 합치고 병합 커브를 새 데이텀에 낸다
날개벽이 있는 구조물(세월교·BOX암거)도 절취한다. 평면 스케치에 이미 사다리꼴
(`wing-box`)이 있으므로 **비탈 투영선과 XY 합집합**으로 묶어 한 번에 자른다
(2026-08-27 사용자). 어디가 잘리는지 눈으로 보려고, 잘린 자리 윤곽을 **현 평면
대비 +3m 새 데이텀**에 `cut-merged` 커브로 따로 낸다. 기존 평면 커브는 그대로 둔다.

- Cut: `CUT_SOURCES`에 `wing-box` 추가. 마스크된 셀 덩어리의 격자 윤곽을 추적해
  (`traceMaskLoops` + 직선 구간 점 버리기) 병합 커브를 만든다. 반환형이
  `{ribbons, curves}`로 바뀐다.
- Plan: `cut-merged` 소스 추가. Mesh: 라임 `0x84cc16`.
- Build: Cut이 돌려준 커브를 planCurves 뒤에 이어 붙인다.
- Corridor: BUILD_VERSION 51 → 52.

검증(실빌드 데이터):
- 마스크 셀 우 6,611→7,856(+1,245)·좌 6,237→6,925(+688). 조각 삼각형 711→814·728→787.
- 합집합 기준 안쪽인데 남은 셀 0, 완전 바깥인데 지운 셀 0(좌·우).
- 병합 커브 8개(좌우×4세트), z가 전부 세트 평면 +3.00m 정확
  (542.05→545.05 / 535.6→538.6 / 540.2→543.2 / 544.76→547.76).
- 화면: BOX·세월교 절취부가 날개 따라 사다리꼴로 벌어지고 라임 커브가 그 윤곽을 덮는다.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 09:59:10 +09:00
eomsangdonandClaude Opus 5 f4a3cb7b44 fix(B05): 절단 실패 셀을 안쪽 면적 비율로 갈라 경계 잔여 메쉬를 지운다
투영 커브 경계 주변에 미세한 성토 메쉬가 남던 문제(사용자 보고). 원인은
`clipCellByChord`가 자를 직선을 못 세운 셀을 **통째로 남기던** 폴백이다.

저장 코리도 실좌표로 셀을 재현해 보니 절단 실패 셀 627개(우 314·좌 313) 중
**622개가 셀 안쪽 비율 1.00** — 속은 통째로 커브 안인데 귀퉁이가 경계에 딱 붙어
`inCount === 4` 판정을 못 받고 걸친 셀로 내려간 뒤, 바깥 귀퉁이가 없어 `keepSign`을
못 잡은 셀들이었다(no-keepsign 491 · degenerate-chord 122 · 교점<2 14).

- Cut: `coverage()` 추가(4×4 이중선형 표본) — 절단 실패 셀만 안쪽 비율로 가른다.
  0.5 이상이면 마스크, 미만이면 종전대로 남긴다. 정상 절단 경로·정점은 불변.
- Corridor: BUILD_VERSION 50 → 51(기하 변경 — 안 올리면 옛 저장본이 복원된다).

검증:
- 실빌드 데이터(공용 브라우저 `__corridorBuild.raw`): 안쪽인데 남은 셀 **0**(좌·우),
  커브 밖인데 지운 셀 **0**. 마스크 셀 우 6,611·좌 6,237, 조각 삼각형 711·728.
- 같은 카메라 전후 스크린샷: 바뀐 픽셀의 수정 전 색이 성토면 청록 5,831 → 수정 후 14.
  투영선·스케치선 픽셀은 그대로 — 지워진 건 성토 메쉬뿐이다.
- 저장본 시뮬레이션: 잔여 우 2.17㎡·좌 4.50㎡ → 0.00㎡, 과절단 합 0.0011㎡.
- npm run typecheck 통과, prettier 적용.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-27 07:25:39 +09:00
eomsangdonandClaude Opus 5 753e8fcb44 feat(B05): 투영 커브 안쪽 성토면을 셀 단위로 지운다
빨간 투영선이 감싸는 자리의 성토면을 지운다. 지울 영역은 결국 **상단 평면 스케치가
덮는 XY 영역** 하나이고 투영선이 그 XY를 그대로 복사한 것이므로, 구조물 종류를
가리지 않고 한 가지 방법으로 자른다(사용자 확정).

- Cut(신규): 격자 셀 중심·귀퉁이로 안팎을 가려 안쪽 셀은 마스크하고, 걸친 셀은
  교점 두 개가 만드는 직선으로 잘라 바깥 조각만 삼각형으로 되살린다. 정점은
  하나도 안 건드린다. 교점이 2개 미만이면 셀을 통째로 남긴다 — 모자라게 자를지언정
  더 자르지 않는다.
- Build: CorridorRibbon에 cellMask·trimTris·trimUvs 추가.
- Mesh: 마스크된 셀의 삼각형을 빼고, 조각 삼각형을 뒤에 이어 붙인다.
- Plan: BOX암거 커브의 **안쪽 끝도 박스 축**으로 쏜다(boxInner + castToToe).
  종전엔 바깥만 박스 축이고 안쪽은 노선 흐름이라 가로대가 비스듬했다 —
  평면 스케치의 횡단 방향은 박스가 놓인 전역 단방향이어야 한다(사용자 확정).
- Corridor: 저장본에 마스크·조각 삼각형을 담고 BUILD_VERSION을 올린다.

검증(공용 브라우저 캐시 데이터 실측):
- BOX 커브 가로대 각도차 0.00°(좌·우) — 전역 단방향 확인. 다른 세트는 노선 흐름대로
  1.1~48.8°.
- 걸친 셀에서 되살린 조각 면적이 기대치와 일치 — 우 2.07㎡ vs 2.07, 좌 4.60 vs 4.61.
- 커브 밖을 지운 셀 0. 도로부·측구·절토 리본 행 수 불변(1768/1768/1768/15/26/23/13).

남은 것: 걸친 셀 1,230개 중 약 600개가 교점 부족으로 통째로 남아 경계에 잔여가
생긴다(우 2.09㎡·좌 4.36㎡). 더 잘리는 문제는 없다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 22:32:35 +09:00
eomsangdonandClaude Opus 5 398b5bdffd feat(B05): 탑뷰 스케치 파란 커브를 절·성토면에 투영해 빨간 선으로 얹는다
구조물 상단 +5m 평면에 눕혀 두던 파란 스케치(slope-original, 유입 실선·유출 파선)의
XY를 그대로 쓰고 z만 그 자리 절·성토면에서 읽어 빨간 투영선(slope-projected)으로
낸다. 스케치는 평면에 그대로 남는다. 투영선이 격자 모서리에 앉도록 구조물 점유
구간 경계를 코리도 행으로 끼워 넣는다.

- Plan: slope-projected 소스 추가. 리본을 받아 `측|누가거리` 색인을 만들고 그 행의
  열 폴리라인에서 z를 읽는다. 절토·성토 모두 대상. 밑에 면이 없으면 점을 버려 끊는다.
- Plan: 파란 스케치 안쪽 기준을 소유 측점 노견 편거리 → **그 행 절·성토면이 실제로
  시작하는 자리**로 바꿨다. 종전에는 노폭 연장·측구를 못 따라가 커브가 면 밖(도로 위)에
  얹혔다 — 275.71 좌측은 노견 4m 확장분만큼 안쪽이었다.
- Plan: 비탈 리본 열 순서가 좌우 반대(조각은 편거리 오름차순, +offset=좌측)라 우측에서
  안쪽 끝을 반대로 집었다. 색인 단계에서 안쪽→바깥으로 방향을 통일한다.
- Mesh: 커브를 점의 z로 그린다(평면 커브는 z에 planZ가 들어 있어 동작 불변).
  투영선 색 = 빨강 0xff3b30, 서피스에서 0.02m 띄운다.
- Build: 구조물 구간 [from, to]를 행 경계로 강제 삽입. 안쪽 블록 걸음은 상수로 뺐다
  (지금은 바깥과 같은 0.2m — 경계 행만 새로 생긴다).
- Corridor: 저장본은 입력 해시로만 무효화되어 기하 코드를 고쳐도 옛 저장본이 계속
  복원된다. ENVELOPE_VERSION을 올리고 그 함정을 주석으로 박았다.
- Viewer: 검증용 __corridorBuild 훅(기존 __corridorClip과 같은 용도).

검증(공용 브라우저 캐시 데이터 실측):
- 3D 회귀 없음 — 외곽선 행 1756→1768, 기존 1756행 좌표까지 전부 불변, 추가된 12행은
  구조물 구간 경계뿐(79.3·83.3·85.3·89.3·144.73·154.73·199.72·202.12·270.71·
  274.71·276.71·280.71). 측구·절토 리본 행 수 불변.
- 투영선 안쪽 끝 8벌 전부 서피스 시작점과 XY·Z 정확 일치(gap 0, dz 0).
- 바깥 끝은 XY 일치, z만 최대 1.01m 차 — 세월교 날개벽·다단 기슭막이 앞면처럼
  거의 수직인 면이라 한 XY에 z가 여럿인 구간이다. 규칙 확정은 후속.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 21:51:54 +09:00
eomsangdonandClaude Opus 5 d857d3d48a fix(B06): 인접 측점에 남던 집수정 트림을 지워 성토선을 살린다
trimLinkedLayout이 링크(인접) 측점 카드에서 구조물 도형만 지우고, 그 구조물이
만든 설계선 트림(designTrim)과 성토부선은 스프레드로 통과시켰다. 집수정은 조작량이
0이면 대체 사면선(minSlope/maxSlope)도 없어서, 구조물은 안 그려지는데 설계선만
노견 밖에서 끊겼다 — 4측점(80.0m, 관 84.3m)·14측점(280.0m, 관 275.71m) 성토선 삭제.

- keepTrimSides(): 살아남지 못한 쪽의 트림을 ∓Infinity로 되돌리고 그쪽
  Elevation·Slope를 뺀다. 양쪽 다 없으면 designTrim = null.
- 집수정은 링크 측점에 서지 않으므로 유입 쪽 트림은 언제나 지운다.
- 연장 밖 유출 벽의 outletFill, 집수정에 딸린 basinFill도 함께 비운다.
- 유입이 min·max 어느 쪽인지는 관 양 끝 offset 대소로 가른다.

3D 무영향: trimLinkedLayout은 export되지 않고 유일한 호출자 computeCardCulvert는
B06 Cross_View만 import한다. B05 코리도는 computeCulvertLayout을 직접 부르며 소유
측점에서만 돈다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 19:58:05 +09:00
eomsangdonandClaude Opus 5 ce77e0735f fix(B05): 세월교 본 바닥·날개 바닥·에이프런을 한 면으로 맞춘다
원인은 종단경사 보정(dz)이었다. 세월교 본체(측벽·바닥판)는 dz를 타서 양끝이
들린 사발 모양인데(앞끝 +0.0907 / 측점 0 / 뒤끝 +0.1613) 날개벽·에이프런은
dz = 0으로 측점 표고에 평평히 놓였다. 접합부 틈 0.0907·0.1613m이 그 dz와
소수점까지 일치했다. 표고 자체는 이미 같았다 — 어긋난 건 dz뿐이다.

본체는 그대로 두고 날개·에이프런을 경사에 태운다(사용자 선택).

- `buildWingSolids`에 선택 인자 `baseElevationM` 추가 — 넘기면 날개·에이프런
  링이 붙는 자리의 dz(end.designZ − baseElevationM)를 탄다. 세월교만 넘기고
  BOX암거는 안 넘겨 dz = 0 현행을 유지한다.
- 에이프런을 본 바닥판과 한 장으로 만든다. ① 밑변을 판이 밀려들어간 뿌리가
  아니라 바닥판 끝면 그 자리에서 시작한다. ② 단면을 직사각형 근사 대신 바닥판
  폴리곤 그대로 쓴다(뿌리 offset 기준으로 다시 잡아 끝으로 갈수록 0으로 줄인다).
  종전엔 사다리꼴 바닥판(2.669~4.283)을 직사각형(2.747~4.283)으로 근사해
  안쪽 모서리가 0.078m 어긋났다.
- `BUILD_VERSION` 39 → 40.

실측: 에이프런 밑변 4꼭짓점이 본 바닥판 끝면 꼭짓점과 거리 0.0000m(4장 전부).
날개·에이프런 dz가 붙는 자리 값을 그대로 타고 같은 자리의 날개와 에이프런이
같은 dz다. 회귀 없음 — 아령 벌어짐 유지, 날개 바깥 세로선↔구체 측면 8장 전부
0.0000m, 성토끝 박스 4/4·4/4.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:38:30 +09:00
eomsangdonandClaude Opus 5 392e471dce feat(B05): BOX암거 비탈 투영 커브를 박스 방향 단일축으로 긋는다
원본·변형 성토면 투영 커브는 행마다 그 자리 노선 프레임을 써서, 곡선 구간이면
가로 방향이 행마다 틀어져 커브가 뒤틀린다. BOX암거는 날개벽처럼 박스 방향
하나로 그어야 한다(사용자).

BOX암거 세트만(`section.box`) 행 자리는 노선 위 그대로 두고 가로 방향만 기준
측점 좌향으로 고정한다. 세월교·배수관은 종전대로 그 행의 노선 프레임을 쓴다.

원본 커브의 바깥 끝은 그 행의 코리도 윤곽 점을 그대로 썼는데 가로 방향이
고정되면 어긋나므로, 고정 방향으로 쏜 선이 성토 끝선과 만나는 자리를 바깥
끝으로 삼는다(`castToToe`를 공개로 돌려 재사용). 끝은 여전히 실제 성토 끝선
위다. `BUILD_VERSION` 37 → 38.

실측(한 커브 안 행별 가로 방향 분산, ±180 감김 보정): BOX 200.92는 원본·변형
× 좌·우 4개 모두 0.00°. 배수관 84.3 11.42~50.80°, 세월교 149.73 22.84~23.02°,
배수관 275.71 2.28~8.95°로 그대로다. 행 손실 없음 — BOX 변형 6행·원본 13행.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:27:26 +09:00
eomsangdonandClaude Opus 5 96be8fe233 fix(B05): 날개벽 바깥 세로선을 구체 측면에 붙여 단을 없앤다
날개 판이 축 위에 가운데 정렬이라, 뿌리를 구체 측면에 놓으면 절반(두께/2)이
측면 밖으로 삐져나와 투영 커브에 단이 졌다.

각도 틸팅 방식은 그대로 두고 판을 축을 따라 뒤로 민다 — 바깥쪽 세로선이 측면에
닿는 데 필요한 양은 (두께/2) × |cos각| / sin각 = (두께/2) × cot각이다. 각이
아주 작으면 cot이 발산하므로 날개 길이의 절반으로 자른다. 세월교·BOX암거 둘 다
적용한다(사용자가 둘 다 지목). 에이프런도 새 뿌리를 따른다.
`BUILD_VERSION` 36 → 37.

실측: 뿌리 링의 바깥 세로선이 구체 측면 평면에서 떨어진 거리가 세월교 4장·BOX
4장 전부 0.0000m. 안쪽 세로선은 0.1414m 안으로 박힌다(= 두께 0.2 × cos45°).
회귀 없음 — 아령 벌어짐 유지(149.73 좌 10.73 → 14.02m, 우 8.63 → 10.81m,
200.92 2.26 → 5.08m), 성토끝 박스 4/4·4/4, 에이프런 4장·0장, 기준 직선 이탈 0.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:20:41 +09:00
eomsangdonandClaude Opus 5 a8793819af feat(B05): 세월교 날개 투영 커브를 노선 흐름에 맞춰 긋는다
성토끝 박스 옆선이 날개 4장 전부 기준 측점의 고정 좌향을 쓰고 있었다. 세월교는
날개가 저마다 다른 자리의 노선 프레임에 붙는데 커브만 한 방향이라 흐름과 어긋난다.
박스암거는 그 고정 방향이 맞으므로 유지한다(사용자).

방향을 구조물에 실어 보낸다 — `CorridorStructure.wingAxis`(단위벡터). 세월교
날개를 만들 때 그 자리 노선 프레임의 좌향을 담고, `wingBoxLoops`가
`structure.wingAxis ?? 측점 좌향`으로 고른다. Plan 쪽에 새 배관이 없다.
`wing` 표식은 `true` → `"station" | "route"`로 바꿔 어느 규칙으로 만든 날개인지
남긴다(문자열이라 기존 truthy 검사는 그대로 통한다). `BUILD_VERSION` 35 → 36.

실측: 149.73 날개 4장 모두 route, 실어 보낸 축이 기준 측점 좌향과 −20.45°/+2.57°
어긋난다. 박스 옆선 각도가 그 값과 정확히 일치(좌 −20.45°·2.57°, 우 159.55°·
−177.43° = 같은 축 반대 방향). 200.92는 4장 모두 station, 옆선 0°·−180°로 무변화.
박스 4/4·4/4, 에이프런 4장·0장, 기준 직선 이탈 0.0000m.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:13:29 +09:00
eomsangdonandClaude Opus 5 24bc9480a5 fix(B05): 세월교 날개벽이 오므라들던 것을 벌어지게 정정
위에서 봤을 때 아령처럼 유입·유출부가 커져야 물을 받는다(사용자). 그런데 노선
프레임 경로에서 앞뒤 기준이 뒤집혀 세월교 날개가 오므라들었다.

뿌리는 frameAt(측점 + along × 반폭)으로 누가거리 기준으로 잡는데, 벌어지는
방향은 dir × along으로 측점 로컬 기준을 쓴다. 이 프레임의 dir은 누가거리가
줄어드는 쪽을 향해 둘이 반대였다 — 뿌리가 벌어짐 방향의 반대편에 앉는다.
실측: 149.73 날개가 (−3.65, 종 3.88) → (−4.48, 종 2.06)으로 종방향이 0에
가까워졌다. BOX암거는 뿌리·방향이 같은 기준이라 영향이 없었다.

부호를 가정하지 않는다. 측점 ± 반폭 두 자리를 다 뽑아 `along` 방향에 놓인 쪽을
고른다(`endFrameOf`) — 누가거리 부호와 진행 방향 부호가 반대인 노선에도 맞는다.
`BUILD_VERSION` 34 → 35.

실측: 같은 측 두 날개의 종방향 간격이 뿌리 → 끝으로 커진다. 149.73 좌 10.89 →
14.19m, 우 8.74 → 10.92m. BOX 200.92는 2.40 → 5.22m로 정정 전과 동일(무변화).
파생물 회귀 없음 — 에이프런 4장(기준 직선 이탈 0.0000m), 성토끝 박스 4/4·4/4.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:10:50 +09:00
eomsangdonandClaude Opus 5 bad291f720 feat(B05): 세월교 날개벽을 노선 흐름에 태우고 바닥 에이프런 추가
세월교 측벽·바닥판은 ringsOf(half, half)로 노선 스플라인을 따라가는데 날개벽만
기준 측점 프레임에서 직선으로 ±월류폭/2 자리에 뿌리를 잡아, 곡선 구간에서 측벽
끝단과 어긋났다. BOX암거는 직선 규칙이 맞으므로 건드리지 않는다(사용자 ②).

- `buildWingSolids`에 선택 인자 `endFrameAt` 추가 — 넘기면 날개 뿌리와 축을
  측벽 끝단부 자리의 노선 프레임에서 뽑는다. 세월교만 `frameAt`을 넘긴다.
  안 넘기면 계산이 옛 식과 완전히 같다(BOX 무변화).
- `WingAnchor.apron` 추가 — 세월교 바닥 에이프런. 날개 끝점과 바닥판 종방향
  끝점을 이은 직선을 외곽으로 하는 평면 삼각형을 바닥 두께로 세운다(사용자 ④).
  링을 뿌리→날개끝으로 깔고 링 좌향을 뿌리→바닥판끝으로 잡아 폭을 |P0P2| → 0으로
  좁히는 방식이라 기존 로프트 모델을 그대로 쓴다.
- 에이프런도 `wing` 표식을 달므로 성토끝 박스 대상은 `kind === "revet"`로 좁혔다.
- `BUILD_VERSION` 33 → 34.

실측: BOX 200.92 날개 뿌리 이동량 0.000m·에이프런 0개(무변화 확인). 세월교
149.73 뿌리 이동량 0.102~1.119m, 뿌리가 측벽 끝단 링 횡단선 위(종방향 잔차 0).
에이프런 4장, 바깥 모서리가 기준 직선 위 이탈 0.0000m. 성토끝 박스는 두 세트
모두 4/4 — 앞서 막혀 있던 149.73 우측 날개 1장도 뿌리 이동으로 풀렸다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 18:06:33 +09:00
eomsangdonandClaude Opus 5 2da4ecb038 feat(B05): 날개벽 탑뷰 투영 — 판 풋프린트 + 성토끝 사다리꼴 박스
날개벽 링은 노선이 아니라 날개 축을 탄다. 그래서 링 폴리곤의 편거리가 노선
편거리가 아니라 패널 두께(±0.10m)라 노견 클립 max(−0.10, +2)에 걸려 날개벽
투영 고리가 0개였다. 실측: 링 좌향과 노선 좌향 정렬 align=0.71, 링 중심의 노선
편거리 2.74~4.16(좌)·−4.01~−2.60(우) — 이미 노견 밖이다.

- `CorridorStructure.wing` 표식 신설, `_Structures_Wing.ts`가 붙인다.
- 날개벽은 도로부 클립을 생략하고 링 위치로 측을 가린다 — 판 두께 × 날개 길이
  직사각형이 나온다.
- `wing-box` 커브 신설(주황) — 밑변은 날개 시작~끝 모서리, 양 옆선은 구조물 축
  (측점 좌향 벡터)과 평행한 고정 직선, 바깥 변은 원본 성토 최하단 끝선 그대로.
  노선 곡률을 따라 각도가 바뀌지 않는다(사용자 확정).
- 성토 끝선은 세트 ±40m만 잘라 쓰고 사거리 15m로 조인다 — 안 조이면 헤어핀
  건너편 끝선에 걸려 −29m짜리 박스(점 115개)가 나온다.
- 교점 탐색은 광선이 아니라 양방향 직선이다 — 세월교 날개는 끝이 성토 끝선
  밖이라(4.16 vs 2.60) 바깥으로만 쏘면 통째로 빠진다.
- `BUILD_VERSION` 32 → 33.

실측: 판 고리가 측당 2장씩 n=11로 살아났다. 박스는 200.92 4/4, 149.73 3/4.
박스 바깥 변의 점은 전부 성토 끝선 위(이탈 0.000m). 149.73 우측 날개 1장은
그 자리에 끝선이 없어 안 그린다 — 처리 방침은 사용자 확정 대기.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 17:47:12 +09:00
eomsangdonandClaude Opus 5 5c8986d46c fix(B05): 구조물 투영 커브를 부재별로 표기 · 저장본 판번호 상향
화면이 안 바뀐 원인은 저장본 캐시였다. `BUILD_VERSION`을 안 올려 코리도 해시가
그대로였고 서버 저장본(planCurves 20개)이 재사용됐다. 실측으로 확인 — 저장본
hash 95cafe53 vs 새 코드 hash 0e67c470. 31 → 32로 올려 만료시킨다.

그리고 겹친 부재를 하나로 머지하지 않는다(사용자: "구조물은 머지하지 말고
표현할 것, 나중에 한번에 진행 예정"). 링 경로 그룹핑·구간 병합을 빼고 부재마다
고리 하나를 낸다.

배관은 투영 면적에서 계속 뺀다 — 다른 부재가 감싸고 있는 구조라는 사용자 확정.

실측(링 횡단선 되투영, 이탈 최대 0.0000m): 84.3 고리 4개 — 집수정 상·하단
2.000~2.650 각 31점, 기슭막이 상단 −2.946~−2.000·하단 −3.250~−2.000 각 47점.
149.73 8개, 200.92 10개(날개벽 4장 각각), 275.71 4개.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 17:25:41 +09:00
eomsangdonandClaude Opus 5 b29113ba22 fix(B05): 구조물 탑뷰 풋프린트를 링별 편거리 병합으로 재구현
기하 합집합(`_Corridor_Union.ts`)이 겹친 스트립에서 무너졌다. "같은 토막이
짝수 번 나오면 버린다"는 내부 칸막이 제거 규칙이 **외곽의 공유 변까지** 지웠다.
4+4.3(84.3m)에서 집수정 두 단은 탑뷰 사각형이 완전히 같아 네 변 전부 소멸해
좌측 커브가 0개였고, 기슭막이 두 단은 안쪽 변 −1.98을 공유해 23칸이 소멸,
0.34×0.92m 쪼가리만 남았다.

합집합을 버리고 구조물이 스윕 솔리드라는 성질을 그대로 쓴다 — 링 경로가 같은
부재끼리 묶고, 링마다 편거리 창을 도로 밖으로 자른 뒤 1차원 병합해 레인으로
잇는다. 기하 불리언이 없어 퇴화 케이스가 원리적으로 없다.

- `_Corridor_Plan_Footprint.ts` 신규 — 위 알고리즘.
- `_Corridor_Plan.ts` — `structureLoops` 제거, 신규 모듈 호출.
- `_Corridor_Carve.ts` — 죽은 `outlineLoops()` 제거(`outerAt`은 유지).
- `_Corridor_Union.ts` — 죽은 `unionOutline`·`insideQuad`·`splitEdges` 제거.
  `UnionQuad`/`unionQuadOf`는 `outerAt`이 계속 쓴다. 189 → 34줄.

실측: 커브 각 점을 가장 가까운 링 횡단선에 되투영해 편거리를 읽었다 — 링선
이탈 최대 0.0000m. 84.3 좌(집수정) 2.000~2.650 31점, 우(기슭막이) −3.250~−2.000
47점으로 전 링이 살아난다. 275.71·149.73·200.92 세트도 날개벽까지 각각 나온다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 17:18:47 +09:00
eomsangdonandClaude Opus 5 25ae04b2cd fix(B05): 변형 실루엣 투영 커브를 행마다 지반선에 트림
실루엣은 소유 측점 단면 한 장이라 그대로 밀면 구간 내내 같은 폭이 됐다.
0.5m 행마다 종단경사만큼 올린 뒤 `trimSlopeToGround`로 그 행 지반과 만나는
자리까지 잘라 실제 발끝을 따라가게 한다. 표기 커브만 바뀐다 — 서피스 절단·
패치는 손대지 않았다(`CARVE_APPLY` 계속 false, 사용자 지시).

4+4.3 우측 실측: 바깥끝 offset −3.25 고정 → −2.96~−4.42(지형 따라), 행 11 → 21.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 16:24:56 +09:00
eomsangdonandClaude Opus 5 5a3b2ebe39 feat(B05): 구조물 탑뷰 투영 커브 재작성 — 세트별 상단+5m 평면·유입/유출 분리
구조물 추가 뒤 3D 투영 영역이 제대로 안 만들어지던 문제. 평면고가 구조물과
무관한 모델 전체 최고표고였고, 구조물 커브와 비탈 커브가 다른 기준으로 따로
나왔으며, 성토면 표면 위에도 절단 투영선이 겹쳐 그려져 이중 표기였다.

- `_Corridor_Plan.ts` 신규 — 구조물 세트(같은 측점 소유)별로 투영 평면을
  그 세트 구조물 최고표고 +5m에 잡고, 유입/유출을 나눠 커브를 만든다.
  세트당 구조물·비탈(변형 실루엣)·비탈(원본 성토선) × 유입/유출.
  도로부(노견 안쪽)는 전 커브에서 빼 좌우가 끊긴 두 루프가 된다.
- `_Corridor_Carve.ts` — 투영 전용 함수(풋프린트 평면 투영·유입유출 판정·
  절단 트레이스 조립) 삭제, `ringEdges` 공개. 패치 리본 경로만 남겼다.
- `_Corridor_Build.ts` — 성토면 위 절단 투영선(`carveTraces`) 생성 삭제,
  `structurePlan`/`fillPlan` → `planCurves` 하나로 교체.
- `_Corridor_Mesh.ts` — 표면 위 투영선 그리기 삭제. 커브를 각자 평면고에
  종류별 색(구조물 노랑/변형 분홍/원본 하늘), 유입 실선·유출 파선으로 그린다.
- `_Corridor.ts` — 저장 코리도 봉투에 `planCurves` 포함, 형식 버전 1→2.
  안 담으면 저장본으로 복원한 코리도에서 커브가 통째로 사라진다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-26 09:42:35 +09:00
eomsangdonandClaude Opus 5 f6296fa7c5 feat(B05·B06): 구조물 3D 투영 표기 · 직교 카메라 · 조정창 템플릿 일원화
3D 구조물과 성토면의 관계를 "잘라내기"에서 "투영 표기"로 바꾸고, 세월교·BOX암거
조정창을 기슭막이 템플릿으로 통일했다.

B05 코리도
- 구조물 탑뷰 투영 산출(_Corridor_Carve.ts 신규): 구조물 솔리드 링 사이 실좌표
  사각형 + 변형 성토면 영역. 노선 파라미터가 아니라 행 횡단선과 실좌표로 교차시켜
  곡선 구간·날개벽 벌어짐이 그대로 잡힌다.
- 사각형 합집합 경계(_Corridor_Union.ts 신규): 변을 교점에서 토막 내고 내부·공유
  토막을 버려 최외곽 윤곽만 남긴다(측정 133 -> 13 루프).
- 표기 모드(CARVE_APPLY=false): 서피스를 자르지 않고 ① 성토면 위 절단 투영선
  ② 원지반 최고 표고 위 Z평면에 구조물 윤곽(노랑)과 유입·유출 성토부 윤곽
  (하늘·주황)을 따로 그린다. 구조물 커브는 성토면 없다고 보고, 성토부 커브는
  구조물 없다고 보고 만든다.
- 구조물 실루엣 공용화(_Corridor_Station_Structure.ts 신규): 기슭막이·BOX암거·
  세월교 실루엣을 한 자료형으로. 성토면 강제 변형은 스위치로 끄고
  (STRUCTURE_SILHOUETTE_OVERRIDE), 노견 확장만 상시 적용(shoulderSpans).
- 평면 영역 분리(_Corridor_Region.ts), 절단기 일반화(clipGeometry가 영역 배열·
  전체 정점 속성 보간 — 리본 UV 유지). 지형은 코리도 스트립만 도려낸다.
- BOX암거 3D를 측점 프레임 직선 압출로(노선 추종 금지), 날개벽 계산 공용화
  (_Corridor_Structures_Wing.ts 신규) 후 세월교에도 날개벽 4매 추가.
- 세월교 보어를 관 련수만큼 뚫고, 보어 밴드를 단면 표고로 클램프해 구멍 찌그러짐
  제거. 날개벽 뿌리를 벽 외측면 모서리로 교정.
- 직교 카메라(_Viewer_Camera.ts 신규) — 원근 왜곡 없이 탑뷰 판독. 커서 피벗 줌이
  직교에서 camera.zoom을 함께 조인다.

B06 횡단
- 조정창 공용 부품(_Cross_Panel_Base.ts 신규): 머리줄·2행 항목·D-pad·키보드
  방향키. 세월교·BOX 조정창을 같은 템플릿으로 옮기고 십자 세트를 창 맨 아래로.
- 세월교 조정창에 날개벽 항목 추가(설치·짧은쪽 높이·길이·각도) — 정본
  pipe_points 되쓰기, 바닥판 연장은 길이×cos각으로 즉시 재계산.
- 세월교 좌우 이동을 집수정 규칙으로: 노견 수평 확장 + 상하 이동분만 성토선.

BUILD_VERSION 19 -> 31(저장 코리도 캐시 무효화). typecheck·prettier 통과.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 20:03:42 +09:00
eomsangdonandClaude Opus 5 07fb2ccf46 fix(B06): BOX암거·세월교를 소유 측점 횡단도 한 장에만 그림
attach_culvert_sets()가 도로 방향 폭(span_m)의 절반을 reach로 잡아 소유 측점
전후 측점에도 같은 스펙을 붙였다. BOX암거는 폭 2.4m라 0.92m 떨어진 옆 측점까지
걸려 횡단도가 한 벌 더 그려졌고, 같은 값을 읽는 3D도 박스 솔리드를 어긋난 채
두 벌 만들었다.

구조물 종류별 연동 표(_SPAN_LINKED_TYPES)를 두고 reach를 분기한다. 지금은 빈
집합이라 세월교·BOX암거 모두 소유 측점 한 곳에만 선다. 3D 스윕 길이는 소유
측점이 span_m으로 직접 내므로 줄지 않는다.

기슭막이 연동은 프론트 culvertOwnerFor 별도 경로라 그대로 살아 있고, 집수정은
이미 링크 카드에서 빠져 있다.

검증(프로젝트 c1bb453f route 85): pytest 208 passed. 횡단도 200.0m 카드에서
box-barrel 사라지고 200.92m에만 남음. 3D 솔리드 42 -> 32, 200.0m 10 -> 0,
200.92m 10 유지, span_m 2.4 불변.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-25 17:41:40 +09:00
eomsangdonandClaude Opus 5 6e87dd6cdf fix(B05): BOX암거 날개벽을 구체 모서리에 붙이고 에이프런을 평면 사다리꼴로
날개벽 시작점을 측점 중앙 프레임으로 잡아 곡선 구간에서 구체 끝과 0.15m 어긋났다.
그 모서리 링의 프레임으로 잡아 정확히 붙인다.

또 에이프런이 평면에서 직사각형이라 각도만큼 벌어진 날개벽 발치가 바닥 밖으로
나갔다. 날개벽 선을 따라 안쪽 변이 물러나는 **사다리꼴**로 바꿔 발치를 받는다
(2026-08-25 사용자 지적).

검증(10+0.9): 날개벽 4매 모두 구체 모서리와 거리 0.000m,
에이프런 링별 안쪽 변 [4.158, 2.744, 2.744, 4.158] — 바깥 링에서 폭 0으로 닫힌다.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 15:41:31 +09:00
eomsangdonandClaude Opus 5 a87182496e feat(B06·B05): BOX암거 조정창 · 구체 기울기 · 3D 벽 구간 정리
조정창에서 좌·우 끝을 따로 잡는다 — ◀▶는 구체 길이, ▲▼는 그 끝의 구체 표고를
0.1m씩 움직인다. 좌·우 표고가 달라지면 구체가 기울고, 날개벽 구간 바닥(에이프런)은
각 끝 표고에서 수평을 지킨다(2026-08-25 사용자).

- `computeBoxLayout`이 좌·우를 따로 푼다: 끝 표고·길이·성토선·에이프런
- 성토선은 그쪽 표고 기준으로 물매 1:1.2를 지키므로 표고를 내리면 구체가 길어진다
- 조정창 `_Cross_Box_Panel.ts` + 제어 `createBoxControls` + `design.box_adjust` 저장
  (세션 → 캐시 → 확정 payload, 세월교와 같은 체계)
- 3D: 구체 밖(날개벽 구간)에 서 있던 벽을 없앴다 — 천장 없는 통로가 생기던 자리는
  날개벽 몫이다. 이제 상판·구체 저판·측벽 2매·에이프런 2매 + 날개벽 4매로 나뉜다
- 카드 렌더러의 구체 배선(선택 토글·강조·조정창)을 `_Cross_View_Bodies.ts`로 분리,
  연동 플래그 세션은 `_Page_Link_Session.ts`로 분리(700줄 제한)

검증(10+0.9): 구체 5.34m·수평 → ◀ 1회 5.44m → ▼ 2회 표고 −0.2m·물매 1:28.4,
에이프런 두 장 모두 수평 유지, ↺ 원복. 3D 솔리드 10개(측벽 링 0.2m).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 15:03:53 +09:00
eomsangdonandClaude Opus 5 2fe8f617da fix(B06): BOX암거 성토선을 박스 최상단 모서리에서 끝냄
모서리 밖은 구체 개구부·날개벽이라 성토가 아니다(2026-08-25 사용자). 원지반까지
잇던 구간을 지운다 — 성토선은 노견 → (수평 연장) → 박스 최상단까지만이다.

검증(10+0.9): 좌 [(2, 535.821) → (2.744, 535.201)],
우 [(−2, 535.701) → 수평 → (−2.744, 535.201)] — 두 선 모두 상단 표고에서 종료.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:55:00 +09:00
eomsangdonandClaude Opus 5 55e97b8925 fix(B06): BOX암거 성토선 추가 — 박스 최상단을 지나고 노견은 수평 연장
박스 위 성토선이 빠져 있었다. 물매 1:1.2를 고정하고 성토선이 **박스 최상단
모서리**를 지나게 하면, 박스를 길게 잡을수록 노견이 저절로 수평 연장되고 각도는
그대로다(기슭막이 "벽이 밖으로 나간 만큼 노폭 연장"과 같은 규칙, 2026-08-25 사용자).

- 구체 길이 = 노폭 + 2 × (노면 − 박스 상단) × 1.2. 노면이 크라운이라 좌·우 필요량이
  다르므로 큰 쪽에 맞춰 대칭으로 잡고, 남는 쪽은 노견을 수평 연장한다
- 성토선 = 노견 → (수평 연장) → 박스 최상단 모서리 → 1:1.2로 원지반까지
- 노견 밖 설계선은 이 성토선이 대신하므로 다시 트림한다

검증(10+0.9): 구체 ±2.744m, 저판 8.32m, 좌 성토선 물매 1.200·1.200,
우 성토선 수평 0.144m 뒤 1.200·1.200.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:52:40 +09:00
eomsangdonandClaude Opus 5 d4c8de738a feat(B05·B06): BOX암거 횡단도 · 3D 중공 셸·날개벽·관통 보어
BOX암거를 세월교와 같은 계류 방향 절단면으로 그리고, 3D는 속이 빈 서피스 셸로
만든다. 관통 컷·중공 튜브는 배수관 세트와 세월교에도 함께 적용한다.

B06 횡단도
- `_box_set()` — 내공 폭·높이(B05 옵션), 부재 두께 세월교 승계(측벽 0.2·상하판 0.3),
  복토 0.5m(별표2 교차 참조), 날개벽 투영 저판 연장
- 상판 윗면 = 노면 − 복토, 구체는 수평 설치(교본 3장). 계류 하상과의 고저차는 툴팁 표기
- 구체가 노면 아래 묻히므로 계획선은 자르지 않는다(세월교와 다른 점)

3D
- 로프트가 **링별 폴리곤**을 받는다 — 구조물을 위·아래 조각으로 갈라 링마다 틈을
  벌려 빈 공간을 만든다. 틈 0이면 속 찬 단면 그대로라 토폴로지가 유지된다
- BOX = 내공 구간만 틈을 벌려 측벽이 저절로 생기는 셸 + 날개벽 4매(날개 축 프레임)
- 관통 보어 = 링 y에서 틈 높이 2·√(r²−(y−y₀)²) → 배관 외측 기준 원형 구멍.
  기슭막이·집수정·세월교 측벽에 적용
- 배관은 중공 튜브(바깥·안쪽 원통 + 양 끝 고리)로 내부 유로를 보인다

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:45:32 +09:00
eomsangdonandClaude Opus 5 98380056cc fix(B06): 세월교 관 위 성토 채움 삭제
채움 색이 --color-chart-0(파랑 rgb 91,141,239)이라 관 선 색(rgb 79,142,247)과
겹쳐 관 일부처럼 읽혔다. 사용자 확정에 따라 면 자체를 지운다 — 배수관 세트와
같이 관 위는 비워 둔다.

- FordLayout.fill·FordSideLayout.roadFace와 전용 보조 함수 제거
- .b06-chart__ford-fill 스타일 삭제

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:12:55 +09:00
eomsangdonandClaude Opus 5 81bb505cc4 feat(B05·B06): 세월교 횡단 구체·조정창·3D 예상형상
B05 세월교 옵션에 BOX암거 날개벽 한 벌(설치·짧은쪽 높이 1m·길이 2m·각도 45°)을
그대로 붙이고, B06 횡단도에 세월교 구체를 그린다. 구체는 양측 ㄴ형 집수정 측벽 +
그 사이를 잇는 바닥판 + 바닥판 상면에 안힌 관 + 관 위 성토(노체) 채움이다.

- 바닥판 편측 연장 = 날개벽 길이 × cos(각도) — 각도는 관축 기준 벌어짐각
- 측벽은 buildBasin 재사용이라 1:0.3 기움·좌우·상하 대각 이동·계류측 성토부선이
  집수정과 같은 규칙으로 따라온다 (기슭막이 다단·재질과는 연계하지 않음)
- 구체는 월류 폭만큼 도로 방향으로 이어져 기준 측점 전후 절반까지 붙는다
- 조정창: 측벽 높이·좌우·상하, 관경·수량(정본 pipe_points 되쓰기).
  높이·좌우·상하는 세션 + design.ford_adjust에 저장
- 3D 예상형상: 구체 부재는 월류 폭 구간 스윕, 관은 련수만큼 폭 안 등간격
- 부재 두께: 바닥판 0.3m(교본 물넘이 물받이 최소 30cm), 측벽 0.2m(집수정 승계)

700줄 제한으로 카드 렌더러·측점 제어기·페이지에서 배선을 분리했다
(_Cross_View_Ford, _Page_Ford_Controls, _Page_Patches, Culvert_Const 구간값 헬퍼).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-25 12:05:42 +09:00
eomsangdonandClaude Opus 5 0e2309f5ce fix(B05): 지운 구조물 부활 차단 · 임시저장이 캐시 수정분을 저장하도록
사용자 확정 모델: 초기 계산값은 **원복용으로 그대로 두고**, 사용자가 제어한 수정
1세트가 최종본이다. 여러 세트는 두지 않는다. 두 곳이 이 모델을 어기고 있었다.

① 지운 구조물이 되살아난다 — B05는 그려질 때마다 종단 정본의 비정규 측점을 모아
   `/structures/migrate`를 부른다. 서버의 "멱등" 기준이 **지금 그 자리에 구조물이
   있는가**여서, 사용자가 지우면 자리가 비고 다음 진입에서 같은 구조물이 다시
   생성됐다(진행단계 오버레이로 오가면 매번). 옮긴 자리를 `structures.json`의
   `migrated_legacy`에 **이력으로** 남기고, 이력에 있으면 구조물이 없어도 다시 만들지
   않는다. 원천(비정규 측점)은 원복용으로 손대지 않는다. 이력은 일반 저장 경로에서도
   보존한다 — 사라지면 삭제분이 부활한다.

② 임시저장이 캐시 수정분을 버린다 — B05 [임시저장]이 `cross_patches`를 보내지 않고
   `invalidateSectionDetail`로 공유 캐시를 비웠다. B06에서 만져 캐시에 얹힌 구조물
   조정(4축·다단·연동·표시 반폭)이 영구저장소에 못 가고 사라졌다. 계획선·비정규 측점
   저장 **뒤에** 캐시 수정분을 `saveSections`로 남기고, 그 다음에 캐시를 비운다 —
   순서가 뒤바뀌면 재계산이 사용자 수정을 덮는다.

`saveCachedCrossPatches`·`crossPatchesFromCache`는 공유 캐시 모듈에 뒀다 — B05 페이지
파일이 이미 700줄을 넘겨 더 불리지 않기 위함이다(기존 부채).

tsc/ruff/prettier 통과, pytest 200 passed(기존 실패 1건 유지).
신규 검증: tmp/tests/test_b05_structures_migration_history.py 4건.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:56:40 +09:00
eomsangdonandClaude Opus 5 38fd7e49e0 fix(B05): 구조물 성토 비탈 Z 반전 — 유출측 실루엣 배열 방향 정규화
사용자 3D 제보: 구조물 자리의 성토가 경사 방향이 뒤집혀 위로 솟는다.

원인은 직전 커밋(b5ceb861)에서 유출측 편거리 정렬을 뺀 것이다. 뒤쪽 코드가 비탈의
도로측 끝점을 **배열 위치**로 집는다 — `slopeRelative`(Corridor_Station)와 코리도
빌더(Corridor_Build)가 `side === "right" ? points.at(-1) : points[0]`로 잡고,
비탈 보간기도 오름차순 배열을 전제한다. 유출이 우측인 측점은 수집 순서(도로 → 바깥)가
편거리 내림차순이라 **바깥 끝을 도로측으로** 잡았고, 그만큼 비탈이 뒤집혀 얹혔다.

정렬로 되돌리면 다단 계단 순서가 다시 깨지므로, 체인은 그대로 두고 **배열 방향만**
오름차순으로 뒤집는다(첫 점이 마지막 점보다 바깥이면 reverse). 점 순서(성토선 >
본 기슭막이 > 추가 성토선 > 추가 기슭막이)는 보존된다.

BUILD_VERSION 18 → 19(저장 코리도 만료).
tsc/prettier 통과, pytest 196 passed(기존 실패 1건 유지).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:42:07 +09:00
eomsangdonandClaude Opus 5 b5ceb8613a fix(B05·B06): 기슭막이 조작의 3D 즉시 반영 · 성토 비탈 실루엣 순서 복구
사용자 보고: 기슭막이 위치(본·연동)를 바꿔도, 추가(다단) 기슭막이를 세워도 3D가
바뀌지 않는다. 형상은 성토선 > 본 기슭막이 > 추가 성토선 > 추가 기슭막이 순이어야
한다. 원인이 둘이었다.

① 조작값이 캐시에 안 실렸다 — 사용자 확정 흐름은 "영구저장소 → 브라우저 캐시 →
   3D는 캐시로 플롯, 편집하면 캐시를 갱신하고 그 캐시로 다시 플롯"이다. 그런데
   조정창 조작값(4축·다단 단 수·유입 구조물·집수정·연동 플래그)은 sessionStorage에만
   있고 확정·임시저장 때만 design에 실렸다. 이제 편집 즉시 `section.design`(B05·B06이
   공유하는 같은 객체)에 함께 기록한다. 세션은 리로드 복원용 사본으로 남는다.
② 기하 캐시가 낡았다 — `culvertLayoutOf`의 WeakMap이 측점 객체만 키로 써서, 캐시를
   제자리 고치면 옛 기하가 그대로 살아남는다. 입력 요약 해시를 함께 담아 무효화한다.
③ 비탈 실루엣이 순서를 잃었다 — 수집한 점을 편거리로 정렬한 뒤 재추출했다. 기슭막이
   앞면이 거의 수직이라 편거리 정렬은 순서를 보장하지 못하고, 다단 계단은 안팎을 오가
   뒤섞인다. 유출측은 수집 순서를 그대로 잇고, 추가 성토선과 추가 기슭막이를 번갈아
   밀어 계단 순서를 맞춘다. 유입측(집수정·절토)은 범위 밖이라 종전 정렬 유지.
④ 성토 조각 해상도 20 → 48열 — 호길이 균등 재추출이 수직면을 뭉갠다. 열을 꼭짓점에
   맞춰 배분하면 측점마다 열 수가 달라 리본이 꼬이므로, 파라미터화는 그대로 두고
   해상도로 해결했다. 절토는 20 유지(다단이 붙지 않는다).

성토 물매 불변: 이번 수정은 trimSlope·outletFill 점을 만들지 않는다 — 잇는 순서와
재추출 열 수만 바꿨고, 물매 산출 경로(layout.fillSlope.ratio)는 손대지 않았다.

BUILD_VERSION 17 → 18(저장 코리도 만료).
tsc/prettier 통과, pytest 196 passed(기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-10.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:37:14 +09:00
eomsangdonandClaude Opus 5 cd8d14f105 feat(B05·B06): 기슭막이 구간값 조정창 · 연동 기슭막이 옵션 · 가림 구간 선 정리
기슭막이 범위(길이·기준측점 전/후)를 B06 횡단도 조정창에서 지정하게 하고, 그
범위가 덮는 옆 측점의 기슭막이를 "연동" 파생물로 다루도록 체계를 세웠다.
값의 원천은 배수관 옵션(pipe_points) 하나다 — 같은 숫자를 B06 정본에 따로 담으면
B05 배수관 카드와 갈려 어느 쪽이 참인지 알 수 없다.

① 집수정 전/후 필드 신설 — inlet_basin_before_m·after_m(기본 각 1m), 길이 2m 유지.
   종방향 구간 계산을 revetSpanOfSpec·basinSpanOfSpec 한 곳으로 모아 2D 링크 판정과
   3D 스윕이 같은 값을 쓰게 했다.
② B06 조정창에 길이·전·후 행 — 기슭막이(유입·유출)·집수정 모두. 캐시를 고쳐 즉시
   보여주고 저장은 조작이 멎으면 한 번만 나간다(세부유역 재계산이 매번 돌지 않게).
   길이를 바꾸면 늘어난 몫만 지금 비율대로 나눠 담는다 — 총길이에서 비율로 다시
   계산하면 0.1m 반올림이 쌓여 5.0/5.0이 5.6/5.4로 어긋난다.
③ 링크 카드 선택 허용 — "소유 측점 통째 복사"에서 "위치 4축만 물려받고 원지반
   접합은 이 측점 지형으로 재계산"으로 바꿨다. 구조물 형식은 언제나 소유 측점 값이다.
   손대기 전에도 어긋나지 않게 소유 측점이 실제로 적용한 4축(revetShift)을 명시값으로
   물려준다.
④ 연동(측점별)·경사(전체 공통) 토글 — 연동 조작은 소유 측점 키에 실리고 그 연장이
   덮는 측점을 함께 다시 그린다. 경사는 3D 전용 스위치다(끄면 스윕 프레임 dz=0).
   횡단도까지 -dz로 밀면 노견에서 출발하는 성토선까지 내려가 노견과 벌어진다.
⑤ 가림 구간 선 정리 — 유입부 접속선과 유출부 접지 후 절토선을 2D·3D 모두에서
   빼되 기하는 남긴다. 면적·수량 계산은 건드리지 않았다(전면 개편 대상).
⑥ 집수정은 소유 측점 횡단도 하나에만 — 링크 카드에서 집수정·계류측 다단을 뺀다.
⑦ 3D 구간 겹침 정리 — 측점 간격이 구조물 연장보다 좁으면 두 구간 제어점이 번갈아
   서서 짧은 쪽(집수정 2m)이 잘려 보였다. 두 소유 측점의 중간에서 끊는다.
⑧ 조정창 정리 — 십자·9키를 맨 아래로, 창을 위쪽 기준 오버레이로(낮은 횡단도에서
   제목이 잘리던 문제), 연동·경사를 1행 토글 버튼으로, 스크롤 자리 유지.

파일 분리: B06_Section_UI_Cross_View_Structure.ts(조정창 배선),
B06_Section_Api_Culvert_Options.ts(구간값 저장) — 700줄 제한.
BUILD_VERSION 14 → 17(저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 196 passed(기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-9.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 19:26:35 +09:00
eomsangdonandClaude Opus 5 83eb58a251 feat(B05·B06): 배수관 측점 정본화 · 코리도 단차 제거 · 인접 측점 기슭막이 링크
3D 예상형상은 종단·횡단 확정 뒤의 최종 산출물이고 3D 쪽 편집 경로는 없다
(2026-08-24 사용자 확정). 그런데 구조물(비정규) 측점은 횡단 정본 자체가 없어
조회할 때마다 프리뷰 기본값이 재계산됐고, 조정창 조작값은 세션에서 사라졌다.
정본 경로를 열고, 그 위에서 코리도 단차를 걷어냈다.

① 구조물 측점 정본화 — 확정·임시저장이 종단 정본 stations 중 DB 행이 없는
   측점을 대상에 넣어 upsert. cross_sections 19 → 23행.
② 조정창 조작값 정본화 — 기슭막이 4축(x·d·h·m)·다단 단 수를 design.revet_adjust
   / extra_wall_counts로 저장하고, 3D culvertLayoutOf가 그 값을 기하 입력으로 쓴다.
   카드 우선순위는 세션 → 정본 → 자동.
③ 노폭 연장의 노견 편입 — PIECE_COLS.shoulder 2→3으로 원 노견 끝 꺾임을 남기고,
   조기 return을 없애 확폭이 구조물 구간 내내 유지되게 했다.
④ 종단 기울기 반영 — 구조물 구간 복사 단면에 계획고 차이를 전량 얹는다.
   노견 표고 단차 0.49~0.61m 제거.
⑤ 접속 테이퍼 — 구간 경계를 제어점으로 세워 "복사 vs 보간" 두 규칙을 하나로
   통합. 노폭 3.0m·성토비탈 8.1m 단차 제거. 접속 길이 = 인접 측점까지.
   제어점 생성은 B05_Profile_UI_Corridor_Frames.ts로 분리(Build 699 → 635줄).
⑥ 인접 측점 링크 — 기슭막이 연장(기본 10m)이 덮는 옆 측점 횡단도에도 소유 측점
   단면을 계획고 차이만 얹어 그린다. 요소별 연장 판정(관·집수정 제외), 표시 전용.

BUILD_VERSION 11 → 14 (저장 코리도 만료).
tsc/ruff/prettier 통과, pytest 192 passed (기존 실패 1건 유지).
작업이력·자체검증 기록: docs/raw/PLAN.md §4-8.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-24 17:11:21 +09:00