/* ============================================================================= * A00_Common/design/logic/design_calc_registry.ts * B05 · B06 계산 등록부(PLAN 472-3 · 요구 273) — 계산 한 갈래 = 줄 하나(목록 문서 * `docs/raw/조사/2026-10-19_472_구조다시세움_목록.md` 1.1 표 # 하나). * * 순수 자료 — 함수 import 없음(타입만). 실행기는 글 이름이라 브라우저에 실려도 서버 쪽 코드가 * 안 딸려감. 시설 · 토량 · 배수 · 3D · 추천 줄 = `design_calc_registry_facility.ts`(같은 꼴 · 자료만). 서버 Node 입구 = `design_calc_node.ts`(id → 함수 표 · `build:design-calc`). * * 칸: * id — 갈래 이름(`<묶음>.<값>`) * no — 목록 1.1 표 # * inputs — 바뀌면 다시 셈 하는 값: `input.<묶음 입력>`(가게 칸) · 앞 id · `file:<정본>` · * `session:<열쇠>` · `context.<서버 문맥>` * outputs — 낳는 값 · 가게 칸(`store.<칸>`) · 서버 정본 자리(`file:` · `db:`) * site — browser_now(브라우저 즉시 + 서버 정본 같은 셈) · server_canon(서버 정본만) · * server_only(무거운 GIS · 래스터 · 추천 엔진) · browser_only(입력 도구 · 표시) * stage — 브라우저 묶음 단계(`design_pipeline.ts`) · 없으면 null * ts — TS 셈 자리 `<경로>#<함수>` · 없으면 null * runner — 실행기: `node:`(서버 Node 입구) · `py:<경로>#<함수>`(지금 파이썬) · * `browser:<경로>#<함수>`(browser_only 만) * pair — 파이썬 짝 `<경로>#<함수>` · 짝 아니면 null * mirror — 거울 · 단위 시험(`resources/tester` 파일 이름 · .py 뺌) * * 묶음 단계의 기댐(`STAGE_DEPS`) = 같은 단계 줄들의 inputs 중 `input.*` · 다른 단계 id 의 단계 * (같은지 시험 `test_472_3_calc_registry.py`). * ========================================================================== */ import { FACILITY_ROWS } from "./design_calc_registry_facility"; import type { StageName } from "./design_pipeline_types"; export type CalcSite = "browser_now" | "server_canon" | "server_only" | "browser_only"; export interface CalcEntry { id: string; no: string; label: string; inputs: string[]; outputs: string[]; site: CalcSite; stage: StageName | null; ts: string | null; runner: string; pair: string | null; mirror: string[]; note?: string; } const B05 = "B05_Profile/"; const B05L = "B05_Profile/logic/"; const B06 = "B06_Section/"; const B06L = "B06_Section/logic/"; const U = "common_util/"; export const CALC_REGISTRY: readonly CalcEntry[] = [ /* ── 노선 ─────────────────────────────────────────────────────────────── */ { id: "route.polyline", no: "R1", label: "평면 폴리라인 · 곡선(BC · EC · MC)", inputs: ["input.route"], outputs: ["노선 선", "곡선표", "file:B05_Profile/route/*"], site: "browser_now", stage: "route", ts: `${B05L}B05_Profile_UI_RouteEdit_Curve.ts#buildEditedPolyline`, runner: "node:route.polyline", pair: `${U}common_util_route_polyline.py#build_planned_polyline`, mirror: ["test_route_polyline_browser_mirror"], note: "서버 노선 저장(편집 갈래 · `_write_planned_polyline`) = Node · 파이썬 짝은 첫 폴리라인(단순화) · 추천 엔진 · B04 배수 · 노선 열기가 부름 — 짝 남음 · 알려진 차 = 교각 딱 5° 배수면 원호 점 ±1(libm 끝자리 · 실데이터 0 차)", }, { id: "route.handle", no: "R2", label: "손잡이 → IP · R", inputs: ["input.route"], outputs: ["편집 입력"], site: "browser_only", stage: null, ts: `${B05L}B05_Profile_UI_RouteEdit_Curve.ts#dragHandleTo`, runner: `browser:${B05L}B05_Profile_UI_RouteEdit_Curve.ts#dragHandleTo`, pair: null, mirror: ["test_route_polyline_handle_drag"], }, { id: "route.node_edits", no: "R3", label: "노드 편집 규칙(곡선 한도 · 고정점)", inputs: ["input.route"], outputs: ["고친 노드"], site: "browser_now", stage: "route", ts: `${B05L}B05_Profile_UI_RouteEdit_Edits.ts#applyCurveLimits`, runner: "node:route.polyline", pair: `${B05}B05_Profile_Route_NodeEdits.py#node_edits`, mirror: ["test_430_route_edit_rules"], note: "곡선표 편집표 = Node `route.polyline` 의 `nodeEdits` · 파이썬 짝 = Node 못 돌릴 때", }, { id: "route.station_fit", no: "R4", label: "스냅 맞춤(MC → 일반측점)", inputs: ["input.route"], outputs: ["IP 자리"], site: "browser_only", stage: null, ts: `${B05L}B05_Profile_RouteEdit_StationFit.ts#fitCurveStations`, runner: `browser:${B05L}B05_Profile_RouteEdit_StationFit.ts#fitCurveStations`, pair: null, mirror: ["test_366_3_station_fit"], note: "짝 아님(머리 명시) — 서버는 저장 IP 그대로", }, /* ── 측점 ─────────────────────────────────────────────────────────────── */ { id: "stations.frame", no: "R5", label: "측점 틀(법선 · 방위 · 스냅 측점)", inputs: ["route.polyline"], outputs: ["측점 좌표 · 방위"], site: "browser_now", stage: "stations", ts: `${B05L}B05_Profile_UI_RouteEdit_Frame.ts#stationFrameAt`, runner: "node:stations.list", pair: `${B05}B05_Profile_Engine_Sections_Core.py#generate_sections`, mirror: ["test_b05_routeedit_frame_mirror", "test_224_2_station_snap"], note: "서버 측점 생성 = Node `stations.sections`(DTM) · 파이썬 짝 = DTM 아닌 지표면 · 추천 엔진 · B06 측점 맞춤", }, { id: "stations.list", no: "R6", label: "측점 목록(일반 · 관 · 구조물 · 곡선 · 시종점)", inputs: [ "route.polyline", "input.pipes", "input.structures", "input.plusStations", "stations.frame", "stations.key", "facility.stations", ], outputs: ["측점 · 열쇠", "store.stations", "db:cross_sections"], site: "browser_now", stage: "stations", ts: `${B05L}B05_Profile_Sections_Stations.ts#buildStations`, runner: "node:stations.list", pair: `${B05}B05_Profile_Engine_Sections_Core.py#generate_sections`, mirror: ["test_344_3_pipeline_stations_mirror", "test_407_curve_station"], note: "서버 측점 생성 길(B03 체인 · 노선 저장 · 재생성 · 추천 초기 종단) = Node `stations.sections`(DTM) · 파이썬 짝 = DTM 아닌 지표면 · B07 IP 표 · 추천 엔진", }, { id: "stations.key", no: "R7", label: "측점 열쇠(grid:k · pipe: · structure:)", inputs: ["stations.frame"], outputs: ["측점 열쇠"], site: "browser_now", stage: "stations", ts: `${U}common_util_station_key.ts#stationKey`, runner: "node:stations.list", pair: `${U}common_util_station_key.py#station_key`, mirror: ["test_344_3_station_key_mirror"], note: "노선 저장 이월 열쇠 = Node 측점 출력(`key` · 옛 노선 = `stations.list`) · 파이썬 짝 = 옛 열쇠 꼴 읽기(at: · 누가거리)", }, { id: "stations.swap", no: "R8", label: "측점 갈아끼움(새 측점에 횡단 옮김)", inputs: ["stations.list", "store.stations"], outputs: ["초안 상세"], site: "browser_only", stage: null, ts: `${B06L}B06_Section_Station_Swap.ts#swapCrossSections`, runner: `browser:${B06L}B06_Section_Station_Swap.ts#swapCrossSections`, pair: null, mirror: ["test_346_2_station_swap", "test_272_swap_keeps_canon"], note: "가게 stations 구독 · 서버는 처음부터 셈 — R6 이 서버와 한 벌이 되면 대부분 걷힘", }, { id: "stations.carry", no: "R9", label: "노선 바뀜 횡단 고침 넘김(측점 열쇠 → 새 측점 patch)", inputs: ["stations.key", "session:crossdesign", "session:revetx"], outputs: ["[저장] 횡단 patch(새 노선)"], site: "browser_now", stage: null, ts: `${B06L}B06_Section_Route_Carry.ts#carryKeyedStates`, runner: "node:stations.carry", pair: null, mirror: ["test_472_6_route_save", "test_417_route_carry", "test_443_2_uphill_carry"], note: "브라우저 = 끌기 동안 같은 노선 목록 갈림(`carryStationKeys`) · 서버 = 노선 바뀐 [저장](`B06_Section_Route_Carry_Patch.routeCarryPatches` · 상단측 안 넘김 요구 274)", }, /* ── 지반 ─────────────────────────────────────────────────────────────── */ { id: "ground.sample", no: "G1", label: "지반 표본", inputs: ["stations.list", "file:dtm_grid"], outputs: ["측점 표본"], site: "browser_now", stage: "ground", ts: `${U}common_util_surface_sampler.ts#heightAt`, runner: `py:${U}common_util_surface_sampler.py#build_surface_sampler`, pair: `${U}common_util_surface_sampler.py#build_surface_sampler`, mirror: ["test_344_1_surface_sampler_mirror"], note: "서버 측점 생성(DTM) = Node `stations.sections` 격자 표본 · 파이썬 표본기 남김 = DTM 아닌 지표면 · 조작 중 「서버」 표본 창구 · B04 · B07 · 추천 · X2 = 브라우저 격자 .bin · 서버 npz(값 협의)", }, { id: "ground.extend", no: "G2", label: "미교차 넓힘 표본", inputs: ["ground.sample", "cross.design"], outputs: ["넓힌 표본"], site: "browser_now", stage: "cross", ts: `${B05L}B05_Profile_Sections_Ground.ts#extendUnclosed`, runner: "node:cross.enforce", pair: `${B06}B06_Section_Engine_SampleExtend.py#extend_unclosed`, mirror: ["test_344_1_sections_ground_mirror", "test_511_b4_cross_save_mirror"], note: "[저장] = Node cross.enforce 안(DTM 격자 · 511-B B-4) · DTM 아닌 지표면 = 파이썬 짝(표본기)", }, { id: "ground.widen", no: "G3", label: "넓힘(표본 폭 넘음)", inputs: ["stations.list", "file:dtm_grid"], outputs: ["표본 폭", "db:cross_sections"], site: "server_only", stage: null, ts: null, runner: `py:${B06}B06_Section_Router_Widen.py#widen_route_sections`, pair: null, mirror: [], note: "저장 밖에서 DB 씀(N10) — 저장 시점 472-6 협의", }, { id: "ground.uphill", no: "G4", label: "상단측(단면 유형 기본 재료)", inputs: ["ground.sample"], outputs: ["상단측"], site: "browser_now", stage: "cross", ts: `${B05L}B05_Profile_Pipeline_Detail.ts#uphillSide`, runner: "node:stations.sections", pair: `${B05}B05_Profile_Engine_Sections_Core.py#generate_sections`, mirror: ["test_346_2_pipeline_cross_page"], note: "서버 측점 생성(DTM) = Node `stations.sections` 의 상단측 · DTM 아닌 지표면 = 파이썬 짝", }, /* ── 종단 ─────────────────────────────────────────────────────────────── */ { id: "profile.base", no: "P1", label: "첫 계획선(지반 따라감 base PVI)", inputs: ["ground.sample"], outputs: ["base PVI"], site: "browser_now", stage: "planline", ts: `${B05L}B05_Profile_Grade_Ground.ts#groundFollowingBasePvi`, runner: "node:profile.base", pair: `${B05}B05_Profile_Engine_Grade_Profile.py#straight_pass_through`, mirror: ["test_344_2_route_pairs", "test_432_1_curve_law", "test_511_b3_profile_node"], note: "1순위 = Node(511-B B-3) · 못 서면 파이썬 2~4 순위(관 정착 · 직선 분할 · 정함) · 파이썬 짝 = 추천 엔진(RouteInitial_Profile) 몫", }, { id: "profile.alignment", no: "P2", label: "계획선 짓기(편집 → 꼭짓점 · 종단곡선)", inputs: ["profile.base", "input.alignment"], outputs: ["측점 계획고", "store.profile", "file:profile_alignment"], site: "browser_now", stage: "profile", ts: `${B05L}B05_Profile_UI_Profile_Alignment.ts#buildAlignment`, runner: "node:profile.alignment", pair: `${B05}B05_Profile_Engine_Grade_Alignment.py#build_alignment`, mirror: [ "test_426_profile_straight", "test_432_1_curve_law", "test_213_1_hidden_station_pvi", "test_438_1_initial_straighten", "test_511_b3_profile_node", ], note: "정본 꼴(0.000001 m) = 파이썬 `Engine_Grade_Node.alignment_record` · 파이썬 짝 = 2~4 순위 폴백 몫", }, { id: "profile.curve_law", no: "P3", label: "종단곡선 법칙(L · R = L/Δ · 큰 R 직선)", inputs: ["profile.alignment"], outputs: ["L · R"], site: "browser_now", stage: "profile", ts: `${B05L}B05_Profile_Profile_CurveLaw.ts#flatBends`, runner: "node:profile.alignment", pair: `${B05}B05_Profile_Engine_Grade_CurveLaw.py#flat_bends`, mirror: ["test_432_1_curve_law"], }, { id: "profile.straight", no: "P4", label: "직선 판정", inputs: ["profile.alignment"], outputs: ["직선 꼭짓점"], site: "browser_now", stage: "profile", ts: `${B05L}B05_Profile_Profile_Straight.ts#isStraightBend`, runner: "node:profile.alignment", pair: `${B05}B05_Profile_Engine_Grade_Alignment.py#is_straight_bend`, mirror: ["test_426_profile_straight", "test_271_straighten_pick"], }, { id: "profile.carry", no: "P5", label: "노선 바뀜 계획고 옮김", inputs: ["route.polyline"], outputs: ["옮긴 편집(input.alignment 고침)"], site: "browser_now", stage: "follow", ts: `${B05L}B05_Profile_Grade_Carry.ts#carryEdits`, runner: "node:profile.carry", pair: null, mirror: ["test_400_profile_carry", "test_349_0v_route_save_span", "test_511_b3_profile_node"], note: "노선 [저장] = 꼭짓점 세움(`seatRouteMoved`)과 Node 한 부름(`Engine_Grade_Node.carry_seat`)", }, { id: "profile.seat", no: "P6", label: "옮긴 시설 꼭짓점 세움", inputs: ["route.polyline"], outputs: ["꼭짓점(input.alignment 고침)"], site: "browser_now", stage: "follow", ts: `${B05L}B05_Profile_Grade_Seat.ts#seatBornNodes`, runner: "node:profile.seat", pair: null, mirror: ["test_427_1_follow_seat", "test_459_route_seat_mirror", "test_472_4_follow_node"], note: "파이썬 `Router_Confirm._seat_born_nodes` = Node 부름 겉(측점 병합 · Route_Save `_carry_profile`)", }, { id: "profile.tools", no: "P7", label: "직선화 · 자유지정 · 쉬프트 · 시종점", inputs: ["profile.alignment"], outputs: ["편집 입력"], site: "browser_only", stage: null, ts: `${B05L}B05_Profile_UI_Profile_Straighten.ts#straightenBetween`, runner: `browser:${B05L}B05_Profile_UI_Profile_Straighten.ts#straightenBetween`, pair: null, mirror: [], note: "편집값만 저장 → profile.alignment · 자유지정 design_profile_free · 쉬프트 Pivot · 시종점 EndOffsets", }, { id: "profile.warnings", no: "P8", label: "종단 경고(최대 기울기 · 법정 L · 최소 R · 최소 피복)", inputs: ["profile.alignment", "context.page_settings"], outputs: ["경고 칩", "file:profile_alignment.warnings"], site: "browser_now", stage: null, ts: `${B05L}B05_Profile_Profile_CurveLaw.ts#verticalCurveShortfalls`, runner: "node:profile.alignment", pair: `${B05}B05_Profile_Engine_Grade.py#resolve_grade_options`, mirror: ["test_442_2_grade_limit_mirror"], note: "경고 = 계획선 짓기 안 · 기준표 TS = `logic/B05_Profile_Grade_Criteria.ts`(X5 · 파이썬 표는 추천 · 폴백 몫 · 거울 442_2)", }, /* ── 횡단 ─────────────────────────────────────────────────────────────── */ { id: "cross.design", no: "C1", label: "횡단 설계선(노면 끝 · 미교차)", inputs: ["profile.alignment", "ground.sample", "input.cross"], outputs: ["설계선", "db:cross_sections.design"], site: "browser_now", stage: "cross", ts: `${U}common_util_cross_design.ts#computeCrossDesign`, runner: "node:cross.design", pair: `${B06}B06_Section_Engine_Design.py#compute_cross_design`, mirror: ["test_b06_cross_design_mirror", "test_178_2_berm_fill_mirror"], note: "[저장] · [확정] 다시 셈 = Node(472-4 ②) · 파이썬 짝 남음(B07 · 추천 · Route_Save · B05 확정 · 넓힘 찾기) · 알려진 차 = 설계선 점 반올림 동점 1e-4 m", }, { id: "cross.areas", no: "C2", label: "단면적(절 · 성 · 측구 · 층따기)", inputs: ["cross.design"], outputs: ["측점 면적", "db:cross_sections.design"], site: "browser_now", stage: "cross", ts: `${U}common_util_cross_design_areas.ts#splitCutAreas`, runner: "node:cross.design", pair: `${B06}B06_Section_Engine_Areas.py#_split_cut_areas`, mirror: ["test_b06_cross_design_mirror"], note: "설계선과 한 셈(cross.design) · X3 한 갈래 — 표준 측점 · 구조물 측점(structure.layouts) 모두 Node", }, { id: "cross.enforce", no: "C3", label: "확정 보정(포장 구간 · 세월교 하강 · 기울임)", inputs: ["cross.design", "input.structures"], outputs: ["보정 설계"], site: "browser_now", stage: "cross", ts: `${B06L}B06_Section_Cross_Enforce.ts#facilityRanges`, runner: "node:cross.enforce", pair: `${B06}B06_Section_Router_Design.py#enforce_design_lines`, note: "[저장] 횡단 한 바퀴 = Node cross.enforce · 기본 설계 구간 = cross.design facilities(511-B B-4) · 파이썬 짝 = DTM 아닌 지표면 · Node 못 부를 때", mirror: ["test_349_0n_cross_enforce_mirror", "test_511_b4_cross_save_mirror"], }, { id: "cross.berm_spans", no: "C4", label: "소단 구간(구조물 → 구간)", inputs: ["input.structures"], outputs: ["소단 구간"], site: "browser_now", stage: null, ts: `${U}common_util_berm_spans.ts#bermSpansFromStructures`, runner: "node:cross.berm_spans", pair: `${B06}B06_Section_Engine_Structures_Wall.py#load_berm_spans`, mirror: ["test_272_berm_source"], note: "[저장] 다시 셈 = Node(472-4 ②) · 파이썬 짝은 Node 못 부를 때만", }, { id: "cross.berm_slope", no: "C5", label: "소단 사면 점", inputs: ["cross.design"], outputs: ["사면 꺾임"], site: "browser_now", stage: "cross", ts: `${U}common_util_cross_berm.ts#cutProfilePoints`, runner: "node:cross.design", pair: `${U}common_util_cross_berm.py#cut_profile_points`, note: "설계선 셈 안(cross.design) · 파이썬 짝 남음(cross.design 과 같은 까닭)", mirror: ["test_178_2_berm_fill_mirror"], }, { id: "cross.underdrain", no: "C6", label: "맹암거 얹기 · 기울임", inputs: ["cross.design", "input.structures"], outputs: ["underdrain 칸"], site: "browser_now", stage: "cross", ts: `${U}common_util_structure_underdrain.ts#attachUnderdrainSpecs`, runner: "node:facility.attach", pair: `${B06}B06_Section_Engine_Tilt.py#attach_underdrain_specs`, mirror: ["test_472_4_underdrain_mirror"], note: "얹기 = GET 상세 Node facility.attach 안(511-B B-4) · 파이썬 짝 = Node 못 부를 때(`_attach_python`) · 알려진 차 = 옛 underdrain 걷음 TS 만 · 기울임은 cross.design 안", }, { id: "cross.fit", no: "C7", label: "반폭 맞춤 · 교차점 손잡이 · 성토 5 m 경고", inputs: ["cross.design"], outputs: ["표시 반폭 · 경고"], site: "browser_only", stage: null, ts: `${B06L}B06_Section_UI_Cross_Fit.ts#toeOffsets`, runner: `browser:${B06L}B06_Section_UI_Cross_Fit.ts#toeOffsets`, pair: null, mirror: [], }, ...FACILITY_ROWS, ];