feat(B05): 구조물 측점과 겹치는 규칙 측점 제거
구조물은 보조말뚝을 박아 그 자리가 정본 측점이 된다. 규칙 격자(20m)와 0.1m 안에서 만나면 세로선·라벨이 두 겹으로 겹쳐 읽히지 않았다. - 공용 유틸 dropStationsNear 추가(B05_Profile_Util_Station). - 종단 그래프와 3D 측점 띠가 같은 규칙을 쓴다 — 두 화면의 측점이 어긋나지 않는다. 검증: tsc --noEmit 통과, tmp/tests/test_b05_station_merge.mjs 통과. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { dropStationsNear } from "./B05_Profile_Util_Station";
|
||||
import { CURRENT_PROJECT_ID_KEY, ROUTES } from "@config/config_frontend";
|
||||
import { currentLanguageIndex, ui_locales } from "@ui/ui_template_locale";
|
||||
import { showToast } from "@ui/ui_template_elements";
|
||||
@@ -449,7 +450,9 @@ export async function renderB05Route(root: HTMLElement): Promise<void> {
|
||||
return best.elevation_m;
|
||||
};
|
||||
// 측점 바 양 끝 램프용 상단측: 사용자 변경분 → solve 자동 판정 순으로 적용.
|
||||
const withUphill = [...regular, ...injected].map((station) => {
|
||||
// 구조물 측점과 0.1m 안에서 겹치는 규칙 측점은 지운다 — 3D 측점 띠도 종단 그래프와
|
||||
// 같은 규칙을 써야 두 화면의 측점이 어긋나지 않는다(2026-09-06).
|
||||
const withUphill = [...dropStationsNear(regular, injected), ...injected].map((station) => {
|
||||
const design = designAt(station.chainage_m);
|
||||
return {
|
||||
...station,
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
* 거친다. 그래프·테이블·유토곡선이 같은 X 매핑을 쓰는 규칙은 그대로다.
|
||||
* ========================================================================== */
|
||||
|
||||
import { dropStationsNear } from "./B05_Profile_Util_Station";
|
||||
import {
|
||||
createLongitudinalProfile,
|
||||
longitudinalMinimumWidth,
|
||||
@@ -237,9 +238,13 @@ export function renderProfile(ctx: ProfileRenderContext): void {
|
||||
// 그대로 남는다(2026-08-02 사용자 보고).
|
||||
const regular = graphData.stations.filter((station) => station.kind !== "irregular");
|
||||
const injected = irregularGraphStations(irregularStations, maxChainageOf(longitudinal));
|
||||
// 구조물 측점과 0.1m 안에서 겹치는 규칙 측점은 지운다 — 세로선·라벨이 두 겹으로
|
||||
// 겹쳐 읽히지 않는다(2026-09-06). 남는 쪽은 구조물 측점이다.
|
||||
const graphLongitudinal = {
|
||||
...graphData,
|
||||
stations: [...regular, ...injected].sort((a, b) => a.chainage_m - b.chainage_m),
|
||||
stations: [...dropStationsNear(regular, injected), ...injected].sort(
|
||||
(a, b) => a.chainage_m - b.chainage_m,
|
||||
),
|
||||
};
|
||||
// 세로 자동 맞춤 — 지금 화면에 보이는 누가거리 구간만 보고 Y 창을 잡는다(2026-09-04
|
||||
// 사용자 확정). 가로 스크롤 위치(`scrollLeft`)와 본문 폭이 곧 보이는 구간이다.
|
||||
|
||||
@@ -52,3 +52,24 @@ export function parseStationText(text: string, intervalM: number): number | null
|
||||
const direct = Number(trimmed);
|
||||
return Number.isFinite(direct) && direct >= 0 ? direct : null;
|
||||
}
|
||||
|
||||
/** 구조물 측점과 겹쳤다고 볼 거리(m) — 이보다 가까우면 규칙 측점을 지운다. */
|
||||
export const STATION_MERGE_TOLERANCE_M = 0.1;
|
||||
|
||||
/**
|
||||
* 구조물 측점과 **겹치는 규칙 측점을 지운다**(2026-09-06).
|
||||
*
|
||||
* 구조물은 보조말뚝을 박아 그 자리가 정본 측점이 된다. 규칙 격자(20m)와 0.1m 안에서
|
||||
* 만나면 세로선·라벨이 두 겹으로 겹쳐 읽히지 않으므로 구조물 쪽만 남긴다.
|
||||
*/
|
||||
export function dropStationsNear<T extends { chainage_m: number }>(
|
||||
stations: readonly T[],
|
||||
anchors: ReadonlyArray<{ chainage_m: number }>,
|
||||
toleranceM: number = STATION_MERGE_TOLERANCE_M,
|
||||
): T[] {
|
||||
if (anchors.length === 0) return [...stations];
|
||||
return stations.filter(
|
||||
(station) =>
|
||||
!anchors.some((anchor) => Math.abs(anchor.chainage_m - station.chainage_m) <= toleranceM),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user