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>
This commit is contained in:
@@ -590,6 +590,34 @@ export function createRouteViewer(): RouteViewer {
|
||||
function setCorridor(build: CorridorBuildResult | null): void {
|
||||
disposeCorridorGroup();
|
||||
corridorBuild = build;
|
||||
// 검증용 요약(2026-08-26) — 격자 재배치·투영선이 리본을 흔들었는지 화면 밖에서
|
||||
// 수치로 확인한다(`__corridorClip`과 같은 용도).
|
||||
(window as unknown as { __corridorBuild?: unknown }).__corridorBuild = build
|
||||
? {
|
||||
ribbons: build.ribbons.map((ribbon) => ({
|
||||
kind: ribbon.kind,
|
||||
side: ribbon.side,
|
||||
rows: ribbon.chainages.length,
|
||||
cols: ribbon.colCount,
|
||||
first: ribbon.chainages[0],
|
||||
last: ribbon.chainages[ribbon.chainages.length - 1],
|
||||
})),
|
||||
outlineRows: build.outline.chainages.length,
|
||||
outline: build.outline,
|
||||
// 원본 참조 — 투영선이 실제로 서피스에 얹혔는지 좌표로 대조할 때 쓴다.
|
||||
raw: { ribbons: build.ribbons, planCurves: build.planCurves ?? [] },
|
||||
planCurves: (build.planCurves ?? []).map((curve) => ({
|
||||
source: curve.source,
|
||||
role: curve.role,
|
||||
side: curve.side,
|
||||
at: curve.setChainageM,
|
||||
loops: curve.loops.length,
|
||||
points: curve.loops.reduce((sum, loop) => sum + loop.length, 0),
|
||||
z0: curve.loops[0]?.[0]?.[2] ?? null,
|
||||
planZ: curve.planZ,
|
||||
})),
|
||||
}
|
||||
: null;
|
||||
if (build && bounds) {
|
||||
snapCorridorEdges(build);
|
||||
corridorGroup = createCorridorGroup(build, bounds);
|
||||
|
||||
Reference in New Issue
Block a user