걷은 함수(운영 부름 0 · 전수 확인 = 화면 · 서버 · 체인 · 추천 엔진 · B07 · 시험) - common_util/common_util_excavation.py 통째(126 줄 · pipe_trench_width_m · wall_trench_area_m2 · wall_trench_width_m · 서버 = Node excavation.trench) - Engine_Grade_Carry.carry_edits(Node carry_seat 겉) · Route_Save_Parts.seat_route_moved(시험 헬퍼 helper_475_1_moved 로 옮김) - Engine_Tilt.attach_underdrains · Engine_Structures_Wall.attach_wall_structures · load_wall_structures - Engine_Grade_Alignment.tangent_elevation(부름 0) · station_key.dedupe_station_keys · loose_chainage 줄 수 전 → 후: excavation.py 126 → 0 · Grade_Carry 178 → 157 · Save_Parts 289 → 269 · Wall 221 → 197 · Tilt 115 → 112 · station_key 141 → 122 · Alignment 657 → 654 남는 짝(머리 「남는 까닭」 한 줄) — Grade · Grade_Profile · Alignment · CurveLaw(2~4 순위 폴백 · 추천) · NodeEdits · SampleExtend · Router_Design · Ranges · Engine_Design · Areas · cross_berm(DTM 아닌 지표면 · Node 못 부를 때 · B07 · 추천) · Tilt · Wall · Culvert(B04 B07 B08) · route_follow · structure_station · station_key · route_polyline(745 줄 · 까닭 = 등록부 R1 줄) 등록부 — until 칸 걷음(G1 = py 표본기 남김 · 까닭 note) · C6 pair = attach_underdrain_specs · F8 pair null 알려진 차 — golden KNOWN 셋 그대로 나타남(R7 표본 출처 · W0 저장 때 경고 · X2 입력 선 자릿수 · 까닭 고침) · underdrain 알려진 차 까닭 · 511_b5 KNOWN_ARC 그대로 계산 자리 창 — 45 줄 · 서버만 아닌 41(바꿀 수 있음 40 + F9) · 서버만 넷(G3 D1 D2 N1 줄마다 까닭) · 옛 까닭 「짝 모으는 중 · B-4」 글 걷음 test_322_3_flow 빨강 — 헬퍼가 @config/config_frontend 흉내(511-A design_calc_server import) 시험 기준 — 걷은 짝 거울 = 걷기 전 파이썬 값 고정(excavation · station_key) · Node carry_seat · attach_underdrain_specs · wall_specs_from 검증: 고친 대상 시험 97 파일 562 통과 · 21 건너뜀 · typecheck 0 · 700 줄 넘는 새 파일 없음 — 요구 320-4 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
138 lines
4.8 KiB
Python
138 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""178-3 사면안정 흙막이 · 옹벽 「추가 단」 상자 → 여러 단 횡단 형상.
|
|
|
|
못박는 것
|
|
- 상자 = 유출 흙막이 상자 양식(공용 [추가] · [빼기]) · 흙막이 = 형태 · 높이 · 옹벽 = 높이만 · 키 `tier_{n}_*`.
|
|
- 명세 저장 왕복 그대로 · 빈 상자도 한 단으로 남음 · 정의 그룹 종류 그대로(`STRUCTURE_SPECS` 에 안 넣음).
|
|
- 서버 저장(structures.json) → 벽 제원(파이썬) 단 수 = 1 + 상자 수 · 단마다 형태 · 높이 · 옹벽 단 = 콘크리트.
|
|
- 횡단 형상(진짜 `computeRevetmentLayout`) — 단 수 · 단마다 형태 · 높이(빈 값 = 본 벽 형태 · 1.5 m) · 옛 `tiers` 그대로.
|
|
|
|
Node 헬퍼 `helper_178_3_slope_tiers.cjs`. 화면은 사용자 확인.
|
|
"""
|
|
|
|
import json
|
|
import os
|
|
import subprocess
|
|
|
|
import pytest
|
|
|
|
from B05_Profile.B05_Profile_Structures_Schema import StructureInstance
|
|
|
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
|
ROOT = os.path.abspath(os.path.join(HERE, "..", ".."))
|
|
|
|
SOIL = {
|
|
"form": "돌쌓기(찰)",
|
|
"length_m": 20,
|
|
"height_m": 2,
|
|
"before_m": 10,
|
|
"after_m": 10,
|
|
"tier_1_form": "콘크리트",
|
|
"tier_1_height": 2,
|
|
"tier_2_form": "돌망태",
|
|
"tier_2_height": 1.2,
|
|
}
|
|
|
|
|
|
def _read(*parts: str) -> str:
|
|
with open(os.path.join(ROOT, *parts), encoding="utf-8") as handle:
|
|
return handle.read()
|
|
|
|
|
|
@pytest.fixture(scope="module")
|
|
def out():
|
|
proc = subprocess.run(
|
|
["node", os.path.join(HERE, "helper_178_3_slope_tiers.cjs")],
|
|
capture_output=True,
|
|
text=True,
|
|
encoding="utf-8",
|
|
timeout=60,
|
|
)
|
|
assert proc.returncode == 0, proc.stderr
|
|
return json.loads(proc.stdout)
|
|
|
|
|
|
def test_상자_칸_흙막이_형태_높이_옹벽_높이(out):
|
|
assert out["roundTrip"]["items"] == {
|
|
"soil_guard": ["form", "height"],
|
|
"retaining_wall": ["height"],
|
|
}
|
|
assert out["roundTrip"]["notMainSpecs"] == []
|
|
|
|
|
|
def test_명세_저장_왕복(out):
|
|
trip = out["roundTrip"]
|
|
assert trip["soilState"] == [
|
|
{"form": "콘크리트", "height": "2"},
|
|
{"form": "돌망태", "height": "1.2"},
|
|
]
|
|
assert trip["soilBack"] == {
|
|
"tier_1_form": "콘크리트",
|
|
"tier_1_height": 2,
|
|
"tier_2_form": "돌망태",
|
|
"tier_2_height": 1.2,
|
|
}
|
|
assert trip["wallBack"] == {"tier_1_height": 1.8}
|
|
assert trip["emptyBox"] == {"tier_1_form": ""} # 값 없이 추가만 해도 단 하나
|
|
|
|
|
|
def test_서버_저장_뒤_벽_제원(tmp_path):
|
|
from B05_Profile.B05_Profile_Structures_Repository import load_structures, save_structures
|
|
from B06_Section import B06_Section_Engine_Structures_Wall as wall
|
|
|
|
items = [
|
|
StructureInstance(
|
|
type_id="soil_guard",
|
|
placement="interval",
|
|
chainage_m=180,
|
|
start_m=170,
|
|
end_m=190,
|
|
options=SOIL,
|
|
),
|
|
StructureInstance(
|
|
type_id="retaining_wall",
|
|
placement="interval",
|
|
chainage_m=300,
|
|
start_m=290,
|
|
end_m=310,
|
|
options={"height_m": 2.5, "tier_1_height": 1.8},
|
|
),
|
|
]
|
|
save_structures(str(tmp_path), items, base_revision=0)
|
|
stored = load_structures(str(tmp_path))[1]
|
|
got = {spec["type_id"]: spec for spec in wall.wall_specs_from(stored)}
|
|
assert got["soil_guard"]["tiers"] == 3
|
|
assert got["soil_guard"]["extras"] == [
|
|
{"form": "콘크리트", "height_m": 2},
|
|
{"form": "돌망태", "height_m": 1.2},
|
|
]
|
|
assert got["retaining_wall"]["tiers"] == 2
|
|
assert got["retaining_wall"]["extras"] == [{"form": "콘크리트", "height_m": 1.8}]
|
|
|
|
|
|
def test_횡단_형상_단_수_단마다_형태_높이(out):
|
|
assert out["soil2"]["requested"] == 3
|
|
assert out["soil2"]["walls"] == [
|
|
{"form": "돌쌓기(찰)", "pure": 2},
|
|
{"form": "콘크리트", "pure": 2},
|
|
{"form": "돌망태", "pure": 1.2},
|
|
]
|
|
assert out["wall1"]["walls"] == [
|
|
{"form": "콘크리트", "pure": 2.5},
|
|
{"form": "콘크리트", "pure": 1.8},
|
|
]
|
|
# 빈 상자 = 본 벽 형태 · 기본 1.5 m · 상자 없으면 옛 tiers 그대로 · 둘 다 없으면 1단
|
|
assert out["emptyBox"]["walls"][1] == {"form": "돌망태", "pure": 1.5}
|
|
assert out["legacy"]["requested"] == 2 and out["legacy"]["extras"] == []
|
|
assert out["none"]["requested"] == 1
|
|
|
|
|
|
def test_배선():
|
|
spec = _read("B05_Profile", "B05_Profile_UI_Structures_Spec.ts")
|
|
# 명세 · 덧붙이 명세 = 본보기 키로(323-7 · 복사한 종류도 같은 상자)
|
|
assert "specFor(type.type_id) ?? ADDON_SPECS[baseType(type.type_id)]" in spec
|
|
walls = _read("common_util", "common_util_structure_walls.ts")
|
|
assert "파이썬 `tier_extras` 짝" in walls
|
|
engine = _read("B06_Section", "B06_Section_Engine_Structures_Wall.py")
|
|
assert "TS `tierExtras` 짝" in engine
|