fix(B06 횡단): 사면 이동 절 ↔ 성 판정을 옮긴 노견에서 — 마루 너머 = 성토 1:n (370-1)
- 짝 common_util_cross_design_geometry.ts ↔ B06_Section_Engine_Design_Geometry.py — 노견 확장을 tilt 바로 뒤로 · 단면유형 · 자동 측구 판정은 옮긴 뒤 - 거울 사례 「마루 너머 = 성토 1:n」 · 「성 → 절 넘어감」 · 옛 사례 이름 「판정은 옮긴 노견」 - 서버 묶음 셋 다시 지음(이 파일 안 실음) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014utrjfoW831Vc5wJUd13kL
This commit is contained in:
@@ -103,6 +103,16 @@ class _SectionGeometry:
|
||||
low_left = ground_at(self.left_extent) < ground_at(-self.right_extent)
|
||||
self.slope_per_offset = -slope if low_left else slope
|
||||
|
||||
# 설계선 쉬프트 = 쪽마다 사면 이동(≥ 0 · 139-6 · 151-2) — 노견(폭 고정) · 측구 · 사면이
|
||||
# 같이 바깥으로 · 늘어난 폭은 차도 · 단면유형 · 측구 판정은 **옮긴 뒤** 노견에서(아래 ·
|
||||
# 370-1 — 마루를 넘으면 그 쪽 사면 기울기로 원지반까지). ⚠ TS 짝 `SectionGeometry`.
|
||||
self.shoulder_extend_left = max(shoulder_extend_left_m, 0.0)
|
||||
self.shoulder_extend_right = max(shoulder_extend_right_m, 0.0)
|
||||
self.half_road_left += self.shoulder_extend_left
|
||||
self.half_road_right += self.shoulder_extend_right
|
||||
self.left_extent += self.shoulder_extend_left
|
||||
self.right_extent += self.shoulder_extend_right
|
||||
|
||||
# 단면 유형 자동 판정(D-2): 각 측 절/성토 역할을 노면 끝 지반이 설계면보다
|
||||
# 높은지(절토)/낮은지(성토)로 결정한다. 좌절/우절/양절/양성이 모두 지형에서
|
||||
# 자연 도출된다. 사용자 입력 section_mode는 측구 방향(ditch_side) 기본값에만 쓰고
|
||||
@@ -156,16 +166,6 @@ class _SectionGeometry:
|
||||
if tilted:
|
||||
self.has_ditch = False
|
||||
|
||||
# 설계선 쉬프트 = 쪽마다 사면 이동(≥ 0 · 139-6 · 151-2) — 단면유형 · 측구 판정은 **옮기기 전**
|
||||
# 노견에서(위) · 노견(폭 고정) · 측구 · 사면이 같이 바깥으로 · 늘어난 폭은 차도.
|
||||
# ⚠ TS 짝 `SectionGeometry`.
|
||||
self.shoulder_extend_left = max(shoulder_extend_left_m, 0.0)
|
||||
self.shoulder_extend_right = max(shoulder_extend_right_m, 0.0)
|
||||
self.half_road_left += self.shoulder_extend_left
|
||||
self.half_road_right += self.shoulder_extend_right
|
||||
self.left_extent += self.shoulder_extend_left
|
||||
self.right_extent += self.shoulder_extend_right
|
||||
|
||||
# 측구 꼭짓점(측구측 노면 끝 기준, 바깥 방향 부호 적용).
|
||||
self.ditch_points: list[tuple[float, float]] = []
|
||||
edge_offset = self.left_extent if ditch_side == "left" else -self.right_extent
|
||||
|
||||
@@ -180,6 +180,16 @@ export class SectionGeometry {
|
||||
this.slopePerOffset = lowLeft ? -slope : slope;
|
||||
}
|
||||
|
||||
// 설계선 쉬프트 = 쪽마다 사면 이동(≥ 0 · 139-6 · 151-2) — 노견(폭 고정) · 측구 · 사면이 같이
|
||||
// 바깥으로 · 늘어난 폭은 차도 · 단면유형 · 측구 판정은 **옮긴 뒤** 노견에서(아래 · 370-1 — 마루를
|
||||
// 넘으면 그 쪽 사면 기울기로 원지반까지). ⚠ 파이썬 짝 `_SectionGeometry`.
|
||||
this.shoulderExtendLeft = Math.max(params.shoulderExtendLeftM ?? 0, 0);
|
||||
this.shoulderExtendRight = Math.max(params.shoulderExtendRightM ?? 0, 0);
|
||||
this.halfRoadLeft += this.shoulderExtendLeft;
|
||||
this.halfRoadRight += this.shoulderExtendRight;
|
||||
this.leftExtent += this.shoulderExtendLeft;
|
||||
this.rightExtent += this.shoulderExtendRight;
|
||||
|
||||
// 단면유형 자동 판정(D-2) — 노면 끝 지반이 설계면보다 높으면 절토, 낮으면 성토.
|
||||
const groundAt = params.groundAt;
|
||||
if (groundAt !== null) {
|
||||
@@ -226,15 +236,6 @@ export class SectionGeometry {
|
||||
// 물넘이포장 · 맹암거 자리(286-2 · 288-1) — 측구가 안 섬 · 선택은 그대로(파이썬 짝)
|
||||
if (params.tilted) this.hasDitch = false;
|
||||
|
||||
// 설계선 쉬프트 = 쪽마다 사면 이동(≥ 0 · 139-6 · 151-2) — 단면유형 · 측구 판정은 **옮기기 전**
|
||||
// 노견에서(위) · 노견(폭 고정) · 측구 · 사면이 같이 바깥으로 · 늘어난 폭은 차도. ⚠ 파이썬 짝 `_SectionGeometry`.
|
||||
this.shoulderExtendLeft = Math.max(params.shoulderExtendLeftM ?? 0, 0);
|
||||
this.shoulderExtendRight = Math.max(params.shoulderExtendRightM ?? 0, 0);
|
||||
this.halfRoadLeft += this.shoulderExtendLeft;
|
||||
this.halfRoadRight += this.shoulderExtendRight;
|
||||
this.leftExtent += this.shoulderExtendLeft;
|
||||
this.rightExtent += this.shoulderExtendRight;
|
||||
|
||||
// 측구 꼭짓점(측구측 노면 끝 기준, 바깥 방향 부호 적용).
|
||||
const edgeOffset = params.ditchSide === "left" ? this.leftExtent : -this.rightExtent;
|
||||
const outward = params.ditchSide === "left" ? 1 : -1;
|
||||
|
||||
@@ -61,6 +61,22 @@ def _dip_ground() -> list[dict]:
|
||||
return samples
|
||||
|
||||
|
||||
def _ridge_ground() -> list[dict]:
|
||||
"""우측 −4 m 까지 노면보다 높은 평지(절토) · 그 너머 급히 내려가는 마루(370-1)."""
|
||||
return [
|
||||
{"offset_m": o, "elevation_m": round(100.3 - 0.6 * max(0.0, -o - 4.0), 4), "valid": True}
|
||||
for o in (-12.0 + i * 0.5 for i in range(49))
|
||||
]
|
||||
|
||||
|
||||
def _rise_ground() -> list[dict]:
|
||||
"""좌측 +3 m 까지 노면보다 낮은 평지(성토) · 그 너머 오르막(370-1)."""
|
||||
return [
|
||||
{"offset_m": o, "elevation_m": round(99.6 + 0.4 * max(0.0, o - 3.0), 4), "valid": True}
|
||||
for o in (-12.0 + i * 0.5 for i in range(49))
|
||||
]
|
||||
|
||||
|
||||
# 갈래를 골고루 태운다 — 지반유형 셋 · 단면유형 · 측구 형식 · 포장 · 2단 경사 · 세월교
|
||||
# 노면 하강 · 곡선부 확폭(바깥쪽 좌/우) · 지반선 결측 구간.
|
||||
CASES = [
|
||||
@@ -214,8 +230,8 @@ CASES = [
|
||||
},
|
||||
},
|
||||
{
|
||||
# 노견 끝 근처에서 지반이 설계면을 넘는 자리 — 단면유형 · 측구 판정은 옮기기 전 노견에서
|
||||
"name": "노견 확장 — 판정은 옮기기 전 노견",
|
||||
# 노견 끝 근처에서 지반이 설계면을 넘는 자리 — 단면유형 · 측구 판정은 옮긴 노견에서(370-1)
|
||||
"name": "노견 확장 — 판정은 옮긴 노견",
|
||||
"samples": _ground(-0.05),
|
||||
"design_elevation_m": 100.0,
|
||||
"options": {
|
||||
@@ -226,6 +242,30 @@ CASES = [
|
||||
"shoulder_extend_left_m": 2.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
# 370-1 — 우 절토 마루를 넘겨 옮김 = 그 쪽 성토 1:n 으로 원지반까지(원지반 직선 아님)
|
||||
"name": "마루 너머 = 성토 1:n",
|
||||
"samples": _ridge_ground(),
|
||||
"design_elevation_m": 100.0,
|
||||
"options": {
|
||||
"ground_type": "soil",
|
||||
"section_mode": "right_cut",
|
||||
"ditch_side": "right",
|
||||
"shoulder_extend_right_m": 3.0,
|
||||
},
|
||||
},
|
||||
{
|
||||
# 370-1 — 좌 성토를 오르막으로 옮김 = 그 쪽 절토(측구 자동 판정 따름)
|
||||
"name": "성 → 절 넘어감",
|
||||
"samples": _rise_ground(),
|
||||
"design_elevation_m": 100.0,
|
||||
"options": {
|
||||
"ground_type": "soil",
|
||||
"section_mode": "left_cut",
|
||||
"ditch_side": "left",
|
||||
"shoulder_extend_left_m": 2.5,
|
||||
},
|
||||
},
|
||||
{
|
||||
# 151-2 — 곡선부 확폭과 사면 이동이 같은 쪽에 겹침(확폭 출력엔 이동 몫 안 섞임)
|
||||
"name": "확폭 좌 + 사면 이동 좌 0.4",
|
||||
@@ -490,3 +530,33 @@ def test_사면_이동은_노견째_평행이동_늘어난_폭은_차도() -> No
|
||||
both = by_name["확폭 좌 + 사면 이동 좌 0.4"]
|
||||
assert both["widening_left_m"] == curve["widening_left_m"] > 0
|
||||
assert abs(both["carriageway_width_m"] - (curve["carriageway_width_m"] + 0.4)) < 1e-9
|
||||
|
||||
|
||||
def _outer_slope(result: dict, side: str, skip: float = 0.0) -> float:
|
||||
"""노면 끝에서 `skip`(측구 폭) 바깥 설계선 한 마디의 기울기(dz / 바깥 거리)."""
|
||||
sign = 1.0 if side == "left" else -1.0
|
||||
start_offset = result["road_edges"][side]["offset_m"] + sign * skip
|
||||
line = sorted(result["design_line"], key=lambda p: sign * p["offset_m"])
|
||||
index = next(i for i, p in enumerate(line) if abs(p["offset_m"] - start_offset) < 1e-6)
|
||||
start, nxt = line[index], line[index + 1]
|
||||
return (nxt["elevation_m"] - start["elevation_m"]) / abs(nxt["offset_m"] - start["offset_m"])
|
||||
|
||||
|
||||
def test_절성_넘어가면_그_쪽_사면_기울기로_원지반까지() -> None:
|
||||
"""370-1 — 옮긴 노견에서 절/성 판정 · 마루 너머 = 성토 1:n · 성 → 절 = 절토 1:n + 측구 자동."""
|
||||
by_name = dict(zip((case["name"] for case in CASES), _python_results(), strict=True))
|
||||
soil = STANDARD_CROSS_SECTION["soil"]
|
||||
ridge = by_name["마루 너머 = 성토 1:n"]
|
||||
assert ridge["section_mode"] == "left_cut" # 우 = 성토
|
||||
assert ridge["ditch_enabled"] is False # 우 측구 자동 판정 따라 빠짐
|
||||
assert ridge["fill_area_m2"] > 0
|
||||
assert abs(_outer_slope(ridge, "right") + 1.0 / soil["fill_slope_ratio"]) < 1e-3
|
||||
rise = by_name["성 → 절 넘어감"]
|
||||
assert rise["section_mode"] == "left_cut" # 좌 = 절토
|
||||
assert rise["ditch_enabled"] is True and rise["ditch_side"] == "left"
|
||||
assert (
|
||||
abs(
|
||||
_outer_slope(rise, "left", soil["ditch"]["top_width_m"]) - 1.0 / soil["cut_slope_ratio"]
|
||||
)
|
||||
< 1e-3
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user