fix(B05): 계류 유역 세월교 판정 + 하단 패널 밀어올리기 동작
- 세월교 판정: 유효직경이 관 최대 규격(D2000, config) 초과 시 bridge_required 플래그 — 관이 아니라 세월교·물넘이·교량 대상(임도설치규정 제12조: 계류 횡단 구간은 물넘이 포장·교량으로 설계). 유역 제원에 '세월교 검토(Ø계산값)' 표기, 관경 자동 지정 제외. 실측: 41.4ha 계류 유역 D5137 -> 세월교 검토 - 사면 유역 계산식은 유지 — FHWA 유입부 조절식과 교차검증 결과 근접 (1.1ha D862/D839, 2.9ha D1426/D1255) - 하단 패널: 서브패널이 종단도를 덮지 않고 밀어올림. 접힘=종단 전체, 하나 펼침=그만큼 종단 축소(테이블 높이 고정), 둘 펼침=종단-테이블-유토곡선 순서로 유토곡선 리사이즈 시 종단만 조절 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -457,6 +457,8 @@ export interface DetailBasin {
|
||||
tc_minutes?: number | null;
|
||||
intensity_mm_hr?: number | null;
|
||||
design_flow_m3s?: number | null;
|
||||
/** 유효직경이 관 최대 규격 초과 — 세월교·물넘이·교량 검토 대상(임도설치규정 제12조). */
|
||||
bridge_required?: boolean;
|
||||
}
|
||||
|
||||
export interface DetailBasinResponse {
|
||||
|
||||
@@ -130,6 +130,8 @@ def _payload(
|
||||
"tc_minutes": basin.tc_minutes,
|
||||
"intensity_mm_hr": basin.intensity_mm_hr,
|
||||
"design_flow_m3s": basin.design_flow_m3s,
|
||||
# 유효직경이 관 최대 규격 초과 — 세월교·물넘이·교량 검토 대상(임도설치규정 제12조).
|
||||
"bridge_required": basin.bridge_required,
|
||||
}
|
||||
for basin in detail.basins
|
||||
],
|
||||
@@ -161,6 +163,7 @@ def _basin_features(
|
||||
"tc_minutes": basin.tc_minutes,
|
||||
"intensity_mm_hr": basin.intensity_mm_hr,
|
||||
"design_flow_m3s": basin.design_flow_m3s,
|
||||
"bridge_required": basin.bridge_required,
|
||||
},
|
||||
"geometry": {"type": "Polygon", "coordinates": [ring]},
|
||||
}
|
||||
|
||||
@@ -398,12 +398,16 @@ export function createDrainagePanel(callbacks: DrainagePanelCallbacks = {}): Dra
|
||||
summaryText(summary, pipeEditor.pipes().length, basins.length, zSource);
|
||||
callbacks.onPipesChanged?.(
|
||||
// 관마다 담당 유역의 배수 유효직경을 붙인다(±0.5m 매칭). 유역 없는 관은 null.
|
||||
pipeEditor.chainages().map((chainage) => ({
|
||||
chainage_m: chainage,
|
||||
effective_diameter_mm:
|
||||
basins.find((basin) => Math.abs(basin.chainage_m - chainage) < 0.51)?.pipe_diameter_mm ??
|
||||
null,
|
||||
})),
|
||||
// 세월교 검토 유역(bridge_required)도 null — 관 규격을 최대치로 올려 봐야 무의미하고,
|
||||
// 그 지점은 세월교·물넘이로 별도 설계한다(임도설치규정 제12조).
|
||||
pipeEditor.chainages().map((chainage) => {
|
||||
const basin = basins.find((entry) => Math.abs(entry.chainage_m - chainage) < 0.51);
|
||||
return {
|
||||
chainage_m: chainage,
|
||||
effective_diameter_mm:
|
||||
basin && !basin.bridge_required ? (basin.pipe_diameter_mm ?? null) : null,
|
||||
};
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -130,8 +130,13 @@ export function renderBasinRows(
|
||||
const metrics = document.createElement("span");
|
||||
metrics.className = "b05-drainage__basin-metrics";
|
||||
// 유효직경은 강우량표(rainfall_table.json)가 생기기 전까지 null → "미정" 표기.
|
||||
const pipe =
|
||||
basin.pipe_diameter_mm === null
|
||||
// 관 최대 규격 초과 계류 유역은 관이 아니라 세월교 대상 — "세월교 검토"로 표기한다.
|
||||
const pipe = basin.bridge_required
|
||||
? L("B05_Drainage_Basin_Bridge").replace(
|
||||
"{d}",
|
||||
String(Math.round(basin.pipe_diameter_mm ?? 0)),
|
||||
)
|
||||
: basin.pipe_diameter_mm === null
|
||||
? L("B05_Drainage_Basin_Undecided")
|
||||
: `Ø${Math.round(basin.pipe_diameter_mm)}mm`;
|
||||
metrics.textContent = L("B05_Drainage_Basin_Metrics")
|
||||
|
||||
@@ -484,13 +484,18 @@ export function createRouteProfilePanel(
|
||||
// 그래프 40% : 테이블 60% (상단 정보 라인은 본문 밖이라 애초에 빠져 있다).
|
||||
// 가로 스크롤바를 `overflow-x: scroll`로 항상 띄우므로 clientHeight에서 이미 빠져 있다.
|
||||
const available = Math.max(120, body.clientHeight);
|
||||
// 테이블은 유토곡선과 같은 바닥 고정 오버레이 서브패널로 옮겼다(2026-08-05 사용자 지시).
|
||||
// 종단도는 본문 전체 높이를 쓰고, 바닥에 접힌 손잡이 띠(24px)만 남긴다 — 띠 없이는
|
||||
// 손잡이가 그래프 편집 버튼 위에 떠서 입력 클릭을 가로챈다(2026-08-04 사용자 보고).
|
||||
const chartHeight = Math.max(MIN_CHART_HEIGHT, available - MASSHAUL_HANDLE_GUTTER_PX);
|
||||
// 오버레이 순서(위→아래): 종단도 → 테이블 → 유토곡선. 유토곡선이 열려 있으면 그 높이만큼
|
||||
// 테이블 오버레이를 위로 밀어 쌓는다.
|
||||
tableOverlay.setBottomOffset(massHaul.overlay.hidden ? 0 : massHaul.overlay.offsetHeight);
|
||||
// 서브패널은 종단도를 **밀고 올라온다**(2026-08-05 사용자 확정 — 덮지 않는다).
|
||||
// · 둘 다 접힘: 종단도가 전체 높이(손잡이 띠 24px만 남김).
|
||||
// · 하나만 펼침: 그 패널 높이만큼 종단도가 줄어든다. 테이블 높이는 고정.
|
||||
// · 둘 다 펼침: 위→아래 = 종단도 → 테이블 → 유토곡선. 유토곡선 높이를 끌어 늘리면
|
||||
// 테이블은 그대로 두고 종단도가 그만큼 줄어든다(리사이저 onResize → draw 재계산).
|
||||
const massHeight = massHaul.overlay.hidden ? 0 : massHaul.overlay.offsetHeight;
|
||||
const tableOverlayHeight = tableOverlay.isOpen() ? tableOverlay.overlay.offsetHeight : 0;
|
||||
tableOverlay.setBottomOffset(massHeight);
|
||||
const chartHeight = Math.max(
|
||||
MIN_CHART_HEIGHT,
|
||||
available - massHeight - tableOverlayHeight - MASSHAUL_HANDLE_GUTTER_PX,
|
||||
);
|
||||
const tableHeight = tableOverlay.contentHeight();
|
||||
|
||||
const table =
|
||||
@@ -614,7 +619,8 @@ export function createRouteProfilePanel(
|
||||
}),
|
||||
);
|
||||
}
|
||||
canvas.style.height = `${available}px`;
|
||||
// 캔버스 높이 = 종단도 영역만. 서브패널이 차지한 아래 공간을 덮지 않는다(밀어올리기).
|
||||
canvas.style.height = `${chartHeight}px`;
|
||||
canvas.append(chartWrap);
|
||||
body.replaceChildren(canvas);
|
||||
body.scrollLeft = scrollLeft;
|
||||
|
||||
@@ -44,6 +44,7 @@ from common_util.common_util_route_geometry import (
|
||||
)
|
||||
from common_util.common_util_wamis_rainfall import idf_intensity
|
||||
from config.config_system import (
|
||||
DRAINAGE_BRIDGE_THRESHOLD_MM,
|
||||
DRAINAGE_DESIGN_FLOW_FACTOR,
|
||||
DRAINAGE_DITCH_SAMPLE_M,
|
||||
DRAINAGE_FLOW_AREA_RATIO,
|
||||
@@ -104,6 +105,9 @@ class WatershedBasin:
|
||||
tc_minutes: float | None = None
|
||||
intensity_mm_hr: float | None = None
|
||||
design_flow_m3s: float | None = None
|
||||
# 유효직경이 관 최대 규격을 넘는 계류 유역 — 관이 아니라 세월교·물넘이·교량 대상
|
||||
# (임도설치규정 제12조). 화면은 "세월교 검토"로 표기하고 관경 자동 지정을 하지 않는다.
|
||||
bridge_required: bool = False
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -529,6 +533,9 @@ def assemble_basins(
|
||||
tc_minutes=sizing["tc_minutes"] if sizing else None,
|
||||
intensity_mm_hr=sizing["intensity_mm_hr"] if sizing else None,
|
||||
design_flow_m3s=sizing["design_flow_m3s"] if sizing else None,
|
||||
bridge_required=bool(
|
||||
sizing and sizing["diameter_mm"] > DRAINAGE_BRIDGE_THRESHOLD_MM
|
||||
),
|
||||
)
|
||||
)
|
||||
return basins
|
||||
@@ -595,8 +602,8 @@ def size_pipe(
|
||||
pipe_slope = math.tan(math.radians(DRAINAGE_PIPE_SLOPE_DEG))
|
||||
diameter = 0.5
|
||||
for _ in range(20):
|
||||
velocity = (1.0 / DRAINAGE_MANNING_N) * (diameter / 4.0) ** (2.0 / 3.0) * math.sqrt(
|
||||
pipe_slope
|
||||
velocity = (
|
||||
(1.0 / DRAINAGE_MANNING_N) * (diameter / 4.0) ** (2.0 / 3.0) * math.sqrt(pipe_slope)
|
||||
)
|
||||
velocity = min(DRAINAGE_VELOCITY_MAX_MS, max(DRAINAGE_VELOCITY_MIN_MS, velocity))
|
||||
required_area = design_flow / velocity
|
||||
|
||||
+25
-2
@@ -341,6 +341,10 @@ DRAINAGE_VELOCITY_MIN_MS = float(os.getenv("DRAINAGE_VELOCITY_MIN_MS", "0.8"))
|
||||
DRAINAGE_VELOCITY_MAX_MS = float(os.getenv("DRAINAGE_VELOCITY_MAX_MS", "3.0"))
|
||||
# 원형관 통수단면 비율. 도로설계요령: 관 단면의 70%만 통수 고려.
|
||||
DRAINAGE_FLOW_AREA_RATIO = float(os.getenv("DRAINAGE_FLOW_AREA_RATIO", "0.7"))
|
||||
# 세월교 검토 문턱(mm). 유효직경이 관 최대 규격(파형강관 D2000)을 넘으면 관이 아니라
|
||||
# 세월교·물넘이·교량 대상이다 — 「임도설치 및 관리 등에 관한 규정」 제12조: 계류 횡단
|
||||
# 구간은 배수구 막힘 우려가 없는 물넘이 포장(세월교) 또는 교량으로 설계(2026-08-05 조사).
|
||||
DRAINAGE_BRIDGE_THRESHOLD_MM = float(os.getenv("DRAINAGE_BRIDGE_THRESHOLD_MM", "2000"))
|
||||
|
||||
# ── B05 구조물 옵션 (드롭다운 목록·기본값, 2026-08-05 사용자 확정) ──
|
||||
# 프론트는 이 값을 /api 설정 응답 또는 빌드타임 복사로 받아 쓴다. 수정은 여기서만 한다.
|
||||
@@ -349,8 +353,27 @@ STRUCTURE_DEFAULT_TYPE = "배관"
|
||||
PIPE_DIAMETERS_MM = {
|
||||
"이중벽관": (150, 200, 250, 300, 400, 450, 500, 600, 700, 800, 900, 1000, 1200, 1500),
|
||||
"삼중벽관": (200, 250, 300, 400, 450, 500, 600, 700, 800, 900, 1000, 1200, 1500),
|
||||
"파형강관": (150, 200, 250, 300, 350, 400, 450, 500, 600, 700, 800, 900, 1000,
|
||||
1200, 1350, 1500, 1650, 1800, 2000),
|
||||
"파형강관": (
|
||||
150,
|
||||
200,
|
||||
250,
|
||||
300,
|
||||
350,
|
||||
400,
|
||||
450,
|
||||
500,
|
||||
600,
|
||||
700,
|
||||
800,
|
||||
900,
|
||||
1000,
|
||||
1200,
|
||||
1350,
|
||||
1500,
|
||||
1650,
|
||||
1800,
|
||||
2000,
|
||||
),
|
||||
}
|
||||
PIPE_DEFAULT_TYPE = "파형강관"
|
||||
# 자동 지정 기본 관경. 별표2 (나) 예외 하한 800mm(사용자 결정 — 계산값이 더 크면 바로 위 규격).
|
||||
|
||||
@@ -77,6 +77,8 @@ export const ui_locales_b2 = {
|
||||
],
|
||||
B05_Drainage_Status_LoadFailed: ["배경도를 불러오지 못했습니다.", "Failed to load the basemap."],
|
||||
B05_Drainage_Basin_Undecided: ["미정", "TBD"],
|
||||
/* {d}=계산 유효직경(mm). 관 최대 규격 초과 계류 유역 — 관이 아니라 세월교 대상 */
|
||||
B05_Drainage_Basin_Bridge: ["세월교 검토 (Ø{d}mm)", "Ford crossing req. (Ø{d}mm)"],
|
||||
/* {area}=배수 유효면적, {relief}=표고차, {flow}=유하장, {pipe}=배수 유효직경 */
|
||||
B05_Drainage_Basin_Metrics: [
|
||||
"유효면적 {area} · 표고 {relief}m · 유하 {flow}m · 유효직경 {pipe}",
|
||||
|
||||
Reference in New Issue
Block a user