diff --git a/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts b/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts index fa25e4f4d..d99b5f4c2 100644 --- a/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts +++ b/B05_Profile/B05_Profile_UI_Corridor_Structures_Hash.ts @@ -37,9 +37,9 @@ export function structureHashParts(section: CrossSection): Array { - const base = storedAdjusts(owner); + // 세월교 · 박스 흙막이 — 본체 기준 x 를 절대값으로(옆 측점엔 본체가 없음 · 횡단도와 같음 · 73-4) + const ownerBody = owner.culvert?.body + ? computeCulvertLayout( + owner, + owner.samples, + storedAdjusts(owner), + "revet", + owner.design?.basin_adjust, + ) + : null; + const base = ownerBody ? bodyAbsolute(ownerBody) : storedAdjusts(owner); const mine = section.design?.revet_adjust; const counts = owner.design?.extra_wall_counts; const pick = (role: string, fallback?: WallAdjust): WallAdjust => diff --git a/B06_Section/B06_Section_Api_Types.ts b/B06_Section/B06_Section_Api_Types.ts index 9ee4a8d6b..f7fbd928f 100644 --- a/B06_Section/B06_Section_Api_Types.ts +++ b/B06_Section/B06_Section_Api_Types.ts @@ -244,6 +244,8 @@ export interface CulvertSet { /** 기초 축 — "기초유" | "기초버림"(실무 정본 탭 제목). **비어 있으면 터파기를 안 그린다** * — 고르기 전에는 근거가 없다(2026-09-09 사용자 확정 ④). */ foundation?: string | null; + /** 세월교 · 박스 흙막이(73-4) — 자리 기준 본체. 있으면 벽 자동 자리 = 관(세월교) · 본체(박스) 끝. */ + body?: "box" | "ford"; } /** 세월교 날개벽 한쪽 — 횡단면엔 안 보이고 바닥판 연장량만 넘긴다. */ diff --git a/B06_Section/B06_Section_Engine_Culvert.py b/B06_Section/B06_Section_Engine_Culvert.py index 2e685d5d0..f2712cb2d 100644 --- a/B06_Section/B06_Section_Engine_Culvert.py +++ b/B06_Section/B06_Section_Engine_Culvert.py @@ -315,6 +315,36 @@ def _revet_set(options: dict[str, Any] | None) -> dict[str, Any]: } +# 세월교 · 박스 유입 · 유출 구조 칸(73-4) — 「흙막이」면 배관 흙막이와 같은 세트를 함께 얹음. +_GUARD_KEYS = {"box": ("wing_in", "wing_out"), "ford": ("inlet_type", "outlet_type")} + + +def _guard_set(values: dict[str, Any], body: str, diameter_m: float) -> dict[str, Any] | None: + """세월교 · 박스 흙막이 — 독립 기슭막이와 같은 세트 모양(관 숨김) · 자리 = 관 · 본체 끝(73-4). + + 같은 측점에 `culvert` 키로 함께 얹혀 배관 흙막이 길(그림 · 연동 · 경사 · 3D · 면적)을 그대로 탐. + 흙막이를 안 고른 쪽 = 구조 빈 값(안 그림) · 둘 다 아니면 None. TS 짝 `guardSet`. + """ + sides: dict[str, Any] = {} + for role, key in zip(("inlet", "outlet"), _GUARD_KEYS[body]): + guarded = str(values.get(key) or "").strip() == "흙막이" + sides[role] = _revet_side(values, role) if guarded else {"role": role, "structure": ""} + if not any(side["structure"] for side in sides.values()): + return None + return { + "type": "pipe", + "hidden_pipe": True, + "body": body, + "side": "양쪽", + "tiers": 1, + "foundation": None, + "pipe_kind": None, + "diameter_m": diameter_m, + "min_cover_m": 0.0, + **sides, + } + + def _wing_spec(values: dict[str, Any], defaults: dict[str, Any], side: str) -> dict[str, Any]: """날개벽 한쪽 제원 + 그 각도가 만드는 바닥판 연장량. @@ -404,7 +434,7 @@ def _ford_set(options: dict[str, Any] | None) -> dict[str, Any]: ("ford_height_m", "월류 높이", 0.0), ], ) - return { + spec = { "type": "ford", "pipe_kind": str(kind) if kind else None, "diameter_m": round((diameter_mm or 1000.0) / 1000.0, 3), @@ -423,6 +453,10 @@ def _ford_set(options: dict[str, Any] | None) -> dict[str, Any]: + _wing_defaulted(values, wing_in, "in") + _wing_defaulted(values, wing_out, "out"), } + guard = _guard_set(values, "ford", spec["diameter_m"]) + if guard: + spec["guard"] = guard + return spec def _ford_pavement_set(options: dict[str, Any] | None) -> dict[str, Any]: @@ -474,7 +508,7 @@ def _box_set(options: dict[str, Any] | None) -> dict[str, Any]: slab = slab if slab and slab > 0 else FORD_SLAB_THICKNESS_M wing_in = _wing_spec(values, defaults, "in") wing_out = _wing_spec(values, defaults, "out") - return { + spec = { "type": "box", "inner_width_m": inner_width or 2.0, "inner_height_m": inner_height or 2.0, @@ -496,6 +530,15 @@ def _box_set(options: dict[str, Any] | None) -> dict[str, Any]: + _wing_defaulted(values, wing_in, "in") + _wing_defaulted(values, wing_out, "out"), } + guard = _guard_set(values, "box", box_body_height(spec)) + if guard: + spec["guard"] = guard + return spec + + +def box_body_height(box: dict[str, Any]) -> float: + """박스 본체 전체 높이(상판 + 내공 + 저판) — 흙막이 세트의 관경 자리(73-4).""" + return round(box["top_thickness_m"] + box["inner_height_m"] + box["slab_thickness_m"], 3) def load_culvert_sets(project_root: Path) -> dict[float, dict[str, Any]]: @@ -578,6 +621,9 @@ def attach_culvert_sets(project_root: Path, cross_sections: list[dict[str, Any]] **spec, "chainage_m": pipe_chainage, } + # 세월교 · 박스 흙막이(73-4) — 배관 흙막이와 같은 자리(`culvert`)에 함께 얹음. + if spec.get("guard"): + section["culvert"] = {**spec["guard"], "chainage_m": pipe_chainage} attached += 1 break return attached diff --git a/B06_Section/B06_Section_Structure_Layouts.ts b/B06_Section/B06_Section_Structure_Layouts.ts index 726ef7306..8b6e403bb 100644 --- a/B06_Section/B06_Section_Structure_Layouts.ts +++ b/B06_Section/B06_Section_Structure_Layouts.ts @@ -188,8 +188,10 @@ function areaRowOf( // ⇒ **가장 가까운 측점 하나**를 주인으로 본다. 거리로 자르지 않으므로 스냅 폭이 // 바뀌어도 따라가고, 하나만 고르므로 두 번 세지도 않는다. const ownerChainage = pipeOwnerChainage(section, sections); + // 세월교 · 박스 흙막이 세트(73-4)는 관이 아님 — 관 연장을 안 실음. const pipeOwner = !!section.culvert && + !section.culvert.body && (ownerChainage === null || Math.abs(ownerChainage - section.chainage_m) <= CHAINAGE_TOLERANCE_M); const pipeLengthM = pipeOwner ? layouts.culvert?.pipe?.lengthM : undefined; diff --git a/B06_Section/B06_Section_UI_Cross_Body_Guard.ts b/B06_Section/B06_Section_UI_Cross_Body_Guard.ts new file mode 100644 index 000000000..714bfaaf6 --- /dev/null +++ b/B06_Section/B06_Section_UI_Cross_Body_Guard.ts @@ -0,0 +1,150 @@ +/* ============================================================================= + * B06_Section_UI_Cross_Body_Guard.ts + * 세월교 · 박스 유입 · 유출 흙막이(73-4) — 관보호공 흙막이와 **같은 벽 · 같은 자리 규칙**. + * + * 세트는 배관 흙막이와 같은 `section.culvert`(관 숨김 · `body`)로 얹혀 그림 · 연동 · 경사 · 3D · + * 면적 길을 그대로 탐. 다른 점은 자동 자리 하나 — 벽 전면이 관(세월교) · 본체(박스) 끝에 옴 + * (배관 벽 전면이 관 끝인 것과 같음). 좌우 x 는 그 자리 기준 · 상하 d 는 배관과 같은 절대값. + * 본체가 이 측점에 없으면(연동 옆 측점) 배관 규칙 그대로 — 소유 측점 값을 절대값으로 넘겨 받음. + * ========================================================================== */ + +import type { CrossSection, SectionSample } from "./B06_Section_Api_Fetch"; +import { computeBoxLayout, DEFAULT_BOX_SIDE_ADJUST } from "./B06_Section_UI_Cross_Box_Geom"; +import type { BoxLayout } from "./B06_Section_UI_Cross_Box_Geom"; +import { FILL_SLOPE_RATIO_MIN } from "./B06_Section_UI_Cross_Culvert_Const"; +import { outletPipeEnd } from "./B06_Section_UI_Cross_Culvert_Tiers"; +import type { + CulvertDesignTrim, + CulvertLayout, + OffsetPoint, + WallAdjust, + WallLayout, +} from "./B06_Section_UI_Cross_Culvert_Types"; +import { computeFordLayout, DEFAULT_FORD_WALL_ADJUST } from "./B06_Section_UI_Cross_Ford_Geom"; +import type { FordLayout } from "./B06_Section_UI_Cross_Ford_Geom"; +import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall"; + +type Role = "inlet" | "outlet"; + +/** 본체 끝(관 invert · 박스 저판 밑) + 본체 설계선 트림 — 본체가 이 측점에 없으면 null. */ +export interface BodyGuardBase { + ends: Record; + trim: CulvertDesignTrim; +} + +export function bodyGuardBase( + section: CrossSection, + samples: SectionSample[], +): BodyGuardBase | null { + const body = section.culvert?.body; + const adjust = section.design; + if (body === "box" && section.box) { + const layout = computeBoxLayout(section, samples, { + left: { ...DEFAULT_BOX_SIDE_ADJUST, ...(adjust?.box_adjust?.left ?? {}) }, + right: { ...DEFAULT_BOX_SIDE_ADJUST, ...(adjust?.box_adjust?.right ?? {}) }, + }); + if (!layout) return null; + const inletOnLeft = (section.uphill_side ?? "left") === "left"; + const endOf = (role: Role): OffsetPoint | null => { + const side = layout.sides.find( + (s) => (s.role === "left") === ((role === "inlet") === inletOnLeft), + ); + return side ? { offset: side.offset, elevation: side.bottomElevation } : null; + }; + return { ends: { inlet: endOf("inlet"), outlet: endOf("outlet") }, trim: layout.designTrim }; + } + if (body === "ford" && section.ford) { + const layout = computeFordLayout(section, samples, { + inlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(adjust?.ford_adjust?.inlet ?? {}) }, + outlet: { ...DEFAULT_FORD_WALL_ADJUST, ...(adjust?.ford_adjust?.outlet ?? {}) }, + }); + if (!layout) return null; + const endOf = (role: Role): OffsetPoint | null => + layout.sides.find((s) => s.role === role)?.pipeEnd ?? null; + return { ends: { inlet: endOf("inlet"), outlet: endOf("outlet") }, trim: layout.designTrim }; + } + return null; +} + +/** + * 벽 전면을 본체 끝에 맞춘 배관 벽 4축(x · d) — `placePipeWall` 역산. + * 바닥 기준(invert) = 본체 끝 표고 · 상단 = 노견 − d/1.2 · 자리 = 0점 + (x + d). + */ +export function bodyGuardAxes( + end: OffsetPoint, + wall: { + autoOffset: number; + outward: number; + height: number; + edgeElevation: number; + lean: number; + thickness: number; + }, +): { x: number; d: number } { + const d = FILL_SLOPE_RATIO_MIN * (wall.edgeElevation - wall.height - end.elevation); + // 전면 위치는 자리(offset)에 평행이동만 함 — 0 에 세워 재고 옮김(노면 멈춤도 같게). + const probe = buildRevetWallGeometry({ + anchor: { offset: 0, elevation: end.elevation }, + outward: wall.outward, + height: wall.height, + material: "dry", + role: "outlet", + thickness: wall.thickness, + lean: wall.lean, + roadElevation: wall.edgeElevation, + }); + const anchorOffset = end.offset - outletPipeEnd(probe).offset; + return { x: (anchorOffset - wall.autoOffset) * wall.outward - d, d }; +} + +/** 벽이 선 쪽은 흙막이 트림 · 안 선 쪽은 본체 트림(73-4). 벽이 하나도 없으면 null. */ +export function mergeGuardTrim( + guard: CulvertDesignTrim, + body: CulvertDesignTrim, + walls: readonly WallLayout[], +): CulvertDesignTrim | null { + if (!walls.length) return null; + const max = walls.some((w) => w.outward > 0) ? guard : body; + const min = walls.some((w) => w.outward < 0) ? guard : body; + return { + minOffset: min.minOffset, + maxOffset: max.maxOffset, + minElevation: min.minElevation, + maxElevation: max.maxElevation, + minSlope: min.minSlope, + maxSlope: max.maxSlope, + }; +} + +/** 소유 측점 적용값(x = 본체 기준) → 옆 측점이 받을 절대값 — 옆 측점엔 본체가 없음. */ +export function bodyAbsolute(layout: CulvertLayout): CulvertLayout["revetShift"] { + const shift = layout.revetShift; + const bodyX = layout.bodyX; + if (!bodyX) return shift; + const plus = (adjust: WallAdjust, dx: number): WallAdjust => ({ ...adjust, x: adjust.x + dx }); + return { + ...shift, + inlet: plus(shift.inlet, bodyX.inlet), + outlet: plus(shift.outlet, bodyX.outlet), + }; +} + +/** 흙막이가 선 쪽의 본체 성토선을 걷음 — 그 쪽 성토선은 흙막이 벽이 냄(두 줄 방지). */ +export function withoutGuardedFill( + layout: T | null, + culvert: CulvertLayout | null, +): T | null { + if (!layout || !culvert?.culvert.body) return layout; + const guarded = (outward: number): boolean => culvert.walls.some((w) => w.outward === outward); + if ("box" in layout && "topSlab" in layout) { + const sides = layout.sides.map((side) => + guarded(side.role === "left" ? 1 : -1) ? { ...side, fillLine: [] } : side, + ); + return { ...layout, sides }; + } + const ford = layout as FordLayout; + const sides = ford.sides.map((side) => + guarded(side.outward) ? { ...side, fillSegments: [] } : side, + ); + return { ...ford, sides } as T; +} diff --git a/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts b/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts index 1d4fa3768..66eef9cd2 100644 --- a/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts +++ b/B06_Section/B06_Section_UI_Cross_Card_Chrome.ts @@ -68,7 +68,8 @@ function facilityNotes(section: CrossSection): Array<[string, string]> { ]); } const own = section.culvert?.hidden_pipe ? section.culvert : null; - if (own && [own.inlet, own.outlet].some((side) => !side.revet_height_m)) { + // 세월교 · 박스 흙막이(73-4)는 흙막이를 고른 쪽(구조 있음)만 봄 + if (own && [own.inlet, own.outlet].some((side) => side.structure && !side.revet_height_m)) { notes.push([ "⚠ 기슭막이 높이 없음 — 근입만 그림", "독립 기슭막이 높이는 설계자 입력 — 계획홍수위 + 0.5~0.7m(사방기술교본 2-나:141 · 3-가:181) · 비우면 수량도 미확정 · B05 시설 칸에 적으면 그림", diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts index f3e0a9a16..5fd3137a6 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts @@ -22,10 +22,12 @@ import { import type { RevetMaterial } from "./B06_Section_UI_Cross_Culvert_Const"; import { outlineLeanOf } from "./B06_Section_UI_Cross_Lean"; import { buildRevetWallGeometry } from "./B06_Section_UI_Cross_Wall"; +import { bodyGuardAxes, bodyGuardBase, mergeGuardTrim } from "./B06_Section_UI_Cross_Body_Guard"; import { ZERO_ADJUST } from "./B06_Section_UI_Cross_Culvert_Types"; import type { BasinLayout, BasinAdjust, + CulvertDesignTrim, CulvertLayout, EndFace, InletStructureChoice, @@ -152,6 +154,26 @@ export function computeCulvertLayout( }; const inletWallSpec = pipeWallSpec(culvert.inlet, adjInlet); const outletWallSpec = pipeWallSpec(culvert.outlet, adjOutlet); + // 세월교 · 박스 흙막이(73-4) — 자동 자리 = 본체 끝(x 0점 · d 기본값). 본체 없으면 배관 규칙. + const body = culvert.body ? bodyGuardBase(section, groundSamples) : null; + const bodyAxesOf = (role: "inlet" | "outlet", info: typeof inletInfo) => { + const end = body?.ends[role]; + const spec = role === "inlet" ? inletWallSpec : outletWallSpec; + if (!end) return null; + return bodyGuardAxes(end, { + autoOffset: slopeZeroAnchor(info.edge, info.outward, spec.height, spec.lean), + outward: info.outward, + height: spec.height, + edgeElevation: info.edge.elevation_m, + lean: spec.lean, + thickness: REVET_THICKNESS_M, + }); + }; + const inletBody = bodyAxesOf("inlet", inletInfo); + const outletBody = bodyAxesOf("outlet", outletInfo); + const onBody = (adjust: WallAdjust, axes: { x: number; d: number } | null): WallAdjust => + axes ? { ...adjust, x: axes.x + adjust.x, d: adjust.d ?? axes.d } : adjust; + const minX = culvert.body ? Number.NEGATIVE_INFINITY : undefined; // 조정창 선택지 가용성 — 판정은 Basin이 맡는다. const inletOptions = inletChoiceAvailability({ designAt, @@ -214,10 +236,11 @@ export function computeCulvertLayout( edgeElevation: inletInfo.edge.elevation_m, // 독립 기슭막이(관 숨김)는 관 토피·역경사 제약이 없다 — 유입도 노견까지 자유롭게 오르내린다. invertCap: culvert.hidden_pipe ? Number.POSITIVE_INFINITY : invertCap(inletInfo.edge), - adjust: adjInlet, + adjust: onBody(adjInlet, inletBody), defaultD: PIPE_WALL_DEFAULT_RUN_M, + minX, }); - appliedAdjust.inlet.x = placed.x; + appliedAdjust.inlet.x = placed.x - (inletBody?.x ?? 0); appliedAdjust.inlet.d = placed.d; wallVertical.inlet = { height: inletWallSpec.height, @@ -321,7 +344,8 @@ export function computeCulvertLayout( } // 구조 · 형태를 안 고른 배관 벽 = 그리지 않음(54-39 · 조정창 형태가 있으면 그 값) const pickedForm = (spec.role === "inlet" ? adjInlet : adjOutlet).m || spec.revet_form; - if (!culvert.hidden_pipe && (spec.structure !== "기슭막이" || !pickedForm)) return null; + if ((!culvert.hidden_pipe || culvert.body) && (spec.structure !== "기슭막이" || !pickedForm)) + return null; // 형상 = 공용 `buildRevetWallGeometry`(추가·사면안정 흙막이·옹벽과 한 벌). 높이는 // vertical(계산용)이 들고 온다 — 형태별 높이 한계 없음, 윗면은 노면에서 멈춤. const height = vertical?.height ?? revetTargetHeight(diameter); @@ -401,10 +425,11 @@ export function computeCulvertLayout( edgeElevation: outletInfo.edge.elevation_m, // 독립 기슭막이는 양쪽 벽이 독립 — 유출을 유입 invert로 묶는 역경사 클램프를 뺀다. invertCap: culvert.hidden_pipe ? Number.POSITIVE_INFINITY : inlet.elevation, - adjust: adjOutlet, + adjust: onBody(adjOutlet, outletBody), defaultD: PIPE_WALL_DEFAULT_RUN_M, + minX, }); - appliedAdjust.outlet.x = placed.x; + appliedAdjust.outlet.x = placed.x - (outletBody?.x ?? 0); appliedAdjust.outlet.d = placed.d; wallVertical.outlet = { height: outletWallSpec.height, @@ -459,7 +484,7 @@ export function computeCulvertLayout( const outletThickness = REVET_THICKNESS_M; // 손으로 민 벽은 정수 맞춤이 **절대 옮기지 않는다**(2026-08-22) — 표기만 올림한다. // d = null(기본 자리)만 자동으로 본다(2026-08-23 — d는 0점 기준 절대값). - const outletPinned = Math.abs(adjOutlet.x) > 1e-9 || adjOutlet.d != null; + const outletPinned = !!outletBody || Math.abs(adjOutlet.x) > 1e-9 || adjOutlet.d != null; if (outletWall && !outletPinned) { const target = Math.ceil(cutLength(pipeCorners) - 1e-6); const rebuild = (): void => { @@ -608,6 +633,17 @@ export function computeCulvertLayout( extendTrimSlope(drawnFillPoints(extrasForArea), outletInfo.outward); extendTrimSlope(drawnFillPoints(basinExtrasForArea), inletInfo.outward); + const ownTrim: CulvertDesignTrim | null = + walls.length || basin + ? { + minOffset: trimMin, + maxOffset: trimMax, + ...(trimMinElevation != null ? { minElevation: trimMinElevation } : {}), + ...(trimMaxElevation != null ? { maxElevation: trimMaxElevation } : {}), + ...(trimMinSlope ? { minSlope: trimMinSlope } : {}), + ...(trimMaxSlope ? { maxSlope: trimMaxSlope } : {}), + } + : null; const outletWallFinal = walls.find((wall) => wall.role === "outlet") ?? null; const outletSlope = outletWallFinal ? slopeOf(outletWallFinal) : null; @@ -645,16 +681,8 @@ export function computeCulvertLayout( extras: extras.appliedAdjusts, basinExtras: basinExtras.appliedAdjusts, }, - designTrim: - walls.length || basin - ? { - minOffset: trimMin, - maxOffset: trimMax, - ...(trimMinElevation != null ? { minElevation: trimMinElevation } : {}), - ...(trimMaxElevation != null ? { maxElevation: trimMaxElevation } : {}), - ...(trimMinSlope ? { minSlope: trimMinSlope } : {}), - ...(trimMaxSlope ? { maxSlope: trimMaxSlope } : {}), - } - : null, + bodyX: + inletBody || outletBody ? { inlet: inletBody?.x ?? 0, outlet: outletBody?.x ?? 0 } : null, + designTrim: body && ownTrim ? mergeGuardTrim(ownTrim, body.trim, walls) : ownTrim, }; } diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts index 6bc79e34b..c61618231 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts @@ -383,6 +383,8 @@ export function placePipeWall(input: { adjust: WallAdjust; /** d 미지정(null) 시의 기본 자리 — 성토사면 경사길이 4m 지점의 수평 성분. */ defaultD: number; + /** x 하한 — 기본 0(안쪽 금지) · 세월교 · 박스 흙막이는 본체 끝이 0점이라 안 막음(73-4). */ + minX?: number; }): PipeWallPlacement { const top0 = input.baseElevation0 + input.height; const dLow = Math.max( @@ -390,7 +392,7 @@ export function placePipeWall(input: { -FILL_SLOPE_RATIO_MIN * (input.invertCap - (top0 - input.height)), ); const d = Math.max(input.adjust.d ?? input.defaultD, Math.ceil(dLow * 10) / 10); - const x = Math.max(input.adjust.x, 0); + const x = Math.max(input.adjust.x, input.minX ?? 0); const topElevation = top0 - d / FILL_SLOPE_RATIO_MIN; return { x, diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts index 465397788..b18c8abaa 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Types.ts @@ -222,6 +222,8 @@ export interface CulvertLayout { * basinLUAllowed = 집수정 ㄴ·ㄷ형(구조물이 원지반으로 밀고 들어갈 때만). */ inletOptions: { revetAllowed: boolean; basinLUAllowed: boolean }; + /** 세월교 · 박스 흙막이(73-4) — 본체 끝 자리의 배관 4축 x(적용 x 의 0점). 본체 없으면 없음. */ + bodyX?: { inlet: number; outlet: number } | null; } /** 유입측 구조물 사용자 선택 — auto = 규칙 기반 자동 선택. */ export type InletStructureChoice = "auto" | "revet" | "I" | "L" | "U"; diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts index bed3e3864..2c39d8d32 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Wire.ts @@ -4,6 +4,7 @@ * 분리(700줄 제한). 카드가 다시 그려질 때마다 한 번 불린다. * ========================================================================== */ +import { bodyAbsolute } from "./B06_Section_UI_Cross_Body_Guard"; import type { CrossSection, SectionSample } from "./B06_Section_Api_Fetch"; import { computeCulvertLayout } from "./B06_Section_UI_Cross_Culvert"; import type { CulvertLayout, InletStructureChoice, RevetKey } from "./B06_Section_UI_Cross_Culvert"; @@ -426,14 +427,15 @@ export function computeCardCulvert( // 조작값만 넘기면 손대기 전(전부 자동)에는 이 측점이 자기 지형으로 자동 자리를 다시 // 잡아 소유 측점과 어긋난다 — "한 번 움직이면 맞는다"던 증상의 원인(2026-08-24 사용자). const ownerInput = adjustsInput(link.source, revetOffset, extraWalls); - const ownerApplied = - computeCulvertLayout( - link.source, - link.source.samples, - ownerInput, - link.source.culvert?.hidden_pipe ? "revet" : inletStructure?.valueFor(link.source), - inletStructure?.adjustFor(link.source), - )?.revetShift ?? ownerInput; + // 세월교 · 박스 흙막이는 본체 기준 x 를 절대값으로 바꿔 넘김 — 옆 측점엔 본체가 없음(73-4). + const ownerLayout = computeCulvertLayout( + link.source, + link.source.samples, + ownerInput, + link.source.culvert?.hidden_pipe ? "revet" : inletStructure?.valueFor(link.source), + inletStructure?.adjustFor(link.source), + ); + const ownerApplied = ownerLayout ? bodyAbsolute(ownerLayout) : ownerInput; // 연동을 풀어도 **같은 기슭막이**다 — 단 수는 소유 측점 것이고, 이 측점이 손댄 // 벽만 자기 값으로 선다(2026-08-30 사용자). const merged = detached ? detachedAdjusts(section, ownerApplied, revetOffset) : ownerApplied; diff --git a/B06_Section/B06_Section_UI_Cross_View.ts b/B06_Section/B06_Section_UI_Cross_View.ts index 8ae48e147..e16177754 100644 --- a/B06_Section/B06_Section_UI_Cross_View.ts +++ b/B06_Section/B06_Section_UI_Cross_View.ts @@ -7,6 +7,7 @@ * 횡단은 종/횡 공통 Y스케일을 쓰지 않고 카드마다 자체 1:1 ppm으로 스케일한다. * ========================================================================== */ +import { withoutGuardedFill } from "./B06_Section_UI_Cross_Body_Guard"; import type { CrossSection } from "./B06_Section_Api_Fetch"; import { appendCrossAreaBands, @@ -404,8 +405,15 @@ export function createCrossSectionCard( revetLink, ); // 세월교·BOX암거 구체 — 배수관과 그림이 달라 계산·그리기를 따로 탄다(2026-08-25). - const boxLayout = computeBoxLayout(section, section.samples, bodies.boxAdjust()); - const fordLayout = computeFordLayout(section, section.samples, bodies.fordAdjust()); + // 흙막이(73-4)가 선 쪽 본체 성토선은 걷음 — 그 쪽 성토선은 흙막이 벽이 냄. + const boxLayout = withoutGuardedFill( + computeBoxLayout(section, section.samples, bodies.boxAdjust()), + culvertLayout, + ); + const fordLayout = withoutGuardedFill( + computeFordLayout(section, section.samples, bodies.fordAdjust()), + culvertLayout, + ); // 포장층 → 설계선 → 암 경계선 순으로 겹쳐, 설계선이 포장 박스 위에 오게 한다. // 물넘이포장은 노면 자체가 파인 자리라 포장층도 그 바닥을 따른다 — 그렸으면 일반 // 포장 박스는 건너뛴다(두 겹으로 깔리면 색 구분이 사라진다). diff --git a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts index ca64a19e5..96bba9554 100644 --- a/B06_Section/B06_Section_UI_Page_Pipe_Options.ts +++ b/B06_Section/B06_Section_UI_Page_Pipe_Options.ts @@ -6,7 +6,7 @@ * 캐시(`section.culvert`·조정창 제어기)만 고친다 — 영구저장은 [저장]·[확정] 몫이다. * ========================================================================== */ -import { pipeDiameterM } from "@util/common_util_culvert_sets"; +import { guardSet, pipeDiameterM } from "@util/common_util_culvert_sets"; import type { DetailPipeInput } from "../B04_PreProcess/B04_PreProcess_Api_Fetch"; import { PIPE_MATCH_M } from "../A00_Common/design/design_selection"; import type { SectionDetailResponse } from "./B06_Section_Api_Fetch"; @@ -17,7 +17,7 @@ import { revetWallSpec, WALL_MIN_PURE_HEIGHT_M, } from "./B06_Section_UI_Cross_Culvert_Const"; -import type { CrossSection } from "./B06_Section_Api_Fetch"; +import type { CrossSection, CulvertSet } from "./B06_Section_Api_Fetch"; import type { createStationControls } from "./B06_Section_UI_Page_Station_Controls"; type StationControls = ReturnType; @@ -69,16 +69,14 @@ export function applyPipeOptionsToCache( if (!owner) return; // 세월교는 스펙 자리(`section.ford`)가 배수관과 달라 조정창 제어기로 보낸다 — // 로직은 그쪽 것을 쓰고 프론트만 폼 UI다(2026-08-30 사용자 확정). - if (owner.ford) { - applyFordFormOptions(ctx.ford, owner.chainage_m, patch); - return; - } + if (owner.ford) applyFordFormOptions(ctx.ford, owner.chainage_m, patch); // BOX암거도 스펙 자리가 따로다(`section.box`) — 같은 규칙으로 제어기에 보낸다 // (2026-08-30 사용자: 세월교와 같은 문제). - if (owner.box) { - applyBoxFormOptions(ctx.box, owner.chainage_m, patch); - return; - } + else if (owner.box) applyBoxFormOptions(ctx.box, owner.chainage_m, patch); + // 세월교 · 박스 흙막이(73-4) — 폼 칸 전부로 세트를 다시 짓고 아래 배관 흙막이 길(높이 · 형태 · + // 추가 흙막이)을 그대로 탐. 일부만 온 되얹기는 세트를 못 지어 건너뜀. + const body = owner.ford ? "ford" : owner.box ? "box" : null; + if (body && (!whole || !syncBodyGuard(owner, body, patch))) return; const culvert = owner.culvert; if (!culvert) return; const num = (key: string): number | undefined => { @@ -111,7 +109,7 @@ export function applyPipeOptionsToCache( own(side, "revet_length_m", num(`${prefix}_revet_length_m`)); own(side, "revet_before_m", num(`${prefix}_revet_before_m`)); own(side, "revet_after_m", num(`${prefix}_revet_after_m`)); - put(side, "structure", patch[`${prefix}_type`]); + if (!body) put(side, "structure", patch[`${prefix}_type`]); // 세월교 구조 칸 = 흙막이 고르기 } // 배관 벽의 **높이·형태는 스펙이 아니라 조정값**(revet_adjust.h·m)이 정한다 // — `revetWallSpec`이 배관에서는 spec.revet_height_m을 쓰지 않기 때문이다. @@ -144,7 +142,14 @@ export function applyPipeOptionsToCache( }); } } - if (!culvert.hidden_pipe) applySoilTiers(ctx, owner, patch, whole); + // 세월교 · 박스 추가 흙막이 = 폼 상자 수가 유출 다단 수(배관은 횡단이 정함 · 73-4) + const soil = body ? soilCount(patch) : null; + if (soil !== null && soil !== (owner.design?.extra_wall_counts?.outlet ?? 0)) + // 늦게 불러옴 — 흙막이 세트 때만 쓰는 횡단 기하 묶음(배관 폼 길은 안 끌어옴) + void import("../A00_Common/design/design_structure_pipe_calc").then((calc) => + calc.setPipeExtraCount(owner.chainage_m, soil), + ); + if (!culvert.hidden_pipe || body) applySoilTiers(ctx, owner, patch, whole); own(culvert.inlet, "basin_length_m", num("inlet_basin_length_m")); own(culvert.inlet, "basin_before_m", num("inlet_basin_before_m")); own(culvert.inlet, "basin_after_m", num("inlet_basin_after_m")); @@ -165,6 +170,34 @@ export function applyPipeOptionsToCache( } } +/** 세월교 · 박스 흙막이 세트를 폼 칸 전부로 다시 지음(73-4) — 흙막이가 없으면 걷음. */ +function syncBodyGuard( + owner: CrossSection, + body: "box" | "ford", + patch: Record, +): boolean { + const box = owner.box; + const diameter = box + ? box.top_thickness_m + box.inner_height_m + box.slab_thickness_m + : (owner.ford?.diameter_m ?? 1); + const guard = guardSet(patch, body, Number(diameter.toFixed(3))); + if (!guard) delete owner.culvert; + else + owner.culvert = { + ...(guard as unknown as CulvertSet), + chainage_m: ((box ?? owner.ford) as { chainage_m?: number } | undefined)?.chainage_m, + }; + return !!guard; +} + +/** 추가 흙막이 상자 수 — 가장 큰 `soil_add_{n}_*` 의 n. */ +function soilCount(patch: Record): number { + return Math.max( + 0, + ...Object.keys(patch).map((key) => Number(/^soil_add_(\d+)_/.exec(key)?.[1] ?? 0)), + ); +} + /** 흙막이 컨테이너가 마지막으로 보낸 높이 · 형태(`측점:extra{n}`) — 기하가 다시 그릴 때마다 키를 지형에 * 맞춰 고쳐 되받으므로(syncApplied) 되받은 값과 견주면 안 바꾼 단도 다시 보냄(54-10). */ const soilSent = new Map(); diff --git a/common_util/common_util_culvert_sets.ts b/common_util/common_util_culvert_sets.ts index 0781ddd5e..a9d3f3b8c 100644 --- a/common_util/common_util_culvert_sets.ts +++ b/common_util/common_util_culvert_sets.ts @@ -199,6 +199,56 @@ function revetSet(values: Record): CulvertSetSpec { }; } +/** 세월교 · 박스 유입 · 유출 구조 칸(73-4) — 「흙막이」면 배관 흙막이와 같은 세트를 함께 얹음. */ +const GUARD_KEYS: Record<"box" | "ford", [string, string]> = { + box: ["wing_in", "wing_out"], + ford: ["inlet_type", "outlet_type"], +}; + +/** 세월교 · 박스 흙막이 — 독립 기슭막이와 같은 세트 모양(관 숨김) · 자리 = 관 · 본체 끝(73-4). + * 흙막이를 안 고른 쪽 = 구조 빈 값(안 그림) · 둘 다 아니면 null. 파이썬 짝 `_guard_set`. */ +export function guardSet( + values: Record, + body: "box" | "ford", + diameterM: number, +): CulvertSetSpec | null { + const [inletKey, outletKey] = GUARD_KEYS[body]; + const side = (role: string, key: string): CulvertSetSpec => + String(values[key] ?? "").trim() === "흙막이" + ? revetSide(values, role) + : { role, structure: "" }; + const inlet = side("inlet", inletKey); + const outlet = side("outlet", outletKey); + if (!inlet.structure && !outlet.structure) return null; + return { + type: "pipe", + hidden_pipe: true, + body, + side: "양쪽", + tiers: 1, + foundation: null, + pipe_kind: null, + diameter_m: diameterM, + min_cover_m: 0.0, + inlet, + outlet, + }; +} + +/** 박스 본체 전체 높이(상판 + 내공 + 저판) — 흙막이 세트의 관경 자리(파이썬 `wall_body_height`). */ +function boxBodyHeight(box: CulvertSetSpec): number { + return round( + Number(box.top_thickness_m) + Number(box.inner_height_m) + Number(box.slab_thickness_m), + 3, + ); +} + +/** 흙막이가 있으면 세트에 `guard` 로 실음(얹을 때 `culvert` 자리로 감). */ +function withGuard(spec: CulvertSetSpec, guard: CulvertSetSpec | null): CulvertSetSpec { + if (guard) spec.guard = guard; + return spec; +} + /** 관경(㎜) → 관 지름(m). 파이썬 `_culvert_set`·`_ford_set` 과 같은 반올림. */ export function pipeDiameterM(diameterMm: number | null | undefined): number { return round((num(diameterMm, 1000.0) ?? 1000.0) / 1000.0, 3); @@ -296,7 +346,7 @@ function fordSet( const pipeCount = count ? Math.max(Math.trunc(count), 1) : 1; const wingIn = wingSpec(values, defaults, "in"); const wingOut = wingSpec(values, defaults, "out"); - return { + const spec: CulvertSetSpec = { type: "ford", pipe_kind: kind, diameter_m: pipeDiameterM(diameterMm), @@ -321,6 +371,7 @@ function fordSet( ...wingDefaulted(values, wingOut, "out"), ], }; + return withGuard(spec, guardSet(values, "ford", Number(spec.diameter_m))); } /** 물넘이포장 1개소 — 구조물이 아니라 **파인 노면**이라 형상이 다르다. */ @@ -368,7 +419,7 @@ function boxSet( const slab = slabValue && slabValue > 0 ? slabValue : FORD_SLAB_THICKNESS_M; const wingIn = wingSpec(values, defaults, "in"); const wingOut = wingSpec(values, defaults, "out"); - return { + const spec: CulvertSetSpec = { type: "box", inner_width_m: innerWidth || 2.0, inner_height_m: innerHeight || 2.0, @@ -388,6 +439,7 @@ function boxSet( ...wingDefaulted(values, wingOut, "out"), ], }; + return withGuard(spec, guardSet(values, "box", boxBodyHeight(spec))); } /** 관 지점 목록 → 누가거리(소수 2자리)별 세트 제원. */ @@ -453,6 +505,9 @@ export function attachCulvertSets( ...spec, chainage_m: pipeChainage, }; + // 세월교 · 박스 흙막이(73-4) — 배관 흙막이와 같은 자리(`culvert`)에 함께 얹음. + if (spec.guard) + section.culvert = { ...(spec.guard as CulvertSetSpec), chainage_m: pipeChainage }; attached += 1; break; } diff --git a/resources/tester/fixtures/b06_73_4_body_guard_sections.json b/resources/tester/fixtures/b06_73_4_body_guard_sections.json new file mode 100644 index 000000000..f232f12dc --- /dev/null +++ b/resources/tester/fixtures/b06_73_4_body_guard_sections.json @@ -0,0 +1 @@ +{"note": "73-4 세월교(173.09) · 박스(352.14) 흙막이 — 검증_sub7 횡단 상세 일부(서버가 culvert 흙막이 세트를 얹은 꼴)", "cross_sections": [{"station_id": "station_000000160000", "chainage_m": 160, "label": "STA.0+160.000", "kind": "regular", "center_x": 208450.494951, "center_y": 367784.971649, "center_z": 854.214169, "azimuth_deg": 86.169709, "plan_radius_m": null, "curve_outer_side": null, "curve_widening_m": 0, "uphill_side": "right", "frame": {"origin": {"x": 208450.494951, "y": 367784.971649, "z": 854.214169}, "tangent_xy": [0.997766291, 0.066801411], "left_xy": [-0.066801411, 0.997766291], "up_xyz": [0, 0, 1]}, "samples": [{"offset_m": -20, "x": 208451.830979, "y": 367765.016323, "z": 863.241565, "elevation_m": 863.241565, "valid": true}, {"offset_m": -19.5, "x": 208451.797578, "y": 367765.515206, "z": 863.093311, "elevation_m": 863.093311, "valid": true}, {"offset_m": -19, "x": 208451.764178, "y": 367766.01409, "z": 862.907514, "elevation_m": 862.907514, "valid": true}, {"offset_m": -18.5, "x": 208451.730777, "y": 367766.512973, "z": 862.712343, "elevation_m": 862.712343, "valid": true}, {"offset_m": -18, "x": 208451.697376, "y": 367767.011856, "z": 862.433124, "elevation_m": 862.433124, "valid": true}, {"offset_m": -17.5, "x": 208451.663976, "y": 367767.510739, "z": 862.104976, "elevation_m": 862.104976, "valid": true}, {"offset_m": -17, "x": 208451.630575, "y": 367768.009622, "z": 861.826684, "elevation_m": 861.826684, "valid": true}, {"offset_m": -16.5, "x": 208451.597174, "y": 367768.508505, "z": 861.618346, "elevation_m": 861.618346, "valid": true}, {"offset_m": -16, "x": 208451.563774, "y": 367769.007389, "z": 861.357811, "elevation_m": 861.357811, "valid": true}, {"offset_m": -15.5, "x": 208451.530373, "y": 367769.506272, "z": 860.976478, "elevation_m": 860.976478, "valid": true}, {"offset_m": -15, "x": 208451.496972, "y": 367770.005155, "z": 860.610887, "elevation_m": 860.610887, "valid": true}, {"offset_m": -14.5, "x": 208451.463571, "y": 367770.504038, "z": 860.301594, "elevation_m": 860.301594, "valid": true}, {"offset_m": -14, "x": 208451.430171, "y": 367771.002921, "z": 859.990439, "elevation_m": 859.990439, "valid": true}, {"offset_m": -13.5, "x": 208451.39677, "y": 367771.501804, "z": 859.894815, "elevation_m": 859.894815, "valid": true}, {"offset_m": -13, "x": 208451.363369, "y": 367772.000687, "z": 859.800347, "elevation_m": 859.800347, "valid": true}, {"offset_m": -12.5, "x": 208451.329969, "y": 367772.499571, "z": 859.548882, "elevation_m": 859.548882, "valid": true}, {"offset_m": -12, "x": 208451.296568, "y": 367772.998454, "z": 859.290838, "elevation_m": 859.290838, "valid": true}, {"offset_m": -11.5, "x": 208451.263167, "y": 367773.497337, "z": 859.094218, "elevation_m": 859.094218, "valid": true}, {"offset_m": -11, "x": 208451.229766, "y": 367773.99622, "z": 858.915932, "elevation_m": 858.915932, "valid": true}, {"offset_m": -10.5, "x": 208451.196366, "y": 367774.495103, "z": 858.809576, "elevation_m": 858.809576, "valid": true}, {"offset_m": -10, "x": 208451.162965, "y": 367774.993986, "z": 858.743279, "elevation_m": 858.743279, "valid": true}, {"offset_m": -9.5, "x": 208451.129564, "y": 367775.492869, "z": 858.495952, "elevation_m": 858.495952, "valid": true}, {"offset_m": -9, "x": 208451.096164, "y": 367775.991753, "z": 858.002711, "elevation_m": 858.002711, "valid": true}, {"offset_m": -8.5, "x": 208451.062763, "y": 367776.490636, "z": 857.632152, "elevation_m": 857.632152, "valid": true}, {"offset_m": -8, "x": 208451.029362, "y": 367776.989519, "z": 857.571307, "elevation_m": 857.571307, "valid": true}, {"offset_m": -7.5, "x": 208450.995962, "y": 367777.488402, "z": 857.515541, "elevation_m": 857.515541, "valid": true}, {"offset_m": -7, "x": 208450.962561, "y": 367777.987285, "z": 857.48851, "elevation_m": 857.48851, "valid": true}, {"offset_m": -6.5, "x": 208450.92916, "y": 367778.486168, "z": 857.459282, "elevation_m": 857.459282, "valid": true}, {"offset_m": -6, "x": 208450.895759, "y": 367778.985051, "z": 857.480644, "elevation_m": 857.480644, "valid": true}, {"offset_m": -5.5, "x": 208450.862359, "y": 367779.483935, "z": 857.503374, "elevation_m": 857.503374, "valid": true}, {"offset_m": -5, "x": 208450.828958, "y": 367779.982818, "z": 857.207078, "elevation_m": 857.207078, "valid": true}, {"offset_m": -4.5, "x": 208450.795557, "y": 367780.481701, "z": 856.850356, "elevation_m": 856.850356, "valid": true}, {"offset_m": -4, "x": 208450.762157, "y": 367780.980584, "z": 856.194313, "elevation_m": 856.194313, "valid": true}, {"offset_m": -3.5, "x": 208450.728756, "y": 367781.479467, "z": 855.416847, "elevation_m": 855.416847, "valid": true}, {"offset_m": -3, "x": 208450.695355, "y": 367781.97835, "z": 855.105141, "elevation_m": 855.105141, "valid": true}, {"offset_m": -2.5, "x": 208450.661954, "y": 367782.477233, "z": 855.127831, "elevation_m": 855.127831, "valid": true}, {"offset_m": -2, "x": 208450.628554, "y": 367782.976117, "z": 855.080874, "elevation_m": 855.080874, "valid": true}, {"offset_m": -1.5, "x": 208450.595153, "y": 367783.475, "z": 854.929777, "elevation_m": 854.929777, "valid": true}, {"offset_m": -1, "x": 208450.561752, "y": 367783.973883, "z": 854.749455, "elevation_m": 854.749455, "valid": true}, {"offset_m": -0.5, "x": 208450.528352, "y": 367784.472766, "z": 854.46552, "elevation_m": 854.46552, "valid": true}, {"offset_m": 0, "x": 208450.494951, "y": 367784.971649, "z": 854.214169, "elevation_m": 854.214169, "valid": true}, {"offset_m": 0.5, "x": 208450.46155, "y": 367785.470532, "z": 854.199329, "elevation_m": 854.199329, "valid": true}, {"offset_m": 1, "x": 208450.42815, "y": 367785.969415, "z": 854.180136, "elevation_m": 854.180136, "valid": true}, {"offset_m": 1.5, "x": 208450.394749, "y": 367786.468299, "z": 853.800221, "elevation_m": 853.800221, "valid": true}, {"offset_m": 2, "x": 208450.361348, "y": 367786.967182, "z": 853.412411, "elevation_m": 853.412411, "valid": true}, {"offset_m": 2.5, "x": 208450.327947, "y": 367787.466065, "z": 853.134577, "elevation_m": 853.134577, "valid": true}, {"offset_m": 3, "x": 208450.294547, "y": 367787.964948, "z": 852.8818, "elevation_m": 852.8818, "valid": true}, {"offset_m": 3.5, "x": 208450.261146, "y": 367788.463831, "z": 852.776158, "elevation_m": 852.776158, "valid": true}, {"offset_m": 4, "x": 208450.227745, "y": 367788.962714, "z": 852.734177, "elevation_m": 852.734177, "valid": true}, {"offset_m": 4.5, "x": 208450.194345, "y": 367789.461597, "z": 852.580805, "elevation_m": 852.580805, "valid": true}, {"offset_m": 5, "x": 208450.160944, "y": 367789.960481, "z": 852.306824, "elevation_m": 852.306824, "valid": true}, {"offset_m": 5.5, "x": 208450.127543, "y": 367790.459364, "z": 852.090112, "elevation_m": 852.090112, "valid": true}, {"offset_m": 6, "x": 208450.094142, "y": 367790.958247, "z": 851.992487, "elevation_m": 851.992487, "valid": true}, {"offset_m": 6.5, "x": 208450.060742, "y": 367791.45713, "z": 851.820773, "elevation_m": 851.820773, "valid": true}, {"offset_m": 7, "x": 208450.027341, "y": 367791.956013, "z": 851.407195, "elevation_m": 851.407195, "valid": true}, {"offset_m": 7.5, "x": 208449.99394, "y": 367792.454896, "z": 851.010725, "elevation_m": 851.010725, "valid": true}, {"offset_m": 8, "x": 208449.96054, "y": 367792.953779, "z": 850.753363, "elevation_m": 850.753363, "valid": true}, {"offset_m": 8.5, "x": 208449.927139, "y": 367793.452663, "z": 850.512, "elevation_m": 850.512, "valid": true}, {"offset_m": 9, "x": 208449.893738, "y": 367793.951546, "z": 850.169581, "elevation_m": 850.169581, "valid": true}, {"offset_m": 9.5, "x": 208449.860338, "y": 367794.450429, "z": 849.794788, "elevation_m": 849.794788, "valid": true}, {"offset_m": 10, "x": 208449.826937, "y": 367794.949312, "z": 849.591344, "elevation_m": 849.591344, "valid": true}, {"offset_m": 10.5, "x": 208449.793536, "y": 367795.448195, "z": 849.437515, "elevation_m": 849.437515, "valid": true}, {"offset_m": 11, "x": 208449.760135, "y": 367795.947078, "z": 849.313909, "elevation_m": 849.313909, "valid": true}, {"offset_m": 11.5, "x": 208449.726735, "y": 367796.445962, "z": 849.211403, "elevation_m": 849.211403, "valid": true}, {"offset_m": 12, "x": 208449.693334, "y": 367796.944845, "z": 849.114325, "elevation_m": 849.114325, "valid": true}, {"offset_m": 12.5, "x": 208449.659933, "y": 367797.443728, "z": 849.024689, "elevation_m": 849.024689, "valid": true}, {"offset_m": 13, "x": 208449.626533, "y": 367797.942611, "z": 848.851981, "elevation_m": 848.851981, "valid": true}, {"offset_m": 13.5, "x": 208449.593132, "y": 367798.441494, "z": 848.48605, "elevation_m": 848.48605, "valid": true}, {"offset_m": 14, "x": 208449.559731, "y": 367798.940377, "z": 848.102496, "elevation_m": 848.102496, "valid": true}, {"offset_m": 14.5, "x": 208449.52633, "y": 367799.43926, "z": 847.706364, "elevation_m": 847.706364, "valid": true}, {"offset_m": 15, "x": 208449.49293, "y": 367799.938144, "z": 847.322396, "elevation_m": 847.322396, "valid": true}, {"offset_m": 15.5, "x": 208449.459529, "y": 367800.437027, "z": 847.202097, "elevation_m": 847.202097, "valid": true}, {"offset_m": 16, "x": 208449.426128, "y": 367800.93591, "z": 847.088649, "elevation_m": 847.088649, "valid": true}, {"offset_m": 16.5, "x": 208449.392728, "y": 367801.434793, "z": 847.143235, "elevation_m": 847.143235, "valid": true}, {"offset_m": 17, "x": 208449.359327, "y": 367801.933676, "z": 847.243727, "elevation_m": 847.243727, "valid": true}, {"offset_m": 17.5, "x": 208449.325926, "y": 367802.432559, "z": 847.486959, "elevation_m": 847.486959, "valid": true}, {"offset_m": 18, "x": 208449.292526, "y": 367802.931442, "z": 847.768579, "elevation_m": 847.768579, "valid": true}, {"offset_m": 18.5, "x": 208449.259125, "y": 367803.430326, "z": 847.968795, "elevation_m": 847.968795, "valid": true}, {"offset_m": 19, "x": 208449.225724, "y": 367803.929209, "z": 848.127477, "elevation_m": 848.127477, "valid": true}, {"offset_m": 19.5, "x": 208449.192323, "y": 367804.428092, "z": 848.115244, "elevation_m": 848.115244, "valid": true}, {"offset_m": 20, "x": 208449.158923, "y": 367804.926975, "z": 847.844396, "elevation_m": 847.844396, "valid": true}], "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 4, "carriageway_width_m": 3, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 0, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 854.2742}, "right": {"offset_m": -2, "elevation_m": 854.1542}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 854.2592}, "right": {"offset_m": -1.5, "elevation_m": 854.1692}}, "design_elevation_m": 854.2142, "cut_area_m2": 3.7082, "cut_soil_area_m2": 2.5662, "cut_rock_area_m2": 1.142, "cut_rock_kind": "ripping_rock", "fill_area_m2": 1.4537, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 2.393, "slope_unclosed": false, "fill_ground_slope": 0.3598, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 863.2416}, {"offset_m": -19.5, "elevation_m": 863.0933}, {"offset_m": -19, "elevation_m": 862.9075}, {"offset_m": -18.5, "elevation_m": 862.7123}, {"offset_m": -18, "elevation_m": 862.4331}, {"offset_m": -17.5, "elevation_m": 862.105}, {"offset_m": -17, "elevation_m": 861.8267}, {"offset_m": -16.5, "elevation_m": 861.6183}, {"offset_m": -16, "elevation_m": 861.3578}, {"offset_m": -15.5, "elevation_m": 860.9765}, {"offset_m": -15, "elevation_m": 860.6109}, {"offset_m": -14.5, "elevation_m": 860.3016}, {"offset_m": -14, "elevation_m": 859.9904}, {"offset_m": -13.5, "elevation_m": 859.8948}, {"offset_m": -13, "elevation_m": 859.8003}, {"offset_m": -12.5, "elevation_m": 859.5489}, {"offset_m": -12, "elevation_m": 859.2908}, {"offset_m": -11.5, "elevation_m": 859.0942}, {"offset_m": -11, "elevation_m": 858.9159}, {"offset_m": -10.5, "elevation_m": 858.8096}, {"offset_m": -10, "elevation_m": 858.7433}, {"offset_m": -9.5, "elevation_m": 858.496}, {"offset_m": -9, "elevation_m": 858.0027}, {"offset_m": -8.5, "elevation_m": 857.6322}, {"offset_m": -8, "elevation_m": 857.5713}, {"offset_m": -7.5, "elevation_m": 857.5155}, {"offset_m": -7, "elevation_m": 857.4885}, {"offset_m": -6.5, "elevation_m": 857.4593}, {"offset_m": -6, "elevation_m": 857.4806}, {"offset_m": -5.79, "elevation_m": 857.4902}, {"offset_m": -5.5, "elevation_m": 857.2382}, {"offset_m": -5, "elevation_m": 856.7382}, {"offset_m": -4.5, "elevation_m": 856.2382}, {"offset_m": -4, "elevation_m": 855.7382}, {"offset_m": -3.5, "elevation_m": 855.2382}, {"offset_m": -3, "elevation_m": 854.7382}, {"offset_m": -2.8727, "elevation_m": 854.6109}, {"offset_m": -2.69, "elevation_m": 854.1542}, {"offset_m": -2.5, "elevation_m": 853.8619}, {"offset_m": -2.495, "elevation_m": 853.8542}, {"offset_m": -2.195, "elevation_m": 853.8542}, {"offset_m": -2, "elevation_m": 854.1542}, {"offset_m": -1.5, "elevation_m": 854.1692}, {"offset_m": -1, "elevation_m": 854.1842}, {"offset_m": -0.5, "elevation_m": 854.1992}, {"offset_m": 0, "elevation_m": 854.2142}, {"offset_m": 0.5, "elevation_m": 854.2292}, {"offset_m": 1, "elevation_m": 854.2442}, {"offset_m": 1.5, "elevation_m": 854.2592}, {"offset_m": 2, "elevation_m": 854.2742}, {"offset_m": 2.5, "elevation_m": 853.8575}, {"offset_m": 3, "elevation_m": 853.4408}, {"offset_m": 3.5, "elevation_m": 853.0242}, {"offset_m": 3.85, "elevation_m": 852.7468}, {"offset_m": 4, "elevation_m": 852.7342}, {"offset_m": 4.5, "elevation_m": 852.5808}, {"offset_m": 5, "elevation_m": 852.3068}, {"offset_m": 5.5, "elevation_m": 852.0901}, {"offset_m": 6, "elevation_m": 851.9925}, {"offset_m": 6.5, "elevation_m": 851.8208}, {"offset_m": 7, "elevation_m": 851.4072}, {"offset_m": 7.5, "elevation_m": 851.0107}, {"offset_m": 8, "elevation_m": 850.7534}, {"offset_m": 8.5, "elevation_m": 850.512}, {"offset_m": 9, "elevation_m": 850.1696}, {"offset_m": 9.5, "elevation_m": 849.7948}, {"offset_m": 10, "elevation_m": 849.5913}, {"offset_m": 10.5, "elevation_m": 849.4375}, {"offset_m": 11, "elevation_m": 849.3139}, {"offset_m": 11.5, "elevation_m": 849.2114}, {"offset_m": 12, "elevation_m": 849.1143}, {"offset_m": 12.5, "elevation_m": 849.0247}, {"offset_m": 13, "elevation_m": 848.852}, {"offset_m": 13.5, "elevation_m": 848.486}, {"offset_m": 14, "elevation_m": 848.1025}, {"offset_m": 14.5, "elevation_m": 847.7064}, {"offset_m": 15, "elevation_m": 847.3224}, {"offset_m": 15.5, "elevation_m": 847.2021}, {"offset_m": 16, "elevation_m": 847.0886}, {"offset_m": 16.5, "elevation_m": 847.1432}, {"offset_m": 17, "elevation_m": 847.2437}, {"offset_m": 17.5, "elevation_m": 847.487}, {"offset_m": 18, "elevation_m": 847.7686}, {"offset_m": 18.5, "elevation_m": 847.9688}, {"offset_m": 19, "elevation_m": 848.1275}, {"offset_m": 19.5, "elevation_m": 848.1152}, {"offset_m": 20, "elevation_m": 847.8444}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 0.4567, "run_m": 0.1827, "start_offset_m": -2.69, "end_offset_m": -2.8727, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 2.9173, "run_m": 2.9173, "start_offset_m": -2.8727, "end_offset_m": -5.79, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": true}}, {"station_id": "station_000000173087", "chainage_m": 173.087, "label": "STA.0+173.087", "kind": "irregular", "center_x": 208463.552718, "center_y": 367785.845879, "center_z": 850.405918, "azimuth_deg": 86.169709, "plan_radius_m": null, "curve_outer_side": null, "curve_widening_m": 0, "uphill_side": "right", "frame": {"origin": {"x": 208463.552718, "y": 367785.845879, "z": 850.405918}, "tangent_xy": [0.997766291, 0.066801411], "left_xy": [-0.066801411, 0.997766291], "up_xyz": [0, 0, 1]}, "structure": "세월교", "samples": [{"offset_m": -20, "x": 208464.888747, "y": 367765.890553, "z": 861.500953, "elevation_m": 861.500953, "valid": true}, {"offset_m": -19.5, "x": 208464.855346, "y": 367766.389437, "z": 861.26784, "elevation_m": 861.26784, "valid": true}, {"offset_m": -19, "x": 208464.821945, "y": 367766.88832, "z": 860.933241, "elevation_m": 860.933241, "valid": true}, {"offset_m": -18.5, "x": 208464.788544, "y": 367767.387203, "z": 860.448023, "elevation_m": 860.448023, "valid": true}, {"offset_m": -18, "x": 208464.755144, "y": 367767.886086, "z": 860.012182, "elevation_m": 860.012182, "valid": true}, {"offset_m": -17.5, "x": 208464.721743, "y": 367768.384969, "z": 859.748541, "elevation_m": 859.748541, "valid": true}, {"offset_m": -17, "x": 208464.688342, "y": 367768.883852, "z": 859.478487, "elevation_m": 859.478487, "valid": true}, {"offset_m": -16.5, "x": 208464.654942, "y": 367769.382735, "z": 859.130421, "elevation_m": 859.130421, "valid": true}, {"offset_m": -16, "x": 208464.621541, "y": 367769.881619, "z": 858.77664, "elevation_m": 858.77664, "valid": true}, {"offset_m": -15.5, "x": 208464.58814, "y": 367770.380502, "z": 858.437324, "elevation_m": 858.437324, "valid": true}, {"offset_m": -15, "x": 208464.55474, "y": 367770.879385, "z": 858.09591, "elevation_m": 858.09591, "valid": true}, {"offset_m": -14.5, "x": 208464.521339, "y": 367771.378268, "z": 857.860003, "elevation_m": 857.860003, "valid": true}, {"offset_m": -14, "x": 208464.487938, "y": 367771.877151, "z": 857.664679, "elevation_m": 857.664679, "valid": true}, {"offset_m": -13.5, "x": 208464.454537, "y": 367772.376034, "z": 857.499265, "elevation_m": 857.499265, "valid": true}, {"offset_m": -13, "x": 208464.421137, "y": 367772.874917, "z": 857.355929, "elevation_m": 857.355929, "valid": true}, {"offset_m": -12.5, "x": 208464.387736, "y": 367773.373801, "z": 857.094967, "elevation_m": 857.094967, "valid": true}, {"offset_m": -12, "x": 208464.354335, "y": 367773.872684, "z": 856.692089, "elevation_m": 856.692089, "valid": true}, {"offset_m": -11.5, "x": 208464.320935, "y": 367774.371567, "z": 856.33112, "elevation_m": 856.33112, "valid": true}, {"offset_m": -11, "x": 208464.287534, "y": 367774.87045, "z": 856.077588, "elevation_m": 856.077588, "valid": true}, {"offset_m": -10.5, "x": 208464.254133, "y": 367775.369333, "z": 855.802444, "elevation_m": 855.802444, "valid": true}, {"offset_m": -10, "x": 208464.220732, "y": 367775.868216, "z": 855.420394, "elevation_m": 855.420394, "valid": true}, {"offset_m": -9.5, "x": 208464.187332, "y": 367776.367099, "z": 855.04587, "elevation_m": 855.04587, "valid": true}, {"offset_m": -9, "x": 208464.153931, "y": 367776.865983, "z": 854.767402, "elevation_m": 854.767402, "valid": true}, {"offset_m": -8.5, "x": 208464.12053, "y": 367777.364866, "z": 854.496619, "elevation_m": 854.496619, "valid": true}, {"offset_m": -8, "x": 208464.08713, "y": 367777.863749, "z": 854.374453, "elevation_m": 854.374453, "valid": true}, {"offset_m": -7.5, "x": 208464.053729, "y": 367778.362632, "z": 854.261877, "elevation_m": 854.261877, "valid": true}, {"offset_m": -7, "x": 208464.020328, "y": 367778.861515, "z": 853.971892, "elevation_m": 853.971892, "valid": true}, {"offset_m": -6.5, "x": 208463.986928, "y": 367779.360398, "z": 853.599906, "elevation_m": 853.599906, "valid": true}, {"offset_m": -6, "x": 208463.953527, "y": 367779.859281, "z": 853.349176, "elevation_m": 853.349176, "valid": true}, {"offset_m": -5.5, "x": 208463.920126, "y": 367780.358165, "z": 853.204068, "elevation_m": 853.204068, "valid": true}, {"offset_m": -5, "x": 208463.886725, "y": 367780.857048, "z": 853.008237, "elevation_m": 853.008237, "valid": true}, {"offset_m": -4.5, "x": 208463.853325, "y": 367781.355931, "z": 852.746089, "elevation_m": 852.746089, "valid": true}, {"offset_m": -4, "x": 208463.819924, "y": 367781.854814, "z": 852.430016, "elevation_m": 852.430016, "valid": true}, {"offset_m": -3.5, "x": 208463.786523, "y": 367782.353697, "z": 852.00184, "elevation_m": 852.00184, "valid": true}, {"offset_m": -3, "x": 208463.753123, "y": 367782.85258, "z": 851.650323, "elevation_m": 851.650323, "valid": true}, {"offset_m": -2.5, "x": 208463.719722, "y": 367783.351463, "z": 851.641671, "elevation_m": 851.641671, "valid": true}, {"offset_m": -2, "x": 208463.686321, "y": 367783.850347, "z": 851.613019, "elevation_m": 851.613019, "valid": true}, {"offset_m": -1.5, "x": 208463.652921, "y": 367784.34923, "z": 851.354565, "elevation_m": 851.354565, "valid": true}, {"offset_m": -1, "x": 208463.61952, "y": 367784.848113, "z": 851.080552, "elevation_m": 851.080552, "valid": true}, {"offset_m": -0.5, "x": 208463.586119, "y": 367785.346996, "z": 850.742309, "elevation_m": 850.742309, "valid": true}, {"offset_m": 0, "x": 208463.552718, "y": 367785.845879, "z": 850.405918, "elevation_m": 850.405918, "valid": true}, {"offset_m": 0.5, "x": 208463.519318, "y": 367786.344762, "z": 850.122486, "elevation_m": 850.122486, "valid": true}, {"offset_m": 1, "x": 208463.485917, "y": 367786.843646, "z": 849.856791, "elevation_m": 849.856791, "valid": true}, {"offset_m": 1.5, "x": 208463.452516, "y": 367787.342529, "z": 849.529427, "elevation_m": 849.529427, "valid": true}, {"offset_m": 2, "x": 208463.419116, "y": 367787.841412, "z": 849.154462, "elevation_m": 849.154462, "valid": true}, {"offset_m": 2.5, "x": 208463.385715, "y": 367788.340295, "z": 848.861371, "elevation_m": 848.861371, "valid": true}, {"offset_m": 3, "x": 208463.352314, "y": 367788.839178, "z": 848.678735, "elevation_m": 848.678735, "valid": true}, {"offset_m": 3.5, "x": 208463.318913, "y": 367789.338061, "z": 848.514238, "elevation_m": 848.514238, "valid": true}, {"offset_m": 4, "x": 208463.285513, "y": 367789.836944, "z": 848.430505, "elevation_m": 848.430505, "valid": true}, {"offset_m": 4.5, "x": 208463.252112, "y": 367790.335828, "z": 848.321847, "elevation_m": 848.321847, "valid": true}, {"offset_m": 5, "x": 208463.218711, "y": 367790.834711, "z": 848.021278, "elevation_m": 848.021278, "valid": true}, {"offset_m": 5.5, "x": 208463.185311, "y": 367791.333594, "z": 847.720824, "elevation_m": 847.720824, "valid": true}, {"offset_m": 6, "x": 208463.15191, "y": 367791.832477, "z": 847.460532, "elevation_m": 847.460532, "valid": true}, {"offset_m": 6.5, "x": 208463.118509, "y": 367792.33136, "z": 847.210979, "elevation_m": 847.210979, "valid": true}, {"offset_m": 7, "x": 208463.085109, "y": 367792.830243, "z": 846.934503, "elevation_m": 846.934503, "valid": true}, {"offset_m": 7.5, "x": 208463.051708, "y": 367793.329126, "z": 846.651893, "elevation_m": 846.651893, "valid": true}, {"offset_m": 8, "x": 208463.018307, "y": 367793.82801, "z": 846.425758, "elevation_m": 846.425758, "valid": true}, {"offset_m": 8.5, "x": 208462.984906, "y": 367794.326893, "z": 846.22484, "elevation_m": 846.22484, "valid": true}, {"offset_m": 9, "x": 208462.951506, "y": 367794.825776, "z": 846.060983, "elevation_m": 846.060983, "valid": true}, {"offset_m": 9.5, "x": 208462.918105, "y": 367795.324659, "z": 845.933829, "elevation_m": 845.933829, "valid": true}, {"offset_m": 10, "x": 208462.884704, "y": 367795.823542, "z": 845.818223, "elevation_m": 845.818223, "valid": true}, {"offset_m": 10.5, "x": 208462.851304, "y": 367796.322425, "z": 845.726205, "elevation_m": 845.726205, "valid": true}, {"offset_m": 11, "x": 208462.817903, "y": 367796.821308, "z": 845.635364, "elevation_m": 845.635364, "valid": true}, {"offset_m": 11.5, "x": 208462.784502, "y": 367797.320192, "z": 845.50477, "elevation_m": 845.50477, "valid": true}, {"offset_m": 12, "x": 208462.751101, "y": 367797.819075, "z": 845.35957, "elevation_m": 845.35957, "valid": true}, {"offset_m": 12.5, "x": 208462.717701, "y": 367798.317958, "z": 845.135932, "elevation_m": 845.135932, "valid": true}, {"offset_m": 13, "x": 208462.6843, "y": 367798.816841, "z": 844.895146, "elevation_m": 844.895146, "valid": true}, {"offset_m": 13.5, "x": 208462.650899, "y": 367799.315724, "z": 844.653821, "elevation_m": 844.653821, "valid": true}, {"offset_m": 14, "x": 208462.617499, "y": 367799.814607, "z": 844.423066, "elevation_m": 844.423066, "valid": true}, {"offset_m": 14.5, "x": 208462.584098, "y": 367800.31349, "z": 844.067868, "elevation_m": 844.067868, "valid": true}, {"offset_m": 15, "x": 208462.550697, "y": 367800.812374, "z": 843.680126, "elevation_m": 843.680126, "valid": true}, {"offset_m": 15.5, "x": 208462.517297, "y": 367801.311257, "z": 843.37023, "elevation_m": 843.37023, "valid": true}, {"offset_m": 16, "x": 208462.483896, "y": 367801.81014, "z": 843.098992, "elevation_m": 843.098992, "valid": true}, {"offset_m": 16.5, "x": 208462.450495, "y": 367802.309023, "z": 842.909769, "elevation_m": 842.909769, "valid": true}, {"offset_m": 17, "x": 208462.417094, "y": 367802.807906, "z": 842.799491, "elevation_m": 842.799491, "valid": true}, {"offset_m": 17.5, "x": 208462.383694, "y": 367803.306789, "z": 842.673904, "elevation_m": 842.673904, "valid": true}, {"offset_m": 18, "x": 208462.350293, "y": 367803.805672, "z": 842.551884, "elevation_m": 842.551884, "valid": true}, {"offset_m": 18.5, "x": 208462.316892, "y": 367804.304556, "z": 842.443783, "elevation_m": 842.443783, "valid": true}, {"offset_m": 19, "x": 208462.283492, "y": 367804.803439, "z": 842.293135, "elevation_m": 842.293135, "valid": true}, {"offset_m": 19.5, "x": 208462.250091, "y": 367805.302322, "z": 842.130774, "elevation_m": 842.130774, "valid": true}, {"offset_m": 20, "x": 208462.21669, "y": 367805.801205, "z": 841.645163, "elevation_m": 841.645163, "valid": true}], "ford": {"type": "ford", "pipe_kind": "파형강관", "diameter_m": 1, "pipe_count": 2, "span_m": 10, "overflow_depth_m": 0, "slab_thickness_m": 0.3, "wall_thickness_m": 0.2, "min_cover_m": 0.5, "wing_in": {"installed": false, "height_m": 1, "length_m": 2, "angle_deg": 45, "slab_extend_m": 0}, "wing_out": {"installed": false, "height_m": 1, "length_m": 2, "angle_deg": 45, "slab_extend_m": 0}, "defaulted": ["배관 수량 2", "월류 높이 0"], "guard": {"type": "pipe", "hidden_pipe": true, "body": "ford", "side": "양쪽", "tiers": 1, "foundation": null, "pipe_kind": null, "diameter_m": 1, "min_cover_m": 0, "inlet": {"role": "inlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 2.5, "revet_length_m": 10, "revet_before_m": 5, "revet_after_m": 5, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 5, "apron_thickness_m": 0.45}, "outlet": {"role": "outlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 1.5, "revet_length_m": 10, "revet_before_m": 5, "revet_after_m": 5, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 3, "apron_thickness_m": 0.45}}, "chainage_m": 173.09}, "culvert": {"type": "pipe", "hidden_pipe": true, "body": "ford", "side": "양쪽", "tiers": 1, "foundation": null, "pipe_kind": null, "diameter_m": 1, "min_cover_m": 0, "inlet": {"role": "inlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 2.5, "revet_length_m": 10, "revet_before_m": 5, "revet_after_m": 5, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 5, "apron_thickness_m": 0.45}, "outlet": {"role": "outlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 1.5, "revet_length_m": 10, "revet_before_m": 5, "revet_after_m": 5, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 3, "apron_thickness_m": 0.45}, "chainage_m": 173.09}, "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 4, "carriageway_width_m": 3, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 0, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 850.4642}, "right": {"offset_m": -2, "elevation_m": 850.3442}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 850.4492}, "right": {"offset_m": -1.5, "elevation_m": 850.3592}}, "design_elevation_m": 850.4042, "cut_area_m2": 1.3451, "cut_soil_area_m2": 0.8234, "cut_rock_area_m2": 0.5216, "cut_rock_kind": "ripping_rock", "fill_area_m2": 1.224, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 4.3485, "slope_unclosed": false, "fill_ground_slope": 0.3618, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 861.501}, {"offset_m": -19.5, "elevation_m": 861.2678}, {"offset_m": -19, "elevation_m": 860.9332}, {"offset_m": -18.5, "elevation_m": 860.448}, {"offset_m": -18, "elevation_m": 860.0122}, {"offset_m": -17.5, "elevation_m": 859.7485}, {"offset_m": -17, "elevation_m": 859.4785}, {"offset_m": -16.5, "elevation_m": 859.1304}, {"offset_m": -16, "elevation_m": 858.7766}, {"offset_m": -15.5, "elevation_m": 858.4373}, {"offset_m": -15, "elevation_m": 858.0959}, {"offset_m": -14.5, "elevation_m": 857.86}, {"offset_m": -14, "elevation_m": 857.6647}, {"offset_m": -13.5, "elevation_m": 857.4993}, {"offset_m": -13, "elevation_m": 857.3559}, {"offset_m": -12.5, "elevation_m": 857.095}, {"offset_m": -12, "elevation_m": 856.6921}, {"offset_m": -11.5, "elevation_m": 856.3311}, {"offset_m": -11, "elevation_m": 856.0776}, {"offset_m": -10.5, "elevation_m": 855.8024}, {"offset_m": -10, "elevation_m": 855.4204}, {"offset_m": -9.5, "elevation_m": 855.0459}, {"offset_m": -9, "elevation_m": 854.7674}, {"offset_m": -8.5, "elevation_m": 854.4966}, {"offset_m": -8, "elevation_m": 854.3745}, {"offset_m": -7.5, "elevation_m": 854.2619}, {"offset_m": -7, "elevation_m": 853.9719}, {"offset_m": -6.5, "elevation_m": 853.5999}, {"offset_m": -6, "elevation_m": 853.3492}, {"offset_m": -5.5, "elevation_m": 853.2041}, {"offset_m": -5, "elevation_m": 853.0082}, {"offset_m": -4.74, "elevation_m": 852.8719}, {"offset_m": -4.5, "elevation_m": 852.6476}, {"offset_m": -4, "elevation_m": 852.1476}, {"offset_m": -3.5, "elevation_m": 851.6476}, {"offset_m": -3.0189, "elevation_m": 851.1665}, {"offset_m": -3, "elevation_m": 851.1192}, {"offset_m": -2.69, "elevation_m": 850.3442}, {"offset_m": -2.5, "elevation_m": 850.0519}, {"offset_m": -2.495, "elevation_m": 850.0442}, {"offset_m": -2.195, "elevation_m": 850.0442}, {"offset_m": -2, "elevation_m": 850.3442}, {"offset_m": -1.5, "elevation_m": 850.3592}, {"offset_m": -1, "elevation_m": 850.3742}, {"offset_m": -0.5, "elevation_m": 850.3892}, {"offset_m": 0, "elevation_m": 850.4042}, {"offset_m": 0.5, "elevation_m": 850.4192}, {"offset_m": 1, "elevation_m": 850.4342}, {"offset_m": 1.5, "elevation_m": 850.4492}, {"offset_m": 2, "elevation_m": 850.4642}, {"offset_m": 2.5, "elevation_m": 850.0475}, {"offset_m": 3, "elevation_m": 849.6308}, {"offset_m": 3.5, "elevation_m": 849.2142}, {"offset_m": 4, "elevation_m": 848.7975}, {"offset_m": 4.5, "elevation_m": 848.3808}, {"offset_m": 4.8, "elevation_m": 848.1415}, {"offset_m": 5, "elevation_m": 848.0213}, {"offset_m": 5.5, "elevation_m": 847.7208}, {"offset_m": 6, "elevation_m": 847.4605}, {"offset_m": 6.5, "elevation_m": 847.211}, {"offset_m": 7, "elevation_m": 846.9345}, {"offset_m": 7.5, "elevation_m": 846.6519}, {"offset_m": 8, "elevation_m": 846.4258}, {"offset_m": 8.5, "elevation_m": 846.2248}, {"offset_m": 9, "elevation_m": 846.061}, {"offset_m": 9.5, "elevation_m": 845.9338}, {"offset_m": 10, "elevation_m": 845.8182}, {"offset_m": 10.5, "elevation_m": 845.7262}, {"offset_m": 11, "elevation_m": 845.6354}, {"offset_m": 11.5, "elevation_m": 845.5048}, {"offset_m": 12, "elevation_m": 845.3596}, {"offset_m": 12.5, "elevation_m": 845.1359}, {"offset_m": 13, "elevation_m": 844.8951}, {"offset_m": 13.5, "elevation_m": 844.6538}, {"offset_m": 14, "elevation_m": 844.4231}, {"offset_m": 14.5, "elevation_m": 844.0679}, {"offset_m": 15, "elevation_m": 843.6801}, {"offset_m": 15.5, "elevation_m": 843.3702}, {"offset_m": 16, "elevation_m": 843.099}, {"offset_m": 16.5, "elevation_m": 842.9098}, {"offset_m": 17, "elevation_m": 842.7995}, {"offset_m": 17.5, "elevation_m": 842.6739}, {"offset_m": 18, "elevation_m": 842.5519}, {"offset_m": 18.5, "elevation_m": 842.4438}, {"offset_m": 19, "elevation_m": 842.2931}, {"offset_m": 19.5, "elevation_m": 842.1308}, {"offset_m": 20, "elevation_m": 841.6452}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 0.8223, "run_m": 0.3289, "start_offset_m": -2.69, "end_offset_m": -3.0189, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 1.7211, "run_m": 1.7211, "start_offset_m": -3.0189, "end_offset_m": -4.74, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": true}}, {"station_id": "station_000000180000", "chainage_m": 180, "label": "STA.0+180.000", "kind": "regular", "center_x": 208470.450277, "center_y": 367786.307677, "center_z": 849.461398, "azimuth_deg": 86.169709, "plan_radius_m": null, "curve_outer_side": "right", "curve_widening_m": 0.1612, "uphill_side": "right", "frame": {"origin": {"x": 208470.450277, "y": 367786.307677, "z": 849.461398}, "tangent_xy": [0.997766291, 0.066801411], "left_xy": [-0.066801411, 0.997766291], "up_xyz": [0, 0, 1]}, "samples": [{"offset_m": -20, "x": 208471.786305, "y": 367766.352352, "z": 860.529417, "elevation_m": 860.529417, "valid": true}, {"offset_m": -19.5, "x": 208471.752904, "y": 367766.851235, "z": 860.366638, "elevation_m": 860.366638, "valid": true}, {"offset_m": -19, "x": 208471.719504, "y": 367767.350118, "z": 860.205348, "elevation_m": 860.205348, "valid": true}, {"offset_m": -18.5, "x": 208471.686103, "y": 367767.849001, "z": 860.020527, "elevation_m": 860.020527, "valid": true}, {"offset_m": -18, "x": 208471.652702, "y": 367768.347884, "z": 859.806521, "elevation_m": 859.806521, "valid": true}, {"offset_m": -17.5, "x": 208471.619301, "y": 367768.846767, "z": 859.602477, "elevation_m": 859.602477, "valid": true}, {"offset_m": -17, "x": 208471.585901, "y": 367769.34565, "z": 859.188341, "elevation_m": 859.188341, "valid": true}, {"offset_m": -16.5, "x": 208471.5525, "y": 367769.844534, "z": 858.777763, "elevation_m": 858.777763, "valid": true}, {"offset_m": -16, "x": 208471.519099, "y": 367770.343417, "z": 858.506677, "elevation_m": 858.506677, "valid": true}, {"offset_m": -15.5, "x": 208471.485699, "y": 367770.8423, "z": 858.255289, "elevation_m": 858.255289, "valid": true}, {"offset_m": -15, "x": 208471.452298, "y": 367771.341183, "z": 858.13678, "elevation_m": 858.13678, "valid": true}, {"offset_m": -14.5, "x": 208471.418897, "y": 367771.840066, "z": 858.083544, "elevation_m": 858.083544, "valid": true}, {"offset_m": -14, "x": 208471.385497, "y": 367772.338949, "z": 857.843952, "elevation_m": 857.843952, "valid": true}, {"offset_m": -13.5, "x": 208471.352096, "y": 367772.837832, "z": 857.451222, "elevation_m": 857.451222, "valid": true}, {"offset_m": -13, "x": 208471.318695, "y": 367773.336716, "z": 856.995656, "elevation_m": 856.995656, "valid": true}, {"offset_m": -12.5, "x": 208471.285294, "y": 367773.835599, "z": 856.442807, "elevation_m": 856.442807, "valid": true}, {"offset_m": -12, "x": 208471.251894, "y": 367774.334482, "z": 855.987682, "elevation_m": 855.987682, "valid": true}, {"offset_m": -11.5, "x": 208471.218493, "y": 367774.833365, "z": 855.806013, "elevation_m": 855.806013, "valid": true}, {"offset_m": -11, "x": 208471.185092, "y": 367775.332248, "z": 855.621862, "elevation_m": 855.621862, "valid": true}, {"offset_m": -10.5, "x": 208471.151692, "y": 367775.831131, "z": 855.36873, "elevation_m": 855.36873, "valid": true}, {"offset_m": -10, "x": 208471.118291, "y": 367776.330014, "z": 855.10221, "elevation_m": 855.10221, "valid": true}, {"offset_m": -9.5, "x": 208471.08489, "y": 367776.828898, "z": 854.855882, "elevation_m": 854.855882, "valid": true}, {"offset_m": -9, "x": 208471.051489, "y": 367777.327781, "z": 854.632221, "elevation_m": 854.632221, "valid": true}, {"offset_m": -8.5, "x": 208471.018089, "y": 367777.826664, "z": 854.356303, "elevation_m": 854.356303, "valid": true}, {"offset_m": -8, "x": 208470.984688, "y": 367778.325547, "z": 854.069583, "elevation_m": 854.069583, "valid": true}, {"offset_m": -7.5, "x": 208470.951287, "y": 367778.82443, "z": 853.521547, "elevation_m": 853.521547, "valid": true}, {"offset_m": -7, "x": 208470.917887, "y": 367779.323313, "z": 852.814988, "elevation_m": 852.814988, "valid": true}, {"offset_m": -6.5, "x": 208470.884486, "y": 367779.822196, "z": 852.437677, "elevation_m": 852.437677, "valid": true}, {"offset_m": -6, "x": 208470.851085, "y": 367780.32108, "z": 852.379859, "elevation_m": 852.379859, "valid": true}, {"offset_m": -5.5, "x": 208470.817685, "y": 367780.819963, "z": 852.299988, "elevation_m": 852.299988, "valid": true}, {"offset_m": -5, "x": 208470.784284, "y": 367781.318846, "z": 852.197297, "elevation_m": 852.197297, "valid": true}, {"offset_m": -4.5, "x": 208470.750883, "y": 367781.817729, "z": 852.076343, "elevation_m": 852.076343, "valid": true}, {"offset_m": -4, "x": 208470.717482, "y": 367782.316612, "z": 851.891797, "elevation_m": 851.891797, "valid": true}, {"offset_m": -3.5, "x": 208470.684082, "y": 367782.815495, "z": 851.700672, "elevation_m": 851.700672, "valid": true}, {"offset_m": -3, "x": 208470.650681, "y": 367783.314379, "z": 851.4131, "elevation_m": 851.4131, "valid": true}, {"offset_m": -2.5, "x": 208470.61728, "y": 367783.813262, "z": 851.131327, "elevation_m": 851.131327, "valid": true}, {"offset_m": -2, "x": 208470.58388, "y": 367784.312145, "z": 850.984668, "elevation_m": 850.984668, "valid": true}, {"offset_m": -1.5, "x": 208470.550479, "y": 367784.811028, "z": 850.84609, "elevation_m": 850.84609, "valid": true}, {"offset_m": -1, "x": 208470.517078, "y": 367785.309911, "z": 850.373781, "elevation_m": 850.373781, "valid": true}, {"offset_m": -0.5, "x": 208470.483677, "y": 367785.808794, "z": 849.826947, "elevation_m": 849.826947, "valid": true}, {"offset_m": 0, "x": 208470.450277, "y": 367786.307677, "z": 849.461398, "elevation_m": 849.461398, "valid": true}, {"offset_m": 0.5, "x": 208470.416876, "y": 367786.806561, "z": 849.209142, "elevation_m": 849.209142, "valid": true}, {"offset_m": 1, "x": 208470.383475, "y": 367787.305444, "z": 848.811344, "elevation_m": 848.811344, "valid": true}, {"offset_m": 1.5, "x": 208470.350075, "y": 367787.804327, "z": 848.251936, "elevation_m": 848.251936, "valid": true}, {"offset_m": 2, "x": 208470.316674, "y": 367788.30321, "z": 847.74991, "elevation_m": 847.74991, "valid": true}, {"offset_m": 2.5, "x": 208470.283273, "y": 367788.802093, "z": 847.358235, "elevation_m": 847.358235, "valid": true}, {"offset_m": 3, "x": 208470.249873, "y": 367789.300976, "z": 847.009667, "elevation_m": 847.009667, "valid": true}, {"offset_m": 3.5, "x": 208470.216472, "y": 367789.799859, "z": 846.902759, "elevation_m": 846.902759, "valid": true}, {"offset_m": 4, "x": 208470.183071, "y": 367790.298743, "z": 846.789761, "elevation_m": 846.789761, "valid": true}, {"offset_m": 4.5, "x": 208470.14967, "y": 367790.797626, "z": 846.792602, "elevation_m": 846.792602, "valid": true}, {"offset_m": 5, "x": 208470.11627, "y": 367791.296509, "z": 846.794286, "elevation_m": 846.794286, "valid": true}, {"offset_m": 5.5, "x": 208470.082869, "y": 367791.795392, "z": 846.984886, "elevation_m": 846.984886, "valid": true}, {"offset_m": 6, "x": 208470.049468, "y": 367792.294275, "z": 847.202877, "elevation_m": 847.202877, "valid": true}, {"offset_m": 6.5, "x": 208470.016068, "y": 367792.793158, "z": 847.306472, "elevation_m": 847.306472, "valid": true}, {"offset_m": 7, "x": 208469.982667, "y": 367793.292041, "z": 847.364111, "elevation_m": 847.364111, "valid": true}, {"offset_m": 7.5, "x": 208469.949266, "y": 367793.790925, "z": 847.040438, "elevation_m": 847.040438, "valid": true}, {"offset_m": 8, "x": 208469.915865, "y": 367794.289808, "z": 846.444306, "elevation_m": 846.444306, "valid": true}, {"offset_m": 8.5, "x": 208469.882465, "y": 367794.788691, "z": 845.470634, "elevation_m": 845.470634, "valid": true}, {"offset_m": 9, "x": 208469.849064, "y": 367795.287574, "z": 844.047602, "elevation_m": 844.047602, "valid": true}, {"offset_m": 9.5, "x": 208469.815663, "y": 367795.786457, "z": 843.065949, "elevation_m": 843.065949, "valid": true}, {"offset_m": 10, "x": 208469.782263, "y": 367796.28534, "z": 842.992199, "elevation_m": 842.992199, "valid": true}, {"offset_m": 10.5, "x": 208469.748862, "y": 367796.784223, "z": 842.906564, "elevation_m": 842.906564, "valid": true}, {"offset_m": 11, "x": 208469.715461, "y": 367797.283107, "z": 842.728572, "elevation_m": 842.728572, "valid": true}, {"offset_m": 11.5, "x": 208469.682061, "y": 367797.78199, "z": 842.557491, "elevation_m": 842.557491, "valid": true}, {"offset_m": 12, "x": 208469.64866, "y": 367798.280873, "z": 842.196277, "elevation_m": 842.196277, "valid": true}, {"offset_m": 12.5, "x": 208469.615259, "y": 367798.779756, "z": 841.838428, "elevation_m": 841.838428, "valid": true}, {"offset_m": 13, "x": 208469.581858, "y": 367799.278639, "z": 841.559716, "elevation_m": 841.559716, "valid": true}, {"offset_m": 13.5, "x": 208469.548458, "y": 367799.777522, "z": 841.292697, "elevation_m": 841.292697, "valid": true}, {"offset_m": 14, "x": 208469.515057, "y": 367800.276405, "z": 840.969919, "elevation_m": 840.969919, "valid": true}, {"offset_m": 14.5, "x": 208469.481656, "y": 367800.775289, "z": 840.614246, "elevation_m": 840.614246, "valid": true}, {"offset_m": 15, "x": 208469.448256, "y": 367801.274172, "z": 840.33741, "elevation_m": 840.33741, "valid": true}, {"offset_m": 15.5, "x": 208469.414855, "y": 367801.773055, "z": 840.126391, "elevation_m": 840.126391, "valid": true}, {"offset_m": 16, "x": 208469.381454, "y": 367802.271938, "z": 839.983307, "elevation_m": 839.983307, "valid": true}, {"offset_m": 16.5, "x": 208469.348053, "y": 367802.770821, "z": 839.933925, "elevation_m": 839.933925, "valid": true}, {"offset_m": 17, "x": 208469.314653, "y": 367803.269704, "z": 839.820028, "elevation_m": 839.820028, "valid": true}, {"offset_m": 17.5, "x": 208469.281252, "y": 367803.768587, "z": 839.572473, "elevation_m": 839.572473, "valid": true}, {"offset_m": 18, "x": 208469.247851, "y": 367804.267471, "z": 839.349567, "elevation_m": 839.349567, "valid": true}, {"offset_m": 18.5, "x": 208469.214451, "y": 367804.766354, "z": 839.219721, "elevation_m": 839.219721, "valid": true}, {"offset_m": 19, "x": 208469.18105, "y": 367805.265237, "z": 839.084921, "elevation_m": 839.084921, "valid": true}, {"offset_m": 19.5, "x": 208469.147649, "y": 367805.76412, "z": 838.921835, "elevation_m": 838.921835, "valid": true}, {"offset_m": 20, "x": 208469.114249, "y": 367806.263003, "z": 838.756768, "elevation_m": 838.756768, "valid": true}], "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 4.1612, "carriageway_width_m": 3.1612, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 0.1612, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 849.5214}, "right": {"offset_m": -2.1612, "elevation_m": 849.3966}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 849.5064}, "right": {"offset_m": -1.6612, "elevation_m": 849.4116}}, "design_elevation_m": 849.4614, "cut_area_m2": 5.0437, "cut_soil_area_m2": 1.9547, "cut_rock_area_m2": 3.089, "cut_rock_kind": "ripping_rock", "fill_area_m2": 5.3181, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 4.1165, "slope_unclosed": false, "fill_ground_slope": 0.2748, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 860.5294}, {"offset_m": -19.5, "elevation_m": 860.3666}, {"offset_m": -19, "elevation_m": 860.2053}, {"offset_m": -18.5, "elevation_m": 860.0205}, {"offset_m": -18, "elevation_m": 859.8065}, {"offset_m": -17.5, "elevation_m": 859.6025}, {"offset_m": -17, "elevation_m": 859.1883}, {"offset_m": -16.5, "elevation_m": 858.7778}, {"offset_m": -16, "elevation_m": 858.5067}, {"offset_m": -15.5, "elevation_m": 858.2553}, {"offset_m": -15, "elevation_m": 858.1368}, {"offset_m": -14.5, "elevation_m": 858.0835}, {"offset_m": -14, "elevation_m": 857.844}, {"offset_m": -13.5, "elevation_m": 857.4512}, {"offset_m": -13, "elevation_m": 856.9957}, {"offset_m": -12.5, "elevation_m": 856.4428}, {"offset_m": -12, "elevation_m": 855.9877}, {"offset_m": -11.5, "elevation_m": 855.806}, {"offset_m": -11, "elevation_m": 855.6219}, {"offset_m": -10.5, "elevation_m": 855.3687}, {"offset_m": -10, "elevation_m": 855.1022}, {"offset_m": -9.5, "elevation_m": 854.8559}, {"offset_m": -9, "elevation_m": 854.6322}, {"offset_m": -8.5, "elevation_m": 854.3563}, {"offset_m": -8, "elevation_m": 854.0696}, {"offset_m": -7.5, "elevation_m": 853.5215}, {"offset_m": -7, "elevation_m": 852.815}, {"offset_m": -6.5, "elevation_m": 852.4377}, {"offset_m": -6, "elevation_m": 852.3799}, {"offset_m": -5.5, "elevation_m": 852.3}, {"offset_m": -5, "elevation_m": 852.1973}, {"offset_m": -4.5, "elevation_m": 852.0763}, {"offset_m": -4.4012, "elevation_m": 852.0399}, {"offset_m": -4, "elevation_m": 851.6476}, {"offset_m": -3.586, "elevation_m": 851.2335}, {"offset_m": -3.5, "elevation_m": 851.0186}, {"offset_m": -3, "elevation_m": 849.7686}, {"offset_m": -2.8512, "elevation_m": 849.3966}, {"offset_m": -2.6562, "elevation_m": 849.0966}, {"offset_m": -2.5, "elevation_m": 849.0966}, {"offset_m": -2.3562, "elevation_m": 849.0966}, {"offset_m": -2.1612, "elevation_m": 849.3966}, {"offset_m": -2, "elevation_m": 849.4014}, {"offset_m": -1.5, "elevation_m": 849.4164}, {"offset_m": -1, "elevation_m": 849.4314}, {"offset_m": -0.5, "elevation_m": 849.4464}, {"offset_m": 0, "elevation_m": 849.4614}, {"offset_m": 0.5, "elevation_m": 849.4764}, {"offset_m": 1, "elevation_m": 849.4914}, {"offset_m": 1.5, "elevation_m": 849.5064}, {"offset_m": 2, "elevation_m": 849.5214}, {"offset_m": 2.5, "elevation_m": 849.1047}, {"offset_m": 3, "elevation_m": 848.6881}, {"offset_m": 3.5, "elevation_m": 848.2714}, {"offset_m": 4, "elevation_m": 847.8547}, {"offset_m": 4.5, "elevation_m": 847.4381}, {"offset_m": 5, "elevation_m": 847.0214}, {"offset_m": 5.2, "elevation_m": 846.8705}, {"offset_m": 5.5, "elevation_m": 846.9849}, {"offset_m": 6, "elevation_m": 847.2029}, {"offset_m": 6.5, "elevation_m": 847.3065}, {"offset_m": 7, "elevation_m": 847.3641}, {"offset_m": 7.5, "elevation_m": 847.0404}, {"offset_m": 8, "elevation_m": 846.4443}, {"offset_m": 8.5, "elevation_m": 845.4706}, {"offset_m": 9, "elevation_m": 844.0476}, {"offset_m": 9.5, "elevation_m": 843.0659}, {"offset_m": 10, "elevation_m": 842.9922}, {"offset_m": 10.5, "elevation_m": 842.9066}, {"offset_m": 11, "elevation_m": 842.7286}, {"offset_m": 11.5, "elevation_m": 842.5575}, {"offset_m": 12, "elevation_m": 842.1963}, {"offset_m": 12.5, "elevation_m": 841.8384}, {"offset_m": 13, "elevation_m": 841.5597}, {"offset_m": 13.5, "elevation_m": 841.2927}, {"offset_m": 14, "elevation_m": 840.9699}, {"offset_m": 14.5, "elevation_m": 840.6142}, {"offset_m": 15, "elevation_m": 840.3374}, {"offset_m": 15.5, "elevation_m": 840.1264}, {"offset_m": 16, "elevation_m": 839.9833}, {"offset_m": 16.5, "elevation_m": 839.9339}, {"offset_m": 17, "elevation_m": 839.82}, {"offset_m": 17.5, "elevation_m": 839.5725}, {"offset_m": 18, "elevation_m": 839.3496}, {"offset_m": 18.5, "elevation_m": 839.2197}, {"offset_m": 19, "elevation_m": 839.0849}, {"offset_m": 19.5, "elevation_m": 838.9218}, {"offset_m": 20, "elevation_m": 838.7568}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 1.837, "run_m": 0.7348, "start_offset_m": -2.8512, "end_offset_m": -3.586, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 0.8152, "run_m": 0.8152, "start_offset_m": -3.586, "end_offset_m": -4.4012, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": true}}, {"station_id": "station_000000340000", "chainage_m": 340, "label": "STA.0+340.000", "kind": "regular", "center_x": 208588.950746, "center_y": 367740.736204, "center_z": 833.980532, "azimuth_deg": 139.146283, "plan_radius_m": null, "curve_outer_side": "right", "curve_widening_m": 1.317, "uphill_side": "right", "frame": {"origin": {"x": 208588.950746, "y": 367740.736204, "z": 833.980532}, "tangent_xy": [0.654130025, -0.756382119], "left_xy": [0.756382119, 0.654130025], "up_xyz": [0, 0, 1]}, "samples": [{"offset_m": -20, "x": 208573.823104, "y": 367727.653603, "z": 846.841966, "elevation_m": 846.841966, "valid": true}, {"offset_m": -19.5, "x": 208574.201295, "y": 367727.980668, "z": 846.413541, "elevation_m": 846.413541, "valid": true}, {"offset_m": -19, "x": 208574.579486, "y": 367728.307733, "z": 846.095096, "elevation_m": 846.095096, "valid": true}, {"offset_m": -18.5, "x": 208574.957677, "y": 367728.634798, "z": 845.892695, "elevation_m": 845.892695, "valid": true}, {"offset_m": -18, "x": 208575.335868, "y": 367728.961863, "z": 845.553595, "elevation_m": 845.553595, "valid": true}, {"offset_m": -17.5, "x": 208575.714059, "y": 367729.288928, "z": 845.119287, "elevation_m": 845.119287, "valid": true}, {"offset_m": -17, "x": 208576.09225, "y": 367729.615993, "z": 844.580234, "elevation_m": 844.580234, "valid": true}, {"offset_m": -16.5, "x": 208576.470441, "y": 367729.943058, "z": 843.968318, "elevation_m": 843.968318, "valid": true}, {"offset_m": -16, "x": 208576.848632, "y": 367730.270123, "z": 843.521179, "elevation_m": 843.521179, "valid": true}, {"offset_m": -15.5, "x": 208577.226823, "y": 367730.597188, "z": 843.322873, "elevation_m": 843.322873, "valid": true}, {"offset_m": -15, "x": 208577.605014, "y": 367730.924253, "z": 843.249521, "elevation_m": 843.249521, "valid": true}, {"offset_m": -14.5, "x": 208577.983205, "y": 367731.251318, "z": 843.174191, "elevation_m": 843.174191, "valid": true}, {"offset_m": -14, "x": 208578.361396, "y": 367731.578383, "z": 842.851363, "elevation_m": 842.851363, "valid": true}, {"offset_m": -13.5, "x": 208578.739587, "y": 367731.905449, "z": 842.453003, "elevation_m": 842.453003, "valid": true}, {"offset_m": -13, "x": 208579.117778, "y": 367732.232514, "z": 842.114098, "elevation_m": 842.114098, "valid": true}, {"offset_m": -12.5, "x": 208579.495969, "y": 367732.559579, "z": 841.855238, "elevation_m": 841.855238, "valid": true}, {"offset_m": -12, "x": 208579.874161, "y": 367732.886644, "z": 841.60776, "elevation_m": 841.60776, "valid": true}, {"offset_m": -11.5, "x": 208580.252352, "y": 367733.213709, "z": 841.358872, "elevation_m": 841.358872, "valid": true}, {"offset_m": -11, "x": 208580.630543, "y": 367733.540774, "z": 841.028392, "elevation_m": 841.028392, "valid": true}, {"offset_m": -10.5, "x": 208581.008734, "y": 367733.867839, "z": 840.649409, "elevation_m": 840.649409, "valid": true}, {"offset_m": -10, "x": 208581.386925, "y": 367734.194904, "z": 840.37448, "elevation_m": 840.37448, "valid": true}, {"offset_m": -9.5, "x": 208581.765116, "y": 367734.521969, "z": 839.956702, "elevation_m": 839.956702, "valid": true}, {"offset_m": -9, "x": 208582.143307, "y": 367734.849034, "z": 839.463992, "elevation_m": 839.463992, "valid": true}, {"offset_m": -8.5, "x": 208582.521498, "y": 367735.176099, "z": 839.046866, "elevation_m": 839.046866, "valid": true}, {"offset_m": -8, "x": 208582.899689, "y": 367735.503164, "z": 838.981843, "elevation_m": 838.981843, "valid": true}, {"offset_m": -7.5, "x": 208583.27788, "y": 367735.830229, "z": 839.035939, "elevation_m": 839.035939, "valid": true}, {"offset_m": -7, "x": 208583.656071, "y": 367736.157294, "z": 839.121668, "elevation_m": 839.121668, "valid": true}, {"offset_m": -6.5, "x": 208584.034262, "y": 367736.484359, "z": 839.104037, "elevation_m": 839.104037, "valid": true}, {"offset_m": -6, "x": 208584.412453, "y": 367736.811424, "z": 838.907937, "elevation_m": 838.907937, "valid": true}, {"offset_m": -5.5, "x": 208584.790644, "y": 367737.138489, "z": 838.291196, "elevation_m": 838.291196, "valid": true}, {"offset_m": -5, "x": 208585.168835, "y": 367737.465554, "z": 837.379341, "elevation_m": 837.379341, "valid": true}, {"offset_m": -4.5, "x": 208585.547026, "y": 367737.792619, "z": 836.414931, "elevation_m": 836.414931, "valid": true}, {"offset_m": -4, "x": 208585.925217, "y": 367738.119684, "z": 836.270266, "elevation_m": 836.270266, "valid": true}, {"offset_m": -3.5, "x": 208586.303409, "y": 367738.446749, "z": 836.186795, "elevation_m": 836.186795, "valid": true}, {"offset_m": -3, "x": 208586.6816, "y": 367738.773814, "z": 835.796121, "elevation_m": 835.796121, "valid": true}, {"offset_m": -2.5, "x": 208587.059791, "y": 367739.100879, "z": 835.450706, "elevation_m": 835.450706, "valid": true}, {"offset_m": -2, "x": 208587.437982, "y": 367739.427944, "z": 835.219705, "elevation_m": 835.219705, "valid": true}, {"offset_m": -1.5, "x": 208587.816173, "y": 367739.755009, "z": 835.114459, "elevation_m": 835.114459, "valid": true}, {"offset_m": -1, "x": 208588.194364, "y": 367740.082074, "z": 834.802698, "elevation_m": 834.802698, "valid": true}, {"offset_m": -0.5, "x": 208588.572555, "y": 367740.409139, "z": 834.380261, "elevation_m": 834.380261, "valid": true}, {"offset_m": 0, "x": 208588.950746, "y": 367740.736204, "z": 833.980532, "elevation_m": 833.980532, "valid": true}, {"offset_m": 0.5, "x": 208589.328937, "y": 367741.063269, "z": 833.44064, "elevation_m": 833.44064, "valid": true}, {"offset_m": 1, "x": 208589.707128, "y": 367741.390334, "z": 832.903406, "elevation_m": 832.903406, "valid": true}, {"offset_m": 1.5, "x": 208590.085319, "y": 367741.717399, "z": 832.406548, "elevation_m": 832.406548, "valid": true}, {"offset_m": 2, "x": 208590.46351, "y": 367742.044464, "z": 832.05145, "elevation_m": 832.05145, "valid": true}, {"offset_m": 2.5, "x": 208590.841701, "y": 367742.371529, "z": 831.748925, "elevation_m": 831.748925, "valid": true}, {"offset_m": 3, "x": 208591.219892, "y": 367742.698594, "z": 831.454741, "elevation_m": 831.454741, "valid": true}, {"offset_m": 3.5, "x": 208591.598083, "y": 367743.025659, "z": 831.225139, "elevation_m": 831.225139, "valid": true}, {"offset_m": 4, "x": 208591.976274, "y": 367743.352724, "z": 830.989327, "elevation_m": 830.989327, "valid": true}, {"offset_m": 4.5, "x": 208592.354466, "y": 367743.679789, "z": 830.713765, "elevation_m": 830.713765, "valid": true}, {"offset_m": 5, "x": 208592.732657, "y": 367744.006854, "z": 830.455586, "elevation_m": 830.455586, "valid": true}, {"offset_m": 5.5, "x": 208593.110848, "y": 367744.333919, "z": 830.190673, "elevation_m": 830.190673, "valid": true}, {"offset_m": 6, "x": 208593.489039, "y": 367744.660984, "z": 829.852543, "elevation_m": 829.852543, "valid": true}, {"offset_m": 6.5, "x": 208593.86723, "y": 367744.988049, "z": 829.423385, "elevation_m": 829.423385, "valid": true}, {"offset_m": 7, "x": 208594.245421, "y": 367745.315114, "z": 828.92854, "elevation_m": 828.92854, "valid": true}, {"offset_m": 7.5, "x": 208594.623612, "y": 367745.642179, "z": 828.688231, "elevation_m": 828.688231, "valid": true}, {"offset_m": 8, "x": 208595.001803, "y": 367745.969244, "z": 828.503286, "elevation_m": 828.503286, "valid": true}, {"offset_m": 8.5, "x": 208595.379994, "y": 367746.296309, "z": 828.355168, "elevation_m": 828.355168, "valid": true}, {"offset_m": 9, "x": 208595.758185, "y": 367746.623374, "z": 828.189545, "elevation_m": 828.189545, "valid": true}, {"offset_m": 9.5, "x": 208596.136376, "y": 367746.950439, "z": 827.973002, "elevation_m": 827.973002, "valid": true}, {"offset_m": 10, "x": 208596.514567, "y": 367747.277504, "z": 827.706158, "elevation_m": 827.706158, "valid": true}, {"offset_m": 10.5, "x": 208596.892758, "y": 367747.604569, "z": 827.50769, "elevation_m": 827.50769, "valid": true}, {"offset_m": 11, "x": 208597.270949, "y": 367747.931634, "z": 827.404407, "elevation_m": 827.404407, "valid": true}, {"offset_m": 11.5, "x": 208597.64914, "y": 367748.258699, "z": 827.363045, "elevation_m": 827.363045, "valid": true}, {"offset_m": 12, "x": 208598.027331, "y": 367748.585764, "z": 827.310618, "elevation_m": 827.310618, "valid": true}, {"offset_m": 12.5, "x": 208598.405522, "y": 367748.912829, "z": 827.158039, "elevation_m": 827.158039, "valid": true}, {"offset_m": 13, "x": 208598.783714, "y": 367749.239894, "z": 826.860103, "elevation_m": 826.860103, "valid": true}, {"offset_m": 13.5, "x": 208599.161905, "y": 367749.566959, "z": 826.454031, "elevation_m": 826.454031, "valid": true}, {"offset_m": 14, "x": 208599.540096, "y": 367749.894024, "z": 826.019801, "elevation_m": 826.019801, "valid": true}, {"offset_m": 14.5, "x": 208599.918287, "y": 367750.221089, "z": 825.760189, "elevation_m": 825.760189, "valid": true}, {"offset_m": 15, "x": 208600.296478, "y": 367750.548154, "z": 825.595865, "elevation_m": 825.595865, "valid": true}, {"offset_m": 15.5, "x": 208600.674669, "y": 367750.875219, "z": 825.45536, "elevation_m": 825.45536, "valid": true}, {"offset_m": 16, "x": 208601.05286, "y": 367751.202284, "z": 825.43772, "elevation_m": 825.43772, "valid": true}, {"offset_m": 16.5, "x": 208601.431051, "y": 367751.529349, "z": 825.472859, "elevation_m": 825.472859, "valid": true}, {"offset_m": 17, "x": 208601.809242, "y": 367751.856414, "z": 825.515732, "elevation_m": 825.515732, "valid": true}, {"offset_m": 17.5, "x": 208602.187433, "y": 367752.183479, "z": 825.325327, "elevation_m": 825.325327, "valid": true}, {"offset_m": 18, "x": 208602.565624, "y": 367752.510544, "z": 825.140167, "elevation_m": 825.140167, "valid": true}, {"offset_m": 18.5, "x": 208602.943815, "y": 367752.837609, "z": 824.917183, "elevation_m": 824.917183, "valid": true}, {"offset_m": 19, "x": 208603.322006, "y": 367753.164674, "z": 824.609324, "elevation_m": 824.609324, "valid": true}, {"offset_m": 19.5, "x": 208603.700197, "y": 367753.491739, "z": 824.360611, "elevation_m": 824.360611, "valid": true}, {"offset_m": 20, "x": 208604.078388, "y": 367753.818804, "z": 824.142208, "elevation_m": 824.142208, "valid": true}], "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 5.317, "carriageway_width_m": 4.317, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 1.317, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 834.0405}, "right": {"offset_m": -3.317, "elevation_m": 833.881}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 834.0255}, "right": {"offset_m": -2.817, "elevation_m": 833.896}}, "design_elevation_m": 833.9805, "cut_area_m2": 8.844, "cut_soil_area_m2": 3.0621, "cut_rock_area_m2": 5.7819, "cut_rock_kind": "ripping_rock", "fill_area_m2": 9.6804, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 10.9115, "slope_unclosed": false, "fill_ground_slope": 0.5509, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 846.842}, {"offset_m": -19.5, "elevation_m": 846.4135}, {"offset_m": -19, "elevation_m": 846.0951}, {"offset_m": -18.5, "elevation_m": 845.8927}, {"offset_m": -18, "elevation_m": 845.5536}, {"offset_m": -17.5, "elevation_m": 845.1193}, {"offset_m": -17, "elevation_m": 844.5802}, {"offset_m": -16.5, "elevation_m": 843.9683}, {"offset_m": -16, "elevation_m": 843.5212}, {"offset_m": -15.5, "elevation_m": 843.3229}, {"offset_m": -15, "elevation_m": 843.2495}, {"offset_m": -14.5, "elevation_m": 843.1742}, {"offset_m": -14, "elevation_m": 842.8514}, {"offset_m": -13.5, "elevation_m": 842.453}, {"offset_m": -13, "elevation_m": 842.1141}, {"offset_m": -12.5, "elevation_m": 841.8552}, {"offset_m": -12, "elevation_m": 841.6078}, {"offset_m": -11.5, "elevation_m": 841.3589}, {"offset_m": -11, "elevation_m": 841.0284}, {"offset_m": -10.5, "elevation_m": 840.6494}, {"offset_m": -10, "elevation_m": 840.3745}, {"offset_m": -9.5, "elevation_m": 839.9567}, {"offset_m": -9, "elevation_m": 839.464}, {"offset_m": -8.5, "elevation_m": 839.0469}, {"offset_m": -8, "elevation_m": 838.9818}, {"offset_m": -7.5, "elevation_m": 839.0359}, {"offset_m": -7, "elevation_m": 839.1217}, {"offset_m": -6.807, "elevation_m": 839.1149}, {"offset_m": -6.5, "elevation_m": 838.8239}, {"offset_m": -6, "elevation_m": 838.3239}, {"offset_m": -5.6403, "elevation_m": 837.9642}, {"offset_m": -5.5, "elevation_m": 837.6135}, {"offset_m": -5, "elevation_m": 836.3635}, {"offset_m": -4.5, "elevation_m": 835.1135}, {"offset_m": -4.007, "elevation_m": 833.881}, {"offset_m": -4, "elevation_m": 833.8703}, {"offset_m": -3.812, "elevation_m": 833.581}, {"offset_m": -3.512, "elevation_m": 833.581}, {"offset_m": -3.5, "elevation_m": 833.5995}, {"offset_m": -3.317, "elevation_m": 833.881}, {"offset_m": -3, "elevation_m": 833.8905}, {"offset_m": -2.5, "elevation_m": 833.9055}, {"offset_m": -2, "elevation_m": 833.9205}, {"offset_m": -1.5, "elevation_m": 833.9355}, {"offset_m": -1, "elevation_m": 833.9505}, {"offset_m": -0.5, "elevation_m": 833.9655}, {"offset_m": 0, "elevation_m": 833.9805}, {"offset_m": 0.5, "elevation_m": 833.9955}, {"offset_m": 1, "elevation_m": 834.0105}, {"offset_m": 1.5, "elevation_m": 834.0255}, {"offset_m": 2, "elevation_m": 834.0405}, {"offset_m": 2.5, "elevation_m": 833.6239}, {"offset_m": 3, "elevation_m": 833.2072}, {"offset_m": 3.5, "elevation_m": 832.7905}, {"offset_m": 4, "elevation_m": 832.3739}, {"offset_m": 4.5, "elevation_m": 831.9572}, {"offset_m": 5, "elevation_m": 831.5405}, {"offset_m": 5.5, "elevation_m": 831.1239}, {"offset_m": 6, "elevation_m": 830.7072}, {"offset_m": 6.5, "elevation_m": 830.2905}, {"offset_m": 7, "elevation_m": 829.8739}, {"offset_m": 7.5, "elevation_m": 829.4572}, {"offset_m": 8, "elevation_m": 829.0405}, {"offset_m": 8.5, "elevation_m": 828.6239}, {"offset_m": 9, "elevation_m": 828.2072}, {"offset_m": 9.05, "elevation_m": 828.1679}, {"offset_m": 9.5, "elevation_m": 827.973}, {"offset_m": 10, "elevation_m": 827.7062}, {"offset_m": 10.5, "elevation_m": 827.5077}, {"offset_m": 11, "elevation_m": 827.4044}, {"offset_m": 11.5, "elevation_m": 827.363}, {"offset_m": 12, "elevation_m": 827.3106}, {"offset_m": 12.5, "elevation_m": 827.158}, {"offset_m": 13, "elevation_m": 826.8601}, {"offset_m": 13.5, "elevation_m": 826.454}, {"offset_m": 14, "elevation_m": 826.0198}, {"offset_m": 14.5, "elevation_m": 825.7602}, {"offset_m": 15, "elevation_m": 825.5959}, {"offset_m": 15.5, "elevation_m": 825.4554}, {"offset_m": 16, "elevation_m": 825.4377}, {"offset_m": 16.5, "elevation_m": 825.4729}, {"offset_m": 17, "elevation_m": 825.5157}, {"offset_m": 17.5, "elevation_m": 825.3253}, {"offset_m": 18, "elevation_m": 825.1402}, {"offset_m": 18.5, "elevation_m": 824.9172}, {"offset_m": 19, "elevation_m": 824.6093}, {"offset_m": 19.5, "elevation_m": 824.3606}, {"offset_m": 20, "elevation_m": 824.1422}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 4.0832, "run_m": 1.6333, "start_offset_m": -4.007, "end_offset_m": -5.6403, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 1.1667, "run_m": 1.1667, "start_offset_m": -5.6403, "end_offset_m": -6.807, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": false}}, {"station_id": "station_000000352140", "chainage_m": 352.14, "label": "STA.0+352.140", "kind": "irregular", "center_x": 208597.266079, "center_y": 367731.950395, "center_z": 834.734726, "azimuth_deg": 122.07332, "plan_radius_m": 12, "curve_outer_side": "right", "curve_widening_m": 2.25, "uphill_side": "right", "frame": {"origin": {"x": 208597.266079, "y": 367731.950395, "z": 834.734726}, "tangent_xy": [0.847369279, -0.531004054], "left_xy": [0.531004054, 0.847369279], "up_xyz": [0, 0, 1]}, "structure": "BOX암거", "samples": [{"offset_m": -20, "x": 208586.645998, "y": 367715.003009, "z": 845.373297, "elevation_m": 845.373297, "valid": true}, {"offset_m": -19.5, "x": 208586.9115, "y": 367715.426694, "z": 845.255483, "elevation_m": 845.255483, "valid": true}, {"offset_m": -19, "x": 208587.177002, "y": 367715.850379, "z": 845.172899, "elevation_m": 845.172899, "valid": true}, {"offset_m": -18.5, "x": 208587.442504, "y": 367716.274063, "z": 845.051391, "elevation_m": 845.051391, "valid": true}, {"offset_m": -18, "x": 208587.708006, "y": 367716.697748, "z": 844.643392, "elevation_m": 844.643392, "valid": true}, {"offset_m": -17.5, "x": 208587.973508, "y": 367717.121433, "z": 844.261074, "elevation_m": 844.261074, "valid": true}, {"offset_m": -17, "x": 208588.23901, "y": 367717.545117, "z": 843.940506, "elevation_m": 843.940506, "valid": true}, {"offset_m": -16.5, "x": 208588.504512, "y": 367717.968802, "z": 843.435541, "elevation_m": 843.435541, "valid": true}, {"offset_m": -16, "x": 208588.770014, "y": 367718.392487, "z": 842.733318, "elevation_m": 842.733318, "valid": true}, {"offset_m": -15.5, "x": 208589.035516, "y": 367718.816171, "z": 842.47225, "elevation_m": 842.47225, "valid": true}, {"offset_m": -15, "x": 208589.301018, "y": 367719.239856, "z": 842.415832, "elevation_m": 842.415832, "valid": true}, {"offset_m": -14.5, "x": 208589.56652, "y": 367719.663541, "z": 842.305419, "elevation_m": 842.305419, "valid": true}, {"offset_m": -14, "x": 208589.832022, "y": 367720.087225, "z": 842.089755, "elevation_m": 842.089755, "valid": true}, {"offset_m": -13.5, "x": 208590.097524, "y": 367720.51091, "z": 841.798083, "elevation_m": 841.798083, "valid": true}, {"offset_m": -13, "x": 208590.363026, "y": 367720.934594, "z": 841.516143, "elevation_m": 841.516143, "valid": true}, {"offset_m": -12.5, "x": 208590.628528, "y": 367721.358279, "z": 841.211817, "elevation_m": 841.211817, "valid": true}, {"offset_m": -12, "x": 208590.89403, "y": 367721.781964, "z": 840.909325, "elevation_m": 840.909325, "valid": true}, {"offset_m": -11.5, "x": 208591.159532, "y": 367722.205648, "z": 840.716903, "elevation_m": 840.716903, "valid": true}, {"offset_m": -11, "x": 208591.425034, "y": 367722.629333, "z": 840.613869, "elevation_m": 840.613869, "valid": true}, {"offset_m": -10.5, "x": 208591.690536, "y": 367723.053018, "z": 840.613241, "elevation_m": 840.613241, "valid": true}, {"offset_m": -10, "x": 208591.956038, "y": 367723.476702, "z": 840.654508, "elevation_m": 840.654508, "valid": true}, {"offset_m": -9.5, "x": 208592.22154, "y": 367723.900387, "z": 840.551855, "elevation_m": 840.551855, "valid": true}, {"offset_m": -9, "x": 208592.487042, "y": 367724.324072, "z": 840.003767, "elevation_m": 840.003767, "valid": true}, {"offset_m": -8.5, "x": 208592.752544, "y": 367724.747756, "z": 839.506264, "elevation_m": 839.506264, "valid": true}, {"offset_m": -8, "x": 208593.018046, "y": 367725.171441, "z": 839.028443, "elevation_m": 839.028443, "valid": true}, {"offset_m": -7.5, "x": 208593.283548, "y": 367725.595125, "z": 838.573601, "elevation_m": 838.573601, "valid": true}, {"offset_m": -7, "x": 208593.54905, "y": 367726.01881, "z": 838.224332, "elevation_m": 838.224332, "valid": true}, {"offset_m": -6.5, "x": 208593.814552, "y": 367726.442495, "z": 838.181242, "elevation_m": 838.181242, "valid": true}, {"offset_m": -6, "x": 208594.080055, "y": 367726.866179, "z": 838.138559, "elevation_m": 838.138559, "valid": true}, {"offset_m": -5.5, "x": 208594.345557, "y": 367727.289864, "z": 838.111724, "elevation_m": 838.111724, "valid": true}, {"offset_m": -5, "x": 208594.611059, "y": 367727.713549, "z": 838.129075, "elevation_m": 838.129075, "valid": true}, {"offset_m": -4.5, "x": 208594.876561, "y": 367728.137233, "z": 838.132546, "elevation_m": 838.132546, "valid": true}, {"offset_m": -4, "x": 208595.142063, "y": 367728.560918, "z": 837.67938, "elevation_m": 837.67938, "valid": true}, {"offset_m": -3.5, "x": 208595.407565, "y": 367728.984603, "z": 836.960701, "elevation_m": 836.960701, "valid": true}, {"offset_m": -3, "x": 208595.673067, "y": 367729.408287, "z": 836.345311, "elevation_m": 836.345311, "valid": true}, {"offset_m": -2.5, "x": 208595.938569, "y": 367729.831972, "z": 835.900316, "elevation_m": 835.900316, "valid": true}, {"offset_m": -2, "x": 208596.204071, "y": 367730.255656, "z": 835.522759, "elevation_m": 835.522759, "valid": true}, {"offset_m": -1.5, "x": 208596.469573, "y": 367730.679341, "z": 835.492901, "elevation_m": 835.492901, "valid": true}, {"offset_m": -1, "x": 208596.735075, "y": 367731.103026, "z": 835.451147, "elevation_m": 835.451147, "valid": true}, {"offset_m": -0.5, "x": 208597.000577, "y": 367731.52671, "z": 835.192564, "elevation_m": 835.192564, "valid": true}, {"offset_m": 0, "x": 208597.266079, "y": 367731.950395, "z": 834.734726, "elevation_m": 834.734726, "valid": true}, {"offset_m": 0.5, "x": 208597.531581, "y": 367732.37408, "z": 834.262242, "elevation_m": 834.262242, "valid": true}, {"offset_m": 1, "x": 208597.797083, "y": 367732.797764, "z": 833.911455, "elevation_m": 833.911455, "valid": true}, {"offset_m": 1.5, "x": 208598.062585, "y": 367733.221449, "z": 833.620184, "elevation_m": 833.620184, "valid": true}, {"offset_m": 2, "x": 208598.328087, "y": 367733.645134, "z": 833.348946, "elevation_m": 833.348946, "valid": true}, {"offset_m": 2.5, "x": 208598.593589, "y": 367734.068818, "z": 833.046076, "elevation_m": 833.046076, "valid": true}, {"offset_m": 3, "x": 208598.859091, "y": 367734.492503, "z": 832.758379, "elevation_m": 832.758379, "valid": true}, {"offset_m": 3.5, "x": 208599.124593, "y": 367734.916188, "z": 832.539371, "elevation_m": 832.539371, "valid": true}, {"offset_m": 4, "x": 208599.390095, "y": 367735.339872, "z": 832.340204, "elevation_m": 832.340204, "valid": true}, {"offset_m": 4.5, "x": 208599.655597, "y": 367735.763557, "z": 832.128996, "elevation_m": 832.128996, "valid": true}, {"offset_m": 5, "x": 208599.921099, "y": 367736.187241, "z": 831.881736, "elevation_m": 831.881736, "valid": true}, {"offset_m": 5.5, "x": 208600.186601, "y": 367736.610926, "z": 831.610105, "elevation_m": 831.610105, "valid": true}, {"offset_m": 6, "x": 208600.452103, "y": 367737.034611, "z": 831.427707, "elevation_m": 831.427707, "valid": true}, {"offset_m": 6.5, "x": 208600.717605, "y": 367737.458295, "z": 831.257567, "elevation_m": 831.257567, "valid": true}, {"offset_m": 7, "x": 208600.983107, "y": 367737.88198, "z": 831.067316, "elevation_m": 831.067316, "valid": true}, {"offset_m": 7.5, "x": 208601.248609, "y": 367738.305665, "z": 830.88809, "elevation_m": 830.88809, "valid": true}, {"offset_m": 8, "x": 208601.514111, "y": 367738.729349, "z": 830.781675, "elevation_m": 830.781675, "valid": true}, {"offset_m": 8.5, "x": 208601.779613, "y": 367739.153034, "z": 830.586456, "elevation_m": 830.586456, "valid": true}, {"offset_m": 9, "x": 208602.045115, "y": 367739.576719, "z": 830.26654, "elevation_m": 830.26654, "valid": true}, {"offset_m": 9.5, "x": 208602.310617, "y": 367740.000403, "z": 829.95947, "elevation_m": 829.95947, "valid": true}, {"offset_m": 10, "x": 208602.576119, "y": 367740.424088, "z": 829.703434, "elevation_m": 829.703434, "valid": true}, {"offset_m": 10.5, "x": 208602.841621, "y": 367740.847772, "z": 829.459745, "elevation_m": 829.459745, "valid": true}, {"offset_m": 11, "x": 208603.107123, "y": 367741.271457, "z": 829.201901, "elevation_m": 829.201901, "valid": true}, {"offset_m": 11.5, "x": 208603.372625, "y": 367741.695142, "z": 828.960229, "elevation_m": 828.960229, "valid": true}, {"offset_m": 12, "x": 208603.638127, "y": 367742.118826, "z": 828.726666, "elevation_m": 828.726666, "valid": true}, {"offset_m": 12.5, "x": 208603.90363, "y": 367742.542511, "z": 828.449297, "elevation_m": 828.449297, "valid": true}, {"offset_m": 13, "x": 208604.169132, "y": 367742.966196, "z": 828.148899, "elevation_m": 828.148899, "valid": true}, {"offset_m": 13.5, "x": 208604.434634, "y": 367743.38988, "z": 827.812001, "elevation_m": 827.812001, "valid": true}, {"offset_m": 14, "x": 208604.700136, "y": 367743.813565, "z": 827.475471, "elevation_m": 827.475471, "valid": true}, {"offset_m": 14.5, "x": 208604.965638, "y": 367744.23725, "z": 827.157723, "elevation_m": 827.157723, "valid": true}, {"offset_m": 15, "x": 208605.23114, "y": 367744.660934, "z": 826.964242, "elevation_m": 826.964242, "valid": true}, {"offset_m": 15.5, "x": 208605.496642, "y": 367745.084619, "z": 826.763424, "elevation_m": 826.763424, "valid": true}, {"offset_m": 16, "x": 208605.762144, "y": 367745.508304, "z": 826.632204, "elevation_m": 826.632204, "valid": true}, {"offset_m": 16.5, "x": 208606.027646, "y": 367745.931988, "z": 826.552893, "elevation_m": 826.552893, "valid": true}, {"offset_m": 17, "x": 208606.293148, "y": 367746.355673, "z": 826.466611, "elevation_m": 826.466611, "valid": true}, {"offset_m": 17.5, "x": 208606.55865, "y": 367746.779357, "z": 826.207486, "elevation_m": 826.207486, "valid": true}, {"offset_m": 18, "x": 208606.824152, "y": 367747.203042, "z": 825.972648, "elevation_m": 825.972648, "valid": true}, {"offset_m": 18.5, "x": 208607.089654, "y": 367747.626727, "z": 825.804194, "elevation_m": 825.804194, "valid": true}, {"offset_m": 19, "x": 208607.355156, "y": 367748.050411, "z": 825.698496, "elevation_m": 825.698496, "valid": true}, {"offset_m": 19.5, "x": 208607.620658, "y": 367748.474096, "z": 825.618856, "elevation_m": 825.618856, "valid": true}, {"offset_m": 20, "x": 208607.88616, "y": 367748.897781, "z": 825.441881, "elevation_m": 825.441881, "valid": true}], "box": {"type": "box", "inner_width_m": 2, "inner_height_m": 2, "wall_thickness_m": 0.3, "slab_thickness_m": 0.25, "top_thickness_m": 0.25, "cover_m": 0.5, "span_m": 2.6, "wing_in": {"installed": false, "height_m": 1, "length_m": 2, "angle_deg": 45, "slab_extend_m": 0}, "wing_out": {"installed": false, "height_m": 1, "length_m": 2, "angle_deg": 45, "slab_extend_m": 0}, "defaulted": [], "guard": {"type": "pipe", "hidden_pipe": true, "body": "box", "side": "양쪽", "tiers": 1, "foundation": null, "pipe_kind": null, "diameter_m": 2.5, "min_cover_m": 0, "inlet": {"role": "inlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 3.5, "revet_length_m": 25, "revet_before_m": 15, "revet_after_m": 10, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 7, "apron_thickness_m": 0.45}, "outlet": {"role": "outlet", "structure": "기슭막이", "revet_form": "콘크리트", "revet_height_m": 3.5, "revet_length_m": 25, "revet_before_m": 15, "revet_after_m": 10, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 7, "apron_thickness_m": 0.45}}, "chainage_m": 352.14}, "culvert": {"type": "pipe", "hidden_pipe": true, "body": "box", "side": "양쪽", "tiers": 1, "foundation": null, "pipe_kind": null, "diameter_m": 2.5, "min_cover_m": 0, "inlet": {"role": "inlet", "structure": "기슭막이", "revet_form": "돌쌓기(찰)", "revet_height_m": 3.5, "revet_length_m": 25, "revet_before_m": 15, "revet_after_m": 10, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 7, "apron_thickness_m": 0.45}, "outlet": {"role": "outlet", "structure": "기슭막이", "revet_form": "콘크리트", "revet_height_m": 3.5, "revet_length_m": 25, "revet_before_m": 15, "revet_after_m": 10, "face_slope": 0.3, "face_side": null, "face_role": null, "face_slope_ratio": null, "apron_length_m": 7, "apron_thickness_m": 0.45}, "chainage_m": 352.14}, "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 6, "carriageway_width_m": 5, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 2, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 834.7847}, "right": {"offset_m": -4, "elevation_m": 834.6047}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 834.7697}, "right": {"offset_m": -3.5, "elevation_m": 834.6197}}, "design_elevation_m": 834.7247, "cut_area_m2": 4.8776, "cut_soil_area_m2": 1.873, "cut_rock_area_m2": 3.0046, "cut_rock_kind": "ripping_rock", "fill_area_m2": 1.5916, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 6.9323, "slope_unclosed": false, "fill_ground_slope": 0.4786, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 845.3733}, {"offset_m": -19.5, "elevation_m": 845.2555}, {"offset_m": -19, "elevation_m": 845.1729}, {"offset_m": -18.5, "elevation_m": 845.0514}, {"offset_m": -18, "elevation_m": 844.6434}, {"offset_m": -17.5, "elevation_m": 844.2611}, {"offset_m": -17, "elevation_m": 843.9405}, {"offset_m": -16.5, "elevation_m": 843.4355}, {"offset_m": -16, "elevation_m": 842.7333}, {"offset_m": -15.5, "elevation_m": 842.4723}, {"offset_m": -15, "elevation_m": 842.4158}, {"offset_m": -14.5, "elevation_m": 842.3054}, {"offset_m": -14, "elevation_m": 842.0898}, {"offset_m": -13.5, "elevation_m": 841.7981}, {"offset_m": -13, "elevation_m": 841.5161}, {"offset_m": -12.5, "elevation_m": 841.2118}, {"offset_m": -12, "elevation_m": 840.9093}, {"offset_m": -11.5, "elevation_m": 840.7169}, {"offset_m": -11, "elevation_m": 840.6139}, {"offset_m": -10.5, "elevation_m": 840.6132}, {"offset_m": -10, "elevation_m": 840.6545}, {"offset_m": -9.5, "elevation_m": 840.5519}, {"offset_m": -9, "elevation_m": 840.0038}, {"offset_m": -8.5, "elevation_m": 839.5063}, {"offset_m": -8, "elevation_m": 839.0284}, {"offset_m": -7.5, "elevation_m": 838.5736}, {"offset_m": -7, "elevation_m": 838.2243}, {"offset_m": -6.5, "elevation_m": 838.1812}, {"offset_m": -6.49, "elevation_m": 838.1804}, {"offset_m": -6, "elevation_m": 837.7319}, {"offset_m": -5.9014, "elevation_m": 837.6333}, {"offset_m": -5.5, "elevation_m": 836.6297}, {"offset_m": -5, "elevation_m": 835.3797}, {"offset_m": -4.69, "elevation_m": 834.6047}, {"offset_m": -4.5, "elevation_m": 834.3124}, {"offset_m": -4.495, "elevation_m": 834.3047}, {"offset_m": -4.195, "elevation_m": 834.3047}, {"offset_m": -4, "elevation_m": 834.6047}, {"offset_m": -3.5, "elevation_m": 834.6197}, {"offset_m": -3, "elevation_m": 834.6347}, {"offset_m": -2.5, "elevation_m": 834.6497}, {"offset_m": -2, "elevation_m": 834.6647}, {"offset_m": -1.5, "elevation_m": 834.6797}, {"offset_m": -1, "elevation_m": 834.6947}, {"offset_m": -0.5, "elevation_m": 834.7097}, {"offset_m": 0, "elevation_m": 834.7247}, {"offset_m": 0.5, "elevation_m": 834.7397}, {"offset_m": 1, "elevation_m": 834.7547}, {"offset_m": 1.5, "elevation_m": 834.7697}, {"offset_m": 2, "elevation_m": 834.7847}, {"offset_m": 2.5, "elevation_m": 834.3681}, {"offset_m": 3, "elevation_m": 833.9514}, {"offset_m": 3.5, "elevation_m": 833.5347}, {"offset_m": 4, "elevation_m": 833.1181}, {"offset_m": 4.5, "elevation_m": 832.7014}, {"offset_m": 5, "elevation_m": 832.2847}, {"offset_m": 5.5, "elevation_m": 831.8681}, {"offset_m": 6, "elevation_m": 831.4514}, {"offset_m": 6.05, "elevation_m": 831.4107}, {"offset_m": 6.5, "elevation_m": 831.2576}, {"offset_m": 7, "elevation_m": 831.0673}, {"offset_m": 7.5, "elevation_m": 830.8881}, {"offset_m": 8, "elevation_m": 830.7817}, {"offset_m": 8.5, "elevation_m": 830.5865}, {"offset_m": 9, "elevation_m": 830.2665}, {"offset_m": 9.5, "elevation_m": 829.9595}, {"offset_m": 10, "elevation_m": 829.7034}, {"offset_m": 10.5, "elevation_m": 829.4597}, {"offset_m": 11, "elevation_m": 829.2019}, {"offset_m": 11.5, "elevation_m": 828.9602}, {"offset_m": 12, "elevation_m": 828.7267}, {"offset_m": 12.5, "elevation_m": 828.4493}, {"offset_m": 13, "elevation_m": 828.1489}, {"offset_m": 13.5, "elevation_m": 827.812}, {"offset_m": 14, "elevation_m": 827.4755}, {"offset_m": 14.5, "elevation_m": 827.1577}, {"offset_m": 15, "elevation_m": 826.9642}, {"offset_m": 15.5, "elevation_m": 826.7634}, {"offset_m": 16, "elevation_m": 826.6322}, {"offset_m": 16.5, "elevation_m": 826.5529}, {"offset_m": 17, "elevation_m": 826.4666}, {"offset_m": 17.5, "elevation_m": 826.2075}, {"offset_m": 18, "elevation_m": 825.9726}, {"offset_m": 18.5, "elevation_m": 825.8042}, {"offset_m": 19, "elevation_m": 825.6985}, {"offset_m": 19.5, "elevation_m": 825.6189}, {"offset_m": 20, "elevation_m": 825.4419}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 3.0285, "run_m": 1.2114, "start_offset_m": -4.69, "end_offset_m": -5.9014, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 0.5886, "run_m": 0.5886, "start_offset_m": -5.9014, "end_offset_m": -6.49, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": false}}, {"station_id": "station_000000360000", "chainage_m": 360, "label": "STA.0+360.000", "kind": "regular", "center_x": 208604.778131, "center_y": 367730.132729, "center_z": 833.995557, "azimuth_deg": 89.05518, "plan_radius_m": null, "curve_outer_side": "right", "curve_widening_m": 2.0387, "uphill_side": "right", "frame": {"origin": {"x": 208604.778131, "y": 367730.132729, "z": 833.995557}, "tangent_xy": [0.99986404, 0.016489465], "left_xy": [-0.016489465, 0.99986404], "up_xyz": [0, 0, 1]}, "samples": [{"offset_m": -20, "x": 208605.107921, "y": 367710.135448, "z": 844.766645, "elevation_m": 844.766645, "valid": true}, {"offset_m": -19.5, "x": 208605.099676, "y": 367710.63538, "z": 844.399162, "elevation_m": 844.399162, "valid": true}, {"offset_m": -19, "x": 208605.091431, "y": 367711.135312, "z": 844.09357, "elevation_m": 844.09357, "valid": true}, {"offset_m": -18.5, "x": 208605.083187, "y": 367711.635244, "z": 843.91167, "elevation_m": 843.91167, "valid": true}, {"offset_m": -18, "x": 208605.074942, "y": 367712.135176, "z": 843.709765, "elevation_m": 843.709765, "valid": true}, {"offset_m": -17.5, "x": 208605.066697, "y": 367712.635108, "z": 843.432471, "elevation_m": 843.432471, "valid": true}, {"offset_m": -17, "x": 208605.058452, "y": 367713.13504, "z": 843.157136, "elevation_m": 843.157136, "valid": true}, {"offset_m": -16.5, "x": 208605.050208, "y": 367713.634972, "z": 842.884599, "elevation_m": 842.884599, "valid": true}, {"offset_m": -16, "x": 208605.041963, "y": 367714.134904, "z": 842.611296, "elevation_m": 842.611296, "valid": true}, {"offset_m": -15.5, "x": 208605.033718, "y": 367714.634836, "z": 842.383594, "elevation_m": 842.383594, "valid": true}, {"offset_m": -15, "x": 208605.025473, "y": 367715.134768, "z": 842.160701, "elevation_m": 842.160701, "valid": true}, {"offset_m": -14.5, "x": 208605.017229, "y": 367715.6347, "z": 842.039423, "elevation_m": 842.039423, "valid": true}, {"offset_m": -14, "x": 208605.008984, "y": 367716.134632, "z": 841.948268, "elevation_m": 841.948268, "valid": true}, {"offset_m": -13.5, "x": 208605.000739, "y": 367716.634564, "z": 841.686605, "elevation_m": 841.686605, "valid": true}, {"offset_m": -13, "x": 208604.992495, "y": 367717.134496, "z": 841.327315, "elevation_m": 841.327315, "valid": true}, {"offset_m": -12.5, "x": 208604.98425, "y": 367717.634428, "z": 840.888982, "elevation_m": 840.888982, "valid": true}, {"offset_m": -12, "x": 208604.976005, "y": 367718.13436, "z": 840.382796, "elevation_m": 840.382796, "valid": true}, {"offset_m": -11.5, "x": 208604.96776, "y": 367718.634292, "z": 840.000442, "elevation_m": 840.000442, "valid": true}, {"offset_m": -11, "x": 208604.959516, "y": 367719.134224, "z": 839.862925, "elevation_m": 839.862925, "valid": true}, {"offset_m": -10.5, "x": 208604.951271, "y": 367719.634156, "z": 839.730312, "elevation_m": 839.730312, "valid": true}, {"offset_m": -10, "x": 208604.943026, "y": 367720.134088, "z": 839.614033, "elevation_m": 839.614033, "valid": true}, {"offset_m": -9.5, "x": 208604.934781, "y": 367720.63402, "z": 839.479212, "elevation_m": 839.479212, "valid": true}, {"offset_m": -9, "x": 208604.926537, "y": 367721.133952, "z": 839.172393, "elevation_m": 839.172393, "valid": true}, {"offset_m": -8.5, "x": 208604.918292, "y": 367721.633884, "z": 838.869507, "elevation_m": 838.869507, "valid": true}, {"offset_m": -8, "x": 208604.910047, "y": 367722.133816, "z": 838.894964, "elevation_m": 838.894964, "valid": true}, {"offset_m": -7.5, "x": 208604.901802, "y": 367722.633748, "z": 838.95904, "elevation_m": 838.95904, "valid": true}, {"offset_m": -7, "x": 208604.893558, "y": 367723.13368, "z": 838.515607, "elevation_m": 838.515607, "valid": true}, {"offset_m": -6.5, "x": 208604.885313, "y": 367723.633612, "z": 837.91885, "elevation_m": 837.91885, "valid": true}, {"offset_m": -6, "x": 208604.877068, "y": 367724.133544, "z": 837.203374, "elevation_m": 837.203374, "valid": true}, {"offset_m": -5.5, "x": 208604.868824, "y": 367724.633476, "z": 836.421711, "elevation_m": 836.421711, "valid": true}, {"offset_m": -5, "x": 208604.860579, "y": 367725.133409, "z": 835.960527, "elevation_m": 835.960527, "valid": true}, {"offset_m": -4.5, "x": 208604.852334, "y": 367725.633341, "z": 835.884515, "elevation_m": 835.884515, "valid": true}, {"offset_m": -4, "x": 208604.844089, "y": 367726.133273, "z": 835.763786, "elevation_m": 835.763786, "valid": true}, {"offset_m": -3.5, "x": 208604.835845, "y": 367726.633205, "z": 835.551716, "elevation_m": 835.551716, "valid": true}, {"offset_m": -3, "x": 208604.8276, "y": 367727.133137, "z": 835.347264, "elevation_m": 835.347264, "valid": true}, {"offset_m": -2.5, "x": 208604.819355, "y": 367727.633069, "z": 835.169616, "elevation_m": 835.169616, "valid": true}, {"offset_m": -2, "x": 208604.81111, "y": 367728.133001, "z": 834.993242, "elevation_m": 834.993242, "valid": true}, {"offset_m": -1.5, "x": 208604.802866, "y": 367728.632933, "z": 834.720796, "elevation_m": 834.720796, "valid": true}, {"offset_m": -1, "x": 208604.794621, "y": 367729.132865, "z": 834.450584, "elevation_m": 834.450584, "valid": true}, {"offset_m": -0.5, "x": 208604.786376, "y": 367729.632797, "z": 834.225285, "elevation_m": 834.225285, "valid": true}, {"offset_m": 0, "x": 208604.778131, "y": 367730.132729, "z": 833.995557, "elevation_m": 833.995557, "valid": true}, {"offset_m": 0.5, "x": 208604.769887, "y": 367730.632661, "z": 833.467954, "elevation_m": 833.467954, "valid": true}, {"offset_m": 1, "x": 208604.761642, "y": 367731.132593, "z": 832.854395, "elevation_m": 832.854395, "valid": true}, {"offset_m": 1.5, "x": 208604.753397, "y": 367731.632525, "z": 832.53628, "elevation_m": 832.53628, "valid": true}, {"offset_m": 2, "x": 208604.745153, "y": 367732.132457, "z": 832.384187, "elevation_m": 832.384187, "valid": true}, {"offset_m": 2.5, "x": 208604.736908, "y": 367732.632389, "z": 832.144567, "elevation_m": 832.144567, "valid": true}, {"offset_m": 3, "x": 208604.728663, "y": 367733.132321, "z": 831.799007, "elevation_m": 831.799007, "valid": true}, {"offset_m": 3.5, "x": 208604.720418, "y": 367733.632253, "z": 831.505691, "elevation_m": 831.505691, "valid": true}, {"offset_m": 4, "x": 208604.712174, "y": 367734.132185, "z": 831.316315, "elevation_m": 831.316315, "valid": true}, {"offset_m": 4.5, "x": 208604.703929, "y": 367734.632117, "z": 831.125691, "elevation_m": 831.125691, "valid": true}, {"offset_m": 5, "x": 208604.695684, "y": 367735.132049, "z": 830.927901, "elevation_m": 830.927901, "valid": true}, {"offset_m": 5.5, "x": 208604.687439, "y": 367735.631981, "z": 830.731145, "elevation_m": 830.731145, "valid": true}, {"offset_m": 6, "x": 208604.679195, "y": 367736.131913, "z": 830.68923, "elevation_m": 830.68923, "valid": true}, {"offset_m": 6.5, "x": 208604.67095, "y": 367736.631845, "z": 830.648734, "elevation_m": 830.648734, "valid": true}, {"offset_m": 7, "x": 208604.662705, "y": 367737.131777, "z": 830.482949, "elevation_m": 830.482949, "valid": true}, {"offset_m": 7.5, "x": 208604.654461, "y": 367737.631709, "z": 830.302071, "elevation_m": 830.302071, "valid": true}, {"offset_m": 8, "x": 208604.646216, "y": 367738.131641, "z": 830.08225, "elevation_m": 830.08225, "valid": true}, {"offset_m": 8.5, "x": 208604.637971, "y": 367738.631573, "z": 829.849711, "elevation_m": 829.849711, "valid": true}, {"offset_m": 9, "x": 208604.629726, "y": 367739.131505, "z": 829.595117, "elevation_m": 829.595117, "valid": true}, {"offset_m": 9.5, "x": 208604.621482, "y": 367739.631437, "z": 829.327625, "elevation_m": 829.327625, "valid": true}, {"offset_m": 10, "x": 208604.613237, "y": 367740.131369, "z": 829.119844, "elevation_m": 829.119844, "valid": true}, {"offset_m": 10.5, "x": 208604.604992, "y": 367740.631301, "z": 828.98517, "elevation_m": 828.98517, "valid": true}, {"offset_m": 11, "x": 208604.596747, "y": 367741.131233, "z": 828.844477, "elevation_m": 828.844477, "valid": true}, {"offset_m": 11.5, "x": 208604.588503, "y": 367741.631165, "z": 828.692227, "elevation_m": 828.692227, "valid": true}, {"offset_m": 12, "x": 208604.580258, "y": 367742.131097, "z": 828.51033, "elevation_m": 828.51033, "valid": true}, {"offset_m": 12.5, "x": 208604.572013, "y": 367742.631029, "z": 828.211737, "elevation_m": 828.211737, "valid": true}, {"offset_m": 13, "x": 208604.563768, "y": 367743.130961, "z": 827.914672, "elevation_m": 827.914672, "valid": true}, {"offset_m": 13.5, "x": 208604.555524, "y": 367743.630893, "z": 827.629847, "elevation_m": 827.629847, "valid": true}, {"offset_m": 14, "x": 208604.547279, "y": 367744.130825, "z": 827.34466, "elevation_m": 827.34466, "valid": true}, {"offset_m": 14.5, "x": 208604.539034, "y": 367744.630757, "z": 827.143011, "elevation_m": 827.143011, "valid": true}, {"offset_m": 15, "x": 208604.53079, "y": 367745.130689, "z": 826.951919, "elevation_m": 826.951919, "valid": true}, {"offset_m": 15.5, "x": 208604.522545, "y": 367745.630621, "z": 826.860211, "elevation_m": 826.860211, "valid": true}, {"offset_m": 16, "x": 208604.5143, "y": 367746.130553, "z": 826.799121, "elevation_m": 826.799121, "valid": true}, {"offset_m": 16.5, "x": 208604.506055, "y": 367746.630485, "z": 826.700021, "elevation_m": 826.700021, "valid": true}, {"offset_m": 17, "x": 208604.497811, "y": 367747.130417, "z": 826.573894, "elevation_m": 826.573894, "valid": true}, {"offset_m": 17.5, "x": 208604.489566, "y": 367747.630349, "z": 826.324967, "elevation_m": 826.324967, "valid": true}, {"offset_m": 18, "x": 208604.481321, "y": 367748.130281, "z": 825.923588, "elevation_m": 825.923588, "valid": true}, {"offset_m": 18.5, "x": 208604.473076, "y": 367748.630213, "z": 825.601301, "elevation_m": 825.601301, "valid": true}, {"offset_m": 19, "x": 208604.464832, "y": 367749.130145, "z": 825.443809, "elevation_m": 825.443809, "valid": true}, {"offset_m": 19.5, "x": 208604.456587, "y": 367749.630077, "z": 825.283582, "elevation_m": 825.283582, "valid": true}, {"offset_m": 20, "x": 208604.448342, "y": 367750.13001, "z": 825.121034, "elevation_m": 825.121034, "valid": true}], "design": {"ground_type": "ripping_rock", "geometry_preset": "rock", "section_mode": "right_cut", "ditch_side": "right", "ditch_type": "standard", "cut_slope_ratio": 0.4, "soil_cut_slope_ratio": 1, "two_stage_slope": true, "fill_slope_ratio": 1.2, "roadbed_width_m": 6, "carriageway_width_m": 5, "carriageway_standard_width_m": 3, "widening_left_m": 0, "widening_right_m": 2, "cross_slope_pct": 3, "ditch": {"type": "standard", "top_width_m": 0.69, "bottom_width_m": 0.3, "depth_m": 0.3}, "ditch_enabled": true, "ditch_choice": null, "paved": false, "road_edges": {"left": {"offset_m": 2, "elevation_m": 834.0556}, "right": {"offset_m": -4, "elevation_m": 833.8756}}, "carriageway_edges": {"left": {"offset_m": 1.5, "elevation_m": 834.0406}, "right": {"offset_m": -3.5, "elevation_m": 833.8906}}, "design_elevation_m": 833.9956, "cut_area_m2": 8.4902, "cut_soil_area_m2": 3.7083, "cut_rock_area_m2": 4.7819, "cut_rock_kind": "ripping_rock", "fill_area_m2": 6.0398, "spoil_fill_area_m2": 0, "spoil_fill_side": null, "spoil_fill_width_m": 0, "spoil_fill_max_width_m": 0, "spoil_fill_line": [], "spoil_fill_unclosed": false, "spoil_fill_replaced_fill_m2": 0, "bench_cut_length_m": 6.5204, "slope_unclosed": false, "fill_ground_slope": 0.4195, "ditch_area_m2": 0.1485, "ditch_soil_area_m2": 0, "ditch_rock_area_m2": 0.1485, "ditch_split_basis": "rock_boundary", "design_line": [{"offset_m": -20, "elevation_m": 844.7666}, {"offset_m": -19.5, "elevation_m": 844.3992}, {"offset_m": -19, "elevation_m": 844.0936}, {"offset_m": -18.5, "elevation_m": 843.9117}, {"offset_m": -18, "elevation_m": 843.7098}, {"offset_m": -17.5, "elevation_m": 843.4325}, {"offset_m": -17, "elevation_m": 843.1571}, {"offset_m": -16.5, "elevation_m": 842.8846}, {"offset_m": -16, "elevation_m": 842.6113}, {"offset_m": -15.5, "elevation_m": 842.3836}, {"offset_m": -15, "elevation_m": 842.1607}, {"offset_m": -14.5, "elevation_m": 842.0394}, {"offset_m": -14, "elevation_m": 841.9483}, {"offset_m": -13.5, "elevation_m": 841.6866}, {"offset_m": -13, "elevation_m": 841.3273}, {"offset_m": -12.5, "elevation_m": 840.889}, {"offset_m": -12, "elevation_m": 840.3828}, {"offset_m": -11.5, "elevation_m": 840.0004}, {"offset_m": -11, "elevation_m": 839.8629}, {"offset_m": -10.5, "elevation_m": 839.7303}, {"offset_m": -10, "elevation_m": 839.614}, {"offset_m": -9.5, "elevation_m": 839.4792}, {"offset_m": -9, "elevation_m": 839.1724}, {"offset_m": -8.5, "elevation_m": 838.8695}, {"offset_m": -8.44, "elevation_m": 838.8726}, {"offset_m": -8, "elevation_m": 838.4376}, {"offset_m": -7.5, "elevation_m": 837.9376}, {"offset_m": -7, "elevation_m": 837.4376}, {"offset_m": -6.5, "elevation_m": 836.9376}, {"offset_m": -6, "elevation_m": 836.4376}, {"offset_m": -5.5247, "elevation_m": 835.9622}, {"offset_m": -5.5, "elevation_m": 835.9006}, {"offset_m": -5, "elevation_m": 834.6506}, {"offset_m": -4.69, "elevation_m": 833.8756}, {"offset_m": -4.5, "elevation_m": 833.5833}, {"offset_m": -4.495, "elevation_m": 833.5756}, {"offset_m": -4.195, "elevation_m": 833.5756}, {"offset_m": -4, "elevation_m": 833.8756}, {"offset_m": -3.5, "elevation_m": 833.8906}, {"offset_m": -3, "elevation_m": 833.9056}, {"offset_m": -2.5, "elevation_m": 833.9206}, {"offset_m": -2, "elevation_m": 833.9356}, {"offset_m": -1.5, "elevation_m": 833.9506}, {"offset_m": -1, "elevation_m": 833.9656}, {"offset_m": -0.5, "elevation_m": 833.9806}, {"offset_m": 0, "elevation_m": 833.9956}, {"offset_m": 0.5, "elevation_m": 834.0106}, {"offset_m": 1, "elevation_m": 834.0256}, {"offset_m": 1.5, "elevation_m": 834.0406}, {"offset_m": 2, "elevation_m": 834.0556}, {"offset_m": 2.5, "elevation_m": 833.6389}, {"offset_m": 3, "elevation_m": 833.2222}, {"offset_m": 3.5, "elevation_m": 832.8056}, {"offset_m": 4, "elevation_m": 832.3889}, {"offset_m": 4.5, "elevation_m": 831.9722}, {"offset_m": 5, "elevation_m": 831.5556}, {"offset_m": 5.5, "elevation_m": 831.1389}, {"offset_m": 6, "elevation_m": 830.7222}, {"offset_m": 6.05, "elevation_m": 830.6852}, {"offset_m": 6.5, "elevation_m": 830.6487}, {"offset_m": 7, "elevation_m": 830.4829}, {"offset_m": 7.5, "elevation_m": 830.3021}, {"offset_m": 8, "elevation_m": 830.0823}, {"offset_m": 8.5, "elevation_m": 829.8497}, {"offset_m": 9, "elevation_m": 829.5951}, {"offset_m": 9.5, "elevation_m": 829.3276}, {"offset_m": 10, "elevation_m": 829.1198}, {"offset_m": 10.5, "elevation_m": 828.9852}, {"offset_m": 11, "elevation_m": 828.8445}, {"offset_m": 11.5, "elevation_m": 828.6922}, {"offset_m": 12, "elevation_m": 828.5103}, {"offset_m": 12.5, "elevation_m": 828.2117}, {"offset_m": 13, "elevation_m": 827.9147}, {"offset_m": 13.5, "elevation_m": 827.6298}, {"offset_m": 14, "elevation_m": 827.3447}, {"offset_m": 14.5, "elevation_m": 827.143}, {"offset_m": 15, "elevation_m": 826.9519}, {"offset_m": 15.5, "elevation_m": 826.8602}, {"offset_m": 16, "elevation_m": 826.7991}, {"offset_m": 16.5, "elevation_m": 826.7}, {"offset_m": 17, "elevation_m": 826.5739}, {"offset_m": 17.5, "elevation_m": 826.325}, {"offset_m": 18, "elevation_m": 825.9236}, {"offset_m": 18.5, "elevation_m": 825.6013}, {"offset_m": 19, "elevation_m": 825.4438}, {"offset_m": 19.5, "elevation_m": 825.2836}, {"offset_m": 20, "elevation_m": 825.121}], "cut_slope_segments": [{"side": "right", "ratio": 0.4, "rise_m": 2.0867, "run_m": 0.8347, "start_offset_m": -4.69, "end_offset_m": -5.5247, "material": "rock"}, {"side": "right", "ratio": 1, "rise_m": 2.9153, "run_m": 2.9153, "start_offset_m": -5.5247, "end_offset_m": -8.44, "material": "soil"}], "rock_boundary_offset_m": -0.5, "status": "provisional", "pavement_suggested": false}}]} \ No newline at end of file diff --git a/resources/tester/helper_73_4_body_guard.cjs b/resources/tester/helper_73_4_body_guard.cjs new file mode 100644 index 000000000..8240ab034 --- /dev/null +++ b/resources/tester/helper_73_4_body_guard.cjs @@ -0,0 +1,119 @@ +/* 73-4 세월교 · 박스 흙막이 횡단 기하 헬퍼 — 화면 TS(`B06_Section_Structure_Layouts` · `_Cross_Body_Guard`)를 + * 그 자리에서 트랜스파일해 Node 로 돌림. 입력 = 픽스처(검증_sub7 상세 일부) · 결과 = 표준출력 JSON 한 벌. + * 짝 = `test_73_4_body_guard.py`. + */ +const fs = require("fs"); +const path = require("path"); +const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript")); + +const ROOT = path.join(__dirname, "..", ".."); +const cache = new Map(); +// 화면 전용 모듈(토스트 · 글) — 기하 계산엔 안 쓰임 +const STUBS = { + "@ui/ui_template_toast": { showToast: () => undefined }, +}; + +function loadTs(file) { + const full = path.resolve(file); + if (cache.has(full)) return cache.get(full); + if (full.endsWith(".json")) { + const data = JSON.parse(fs.readFileSync(full, "utf8")); + cache.set(full, data); + return data; + } + const js = ts.transpileModule(fs.readFileSync(full, "utf8"), { + compilerOptions: { + module: ts.ModuleKind.CommonJS, + target: ts.ScriptTarget.ES2020, + esModuleInterop: true, + }, + }).outputText; + const box = { exports: {} }; + cache.set(full, box.exports); + const localRequire = (request) => { + if (STUBS[request]) return STUBS[request]; + const alias = { "@util/": "common_util", "@ui/": "ui_template", "@config/": "config" }; + for (const [prefix, dir] of Object.entries(alias)) + if (request.startsWith(prefix)) + return loadTs(resolve(path.join(ROOT, dir, request.slice(prefix.length)))); + return loadTs(resolve(path.join(path.dirname(full), request))); + }; + new Function("exports", "module", "require", js)(box.exports, box, localRequire); + cache.set(full, box.exports); + return box.exports; +} +const resolve = (base) => + [base, `${base}.ts`, path.join(base, "index.ts")].find( + (p) => fs.existsSync(p) && fs.statSync(p).isFile(), + ) ?? `${base}.ts`; + +const B06 = (f) => path.join(ROOT, "B06_Section", f); +const { computeStoredLayouts, structureAreaRows, trimOfLayouts } = loadTs( + B06("B06_Section_Structure_Layouts.ts"), +); +const { outletPipeEnd } = loadTs(B06("B06_Section_UI_Cross_Culvert_Tiers.ts")); +const { bodyGuardBase } = loadTs(B06("B06_Section_UI_Cross_Body_Guard.ts")); + +const fixture = JSON.parse( + fs.readFileSync(path.join(__dirname, "fixtures", "b06_73_4_body_guard_sections.json"), "utf8"), +); +const sections = fixture.cross_sections; +const at = (c) => sections.find((s) => Math.abs(s.chainage_m - c) < 0.6); +const round = (v) => Math.round(v * 1000) / 1000; + +/** 벽마다 전면(관 끝 자리) ↔ 본체 끝 차이(m) · 바닥 기준 ↔ 본체 끝 표고 차이. */ +function fronts(section) { + const layouts = computeStoredLayouts(section, sections); + const base = bodyGuardBase(section, section.samples); + const walls = layouts.culvert?.walls ?? []; + return { + walls: walls.map((w) => { + const end = base.ends[w.role]; + const front = outletPipeEnd(w); + return { + role: w.role, + form: w.form, + dOffset: round(front.offset - end.offset), + dElevation: round(front.elevation - end.elevation), + front: round(front.offset), + }; + }), + bodyX: layouts.culvert?.bodyX ?? null, + applied: layouts.culvert?.revetShift + ? { inlet: layouts.culvert.revetShift.inlet.x, outlet: layouts.culvert.revetShift.outlet.x } + : null, + trimSame: + JSON.stringify(trimOfLayouts(layouts)) === JSON.stringify(layouts.culvert?.designTrim), + pipeLength: null, + }; +} + +const out = {}; +const box = at(352.14); +const ford = at(173.09); +out.box = fronts(box); +out.ford = fronts(ford); + +// 박스를 좌우로 1 m 늘리면 벽 전면도 1 m 따라 나감(연동 = 본체 기준 자리) +const moved = JSON.parse(JSON.stringify(box)); +moved.design.box_adjust = { left: { lengthM: 1, riseM: 0 }, right: { lengthM: 1, riseM: 0 } }; +const swapped = sections.map((s) => (s === box ? moved : s)); +const movedLayouts = computeStoredLayouts(moved, swapped); +const base = bodyGuardBase(moved, moved.samples); +out.boxMoved = movedLayouts.culvert.walls.map((w) => ({ + role: w.role, + dOffset: round(outletPipeEnd(w).offset - base.ends[w.role].offset), + front: round(outletPipeEnd(w).offset), +})); + +// 연동 옆 측점(340 · 360) — 소유 측점 벽이 섬 +out.linked = [340, 360].map((c) => { + const s = at(c); + return { chainage: c, walls: computeStoredLayouts(s, sections)?.culvert?.walls.length ?? 0 }; +}); + +// 면적 행 — 서버 Node 진입점과 같은 함수(`structureAreaRows`) +out.areas = structureAreaRows(sections).filter((r) => + [173.087, 352.14].some((c) => Math.abs(r.chainage_m - c) < 0.6), +); +process.stdout.write(JSON.stringify(out)); diff --git a/resources/tester/test_73_4_body_guard.py b/resources/tester/test_73_4_body_guard.py new file mode 100644 index 000000000..15eb8cd7d --- /dev/null +++ b/resources/tester/test_73_4_body_guard.py @@ -0,0 +1,82 @@ +"""73-4 세월교 · 박스 흙막이 — 관보호공 흙막이와 같은 벽 · 같은 자리 규칙(관 · 본체 끝). + +화면 TS 를 그 자리에서 돌린 값(`helper_73_4_body_guard.cjs`)과 서버 Node 번들(면적)을 대조함. +픽스처 = 검증_sub7 상세 일부(세월교 173.09 유입 · 유출 흙막이 · 박스 352.14 유입 · 유출 흙막이 전후 15 · 10 m). +""" + +import json +import subprocess +import sys +from pathlib import Path + +import pytest + +ROOT = Path(__file__).resolve().parents[2] +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +HELPER = Path(__file__).parent / "helper_73_4_body_guard.cjs" +FIXTURE = Path(__file__).parent / "fixtures" / "b06_73_4_body_guard_sections.json" +NODE_MODULES = ROOT / "config" / "node_modules" + +pytestmark = pytest.mark.skipif(not NODE_MODULES.is_dir(), reason="프론트엔드 의존성 미설치") + + +@pytest.fixture(scope="module") +def screen() -> dict: + done = subprocess.run( # noqa: S603 — 고정 실행 파일 + ["node", str(HELPER)], cwd=str(ROOT), capture_output=True, text=True, encoding="utf-8" + ) + assert done.returncode == 0, done.stderr + return json.loads(done.stdout) + + +def test_박스_벽_전면이_본체_끝(screen: dict) -> None: + walls = screen["box"]["walls"] + assert {w["role"] for w in walls} == {"inlet", "outlet"} + for wall in walls: + assert wall["dOffset"] == pytest.approx(0, abs=1e-3) + assert wall["dElevation"] == pytest.approx(0, abs=1e-3) + # 형태 = 폼 값 그대로(유입 찰 · 유출 콘크리트) + assert {w["role"]: w["form"] for w in walls} == {"inlet": "돌쌓기(찰)", "outlet": "콘크리트"} + # 자동 자리 = 본체 기준 0 — 되받아 저장해도 본체를 따라감 + assert screen["box"]["applied"] == {"inlet": 0, "outlet": 0} + + +def test_박스를_늘리면_벽도_m_단위로_따라감(screen: dict) -> None: + before = {w["role"]: w["front"] for w in screen["box"]["walls"]} + for wall in screen["boxMoved"]: + assert wall["dOffset"] == pytest.approx(0, abs=1e-3) + assert abs(wall["front"] - before[wall["role"]]) == pytest.approx(1.0, abs=1e-3) + + +def test_세월교_벽_전면이_관_끝(screen: dict) -> None: + walls = {w["role"]: w for w in screen["ford"]["walls"]} + assert walls["outlet"]["dOffset"] == pytest.approx(0, abs=1e-3) + assert walls["outlet"]["dElevation"] == pytest.approx(0, abs=1e-3) + # 유입 2.5 m 벽은 관 끝 자리에선 노면 위로 솟음 — 배관 벽과 같이 상단이 노견에서 멈춰 내려앉음 + assert walls["inlet"]["dElevation"] <= 0 + + +def test_연동_옆_측점에도_벽이_섬(screen: dict) -> None: + assert [row["walls"] for row in screen["linked"]] == [2, 2] + + +def test_설계선_트림은_흙막이_쪽(screen: dict) -> None: + assert screen["box"]["trimSame"] and screen["ford"]["trimSame"] + + +def test_서버_면적이_화면과_같음(screen: dict) -> None: + from B06_Section.B06_Section_Server_Calc_Prebuild import _NPM_SCRIPT, BUNDLE + from common_util.common_util_node_bundle import run_bundle_json + + sections = json.loads(FIXTURE.read_text(encoding="utf-8"))["cross_sections"] + output = run_bundle_json(BUNDLE, _NPM_SCRIPT, {"detail": {"cross_sections": sections}}) + assert output, "서버 Node 번들 실행 실패" + server = {round(r["chainage_m"], 2): r for r in output["areas"]} + for row in screen["areas"]: + mine = server[round(row["chainage_m"], 2)] + for key in ("cut_area_m2", "fill_area_m2"): + assert mine[key] == pytest.approx(row[key], abs=1e-4), (row["chainage_m"], key) + # 세월교 · 박스 흙막이 세트는 관이 아님 — 관 연장 안 실음 + assert all("pipe_length_m" not in r for r in screen["areas"]) diff --git a/resources/tester/test_b06_culvert_sets_mirror.py b/resources/tester/test_b06_culvert_sets_mirror.py index d8ac02cd8..8ddc842e5 100644 --- a/resources/tester/test_b06_culvert_sets_mirror.py +++ b/resources/tester/test_b06_culvert_sets_mirror.py @@ -53,6 +53,10 @@ POINTS = [ "wing_in_length_m": 3.0, "wing_in_angle_deg": 30.0, "wing_out": "없음", + # 세월교 유입 흙막이(73-4) + "inlet_type": "흙막이", + "inlet_revet_form": "콘크리트", + "inlet_revet_height_m": 1.5, }, }, { @@ -64,6 +68,10 @@ POINTS = [ "wing_in": "날개벽", "wing_out": "흙막이", "wing_out_length_m": 2.0, + # 박스 유출 흙막이(73-4) — 배관 흙막이와 같은 칸 · `culvert` 자리에 함께 얹힘 + "outlet_revet_form": "돌쌓기(찰)", + "outlet_revet_height_m": 3.5, + "outlet_revet_length_m": 10, }, }, { @@ -175,3 +183,19 @@ def test_culvert_sets_match_between_python_and_ts(tmp_path: Path) -> None: assert left == right, f"{CHAINAGES[index]}m 측점 세트가 갈렸다" # 시설이 실제로 붙었는지 — 빈 결과끼리 같아서 통과하는 것을 막는다. assert sum(1 for item in expected if len(item) > 1) >= 6 + + +def test_ford_box_guard_attached_as_culvert() -> None: + """세월교 · 박스 흙막이(73-4) — 흙막이 고른 쪽만 기슭막이 · 관 숨김 · 자리 기준 = 본체.""" + sections = {item["chainage_m"]: item for item in _python_sections()} + ford, box = sections[60.0]["culvert"], sections[80.0]["culvert"] + assert (ford["body"], ford["hidden_pipe"], ford["diameter_m"]) == ("ford", True, 1.0) + assert ford["inlet"]["structure"] == "기슭막이" and ford["outlet"]["structure"] == "" + assert ford["inlet"]["revet_form"] == "콘크리트" + assert box["body"] == "box" and box["inlet"]["structure"] == "" + assert box["outlet"]["revet_height_m"] == 3.5 + # 본체 전체 높이 = 상판 + 내공 2.5 + 저판 + b = sections[80.0]["box"] + assert box["diameter_m"] == round(b["top_thickness_m"] + 2.5 + b["slab_thickness_m"], 3) + # 흙막이 없는 시설엔 안 얹음 + assert "culvert" not in sections[100.0]