feat(측점열쇠): 346-2 덧 2 열쇠 한 벌 — 구간형 :start · :end · 묶음 측점 종류(grid · end) · 같은 열쇠 둘째 규칙 공용
- common_util_station_key(ts · py 짝): role 덧붙임(구간형 시작 · 끝 = structure:<id>:start · :end · 기준은 structure:<id> 그대로) · grid(원래 격자 번호) · end(BP/EP) 종류 · dedupeStationKeys(같은 열쇠 둘째부터 at:<누가거리>) - B06 stationKeysOf 가 같은 규칙(측점 계획 · 구조물 목록의 시작 · 끝 자리 · 공용 dedupe) - 거울 시험에 새 갈래(구간형 · grid · end · dedupe) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QfHKQs7J3hQELKMWQMUJEy
This commit is contained in:
@@ -18,7 +18,13 @@
|
|||||||
import { readState, writeState } from "../A00_Common/b_page_state";
|
import { readState, writeState } from "../A00_Common/b_page_state";
|
||||||
import { pipeIdAt } from "../A00_Common/design/design_pipe_ids";
|
import { pipeIdAt } from "../A00_Common/design/design_pipe_ids";
|
||||||
import { showToast } from "@ui/ui_template_elements";
|
import { showToast } from "@ui/ui_template_elements";
|
||||||
import { chainageKey, looseChainage, stationKey } from "@util/common_util_station_key";
|
import {
|
||||||
|
chainageKey,
|
||||||
|
dedupeStationKeys,
|
||||||
|
looseChainage,
|
||||||
|
stationKey,
|
||||||
|
type StationKeyRole,
|
||||||
|
} from "@util/common_util_station_key";
|
||||||
import { inferStationInterval } from "@util/common_util_svg";
|
import { inferStationInterval } from "@util/common_util_svg";
|
||||||
import type { CrossSection, SectionDetailResponse } from "./B06_Section_Api_Fetch";
|
import type { CrossSection, SectionDetailResponse } from "./B06_Section_Api_Fetch";
|
||||||
|
|
||||||
@@ -46,7 +52,8 @@ type Raw = Record<string, unknown> & { [HINT]?: Record<string, number> };
|
|||||||
|
|
||||||
const lists = new Map<string, Keyed[]>();
|
const lists = new Map<string, Keyed[]>();
|
||||||
/** 프로젝트마다 구조물 측점 → id(측점 계획 · 구조물 목록). */
|
/** 프로젝트마다 구조물 측점 → id(측점 계획 · 구조물 목록). */
|
||||||
const owners = new Map<string, Array<{ id: string; kind: "pipe" | "structure"; at: number }>>();
|
type Owner = { id: string; kind: "pipe" | "structure"; at: number; role: StationKeyRole };
|
||||||
|
const owners = new Map<string, Owner[]>();
|
||||||
let current: { projectId: string; routeId: number } | null = null;
|
let current: { projectId: string; routeId: number } | null = null;
|
||||||
|
|
||||||
const scopeOf = (projectId: string, routeId: number): string => `${projectId}:${routeId}`;
|
const scopeOf = (projectId: string, routeId: number): string => `${projectId}:${routeId}`;
|
||||||
@@ -54,7 +61,7 @@ const scopeOf = (projectId: string, routeId: number): string => `${projectId}:${
|
|||||||
/** 측점 계획(초안 · `planStations`)이 낸 덮는 구조물 id — 관 세션 id 는 `pipe-` 머리. */
|
/** 측점 계획(초안 · `planStations`)이 낸 덮는 구조물 id — 관 세션 id 는 `pipe-` 머리. */
|
||||||
export function useStationOwners(
|
export function useStationOwners(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
planned: ReadonlyArray<{ chainage_m: number; owners: string[] }>,
|
planned: ReadonlyArray<{ chainage_m: number; owners: string[]; role?: StationKeyRole }>,
|
||||||
): void {
|
): void {
|
||||||
owners.set(
|
owners.set(
|
||||||
projectId,
|
projectId,
|
||||||
@@ -63,6 +70,7 @@ export function useStationOwners(
|
|||||||
id,
|
id,
|
||||||
kind: id.startsWith("pipe-") ? ("pipe" as const) : ("structure" as const),
|
kind: id.startsWith("pipe-") ? ("pipe" as const) : ("structure" as const),
|
||||||
at: station.chainage_m,
|
at: station.chainage_m,
|
||||||
|
role: station.role ?? "anchor",
|
||||||
})),
|
})),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@@ -71,12 +79,25 @@ export function useStationOwners(
|
|||||||
/** 구조물 목록(횡단 보기) — 한 자리 구조물의 id. 관 자리는 관 장부가 정함. */
|
/** 구조물 목록(횡단 보기) — 한 자리 구조물의 id. 관 자리는 관 장부가 정함. */
|
||||||
export function useStructureIds(
|
export function useStructureIds(
|
||||||
projectId: string,
|
projectId: string,
|
||||||
structures: ReadonlyArray<{ structure_id?: string | null; chainage_m?: number | null }>,
|
structures: ReadonlyArray<{
|
||||||
|
structure_id?: string | null;
|
||||||
|
chainage_m?: number | null;
|
||||||
|
start_m?: number | null;
|
||||||
|
end_m?: number | null;
|
||||||
|
}>,
|
||||||
): void {
|
): void {
|
||||||
const known = (owners.get(projectId) ?? []).filter((owner) => owner.kind === "pipe");
|
const known = (owners.get(projectId) ?? []).filter((owner) => owner.kind === "pipe");
|
||||||
for (const item of structures) {
|
for (const item of structures) {
|
||||||
if (item.structure_id && typeof item.chainage_m === "number")
|
const id = item.structure_id;
|
||||||
known.push({ id: item.structure_id, kind: "structure", at: item.chainage_m });
|
if (!id) continue;
|
||||||
|
// 기준 측점 = structure:<id> · 구간형 시작 · 끝 = :start · :end(열쇠 한 벌 · common_util_station_key)
|
||||||
|
const marks: Array<[StationKeyRole, number | null | undefined]> = [
|
||||||
|
["anchor", item.chainage_m],
|
||||||
|
["start", item.start_m],
|
||||||
|
["end", item.end_m],
|
||||||
|
];
|
||||||
|
for (const [role, at] of marks)
|
||||||
|
if (typeof at === "number") known.push({ id, kind: "structure", at, role });
|
||||||
}
|
}
|
||||||
owners.set(projectId, known);
|
owners.set(projectId, known);
|
||||||
}
|
}
|
||||||
@@ -84,20 +105,19 @@ export function useStructureIds(
|
|||||||
const looksLikePipe = (section: CrossSection): boolean =>
|
const looksLikePipe = (section: CrossSection): boolean =>
|
||||||
Boolean(section.culvert || section.box) || /^.+ D\d+/.test(section.structure ?? "");
|
Boolean(section.culvert || section.box) || /^.+ D\d+/.test(section.structure ?? "");
|
||||||
|
|
||||||
/** 측점 목록 → 열쇠(같은 열쇠가 둘이면 뒤엣것은 `at:`). */
|
/** 측점 목록 → 열쇠(같은 열쇠가 둘이면 뒤엣것은 `at:` · `dedupeStationKeys`). */
|
||||||
export function stationKeysOf(
|
export function stationKeysOf(
|
||||||
projectId: string | null,
|
projectId: string | null,
|
||||||
sections: ReadonlyArray<CrossSection>,
|
sections: ReadonlyArray<CrossSection>,
|
||||||
intervalM: number | null,
|
intervalM: number | null,
|
||||||
): Keyed[] {
|
): Keyed[] {
|
||||||
const known = projectId ? (owners.get(projectId) ?? []) : [];
|
const known = projectId ? (owners.get(projectId) ?? []) : [];
|
||||||
const seen = new Set<string>();
|
const keys = sections.map((section) => {
|
||||||
return sections.map((section) => {
|
|
||||||
const at = section.chainage_m;
|
const at = section.chainage_m;
|
||||||
let key: string;
|
let key: string;
|
||||||
if (section.kind === "irregular") {
|
if (section.kind === "irregular") {
|
||||||
const owner = known.find((entry) => Math.abs(entry.at - at) < NEAR_M);
|
const owner = known.find((entry) => Math.abs(entry.at - at) < NEAR_M);
|
||||||
if (owner) key = stationKey("irregular", at, intervalM, owner.id, owner.kind);
|
if (owner) key = stationKey("irregular", at, intervalM, owner.id, owner.kind, owner.role);
|
||||||
else if (looksLikePipe(section))
|
else if (looksLikePipe(section))
|
||||||
key = stationKey("pipe", at, intervalM, pipeIdAt(at, projectId));
|
key = stationKey("pipe", at, intervalM, pipeIdAt(at, projectId));
|
||||||
else
|
else
|
||||||
@@ -105,10 +125,10 @@ export function stationKeysOf(
|
|||||||
? stationKey("regular", at, intervalM)
|
? stationKey("regular", at, intervalM)
|
||||||
: stationKey("irregular", at, intervalM);
|
: stationKey("irregular", at, intervalM);
|
||||||
} else key = stationKey(section.kind, at, intervalM);
|
} else key = stationKey(section.kind, at, intervalM);
|
||||||
if (seen.has(key)) key = `at:${chainageKey(at)}`;
|
return key;
|
||||||
seen.add(key);
|
|
||||||
return { key, chainageM: at };
|
|
||||||
});
|
});
|
||||||
|
const chainages = sections.map((section) => section.chainage_m);
|
||||||
|
return dedupeStationKeys(keys, chainages).map((key, i) => ({ key, chainageM: chainages[i] }));
|
||||||
}
|
}
|
||||||
|
|
||||||
type KeyedDetail = Pick<SectionDetailResponse, "cross_sections" | "longitudinal">;
|
type KeyedDetail = Pick<SectionDetailResponse, "cross_sections" | "longitudinal">;
|
||||||
|
|||||||
@@ -2,6 +2,8 @@
|
|||||||
|
|
||||||
일반 = ``grid:k``(누가거리 ÷ 측점 간격 반올림) · 관 = ``pipe:<id>`` · 구조물 = ``structure:<id>`` ·
|
일반 = ``grid:k``(누가거리 ÷ 측점 간격 반올림) · 관 = ``pipe:<id>`` · 구조물 = ``structure:<id>`` ·
|
||||||
시종점 = ``end:BP`` · ``end:EP`` · id 를 모르는 구조물 측점 = ``at:<누가거리 0.01 m>``.
|
시종점 = ``end:BP`` · ``end:EP`` · id 를 모르는 구조물 측점 = ``at:<누가거리 0.01 m>``.
|
||||||
|
구간형 구조물 시작 · 끝 측점 = ``structure:<id>:start`` · ``:end``(기준 측점은 ``structure:<id>``).
|
||||||
|
한 목록에 같은 열쇠가 둘이면 둘째부터 ``at:<누가거리>``(``dedupe_station_keys``).
|
||||||
|
|
||||||
⚠ 파이썬·TS 짝 — ``common_util_station_key.ts`` ``stationKey`` ↔ ``station_key``.
|
⚠ 파이썬·TS 짝 — ``common_util_station_key.ts`` ``stationKey`` ↔ ``station_key``.
|
||||||
한쪽을 고치면 다른 쪽도 고치고 거울 시험 ``resources/tester/test_344_3_station_key_mirror.py``.
|
한쪽을 고치면 다른 쪽도 고치고 거울 시험 ``resources/tester/test_344_3_station_key_mirror.py``.
|
||||||
@@ -31,19 +33,43 @@ def station_key(
|
|||||||
interval_m: float | None,
|
interval_m: float | None,
|
||||||
station_id: str | None = None,
|
station_id: str | None = None,
|
||||||
id_kind: str = "structure",
|
id_kind: str = "structure",
|
||||||
|
role: str = "anchor",
|
||||||
) -> str:
|
) -> str:
|
||||||
"""측점 열쇠 — irregular 는 id 가 있으면 pipe: · structure:(``id_kind``) · 없으면 at:."""
|
"""측점 열쇠 — irregular 는 id 가 있으면 pipe: · structure:(``id_kind``) · 없으면 at:.
|
||||||
|
|
||||||
|
구간형 시작 · 끝은 ``role`` 로 ``:start`` · ``:end``. ``grid`` · ``end`` 는 ``station_id`` 에
|
||||||
|
원래 격자 번호 · BP/EP(없으면 누가거리 ÷ 간격 반올림 · 0 이면 BP).
|
||||||
|
"""
|
||||||
|
loose = f"at:{chainage_key(chainage_m)}"
|
||||||
|
suffix = "" if role == "anchor" else f":{role}"
|
||||||
if kind == "bp":
|
if kind == "bp":
|
||||||
return "end:BP"
|
return "end:BP"
|
||||||
if kind == "ep":
|
if kind == "ep":
|
||||||
return "end:EP"
|
return "end:EP"
|
||||||
|
if kind == "end":
|
||||||
|
return (
|
||||||
|
f"end:{station_id if station_id is not None else ('BP' if chainage_m <= 0 else 'EP')}"
|
||||||
|
)
|
||||||
if kind in ("pipe", "structure"):
|
if kind in ("pipe", "structure"):
|
||||||
return f"{kind}:{station_id}" if station_id else f"at:{chainage_key(chainage_m)}"
|
return f"{kind}:{station_id}{suffix}" if station_id else loose
|
||||||
if kind == "irregular":
|
if kind == "irregular":
|
||||||
return f"{id_kind}:{station_id}" if station_id else f"at:{chainage_key(chainage_m)}"
|
return f"{id_kind}:{station_id}{suffix}" if station_id else loose
|
||||||
|
if kind == "grid" and station_id is not None:
|
||||||
|
return f"grid:{station_id}"
|
||||||
if interval_m and interval_m > 0:
|
if interval_m and interval_m > 0:
|
||||||
return f"grid:{_half_up(chainage_m / interval_m)}"
|
return f"grid:{_half_up(chainage_m / interval_m)}"
|
||||||
return f"at:{chainage_key(chainage_m)}"
|
return loose
|
||||||
|
|
||||||
|
|
||||||
|
def dedupe_station_keys(keys: list[str], chainages: list[float]) -> list[str]:
|
||||||
|
"""한 목록에 같은 열쇠가 둘이면 둘째부터 ``at:<누가거리>`` — 열쇠마다 측점 하나."""
|
||||||
|
seen: set[str] = set()
|
||||||
|
out: list[str] = []
|
||||||
|
for key, chainage in zip(keys, chainages, strict=True):
|
||||||
|
unique = f"at:{chainage_key(chainage)}" if key in seen else key
|
||||||
|
seen.add(unique)
|
||||||
|
out.append(unique)
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
def loose_chainage(key: str) -> float | None:
|
def loose_chainage(key: str) -> float | None:
|
||||||
|
|||||||
@@ -3,21 +3,29 @@
|
|||||||
* 측점 열쇠 한 규칙(PLAN 344-3) — 노선이 바뀌어도 같은 측점을 같은 이름으로 부름.
|
* 측점 열쇠 한 규칙(PLAN 344-3) — 노선이 바뀌어도 같은 측점을 같은 이름으로 부름.
|
||||||
* 일반 = `grid:k`(누가거리 ÷ 측점 간격 반올림) · 관 = `pipe:<id>` · 구조물 = `structure:<id>` ·
|
* 일반 = `grid:k`(누가거리 ÷ 측점 간격 반올림) · 관 = `pipe:<id>` · 구조물 = `structure:<id>` ·
|
||||||
* 시종점 = `end:BP` · `end:EP` · id 를 모르는 구조물 측점 = `at:<누가거리 0.01 m>`(옛 초안 열쇠와 같은 몫).
|
* 시종점 = `end:BP` · `end:EP` · id 를 모르는 구조물 측점 = `at:<누가거리 0.01 m>`(옛 초안 열쇠와 같은 몫).
|
||||||
|
* 구간형 구조물의 시작 · 끝 측점 = `structure:<id>:start` · `:end`(기준 측점은 `structure:<id>` 그대로).
|
||||||
|
* 한 목록에 같은 열쇠가 둘이면 둘째부터 `at:<누가거리>`(`dedupeStationKeys`).
|
||||||
|
* 쓰는 곳 = 서버 `B05_Profile_Route_Save_Parts` · 묶음 stations 단계 · B06 세션 횡단 초안(`stationKeysOf`).
|
||||||
*
|
*
|
||||||
* ⚠ 파이썬·TS 짝 — `common_util_station_key.py` `station_key` ↔ `stationKey`. 한쪽을 고치면 다른 쪽도
|
* ⚠ 파이썬·TS 짝 — `common_util_station_key.py` `station_key` ↔ `stationKey`. 한쪽을 고치면 다른 쪽도
|
||||||
* 고치고 거울 시험 `resources/tester/test_344_3_station_key_mirror.py`.
|
* 고치고 거울 시험 `resources/tester/test_344_3_station_key_mirror.py`.
|
||||||
* ========================================================================== */
|
* ========================================================================== */
|
||||||
|
|
||||||
/** 측점 종류 — 서버 측점 `kind`(bp · ep · regular · irregular) 그대로 받음. */
|
/** 측점 종류 — 서버 측점 `kind`(bp · ep · regular · irregular) · 묶음 측점 `kind`(grid · end · pipe · structure). */
|
||||||
export type StationKeyKind = "bp" | "ep" | "regular" | "irregular" | "pipe" | "structure";
|
export type StationKeyKind =
|
||||||
|
"bp" | "ep" | "regular" | "irregular" | "grid" | "end" | "pipe" | "structure";
|
||||||
|
|
||||||
|
/** 구간형 구조물 측점 자리 — 기준(anchor) · 시작 · 끝. */
|
||||||
|
export type StationKeyRole = "anchor" | "start" | "end";
|
||||||
|
|
||||||
/** 누가거리 0.01 m — 옛 초안 열쇠(`toFixed(2)`)와 같은 자릿수. */
|
/** 누가거리 0.01 m — 옛 초안 열쇠(`toFixed(2)`)와 같은 자릿수. */
|
||||||
export const chainageKey = (chainageM: number): string =>
|
export const chainageKey = (chainageM: number): string =>
|
||||||
(Math.round(chainageM * 100) / 100).toFixed(2);
|
(Math.round(chainageM * 100) / 100).toFixed(2);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 측점 열쇠. irregular 는 id 가 있으면 `pipe:` · `structure:`(종류는 `idKind`) · 없으면 `at:`.
|
* 측점 열쇠. irregular 는 id 가 있으면 `pipe:` · `structure:`(종류는 `idKind`) · 없으면 `at:` · 구간형 시작 · 끝은
|
||||||
* 간격이 없거나 0 이하면 일반 측점도 `at:`.
|
* `role` 로 `:start` · `:end` 덧붙임. `grid` · `end` 는 `id` 에 원래 격자 번호 · `BP`/`EP` 를 줄 수 있음(없으면
|
||||||
|
* 누가거리 ÷ 간격 반올림 · 0 이면 BP). 간격이 없거나 0 이하면 일반 측점도 `at:`.
|
||||||
*/
|
*/
|
||||||
export function stationKey(
|
export function stationKey(
|
||||||
kind: StationKeyKind,
|
kind: StationKeyKind,
|
||||||
@@ -25,14 +33,31 @@ export function stationKey(
|
|||||||
intervalM: number | null,
|
intervalM: number | null,
|
||||||
id: string | null = null,
|
id: string | null = null,
|
||||||
idKind: "pipe" | "structure" = "structure",
|
idKind: "pipe" | "structure" = "structure",
|
||||||
|
role: StationKeyRole = "anchor",
|
||||||
): string {
|
): string {
|
||||||
|
const loose = `at:${chainageKey(chainageM)}`;
|
||||||
|
const suffix = role === "anchor" ? "" : `:${role}`;
|
||||||
if (kind === "bp") return "end:BP";
|
if (kind === "bp") return "end:BP";
|
||||||
if (kind === "ep") return "end:EP";
|
if (kind === "ep") return "end:EP";
|
||||||
if (kind === "pipe" || kind === "structure")
|
if (kind === "end") return `end:${id ?? (chainageM <= 0 ? "BP" : "EP")}`;
|
||||||
return id ? `${kind}:${id}` : `at:${chainageKey(chainageM)}`;
|
if (kind === "pipe" || kind === "structure") return id ? `${kind}:${id}${suffix}` : loose;
|
||||||
if (kind === "irregular") return id ? `${idKind}:${id}` : `at:${chainageKey(chainageM)}`;
|
if (kind === "irregular") return id ? `${idKind}:${id}${suffix}` : loose;
|
||||||
|
if (kind === "grid" && id !== null) return `grid:${id}`;
|
||||||
if (intervalM && intervalM > 0) return `grid:${Math.round(chainageM / intervalM)}`;
|
if (intervalM && intervalM > 0) return `grid:${Math.round(chainageM / intervalM)}`;
|
||||||
return `at:${chainageKey(chainageM)}`;
|
return loose;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 한 목록에 같은 열쇠가 둘이면 둘째부터 `at:<누가거리>` — 열쇠마다 측점 하나. */
|
||||||
|
export function dedupeStationKeys(
|
||||||
|
keys: ReadonlyArray<string>,
|
||||||
|
chainages: ReadonlyArray<number>,
|
||||||
|
): string[] {
|
||||||
|
const seen = new Set<string>();
|
||||||
|
return keys.map((key, index) => {
|
||||||
|
const unique = seen.has(key) ? `at:${chainageKey(chainages[index])}` : key;
|
||||||
|
seen.add(unique);
|
||||||
|
return unique;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 옛 초안 열쇠(누가거리 글 `"85.05"`) · `at:` 열쇠의 누가거리 — 측점 열쇠면 null. */
|
/** 옛 초안 열쇠(누가거리 글 `"85.05"`) · `at:` 열쇠의 누가거리 — 측점 열쇠면 null. */
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ if str(PROJECT_ROOT) not in sys.path:
|
|||||||
|
|
||||||
from common_util.common_util_station_key import ( # noqa: E402
|
from common_util.common_util_station_key import ( # noqa: E402
|
||||||
chainage_key,
|
chainage_key,
|
||||||
|
dedupe_station_keys,
|
||||||
loose_chainage,
|
loose_chainage,
|
||||||
station_key,
|
station_key,
|
||||||
)
|
)
|
||||||
@@ -24,7 +25,17 @@ TS = PROJECT_ROOT / "common_util" / "common_util_station_key.ts"
|
|||||||
TYPESCRIPT = PROJECT_ROOT / "config" / "node_modules" / "typescript"
|
TYPESCRIPT = PROJECT_ROOT / "config" / "node_modules" / "typescript"
|
||||||
|
|
||||||
CASES = [
|
CASES = [
|
||||||
("bp", 0.0, 20.0, None, "structure"),
|
("bp", 0.0, 20.0, None, "structure", "anchor"),
|
||||||
|
# 5파 — 묶음 측점 종류(grid · end) · 구간형 시작 · 끝(:start · :end)
|
||||||
|
("grid", 41.3, 20.0, "2", "structure", "anchor"),
|
||||||
|
("grid", 41.3, 20.0, None, "structure", "anchor"),
|
||||||
|
("end", 0.0, 20.0, None, "structure", "anchor"),
|
||||||
|
("end", 99.0, 20.0, None, "structure", "anchor"),
|
||||||
|
("end", 99.0, 20.0, "EP", "structure", "anchor"),
|
||||||
|
("structure", 30.0, 20.0, "st-9", "structure", "start"),
|
||||||
|
("structure", 36.0, 20.0, "st-9", "structure", "end"),
|
||||||
|
("irregular", 30.0, 20.0, "st-9", "structure", "start"),
|
||||||
|
("pipe", 30.0, 20.0, None, "structure", "end"),
|
||||||
("ep", 812.345, 20.0, None, "structure"),
|
("ep", 812.345, 20.0, None, "structure"),
|
||||||
("regular", 40.0, 20.0, None, "structure"),
|
("regular", 40.0, 20.0, None, "structure"),
|
||||||
("regular", 50.0, 20.0, None, "structure"), # 2.5 → 3(위로)
|
("regular", 50.0, 20.0, None, "structure"), # 2.5 → 3(위로)
|
||||||
@@ -37,6 +48,7 @@ CASES = [
|
|||||||
("pipe", 12.344, 20.0, "pipe-s1", "structure"),
|
("pipe", 12.344, 20.0, "pipe-s1", "structure"),
|
||||||
("structure", 12.345, 20.0, None, "structure"),
|
("structure", 12.345, 20.0, None, "structure"),
|
||||||
]
|
]
|
||||||
|
DEDUPE = (["grid:1", "structure:st-1", "grid:1", "structure:st-1"], [20.0, 25.0, 20.004, 25.006])
|
||||||
LOOSE = ["85.05", "at:85.05", "grid:4", "pipe:pipe-s3", "-1.5", "end:BP"]
|
LOOSE = ["85.05", "at:85.05", "grid:4", "pipe:pipe-s3", "-1.5", "end:BP"]
|
||||||
|
|
||||||
SCRIPT = r"""
|
SCRIPT = r"""
|
||||||
@@ -50,7 +62,8 @@ new Function("exports", "module", js)(box.exports, box);
|
|||||||
const m = box.exports;
|
const m = box.exports;
|
||||||
const input = JSON.parse(process.argv[3]);
|
const input = JSON.parse(process.argv[3]);
|
||||||
process.stdout.write(JSON.stringify({
|
process.stdout.write(JSON.stringify({
|
||||||
keys: input.cases.map((c) => m.stationKey(c[0], c[1], c[2], c[3], c[4])),
|
keys: input.cases.map((c) => m.stationKey(c[0], c[1], c[2], c[3], c[4], c[5] ?? "anchor")),
|
||||||
|
dedupe: m.dedupeStationKeys(input.dedupe[0], input.dedupe[1]),
|
||||||
chainage: input.cases.map((c) => m.chainageKey(c[1])),
|
chainage: input.cases.map((c) => m.chainageKey(c[1])),
|
||||||
loose: input.loose.map((k) => m.looseChainage(k)),
|
loose: input.loose.map((k) => m.looseChainage(k)),
|
||||||
}));
|
}));
|
||||||
@@ -65,7 +78,7 @@ def test_파이썬과_TS_열쇠_같음():
|
|||||||
SCRIPT,
|
SCRIPT,
|
||||||
str(TYPESCRIPT),
|
str(TYPESCRIPT),
|
||||||
str(TS),
|
str(TS),
|
||||||
json.dumps({"cases": CASES, "loose": LOOSE}),
|
json.dumps({"cases": CASES, "loose": LOOSE, "dedupe": DEDUPE}),
|
||||||
],
|
],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True,
|
text=True,
|
||||||
@@ -77,6 +90,7 @@ def test_파이썬과_TS_열쇠_같음():
|
|||||||
assert out["keys"] == [station_key(*case) for case in CASES]
|
assert out["keys"] == [station_key(*case) for case in CASES]
|
||||||
assert out["chainage"] == [chainage_key(case[1]) for case in CASES]
|
assert out["chainage"] == [chainage_key(case[1]) for case in CASES]
|
||||||
assert out["loose"] == [loose_chainage(key) for key in LOOSE]
|
assert out["loose"] == [loose_chainage(key) for key in LOOSE]
|
||||||
|
assert out["dedupe"] == dedupe_station_keys(*DEDUPE)
|
||||||
|
|
||||||
|
|
||||||
def test_열쇠_규칙():
|
def test_열쇠_규칙():
|
||||||
@@ -86,3 +100,9 @@ def test_열쇠_규칙():
|
|||||||
assert station_key("irregular", 85.054, 20.0, "pipe-s3", "pipe") == "pipe:pipe-s3"
|
assert station_key("irregular", 85.054, 20.0, "pipe-s3", "pipe") == "pipe:pipe-s3"
|
||||||
assert station_key("irregular", 85.054, 20.0) == "at:85.05"
|
assert station_key("irregular", 85.054, 20.0) == "at:85.05"
|
||||||
assert loose_chainage("85.05") == 85.05 and loose_chainage("grid:4") is None
|
assert loose_chainage("85.05") == 85.05 and loose_chainage("grid:4") is None
|
||||||
|
# 5파 — 구간형 시작 · 끝 · 기준은 그대로 · 원래 격자 번호 · 같은 열쇠 둘째는 at:
|
||||||
|
assert station_key("structure", 30.0, 20.0, "st-9", role="start") == "structure:st-9:start"
|
||||||
|
assert station_key("structure", 33.0, 20.0, "st-9") == "structure:st-9"
|
||||||
|
assert station_key("grid", 41.3, 20.0, "2") == "grid:2"
|
||||||
|
assert station_key("end", 99.0, 20.0) == "end:EP"
|
||||||
|
assert dedupe_station_keys(*DEDUPE) == ["grid:1", "structure:st-1", "at:20.00", "at:25.01"]
|
||||||
|
|||||||
Reference in New Issue
Block a user