Merge remote-tracking branch 'origin/sub_laptop_2' into main_laptop_1
This commit is contained in:
@@ -205,13 +205,16 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
|
||||
? inside.reduce((best, at) => (Math.abs(at - anchor) < Math.abs(best - anchor) ? at : best))
|
||||
: anchor;
|
||||
};
|
||||
/** 종단 알약 레인에 올릴 목록 — 구조물 정본 + 관 정본(가상 구조물). */
|
||||
const pushMarks = (): void =>
|
||||
/** 종단 알약 레인에 올릴 목록 — 구조물 정본 + 관 정본(가상 구조물). 알약 · 측점선 · 관 id 장부 = 페이지
|
||||
* 시설 줄 한 벌(462 · 숨은 B05 평면 마커도 따라감) · `carryEdits` = 사용자 고침(불러옴은 false). */
|
||||
const pushMarks = (carryEdits = true): void => {
|
||||
deps.shared.lane.set({ structures, pipes: pipeFacilities }, carryEdits);
|
||||
deps.onMarks?.(
|
||||
[...structures, ...pipesToStructureMarks(pipeFacilities)],
|
||||
markTypes,
|
||||
pipeFacilities,
|
||||
);
|
||||
};
|
||||
// 폼 한 벌(계획서 24-3b) — 횡단 보기가 보일 때 폼 알림을 받는 동작만 건다. 상세 옵션 칸은
|
||||
// 한 벌이 보기에 따라 그린다(횡단 보기에서만).
|
||||
const section = sharedStructures(deps.shared);
|
||||
@@ -396,8 +399,10 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
|
||||
]);
|
||||
section.setTypes(types, listPick("b06")); // 표 목록 both + b06(322-1)
|
||||
markTypes = types;
|
||||
deps.shared.lane.setTypes(types);
|
||||
// 저장하지 않고 나갔던 조작분이 있으면 그것으로 화면을 세운다(B05와 같은 규칙).
|
||||
storedStructures = stored.structures;
|
||||
deps.shared.lane.setStored(storedStructures);
|
||||
storedPipes = pipeResponse.pipe_points;
|
||||
structures = readPendingStructures(projectId) ?? stored.structures;
|
||||
const note = staleDefinitionNotice(projectId, stored.definition_version); // 322-2
|
||||
@@ -438,7 +443,7 @@ export function createB06StructuresPanel(deps: B06StructuresPanelDeps): B06Struc
|
||||
if (!pendingPipes) snapOldPipes(projectId);
|
||||
section.setPipeFacilities(pipeFacilities);
|
||||
// 종단 알약 레인 — 구조물 정본 + 계곡 통과 시설(관 정본)을 합쳐 B05 와 같은 표기로.
|
||||
pushMarks();
|
||||
pushMarks(false);
|
||||
// 목록이 늦게 도착하면 그 사이에 고른 시설은 강조될 자리가 없었다 — 다시 세운다
|
||||
// (2026-09-04 사용자 보고: B06 좌측 목록만 하이라이트가 안 붙음). 폼에 아직 아무것도
|
||||
// 없으면 세션에 남은 선택(카드형 — 부재키 없는 측점)도 같은 규칙으로 세운다.
|
||||
|
||||
@@ -670,11 +670,10 @@ export function createSectionView(
|
||||
setStructureEdit(edit) {
|
||||
structureEdit = edit;
|
||||
},
|
||||
setStructureMarks(structures, types, pipes) {
|
||||
setStructureMarks(structures, types) {
|
||||
spanMarks = structures;
|
||||
spanTypes = types;
|
||||
syncSpanHighlights();
|
||||
profile.setMarks(structures, types, pipes);
|
||||
syncSpanHighlights(); // 종단 알약 · 측점선은 시설 줄 한 벌(462)
|
||||
// 검증용 훅 — 알약 레인이 무엇을 받았는지 화면 밖에서 수치로 본다
|
||||
// (`__corridorBuild` 등과 같은 용도).
|
||||
(window as unknown as { __b06Marks?: unknown }).__b06Marks = {
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
*
|
||||
* 옛 위쪽 붙박이 종단(자체 그래프 · 유토곡선 없음 · 흙덮기 막기 없음)을 갈음한다.
|
||||
* 도구(▲▼ · 되돌리기 · 직선화 · 옮기기 · 확대 · 표 · 유토곡선 · 범례 · 뱃지)와 막기 규칙
|
||||
* (최소 흙덮기 · 기울기 상한)은 종단도 한 벌이 맡고, 여기서는 이음만 한다.
|
||||
* (최소 흙덮기 · 기울기 상한)은 종단도 한 벌이 맡고, 여기서는 이음만 한다. 알약 · 측점선 · 흙덮기 관은
|
||||
* 페이지 시설 줄 한 벌(`shared.lane` · 462)이 종단도에 씀 — 여기는 읽기만.
|
||||
* ========================================================================== */
|
||||
|
||||
import type { DesignProfile } from "../A00_Common/design/design_profile";
|
||||
@@ -32,24 +33,13 @@ import type {
|
||||
HaulEquipmentLimit,
|
||||
SectionDetailResponse,
|
||||
} from "./B06_Section_Api_Fetch";
|
||||
import {
|
||||
structureAnchorM,
|
||||
type StructureInstance,
|
||||
type StructureType,
|
||||
} from "../B05_Profile/B05_Profile_Api_Structures";
|
||||
import {
|
||||
irregularStationId,
|
||||
isPipeStation,
|
||||
type IrregularStation,
|
||||
} from "../B05_Profile/B05_Profile_UI_IrregularStations";
|
||||
import { structureAnchorM } from "../B05_Profile/B05_Profile_Api_Structures";
|
||||
import { irregularStationId, isPipeStation } from "../B05_Profile/B05_Profile_UI_IrregularStations";
|
||||
import {
|
||||
isPipeMark,
|
||||
moveMarkById,
|
||||
type SectionStructureEdit,
|
||||
} from "./B06_Section_UI_Section_View_Menu";
|
||||
import { planStations, type PlanPipe } from "../common_util/common_util_structure_station";
|
||||
import { plannedIrregular } from "../A00_Common/design/design_structure_status";
|
||||
import { withPipeIds } from "../A00_Common/design/design_pipe_ids";
|
||||
|
||||
/** 관 · 측점을 같은 자리로 보는 거리(m) — 계획서 24-1 `PIPE_MATCH_M` 과 같은 값. */
|
||||
const MATCH_M = PIPE_MATCH_M;
|
||||
@@ -79,11 +69,6 @@ export interface SectionProfile {
|
||||
haulLimits?: HaulEquipmentLimit[];
|
||||
naturalSpoilMinSlope?: number;
|
||||
}) => void;
|
||||
setMarks: (
|
||||
structures: ReadonlyArray<StructureInstance>,
|
||||
types: ReadonlyArray<StructureType>,
|
||||
pipes?: ReadonlyArray<PlanPipe>,
|
||||
) => void;
|
||||
/** 카드가 바뀌었다 — 유토곡선 · 뱃지만 다시 싣는다(편집 초안은 그대로). */
|
||||
redraw: () => void;
|
||||
/** 카드를 골랐다 — 종단도 선택 표시가 따라간다. */
|
||||
@@ -92,26 +77,6 @@ export interface SectionProfile {
|
||||
selectMark: (structureId: string | null) => void;
|
||||
}
|
||||
|
||||
/** 종단 측점선 = 측점 계획 한 벌(322-3 · 관 · 측점 심는 구조물 모두 · 종단 보기 · 카드와 같은 목록).
|
||||
* 관 구간(독립 기슭막이 시작 · 끝)은 받은 관 목록에서 · 없으면 알약에서 기준만. */
|
||||
function planMarkStations(
|
||||
marks: ReadonlyArray<StructureInstance>,
|
||||
pipes: ReadonlyArray<PlanPipe> | null,
|
||||
types: ReadonlyArray<StructureType>,
|
||||
intervalM: number,
|
||||
): IrregularStation[] {
|
||||
const pipeList =
|
||||
pipes ??
|
||||
marks.filter(isPipeMark).map((mark) => ({
|
||||
chainage_m: structureAnchorM(mark),
|
||||
facility: mark.type_id,
|
||||
options: mark.options,
|
||||
}));
|
||||
const structures = marks.filter((mark) => !isPipeMark(mark));
|
||||
// 덮는 구조물 id = 관 세션 id(323-5 · 알약 id 와 같음)
|
||||
return plannedIrregular(planStations(withPipeIds(pipeList), structures, types), intervalM);
|
||||
}
|
||||
|
||||
/**
|
||||
* 배수유역도에 노선 평면선을 싣는다 — 종단 보기가 두고 간 최신 노선 캐시를 먼저 쓰고,
|
||||
* 없으면 한 번 읽는다(읽기만 · 계산 없음).
|
||||
@@ -143,13 +108,10 @@ export function createSectionProfile(
|
||||
): SectionProfile {
|
||||
let profile: DesignProfile | null = null;
|
||||
let detail: SectionDetailResponse | null = null;
|
||||
let marks: ReadonlyArray<StructureInstance> = [];
|
||||
let markPipes: ReadonlyArray<PlanPipe> | null = null;
|
||||
/** 알약 · 비정규 측점 = 시설 줄 한 벌(462 · 읽기만). */
|
||||
const lane = shared.lane;
|
||||
/** 마지막으로 세운 알약 — 카드 고름이 측점선을 맞출 때 지킬지 가름(53-1). */
|
||||
let markedId: string | null = null;
|
||||
let types: ReadonlyArray<StructureType> = [];
|
||||
let stations: IrregularStation[] = [];
|
||||
let intervalM = 20;
|
||||
/** 마지막으로 받은 관 목록 지문(자리 · 종류 · 관경) — 바뀔 때만 카드를 다시 얹음. */
|
||||
let pipeSignature: string | null = null;
|
||||
|
||||
@@ -166,7 +128,7 @@ export function createSectionProfile(
|
||||
/** 종단도 측점 id → 카드 id. 관 측점(`irregular:`)은 누가거리로 카드를 찾는다. */
|
||||
const cardOf = (stationId: string | null): string | null => {
|
||||
if (stationId === null) return null;
|
||||
const pipe = stations.find((entry) => irregularStationId(entry.id) === stationId);
|
||||
const pipe = lane.stations().find((entry) => irregularStationId(entry.id) === stationId);
|
||||
if (pipe) return nearestCard(pipe.chainage_m)?.station_id ?? null;
|
||||
return stationId;
|
||||
};
|
||||
@@ -180,22 +142,6 @@ export function createSectionProfile(
|
||||
{ from: "map" },
|
||||
);
|
||||
|
||||
const syncMarks = (): void => {
|
||||
if (!profile) return;
|
||||
profile.setStructureTypes([...types]);
|
||||
profile.setStructures([...marks]);
|
||||
stations = planMarkStations(marks, markPipes, types, intervalM);
|
||||
profile.setIrregularStations(stations);
|
||||
// 판(배수유역도)이 없는 보기 — 관 목록을 직접 넘겨 최소 흙덮기를 판정한다.
|
||||
profile.setMinCoverPipes(
|
||||
marks.filter(isPipeMark).map((mark) => ({
|
||||
chainage_m: structureAnchorM(mark),
|
||||
facility: mark.type_id as never,
|
||||
options: mark.options,
|
||||
})),
|
||||
);
|
||||
};
|
||||
|
||||
/** 한 벌 종단도에 횡단 보기 알림을 건다 — 횡단 보기가 보일 때만 이쪽으로 온다. */
|
||||
const build = (): DesignProfile => {
|
||||
bindDesignView(shared, "cross", {
|
||||
@@ -245,7 +191,7 @@ export function createSectionProfile(
|
||||
selectDesign(shared.projectId, NO_SELECTION, { from: ESCAPE_FROM });
|
||||
return;
|
||||
}
|
||||
const hit = marks.find((entry) => entry.structure_id === structureId);
|
||||
const hit = lane.marks().find((entry) => entry.structure_id === structureId);
|
||||
if (!hit) return;
|
||||
const edit = host.edit();
|
||||
if (!isPipeMark(hit) && hit.structure_id && edit) {
|
||||
@@ -253,7 +199,7 @@ export function createSectionProfile(
|
||||
return;
|
||||
}
|
||||
// 측점 없는 관 = 카드 안 고름 · 스크롤 없음 · 그 관 폼 · 알약만(요구 178 · 307)
|
||||
if (edit?.selectPipe && !plantsStation(hit, types)) {
|
||||
if (edit?.selectPipe && !plantsStation(hit, lane.types())) {
|
||||
edit.selectPipe(structureAnchorM(hit));
|
||||
return;
|
||||
}
|
||||
@@ -266,7 +212,7 @@ export function createSectionProfile(
|
||||
const edit = host.edit();
|
||||
if (!edit) return;
|
||||
moveMarkById(structureId, toChainageM, {
|
||||
structures: marks,
|
||||
structures: lane.marks(),
|
||||
stations: detail?.longitudinal.stations ?? [],
|
||||
edit,
|
||||
});
|
||||
@@ -287,10 +233,9 @@ export function createSectionProfile(
|
||||
const fresh = !shared.profile;
|
||||
profile = build();
|
||||
if (fresh) loadRoute(id, profile);
|
||||
syncMarks();
|
||||
}
|
||||
detail = input.detail;
|
||||
intervalM = input.stationInterval;
|
||||
lane.setIntervalM(input.stationInterval);
|
||||
const routeId = Number(route);
|
||||
profile.render(
|
||||
input.detail,
|
||||
@@ -304,13 +249,7 @@ export function createSectionProfile(
|
||||
naturalSpoilMinSlope: input.naturalSpoilMinSlope,
|
||||
});
|
||||
}
|
||||
syncMarks();
|
||||
},
|
||||
setMarks(nextMarks, nextTypes, nextPipes) {
|
||||
marks = nextMarks;
|
||||
types = nextTypes;
|
||||
markPipes = nextPipes ?? null;
|
||||
syncMarks();
|
||||
lane.paint(); // 다시 그린 종단도에 시설 줄(추가 측점이 늦게 왔으면 다시 셈)
|
||||
},
|
||||
redraw() {
|
||||
profile?.redraw();
|
||||
@@ -325,12 +264,14 @@ export function createSectionProfile(
|
||||
profile.setSelectedStation(null);
|
||||
return;
|
||||
}
|
||||
const pipe = stations.find(
|
||||
(entry) => Math.abs(entry.chainage_m - section.chainage_m) < MATCH_M,
|
||||
);
|
||||
const pipe = lane
|
||||
.stations()
|
||||
.find((entry) => Math.abs(entry.chainage_m - section.chainage_m) < MATCH_M);
|
||||
profile.setSelectedStation(pipe ? irregularStationId(pipe.id) : section.station_id);
|
||||
// 일반 측점은 측점선 짝 알약이 없어 꺼짐 — 고른 구조물이 이 측점을 덮으면 그 알약을 지킴(53-1)
|
||||
const marked = markedId ? marks.find((entry) => entry.structure_id === markedId) : undefined;
|
||||
const marked = markedId
|
||||
? lane.marks().find((entry) => entry.structure_id === markedId)
|
||||
: undefined;
|
||||
if (!pipe && marked && coversChainage(marked, section.chainage_m))
|
||||
profile.setSelectedStructure(markedId, true);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user