refactor(454 계산 줄 유토 단계): 안 쓰는 masshaul · haul 단계 걷음 (433-3)
- 계산 줄 masshaul(유토곡선 계열) · haul(흙 배분 POST) 단계 지움 — 읽는 화면 없음 · 조작마다 헛 셈 · 헛 POST - 유토곡선 판 계산 · createHaulPlanPrefetch · postHaulPlan 남김 · 표준단면 도착 때 cross 다시 먹이기 남김 - 탐침 시험: 끝 누가토량은 공용 계산 헬퍼(helper_454_final_cumulative) · 뒤 단계 늦은 응답 = corridor · 묶음 흙 배분 POST 0 단언 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -6,9 +6,8 @@
|
||||
* route · ground `B05_Profile/logic/B05_Profile_Pipeline_RouteGround.ts`(sub8)
|
||||
* follow · planline · profile `B05_Profile/logic/B05_Profile_Pipeline_Grade.ts`
|
||||
* stations `design_pipeline_stations.ts` · footprint `B05_Profile_Footprint_Stage.ts`(sub6)
|
||||
* cross · masshaul · haul `B06_Section_Cross_Stage` · `logic/B05_Profile_MassHaul_Stage` ·
|
||||
* `B05_Profile_Api_HaulPlan`(sub2) · drainage 배수유역 판 `pipelineStage`(sub3) · corridor 3D 「낡음」.
|
||||
* haul · corridor 는 노선 초안 동안만(저장 노선은 유토곡선 판 · 횡단 다시 셈이 맡음).
|
||||
* cross `B06_Section_Cross_Stage` · drainage 배수유역 판 `pipelineStage`(sub3) · corridor 3D 「낡음」.
|
||||
* corridor 는 노선 초안 동안만 · 유토곡선 · 흙 배분은 유토곡선 판이 셈(454).
|
||||
*
|
||||
* 입력 — 노선 = 편집기 다리(`RouteDraftBridge` · 캐시 칸 route-draft) · 계획고 = 종단도 편집
|
||||
* (`pipelineGrade` · 노선 초안 동안은 alignment-draft 노선 `DRAFT_ROUTE_ID`) · 횡단 = 저장 상세의 측점
|
||||
@@ -65,7 +64,6 @@ import {
|
||||
fetchRoutePlan,
|
||||
type RoutePlanResponse,
|
||||
} from "../../B05_Profile/B05_Profile_Api_Replan";
|
||||
import { createHaulStage } from "../../B05_Profile/B05_Profile_Api_HaulPlan";
|
||||
import { fetchStructureTypes } from "../../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { forgetPageData, pagePipes, pageStructures, trackPageBusy } from "./design_page_data";
|
||||
import type { PagePipelineOptions, ProfileLink } from "./design_pipeline_page_types";
|
||||
@@ -98,10 +96,6 @@ import {
|
||||
SECTION_STATION_INTERVAL_M,
|
||||
} from "../../B05_Profile/logic/B05_Profile_Sections_Stations";
|
||||
import { footprintStage } from "../../B05_Profile/logic/B05_Profile_Footprint_Stage";
|
||||
import {
|
||||
createMassHaulStage,
|
||||
type MassHaulStageContext,
|
||||
} from "../../B05_Profile/logic/B05_Profile_MassHaul_Stage";
|
||||
import type {
|
||||
PlanPipe,
|
||||
PlanStructure,
|
||||
@@ -122,7 +116,7 @@ interface PagePipeline {
|
||||
bridge: RouteDraftBridge;
|
||||
grade(edits: AlignmentEdits): void;
|
||||
restart(): void;
|
||||
earthwork(context: MassHaulStageContext | null): void;
|
||||
earthwork(): void;
|
||||
cross(): void;
|
||||
reconcile(): Promise<number>;
|
||||
ownsCross: boolean;
|
||||
@@ -154,9 +148,8 @@ export const pipelineGrade = (projectId: string, edits: AlignmentEdits): void =>
|
||||
/** 저장 정본이 바뀜(새로 받은 상세 · 새 노선) — 처음부터 다시. 갈아끼운 상세 · 같은 상세 다시 그림은 안 셈. */
|
||||
export const restartPagePipeline = (projectId: string): void => pages.get(projectId)?.restart();
|
||||
|
||||
/** 유토곡선 설정(토량환산계수 · 자연방토 경사) — masshaul 단계 재료 · 표준단면이 막 왔으면 횡단 입력도. */
|
||||
export const pipelineEarthwork = (projectId: string, context: MassHaulStageContext | null): void =>
|
||||
pages.get(projectId)?.earthwork(context);
|
||||
/** 유토곡선 설정(표준단면 포함)이 막 옴 — 횡단 입력을 다시 먹임. */
|
||||
export const pipelineEarthwork = (projectId: string): void => pages.get(projectId)?.earthwork();
|
||||
|
||||
/** 횡단 고침(지반 유형 · 측구 · 암 · 소단 · 표준 — B06 · 365-2) — 세션 횡단 입력을 다시 모아 cross 부터. */
|
||||
export const pipelineCross = (projectId: string): void => pages.get(projectId)?.cross();
|
||||
@@ -195,7 +188,6 @@ function createPagePipeline(
|
||||
let enabled: PlanType[] = [];
|
||||
let savedStructures: PlanStructure[] = [];
|
||||
let savedPipes: PlanPipe[] = [];
|
||||
let earthwork: MassHaulStageContext | null = null;
|
||||
/** 저장 노선 측점(열쇠) · 마지막으로 모은 횡단 입력(시설 제원 — 새 노선 상세가 씀). */
|
||||
let savedStations: PipelineStation[] = [];
|
||||
let crossSource: PipelineCrossSource | null = null;
|
||||
@@ -280,7 +272,6 @@ function createPagePipeline(
|
||||
};
|
||||
const groundDeps = groundStageDeps(projectId);
|
||||
const crossStage = createCrossStage({ grid: groundDeps.grid }); // 미교차 넓힘 = 같은 지형 격자(349-0j)
|
||||
const haulStage = createHaulStage(projectId, () => savedSource().routeId ?? undefined);
|
||||
const followStage = createFollowStage({
|
||||
savedLine,
|
||||
saved: () => {
|
||||
@@ -379,8 +370,6 @@ function createPagePipeline(
|
||||
});
|
||||
},
|
||||
footprint: footprintStage,
|
||||
masshaul: createMassHaulStage(() => earthwork),
|
||||
haul: (ctx) => (ctx.inputs.route ? haulStage(ctx) : (ctx.prev ?? null)),
|
||||
drainage: link.side?.pipelineStage,
|
||||
corridor: (ctx) => {
|
||||
if (ctx.inputs.route) options.onCorridorStale?.();
|
||||
@@ -678,8 +667,7 @@ function createPagePipeline(
|
||||
// 갈아끼움 · 같은 상세 다시 그림은 안 셈 · 보기가 심은 측점은 묶음이 입력으로 셈(386-3)
|
||||
if (canonChanged()) void loadPlan().then(start);
|
||||
},
|
||||
earthwork(context) {
|
||||
earthwork = context;
|
||||
earthwork() {
|
||||
const cross = crossNow()?.input ?? null;
|
||||
if (started && cross) void feed("cross", cross);
|
||||
},
|
||||
|
||||
@@ -522,7 +522,7 @@ export function createDesignProfile(ctx: DesignProfileContext) {
|
||||
*/
|
||||
setEarthworkContext(next: RouteMassHaulContext | null) {
|
||||
massHaul.setContext(next);
|
||||
pagePipeline.pipelineEarthwork(projectId, next);
|
||||
pagePipeline.pipelineEarthwork(projectId);
|
||||
drawSoon();
|
||||
},
|
||||
setSelectedStation(stationId: string | null) {
|
||||
|
||||
@@ -39,10 +39,9 @@ export const BROWSER_STAGES: StageName[] = [
|
||||
"profile",
|
||||
"cross",
|
||||
"footprint",
|
||||
"masshaul",
|
||||
];
|
||||
/** 뒤 — 브라우저 단계가 끝나면 함께 띄우고 기다리지 않음. */
|
||||
export const AFTER_STAGES: StageName[] = ["haul", "drainage", "corridor"];
|
||||
export const AFTER_STAGES: StageName[] = ["drainage", "corridor"];
|
||||
|
||||
type Dep = StageName | `input.${InputKey}`;
|
||||
|
||||
@@ -56,15 +55,13 @@ export const STAGE_DEPS: Record<StageName, Dep[]> = {
|
||||
profile: ["planline", "input.alignment"],
|
||||
cross: ["profile", "ground", "input.cross", "input.pipes", "input.structures"],
|
||||
footprint: ["cross", "ground"],
|
||||
masshaul: ["cross"],
|
||||
haul: ["masshaul"],
|
||||
drainage: ["route", "input.pipes"],
|
||||
corridor: ["profile", "cross"],
|
||||
};
|
||||
|
||||
/** follow 가 고칠 수 있는 입력 — 노선 · 횡단은 안 됨(고리). */
|
||||
const FOLLOW_KEYS: ReadonlyArray<keyof FollowPatch> = ["pipes", "structures", "alignment"];
|
||||
/** 이 단계 뒤 한 번 쉼 — 종단이 먼저 그려지고 횡단 · 유토곡선이 그다음. */
|
||||
/** 이 단계 뒤 한 번 쉼 — 종단이 먼저 그려지고 횡단이 그다음. */
|
||||
const YIELD_AFTER = new Set<StageName>(["profile"]);
|
||||
export const RUN_LOG_SIZE = 20;
|
||||
|
||||
|
||||
@@ -9,9 +9,9 @@
|
||||
* plusStations(추가 측점 · 429 ⑨)
|
||||
* ↓ update(출처, 값, 범위) — 조작마다 차례 번호(generation) +1 · 옛 계산 · 옛 요청 버림
|
||||
* 브라우저 즉시(차례대로 · 단계 사이마다 번호 확인 · 단계마다 결과 바로 내보냄)
|
||||
* route → follow → stations → ground → planline → profile → cross → footprint → masshaul
|
||||
* route → follow → stations → ground → planline → profile → cross → footprint
|
||||
* 뒤(기다리지 않음 · 새 조작이 오면 AbortSignal 로 끊김 · 옛 번호 결과 버림)
|
||||
* haul(흙 배분 · 서버 Node) · drainage(배수유역 「낡음」 표시) · corridor(3D 「낡음」 표시)
|
||||
* drainage(배수유역 「낡음」 표시) · corridor(3D 「낡음」 표시)
|
||||
*
|
||||
* 규칙:
|
||||
* · 단계는 자기 출력만 돌려줌 — 입력 · 다른 단계 출력을 고치지 않음(ctx 의 값은 읽기만).
|
||||
@@ -31,8 +31,6 @@
|
||||
* | profile | sub1 | planline · input.alignment | ProfileAlignment |
|
||||
* | cross | sub2 | profile · ground · input.cross · pipes · structures | CrossOutput |
|
||||
* | footprint | sub6 | cross · ground | PlanFootprint |
|
||||
* | masshaul | sub2 | cross | unknown(sub2 모양) |
|
||||
* | haul | sub2 | masshaul | unknown(서버 응답) |
|
||||
* | drainage | sub3 | route · input.pipes | 「낡음」 표시(출력 안 씀) |
|
||||
* | corridor | sub5 | profile · cross | 「낡음」 표시(출력 안 씀) |
|
||||
*
|
||||
@@ -238,8 +236,6 @@ export interface PipelineOutputs {
|
||||
profile: ProfileAlignment;
|
||||
cross: CrossOutput;
|
||||
footprint: PlanFootprint;
|
||||
masshaul: unknown;
|
||||
haul: unknown;
|
||||
drainage: null;
|
||||
corridor: null;
|
||||
}
|
||||
|
||||
@@ -12,8 +12,6 @@
|
||||
|
||||
import { API_BASE_URL } from "@config/config_frontend";
|
||||
import type { HaulPlan } from "@util/common_util_mass_haul_balance";
|
||||
import type { StageContext } from "../A00_Common/design/logic/design_pipeline_types";
|
||||
import type { MassHaulStageOutput } from "./logic/B05_Profile_MassHaul_Stage";
|
||||
|
||||
/** 서버가 돌려주는 배분 한 벌 — **화면이 쓰는 꼴 그대로**라 그리기 코드가 손대지 않는다.
|
||||
* `import type` 이라 배분 모듈이 번들에 실리지 않는다(빌드에서 지워진다). */
|
||||
@@ -26,7 +24,7 @@ const TIMEOUT_MS = 20000;
|
||||
/** 열쇠별로 받아 둔 배분 — 되돌리기 · 보기 오감처럼 같은 누가토량이 다시 오면 묻지 않음(342-1). */
|
||||
const KEPT_PLANS = 8;
|
||||
|
||||
/** 받은 배분 — `프로젝트:노선|열쇠` → 배분 · 오래된 것부터 버림 · 선반입 · 묶음 단계가 함께 씀. */
|
||||
/** 받은 배분 — `프로젝트:노선|열쇠` → 배분 · 오래된 것부터 버림 · 선반입이 씀. */
|
||||
const kept = new Map<string, HaulPlanPayload>();
|
||||
|
||||
/**
|
||||
@@ -86,24 +84,6 @@ async function postHaulPlan(
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 계산 묶음 `haul` 단계(PLAN 346-2 · 계약 `design_pipeline_types.ts`) — masshaul 의 횡단 기준 결과를 서버
|
||||
* Node 로 배분 · 같은 열쇠면 안 물음 · 새 조작이 오면 `ctx.signal` 로 끊김(옛 번호 결과는 묶음이 버림).
|
||||
* 못 받으면 앞 배분(`ctx.prev`) 그대로.
|
||||
*/
|
||||
export function createHaulStage(projectId: string, routeId: () => number | undefined) {
|
||||
return async (ctx: StageContext<"haul">): Promise<HaulPlanPayload> => {
|
||||
const result = (ctx.out.masshaul as MassHaulStageOutput | null)?.haulInput;
|
||||
const route = routeId();
|
||||
if (!result || !route) return (ctx.prev as HaulPlanPayload) ?? null;
|
||||
const key = keyOf(result);
|
||||
const at = keptKey(projectId, route, key);
|
||||
if (kept.has(at)) return kept.get(at) ?? null;
|
||||
const plan = await postHaulPlan(projectId, route, result, key, ctx.signal);
|
||||
return plan === undefined ? ((ctx.prev as HaulPlanPayload) ?? null) : plan;
|
||||
};
|
||||
}
|
||||
|
||||
export interface HaulPlanPrefetch {
|
||||
/** 새 누가토량 결과가 나왔음을 알린다 — 잠잠해지면 서버에 물어본다. */
|
||||
schedule: (result: unknown) => void;
|
||||
|
||||
@@ -17,7 +17,7 @@ import { useDesignStore } from "../A00_Common/design/design_store";
|
||||
import type { DesignPipeline, PipelineEvent } from "../A00_Common/design/logic/design_pipeline";
|
||||
|
||||
/** cross 를 지났다고 볼 단계(cross 가 같은 입력이라 건너뛰어도 뒤 단계가 알림). */
|
||||
const AFTER_CROSS = new Set(["cross", "footprint", "masshaul"]);
|
||||
const AFTER_CROSS = new Set(["cross", "footprint"]);
|
||||
/** 묶음 차례가 cross 를 못 낸 채 끝나도(단계 실패) 「다시 계산 중」을 푸는 때(ms). */
|
||||
const DRAFT_WAIT_MS = 3000;
|
||||
|
||||
|
||||
@@ -1,53 +0,0 @@
|
||||
/* =============================================================================
|
||||
* B05_Profile_MassHaul_Stage.ts
|
||||
* 계산 묶음 `masshaul` 단계(PLAN 346-2 · 계약 `design_pipeline_types.ts`) — cross(측점 열쇠마다 면적) ·
|
||||
* profile → 유토곡선 계열(`computeMassHaulSeries` · 화면 유토곡선 · B06 과 같은 계산).
|
||||
*
|
||||
* 출력 = `MassHaulStageOutput`(계열 + 흙 배분에 보낼 횡단 기준 결과) · 순수 계산(DOM · fetch · 세션 없음).
|
||||
* 토량환산계수 · 자연 사토 기울기는 부르는 쪽이 넘김(`context`) — 없으면 null.
|
||||
* ========================================================================== */
|
||||
|
||||
import { computeMassHaulSeries, type MassHaulSeries } from "@util/common_util_mass_haul";
|
||||
import type { EarthworkConversion, MassHaulSection } from "@util/common_util_mass_haul_types";
|
||||
import type { StageContext } from "../../A00_Common/design/logic/design_pipeline_types";
|
||||
|
||||
export interface MassHaulStageContext {
|
||||
conversion: EarthworkConversion;
|
||||
naturalSpoilMinSlope?: number;
|
||||
}
|
||||
|
||||
export interface MassHaulStageOutput {
|
||||
series: MassHaulSeries[];
|
||||
/** 흙 배분(haul 단계)에 보낼 결과 — 횡단 기준(없으면 첫 계열) · 계열이 없으면 null. */
|
||||
haulInput: MassHaulSeries["result"] | null;
|
||||
}
|
||||
|
||||
/** `masshaul` 단계 만들기 — `context()` 는 부를 때마다 읽음(설정이 바뀌면 다음 계산부터). */
|
||||
export function createMassHaulStage(context: () => MassHaulStageContext | null) {
|
||||
return (ctx: StageContext<"masshaul">): MassHaulStageOutput | null => {
|
||||
const cross = ctx.out.cross;
|
||||
const settings = context();
|
||||
if (!cross || !settings) return null;
|
||||
const sections: MassHaulSection[] = Object.values(cross.byKey)
|
||||
.sort((a, b) => a.chainageM - b.chainageM)
|
||||
.map((entry) => ({
|
||||
station_id: entry.key,
|
||||
chainage_m: entry.chainageM,
|
||||
design: entry.detail as MassHaulSection["design"],
|
||||
}));
|
||||
const samples = ctx.out.profile?.samples ?? [];
|
||||
const longitudinal = {
|
||||
length_m:
|
||||
samples[samples.length - 1]?.chainage_m ?? sections[sections.length - 1]?.chainage_m ?? 0,
|
||||
design_profiles: samples.length ? [{ samples }] : [],
|
||||
};
|
||||
const series = computeMassHaulSeries(
|
||||
longitudinal,
|
||||
sections,
|
||||
settings.conversion,
|
||||
settings.naturalSpoilMinSlope,
|
||||
);
|
||||
const picked = series.find((entry) => entry.basis === "cross") ?? series[0];
|
||||
return { series, haulInput: picked?.result ?? null };
|
||||
};
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/* 344-3 · 346-2 2파 시험 묶음 진입점 — 진짜 모듈을 vite ssr 로 한 벌 묶어 Node 헬퍼가 부름.
|
||||
* 측점 열쇠(옛 초안 옮김 · 노선 밖 고침) · cross · masshaul · haul 단계를 화면 · 서버 없이 잰다.
|
||||
* 측점 열쇠(옛 초안 옮김 · 노선 밖 고침) · cross 단계를 화면 · 서버 없이 잰다.
|
||||
*/
|
||||
export {
|
||||
carryStationDrafts,
|
||||
@@ -20,8 +20,6 @@ export {
|
||||
readRockBoundarySession,
|
||||
} from "../../B06_Section/B06_Section_UI_Page_Persist";
|
||||
export { createCrossStage, groundSamples } from "../../B06_Section/logic/B06_Section_Cross_Stage";
|
||||
export { createMassHaulStage } from "../../B05_Profile/logic/B05_Profile_MassHaul_Stage";
|
||||
export { createHaulStage } from "../../B05_Profile/B05_Profile_Api_HaulPlan";
|
||||
export {
|
||||
buildAlignment,
|
||||
emptyEdits,
|
||||
|
||||
@@ -202,39 +202,4 @@ const edited = m.buildAlignment(base, { station_offsets: { "40.000": 0.4 }, curv
|
||||
stage(ctxOf(touched, { sources: ["grade"], fromM: 20, toM: 60, keys: [] }, third, edited));
|
||||
out.crossGrade = counts();
|
||||
|
||||
/* 6. masshaul 단계 — 계열 · 흙 배분 입력 */
|
||||
const conversion = {
|
||||
soil: { loose: 1.25, compacted: 0.9 },
|
||||
ripping_rock: { loose: 1.5, compacted: 1.2 },
|
||||
blasting_rock: { loose: 1.65, compacted: 1.35 },
|
||||
};
|
||||
const massStage = m.createMassHaulStage(() => ({ conversion }));
|
||||
const mass = massStage({ ...ctxOf(crossInput, null, null), out: { profile, cross: first } });
|
||||
out.massSeries = mass.series.map((s) => s.basis);
|
||||
out.massHaulInput = Array.isArray(mass.haulInput?.points);
|
||||
|
||||
/* 7. haul 단계 — 같은 열쇠 안 물음 · 끊김 = 앞 배분 그대로 */
|
||||
const posts = [];
|
||||
globalThis.fetch = async (_url, init) => {
|
||||
if (init.signal?.aborted) throw new Error("aborted");
|
||||
posts.push(1);
|
||||
return { ok: true, json: async () => ({ haul_plan: { n: posts.length } }) };
|
||||
};
|
||||
const haul = m.createHaulStage(P, () => R);
|
||||
const haulCtx = (masshaul, prev, signal = new AbortController().signal) => ({
|
||||
...ctxOf(crossInput, null, prev),
|
||||
signal,
|
||||
out: { masshaul },
|
||||
});
|
||||
const plan1 = await haul(haulCtx(mass, null));
|
||||
const plan2 = await haul(haulCtx(mass, plan1));
|
||||
const other = massStage({
|
||||
...ctxOf(crossInput, null, null),
|
||||
out: { profile: edited, cross: third },
|
||||
});
|
||||
const aborted = new AbortController();
|
||||
aborted.abort();
|
||||
const plan3 = await haul(haulCtx(other, plan1, aborted.signal));
|
||||
out.haul = { posts: posts.length, plan1, plan2, plan3 };
|
||||
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
|
||||
@@ -133,7 +133,7 @@ async function run() {
|
||||
};
|
||||
}
|
||||
|
||||
// ② 늦은 응답 버림 — 브라우저 단계(ground 늦음) · 뒤 단계(haul 늦음 · 끊김)
|
||||
// ② 늦은 응답 버림 — 브라우저 단계(ground 늦음) · 뒤 단계(corridor 늦음 · 끊김)
|
||||
{
|
||||
const log = [];
|
||||
let releaseGround = null;
|
||||
@@ -161,25 +161,27 @@ async function run() {
|
||||
commits,
|
||||
};
|
||||
|
||||
// 뒤 단계 — haul 1 이 늦게 옴 · 그 사이 새 조작 → 끊김 · 버림
|
||||
let releaseHaul = [];
|
||||
const hold2 = { haul: () => new Promise((resolve) => releaseHaul.push(resolve)) };
|
||||
// 뒤 단계 — corridor 1 이 늦게 옴 · 그 사이 새 조작 → 끊김 · 버림
|
||||
let releaseAfter = [];
|
||||
const hold2 = { corridor: () => new Promise((resolve) => releaseAfter.push(resolve)) };
|
||||
const log2 = [];
|
||||
const pipe2 = pipeMod.createDesignPipeline({ stages: fakeStages(log2, hold2) });
|
||||
const commits2 = [];
|
||||
pipe2.subscribe((e) => e.kind === "stage" && e.stage === "haul" && commits2.push(e.generation));
|
||||
pipe2.subscribe(
|
||||
(e) => e.kind === "stage" && e.stage === "corridor" && commits2.push(e.generation),
|
||||
);
|
||||
await pipe2.start(BASE);
|
||||
const haul1 = log2.find((e) => e.name === "haul");
|
||||
const after1 = log2.find((e) => e.name === "corridor");
|
||||
await pipe2.update("cross", { x: 1 }, { fromM: 0, toM: 0 });
|
||||
const haul1Aborted = haul1.aborted();
|
||||
releaseHaul[0]();
|
||||
const after1Aborted = after1.aborted();
|
||||
releaseAfter[0]();
|
||||
await tick(1);
|
||||
releaseHaul[1]();
|
||||
releaseAfter[1]();
|
||||
await pipe2.settled();
|
||||
out.lateAfter = {
|
||||
haul1Aborted,
|
||||
after1Aborted,
|
||||
commits: commits2,
|
||||
haulGen: pipe2.output("haul").gen,
|
||||
afterGen: pipe2.output("corridor").gen,
|
||||
generation: pipe2.generation,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* PLAN 346-1 · 346-2 붙임 단위검증 헬퍼 — 페이지 묶음에 cross · masshaul · haul · drainage · corridor 를
|
||||
/* PLAN 346-1 · 346-2 붙임 단위검증 헬퍼 — 페이지 묶음에 cross · drainage · corridor 를
|
||||
* 붙인 것. 진짜 TS(`design_pipeline_page` · `_cross` · 단계 파일 전부)를 그 자리에서 트랜스파일해 Node 로
|
||||
* 돌림. 서버 창구(노선 · 구조물 · 관 목록 · 지형 격자 · 표준단면 · 흙 배분 fetch)만 가짜.
|
||||
* 입력 argv[2] JSON · argv[3] 격자 이진. 결과 = 표준출력 JSON. 짝 = `test_346_2_pipeline_cross_page.py`. */
|
||||
@@ -6,6 +6,7 @@ const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
const CATALOG = require("./helper_322_catalog_module.cjs");
|
||||
const finalCumulative = require("./helper_454_final_cumulative.cjs");
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
const job = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
@@ -29,7 +30,7 @@ globalThis.window = {
|
||||
clearTimeout,
|
||||
};
|
||||
|
||||
// 흙 배분 서버 — 늦게 답함 · 끊기면 버림
|
||||
// 흙 배분 서버 — 늦게 답함 · 끊기면 버림 · 묶음은 안 부름(454 masshaul · haul 단계 걷음)
|
||||
const haul = { calls: 0, aborted: 0, answered: 0 };
|
||||
globalThis.fetch = (url, init) =>
|
||||
new Promise((resolve, reject) => {
|
||||
@@ -205,7 +206,7 @@ async function run() {
|
||||
stationIntervalM: job.interval,
|
||||
onCorridorStale: () => (corridor += 1),
|
||||
});
|
||||
pageMod.pipelineEarthwork(P, { conversion: job.conversion });
|
||||
pageMod.pipelineEarthwork(P);
|
||||
const pipe = pageMod.pagePipeline(P);
|
||||
const commits = [];
|
||||
pipe.subscribe((e) => e.kind === "stage" && commits.push(`${e.stage}@${e.generation}`));
|
||||
@@ -242,7 +243,6 @@ async function run() {
|
||||
const ground = pipe.output("ground");
|
||||
const profile = pipe.output("profile");
|
||||
const shown = pageMod.pipelineDetail(P);
|
||||
const mass = pipe.output("masshaul");
|
||||
const moved = {
|
||||
run: {
|
||||
outcome: runB.outcome,
|
||||
@@ -264,7 +264,7 @@ async function run() {
|
||||
cut: pipe.output("cross").byKey[s.key]?.cutAreaM2 ?? null,
|
||||
fill: pipe.output("cross").byKey[s.key]?.fillAreaM2 ?? null,
|
||||
})),
|
||||
finalCumulative: mass?.haulInput?.final_cumulative_m3 ?? null,
|
||||
finalCumulative: finalCumulative(load, pipe, job.conversion),
|
||||
footprint: pipe.output("footprint")?.records.length ?? 0,
|
||||
detail: shown && {
|
||||
sections: shown.cross_sections.length,
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
const finalCumulative = require("./helper_454_final_cumulative.cjs");
|
||||
const CATALOG = require("./helper_322_catalog_module.cjs");
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
@@ -167,7 +168,7 @@ async function run() {
|
||||
drawn = next;
|
||||
void Promise.resolve().then(renderB06);
|
||||
});
|
||||
const final = () => pipe.output("masshaul")?.haulInput?.final_cumulative_m3 ?? null;
|
||||
const final = () => finalCumulative(load, pipe, job.conversion);
|
||||
const cut = () =>
|
||||
Object.values(pipe.output("cross")?.byKey ?? {}).reduce((s, c) => s + (c.cutAreaM2 ?? 0), 0);
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
const finalCumulative = require("./helper_454_final_cumulative.cjs");
|
||||
const CATALOG = require("./helper_322_catalog_module.cjs");
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
@@ -249,7 +250,7 @@ async function draftRun(P, grid) {
|
||||
totalMs: run.totalMs,
|
||||
line: pipe.output("route").line,
|
||||
curves: pipe.output("route").curves,
|
||||
final: pipe.output("masshaul")?.haulInput?.final_cumulative_m3 ?? null,
|
||||
final: finalCumulative(load, pipe, job.conversion),
|
||||
stations,
|
||||
copied,
|
||||
};
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
const finalCumulative = require("./helper_454_final_cumulative.cjs");
|
||||
const CATALOG = require("./helper_322_catalog_module.cjs");
|
||||
|
||||
const ROOT = path.join(__dirname, "..", "..");
|
||||
@@ -198,7 +199,7 @@ async function run() {
|
||||
stations: chainagesOf(stations),
|
||||
saved: job.detail.cross_sections.map((s) => s.chainage_m),
|
||||
pipeChainages: (pipe.input("pipes") ?? []).map((p) => p.chainage_m),
|
||||
final: pipe.output("masshaul")?.haulInput?.final_cumulative_m3 ?? null,
|
||||
final: finalCumulative(load, pipe, job.conversion),
|
||||
footprint: pipe.output("footprint")?.records.length ?? 0,
|
||||
};
|
||||
|
||||
@@ -239,7 +240,7 @@ async function run() {
|
||||
const again = await openOnce("proj-349b");
|
||||
const reopen = {
|
||||
runs: runs().slice(again.before).length,
|
||||
final: again.pipe.output("masshaul")?.haulInput?.final_cumulative_m3 ?? null,
|
||||
final: finalCumulative(load, again.pipe, job.conversion),
|
||||
stations: chainagesOf(again.pipe.output("ground")?.stations),
|
||||
};
|
||||
again.stop();
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/* 454 — 옛 masshaul 단계 탐침 자리: 묶음 cross · profile 출력으로 누가토량 끝값(m3).
|
||||
* 유토곡선 판(`B05_Profile_UI_Profile_MassHaul`)과 같은 공용 계산(`computeMassHaulSeries`) · 횡단 기준.
|
||||
* `load` = 부르는 헬퍼의 TS 로더(`load("common_util", "…ts")`). */
|
||||
module.exports = function finalCumulative(load, pipe, conversion) {
|
||||
const cross = pipe.output("cross");
|
||||
const samples = pipe.output("profile")?.samples ?? [];
|
||||
if (!cross) return null;
|
||||
const { computeMassHaulSeries } = load("common_util", "common_util_mass_haul.ts");
|
||||
const sections = Object.values(cross.byKey)
|
||||
.sort((a, b) => a.chainageM - b.chainageM)
|
||||
.map((e) => ({ station_id: e.key, chainage_m: e.chainageM, design: e.detail }));
|
||||
const series = computeMassHaulSeries(
|
||||
{
|
||||
length_m:
|
||||
samples[samples.length - 1]?.chainage_m ?? sections[sections.length - 1]?.chainage_m ?? 0,
|
||||
design_profiles: samples.length ? [{ samples }] : [],
|
||||
},
|
||||
sections,
|
||||
conversion,
|
||||
);
|
||||
const picked = series.find((s) => s.basis === "cross") ?? series[0];
|
||||
return picked?.result?.final_cumulative_m3 ?? null;
|
||||
};
|
||||
@@ -1,5 +1,5 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""344-3 · 346-2 2파 — 세션 횡단 초안 측점 열쇠 · cross · masshaul · haul 단계.
|
||||
"""344-3 · 346-2 2파 — 세션 횡단 초안 측점 열쇠 · cross 단계(masshaul · haul 단계는 454 에서 걷음).
|
||||
|
||||
못박는 것
|
||||
- 옛 초안(누가거리 열쇠)은 읽을 때 측점 열쇠로 옮김 · 지금 측점에 없는 것은 지우지 않고 남김.
|
||||
@@ -8,7 +8,6 @@
|
||||
- 노선이 바뀜 = 측점 열쇠로 넘김(관 · 구조물은 옮긴 자리로) · 넘김 = 카드 선택 넷 · 암 경계 ·
|
||||
노견 확장(417) · 단면 유형 · 측구 방향 · 포장은 안 넘김 · 사라진 측점 = 「노선 밖 고침 N 건」.
|
||||
- cross 단계: 같은 입력 다시 셈 0 · 측점 하나 고침 = 1 · 범위 밖 재사용.
|
||||
- masshaul 단계 = 계열 + 흙 배분 입력 · haul 단계 = 같은 열쇠 안 물음 · 끊김 = 앞 배분 그대로.
|
||||
|
||||
Node 헬퍼 `helper_344_3_station_keys.mjs` 가 vite ssr 로 묶은 진짜 모듈(`helper_344_3_entry.ts`)을
|
||||
부름.
|
||||
@@ -116,9 +115,3 @@ def test_cross_단계_국부_연산(out):
|
||||
assert out["crossOne"] == {"computed": 1, "reused": 5}
|
||||
assert out["crossOneChanged"] == "soil"
|
||||
assert out["crossGrade"]["computed"] <= 3 and out["crossGrade"]["reused"] >= 3
|
||||
|
||||
|
||||
def test_masshaul_haul_단계(out):
|
||||
assert out["massSeries"] == ["cross", "longitudinal"]
|
||||
assert out["massHaulInput"] is True
|
||||
assert out["haul"] == {"posts": 1, "plan1": {"n": 1}, "plan2": {"n": 1}, "plan3": {"n": 1}}
|
||||
|
||||
@@ -31,9 +31,8 @@ BROWSER = [
|
||||
"profile",
|
||||
"cross",
|
||||
"footprint",
|
||||
"masshaul",
|
||||
]
|
||||
AFTER = ["haul", "drainage", "corridor"]
|
||||
AFTER = ["drainage", "corridor"]
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
@@ -65,7 +64,7 @@ def test_같은_입력_다시_안_셈(r):
|
||||
b = r["basic"]
|
||||
assert b["same"] == {"result": None, "generation": 1} # 같은 값 = 차례 번호도 안 오름
|
||||
# 횡단만 바뀌면 노선 ~ 종단 · 배수유역은 건너뜀
|
||||
assert b["crossRan"] == ["cross", "footprint", "masshaul", "haul", "corridor"]
|
||||
assert b["crossRan"] == ["cross", "footprint", "corridor"]
|
||||
assert b["crossSkipped"] == [
|
||||
"route",
|
||||
"follow",
|
||||
@@ -76,7 +75,7 @@ def test_같은_입력_다시_안_셈(r):
|
||||
"drainage",
|
||||
]
|
||||
# 계획고만 바뀌면 측점 · 지반 · 첫 계획선 · 배수유역 건너뜀
|
||||
assert b["gradeRan"] == ["profile", "cross", "footprint", "masshaul", "haul", "corridor"]
|
||||
assert b["gradeRan"] == ["profile", "cross", "footprint", "corridor"]
|
||||
# 노선이 바뀌면 전부
|
||||
assert b["routeRan"] == BROWSER + AFTER
|
||||
|
||||
@@ -101,8 +100,8 @@ def test_늦은_응답_버림_브라우저_단계(r):
|
||||
|
||||
def test_늦은_응답_버림_뒤_단계_끊김(r):
|
||||
late = r["lateAfter"]
|
||||
assert late["haul1Aborted"] is True # 새 조작 = 옛 요청 끊음
|
||||
assert late["commits"] == [2] and late["haulGen"] == 2 and late["generation"] == 2
|
||||
assert late["after1Aborted"] is True # 새 조작 = 옛 요청 끊음
|
||||
assert late["commits"] == [2] and late["afterGen"] == 2 and late["generation"] == 2
|
||||
|
||||
|
||||
def test_못_끝낸_단계는_범위를_합쳐_셈(r):
|
||||
@@ -133,8 +132,6 @@ def test_단계_시간_기록(r):
|
||||
"profile",
|
||||
"cross",
|
||||
"footprint",
|
||||
"masshaul",
|
||||
"haul",
|
||||
"corridor",
|
||||
]
|
||||
assert t["last"]["totalIsNumber"] is True
|
||||
|
||||
@@ -201,7 +201,7 @@ def r(request) -> dict:
|
||||
def test_열_때_한_번_발자국_저장_횡단_입력(r):
|
||||
o = r["open"]
|
||||
assert o["outcome"] == "done"
|
||||
assert {"cross", "footprint", "masshaul"} <= set(o["stages"])
|
||||
assert {"cross", "footprint"} <= set(o["stages"])
|
||||
assert o["crossCount"] == o["stations"] and o["footprint"] > 2
|
||||
assert o["carried"] == o["stations"] # 저장 측점마다 입력이 측점 열쇠로
|
||||
assert o["corridor"] == 0 and o["haulCalls"] == 0 and o["detail"] is None
|
||||
@@ -214,7 +214,7 @@ def test_노선_옮김_한_번에_유토곡선까지_시간(r):
|
||||
assert run["outcome"] == "done" and run["sources"] == ["route"]
|
||||
for stage in ("route", "stations", "ground", "planline", "profile", "cross", "footprint"):
|
||||
assert stage in run["stages"], stage
|
||||
assert "masshaul" in run["stages"]
|
||||
assert "masshaul" not in run["stages"] and "haul" not in run["stages"] # 454 걷음
|
||||
assert (
|
||||
sum(run["stages"][s] for s in run["stages"] if s not in ("haul", "drainage", "corridor"))
|
||||
< BUDGET_MS
|
||||
@@ -271,9 +271,8 @@ def test_누가토량_서버_엔진과_같은_자리수(r):
|
||||
def test_늦은_응답_버림(r):
|
||||
late = r["late"]
|
||||
assert late["genB"] > late["genA"]
|
||||
assert late["haul"]["aborted"] >= 1 # 앞 차례 흙 배분 요청 끊김
|
||||
assert f"haul@{late['genA']}" not in late["haulCommits"] # 옛 차례 배분 안 들어옴
|
||||
assert late["haulCommits"][-1] == f"haul@{late['genB']}"
|
||||
# 454 — 묶음은 흙 배분을 안 물음(유토곡선 판 선반입만) · 늦은 응답 버림 = 344-4 corridor
|
||||
assert late["haul"]["calls"] == 0 and late["haulCommits"] == []
|
||||
|
||||
|
||||
def test_저장_관_목록이_좌표로_따라감(r):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
- 그리기 = 횡단 기준만(`["cross"]`) · 범례는 낸 계열마다라 종단 단추가 안 섬.
|
||||
- 저장된 범례가 종단(`longitudinal`)이면 횡단으로 맞춤 · 분배 켬은 그대로.
|
||||
- 계산 묶음 단계(MassHaul_Stage)는 두 기준 그대로 · 공용 계산 코드 남김.
|
||||
- 공용 계산 코드는 두 기준 그대로 남김(계산 묶음 masshaul 단계는 454 에서 걷음).
|
||||
|
||||
`helper_354_2_masshaul_cross_only.cjs` 가 진짜 TS 를 잘라 돌림.
|
||||
"""
|
||||
@@ -52,8 +52,7 @@ def test_그리기는_횡단만_부름():
|
||||
|
||||
|
||||
def test_묶음_단계와_공용_코드는_그대로():
|
||||
stage = (ROOT / "B05_Profile/logic/B05_Profile_MassHaul_Stage.ts").read_text(encoding="utf-8")
|
||||
assert '["cross"]' not in stage
|
||||
assert not (ROOT / "B05_Profile/logic/B05_Profile_MassHaul_Stage.ts").exists() # 454 걷음
|
||||
util = (ROOT / "common_util/common_util_mass_haul.ts").read_text(encoding="utf-8")
|
||||
assert 'const SERIES_BASES: MassHaulBasis[] = ["cross", "longitudinal"];' in util
|
||||
assert "longitudinalAreaSamples(longitudinal, sections)" in util
|
||||
|
||||
Reference in New Issue
Block a user