Files
Aislo/common_util/common_util_structure_station.ts
T
eomsangdonandClaude Opus 5.5 994b91636c feat(B05·B06): 구조물 · 관 기준 측점 정수 m · 일반 측점 1 m 안 붙기 · [정수 맞춤] 단추(234-1)
- 맞춤 규칙 한 벌 — common_util_structure_station(파이썬 · TS 짝 · 거울 시험)
- 입력 — 좌측 폼 칸(1 m 단계 · 친 값만) · 끌기 · 우클릭 · 방향키(1 m 걸음) · 배수유역도 관 · B06 관 옮김 · 추가
- 구간형 시작 · 끝도 정수 m · 일반 측점 = 횡단 상세를 읽을 때 등록
- 서버 자동 배치 · 노선 재투영 자리도 정수 m(확정본은 단추로만)
- [정수 맞춤] — 구조물 목록 머리 · 확인 창 · 관은 하나씩 폼 [수정] 길 · 계획고 편집 따라감 · 결과 n건 알림
- 찾는 폭 한 값 — 손으로 적은 0.51 을 PIPE_MATCH_M 으로
- 시험 — test_234_1 새로 · 1 m 걸음 · 정수 입력에 맞춘 기대값 고침(219_1 · station_roundtrip) · 헬퍼 대역 보탬

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01F3mdb91125mPoC6tpsQx4P
2026-10-10 19:05:52 +09:00

70 lines
2.9 KiB
TypeScript

/* =============================================================================
* common_util/common_util_structure_station.ts
* 구조물 · 관 기준 측점 = 정수 m · 일반 측점 1 m 안이면 그 측점에 붙음(234-1).
*
* 파이썬 짝 = `common_util/common_util_structure_station.py`(서버 자동 배치 · 노선 재투영).
* 거울 시험 = `resources/tester/test_234_1_structure_station.py`.
* 일반 측점 = 격자 · 시종점(구조물 측점 kind "irregular" 은 뺌) — 상세를 읽을 때 한 번 둔다.
* ========================================================================== */
/** 일반 측점에 붙는 폭(m) — 이 안이면 그 측점 값(끝 측점처럼 정수가 아니어도). */
export const GENERAL_SNAP_M = 1;
const EPS = 1e-6;
let general: number[] = [];
/** 일반 측점 목록을 둔다 — 횡단 상세를 읽을 때마다(B05 · B06 한 노선). */
export function setGeneralStations(
stations: ReadonlyArray<{ chainage_m: number; kind?: string }> | null | undefined,
): void {
general = (stations ?? [])
.filter((station) => station.kind !== "irregular")
.map((station) => station.chainage_m);
}
export const generalStations = (): readonly number[] => general;
function nearGeneral(value: number, stations: readonly number[]): number | null {
let best: number | null = null;
for (const station of stations) {
const gap = Math.abs(station - value);
if (gap < GENERAL_SNAP_M - EPS && (best === null || gap < Math.abs(best - value)))
best = station;
}
return best;
}
/** 기준 측점 맞춤 — 일반 측점 1 m 안이면 그 측점 · 아니면 정수 m(.5 는 올림) · 정수가 일반 측점
* 1 m 안이면 그 측점(끝 119.8 옆 119 → 119.8). 두 번 맞춰도 같다. */
export function snapStructureStation(
chainageM: number,
stations: readonly number[] = general,
): number {
if (!Number.isFinite(chainageM)) return chainageM;
const direct = nearGeneral(chainageM, stations);
if (direct !== null) return direct;
const whole = Math.floor(chainageM + 0.5);
return nearGeneral(whole, stations) ?? whole;
}
/** 방향키 한 걸음(1 m) — 붙기가 제자리로 되돌리면 한 걸음 더(끝 119.8 → 118). 노선 밖이면 제자리. */
export function stepStructureStation(
fromM: number,
direction: 1 | -1,
stations: readonly number[] = general,
): number {
const end = stations.length ? Math.max(...stations) : Infinity;
for (let steps = 1; steps <= 3; steps += 1) {
const next = snapStructureStation(fromM + direction * steps, stations);
if (next < 0 || next > end + EPS) return fromM;
if ((next - fromM) * direction > EPS) return next;
}
return fromM;
}
/** 이미 맞춘 값인가(정수 맞춤 단추가 옮길 것을 가름). */
export const isSnappedStation = (
chainageM: number,
stations: readonly number[] = general,
): boolean => Math.abs(snapStructureStation(chainageM, stations) - chainageM) < EPS;