main_laptop_1 -> main byeonghap (4 hwangyeong 585 commits) #12

Merged
eomsangdon merged 585 commits from main_laptop_1 into main 2026-09-08 17:26:30 +09:00
3 changed files with 45 additions and 42 deletions
Showing only changes of commit 1bb367058b - Show all commits
+33 -35
View File
@@ -41,6 +41,10 @@ import {
normalizeVisibleBasis,
} from "@util/common_util_mass_haul";
import { computeHaulPlan } from "@util/common_util_mass_haul_balance";
import {
badgeValuesFrom,
type MassHaulBadgeValues,
} from "@util/common_util_mass_haul_badge";
import { resetBalloonOffsets } from "@util/common_util_mass_haul_balance_view";
import {
createMassHaulChart,
@@ -185,18 +189,7 @@ function readVisible(): Set<string> {
* 종단 상단줄이 **접힌 상태에서도** 보여 주는 유토곡선 총괄값(2026-09-06 사용자 지시).
* 곡선 자체는 접으면 사라져도 이 값은 계획선을 만지며 계속 봐야 한다.
*/
export interface MassHaulSummaryValues {
/** 노선 끝 누가토량(㎥) — 양수 잉여, 음수 부족. */
finalM3: number;
/** 절토(자연상태) 합계(㎥). */
cutNaturalM3: number;
/** 절토를 다짐으로 환산한 값(㎥). */
cutCompactedM3: number;
/** 성토(다짐) 합계(㎥). */
fillCompactedM3: number;
surplusM3: number;
shortageM3: number;
}
export type MassHaulSummaryValues = MassHaulBadgeValues;
export function createRouteMassHaulPanel(
onChanged: () => void,
@@ -339,31 +332,31 @@ export function createRouteMassHaulPanel(
/** 마지막으로 그린 입력 — 이동이 아직 안 끝났으면 다음 프레임에 이걸로 한 번 더 그린다. */
let lastParams: RouteMassHaulDrawParams | null = null;
/** 총괄값만 따로 낸다 — 패널을 접어도 상단줄이 값을 잃지 않게(2026-09-06). */
function reportSummary(params: RouteMassHaulDrawParams): void {
/** 이미 낸 계열에서 총괄값만 낸다 — 계산은 하지 않는다. */
function emitSummary(series: MassHaulSeries[]): void {
if (!onSummary) return;
if (!context || params.pendingRecalc) return;
const series = computeMassHaulSeries(
params.longitudinal,
params.crossSections,
context.conversion,
context.naturalSpoilMinSlope,
);
if (!series.length) return onSummary(null);
// 총괄값 기준은 **횡단 고정**이다(2026-09-06 사용자: 종단 기준 곡선은 뒤에 없앨 예정).
// 범례에서 무엇을 켜 두었든 배지·상단줄이 흔들리지 않는다.
const picked = series.find((entry) => entry.basis === "cross") ?? series[0];
const result = picked.result;
const cut = result.cut_natural_m3;
const points = result.points;
onSummary({
finalM3: points.length ? points[points.length - 1].cumulative_volume_m3 : 0,
cutNaturalM3: cut.soil + cut.ripping_rock + cut.blasting_rock,
cutCompactedM3: result.cut_compacted_m3,
fillCompactedM3: result.fill_compacted_m3,
surplusM3: result.surplus_m3,
shortageM3: result.shortage_m3,
});
onSummary(badgeValuesFrom(picked.result));
}
/** 총괄값만 따로 낸다 — 패널을 접어도 상단줄이 값을 잃지 않게(2026-09-06).
* **횡단 기준만** 적분한다 — 접힌 상태에서 종단 기준까지 내던 것은 버려질 값이었다
* (2026-09-06 조작 실측: 계획고 ▲ → 라벨 갱신 중앙 130ms 중 낭비분). */
function reportSummary(params: RouteMassHaulDrawParams): void {
if (!onSummary) return;
if (!context || params.pendingRecalc) return;
emitSummary(
computeMassHaulSeries(
params.longitudinal,
params.crossSections,
context.conversion,
context.naturalSpoilMinSlope,
["cross"],
),
);
}
function draw(params: RouteMassHaulDrawParams): void {
@@ -371,9 +364,12 @@ export function createRouteMassHaulPanel(
clearSelection = params.onClearSelection;
overlay.hidden = !open;
syncHandlePosition();
// 곡선을 그리기 전에 총괄값부터 낸다 — 접혀 있어도 상단줄에는 값이 서야 한다.
reportSummary(params);
if (!open) return;
// 접혀 있어도 상단줄에는 값이 서야 한다 — 이때는 **횡단 기준만** 적분한다.
// 펼친 경우에는 아래에서 두 기준을 내므로 그 결과로 총괄값을 낸다(계산 한 번).
if (!open) {
reportSummary(params);
return;
}
if (!context) {
note("토량환산계수를 불러오지 못해 유토곡선을 계산할 수 없습니다.");
return;
@@ -400,6 +396,8 @@ export function createRouteMassHaulPanel(
context.conversion,
context.naturalSpoilMinSlope,
);
// 총괄값은 방금 낸 계열에서 꺼낸다 — 접힘 경로처럼 따로 적분하지 않는다.
emitSummary(series);
if (!series.length) {
note("횡단 설계가 아직 없어 유토곡선을 그릴 수 없습니다.");
return;
+4 -2
View File
@@ -85,8 +85,10 @@ const MAX_PANEL_HEIGHT_RATIO = 0.9;
/** 계획고 편집 후 횡단을 다시 계산하기까지 기다리는 시간(ms).
* ▲/▼ 길게 누르기(초당 10회)·끌기에서 매 프레임 다시 돌지 않게 마지막 값만 계산한다.
* 계산이 브라우저 안에서 끝나면서(2026-09-03) 서버 왕복이 사라져 250→60ms 로 줄였다 —
* 실측 전 측점(128) 재계산 7.5ms 라 손을 떼는 즉시 유토곡선이 따라온다. */
const CROSS_PREVIEW_DEBOUNCE_MS = 60;
* 실측 전 측점(128) 재계산 7.5ms 라 손을 떼는 즉시 유토곡선이 따라온다.
* 60→16ms(2026-09-06) — ▲ 한 번에 라벨이 서기까지 중앙 130ms 를 쟀는데 그중 60ms 가
* 이 대기였다. 한 프레임(16ms)이면 연속 입력은 여전히 마지막 값만 계산한다. */
const CROSS_PREVIEW_DEBOUNCE_MS = 16;
/** 구조물 측점을 종단 정본 측점으로 맞춰 주는 허용 오차(m). 층마다 반올림이 달라 생기는
* mm~cm 어긋남만 흡수할 크기다 — 이보다 멀면 서로 다른 측점이다. */
const STATION_SNAP_TOLERANCE_M = 0.1;
+8 -5
View File
@@ -445,15 +445,18 @@ export function computeMassHaulSeries(
crossSections: MassHaulSection[],
conversion: EarthworkConversion,
naturalSpoilMinSlope?: number,
/** 낼 기준. 총괄값(배지)만 필요하면 `["cross"]` 로 불러 종단 기준 적분을 건너뛴다. */
bases: readonly MassHaulBasis[] = SERIES_BASES,
): MassHaulSeries[] {
const sections = designedSections(crossSections);
const sampleSets: Record<MassHaulBasis, AreaSample[]> = {
cross: crossAreaSamples(sections, naturalSpoilMinSlope),
longitudinal: longitudinalAreaSamples(longitudinal, sections),
};
const samplesFor = (basis: MassHaulBasis): AreaSample[] =>
basis === "cross"
? crossAreaSamples(sections, naturalSpoilMinSlope)
: longitudinalAreaSamples(longitudinal, sections);
const series: MassHaulSeries[] = [];
for (const basis of SERIES_BASES) {
const result = integrate(sampleSets[basis], conversion);
if (!bases.includes(basis)) continue;
const result = integrate(samplesFor(basis), conversion);
if (result) series.push({ key: basis, basis, result });
}
return series;