feat(B03·B04): 지형 라이다 여러 장 입력·병합 전처리
- 지형 파일 개수 제한 해제(정확히 1개 → 1장 이상), 한 카드에 여러 장 담기 (화면 표시 「용화_서편.las 외 1장」, 업로드는 한 장씩 차례로 전송) - 구조화 엔진이 여러 파일을 합친 범위로 한 벌 생성 — WF1 자동 전처리·B04 재분석 모두 프로젝트 지형 파일 전부를 대상으로 실행 - 점이 1억 개를 넘으면 씨닝 — 지면 분류점은 전부 남기고 나머지만 0.5m 칸 최저점으로 축소 (용화 실측: 4,900만점 → 249만점, 지면점 1,140,716개 그대로, 1m 지면격자 표고차 0.0000m) - 머리글만 읽어 5km 넘게 떨어진 파일은 업로드 거부 (임도는 길어도 2~3km) - 화면 조립부 700줄 준수를 위해 terrainCoverage 를 판정 모듈로 이동 Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -24,15 +24,11 @@ import { createUploadFlow } from "./B03_FileInput_UI_Page_Flow";
|
||||
import {
|
||||
isSlotRequired,
|
||||
slotForOverviewFile,
|
||||
terrainCoverage,
|
||||
validateFileForSlot,
|
||||
validateSlots,
|
||||
} from "./B03_FileInput_UI_Page_Rules";
|
||||
import {
|
||||
readCrsLabel,
|
||||
readExtent,
|
||||
renderSlotPreview,
|
||||
type PreviewExtent,
|
||||
} from "./B03_FileInput_UI_Preview";
|
||||
import { readCrsLabel, renderSlotPreview } from "./B03_FileInput_UI_Preview";
|
||||
import { confirmReplaceUpload } from "./B03_FileInput_UI_Upload";
|
||||
import {
|
||||
createFileCardTemplate,
|
||||
@@ -41,9 +37,11 @@ import {
|
||||
initializeSlots,
|
||||
makeSessionKey,
|
||||
planSlotAssignments,
|
||||
pushExtraFile,
|
||||
ROUTE_SLOTS,
|
||||
SHAPEFILE_DEPENDENT_SLOTS,
|
||||
slotConfigs,
|
||||
slotFileLabel,
|
||||
TERRAIN_SLOTS,
|
||||
type FileSlot,
|
||||
type FileSlotState,
|
||||
@@ -209,7 +207,7 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
|
||||
const percent = state.file ? Math.min(100, (state.progressBytes / state.file.size) * 100) : 0;
|
||||
// 로컬 파일이 없어도 서버에 업로드된 파일이 있으면 그 정보(정본)를 보여준다.
|
||||
if (fileName) fileName.textContent = state.file?.name ?? state.serverUploaded?.name ?? "";
|
||||
if (fileName) fileName.textContent = slotFileLabel(state);
|
||||
if (fileSize) {
|
||||
fileSize.textContent = state.file
|
||||
? formatBytes(state.file.size)
|
||||
@@ -240,7 +238,7 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
|
||||
const preview = card.querySelector<HTMLDivElement>(".b03-file__preview");
|
||||
if (preview) {
|
||||
const terrain = terrainCoverage();
|
||||
const terrain = terrainCoverage(slots);
|
||||
renderSlotPreview(preview, {
|
||||
metadata: state.serverUploaded?.metadata,
|
||||
// 업로드·분석이 끝난 카드에만 보인다 (2026-09-04 사용자 지시).
|
||||
@@ -258,26 +256,6 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
* 들어오는지 대조하는 기준. 초기 계산 실패의 주된 원인이 범위 불일치라
|
||||
* 카드에서 바로 보이게 한다(2026-09-04).
|
||||
*/
|
||||
function terrainCoverage(): { extent: PreviewExtent | null; crs: string | null } {
|
||||
let extent: PreviewExtent | null = null;
|
||||
let crs: string | null = null;
|
||||
for (const slot of TERRAIN_SLOTS) {
|
||||
const metadata = slots.get(slot)?.serverUploaded?.metadata;
|
||||
const next = readExtent(metadata);
|
||||
if (!next) continue;
|
||||
crs ??= readCrsLabel(metadata);
|
||||
extent = extent
|
||||
? {
|
||||
xMin: Math.min(extent.xMin, next.xMin),
|
||||
xMax: Math.max(extent.xMax, next.xMax),
|
||||
yMin: Math.min(extent.yMin, next.yMin),
|
||||
yMax: Math.max(extent.yMax, next.yMax),
|
||||
}
|
||||
: next;
|
||||
}
|
||||
return { extent, crs };
|
||||
}
|
||||
|
||||
function showErrorMessage(slot: FileSlot, error: string): void {
|
||||
const state = slots.get(slot);
|
||||
if (!state) return;
|
||||
@@ -297,8 +275,13 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
showErrorMessage(state.slot, `${validation} ${file.name}`);
|
||||
return;
|
||||
}
|
||||
if (!targetSlot && state.file && state.file.name !== file.name) {
|
||||
showErrorMessage(state.slot, `${L("B03_File_Error_DuplicateSlot")} ${file.name}`);
|
||||
// 지형 자료는 도엽별로 여러 장이 온다 — 카드에 더 담고 전처리가 합쳐 쓴다.
|
||||
if (state.file && state.file.name !== file.name) {
|
||||
if (!pushExtraFile(state, file)) {
|
||||
showErrorMessage(state.slot, `${L("B03_File_Error_DuplicateSlot")} ${file.name}`);
|
||||
return;
|
||||
}
|
||||
renderSlot(state.slot);
|
||||
return;
|
||||
}
|
||||
// 서버에 이미 완료된 슬롯이면 교체 확인을 받는다(2026-08-04 사용자 지시). 이어올리기로
|
||||
@@ -382,6 +365,7 @@ export async function renderB03FileInput(root: HTMLElement): Promise<void> {
|
||||
localStorage.removeItem(makeSessionKey(activeProjectId, state.file));
|
||||
}
|
||||
state.file = undefined;
|
||||
state.extraFiles = undefined;
|
||||
state.uploadSessionId = undefined;
|
||||
state.uploadStatus = "pending";
|
||||
state.progressBytes = 0;
|
||||
|
||||
Reference in New Issue
Block a user