- _Search 에 on_progress · should_stop(기본 None · 결과 불변 시험) — 533-2 시험 14 그대로 통과 - 탐색 노드 = 중심선 ± 탐색 폭 · 구간 누가 안 · 격자 = 그 밖 깊이 + 10 m 여유 - 미리보기(가짜) 엔진 지움 · 방법 고르기 → 조건(건기 · 우기) · Hovland 는 같은 임계면 비교 값 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
142 lines
4.3 KiB
TypeScript
142 lines
4.3 KiB
TypeScript
/* =============================================================================
|
|
* E04_Stab3D_UI_Settings.ts
|
|
* E04 좌측 탐색 설정 칸(PLAN 533-3) — 구간 시작 · 끝 · 기본(조건 · 모양 · 탐색 폭) · 고급(접힘 ·
|
|
* 기둥 · 구 중심 격자 · 반지름 증분 · 깊이 · 부피 제약) · [기본값]. 기본값 = 서버 SearchSettings.
|
|
* ========================================================================== */
|
|
|
|
import { createPanelCard } from "@ui/ui_template_collapsible";
|
|
import {
|
|
createButton,
|
|
createInputField,
|
|
createSelectField,
|
|
el,
|
|
type InputFieldHandle,
|
|
} from "@ui/ui_template_elements";
|
|
import { t, type LocaleKey } from "@ui/ui_template_locale";
|
|
|
|
export interface Settings {
|
|
start_m: number;
|
|
end_m: number;
|
|
condition: string;
|
|
shape: string;
|
|
ellipsoid_ratio: number;
|
|
box_half_width_m: number;
|
|
cell_m: number;
|
|
spacing_m: number;
|
|
h_min_m: number;
|
|
h_max_m: number;
|
|
h_step_m: number;
|
|
dr_m: number;
|
|
max_depth_m: number;
|
|
v_min_m3: number;
|
|
v_max_m3: number;
|
|
}
|
|
|
|
type NumberKey = Exclude<keyof Settings, "condition" | "shape">;
|
|
|
|
const BASIC: [NumberKey, LocaleKey][] = [
|
|
["ellipsoid_ratio", "E04_Ratio"],
|
|
["box_half_width_m", "E04_BoxWidth"],
|
|
];
|
|
const ADVANCED: [NumberKey, LocaleKey][] = [
|
|
["cell_m", "E04_Cell"],
|
|
["spacing_m", "E04_Spacing"],
|
|
["h_min_m", "E04_HMin"],
|
|
["h_max_m", "E04_HMax"],
|
|
["h_step_m", "E04_HStep"],
|
|
["dr_m", "E04_Dr"],
|
|
["max_depth_m", "E04_MaxDepth"],
|
|
["v_min_m3", "E04_VMin"],
|
|
["v_max_m3", "E04_VMax"],
|
|
];
|
|
|
|
export function buildSettingsCards() {
|
|
const fields = new Map<NumberKey, InputFieldHandle>();
|
|
const listeners: (() => void)[] = [];
|
|
const changed = (): void => listeners.forEach((fn) => fn());
|
|
const number = (key: NumberKey, label: LocaleKey): HTMLElement => {
|
|
const field = createInputField({ label: t(label), type: "number", compact: true });
|
|
field.input.step = "any";
|
|
field.input.dataset.key = key;
|
|
field.input.addEventListener("change", changed);
|
|
fields.set(key, field);
|
|
return field.root;
|
|
};
|
|
|
|
const rangeRow = el("div", { className: "e04-range" });
|
|
rangeRow.append(number("start_m", "E04_Start"), number("end_m", "E04_End"));
|
|
|
|
const shape = createSelectField({
|
|
label: t("E04_Shape"),
|
|
compact: true,
|
|
options: (["both", "sphere"] as const).map((v) => ({
|
|
value: v,
|
|
text: t(`E04_Shape_${v}` as LocaleKey),
|
|
})),
|
|
onChange: changed,
|
|
});
|
|
const condition = createSelectField({
|
|
label: t("E04_Condition"),
|
|
compact: true,
|
|
options: (["dry", "wet"] as const).map((v) => ({
|
|
value: v,
|
|
text: t(`E04_Condition_${v}` as LocaleKey),
|
|
})),
|
|
onChange: changed,
|
|
});
|
|
const basicCard = createPanelCard(t("E04_Card_Search"), false);
|
|
basicCard.append(condition.root, shape.root, ...BASIC.map(([k, l]) => number(k, l)));
|
|
|
|
let defaults: Partial<Settings> = {};
|
|
const advancedCard = createPanelCard(t("E04_Card_Advanced"), true);
|
|
const grid = el("div", { className: "e04-advanced" });
|
|
grid.append(...ADVANCED.map(([k, l]) => number(k, l)));
|
|
advancedCard.append(
|
|
grid,
|
|
createButton({
|
|
label: t("E04_Defaults"),
|
|
variant: "ghost",
|
|
size: "sm",
|
|
onClick: () => {
|
|
const range = { start_m: read().start_m, end_m: read().end_m };
|
|
write({ ...read(), ...defaults, ...range, condition: "dry" });
|
|
changed();
|
|
},
|
|
}),
|
|
);
|
|
|
|
function read(): Settings {
|
|
const out = { shape: shape.select.value, condition: condition.select.value } as Settings;
|
|
for (const [key, field] of fields) out[key] = Number(field.input.value);
|
|
return out;
|
|
}
|
|
|
|
function write(values: Partial<Settings>): void {
|
|
for (const [key, field] of fields) {
|
|
const value = values[key];
|
|
if (typeof value === "number" && Number.isFinite(value)) field.input.value = String(value);
|
|
}
|
|
if (values.shape) shape.select.value = values.shape;
|
|
if (values.condition) condition.select.value = values.condition;
|
|
}
|
|
|
|
return {
|
|
rangeRow,
|
|
basicCard,
|
|
advancedCard,
|
|
read,
|
|
write,
|
|
setRange(start: number, end: number) {
|
|
write({ start_m: start, end_m: end });
|
|
changed();
|
|
},
|
|
setDefaults(next: Partial<Settings>, maxSection: number) {
|
|
defaults = next;
|
|
fields.get("end_m")!.input.title = `≤ ${maxSection} m`;
|
|
},
|
|
onChange(fn: () => void) {
|
|
listeners.push(fn);
|
|
},
|
|
};
|
|
}
|