Merge remote-tracking branch 'origin/sub_laptop_7' into main_laptop_1
This commit is contained in:
@@ -24,7 +24,10 @@ const input = JSON.parse(fs.readFileSync(process.argv[2], "utf8"));
|
||||
const station = loadTs(path.join(ROOT, "common_util", "common_util_structure_station.ts"));
|
||||
|
||||
const ford = loadTs(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Ford_Pavement.ts"), {
|
||||
"./B06_Section_UI_Cross_Wall_Hatch": { appendChuteBand() {} },
|
||||
"./B06_Section_UI_Cross_Wall_Hatch": loadTs(
|
||||
path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Wall_Hatch.ts"),
|
||||
{ "./B06_Section_UI_Cross_Culvert_Const": {} },
|
||||
),
|
||||
"./B06_Section_UI_Cross_Design_Surface": { appendPavementOverlay() {} },
|
||||
});
|
||||
// 286-3 도수로 · 돌붙임 길이 — 유출(좌 · 우가 높음) 성토사면 1:1.5(5 m 내려감 · 사면 길이 √(7.5²+5²) ≈ 9.01)
|
||||
|
||||
@@ -55,8 +55,40 @@ pave.appendFordPavementOverlay(
|
||||
);
|
||||
const paveLayer = svg.children.find((k) => (k.attrs.class ?? "").includes("ford-pavement"));
|
||||
|
||||
// 294-4 도수로 · 돌붙임 끝단 · 길이
|
||||
const hatch = load(path.join(ROOT, "B06_Section", "B06_Section_UI_Cross_Wall_Hatch.ts"));
|
||||
const P = (offset, elevation) => ({ offset, elevation });
|
||||
const slope = [{ points: [P(0, 0), P(3, -4)], kind: "fill" }]; // 사면 5 m
|
||||
const flat = [P(3, -4), P(5, -4), P(8, -4)]; // 사면 끝 바깥 원지반
|
||||
const pts = (lines) =>
|
||||
lines.map((l) => l.points.map((p) => [+p.offset.toFixed(4), +p.elevation.toFixed(4)]));
|
||||
const dipGround = hatch.groundLine(input.dipSamples);
|
||||
const fillGround = hatch.groundLine(input.fillSamples);
|
||||
const calc = load(path.join(ROOT, "A00_Common", "design", "design_structure_ford_calc.ts"));
|
||||
const formOf = (state) => ({ state: () => state, setValue: (c, i, v) => (state[c][0][i] = v) });
|
||||
const fordState = { ford: [{ width: "8" }], chute_add: [{ length_m: "2.5", area: "30" }] };
|
||||
calc.syncChuteArea(formOf(fordState), { id: "chute_add" }, { id: "length_m" }, "chute_add", "ford");
|
||||
const guard = load(path.join(ROOT, "A00_Common", "design", "design_structure_guard.ts"));
|
||||
const fordPave = load(path.join(ROOT, "A00_Common", "design", "design_structure_ford_pavement.ts"));
|
||||
|
||||
const out = {
|
||||
edges: pave.fordEdges(design),
|
||||
pavePoints: paveLayer?.attrs.points ?? null,
|
||||
runNone: pts(hatch.chuteRun(slope)),
|
||||
runShort: pts(hatch.chuteRun(slope, 2)),
|
||||
runLong: pts(hatch.chuteRun(slope, 7, flat)),
|
||||
runPointOnly: pts(hatch.chuteRun([{ points: [P(3, -4)] }])),
|
||||
runPointLength: pts(hatch.chuteRun([{ points: [P(3, -4)] }], 2, flat)),
|
||||
dipLine: pave.outletFillLine(design, dipGround),
|
||||
dipChute: pave.fordChuteLine(design, {}, dipGround),
|
||||
dipChuteLength: pave.fordChuteLine(design, { length_m: 1.5 }, dipGround),
|
||||
fillLine: pave.outletFillLine(input.fillDesign, fillGround),
|
||||
fillLineOld: pave.outletFillLine(input.fillDesign),
|
||||
fillChuteLength: pave.fordChuteLine(input.fillDesign, { length_m: 1 }, fillGround),
|
||||
fordArea: fordState.chute_add[0].area,
|
||||
chuteItems: guard.CHUTE_ITEMS.map((i) => i.id),
|
||||
fordPaveChuteSame:
|
||||
fordPave.FORD_PAVEMENT_SPEC.containers.find((c) => c.id === "chute").items ===
|
||||
guard.CHUTE_ITEMS,
|
||||
};
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
|
||||
@@ -55,9 +55,8 @@ def test_거름_한_벌_배선() -> None:
|
||||
culvert = _src("B06_Section/B06_Section_UI_Cross_Culvert.ts")
|
||||
assert "layout.outletFill.segments.filter(isChuteSegment)," in culvert
|
||||
corridor = _src("B05_Profile/B05_Profile_UI_Corridor_Structures.ts")
|
||||
assert (
|
||||
"chuteBands(layout.outletFill.segments, section.culvert?.chute, isChuteSegment)" in corridor
|
||||
)
|
||||
flat = " ".join(corridor.split())
|
||||
assert "chuteBands( layout.outletFill.segments, section.culvert?.chute, isChuteSegment," in flat
|
||||
hatch = _src("B06_Section/B06_Section_UI_Cross_Wall_Hatch.ts")
|
||||
assert '"3도 절토선"' in hatch
|
||||
# 박스 · 세월교 본체 끝은 성토만(3도 규칙 안 넓힘)
|
||||
|
||||
@@ -174,8 +174,7 @@ def test_도수로_길이_없음_원지반까지_있음_그_길이(ts):
|
||||
def test_컨테이너_같은_칸_맨_아래_길이():
|
||||
spec = _read("A00_Common", "design", "design_structure_ford_pavement.ts")
|
||||
assert (
|
||||
'items: [...CHUTE_ITEMS, { id: "length_m", label: "길이 (m)", kind: "number", step: 0.1 }],'
|
||||
in spec
|
||||
"items: CHUTE_ITEMS," in spec # 공용 칸 맨 아래 길이(294-4 · CHUTE_ITEMS 로 옮김)
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
처음 만나는 자리까지(그 쪽 절토 사면 없음 · `tilt_reach`) · 성토 쪽 그대로 · 반폭 안에서 못 만나면 옛 길 ·
|
||||
서버 정본 ↔ TS 짝 같은 값 = 횡단 설계 거울(`test_b06_cross_design_mirror` 「물넘이포장 낮은 쪽 노면
|
||||
연장」) · 그림 = 콘크리트(포장층)가 늘인 끝까지.
|
||||
- 294-4 도수로/돌붙임 띠 = 낮은 쪽 끝단(늘인 끝 · 아니면 유출 쪽 노견 끝)에서 성토 사면 따라 · 길이 비움 =
|
||||
원지반 닿으면 끝 · 양측 절토 물넘이 = 띠 없음 · 길이 = 그 길이(사면보다 길면 원지반 따라) · 다른 구조물
|
||||
(배관 · 박스 · 세월교) 같은 규칙(`chuteRun` · 원지반 `layout.ground`) + 같은 「길이 (m)」 칸 · 면적 = 세월교만
|
||||
월류 폭 × 길이(배관 · 박스 = 폭 정의 없어 자동 안 함) · 길이는 집계 · B08 수량에 안 실림.
|
||||
|
||||
진짜 TS 는 `helper_294_3_ford_extend_chute.cjs` 가 Node 로 돌림. 화면은 사용자 확인.
|
||||
"""
|
||||
@@ -60,7 +64,15 @@ def dip() -> dict:
|
||||
@pytest.fixture(scope="module")
|
||||
def ts(dip, tmp_path_factory) -> dict:
|
||||
source = tmp_path_factory.mktemp("s294") / "in.json"
|
||||
source.write_text(json.dumps({"design": dip}), encoding="utf-8")
|
||||
fill_samples = _line(lambda o: 100.0 + 0.35 * o)
|
||||
fill = compute_cross_design(fill_samples, 100.4, **KW)
|
||||
payload = {
|
||||
"design": dip,
|
||||
"dipSamples": _dip_ground(),
|
||||
"fillSamples": fill_samples,
|
||||
"fillDesign": fill,
|
||||
}
|
||||
source.write_text(json.dumps(payload), encoding="utf-8")
|
||||
proc = subprocess.run(
|
||||
["node", str(HERE / "helper_294_3_ford_extend_chute.cjs"), str(source)],
|
||||
capture_output=True,
|
||||
@@ -110,3 +122,80 @@ def test_콘크리트는_늘인_끝까지(dip, ts):
|
||||
}
|
||||
first = ts["pavePoints"].split()[1] # 포장층 윗면 우 끝
|
||||
assert float(first.split(",")[0]) == pytest.approx(-4.3333, abs=1e-4)
|
||||
|
||||
|
||||
def test_띠_길이_맞춤_공용(ts):
|
||||
assert ts["runNone"] == [[[0, 0], [3, -4]]] # 길이 없음 = 원지반 닿으면 끝(그대로)
|
||||
assert ts["runShort"] == [[[0, 0], [1.2, -1.6]]] # 길이 2 = 사면 따라 2 m
|
||||
assert ts["runLong"] == [[[0, 0], [3, -4]], [[3, -4], [5, -4]]] # 사면 5 + 원지반 2
|
||||
assert ts["runPointOnly"] == [] # 끝단이 이미 원지반 · 길이 없음 = 안 그림
|
||||
assert ts["runPointLength"] == [[[3, -4], [5, -4]]]
|
||||
|
||||
|
||||
def test_양측_절토_물넘이_띠_없음(ts):
|
||||
assert len(ts["dipLine"]) == 1 # 늘인 끝이 원지반
|
||||
assert ts["dipLine"][0]["offset"] == pytest.approx(-4.3333, abs=1e-4)
|
||||
assert ts["dipChute"] == []
|
||||
tail = ts["dipChuteLength"] # 길이를 넣으면 늘인 끝에서 원지반 따라 그 길이
|
||||
assert tail[0]["offset"] == pytest.approx(-4.3333, abs=1e-4) and len(tail) >= 2
|
||||
|
||||
|
||||
def test_성토_쪽_띠는_원지반_닿으면_끝(ts):
|
||||
line = ts["fillLine"]
|
||||
end = line[-1]
|
||||
assert end["elevation"] == pytest.approx(100.0 + 0.35 * end["offset"], abs=1e-3) # 원지반 위
|
||||
assert len(ts["fillLineOld"]) > len(line) # 원지반을 모르면 내려가는 원지반까지 따라갔음
|
||||
chute = ts["fillChuteLength"]
|
||||
start, stop = chute[0], chute[-1]
|
||||
assert (stop["offset"] - start["offset"]) ** 2 + (
|
||||
stop["elevation"] - start["elevation"]
|
||||
) ** 2 == pytest.approx(1.0, abs=1e-6)
|
||||
|
||||
|
||||
def test_다른_구조물_같은_규칙과_길이_칸(ts):
|
||||
assert ts["chuteItems"][-1] == "length_m"
|
||||
assert ts["fordPaveChuteSame"] is True
|
||||
assert ts["fordArea"] == "20" # 세월교 월류 폭 8 × 길이 2.5
|
||||
hatch = (ROOT / "B06_Section" / "B06_Section_UI_Cross_Wall_Hatch.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "const lines = chuteRun(allLines, chute.length_m, ground);" in hatch
|
||||
for name in ("Culvert", "Box", "Ford"):
|
||||
overlay = (ROOT / "B06_Section" / f"B06_Section_UI_Cross_{name}.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert "layout.ground," in overlay
|
||||
form = (ROOT / "B05_Profile" / "B05_Profile_UI_Drainage_Facility.ts").read_text(
|
||||
encoding="utf-8"
|
||||
)
|
||||
assert form.count("syncChuteArea(") == 2 # 물넘이 · 세월교만(배관 · 박스 = 폭 정의 없음)
|
||||
|
||||
|
||||
def test_길이는_집계_수량에_안_실림():
|
||||
from B06_Section.B06_Section_Engine_Culvert import _chute
|
||||
from B08_Quantity.B08_Quantity_Router_Summary import _chutes
|
||||
from M02_MasterTemplete.M02_Table_Fill_Spec import container_rows
|
||||
|
||||
options = {
|
||||
"chute_add_1_structure": "돌붙임",
|
||||
"chute_add_1_bond": "찰붙임",
|
||||
"chute_add_1_area": 12,
|
||||
}
|
||||
longer = {**options, "chute_add_1_length_m": 7}
|
||||
assert _chute(longer)["length_m"] == 7 and "length_m" not in _chute(options)
|
||||
|
||||
class Sheet:
|
||||
def __init__(self) -> None:
|
||||
self.rows: list[tuple] = []
|
||||
|
||||
def add(self, at, key, sort, group, label, value, combos) -> None:
|
||||
self.rows.append((key, label, value))
|
||||
|
||||
sheet = Sheet()
|
||||
_chutes(sheet, 50.0, longer, {"gchuteadd1": "SS1"}, {})
|
||||
assert sheet.rows == [("chute|찰붙임", "㎡", 12.0)]
|
||||
item = {"type_id": "pipe", "options": options, "복사본": "pipe@50.0", "흙막이단": 0}
|
||||
plain = container_rows(item, {"gchuteadd1": "SS1"})
|
||||
long = container_rows({**item, "options": longer}, {"gchuteadd1": "SS1"})
|
||||
for key in ("length_m", "inlet_revet_length_m", "outlet_revet_length_m", "area_m"):
|
||||
assert plain[0]["options"].get(key) == long[0]["options"].get(key)
|
||||
|
||||
@@ -113,4 +113,7 @@ def test_정의_파일에_세월교_이름_표가_올라_있음():
|
||||
os.path.join(ROOT, "resources", "master_template", "구조물정의.json"), encoding="utf-8"
|
||||
) as f:
|
||||
doc = json.load(f)
|
||||
assert doc["종류"]["ford_bridge"]["이름"] == names
|
||||
# 그림 전용 길이 칸(294-4)은 마스터 정의 이름 표에 안 올림(마스터 손대지 않음) — 대조 밖
|
||||
assert doc["종류"]["ford_bridge"]["이름"] == {
|
||||
k: v for k, v in names.items() if k != "chute_add.length_m"
|
||||
}
|
||||
|
||||
@@ -102,7 +102,8 @@ def test_정의_파일에_이름_표_그룹_선택지가_올라_있음():
|
||||
os.path.join(ROOT, "resources", "master_template", "구조물정의.json"), encoding="utf-8"
|
||||
) as f:
|
||||
doc = json.load(f)
|
||||
assert set(names) == set(doc["종류"]["box_culvert"]["이름"])
|
||||
# 그림 전용 길이 칸(294-4)은 마스터 정의 이름 표에 안 올림(마스터 손대지 않음) — 대조 밖
|
||||
assert set(names) - {"chute_add.length_m"} == set(doc["종류"]["box_culvert"]["이름"])
|
||||
assert [g["id"] for g in doc["그룹"]["box_culvert"]] == ["gboxbody", "gboxin", "gboxout"]
|
||||
box = next(t for t in doc["types"] if t["type_id"] == "box_culvert")
|
||||
wing = {o["key"]: o for o in box["options"]}
|
||||
|
||||
@@ -107,5 +107,6 @@ def test_정의_파일에_이름_표가_올라_있음():
|
||||
) as f:
|
||||
doc = json.load(f)
|
||||
on_file = doc["종류"]["pipe"]["이름"]
|
||||
assert set(names) == set(on_file)
|
||||
# 그림 전용 길이 칸(294-4)은 마스터 정의 이름 표에 안 올림(마스터 손대지 않음) — 대조 밖
|
||||
assert set(names) - {"chute_add.length_m"} == set(on_file)
|
||||
assert on_file["inlet.structure=기슭막이"] == "흙막이"
|
||||
|
||||
@@ -73,6 +73,7 @@ def test_유입_유출은_구조와_흙막이_칸만(out):
|
||||
["bond", None, "메붙임"],
|
||||
["thickness", None, "45"],
|
||||
["area", None, "30"],
|
||||
["length_m", None, None], # 그림 전용 길이(294-4)
|
||||
]
|
||||
keys = out[f"{spec}Keys"]
|
||||
assert keys["prefixes"] == ["soil_add_", "chute_add_"]
|
||||
|
||||
Reference in New Issue
Block a user