115 lines
4.1 KiB
TypeScript
115 lines
4.1 KiB
TypeScript
/* =============================================================================
|
|
* D03_PlanAnalysis_Api.ts
|
|
* D03 분석 화면 서버 요청(PLAN 530-3) — 지점 정본(D02) · 지형 받기 · 분석 · 진행 · 저장본 · [저장] ·
|
|
* 연도별 지형면(모델 행 · 격자). 끈 지점은 `points`(작업 좌표계 m)로 실어 보냄.
|
|
* ========================================================================== */
|
|
|
|
import { API_BASE_URL } from "@config/config_frontend";
|
|
import { fetchCachedBytes } from "../A00_Common/b_asset_cache";
|
|
import { listSurfaceModels } from "../B04_PreProcess/B04_PreProcess_Api_Fetch";
|
|
import { type DtmGrid, parseDtmGrid } from "../common_util/common_util_surface_sampler";
|
|
import type { ChainRow, Vertex, YearAnalysis } from "./logic/D03_PlanAnalysis_Plan";
|
|
|
|
export interface PlanPointsView {
|
|
year_start: number;
|
|
year_end: number;
|
|
epsg: number | null;
|
|
years: Array<{
|
|
year: number;
|
|
start: { x: number; y: number } | null;
|
|
end: { x: number; y: number } | null;
|
|
}>;
|
|
}
|
|
|
|
export interface PlanJob {
|
|
running: boolean;
|
|
percent: number;
|
|
message: string | null;
|
|
error: string | null;
|
|
}
|
|
|
|
export interface PlanAnalysisView {
|
|
years: Array<{ year: number; start: Vertex; end: Vertex; analysis: YearAnalysis | null }>;
|
|
chain: ChainRow[] | null;
|
|
/** 등록 노선 시작 누가(m). */
|
|
start_chainage_m: number;
|
|
/** 등록 노선 종료 누가(계획 목표 · m) — 없으면 null. */
|
|
end_chainage_target_m?: number | null;
|
|
}
|
|
|
|
export type PlanPoints = Array<{ year: number; start: Vertex; end: Vertex }>;
|
|
|
|
async function request<T>(path: string, init: RequestInit = {}): Promise<T> {
|
|
const response = await fetch(`${API_BASE_URL}${path}`, {
|
|
...init,
|
|
credentials: "include",
|
|
headers: { "Content-Type": "application/json", ...(init.headers ?? {}) },
|
|
});
|
|
const body = (await response.json().catch(() => ({}))) as T & { detail?: unknown };
|
|
if (!response.ok) {
|
|
const detail = typeof body.detail === "string" ? body.detail : `HTTP ${response.status}`;
|
|
throw new Error(detail);
|
|
}
|
|
return body;
|
|
}
|
|
|
|
const base = (projectId: string): string => `/projects/${projectId}/plan`;
|
|
const pointsBody = (points: PlanPoints | null): string => JSON.stringify(points ? { points } : {});
|
|
|
|
export const fetchPlanPoints = (projectId: string): Promise<PlanPointsView> =>
|
|
request(`${base(projectId)}/points`);
|
|
|
|
export const startPlanJob = (
|
|
projectId: string,
|
|
kind: "terrain" | "analyze",
|
|
points: PlanPoints | null,
|
|
): Promise<PlanJob> =>
|
|
request(`${base(projectId)}/${kind}`, { method: "POST", body: pointsBody(points) });
|
|
|
|
export const fetchPlanProgress = (
|
|
projectId: string,
|
|
): Promise<{ terrain: PlanJob; analyze: PlanJob }> => request(`${base(projectId)}/progress`);
|
|
|
|
export const fetchPlanAnalysis = (
|
|
projectId: string,
|
|
points: PlanPoints | null,
|
|
): Promise<PlanAnalysisView> =>
|
|
request(
|
|
`${base(projectId)}/analysis` +
|
|
(points ? `?points=${encodeURIComponent(JSON.stringify(points))}` : ""),
|
|
);
|
|
|
|
export const savePlanAnalysis = (
|
|
projectId: string,
|
|
choices: Record<number, string>,
|
|
points: PlanPoints | null,
|
|
): Promise<{ chain: ChainRow[] }> =>
|
|
request(`${base(projectId)}/analysis`, {
|
|
method: "PUT",
|
|
body: JSON.stringify(points ? { choices, points } : { choices }),
|
|
});
|
|
|
|
export interface YearSurface {
|
|
modelId: number;
|
|
grid: DtmGrid;
|
|
}
|
|
|
|
/** 연도별 지형면 — 모델 행 경로 `…/models_<연도>/…` · 격자 = 분석과 같은 평활본. */
|
|
export async function fetchYearSurfaces(projectId: string): Promise<Map<number, YearSurface>> {
|
|
const { models } = await listSurfaceModels(projectId);
|
|
const out = new Map<number, YearSurface>();
|
|
for (const model of models) {
|
|
const year = Number(/models_(\d+)\//.exec(model.model_file_path ?? "")?.[1]);
|
|
if (!year || out.has(year)) continue;
|
|
const stamp = String(model.generation_params?.file_stamp ?? "");
|
|
const url =
|
|
`${API_BASE_URL}/projects/${projectId}/surface/models/${model.id}/grid` +
|
|
`?smooth=true&sig=${encodeURIComponent(stamp)}`;
|
|
out.set(year, {
|
|
modelId: model.id,
|
|
grid: parseDtmGrid(await fetchCachedBytes(projectId, url)),
|
|
});
|
|
}
|
|
return out;
|
|
}
|