fix(B05): 구조물 측점 계획고 편집이 가짜 변화점을 만들던 것 — 정본 누가거리 일원화
사용자 보고(2026-09-04) — 배수관 2 자리에서 계획선이 수직으로 꺾이고 최대 기울기가 **155,791 %**. 원인은 「가까운 점」이 아니라 **한 구조물이 층마다 다른 누가거리를 든 것**: 횡단 측점 264.054626 · 종단 정본 변화점 264.055 · 배수 정본 파일 **264.06**(cm 반올림). 사이드 목록이 든 264.06 으로 계획고를 편집하면 정본 옆 5mm 자리에 변화점이 하나 더 서고, 둘 사이 종단곡선이 mm 로 쭈그러들어 기울기가 거리 0 에 가까운 값으로 나뉘었음. 2026-09-03 에 ▲▼ 버튼 경로만 막아 뒀고(같은 증상 11,858%), 측점 테이블·도구 경로가 남아 다시 터진 것. - **저장**(`common_util_drainage_pipes.py`) — 누가거리를 좌표(x·y)와 같은 **밀리미터 기준**으로 남김(cm 반올림 제거). 종단 정본 변화점(3자리)과 값이 어긋나지 않음. - **화면**(`_UI_Profile_Panel.ts`) — 구조물 측점 목록이 들어오는 **한 자리**에서 종단 정본 측점(0.1m 안)으로 누가거리를 갈아 끼움. 버튼·테이블·도구 **모든 편집 경로**가 함께 막힘. 이미 cm 로 저장된 옛 프로젝트도 이 경로로 안전해짐. 자체검증(공용 브라우저 임시 탭): ① 264 부근 그래프 측점이 **264.055 하나**로 모임(고치기 전 264.06 이 따로 있었음) ② 그 구조물 측점 계획고를 8칸 올려도 **수직 꺾임 0건**, 계획선 점 수 1,208 불변, 최대 기울기 66.0 → 183.5%(8칸 올린 만큼의 정상값. 고치기 전 155,791%) ③ 전체 시험 381 통과·17 건너뜀. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -85,6 +85,9 @@ const MAX_PANEL_HEIGHT_RATIO = 0.9;
|
||||
* 계산이 브라우저 안에서 끝나면서(2026-09-03) 서버 왕복이 사라져 250→60ms 로 줄였다 —
|
||||
* 실측 전 측점(128) 재계산 7.5ms 라 손을 떼는 즉시 유토곡선이 따라온다. */
|
||||
const CROSS_PREVIEW_DEBOUNCE_MS = 60;
|
||||
/** 구조물 측점을 종단 정본 측점으로 맞춰 주는 허용 오차(m). 층마다 반올림이 달라 생기는
|
||||
* mm~cm 어긋남만 흡수할 크기다 — 이보다 멀면 서로 다른 측점이다. */
|
||||
const STATION_SNAP_TOLERANCE_M = 0.1;
|
||||
|
||||
/**
|
||||
* 저장된 계획선 선형을 읽되 **모양을 먼저 검증한다**.
|
||||
@@ -341,6 +344,36 @@ export function createRouteProfilePanel(
|
||||
세로는 보이는 구간에 맞춰 자동이라 사람이 맞출 것이 없다(2026-09-04 사용자 확정). */
|
||||
const profileZoom = createProfileZoom(() => draw());
|
||||
|
||||
/**
|
||||
* 구조물 측점의 누가거리를 **종단 정본 값으로 갈아 끼운다**(2026-09-04).
|
||||
*
|
||||
* 같은 구조물이 층마다 다른 누가거리를 들고 있었다 — 횡단 측점 `264.054626`,
|
||||
* 종단 정본 변화점 `264.055`, 배수 정본 파일 `264.06`(cm 반올림). 사이드 목록이 든
|
||||
* 값으로 계획고를 편집하면 정본 옆 mm 자리에 **가짜 변화점**이 하나 더 서고, 둘 사이
|
||||
* 종단곡선이 mm 로 쭈그러들어 기울기가 155,791% 로 튀었다(2026-09-04 사용자 보고).
|
||||
*
|
||||
* 2026-09-03 에 ▲▼ 버튼 경로만 막았는데 측점 테이블·도구 경로가 남아 다시 터졌다.
|
||||
* 값이 화면에 들어오는 **이 한 자리**에서 정본으로 맞춰 모든 경로를 함께 막는다.
|
||||
*/
|
||||
function snapToMasterStations(stations: IrregularStation[]): IrregularStation[] {
|
||||
const master = alignment?.stations;
|
||||
if (!master?.length) return stations;
|
||||
return stations.map((station) => {
|
||||
let best: number | null = null;
|
||||
let gap = STATION_SNAP_TOLERANCE_M;
|
||||
for (const node of master) {
|
||||
const distance = Math.abs(node.chainage_m - station.chainage_m);
|
||||
if (distance <= gap) {
|
||||
gap = distance;
|
||||
best = node.chainage_m;
|
||||
}
|
||||
}
|
||||
return best === null || best === station.chainage_m
|
||||
? station
|
||||
: { ...station, chainage_m: best };
|
||||
});
|
||||
}
|
||||
|
||||
/** 세로 자동 맞춤이 지금 쓰는 Y 창. 계획고를 끄는 동안에는 이 값을 붙잡는다. */
|
||||
let elevationWindow: { min: number; max: number } | undefined;
|
||||
/** 세로 창을 **다시 그리지 않고** 옮기는 갱신기 — 그릴 때마다 렌더러가 새로 준다. */
|
||||
@@ -652,7 +685,7 @@ export function createRouteProfilePanel(
|
||||
},
|
||||
/** 비정규 측점 목록을 반영해 그래프(세로선+라벨)·테이블(주석)을 다시 그린다. */
|
||||
setIrregularStations(stations: IrregularStation[]) {
|
||||
irregularStations = stations;
|
||||
irregularStations = snapToMasterStations(stations);
|
||||
draw();
|
||||
},
|
||||
/** 구조물 타입 레지스트리를 받아 마크 색·약호·우클릭 메뉴에 쓴다(최초 1회). */
|
||||
|
||||
@@ -90,7 +90,11 @@ class PipePoint:
|
||||
def as_dict(self) -> dict[str, Any]:
|
||||
# 구 형식 저장분이 확장 필드 없이 그대로 다시 저장되도록 기본값은 생략한다.
|
||||
payload: dict[str, Any] = {
|
||||
"chainage_m": round(float(self.chainage_m), 2),
|
||||
# 누가거리는 좌표(x·y)와 **같은 밀리미터 기준**으로 남긴다. cm 로 반올림하던
|
||||
# 옛 규칙은 종단 정본 변화점(3자리)과 최대 5mm 어긋났고, 그 값으로 계획고를
|
||||
# 편집하면 정본 옆 mm 자리에 가짜 변화점이 하나 더 서서 종단곡선이 mm 로
|
||||
# 쭈그러들었다 — 그 구간 기울기가 155,791% 로 튀었다(2026-09-04 사용자 보고).
|
||||
"chainage_m": round(float(self.chainage_m), 3),
|
||||
"source": self.source,
|
||||
}
|
||||
if self.facility != PIPE_FACILITY_PIPE:
|
||||
|
||||
Reference in New Issue
Block a user