feat(B02/B03/B04/B05): 계획노선 사용 범위 · 절단 여유 3m · 배수유역도 줌·측점 표기
- 계획노선 사용 범위: B02 등록에 시작·종료 누가거리 두 칸 추가, B01 수정 모달에서도 변경. projects.route_start_m·route_end_m 신설(015_route_range.sql). load_design_route 가 범위 절단 → 서피스 트림 순서로 적용. 시작 >= 종료는 화면·서버 양쪽에서 차단. 비우면 전 구간으로 종전과 같음. - 서피스 절단 여유 기본값 30m → 3m (SURFACE_ROUTE_EDGE_TRIM_M). - B04 지도·B05 배수유역도 줌 상한을 「화면 폭 20m」 기준으로 계산(고정 8배·16배 폐지). 4배를 넘으면 배경 그림 흐림 보간 해제. - 계획선 위 측점 눈금·번호 표기(측점번호+잔여거리). 관 마커와 겹치면 반대쪽으로 밀고, 되꺾임 구간에서 라벨이 겹치면 건너뜀. 그리기 코드는 두 화면 공용. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -121,6 +121,59 @@ export function computeMapRect(meta: VWorldMeta | null, width: number, height: n
|
||||
* (2026-08-01 사용자 지시: 도로 중심을 화면 중앙에, 도로 전체 + 200m까지). */
|
||||
export const ROUTE_VIEW_MARGIN_M = 200;
|
||||
|
||||
/**
|
||||
* 사업지 미터 좌표를 화면 좌표로 옮기는 변환기 (B04 지도·B05 배수유역도 공용).
|
||||
*
|
||||
* 배수유역도에서 쓰던 것을 여기로 옮겼다 — 두 화면이 같은 자리에 측점 눈금을 찍어야 한다
|
||||
* (2026-09-04). `pxPerMeter` 는 라벨 솎기·축척 계산에 쓴다.
|
||||
*/
|
||||
export function createMetricProjector(
|
||||
meta: VWorldMeta,
|
||||
view: ViewState,
|
||||
): { toScreen: (x: number, y: number) => [number, number]; pxPerMeter: number } {
|
||||
const spanX = meta.width_meters || 1;
|
||||
const spanY = meta.height_meters || 1;
|
||||
const ax = view.mapRect.width * view.scale;
|
||||
const bx = view.mapRect.x * view.scale + (view.width / 2) * (1 - view.scale) + view.offsetX;
|
||||
const ay = view.mapRect.height * view.scale;
|
||||
const by = view.mapRect.y * view.scale + (view.height / 2) * (1 - view.scale) + view.offsetY;
|
||||
return {
|
||||
toScreen: (x, y) => [
|
||||
((x - meta.x_min) / spanX) * ax + bx,
|
||||
(1 - (y - meta.y_min) / spanY) * ay + by,
|
||||
],
|
||||
pxPerMeter: ax / spanX,
|
||||
};
|
||||
}
|
||||
|
||||
/** 규칙 측점 간격(m) — 종단 패널과 같은 20m 고정. 지도·배수유역도 눈금 표기 기준(2026-09-04). */
|
||||
export const MAP_STATION_INTERVAL_M = 20;
|
||||
|
||||
/** 최대 확대에서 화면 폭에 들어올 실거리(m) — 규칙 측점 20m 기준 1~2측점
|
||||
* (2026-09-04 사용자 지시). 고정 배율(8배·16배)로는 도엽 크기마다 체감이 달라진다. */
|
||||
export const MAX_ZOOM_VIEW_WIDTH_M = 20;
|
||||
|
||||
/** 배율 상한의 안전장치 — 도엽 메타가 이상해도 여기서 멈춘다. */
|
||||
export const ZOOM_SCALE_HARD_CAP = 2000;
|
||||
|
||||
/**
|
||||
* 「화면 폭이 `MAX_ZOOM_VIEW_WIDTH_M` 가 될 때까지」에 해당하는 배율 상한을 구한다.
|
||||
*
|
||||
* 배율 1에서 도엽 실폭(`meta.width_meters`)이 지도 사각형 폭(px)을 채우므로,
|
||||
* 화면 폭(px)에 들어오는 실거리 = width_meters × viewportWidth / (mapRect.width × scale) 이다.
|
||||
* 이것을 20m 로 놓고 scale 을 푼다. 메타가 없으면 종전 고정값으로 되돌아간다.
|
||||
*/
|
||||
export function computeMaxScale(
|
||||
meta: VWorldMeta | null,
|
||||
mapRectWidth: number,
|
||||
viewportWidth: number,
|
||||
fallback: number,
|
||||
): number {
|
||||
if (!meta || mapRectWidth <= 0 || viewportWidth <= 0) return fallback;
|
||||
const scale = (meta.width_meters * viewportWidth) / (mapRectWidth * MAX_ZOOM_VIEW_WIDTH_M);
|
||||
return Math.min(ZOOM_SCALE_HARD_CAP, Math.max(fallback, scale));
|
||||
}
|
||||
|
||||
/** 평면 좌표(m) 범위. */
|
||||
export interface PlanBounds {
|
||||
x_min: number;
|
||||
|
||||
Reference in New Issue
Block a user