- 측점 뜨기(design_pipeline_probe)가 형상 · 이름 얹은 단면도 돌려줌 · 창은 「횡단」 판과 같은 routeCrossCard(서버 미리 뜬 것만 선 그림) - Cross_Card 판 재료 crossSourceOf 로 나눔(창 · 판 한 벌) · 카드 머리 걷기 전 경고 칩을 그래프 오른쪽 위로 - 곡선 판 가둠 = 편집 도구줄 아래 · 열린 횡단 판 왼쪽 · 뜬 종단 판 위 · 판 크기 바뀌면 다시 가둠 - 종단 지반선 · 계획선 pointer-events none · WF_State_Stale = 「다시 확인 필요 (앞 단계 변경)」 · ui-button → ui-btn - 시험 test_505_3_cross_card_text · test_505_3_cross_card_screen(5179) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
119 lines
5.1 KiB
TypeScript
119 lines
5.1 KiB
TypeScript
/* =============================================================================
|
|
* A00_Common/design/design_pipeline_probe.ts
|
|
* 계산 묶음 아무 누가거리 한 장(368-4 · 요구 240-21) — 종단 원지반 점 작은 창 = 지금 계획선(초안 포함).
|
|
*
|
|
* 묶음 출력(노선 · 측점 · 종단 · 횡단 입력 · 관 · 구조물)을 읽기만 하고, 같은 단계 함수(ground · cross ·
|
|
* `crossWithUphill` · `stationSection`)를 그 자리 측점 하나로 다시 부름 — [측점 추가] 뒤 묶음이 낼 측점과
|
|
* 같은 틀 · 반경 · 확폭(기존 측점 + 그 자리로 셈). 파생 저장 · 캐시 · 묶음 상태는 안 건드림.
|
|
* 지형 격자가 없거나 분석 지형 ≠ 설계 지형이면 null(부르는 쪽이 서버 미리 뜨기로).
|
|
* 단면(`section`) = 그 측점에 지금 현황 형상 · 이름을 얹은 것 — 창이 「횡단」 판과 같은 B06 카드로 그림(505-3).
|
|
* ========================================================================== */
|
|
|
|
import { pagePipeline } from "./design_pipeline_page";
|
|
import type {
|
|
CrossOutput,
|
|
GroundOutput,
|
|
StageContext,
|
|
StageName,
|
|
} from "./logic/design_pipeline_types";
|
|
import { probeStation } from "./logic/design_pipeline_probe_station";
|
|
import { groundStageDeps } from "../../B05_Profile/B05_Profile_Api_TerrainGrid";
|
|
import { createGroundStage } from "../../B05_Profile/logic/B05_Profile_Pipeline_RouteGround";
|
|
import {
|
|
attachStatus,
|
|
crossWithShapes,
|
|
crossAtSeat,
|
|
crossWithUphill,
|
|
shapeStatus,
|
|
stationSection,
|
|
type CrossInput,
|
|
} from "../../B05_Profile/logic/B05_Profile_Pipeline_Detail";
|
|
import { fetchStructureTypes } from "../../B05_Profile/B05_Profile_Api_Structures";
|
|
import { createCrossStage } from "../../B06_Section/logic/B06_Section_Cross_Stage";
|
|
import { pipelineCrossAt } from "../../B05_Profile/B05_Profile_UI_RouteEdit_Cross";
|
|
import type { CrossPreviewResponse } from "../../B05_Profile/B05_Profile_Api_Replan";
|
|
import type { CrossSection } from "../../B06_Section/B06_Section_Api_Fetch";
|
|
|
|
const SAME_M = 1e-6;
|
|
|
|
/**
|
|
* 지금 계획선(초안 포함)으로 그 누가거리 임시 횡단(선 그림 재료 · 형상 얹은 단면) — 묶음이 아직 안 셌거나
|
|
* 격자 없음 · 분석 지형 ≠ 설계 지형이면 null.
|
|
*/
|
|
export async function pipelineCrossAtChainage(
|
|
projectId: string,
|
|
chainageM: number,
|
|
intervalM: number,
|
|
): Promise<{ preview: CrossPreviewResponse; section: CrossSection } | null> {
|
|
const pipe = pagePipeline(projectId);
|
|
const route = pipe?.output("route");
|
|
const profile = pipe?.output("profile");
|
|
const ground = pipe?.output("ground");
|
|
if (!pipe || !route || !profile || !ground) return null;
|
|
const deps = groundStageDeps(projectId);
|
|
const local = deps.grid();
|
|
const terrain = pipe.input("route")?.terrain ?? null;
|
|
if (!local || (terrain !== null && terrain !== local.design)) return null;
|
|
|
|
const inputs = {
|
|
route: pipe.input("route"),
|
|
alignment: pipe.input("alignment"),
|
|
cross: pipe.input("cross"),
|
|
pipes: pipe.input("pipes"),
|
|
structures: pipe.input("structures"),
|
|
};
|
|
const existing = ground.stations.find((s) => Math.abs(s.chainageM - chainageM) < SAME_M);
|
|
let station = existing ?? null;
|
|
if (!station) {
|
|
const probe = probeStation(route.line, route.curves, ground.stations, chainageM);
|
|
if (!probe) return null;
|
|
// ground 단계 그대로 — 측점 하나 · 종단 지반선은 안 뜸(노선 선 빼고 넘김)
|
|
const ctx = {
|
|
generation: 0,
|
|
range: null,
|
|
signal: new AbortController().signal,
|
|
inputs,
|
|
out: { stations: [probe], route: { ...route, line: null } },
|
|
before: {},
|
|
prev: null,
|
|
} as unknown as StageContext<"ground">;
|
|
const filled = (await createGroundStage(deps)(ctx)) as GroundOutput;
|
|
station = filled.stations[0] ?? null;
|
|
}
|
|
if (!station) return null;
|
|
// 시설 맥락 = 지금 현황을 그 측점에 얹은 그림에서(묶음 cross 와 같음 · 457)
|
|
const status = shapeStatus(
|
|
inputs.pipes,
|
|
inputs.structures,
|
|
await fetchStructureTypes(true).catch(() => []),
|
|
);
|
|
const shaped = crossWithShapes(
|
|
crossAtSeat(inputs.cross as CrossInput | null, [station]),
|
|
[station],
|
|
status,
|
|
);
|
|
const out = {
|
|
profile,
|
|
ground: { stations: [station], longitudinal: { chainageM: [], z: [] } },
|
|
} as Partial<Record<StageName, unknown>>;
|
|
const cross: CrossOutput = createCrossStage({ grid: deps.grid }).stage({
|
|
generation: 0,
|
|
range: null,
|
|
signal: new AbortController().signal,
|
|
inputs: { ...inputs, cross: crossWithUphill(shaped, [station]) },
|
|
out,
|
|
before: {},
|
|
prev: null,
|
|
} as unknown as StageContext<"cross">);
|
|
// 평면 우측 횡단 판과 같은 꼴(그림 · 요약) — 이 측점 하나만 실은 묶음처럼 넘김
|
|
const one = {
|
|
output: (name: StageName) =>
|
|
name === "ground" ? { stations: [station] } : name === "cross" ? cross : null,
|
|
} as unknown as Parameters<typeof pipelineCrossAt>[0];
|
|
const preview = pipelineCrossAt(one, chainageM, intervalM, undefined);
|
|
if (!preview) return null;
|
|
const section = stationSection(station, cross, {}, intervalM);
|
|
attachStatus([section], status);
|
|
return { preview, section };
|
|
}
|