- 한몸으로 동작하는 두 페이지라 한 커밋으로 처리 (상호 참조 다수) - B05 37파일 + B06 20파일 접두사 개명 (git mv, 이력 보존) - 참조 치환 91파일: import 경로, 라우트 슬러그(b05-profile/b06-section), 라우트 키(B05_PROFILE/B06_SECTION), B03 자동 체인, storage 상수, pyproject 제외 경로 - 로직 변경 없음. typecheck·백엔드 import 검증 통과 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
83 lines
3.5 KiB
Python
83 lines
3.5 KiB
Python
"""B06 횡단 단면적 적분 — 절·성토 면적과 절토의 토사/암반 분리.
|
|
|
|
`_Engine_Design.py`가 700줄을 넘겨, 「설계선을 어떻게 세우나」(그쪽)와 「그 선과 지반 사이
|
|
넓이를 어떻게 재나」(여기)로 갈랐다. 두 함수 모두 지반선과 설계선의 **차이 배열**만 받으므로
|
|
설계 로직을 전혀 모른다 — 그래서 따로 떼어 검산하기도 쉽다.
|
|
"""
|
|
|
|
|
|
def _trapezoid_areas(offsets: list[float], diffs: list[float]) -> tuple[float, float]:
|
|
"""오프셋 순 (지반-설계) 차이를 사다리꼴 적분해 (절토, 성토) 면적을 반환한다.
|
|
|
|
diff>0(지반이 설계보다 높음)=절토, diff<0=성토. 부호가 바뀌는 구간은 영교점에서
|
|
나눠 절·성토가 섞이지 않게 한다.
|
|
"""
|
|
cut_area = 0.0
|
|
fill_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
|
|
if d0 == 0 and d1 == 0:
|
|
continue
|
|
if d0 * d1 < 0:
|
|
# 부호 변화: 영교점에서 두 삼각형으로 분리
|
|
zero_ratio = d0 / (d0 - d1)
|
|
x_zero = x0 + width * zero_ratio
|
|
left_area = 0.5 * (x_zero - x0) * abs(d0)
|
|
right_area = 0.5 * (x1 - x_zero) * abs(d1)
|
|
if d0 > 0:
|
|
cut_area += left_area
|
|
fill_area += right_area
|
|
else:
|
|
fill_area += left_area
|
|
cut_area += right_area
|
|
continue
|
|
area = 0.5 * (d0 + d1) * width
|
|
if area >= 0:
|
|
cut_area += area
|
|
else:
|
|
fill_area += -area
|
|
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
|