Files
Aislo/B05_Profile/B05_Profile_Api_TerrainGrid.ts
T

56 lines
2.5 KiB
TypeScript

/* =============================================================================
* B05_Profile_Api_TerrainGrid.ts
* 설계 지형 격자를 받아 둔다 — 노선 편집이 지반고를 브라우저에서 바로 읽게(PLAN 344-1).
*
* GET /projects/{id}/route/terrain-sources → 설계 지형 · 격자 받을 자리(`grid`)
* GET /projects/{id}/surface/models/{mid}/grid → DTM 격자 원시 이진(ETag · IndexedDB)
*
* 주소에 manifest 서명을 붙임 — 보관함은 옛 저장본을 먼저 내므로(`fetchCachedBytes`) 지형이
* 바뀐 뒤 옛 격자로 한 번 그리는 일을 막음. DTM 아닌 표현 · 못 받음 = null → 서버 표본 길.
* ========================================================================== */
import { API_BASE_URL } from "@config/config_frontend";
import { fetchCachedBytes } from "../A00_Common/b_asset_cache";
import { type DtmGrid, parseDtmGrid } from "../common_util/common_util_surface_sampler";
export interface DesignTerrainGrid {
/** 이 격자의 지형 — 편집 창 분석 지형이 이것과 같을 때만 씀. */
design: "las" | "sheet";
grid: DtmGrid;
}
interface TerrainSourcesPayload {
design?: "las" | "sheet";
grid?: { model_id: number; smooth: boolean; signature: string } | null;
}
const loaded = new Map<string, Promise<DesignTerrainGrid | null>>();
async function download(projectId: string): Promise<DesignTerrainGrid | null> {
const response = await fetch(`${API_BASE_URL}/projects/${projectId}/route/terrain-sources`, {
credentials: "include",
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
const payload = (await response.json()) as TerrainSourcesPayload;
const info = payload.grid;
if (!info) return null;
const url =
`${API_BASE_URL}/projects/${projectId}/surface/models/${info.model_id}/grid` +
`?smooth=${info.smooth}&sig=${encodeURIComponent(info.signature)}`;
const grid = parseDtmGrid(await fetchCachedBytes(projectId, url));
return { design: payload.design === "sheet" ? "sheet" : "las", grid };
}
/** 설계 지형 격자 — 페이지 수명 동안 한 번만 받음 · 받다 실패하면 null(다음 부름에 다시 해 봄). */
export function loadDesignTerrainGrid(projectId: string): Promise<DesignTerrainGrid | null> {
let pending = loaded.get(projectId);
if (!pending) {
pending = download(projectId).catch(() => {
loaded.delete(projectId);
return null;
});
loaded.set(projectId, pending);
}
return pending;
}