119 lines
4.7 KiB
TypeScript
119 lines
4.7 KiB
TypeScript
/* =============================================================================
|
|
* A00_Common/design/logic/design_calc_node_profile.ts
|
|
* 계산 Node 입구(`design_calc_node.ts`)의 종단 몫(PLAN 511-B B-3) — 첫 계획선 꼭짓점 · 계획선 짓기 ·
|
|
* 노선 바뀜 계획고 옮김. 브라우저 묶음이 쓰는 같은 TS · 파이썬은 `B05_Profile_Engine_Grade_Node.py` 로
|
|
* (늘 떠 있는 Node · 출력 = 반올림 전 값 · 정본 꼴 0.000001 m 는 파이썬이 적음).
|
|
*
|
|
* profile.base 입력 profile { chainage · ground(파이썬 `ground_profile`) · policy(`AlignmentPolicy.as_dict`) ·
|
|
* ground_following { stations: [측점 m] · start_offset_m · end_offset_m } } →
|
|
* 꼭짓점(`groundFollowingNodes` · 반올림 전) · 못 서는 땅 null(파이썬 2~4 순위)
|
|
* profile.alignment 입력 profile { chainage · ground · stations: [{ station_id · chainage_m }] · policy ·
|
|
* base_pvi(없으면 profile.base 출력) · edits · only_explicit_curves } → `buildAlignment`
|
|
* profile.carry 입력 carry_profile { old_xy · new_xy · old_base · edits · stations · half_m ·
|
|
* seat?{ ground_s · ground_z · policy · base_pvi · born } } →
|
|
* { edits(`carryEdits`) · base_pvi(`seatRouteMoved` · 높이 고친 측점 = 옮긴 편집 열쇠) }
|
|
* ========================================================================== */
|
|
|
|
import {
|
|
buildAlignment,
|
|
emptyEdits,
|
|
type AlignmentEdits,
|
|
type AlignmentNode,
|
|
type AlignmentPolicy,
|
|
} from "../../../B05_Profile/logic/B05_Profile_UI_Profile_Alignment";
|
|
import { groundFollowingNodes } from "../../../B05_Profile/logic/B05_Profile_Grade_Ground";
|
|
import { carryEdits } from "../../../B05_Profile/logic/B05_Profile_Grade_Carry";
|
|
import { seatRouteMoved } from "../../../B05_Profile/logic/B05_Profile_Pipeline_Grade";
|
|
|
|
type Line = Array<[number, number]>;
|
|
const xyOf = (line: Line) => line.map(([x, y]) => ({ x, y }));
|
|
|
|
export interface ProfileInputs {
|
|
profile?: {
|
|
chainage: number[];
|
|
ground: number[];
|
|
policy: AlignmentPolicy;
|
|
stations?: Array<{ station_id: string | null; chainage_m: number }>;
|
|
base_pvi?: AlignmentNode[] | null;
|
|
edits?: AlignmentEdits | null;
|
|
only_explicit_curves?: boolean;
|
|
ground_following?: { stations: number[]; start_offset_m?: number; end_offset_m?: number };
|
|
};
|
|
carry_profile?: {
|
|
old_xy: Line;
|
|
new_xy: Line;
|
|
old_base: AlignmentNode[];
|
|
edits?: Partial<AlignmentEdits> | null;
|
|
stations: number[];
|
|
half_m: number;
|
|
seat?: {
|
|
ground_s: number[];
|
|
ground_z: number[];
|
|
policy: AlignmentPolicy;
|
|
base_pvi: AlignmentNode[];
|
|
born: number[];
|
|
} | null;
|
|
};
|
|
}
|
|
|
|
/** id → 셈(입구 `RUNNERS` 에 얹음) — 계획선은 꼭짓점이 없으면 같은 요청의 첫 계획선 꼭짓점 위. */
|
|
export function profileRunners(inputs: ProfileInputs): Record<string, () => unknown> {
|
|
let nodes: AlignmentNode[] | null | undefined;
|
|
const base = (): AlignmentNode[] | null => {
|
|
const profile = inputs.profile;
|
|
const follow = profile?.ground_following;
|
|
if (nodes === undefined)
|
|
nodes =
|
|
profile && follow
|
|
? groundFollowingNodes(profile.chainage, profile.ground, {
|
|
stations: follow.stations,
|
|
policy: profile.policy,
|
|
startOffsetM: follow.start_offset_m ?? 0,
|
|
endOffsetM: follow.end_offset_m ?? 0,
|
|
})
|
|
: null;
|
|
return nodes;
|
|
};
|
|
return {
|
|
"profile.base": base,
|
|
"profile.alignment": () => {
|
|
const profile = inputs.profile;
|
|
const basePvi = profile?.base_pvi ?? base();
|
|
if (!profile || !basePvi) return null;
|
|
return buildAlignment(
|
|
{
|
|
policy: profile.policy,
|
|
onlyExplicitCurves: profile.only_explicit_curves === true,
|
|
basePvi,
|
|
chainage: profile.chainage,
|
|
ground: profile.ground,
|
|
stations: profile.stations ?? [],
|
|
},
|
|
profile.edits ?? emptyEdits(),
|
|
);
|
|
},
|
|
"profile.carry": () => {
|
|
const carry = inputs.carry_profile;
|
|
if (!carry) return null;
|
|
const edits = carryEdits(
|
|
xyOf(carry.old_xy),
|
|
xyOf(carry.new_xy),
|
|
carry.old_base,
|
|
carry.edits,
|
|
carry.stations,
|
|
carry.half_m,
|
|
);
|
|
const seat = carry.seat;
|
|
if (!seat) return { edits, base_pvi: null };
|
|
const held = Object.keys(edits.station_offsets).map(Number);
|
|
const base = {
|
|
chainage: seat.ground_s,
|
|
ground: seat.ground_z,
|
|
policy: seat.policy,
|
|
basePvi: seat.base_pvi,
|
|
};
|
|
return { edits, base_pvi: seatRouteMoved(base, seat.born, held) };
|
|
},
|
|
};
|
|
}
|