feat(B05): 3D 평면 스케치를 최종 결과물에서 숨긴다 (디버깅용으로 되켤 수 있게)

투영 커브(구조물 노랑·날개 주황·투영선 빨강·잘린 자리 라임 등)는 구조물이 어디를
지우고 어디를 다시 채우는지 눈으로 좇으려고 만든 표기라 설계 산출물이 아니다.
사용자 지시로 **기본은 숨김**. 다만 절취·패치 기하를 다시 볼 때 쓰므로 지우지 않고
묶음째 감춘다(2026-09-02 사용자: "나중에 디버깅을 위해 재사용 가능성 있음").

- `_Corridor_Mesh.ts` — 커브를 `corridor-plan-sketch` 묶음에 담고 `visible` 을
  브라우저 스위치(`frd_debug_plan_curves`, 기본 꺼짐)로 정한다.
- `_Profile_UI_Viewer.ts` — `__corridorPlanCurves(true|false)` 로 켜고 끈다. 선택은
  브라우저에 남아 다음에 열 때도 유지된다. 인자 없이 부르면 지금 상태를 돌려준다.

검증(wdw · 3D 실측, 같은 화면에서 켜고 끄며 스케치 색 픽셀을 셈):
  숨김(기본) — 주황 1 · 노랑 0 · 빨강 0 · 라임 0
  켬        — 주황 89 · 노랑 260 · 빨강 6 · 라임 195
`__corridorPlanCurves()` 기본 false → true → false 왕복 확인.
`tsc --noEmit` 통과, `pytest tmp/tests/ -q` 356 passed / 0 failed, prettier 정합.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-09-02 11:41:41 +09:00
co-authored by Claude Opus 5
parent 7498d6a2ec
commit 2d07b990a4
2 changed files with 51 additions and 2 deletions
+28 -1
View File
@@ -50,6 +50,26 @@ const PLAN_CURVE_COLORS: Record<PlanCurve["source"], number> = {
"cut-wall": 0x000000,
};
/**
* 평면 스케치(투영 커브) 묶음의 이름 — 뷰어가 이 이름으로 찾아 켜고 끈다.
*
* **최종 결과물에서는 숨긴다**(2026-09-02 사용자). 이 커브들은 구조물이 어디를 지우고
* 어디를 다시 채우는지 눈으로 좇으려고 만든 것이라 설계 산출물이 아니다. 다만 절취·패치
* 기하를 다시 들여다볼 때 쓸모가 있어 **지우지 않고 감춰만 둔다**.
*/
export const PLAN_CURVE_GROUP = "corridor-plan-sketch";
/** 평면 스케치를 켜 둔 브라우저인가 — 기본은 꺼짐. 디버깅용 스위치다. */
export const PLAN_CURVE_FLAG = "frd_debug_plan_curves";
export function planCurvesVisible(): boolean {
try {
return window.localStorage.getItem(PLAN_CURVE_FLAG) === "1";
} catch {
return false; // 저장소가 막힌 환경(사생활 보호 모드 등) — 꺼진 것으로 본다.
}
}
/** 유출측 파선 눈금(m) — 유입은 실선이다. */
const PLAN_DASH_M = { dashSize: 0.6, gapSize: 0.4 };
@@ -391,6 +411,13 @@ export function createCorridorGroup(build: CorridorBuildResult, bounds: ModelBou
// 탑뷰 투영 커브(2026-08-26 사용자) — 구조물 세트마다 **그 세트 구조물 상단 +5m**
// 평면에 눕힌 닫힌 고리다. 종류는 색(구조물 노랑 / 변형 성토선 분홍 / 원본 하늘),
// 유입·유출은 실선·파선으로 나눈다. 표기 전용 — 서피스는 안 건드린다.
//
// **최종 결과물에서는 숨긴다**(2026-09-02 사용자). 지우지는 않는다 — 절취·패치 기하를
// 다시 들여다볼 때 쓰므로 묶음째 감춰 두고 `__corridorPlanCurves(true)` 로 되켠다.
const planGroup = new THREE.Group();
planGroup.name = PLAN_CURVE_GROUP;
planGroup.visible = planCurvesVisible();
group.add(planGroup);
(build.planCurves ?? []).forEach((curve) => {
// 벽 자리 커브는 표시용이 아니다 — 벽 서피스로만 나간다(2026-08-27 사용자).
if (curve.source === "cut-wall") return;
@@ -417,7 +444,7 @@ export function createCorridorGroup(build: CorridorBuildResult, bounds: ModelBou
if (dashed) line.computeLineDistances();
const station = curve.setChainageM.toFixed(2);
line.name = `corridor-plan:${curve.source}:${curve.role}:${curve.side}:${station}:${index}`;
group.add(line);
planGroup.add(line);
});
});
// 절취 측벽 — 리본과 분리된 **별도 서피스**(2026-08-27 사용자). 성토면과 같은 색·빗금이라
+23 -1
View File
@@ -16,7 +16,11 @@ import {
} from "./B05_Profile_UI_Markers";
import { createOrthoCameraRig } from "./B05_Profile_UI_Viewer_Camera";
import type { CorridorBuildResult } from "./B05_Profile_UI_Corridor_Build";
import { createCorridorGroup } from "./B05_Profile_UI_Corridor_Mesh";
import {
createCorridorGroup,
PLAN_CURVE_FLAG,
PLAN_CURVE_GROUP,
} from "./B05_Profile_UI_Corridor_Mesh";
import { clipTerrain } from "./B05_Profile_UI_Corridor_Clip";
import { TerrainHeightIndex } from "./B05_Profile_UI_Corridor_Terrain";
import { buildPatchSkirts } from "./B05_Profile_UI_Corridor_Skirt";
@@ -671,6 +675,24 @@ export function createRouteViewer(): RouteViewer {
corridorGroup = createCorridorGroup(build, bounds);
scene.add(corridorGroup);
}
// 평면 스케치 되켜기 — 최종 결과물에서는 숨기지만 절취·패치 기하를 다시 볼 때 쓴다
// (2026-09-02 사용자: "나중에 디버깅을 위해 재사용 가능성 있음").
// `__corridorPlanCurves(true)` 로 켜고 `(false)` 로 끈다. 선택은 이 브라우저에 남아
// 다음에 열 때도 그대로다. 인자 없이 부르면 지금 상태를 돌려준다.
(
window as unknown as { __corridorPlanCurves?: (on?: boolean) => boolean }
).__corridorPlanCurves = (on?: boolean): boolean => {
const sketch = corridorGroup?.getObjectByName(PLAN_CURVE_GROUP);
if (on !== undefined) {
try {
window.localStorage.setItem(PLAN_CURVE_FLAG, on ? "1" : "0");
} catch {
// 저장소가 막힌 환경 — 이번 화면에만 적용한다.
}
if (sketch) sketch.visible = on;
}
return sketch?.visible ?? false;
};
scheduleTerrainClip();
}