diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts index 6b8fb40a..5c701f01 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Const.ts @@ -105,3 +105,12 @@ export const FILL_SLOPE_MAX_LENGTH_M = 5.0; * 끝이 아니라 **사면길이 5m 지점**으로 끌어올리는 판정에 쓴다(2026-08-21 사용자 지시). */ export const FILL_STRUCTURE_HEIGHT_M = 3.0; + +/** + * 성토 사면이 성립하는 **최소 성토고**(m) — 노견 − 벽 이음선 상단. + * + * 이보다 낮은 자리에 벽을 세우면 사면선이 노견에서 벽 상단으로 **올라가** 역전된다 + * (2026-08-21 사용자 지적). 자동 배치는 물매 조건이 이미 막지만, 조정창으로 손수 + * 미는 경우는 이 하한으로 막는다. + */ +export const FILL_MIN_RISE_M = 0.3; diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts index cfc2ddc1..cda61b92 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Geom.ts @@ -1,20 +1,14 @@ /* ============================================================================= * B06_Section_UI_Cross_Culvert_Geom.ts * 배수관 세트(배관·기슭막이·보호공) **기하 계산** — 그리기(`_Cross_Culvert.ts`)와 분리. + * 백엔드가 만든 `section.culvert` 제원을 좌표로 옮긴다 — 치수를 새로 정하지 않는다. * - * 백엔드(`B06_Section_Engine_Culvert`)가 `pipe_points.json` 정본 + 레지스트리 기본값으로 - * 만든 `section.culvert` 제원을 좌표로 옮기기만 한다 — 여기서 치수를 새로 정하지 않는다. - * - * 배치 규칙 — **실무 횡단도 4장 기준으로 재정립**(2026-08-20 사용자 제공, 울진 계열 - * `관매설 Φ800~1000 · 기슭막이 유입 찰/유출 메 H=1.5 · 돌붙임(메붙임) ㎡` 주기): - * · 기슭막이 2기 — **도로면 양 가장자리**(유입 = 절토측 측구부, 유출 = 성토측 노견 - * 바깥 = 성토사면 최상단)에 선다. 형상은 사면 쪽으로 **기운 평행사변형**(전면 1:0.3, - * 두께 0.45m), 상단 ≈ 노면고. - * · 배관 — 두 벽 사이(도로 하부)만 직선으로 지난다. 단면 항상 직사각형(축 법선 두께), - * 끝단면은 벽 전면과 평행하게 마감. 수평 가능. 길이 표기는 m 단위 올림. - * · 보호공(돌붙임) — **관 하단 꼭짓점**에서 시작해 성토사면 경사(1:n)를 따라 원지반까지, - * 최소 보호공 길이(낙차고×2)를 채울 때까지 지반을 따라 더 간다. - * · 유입측 — 수평 보호공 없음. 측구 접속은 설계선(표준단면 측구)이 이미 표현한다. + * 배치 규칙 — 실무 횡단도 4장 기준(2026-08-20 사용자 제공, 울진 계열 주기): + * · 기슭막이 2기 — 유입/유출측 성토사면 안. 사면 쪽으로 기운 평행사변형(전면 1:0.3, + * 두께 0.45m). 자리는 사면선이 이음선 상단점을 지나도록 풀어서 정한다. + * · 배관 — 두 벽 사이(도로 하부)만 직선. 끝단면은 벽 전면과 평행하게 마감(수평 가능). + * · 보호공(돌붙임) — 관 하단 꼭짓점에서 성토사면 경사를 따라 원지반까지, 최소 길이 + * (낙차고×2)를 채울 때까지 지반을 따라 더 간다. 유입측은 수평 보호공 없음. * · 성토 경사 — 벽 전면과 교차된 이후는 끊는다(designTrim — 벽·보호공이 대신한다). * * 유입 = 상단측(uphill_side), 유출 = 하단측. 유입구가 "집수정"이면 그쪽 기슭막이는 @@ -23,6 +17,7 @@ import type { CrossSection, CulvertSideSpec, SectionSample } from "./B06_Section_Api_Fetch"; import { + FILL_MIN_RISE_M, FILL_SLOPE_MAX_LENGTH_M, FILL_STRUCTURE_HEIGHT_M, FILL_SLOPE_RATIO_MAX, @@ -50,6 +45,9 @@ export * from "./B06_Section_UI_Cross_Culvert_Const"; export * from "./B06_Section_UI_Cross_Culvert_Types"; import { + clampWallOffset, + cutLength, + outletSlopeFactory, fillSlopeOf, groundInterpolator, designInterpolator, @@ -117,8 +115,7 @@ export function computeCulvertLayout( : null; // 성토측 유입 기슭막이는 노견에 붙여 두지 않는다 — 사면선이 벽 이음선 상단점을 지나야 - // 하므로 자리를 풀어서 정한다(2026-08-21 사용자 ②). 집수정(절토·막힘)은 측구부 자리 - // 그대로 둔다. 벽 높이는 관경 + 여유고(0.1m 눈금 올림). + // 하므로 자리를 풀어서 정한다(집수정은 측구부 자리 그대로). const wallHeightFor = (spec: CulvertSideSpec): number => Math.min(revetTargetHeight(diameter), revetHeightLimit(spec.revet_form)); let inletPlacement: FillWallPlacement | null = null; @@ -134,8 +131,17 @@ export function computeCulvertLayout( slopeToeOffset(designAt, groundAt, inletInfo.edge.offset_m, inletInfo.limit), ); if (inletPlacement) { - // 사용자가 화살표로 민 만큼 자동 자리에서 더 옮긴다(2026-08-21 사용자 ①). - const shifted = inletPlacement.offset + inletInfo.outward * (revetShift?.inlet ?? 0); + // 사용자가 조정창으로 민 만큼 자동 자리에서 더 옮긴다 — 사면 역전 구간은 막는다. + const inletBaseAt = (offset: number): number => + Math.min(groundAt(offset), invertCap(inletInfo.edge)); + const shifted = clampWallOffset( + inletPlacement.offset, + inletPlacement.offset + inletInfo.outward * (revetShift?.inlet ?? 0), + wallHeightFor(culvert.inlet), + inletInfo.edge, + inletBaseAt, + inletInfo.outward, + ); inlet.offset = shifted; inlet.elevation = Math.min(groundAt(shifted), invertCap(inletInfo.edge)); } @@ -167,8 +173,7 @@ export function computeCulvertLayout( const rise0 = outletAnchor.elevation - inlet.elevation; const length0 = Math.hypot(run0, rise0); if (!(length0 > 0.5)) return null; - // 관은 m 단위 설치 — 올림 연장분은 유출 쪽으로(기슭막이를 조금 벗어나도 무관, - // 2026-08-20 사용자 확정). 실무 표기 L=10~12m대가 여기서 나온다. + // 관은 m 단위 설치 — 올림 연장분은 유출 쪽으로(2026-08-20 사용자 확정). let lengthM = Math.ceil(length0 - 1e-6); const scale = lengthM / length0; const outlet: OffsetPoint = { @@ -346,9 +351,8 @@ export function computeCulvertLayout( }; return null; } - // 형상(사용자 스케치 확정 — 좌측 벽 기준, 우측은 반전): **배면(도로측) 수직**, - // **전면(계류측)은 1:0.3 기운 평행사변형 띠**. 띠 안쪽 평행선과 수직 배면 사이가 - // 사다리꼴 — 합집합의 내부 대각 이음선은 배면 상단에서 바닥으로 내려온다. + // 형상(사용자 스케치 확정 — 좌측 벽 기준, 우측은 반전): 배면(도로측) 수직, 전면 + // (계류측)은 1:0.3 기운 평행사변형 띠. 띠 안쪽 평행선과 수직 배면 사이가 사다리꼴로, // 바닥이 넓고 상단이 좁다(상단 폭 = 띠 두께 0.45). // 높이: **관경 + 여유고**를 0.1m 눈금으로 올린 값(2026-08-21 사용자 확정). 관이 // 물매를 두어 좌·우 invert가 달라도 **관 상단 위 여유고는 같아야** 한다. 사면선은 @@ -429,7 +433,14 @@ export function computeCulvertLayout( outletAnchorOffset, ); if (outletPlacement) { - const shifted = outletPlacement.offset + outletInfo.outward * (revetShift?.outlet ?? 0); + const shifted = clampWallOffset( + outletPlacement.offset, + outletPlacement.offset + outletInfo.outward * (revetShift?.outlet ?? 0), + wallHeightFor(culvert.outlet), + outletInfo.edge, + invertAt, + outletInfo.outward, + ); outletWallAnchor = { offset: shifted, elevation: invertAt(shifted) }; } } @@ -490,27 +501,7 @@ export function computeCulvertLayout( // 길이가 다르다** — 긴 변을 기준으로 올림해 정수 m로 잡고, 모자란 만큼 **유출 벽 자리** // 를 관 축 방향 바깥으로 민다(벽 두께는 0.45 고정 — 사용자 확정). 벽 상단이 사면선과 // 벌어지는 문제는 설계선 트림이 벽 상단을 따라오므로 생기지 않는다(사용자 ②). - const cutLength = (corners: { inlet: PipeEnd; outlet: PipeEnd }): number => - Math.max( - Math.hypot( - corners.outlet.bottom.offset - corners.inlet.bottom.offset, - corners.outlet.bottom.elevation - corners.inlet.bottom.elevation, - ), - Math.hypot( - corners.outlet.top.offset - corners.inlet.top.offset, - corners.outlet.top.elevation - corners.inlet.top.elevation, - ), - ); - /** 그 자리에 벽을 세웠을 때의 성토 사면 — 물매(1:n)와 사면길이(노견 → 이음선 상단점). */ - const outletSlopeAt = (offset: number, thickness: number): { ratio: number; lengthM: number } => { - const joint = offset + outletInfo.outward * (thickness / 2); - const rise = outletInfo.edge.elevation_m - (invertAt(offset) + wallHeightFor(culvert.outlet)); - const run = Math.abs(joint - outletInfo.edge.offset_m); - return { - ratio: rise > 1e-6 ? run / rise : Number.POSITIVE_INFINITY, - lengthM: Math.hypot(run, Math.max(rise, 0)), - }; - }; + const outletSlopeAt = outletSlopeFactory(outletInfo, invertAt, wallHeightFor(culvert.outlet)); /** 유출 벽 두께 — 자리 이동만으로 관 길이를 정수로 못 맞출 때만 0.45에서 벗어난다. */ let outletThickness = REVET_THICKNESS_M; if (outletWall) { @@ -535,15 +526,25 @@ export function computeCulvertLayout( const gap = target - cutLength(pipeCorners); if (Math.abs(gap) < 0.005) break; // ① 벽 자리를 관 축 방향으로 gap 만큼 옮긴다(두께 불변 — 사용자 확정 우선순위). - // 단 사용자가 화살표로 자리를 지정했으면 그 자리를 지키고 폭으로만 흡수한다. - const pinned = Math.abs(revetShift?.outlet ?? 0) > 1e-9; const moved = outletWallAnchor.offset + axis.offset * gap; const movedSlope = outletSlopeAt(moved, outletThickness); + // 사면 역전·노견 안쪽으로는 옮기지 않는다 — 길이 맞춤보다 도면 성립이 먼저다. if ( - !pinned && - movedSlope.ratio >= FILL_SLOPE_RATIO_MIN && - movedSlope.ratio <= FILL_SLOPE_RATIO_MAX && - movedSlope.lengthM <= FILL_SLOPE_MAX_LENGTH_M + 1e-6 + (moved - outletInfo.edge.offset_m) * outletInfo.outward < 0 || + outletInfo.edge.elevation_m - (invertAt(moved) + wallHeightFor(culvert.outlet)) < + FILL_MIN_RISE_M + ) { + break; + } + // 조정창으로 옮긴 벽은 **폭을 건드리지 않는다** — 폭으로 흡수하면 미는 동안 벽 + // 단면이 변한다(2026-08-21 사용자 지적: 유출 벽만 0.45→0.90). 조정이 관 길이 1m + // 단위라 자리만 맞추면 정수가 성립한다. 물매·5m 한계는 자동 배치용 제약이라 + // 사용자가 지정한 자리에는 걸지 않는다(경고로 알린다). + if ( + Math.abs(revetShift?.outlet ?? 0) > 1e-9 || + (movedSlope.ratio >= FILL_SLOPE_RATIO_MIN && + movedSlope.ratio <= FILL_SLOPE_RATIO_MAX && + movedSlope.lengthM <= FILL_SLOPE_MAX_LENGTH_M + 1e-6) ) { outletWallAnchor = { offset: moved, elevation: invertAt(moved) }; rebuild(); @@ -633,8 +634,8 @@ export function computeCulvertLayout( } } - // ── 성토 사면 구간 확정. 벽 자리가 다 굳은 뒤에 물매를 역산해야 관 길이 맞춤(벽 이동) - // 이 접점을 다시 깨뜨리지 않는다 — 종전 어긋남의 직접 원인이 이 순서였다. + // ── 성토 사면 구간 확정. 벽 자리가 굳은 뒤에 물매를 역산해야 관 길이 맞춤(벽 이동)이 + // 접점을 다시 깨뜨리지 않는다 — 종전 어긋남의 직접 원인이 이 순서였다. const slopeOf = (wall: WallLayout): FillSlopeSegment => fillSlopeOf(wall, wall.role === "inlet" ? inletInfo.edge : outletInfo.edge); for (const wall of walls) { diff --git a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts b/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts index 83b9e717..5a30663b 100644 --- a/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts +++ b/B06_Section/B06_Section_UI_Cross_Culvert_Solve.ts @@ -6,13 +6,14 @@ import type { SectionSample } from "./B06_Section_Api_Fetch"; import { + FILL_MIN_RISE_M, FILL_SLOPE_MAX_LENGTH_M, FILL_SLOPE_RATIO_MAX, FILL_SLOPE_RATIO_MIN, FILL_STRUCTURE_HEIGHT_M, REVET_TRAP_TOP_M, } from "./B06_Section_UI_Cross_Culvert_Const"; -import type { OffsetPoint } from "./B06_Section_UI_Cross_Culvert_Types"; +import type { OffsetPoint, PipeEnd } from "./B06_Section_UI_Cross_Culvert_Types"; /** 유효 지반 샘플 → offset 오름차순 보간기. 범위 밖은 끝값 클램프, 샘플 없으면 null. */ export function groundInterpolator(samples: SectionSample[]): ((offset: number) => number) | null { @@ -219,3 +220,65 @@ export function fillSlopeOf( to, }; } + +/** + * 손으로 민 벽 자리를 **사면이 역전되지 않는 범위**로 되돌린다(2026-08-21 사용자 지적). + * 노견보다 벽 상단이 높아지면 사면선이 위로 올라가 버린다 — 자동 자리에서 목표 자리로 + * 훑으며 성토고가 하한 아래로 떨어지기 직전까지만 간다. + */ +export function clampWallOffset( + autoOffset: number, + wantedOffset: number, + height: number, + edge: { offset_m: number; elevation_m: number }, + baseAt: (offset: number) => number, + outward: number, +): number { + const steps = 40; + let allowed = autoOffset; + for (let i = 1; i <= steps; i += 1) { + const candidate = autoOffset + ((wantedOffset - autoOffset) * i) / steps; + // 벽은 제 노견 바깥에 선다 — 안쪽으로 넘기면 도로 밑을 파고들어 반대편까지 간다. + if ((candidate - edge.offset_m) * outward < 0) break; + if (edge.elevation_m - (baseAt(candidate) + height) < FILL_MIN_RISE_M) break; + allowed = candidate; + } + return allowed; +} + +/** + * 관 절단 길이(m) — 끝이 기운 벽 전면으로 잘려 **상단·하단 길이가 다르다**. + * 표기·정수 맞춤은 **긴 변** 기준이다(2026-08-21 사용자 확정). + */ +export function cutLength(corners: { inlet: PipeEnd; outlet: PipeEnd }): number { + return Math.max( + Math.hypot( + corners.outlet.bottom.offset - corners.inlet.bottom.offset, + corners.outlet.bottom.elevation - corners.inlet.bottom.elevation, + ), + Math.hypot( + corners.outlet.top.offset - corners.inlet.top.offset, + corners.outlet.top.elevation - corners.inlet.top.elevation, + ), + ); +} + +/** + * 유출 벽을 그 자리에 세웠을 때의 성토 사면(물매 1:n·사면길이)을 재는 함수를 만든다. + * 관 길이 정수 맞춤이 벽을 옮겨도 되는 자리인지 판정하는 데 쓴다. + */ +export function outletSlopeFactory( + info: { edge: { offset_m: number; elevation_m: number }; outward: number }, + invertAt: (offset: number) => number, + wallHeight: number, +): (offset: number, thickness: number) => { ratio: number; lengthM: number } { + return (offset, thickness) => { + const joint = offset + info.outward * (thickness / 2); + const rise = info.edge.elevation_m - (invertAt(offset) + wallHeight); + const run = Math.abs(joint - info.edge.offset_m); + return { + ratio: rise > 1e-6 ? run / rise : Number.POSITIVE_INFINITY, + lengthM: Math.hypot(run, Math.max(rise, 0)), + }; + }; +} diff --git a/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts b/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts index 9e434e9f..49906d1a 100644 --- a/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts +++ b/B06_Section/B06_Section_UI_Cross_Structure_Panel.ts @@ -21,6 +21,8 @@ export interface StructurePanelDeps { nudge: (key: RevetKey, screenDeltaM: number) => void; /** 자동 자리로 되돌린다. */ reset: (key: RevetKey) => void; + /** 지금 관 길이(m) — 조정 단위가 관 길이 1m이라 창에 같이 적는다. */ + pipeLengthM: () => number | null; /** 창을 닫는다 = 구조물 선택 해제. */ close: () => void; } @@ -31,8 +33,12 @@ export interface StructurePanelHandle { show: (key: RevetKey | null) => void; } -/** 한 걸음 이동량(m) — 벽 높이 눈금(0.1m)과 같은 단위로 맞춘다. */ -const STEP_M = 0.1; +/** + * 한 걸음 이동량(m) — **관 길이 1m**에 맞춘다(2026-08-21 사용자 확정). + * 관은 m 단위로 설치하므로 0.1m씩 밀면 그 끝수를 벽 폭이 흡수하게 되어 미는 동안 + * 벽 단면이 변한다. 한 걸음을 1m로 두면 벽은 자리만 옮기고 형상은 그대로다. + */ +const STEP_M = 1.0; function makeButton(label: string, title: string, onClick: () => void): HTMLButtonElement { const button = document.createElement("button"); @@ -105,10 +111,13 @@ export function buildStructurePanel(deps: StructurePanelDeps): StructurePanelHan // 자동 자리 기준 이동량 — 0이면 "자동"으로 적어 손을 안 댔음을 바로 알린다. // 부호(+/−)만 적으면 좌·우 벽에서 어느 쪽인지 읽히지 않아 **안/바깥**으로 적는다. const direction = L(shift > 0 ? "B06_Cross_Revet_Outward" : "B06_Cross_Revet_Inward"); - value.textContent = + const moved = Math.abs(shift) < 1e-9 ? L("B06_Cross_Revet_Auto") : `${direction} ${Math.abs(shift).toFixed(1)}m`; + const pipeLength = deps.pipeLengthM(); + value.textContent = + pipeLength === null ? moved : `${L("B06_Cross_Revet_Pipe")} ${pipeLength}m · ${moved}`; }, }; } diff --git a/B06_Section/B06_Section_UI_Cross_View.ts b/B06_Section/B06_Section_UI_Cross_View.ts index e61f6903..8397ef27 100644 --- a/B06_Section/B06_Section_UI_Cross_View.ts +++ b/B06_Section/B06_Section_UI_Cross_View.ts @@ -212,6 +212,8 @@ export function createCrossSectionCard( let activeRevet: RevetKey | null = revetOffset?.selectedFor(section) ?? null; let setRevetActive: RevetHighlightSetter = () => undefined; let showRevetControl: (visible: boolean) => void = () => undefined; + /** 지금 그린 관 길이(m) — 조정창이 "관 길이 8m"으로 적는다. 배수관 측점이 아니면 null. */ + let culvertPipeLengthM: number | null = null; /** * 기슭막이를 고른다. 구조물 선택과 절·성토 면적 강조는 **같은 레벨**이라 하나를 * 고르면 다른 하나는 풀린다(2026-08-21 사용자). 또 구조물을 고르면 그 **측점 카드도 @@ -450,7 +452,7 @@ export function createCrossSectionCard( toggleArea, ); // 배수관 세트 기하를 먼저 계산한다 — 설계선이 기슭막이 밖 성토 경사를 끊는 데 쓴다. - const culvertLayout = computeCulvertLayout( + const culvertLayout: ReturnType = computeCulvertLayout( section, sourceSamples, revetOffset @@ -481,6 +483,7 @@ export function createCrossSectionCard( ); } // 배수관 측점 세트(배관·기슭막이·보호공) — 기존 도형 위에 추가만 한다(2026-08-19). + culvertPipeLengthM = culvertLayout?.pipe.lengthM ?? null; if (culvertLayout) { setRevetActive = appendCulvertOverlay( plotLayer, @@ -571,6 +574,7 @@ export function createCrossSectionCard( nudge: (key, screenDeltaM) => revetOffset?.adjust(section.chainage_m, key, screenDeltaM * outwardOf(key)), reset: (key) => revetOffset?.reset(section.chainage_m, key), + pipeLengthM: () => culvertPipeLengthM, close: () => { if (activeRevet) toggleRevet(activeRevet); }, diff --git a/B06_Section/B06_Section_UI_Page_Station_Controls.ts b/B06_Section/B06_Section_UI_Page_Station_Controls.ts index 6630a595..5d8ce1fb 100644 --- a/B06_Section/B06_Section_UI_Page_Station_Controls.ts +++ b/B06_Section/B06_Section_UI_Page_Station_Controls.ts @@ -135,9 +135,9 @@ export function createStationControls(deps: StationControlDeps): StationControls } } - /** 손으로 미는 범위 한계(m) — 벽이 노면 밑이나 사면 밖으로 달아나지 않게 묶는다. */ + /** 손으로 미는 범위 한계(m) — 조정 단위가 관 길이 1m이라 ±10m(=관 10m분)까지 둔다. */ const clampRevetShift = (value: number): number => - Math.min(Math.max(Math.round(value * 10) / 10, -3), 3); + Math.min(Math.max(Math.round(value * 10) / 10, -10), 10); const revetOffsetControl: RevetOffsetControl = { shiftFor: (section, role) => revetShifts.get(revetKey(section.chainage_m, role)) ?? 0, diff --git a/ui_template/ui_template_locale_b2.ts b/ui_template/ui_template_locale_b2.ts index 2cc6840f..94322daa 100644 --- a/ui_template/ui_template_locale_b2.ts +++ b/ui_template/ui_template_locale_b2.ts @@ -242,10 +242,11 @@ export const ui_locales_b2 = { B06_Cross_Revet_Label: ["기슭막이", "Revetment"], B06_Cross_Revet_Close: ["조정창 닫기", "Close adjuster"], B06_Cross_Revet_Auto: ["자동 자리", "Solved position"], + B06_Cross_Revet_Pipe: ["관 길이", "Pipe length"], B06_Cross_Revet_Outward: ["바깥", "outward"], B06_Cross_Revet_Inward: ["안쪽", "inward"], - B06_Cross_Revet_Left: ["기슭막이 0.1m 왼쪽으로", "Move revetment 0.1m left"], - B06_Cross_Revet_Right: ["기슭막이 0.1m 오른쪽으로", "Move revetment 0.1m right"], + B06_Cross_Revet_Left: ["왼쪽으로 — 관 길이 1m 단위", "Move left — 1m of pipe length"], + B06_Cross_Revet_Right: ["오른쪽으로 — 관 길이 1m 단위", "Move right — 1m of pipe length"], B06_Cross_Revet_Reset: ["기슭막이 자동 자리로 초기화", "Reset revetment to solved position"], B06_Cross_Revet_Inlet: ["유입 기슭막이", "Inlet revetment"], B06_Cross_Revet_Outlet: ["유출 기슭막이", "Outlet revetment"],