fix(B06 십자선): 십자선 = 형상과 한 높이(측점 설계 높이) · 원지반 십자선 · 평면 초안 계획선 표본도 초안 종단 (413-1)
- 카드 · B05 오른쪽 판 · [상세] 창 십자선 · 계획 상자 = section.design.design_elevation_m · 설계 없을 때만 종단 표본 - 원지반 십자선(center_z · 원지반 색 · 다른 무리) 먼저 그림 · 겹치면 보라 위 · 확대 보정 둘 다 - [상세] 표 원지반고 = 원지반 십자 · 절성토고 = 둘 다 - 시험 318 · 150 · 164 고쳐 씀 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013QyNXY2TUKXCFMwAca2APG
This commit is contained in:
@@ -24,6 +24,7 @@ import type {
|
||||
PipelineStation,
|
||||
} from "../../A00_Common/design/logic/design_pipeline_types";
|
||||
import type { ProfileAlignment } from "./B05_Profile_UI_Profile_Alignment";
|
||||
import { toDesignProfile } from "./B05_Profile_UI_Profile_Data";
|
||||
import { stationLabel } from "../../common_util/common_util_station";
|
||||
import { stationIdOf } from "./B05_Profile_Pipeline_Grade";
|
||||
|
||||
@@ -212,7 +213,8 @@ export function stationSection(
|
||||
};
|
||||
}
|
||||
|
||||
/** 묶음 출력 → 상세. 저장 상세의 종단 머리(이름 · 계획선 묶음)는 그대로 · 측점 · 지반 · 횡단은 새 노선. */
|
||||
/** 묶음 출력 → 상세. 저장 상세의 종단 머리(이름)는 그대로 · 측점 · 지반 · 횡단 · 계획선 표본은 새 노선
|
||||
* (십자선 대체 높이도 초안 종단 · 413). */
|
||||
export function draftSectionDetail(
|
||||
saved: SectionDetailResponse,
|
||||
ground: GroundOutput,
|
||||
@@ -242,6 +244,7 @@ export function draftSectionDetail(
|
||||
})),
|
||||
stations: sections.map(({ samples: _s, design: _d, preview: _p, ...head }) => head),
|
||||
profile_alignment: profile,
|
||||
design_profiles: [toDesignProfile(profile, saved.longitudinal.design_profiles?.[0])],
|
||||
},
|
||||
cross_sections: sections,
|
||||
balloon_offsets: saved.balloon_offsets,
|
||||
|
||||
@@ -37,6 +37,7 @@ import {
|
||||
type ZoomPanState,
|
||||
} from "../A00_Common/b_svg_zoom_pan";
|
||||
import { buildZoomControls } from "./B06_Section_UI_Cross_View_Zoom";
|
||||
import { unscaleAt } from "./B06_Section_UI_Cross_View_Frame";
|
||||
import { detailHomeView, layerPoints } from "./B06_Section_UI_Cross_Detail_Home";
|
||||
import { attachDetailTable, designForTable, groupSpan } from "./B06_Section_UI_Cross_Detail_Table";
|
||||
import { createCrossAxes, IDENTITY_VIEW, type CrossAxesOptions } from "./B06_Section_UI_Cross_Axes";
|
||||
@@ -209,16 +210,20 @@ export function attachDetailZoom(
|
||||
const [, , width, height] = (clone.getAttribute("viewBox") ?? "").split(/[\s,]+/).map(Number);
|
||||
const axisLayer = clone.querySelector<SVGGElement>("g.b06-chart__axes");
|
||||
const renderAxes = axes && axisLayer ? createCrossAxes(axisLayer, axes) : null;
|
||||
// 십자 중심 = 세로 선 x1 · y1 + 18 · 계획 십자가 첫 보기 중심 · 원지반 십자도 크기 되돌림(413)
|
||||
const centerOf = (marker: Element | null): [number, number] => {
|
||||
const line = marker?.querySelector("line");
|
||||
return [Number(line?.getAttribute("x1")), Number(line?.getAttribute("y1")) + 18];
|
||||
};
|
||||
const marker = layer.querySelector<SVGGElement>("g.b06-chart__center");
|
||||
const markerLine = marker?.querySelector("line");
|
||||
const cx = Number(markerLine?.getAttribute("x1"));
|
||||
const cy = Number(markerLine?.getAttribute("y1")) + 18;
|
||||
const [cx, cy] = centerOf(marker);
|
||||
const ground = layer.querySelector<SVGGElement>("g.b06-chart__ground-center");
|
||||
const [gx, gy] = centerOf(ground);
|
||||
const follow = (state: ZoomPanState): void => {
|
||||
renderAxes?.(state);
|
||||
marker?.setAttribute(
|
||||
"transform",
|
||||
`translate(${cx} ${cy}) scale(${1 / Math.max(state.scale, 1e-6)}) translate(${-cx} ${-cy})`,
|
||||
);
|
||||
marker?.setAttribute("transform", unscaleAt(cx, cy, state.scale));
|
||||
ground?.setAttribute("transform", unscaleAt(gx, gy, state.scale));
|
||||
};
|
||||
follow(initial ?? IDENTITY_VIEW);
|
||||
const plot = {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
* B06_Section_UI_Cross_Detail_Pick.ts
|
||||
* [상세] 수량표 칸 누름 → 그림 복제 안 그 항목 강조(150-4).
|
||||
*
|
||||
* 칸 키 → 그림 요소: 면적 띠(깍기 · 쌓기) · 사토장 선 · 중심 십자(높이 넷) · 보라 판정 선 구역
|
||||
* 칸 키 → 그림 요소: 면적 띠(깍기 · 쌓기) · 사토장 선 · 계획 · 원지반 십자(높이 넷) · 보라 판정 선 구역
|
||||
* (사면 · 노면 · 측구). 판정 선은 화면 좌표라 십자(x(0)) · `data-px-per-m` 로 m 로 되돌려
|
||||
* `crossZoneAt` 으로 가름 — 측구 = 단면유형을 성토 양쪽으로 둬도 절토로 남는 자리.
|
||||
* 편책 · 제근 · 표토제거는 늘 빈칸 = 누름 없음(짝 표에서 뺌) · 대상이 그 카드에 없는 칸 = `presentKeys` 밖.
|
||||
@@ -16,10 +16,10 @@ import { crossZoneAt, type CrossZone } from "./B06_Section_UI_Cross_Design_Pick"
|
||||
type LineZone = CrossZone | "ditch" | "cut_slope";
|
||||
/** 칸 키 → 강조 대상(선택자 = 그 요소 · zone = 그 구역 판정 선). 없는 키 = 누름 없음. */
|
||||
export const DETAIL_TARGETS: Readonly<Record<string, { selector: string } | { zone: LineZone }>> = {
|
||||
ground: { selector: "g.b06-chart__center" },
|
||||
ground: { selector: "g.b06-chart__ground-center" }, // 원지반 십자(413)
|
||||
planned: { selector: "g.b06-chart__center" },
|
||||
fill: { selector: "g.b06-chart__center" },
|
||||
cut: { selector: "g.b06-chart__center" },
|
||||
fill: { selector: "g.b06-chart__center, g.b06-chart__ground-center" },
|
||||
cut: { selector: "g.b06-chart__center, g.b06-chart__ground-center" },
|
||||
cut_soil: { selector: "g.b06-chart__area--cut_soil" },
|
||||
cut_rock: { selector: "g.b06-chart__area--cut_rock" },
|
||||
embankment: { selector: "g.b06-chart__area--fill" },
|
||||
|
||||
@@ -344,7 +344,9 @@ export function createCrossSectionCard(
|
||||
} else {
|
||||
const { sourceSamples, maxOffset, elevationMid, displayMax, pixelsPerMeter, heightPx } =
|
||||
metrics;
|
||||
const hasDesign = designElevation !== undefined && Number.isFinite(designElevation);
|
||||
// 십자선 · 계획 상자 = 형상과 한 높이(그 측점 설계 높이 · 413) · 설계 없을 때만 넘겨받은 종단 표본
|
||||
const designZ = section.design?.design_elevation_m ?? designElevation;
|
||||
const hasDesign = designZ !== undefined && Number.isFinite(designZ);
|
||||
const valid = sourceSamples.filter(validElevation);
|
||||
const exaggeration = Math.max(verticalExaggeration, 0.1);
|
||||
// 좌표 규약(+offset=좌, -offset=우)을 표준 횡단면도 관례에 맞춘다: 진행방향을 바라보는
|
||||
@@ -378,7 +380,7 @@ export function createCrossSectionCard(
|
||||
elevationMid,
|
||||
exaggeration,
|
||||
centerZ: section.center_z ?? null,
|
||||
designZ: hasDesign ? (designElevation as number) : null,
|
||||
designZ: hasDesign ? (designZ as number) : null,
|
||||
});
|
||||
renderAxes(cardZoomStates.get(section.station_id) ?? IDENTITY_VIEW);
|
||||
|
||||
@@ -610,7 +612,8 @@ export function createCrossSectionCard(
|
||||
const scaleCenter = appendCardFrame(svg, plotLayer, {
|
||||
valid,
|
||||
centerX: x(0),
|
||||
designElevation: hasDesign ? (designElevation as number) : null,
|
||||
designElevation: hasDesign ? (designZ as number) : null,
|
||||
groundElevation: section.center_z ?? null,
|
||||
toY: toDisplayY,
|
||||
widthPx,
|
||||
heightPx,
|
||||
|
||||
@@ -15,6 +15,8 @@ export interface CardFrameInput {
|
||||
centerX: number;
|
||||
/** 계획고(없으면 null — 옛 자료는 지반고 폴백). */
|
||||
designElevation: number | null;
|
||||
/** 중심 원지반고(`section.center_z` · 없으면 null = 중심에 가장 가까운 지반고). */
|
||||
groundElevation?: number | null;
|
||||
/** 표고 → 화면 y(높이 배율 반영). */
|
||||
toY: (elevation: number) => number;
|
||||
widthPx: number;
|
||||
@@ -34,27 +36,30 @@ export function appendCardFrame(
|
||||
if (!nearest || Math.abs(sample.offset_m ?? 0) < Math.abs(nearest.offset_m ?? 0)) return sample;
|
||||
return nearest;
|
||||
}, null);
|
||||
const groundElevation = input.groundElevation ?? centerSample?.elevation_m ?? null;
|
||||
// 십자선 = 계획 노선 자리(구 데이터는 지반고 폴백).
|
||||
const centerElevation = hasDesign ? designElevation : (centerSample?.elevation_m ?? null);
|
||||
const centerElevation = hasDesign ? designElevation : groundElevation;
|
||||
const centerY = centerElevation !== null ? toY(centerElevation) : heightPx / 2;
|
||||
const centerMarkerClass = `b06-chart__center-marker${hasDesign ? " b06-chart__center-marker--design" : ""}`;
|
||||
const marker = svgElement("g", { class: "b06-chart__center" });
|
||||
marker.append(
|
||||
svgElement("line", {
|
||||
x1: centerX,
|
||||
y1: centerY - 18,
|
||||
x2: centerX,
|
||||
y2: centerY + 18,
|
||||
class: centerMarkerClass,
|
||||
}),
|
||||
svgElement("line", {
|
||||
x1: centerX - 18,
|
||||
y1: centerY,
|
||||
x2: centerX + 18,
|
||||
y2: centerY,
|
||||
class: centerMarkerClass,
|
||||
}),
|
||||
const cross = (groupClass: string, y: number, lineClass: string): SVGElement => {
|
||||
const group = svgElement("g", { class: groupClass });
|
||||
group.append(
|
||||
svgElement("line", { x1: centerX, y1: y - 18, x2: centerX, y2: y + 18, class: lineClass }),
|
||||
svgElement("line", { x1: centerX - 18, y1: y, x2: centerX + 18, y2: y, class: lineClass }),
|
||||
);
|
||||
return group;
|
||||
};
|
||||
// 원지반 십자선(413) — 계획 십자선보다 먼저(겹치면 보라가 위) · 다른 무리(고름 · 강조 선택자 안 닿음)
|
||||
const groundY = groundElevation !== null ? toY(groundElevation) : null;
|
||||
const ground =
|
||||
hasDesign && groundY !== null
|
||||
? cross("b06-chart__ground-center", groundY, "b06-chart__ground-center-marker")
|
||||
: null;
|
||||
const marker = cross(
|
||||
"b06-chart__center",
|
||||
centerY,
|
||||
`b06-chart__center-marker${hasDesign ? " b06-chart__center-marker--design" : ""}`,
|
||||
);
|
||||
if (ground) plotLayer.append(ground);
|
||||
plotLayer.append(marker);
|
||||
svg.append(
|
||||
svgElement("line", {
|
||||
@@ -79,12 +84,17 @@ export function appendCardFrame(
|
||||
class: "b06-chart__axis-label",
|
||||
}),
|
||||
);
|
||||
// 도형 레이어 배율을 십자선 중심에서 되돌림 — 자리는 따라가고 길이 18px 은 그대로.
|
||||
return (scale) =>
|
||||
marker.setAttribute(
|
||||
"transform",
|
||||
`translate(${centerX} ${centerY}) scale(${1 / Math.max(scale, 1e-6)}) translate(${-centerX} ${-centerY})`,
|
||||
);
|
||||
// 도형 레이어 배율을 십자선 중심에서 되돌림 — 자리는 따라가고 길이 18px 은 그대로(두 십자 모두).
|
||||
return (scale) => {
|
||||
marker.setAttribute("transform", unscaleAt(centerX, centerY, scale));
|
||||
if (ground && groundY !== null)
|
||||
ground.setAttribute("transform", unscaleAt(centerX, groundY, scale));
|
||||
};
|
||||
}
|
||||
|
||||
/** (cx, cy) 를 축으로 배율을 되돌리는 transform — 카드 · [상세] 창 십자선이 같이 씀. */
|
||||
export function unscaleAt(cx: number, cy: number, scale: number): string {
|
||||
return `translate(${cx} ${cy}) scale(${1 / Math.max(scale, 1e-6)}) translate(${-cx} ${-cy})`;
|
||||
}
|
||||
|
||||
/** 원지반선 — 끊긴 샘플(무효 표고)마다 폴리선을 나눠 그린다. `toY` = 표고 → 화면 y(배율 반영). */
|
||||
|
||||
@@ -335,13 +335,13 @@ export function createSectionView(
|
||||
applySelection(previous);
|
||||
};
|
||||
|
||||
/** 십자선이 설 계획고 — 세월교 측점은 구체 위 노면이 월류 높이만큼 낮게 앉으므로
|
||||
* 그만큼 내려 찍는다(2026-08-30 사용자 확정). 하강량은 백엔드가 계획고를 내려
|
||||
* 잡으며 실어 준 값(`design.surface_drop_m`)이고, 원래 노면은 점선이 남긴다. */
|
||||
/** 십자선이 설 계획고 = 그 측점 설계 높이(형상과 한 값 · 413). 설계가 없을 때만 종단 표본 —
|
||||
* 세월교 측점은 월류 높이(`design.surface_drop_m`)만큼 내려 찍는다(2026-08-30 사용자 확정). */
|
||||
const cardDesignElevation = (
|
||||
detail: SectionDetailResponse,
|
||||
section: CrossSection,
|
||||
): number | undefined => {
|
||||
if (section.design?.design_elevation_m !== undefined) return section.design.design_elevation_m;
|
||||
const planZ = designElevationAt(detail.longitudinal.design_profiles, section.chainage_m);
|
||||
if (planZ === undefined) return undefined;
|
||||
return planZ - (section.design?.surface_drop_m ?? 0);
|
||||
|
||||
@@ -85,10 +85,17 @@
|
||||
}
|
||||
|
||||
/* 중심점 고름(356-3) — 십자 자리 투명 원 · 고르면 보라 테두리 · 끌면 좌우. 십자는 누름을 원으로 넘김. */
|
||||
.b06-chart__center {
|
||||
.b06-chart__center,
|
||||
.b06-chart__ground-center {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* 원지반 십자선(413) = 원지반선 색 · 계획 십자선 아래(먼저 그림) */
|
||||
.b06-chart__ground-center-marker {
|
||||
stroke: var(--color-chart-1);
|
||||
stroke-width: 2.5;
|
||||
}
|
||||
|
||||
.b06-chart__center-hit {
|
||||
fill: transparent;
|
||||
stroke: transparent;
|
||||
|
||||
@@ -154,6 +154,7 @@
|
||||
stroke-width: 9;
|
||||
}
|
||||
|
||||
.b06-detail__cad .b06-chart__ground-center.is-active line,
|
||||
.b06-detail__cad .b06-chart__center.is-active line {
|
||||
stroke: var(--color-danger);
|
||||
stroke-width: 3;
|
||||
|
||||
@@ -58,7 +58,9 @@ const matches = (el, selector) => {
|
||||
};
|
||||
function fakeSvg(ppm, x0) {
|
||||
const center = node("g", ["b06-chart__center"]);
|
||||
const ground = node("g", ["b06-chart__ground-center"]); // 원지반 십자(413)
|
||||
const els = [
|
||||
ground,
|
||||
center,
|
||||
node("line", [], { x1: String(x0) }, center),
|
||||
node("g", ["b06-chart__area", "b06-chart__area--cut_soil"]),
|
||||
@@ -104,7 +106,11 @@ const activeOf = (svg) => {
|
||||
if (el.set.has("is-active") && !el.set.has("b06-chart__design-hit"))
|
||||
names.push(
|
||||
[...el.set].find(
|
||||
(c) => c.includes("--") || c === "b06-chart__center" || c === "b06-chart__spoil-fill",
|
||||
(c) =>
|
||||
c.includes("--") ||
|
||||
c === "b06-chart__center" ||
|
||||
c === "b06-chart__ground-center" ||
|
||||
c === "b06-chart__spoil-fill",
|
||||
),
|
||||
);
|
||||
return names;
|
||||
@@ -124,6 +130,8 @@ for (const key of [
|
||||
"embankment",
|
||||
"spoil_fill",
|
||||
"ground",
|
||||
"planned",
|
||||
"cut",
|
||||
"ditch_soil",
|
||||
"grading_cut",
|
||||
"grading_fill",
|
||||
|
||||
@@ -129,14 +129,17 @@ function chart() {
|
||||
const plot = svgElement("g", { class: "b06-chart__plot-layer" });
|
||||
const center = svgElement("g", { class: "b06-chart__center" });
|
||||
center.append(svgElement("line", { x1: 319, y1: 124, x2: 319, y2: 160 }));
|
||||
plot.append(center);
|
||||
// 원지반 십자(413) — 계획 십자보다 먼저 · 중심 319,200
|
||||
const ground = svgElement("g", { class: "b06-chart__ground-center" });
|
||||
ground.append(svgElement("line", { x1: 319, y1: 182, x2: 319, y2: 218 }));
|
||||
plot.append(ground, center);
|
||||
clipGroup.append(plot);
|
||||
svg.append(svgElement("rect"), axes, clipGroup, svgElement("line", { class: "b06-chart__axis" }));
|
||||
return { svg, axes, plot, center };
|
||||
return { svg, axes, plot, center, ground };
|
||||
}
|
||||
const ticks = (axes) =>
|
||||
axes.childNodes.filter((node) => node.tag === "text").map((node) => node.textContent);
|
||||
const { svg, axes, plot: layer, center } = chart();
|
||||
const { svg, axes, plot: layer, center, ground } = chart();
|
||||
let saved;
|
||||
const handle = attachDetailZoom(svg, AXES, undefined, (next) => (saved = next));
|
||||
const ticksBefore = ticks(axes);
|
||||
@@ -194,6 +197,7 @@ out.reset = layer.getAttribute("transform");
|
||||
// 확대 — 십자는 중심에서 배율을 되돌림(크기 그대로)
|
||||
svg.fire("wheel", { clientX: 600, clientY: 300, deltaY: -100 });
|
||||
out.centerTransform = center.getAttribute("transform");
|
||||
out.groundTransform = ground.getAttribute("transform");
|
||||
out.max = (() => {
|
||||
for (let i = 0; i < 60; i++) svg.fire("wheel", { clientX: 600, clientY: 300, deltaY: -100 });
|
||||
return saved.scale;
|
||||
|
||||
@@ -318,6 +318,88 @@ const out = {};
|
||||
};
|
||||
}
|
||||
|
||||
// ── 1b. 십자선 둘(413) — 원지반 먼저 · 계획 나중 · 배율 되돌림 둘 다 ─────────────
|
||||
{
|
||||
const { appendCardFrame } = makeLoader(
|
||||
[
|
||||
B06("B06_Section_UI_Cross_View_Frame"),
|
||||
B06("B06_Section_UI_Section_Common"),
|
||||
path.join(ROOT, "common_util", "common_util_svg.ts"),
|
||||
],
|
||||
{
|
||||
"@config/config_frontend": { PIPE_TYPES: [] },
|
||||
"../B05_Profile/B05_Profile_UI_IrregularStations": { PIPE_DISPLAY_NAME: {} },
|
||||
"@ui/ui_template_locale": {
|
||||
currentLanguageIndex: 0,
|
||||
ui_locales: new Proxy({}, { get: (_t, key) => [String(key)] }),
|
||||
},
|
||||
},
|
||||
)(B06("B06_Section_UI_Cross_View_Frame"));
|
||||
const toY = (z) => (900 - z) * 10;
|
||||
const frame = (designElevation, groundElevation) => {
|
||||
const plot = new FakeNode("g");
|
||||
const scale = appendCardFrame(new FakeNode("svg"), plot, {
|
||||
valid: [{ offset_m: 0.4, elevation_m: 870, valid: true }],
|
||||
centerX: 50,
|
||||
designElevation,
|
||||
groundElevation,
|
||||
toY,
|
||||
widthPx: 480,
|
||||
heightPx: 300,
|
||||
});
|
||||
return { plot, scale };
|
||||
};
|
||||
const midY = (group) => Number(group.querySelector("line").attrs.y1) + 18;
|
||||
const { plot, scale } = frame(878.5, 876.57);
|
||||
scale(2);
|
||||
const [groundG, designG] = plot.children;
|
||||
const bare = frame(null, null).plot;
|
||||
out.crosshair = {
|
||||
order: plot.children.map((node) => node.className),
|
||||
design_y: midY(designG),
|
||||
want_design_y: toY(878.5),
|
||||
ground_y: midY(groundG),
|
||||
want_ground_y: toY(876.57),
|
||||
design_only_ground: bare.querySelector(".b06-chart__ground-center"),
|
||||
scaled: [groundG.attrs.transform, designG.attrs.transform],
|
||||
want_scaled: [toY(876.57), toY(878.5)].map(
|
||||
(y) => `translate(50 ${y}) scale(0.5) translate(-50 ${-y})`,
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
// ── 1c. 평면 초안 상세 = 계획선 표본도 초안 종단(413 · 십자선 대체 높이) ─────────────
|
||||
{
|
||||
const B05 = (name) => path.join(ROOT, "B05_Profile", "logic", `${name}.ts`);
|
||||
const { draftSectionDetail } = makeLoader([
|
||||
B05("B05_Profile_Pipeline_Detail"),
|
||||
B05("B05_Profile_UI_Profile_Data"),
|
||||
])(B05("B05_Profile_Pipeline_Detail"));
|
||||
const draftSamples = [
|
||||
{ chainage_m: 0, elevation_m: 110 },
|
||||
{ chainage_m: 20, elevation_m: 112 },
|
||||
];
|
||||
const saved = {
|
||||
longitudinal: {
|
||||
design_profiles: [
|
||||
{ id: "old", name: "계획선", samples: [{ chainage_m: 0, elevation_m: 100 }] },
|
||||
],
|
||||
},
|
||||
cross_sections: [],
|
||||
balloon_offsets: {},
|
||||
};
|
||||
const detail = draftSectionDetail(
|
||||
saved,
|
||||
{ stations: [], longitudinal: { chainageM: [0, 20], z: [109, 111] } },
|
||||
{ samples: draftSamples, balance: { cut_area_m2: 0, fill_area_m2: 0, net_area_m2: 0 } },
|
||||
null,
|
||||
new Map(),
|
||||
20,
|
||||
);
|
||||
const profile = detail.longitudinal.design_profiles[0];
|
||||
out.draftProfile = { samples: profile.samples, id: profile.id };
|
||||
}
|
||||
|
||||
// ── 2. 아래 띠(318-2 · 318-3) — 중심고 글 없음 · 암 경계 맨 왼쪽 · 토사도 띠 남음 ─────
|
||||
{
|
||||
const control = (cls) => () => {
|
||||
|
||||
@@ -60,7 +60,10 @@ def test_칸마다_그림_강조(out):
|
||||
assert active["cut_rock"] == ["b06-chart__area--cut_rock"]
|
||||
assert active["embankment"] == ["b06-chart__area--fill"]
|
||||
assert "spoil_fill" not in out["targets"] # 사토장 횡단 그림 없음(380-1)
|
||||
assert active["ground"] == ["b06-chart__center"]
|
||||
# 413 — 원지반고 = 원지반 십자 · 계획고 = 계획 십자 · 절성토고 = 둘 다
|
||||
assert active["ground"] == ["b06-chart__ground-center"]
|
||||
assert active["planned"] == ["b06-chart__center"]
|
||||
assert active["cut"] == ["b06-chart__ground-center", "b06-chart__center"]
|
||||
assert active["ditch_soil"] == ["ditch"]
|
||||
assert active["grading_cut"] == ["cutSlope"]
|
||||
assert active["grading_fill"] == ["fillSlope"]
|
||||
|
||||
@@ -56,6 +56,8 @@ def test_축_고정_도형_층만_움직임_눈금_다시(out):
|
||||
assert out["restoredTicksShifted"] is True # 다시 떠도 이어 간 범위로
|
||||
# 확대 — 십자는 중심(319,142 · 칸 가운데)에서 배율 되돌림
|
||||
assert out["centerTransform"].startswith("translate(319 142) scale(0.869")
|
||||
# 413 — 원지반 십자도 자기 중심(319,200)에서 배율 되돌림
|
||||
assert out["groundTransform"].startswith("translate(319 200) scale(0.869")
|
||||
assert out["noAxesHandle"] is True # 축 옵션 없음 = 줌만
|
||||
assert out["noLayer"] is None # 도형 층 없음 = 줌 없음
|
||||
|
||||
@@ -105,7 +107,7 @@ def test_강조_붉은_한_벌_고름_hover_다름_빈칸():
|
||||
for selector in (
|
||||
".b06-detail__cad .b06-chart__area.is-active > polygon {\n fill: color-mix(in srgb, var(--color-danger)",
|
||||
".b06-detail__cad .b06-chart__design-hit.is-active {\n stroke: color-mix(in srgb, var(--color-danger)",
|
||||
".b06-detail__cad .b06-chart__center.is-active line {\n stroke: var(--color-danger);",
|
||||
".b06-detail__cad .b06-chart__ground-center.is-active line,\n.b06-detail__cad .b06-chart__center.is-active line {\n stroke: var(--color-danger);",
|
||||
".b06-detail__qtable .is-picked {\n background: color-mix(in srgb, var(--color-danger) 18%",
|
||||
".b06-detail__qtable [data-key][data-empty] {\n cursor: default;",
|
||||
):
|
||||
|
||||
@@ -135,15 +135,43 @@ def test_center_wired_into_card_and_modal() -> None:
|
||||
assert "centerZ: section.center_z ?? null" in _src(
|
||||
"B06_Section", "B06_Section_UI_Section_View.ts"
|
||||
)
|
||||
# 379-3 계획 상자 = 십자선 계획고(카드 designElevation · 모달 cardDesignElevation)
|
||||
assert "designZ: hasDesign ? (designElevation as number) : null" in _src(
|
||||
"B06_Section", "B06_Section_UI_Cross_View.ts"
|
||||
)
|
||||
assert "designZ: cardDesignElevation(detail, section) ?? null" in _src(
|
||||
"B06_Section", "B06_Section_UI_Section_View.ts"
|
||||
# 379-3 계획 상자 = 십자선 계획고(카드 designZ · 모달 cardDesignElevation)
|
||||
# 413 — 십자선 · 계획 상자 = 그 측점 설계 높이(형상과 한 값) · 설계 없을 때만 종단 표본
|
||||
card = _src("B06_Section", "B06_Section_UI_Cross_View.ts")
|
||||
assert "const designZ = section.design?.design_elevation_m ?? designElevation;" in card
|
||||
assert "designZ: hasDesign ? (designZ as number) : null" in card
|
||||
assert "designElevation: hasDesign ? (designZ as number) : null" in card
|
||||
assert "groundElevation: section.center_z ?? null" in card
|
||||
view = _src("B06_Section", "B06_Section_UI_Section_View.ts")
|
||||
assert "designZ: cardDesignElevation(detail, section) ?? null" in view
|
||||
assert (
|
||||
"if (section.design?.design_elevation_m !== undefined) return section.design.design_elevation_m;"
|
||||
in view
|
||||
)
|
||||
|
||||
|
||||
def test_two_crosshairs(result: dict) -> None:
|
||||
"""413 — 원지반 십자(원지반 색 · 다른 무리) 먼저 · 계획 십자 나중(위) · 높이 = 설계 · 원지반."""
|
||||
cross = result["crosshair"]
|
||||
assert cross["order"] == ["b06-chart__ground-center", "b06-chart__center"]
|
||||
assert abs(cross["design_y"] - cross["want_design_y"]) < 1e-6 # 설계 높이(종단 표본 아님)
|
||||
assert abs(cross["ground_y"] - cross["want_ground_y"]) < 1e-6 # center_z
|
||||
assert cross["design_only_ground"] is None # 설계 없음 = 십자 하나(지반 폴백)
|
||||
assert cross["scaled"] == cross["want_scaled"] # 둘 다 자기 중심에서 배율 되돌림
|
||||
areas = _src("B06_Section", "B06_Section_UI_Style_Cross_Areas.css")
|
||||
assert "var(--color-chart-1)" in _rule(areas, ".b06-chart__ground-center-marker")
|
||||
|
||||
|
||||
def test_draft_detail_profile_is_draft(result: dict) -> None:
|
||||
"""413 — 평면 초안 상세의 계획선 표본 = 초안 종단(저장 종단 아님) · 이름은 저장분 그대로."""
|
||||
draft = result["draftProfile"]
|
||||
assert draft["samples"] == [
|
||||
{"chainage_m": 0, "elevation_m": 110},
|
||||
{"chainage_m": 20, "elevation_m": 112},
|
||||
]
|
||||
assert draft["id"] == "old"
|
||||
|
||||
|
||||
# ── 318-2 · 318-3 양식 ──────────────────────────────────────────────────────
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user