- pivotAxes 직선 안쪽 null 지움 · 꼭짓점 아닌 자리는 품은 마디로 축 찾기 - 시험 helper_355_1 ③ 직선 안 80 바꿈 · ④ 꼭짓점 아닌 70 더함 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
55 lines
2.6 KiB
TypeScript
55 lines
2.6 KiB
TypeScript
/* =============================================================================
|
|
* B05_Profile_UI_Profile_Pivot.ts
|
|
* 종단 ▲▼ 축 찾기(355-1 · 368-1 · 요구 235-15 · 240-20) — 누른 점에서 좌우로 같은
|
|
* 기울기 마디를 건너 다음 꺾임(R 있는 점 · 없으면 시점 · 종점)을 축으로 삼는다. 사이
|
|
* 측점은 새 직선(축 → 누른 점 → 축) 위로 따라 돈다(`adjustStation`). 직선 안 점 ·
|
|
* 꼭짓점 아닌 자리(추가 측점)도 같은 규칙 — 누른 점이 새 꺾임(기본 L 곡선)이 된다.
|
|
*
|
|
* 처음 계획선은 마디마다 꺾여 축 = 누른 점 ±1 → 사이 측점 없음(옛 동작 그대로).
|
|
* `B05_Profile_UI_Profile_Alignment` 를 타입으로만 읽는다(순환 import 없음).
|
|
* ========================================================================== */
|
|
|
|
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
|
|
|
|
/** 같은 직선으로 볼 기울기 차이 — `B05_Profile_UI_Profile_Straighten` 과 같은 값. */
|
|
const COLLINEAR_EPSILON = 1e-6;
|
|
const SAME_STATION_M = 1e-6;
|
|
|
|
export interface PivotAxes {
|
|
fromM: number;
|
|
fromZ: number;
|
|
toM: number;
|
|
toZ: number;
|
|
/** 두 축 사이(끝 · 누른 점 제외) 변화점 chainage. */
|
|
inner: number[];
|
|
}
|
|
|
|
/** 누른 점의 두 축과 사이 변화점 — 시종점 · 계획선 밖이면 null. */
|
|
export function pivotAxes(alignment: ProfileAlignment, chainageM: number): PivotAxes | null {
|
|
const { pvi, segments } = alignment;
|
|
const index = pvi.findIndex((node) => Math.abs(node.chainage_m - chainageM) < SAME_STATION_M);
|
|
// 꼭짓점 아닌 자리 = 그 점을 품은 마디 하나가 좌우 마디
|
|
const right = index >= 0 ? index : pvi.findIndex((node) => node.chainage_m > chainageM);
|
|
if (right <= 0 || (index >= 0 && index >= pvi.length - 1)) return null;
|
|
const [leftSeg, rightSeg] = index >= 0 ? [index - 1, index] : [right - 1, right - 1];
|
|
const grade = (at: number): number => {
|
|
const segment = segments[at];
|
|
return segment && segment.length_m > 1e-12 ? segment.height_m / segment.length_m : 0;
|
|
};
|
|
const same = (a: number, b: number): boolean => Math.abs(grade(a) - grade(b)) < COLLINEAR_EPSILON;
|
|
let from = leftSeg;
|
|
while (from > 0 && same(from - 1, leftSeg)) from -= 1;
|
|
let to = rightSeg + 1;
|
|
while (to < pvi.length - 1 && same(to, rightSeg)) to += 1;
|
|
return {
|
|
fromM: pvi[from].chainage_m,
|
|
fromZ: pvi[from].elevation_m,
|
|
toM: pvi[to].chainage_m,
|
|
toZ: pvi[to].elevation_m,
|
|
inner: pvi
|
|
.slice(from + 1, to)
|
|
.map((node) => node.chainage_m)
|
|
.filter((chainage) => Math.abs(chainage - chainageM) >= SAME_STATION_M),
|
|
};
|
|
}
|