- 짝 `common_util_structure_attach.ts` attachShapes ↔ `B06_Section_Engine_Attach.py` attach_shapes — 열쇠 걷고 관 세트 → 벽 → 포장 → 맹암거 → 빈칸 경고(측점 계획 자리 · 「옹벽 높이」 · 「배관 관경」 · 「맹암거 암거 높이」 · 「물넘이포장 월류 높이」) - 서버 `_read_section_detail` · 재생성 응답 = attach_saved_shapes 하나 · 화면 `withDraftShapes`(현황 = 초안 ?? 저장분 · 초안 없어지면 저장분으로 한 번) — decorate 관 세트 · withDraftPipeKinds · 맹암거 · 포장 · 벽 블록 걷음 · 구조물 초안 없을 때 미리 뜬 횡단에 포장 · 벽 · 맹암거 빠지던 것 · 반폭 넓힘 뒤 날 상세(초안 빠짐) 고침 - 파이썬 얹기 = 목록 함수(culvert_sets_from · attach_culvert_specs · wall_specs_from · attach_wall_specs · underdrains_from · attach_underdrain_specs) + 옛 파일 함수는 감쌈 - 3D 지문 = SHAPE_KEYS(`common_util_structure_shape_keys.ts`) + 조작값 통째(손 해시 걷음 · 벽 기초 · 단 · 포장 · 맹암거 빠짐) · C군 벽 = 기준 측점과 가장 가까운 측점에서만 시작 ~ 끝 스윕(`wallSweepAt`) - 소단 = 표 형상 berm(BERM_TYPE_ID 걷음 · 화면 isBermType · 서버 catalog_row) - 시험: test_323_4_attach_mirror(42종 + 빈칸 · 서버 = 화면 · 옛 자리 걷힘 · 벽 한 번 · 지문) · 전수 표 ★ 둘(물넘이포장 걸친 격자 100 = 서버와 같음 · STAGE 4) · 옛 도움 파일 = 측점 → 형상 차례 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ji4nuyLVHcxrXWHTdb5nRD
125 lines
4.8 KiB
TypeScript
125 lines
4.8 KiB
TypeScript
/* =============================================================================
|
|
* common_util/common_util_structure_attach.ts
|
|
* 형상 얹기 한 벌(323-4) — 측점(횡단) + 현황(관 · 구조물) + 구조물 표 → 그 측점 그림 자료.
|
|
*
|
|
* 구조물 열쇠(`SHAPE_KEYS` · 빈칸 경고 `blank`)를 걷고 서버와 같은 차례로 다시 얹음 — 관 세트 → 벽 →
|
|
* 포장 → 맹암거 → 빈칸 경고. 고르기 = 표 형상(322-1). 화면은 초안 ?? 저장분 현황으로 이것 하나를 씀
|
|
* (`B06_Section_Section_Drafts.withDraftShapes`) — 저장 전 그림 = 저장 뒤 그림.
|
|
* 파이썬 짝 = `B06_Section/B06_Section_Engine_Attach.py` `attach_shapes`(서버 상세 읽기 · 재생성 응답) ·
|
|
* 거울 시험 = `resources/tester/test_323_4_attach_mirror.py`.
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
attachCulvertSets,
|
|
buildCulvertSets,
|
|
registryDefaults,
|
|
type CulvertPipePoint,
|
|
} from "./common_util_culvert_sets";
|
|
import {
|
|
attachWallSpecs,
|
|
wallSpecsFrom,
|
|
type WallStructureInput,
|
|
} from "./common_util_structure_walls";
|
|
import {
|
|
attachPavementSpecs,
|
|
pavementSpecsFrom,
|
|
type PavementStructureInput,
|
|
} from "./common_util_structure_pavement";
|
|
import {
|
|
attachUnderdrainSpecs,
|
|
underdrainSpecsFrom,
|
|
type UnderdrainInput,
|
|
} from "./common_util_structure_underdrain";
|
|
import { catalogRow, fieldName } from "./common_util_structure_catalog";
|
|
import {
|
|
blankKeys,
|
|
planStations,
|
|
SAME_STATION_M,
|
|
type PlanPipe,
|
|
type PlanStructure,
|
|
type PlanType,
|
|
} from "./common_util_structure_station";
|
|
import { SHAPE_KEYS } from "./common_util_structure_shape_keys";
|
|
|
|
export { SHAPE_KEYS };
|
|
|
|
export interface AttachType extends PlanType {
|
|
name: string;
|
|
options: ReadonlyArray<{ key: string; label?: string; default: unknown }>;
|
|
}
|
|
|
|
/** 빈 필수 칸 → 「종류 이름 칸 이름」(칸 이름 = 그 종류 정의 → 다른 종류 정의 → 부품 상자 → 키). */
|
|
function blankLabels(
|
|
typeId: string,
|
|
options: Record<string, unknown> | null | undefined,
|
|
types: ReadonlyArray<AttachType>,
|
|
): string[] {
|
|
const name = catalogRow(typeId)?.name ?? typeId;
|
|
const ordered = [...types.filter((t) => t.type_id === typeId), ...types];
|
|
return blankKeys(typeId, options).map((key) => {
|
|
const option = ordered.flatMap((t) => t.options).find((o) => o.key === key);
|
|
return `${name} ${option?.label ?? fieldName(key) ?? key}`;
|
|
});
|
|
}
|
|
|
|
/** 빈칸 경고 — 측점 계획 자리마다 덮는 관 · 구조물의 빈 필수 칸(파이썬 `_attach_blanks` 짝). */
|
|
function attachBlanks(
|
|
sections: Array<Record<string, unknown>>,
|
|
pipes: ReadonlyArray<PlanPipe>,
|
|
structures: ReadonlyArray<PlanStructure>,
|
|
types: ReadonlyArray<AttachType>,
|
|
): void {
|
|
const owners = new Map<string, [string, Record<string, unknown> | null | undefined]>();
|
|
for (const pipe of pipes)
|
|
owners.set(pipe.id ?? `pipe-${pipe.chainage_m.toFixed(2)}`, [
|
|
pipe.facility ?? "pipe",
|
|
pipe.options,
|
|
]);
|
|
for (const item of structures)
|
|
if (item.structure_id) owners.set(item.structure_id, [item.type_id, item.options]);
|
|
for (const station of planStations(pipes, structures, types)) {
|
|
if (!station.blank.length) continue;
|
|
const labels = [
|
|
...new Set(
|
|
station.owners.flatMap((owner) => {
|
|
const hit = owners.get(owner);
|
|
return hit ? blankLabels(hit[0], hit[1], types) : [];
|
|
}),
|
|
),
|
|
];
|
|
for (const section of sections)
|
|
if (Math.abs(Number(section.chainage_m) - station.chainage_m) < SAME_STATION_M)
|
|
section.blank = labels;
|
|
}
|
|
}
|
|
|
|
/** 측점마다 그림 자료를 걷고 현황으로 다시 얹음(파이썬 `attach_shapes` 짝 · 제자리 고침). */
|
|
export function attachShapes(
|
|
sections: Array<Record<string, unknown>>,
|
|
pipes: ReadonlyArray<PlanPipe>,
|
|
structures: ReadonlyArray<PlanStructure>,
|
|
types: ReadonlyArray<AttachType>,
|
|
): void {
|
|
for (const section of sections) for (const key of [...SHAPE_KEYS, "blank"]) delete section[key];
|
|
const registry = registryDefaults(types);
|
|
attachCulvertSets(sections, buildCulvertSets(pipes as readonly CulvertPipePoint[], registry));
|
|
const shaped = (shape: string) => types.filter((t) => catalogRow(t.type_id)?.shape === shape);
|
|
// 관 세트가 선 측점은 벽을 안 얹음(`attachWallSpecs`) — 차례 = 서버와 같음
|
|
attachWallSpecs(
|
|
sections,
|
|
wallSpecsFrom(
|
|
structures as unknown as WallStructureInput[],
|
|
new Map(shaped("wall").map((t) => [t.type_id, t.name] as const)),
|
|
),
|
|
);
|
|
attachPavementSpecs(
|
|
sections,
|
|
pavementSpecsFrom(
|
|
structures as unknown as PavementStructureInput[],
|
|
new Set(shaped("pavement").map((t) => t.type_id)),
|
|
),
|
|
);
|
|
attachUnderdrainSpecs(sections, underdrainSpecsFrom(structures as UnderdrainInput[]));
|
|
attachBlanks(sections, pipes, structures, types);
|
|
}
|