feat(B06): 절토면적을 암반 경계선 기준 토사/암반으로 분리하고 유토곡선에 배선
절토부의 토사·암반 구분은 환산계수가 아니라 횡단도 기하로 갈린다. 지표면~암반 경계선이 토사, 그 아래가 암이다. 기존에는 측점당 절토 단면적이 하나뿐이라 리핑암/발파암 측점의 상단 토사층까지 암 환산계수로 곱해졌다(실데이터 기준 다짐환산 +21% 과대). - Engine_Design: `_split_cut_areas()` 신설. `d=0`, `d=t0` 교차점을 브레이크포인트로 넣어 정확 적분(무작위 2,000회 검산 `soil+rock==cut` 최대오차 1.4e-14). `cut_soil_area_m2` / `cut_rock_area_m2` / `cut_rock_kind` 3필드 추가(기존 키 불변). - UI_Cross_Areas(신규): 면적 readout을 4칩으로 확장하고 절토(토사)/절토(암반)/성토 밴드를 그린다. 선택된 카드에서만 붙어 다른 측점을 고르면 자동 해제된다. - UI_MassHaul: `AreaSample`을 2분할로 교체해 부분별 환산계수를 물리고, 측점별 구간 물량 내역(토사/암반/다짐환산/성토)을 남긴다. 구 데이터는 전량 측점 지반유형으로 폴백. - UI_MassHaul_View: 선택 측점의 구간 물량 표기 줄과 곡선 위 강조점 추가. 측점 매칭은 id가 아니라 누가거리로 한다(종단 기준 곡선의 점 id는 파생값이라 형태가 다름). 암반 경계선 오프셋을 바꾸면 분리 면적과 유토곡선 환산량이 함께 움직인다. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -136,6 +136,45 @@ def _trapezoid_areas(offsets: list[float], diffs: list[float]) -> tuple[float, f
|
||||
return cut_area, fill_area
|
||||
|
||||
|
||||
def _split_cut_areas(
|
||||
offsets: list[float], diffs: list[float], soil_depth_m: float
|
||||
) -> tuple[float, float]:
|
||||
"""절토 면적을 암반 경계선 기준으로 (토사, 암반)으로 나눈다.
|
||||
|
||||
암반 경계선은 지반선 평행 복사(`지반고 + rock_boundary_offset_m`)이므로 토사층 두께
|
||||
`t0`가 절토 구간 전체에서 균일하다. 따라서 오프셋별 절토 종거 `d = 지반고 - 설계고`에
|
||||
대해 토사분은 `min(max(d, 0), t0)`, 암반분은 `max(d - t0, 0)`이며 두 값의 합은 항상
|
||||
`max(d, 0)`이라 `_trapezoid_areas`의 절토 면적과 정확히 일치한다.
|
||||
|
||||
두 함수 모두 `d = 0`과 `d = t0`에서 꺾이므로 그 교차점을 구간 분할점으로 넣어야
|
||||
사다리꼴 적분이 근사가 아닌 정확값이 된다.
|
||||
"""
|
||||
t0 = max(float(soil_depth_m), 0.0)
|
||||
soil_area = 0.0
|
||||
rock_area = 0.0
|
||||
for index in range(1, len(offsets)):
|
||||
x0, x1 = offsets[index - 1], offsets[index]
|
||||
d0, d1 = diffs[index - 1], diffs[index]
|
||||
width = x1 - x0
|
||||
if width <= 0:
|
||||
continue
|
||||
ratios = [0.0, 1.0]
|
||||
for level in (0.0, t0):
|
||||
if (d0 - level) * (d1 - level) < 0:
|
||||
ratios.append((level - d0) / (d1 - d0))
|
||||
ratios.sort()
|
||||
for step in range(1, len(ratios)):
|
||||
ratio_a, ratio_b = ratios[step - 1], ratios[step]
|
||||
span = width * (ratio_b - ratio_a)
|
||||
if span <= 0:
|
||||
continue
|
||||
d_a = d0 + (d1 - d0) * ratio_a
|
||||
d_b = d0 + (d1 - d0) * ratio_b
|
||||
soil_area += (min(max(d_a, 0.0), t0) + min(max(d_b, 0.0), t0)) / 2.0 * span
|
||||
rock_area += (max(d_a - t0, 0.0) + max(d_b - t0, 0.0)) / 2.0 * span
|
||||
return soil_area, rock_area
|
||||
|
||||
|
||||
def _ground_interpolator(valid: list[tuple[float, float]]):
|
||||
"""정렬된 (offset, 지반고) 샘플의 선형 보간 함수를 만든다(범위 밖 끝값 클램프)."""
|
||||
|
||||
@@ -501,6 +540,22 @@ def compute_cross_design(
|
||||
# 측구 굴착은 설계선에 포함돼 절토 면적에 자연 반영된다(별도 가산 없음 — 이중계상 방지).
|
||||
cut_area, fill_area = _trapezoid_areas(offsets, diffs)
|
||||
|
||||
# 절토면적 토사/암반 분리 — 지표면~암반 경계선이 토사, 그 아래가 암이다. 경계선 위치가
|
||||
# 곧 유토곡선 EA/RR/BR 비율을 만들므로, 사용자가 경계선을 올리내리면 이 값이 함께 바뀐다.
|
||||
# 토사 지반은 암반 경계선 자체가 없어 전량 토사, 암 지반인데 경계선 값이 없으면(구 데이터)
|
||||
# 분리 근거가 없으므로 전량 암으로 둔다(기존 단일 지반유형 환산과 같은 결과).
|
||||
if preset_key != "rock":
|
||||
cut_soil_area, cut_rock_area = cut_area, 0.0
|
||||
cut_rock_kind: str | None = None
|
||||
elif rock_boundary_offset_m is None:
|
||||
cut_soil_area, cut_rock_area = 0.0, cut_area
|
||||
cut_rock_kind = ground_type
|
||||
else:
|
||||
cut_soil_area, cut_rock_area = _split_cut_areas(
|
||||
offsets, diffs, abs(float(rock_boundary_offset_m))
|
||||
)
|
||||
cut_rock_kind = ground_type
|
||||
|
||||
# 측구 공칭 단면적(수량 산출 참고용): 일반=사다리꼴, L형=직각삼각형 근사.
|
||||
if not geometry.has_ditch:
|
||||
ditch_area = 0.0
|
||||
@@ -575,6 +630,10 @@ def compute_cross_design(
|
||||
},
|
||||
"design_elevation_m": round(float(design_elevation_m), 4),
|
||||
"cut_area_m2": round(cut_area, 4),
|
||||
# 절토 내역(합=cut_area_m2). 유토곡선이 지반유형별 환산계수를 물리는 단위다.
|
||||
"cut_soil_area_m2": round(cut_soil_area, 4),
|
||||
"cut_rock_area_m2": round(cut_rock_area, 4),
|
||||
"cut_rock_kind": cut_rock_kind,
|
||||
"fill_area_m2": round(fill_area, 4),
|
||||
"ditch_area_m2": round(ditch_area, 4),
|
||||
"design_line": design_line,
|
||||
|
||||
Reference in New Issue
Block a user