Merge remote-tracking branches 'origin/sub_laptop_1', 'origin/sub_laptop_2', 'origin/sub_laptop_3', 'origin/sub_laptop_5' and 'origin/sub_laptop_7' into main_laptop_1
This commit is contained in:
@@ -49,6 +49,7 @@ import {
|
||||
type WallPath,
|
||||
} from "./B05_Profile_UI_Corridor_Structures_Path";
|
||||
import { computeRevetmentLayout } from "../B06_Section/B06_Section_UI_Cross_Revetment";
|
||||
import { withoutGuardedFill } from "../B06_Section/B06_Section_UI_Cross_Body_Guard";
|
||||
|
||||
/** 스윕 프레임 하나 — 노선 위 한 지점의 중심 XY·좌향 단위벡터와 종단 표고 오프셋. */
|
||||
export interface StructureFrame {
|
||||
@@ -274,7 +275,8 @@ export function buildCorridorStructures(
|
||||
const solids: CorridorStructure[] = [];
|
||||
for (const section of crossSections) {
|
||||
const layout = culvertLayoutOf(section);
|
||||
const fordLayout = fordLayoutOf(section);
|
||||
// 흙막이가 선 쪽은 횡단과 같은 자리 함수로 — 측벽 걷고 관 · 바닥판이 흙막이까지(89-1)
|
||||
const fordLayout = withoutGuardedFill(fordLayoutOf(section), layout);
|
||||
// 독립 기슭막이(옛 D군 경로) — 측점에 배관/숨김 기슭막이 세트가 붙으면 그쪽(위
|
||||
// culvertLayoutOf)이 그린다. 아직 이관 안 된 정본만 이 옛 경로로 스윕한다
|
||||
// (2026-08-28 이관 이중그리기 방지 — 횡단도 가드와 같은 규칙).
|
||||
@@ -449,12 +451,11 @@ export function buildCorridorStructures(
|
||||
if (fordLayout) {
|
||||
// 구체는 월류 폭만큼 도로 방향으로 이어지고 기준 측점 전후로 절반씩 걸친다.
|
||||
const half = Math.max(fordLayout.ford.span_m, 0.5) / 2;
|
||||
const invertPoints = fordLayout.pipe.outer;
|
||||
const fordBore = pipeBore(
|
||||
fordLayout.ford.diameter_m,
|
||||
{ offset: invertPoints[3].offset, elevation: invertPoints[3].elevation },
|
||||
{ offset: invertPoints[2].offset, elevation: invertPoints[2].elevation },
|
||||
);
|
||||
// 관 끝 = 윗 꼭짓점 자리(흙막이 사면에서 안 튀어나옴 · 89-1) · 높이 = invert
|
||||
const [topLeft, topRight, invertRight, invertLeft] = fordLayout.pipe.outer;
|
||||
const pipeStart = { offset: topLeft.offset, elevation: invertLeft.elevation };
|
||||
const pipeEnd = { offset: topRight.offset, elevation: invertRight.elevation };
|
||||
const fordBore = pipeBore(fordLayout.ford.diameter_m, pipeStart, pipeEnd);
|
||||
// 관은 련수만큼 폭 안에 등간격 — 구멍도 관마다 하나씩 낸다(2026-08-25 사용자 ⑥).
|
||||
const count = Math.max(fordLayout.ford.pipe_count, 1);
|
||||
const pipeChainages = Array.from(
|
||||
@@ -518,7 +519,6 @@ export function buildCorridorStructures(
|
||||
),
|
||||
);
|
||||
// 관은 련수만큼 폭 안에 등간격으로 놓는다(단면엔 1개만 보이지만 실물은 여러 련).
|
||||
const invert = fordLayout.pipe.outer;
|
||||
for (const at of pipeChainages) {
|
||||
const frame = frameAt(at);
|
||||
solids.push({
|
||||
@@ -526,8 +526,8 @@ export function buildCorridorStructures(
|
||||
kind: "pipe",
|
||||
key: "pipe",
|
||||
pipe: {
|
||||
start: [invert[3].offset, invert[3].elevation],
|
||||
end: [invert[2].offset, invert[2].elevation],
|
||||
start: [pipeStart.offset, pipeStart.elevation],
|
||||
end: [pipeEnd.offset, pipeEnd.elevation],
|
||||
diameterM: fordLayout.ford.diameter_m,
|
||||
wallThicknessM: pipeWallThicknessM(
|
||||
fordLayout.ford.pipe_kind,
|
||||
|
||||
@@ -161,6 +161,22 @@ export function buildStructuresForm(options: {
|
||||
optionRow,
|
||||
{ get: groupBoxes.get, pick: groupBoxes.pick, clear: groupBoxes.clear, set: groupBoxes.setOne },
|
||||
options.onFacilityChange,
|
||||
// 노면공 길이 칸(87-1) = 시작~종료 출력 — 못 셈이면 빈 글(「—」)
|
||||
(_c, item) => {
|
||||
if (item.id !== "length") return "";
|
||||
const step = options.getInterval();
|
||||
const start = startFields.read(step, false);
|
||||
const end = endFields.read(step, false);
|
||||
return start !== null && end !== null && end > start
|
||||
? String(Number((end - start).toFixed(2)))
|
||||
: "";
|
||||
},
|
||||
);
|
||||
// 시작 · 종료를 고치면 길이 출력을 다시 그림
|
||||
[startFields, endFields].forEach((fields) =>
|
||||
[fields.station, fields.remainder].forEach((input) =>
|
||||
input.addEventListener("change", () => structureSpec.refresh()),
|
||||
),
|
||||
);
|
||||
groupBoxes.watch(structureSpec.paintLinks);
|
||||
const staleBox = document.createElement("fieldset");
|
||||
|
||||
@@ -56,6 +56,7 @@ import {
|
||||
DEFAULT_INTERVAL_LENGTH_M,
|
||||
groupOptions,
|
||||
hasComputedRange,
|
||||
isRangeOnly,
|
||||
typeOptions,
|
||||
readBeforeOption,
|
||||
readLengthOption,
|
||||
@@ -238,7 +239,7 @@ export function createStructuresSection(
|
||||
// [?] 설명서가 먼저 여는 항목 = `구조물_<종류 이름>.md`(54-2 · 종류 안내 글은 그 파일로 옮김)
|
||||
root.dataset.helpTopic = type ? `구조물_${type.name}` : "";
|
||||
// 정의가 기준 측점을 끈 종류(48-3) — 기준 측점이 곧 위치인 종류(점형 · 범위 계산)는 늘 보임
|
||||
anchorFields.wrap.hidden = isInterval && !showsAnchor(type!);
|
||||
anchorFields.wrap.hidden = isInterval && (!showsAnchor(type!) || isRangeOnly(type));
|
||||
anchorFields.wrap.querySelector("span")!.textContent = "기준 측점"; // 빈 칸 안내 없음(54-43)
|
||||
syncRangeDisplay();
|
||||
}
|
||||
|
||||
@@ -314,7 +314,10 @@ export async function commit(ctx: StructuresCommitContext, live = false): Promis
|
||||
return;
|
||||
}
|
||||
// 기준 측점(마킹 위치) — 비우면 시작 측점. 시작~종료 밖은 서버도 거절한다.
|
||||
anchor = ctx.anchorFields.read(step, false) ?? start;
|
||||
// 범위 직접 입력형(노면공 · 87-1) = 기준 칸 없음 → 늘 시점.
|
||||
anchor = STRUCTURE_SPECS[type.type_id]?.byRange
|
||||
? start
|
||||
: (ctx.anchorFields.read(step, false) ?? start);
|
||||
if (anchor < start || anchor > end) {
|
||||
ctx.anchorFields.station.classList.add("is-invalid");
|
||||
ctx.anchorFields.station.focus();
|
||||
|
||||
@@ -20,6 +20,7 @@ import {
|
||||
} from "./B05_Profile_Api_Structures";
|
||||
import type { DesignSelection, ResolvedSelection } from "../A00_Common/design/design_selection";
|
||||
import type { GroupItems, SummaryItem } from "../common_util/common_util_summary_item";
|
||||
import { STRUCTURE_SPECS } from "../A00_Common/design/design_structure_pipe";
|
||||
|
||||
/** 구조물군 표시 이름. 리스트 기호(A~G)만으로는 무엇인지 알기 어렵다.
|
||||
* 우클릭 메뉴(종단그래프·배수유역도)도 같은 이름을 쓴다(2026-08-18 일원화). */
|
||||
@@ -209,6 +210,10 @@ export function readBeforeOption(inputs: OptionEntry[]): number {
|
||||
return length !== null && before > length ? length : before;
|
||||
}
|
||||
|
||||
/** 시작 · 종료 측점만 받는 명세 종류인가(노면공 · 87-1) — 기준 측점 칸 없음 · 길이 출력. */
|
||||
export const isRangeOnly = (type: { type_id: string } | null): boolean =>
|
||||
!!type && !!STRUCTURE_SPECS[type.type_id]?.byRange;
|
||||
|
||||
/** 구간을 직접 입력하지 않는 타입인가 — C군 사면안정 5종처럼 B05 길이 옵션이
|
||||
* 있으면 시작·종료 입력 칸을 없애고 기준 측점 + 길이로 범위를 계산해 보여만
|
||||
* 준다(2026-08-19 사용자 지시). */
|
||||
@@ -217,6 +222,7 @@ export function hasComputedRange(type: StructureType | null): boolean {
|
||||
!!type &&
|
||||
!type.managed_by &&
|
||||
type.placement === "interval" &&
|
||||
!isRangeOnly(type) &&
|
||||
type.options.some((option) => option.key === "length_m" && isB05Option(option))
|
||||
);
|
||||
}
|
||||
|
||||
@@ -12,6 +12,7 @@ import type { StructureType } from "./B05_Profile_Api_Structures";
|
||||
import {
|
||||
createSpecForm,
|
||||
type SpecForm,
|
||||
type SpecFormHooks,
|
||||
type SpecLinks,
|
||||
} from "../A00_Common/design/design_structure_form";
|
||||
import { STRUCTURE_SPECS } from "../A00_Common/design/design_structure_pipe";
|
||||
@@ -29,8 +30,9 @@ export function createStructureSpecForm(
|
||||
optionRow: HTMLElement,
|
||||
links: SpecLinks,
|
||||
onChange: () => void,
|
||||
auto?: SpecFormHooks["auto"],
|
||||
): SpecForm {
|
||||
const form = createSpecForm(links, { onChange });
|
||||
const form = createSpecForm(links, { onChange, auto });
|
||||
form.root.hidden = true;
|
||||
forms.set(optionRow, form);
|
||||
const lock = (): void => {
|
||||
@@ -49,7 +51,7 @@ export function createStructureSpecForm(
|
||||
/** 정의 옵션 칸으로 안 그리는 키 — 명세 키 · 명세가 뺀 옛 키. */
|
||||
export function specOwnedKeys(type: StructureType | null): Set<string> {
|
||||
const spec = structureSpecOf(type);
|
||||
return new Set(spec ? [...specKeys(spec).keys, ...spec.retired] : []);
|
||||
return new Set(spec ? [...specKeys(spec).keys, ...spec.retired, ...(spec.dropped ?? [])] : []);
|
||||
}
|
||||
|
||||
/** 종류 · 값으로 명세 폼을 다시 그림(명세 없는 종류면 가림). */
|
||||
@@ -85,5 +87,5 @@ export function specRenderedKeys(
|
||||
if (!spec) return [];
|
||||
const { keys, prefixes } = specKeys(spec);
|
||||
const own = Object.keys(previous ?? {}).filter((key) => prefixes.some((p) => key.startsWith(p)));
|
||||
return [...keys, ...own];
|
||||
return [...keys, ...own, ...(spec.dropped ?? [])];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user