Merge remote-tracking branch 'origin/sub_laptop_5' into main_laptop_1
This commit is contained in:
@@ -0,0 +1,54 @@
|
||||
/* 노면공 확폭 구간 규칙(PLAN 87-3) — `design_structure_widening.ts` 를 그 자리에서 트랜스파일해 Node 로 돌림. */
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
const ts = require(path.join(__dirname, "..", "..", "config", "node_modules", "typescript"));
|
||||
|
||||
const file = path.join(
|
||||
__dirname,
|
||||
"..",
|
||||
"..",
|
||||
"A00_Common",
|
||||
"design",
|
||||
"design_structure_widening.ts",
|
||||
);
|
||||
const js = ts.transpileModule(fs.readFileSync(file, "utf8"), {
|
||||
compilerOptions: { module: ts.ModuleKind.CommonJS, target: ts.ScriptTarget.ES2020 },
|
||||
}).outputText;
|
||||
const box = { exports: {} };
|
||||
new Function("exports", "module", js)(box.exports, box);
|
||||
const w = box.exports;
|
||||
|
||||
// 곡선 둘(앞 No.1+0~No.3+0 · 뒤 No.5+0~No.6+0) 사이에 직선 측점 하나 — 확폭 좌우 합
|
||||
const at = (chainage_m, left = 0, right = 0) => ({
|
||||
chainage_m,
|
||||
design: { widening_left_m: left, widening_right_m: right },
|
||||
});
|
||||
const stations = [
|
||||
at(0),
|
||||
at(20, 0.3, 0),
|
||||
at(40, 0.75, 0),
|
||||
at(60, 0.4, 0),
|
||||
at(80),
|
||||
at(100, 0, 0.5),
|
||||
at(120, 0, 0.6),
|
||||
at(140),
|
||||
];
|
||||
const runs = w.wideningRuns(stations, 0, 140);
|
||||
const inner = w.wideningRuns(stations, 30, 110); // 범위가 곡선을 가로지름
|
||||
const off = w.formatOff([[20, 60]]);
|
||||
const out = {
|
||||
runs,
|
||||
inner,
|
||||
none: w.wideningRuns(stations, 0, 10),
|
||||
fallback: w.wideningOf({ chainage_m: 1, curve_widening_m: 0.9, curve_outer_side: "left" }),
|
||||
fallbackStraight: w.wideningOf({ chainage_m: 1, curve_widening_m: 0.9, curve_outer_side: null }),
|
||||
off,
|
||||
parsed: w.parseOff("20-60, 100-120,bad,5"),
|
||||
isOff: runs.map((r) => w.isRunOff(r, off)),
|
||||
toggledOff: w.toggleRun(runs, "", runs[1]),
|
||||
toggledBoth: w.toggleRun(runs, off, runs[1]),
|
||||
toggledOn: w.toggleRun(runs, off, runs[0]),
|
||||
stale: w.offForRuns(runs, "20-60,0-5,100-130"),
|
||||
empty: w.offForRuns([], "20-60"),
|
||||
};
|
||||
process.stdout.write(JSON.stringify(out));
|
||||
@@ -0,0 +1,60 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""노면공 확폭 구간(PLAN 87-3) — 구간 묶기 · `widening_off` 글 읽고 쓰기 · 안 맞는 값 무시.
|
||||
|
||||
규칙은 Node 헬퍼(`helper_87_widening.cjs`)가 `design_structure_widening.ts` 를 그대로 돌림.
|
||||
"""
|
||||
|
||||
import json
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
import pytest
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def out():
|
||||
proc = subprocess.run(
|
||||
["node", os.path.join(HERE, "helper_87_widening.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["runs"] == [
|
||||
{"start_m": 20, "end_m": 60, "widening_m": 0.75},
|
||||
{"start_m": 100, "end_m": 120, "widening_m": 0.6},
|
||||
]
|
||||
|
||||
|
||||
def test_범위_안_측점만_묶음(out):
|
||||
assert out["inner"] == [
|
||||
{"start_m": 40, "end_m": 60, "widening_m": 0.75},
|
||||
{"start_m": 100, "end_m": 100, "widening_m": 0.5},
|
||||
]
|
||||
assert out["none"] == []
|
||||
|
||||
|
||||
def test_설계_없으면_곡선_확폭_바깥쪽만(out):
|
||||
assert out["fallback"] == 0.9
|
||||
assert out["fallbackStraight"] == 0
|
||||
|
||||
|
||||
def test_끈_구간_글_왕복(out):
|
||||
assert out["off"] == "20-60"
|
||||
assert out["parsed"] == [[20, 60], [100, 120]] # 틀린 조각은 버림
|
||||
assert out["isOff"] == [True, False]
|
||||
assert out["toggledOff"] == "100-120"
|
||||
assert out["toggledBoth"] == "20-60,100-120"
|
||||
assert out["toggledOn"] == ""
|
||||
|
||||
|
||||
def test_안_맞는_끈_값은_무시_저장_때_빠짐(out):
|
||||
assert out["stale"] == "20-60"
|
||||
assert out["empty"] == ""
|
||||
@@ -8,8 +8,9 @@
|
||||
* orca eval --expression "window.__m5210='restore'; $(cat 이 파일)" → 추가한 둘 삭제 · [저장]
|
||||
* 쓰는 것: 검증 프로젝트 structures.json(되돌림 단계가 지움)
|
||||
* 기대 수치:
|
||||
* 포장 — containers ["detail"] · 상세 내용 · 포장사양 선택지 ["콘크리트"] · 높이 0.35 · 잇기 지정 ·
|
||||
* 종류 단위 잇기 줄 가림 · 옛 상세 칸(두께 · 줄눈 …) 안 보임 · 길이 · 전 · 후 칸 보임
|
||||
* 포장 — containers ["detail"] · 상세 내용 · 포장사양 선택지 [콘크리트 · 아스콘 · 쇄석] · 칸 차례 포장사양 → 길이(출력 20) →
|
||||
* 높이 0.35 · 잇기 지정 · 종류 단위 잇기 줄 가림 · 옛 상세 칸(두께 · 줄눈 …) 안 보임 ·
|
||||
* 기준 측점 칸 없음 · 시작 · 종료 칸 보임 · 길이 · 전 · 후 입력 칸 없음
|
||||
* 기타 — 「상세 종류 이름」 글 칸 = 「52-10 시험 기타」 · 목록 이름도 그 글 ·
|
||||
* 선택 컨테이너 「상세 내용」(52-14) 하나만(52-17) — 추가 → [추가] 없음 · 빼기 → 다시 보임 ·
|
||||
* 다시 추가 · 비고 「52-14 비고」(길이 상한 100) · 잇기 · 하나 남음 · 종류 단위 잇기 줄 가림
|
||||
@@ -37,7 +38,7 @@
|
||||
};
|
||||
const listItems = () => [...document.querySelectorAll(".b05-route__irregular-list li")];
|
||||
const ITEMS = [
|
||||
{ typeId: "pavement_concrete", group: "G", at: [4, 6], list: /콘크리트 포장/ },
|
||||
{ typeId: "pavement_concrete", group: "G", at: [4, 6], to: [5, 6], list: /콘크리트 포장/ },
|
||||
{ typeId: "etc", group: "호환", at: [5, 2], list: new RegExp(NAME) },
|
||||
];
|
||||
const typeSummary = () =>
|
||||
@@ -76,6 +77,16 @@
|
||||
: null,
|
||||
paveSpec: specCtl("spec")?.value ?? null,
|
||||
height: specCtl("height")?.value ?? null,
|
||||
itemOrder: boxes[0]
|
||||
? [...boxes[0].querySelectorAll("[data-spec-item]")].map((n) => n.dataset.specItem)
|
||||
: [],
|
||||
lengthOut:
|
||||
spec()?.querySelector('[data-spec-item="detail.length"] output')?.textContent ?? null,
|
||||
anchorHidden: !!sec().querySelectorAll(".b05-structure__position-row > label")[2]?.hidden,
|
||||
startEndShown: [1, 3].every(
|
||||
(n) => !sec().querySelectorAll(".b05-structure__position-row > label")[n]?.hidden,
|
||||
),
|
||||
wideningShown: vis(sec().querySelector(".b05-structure__widening")),
|
||||
containerLink: !!boxes[0]?.querySelector(".b05-structure__summary-name.is-assigned"),
|
||||
containerLinks: boxes.map(
|
||||
(b) => !!b.querySelector(".b05-structure__summary-name.is-assigned"),
|
||||
@@ -139,11 +150,20 @@
|
||||
for (const item of ITEMS) {
|
||||
await pickType(item.group, item.typeId);
|
||||
const row = { lockedBeforePosition: shape(item.typeId).locked };
|
||||
const [no, dist] = sec()
|
||||
.querySelectorAll(".b05-structure__position-row > label")[2]
|
||||
.querySelectorAll("input");
|
||||
fire(no, String(item.at[0]));
|
||||
fire(dist, String(item.at[1]));
|
||||
const labels = sec().querySelectorAll(".b05-structure__position-row > label");
|
||||
if (item.to) {
|
||||
// 노면공 = 시작 · 종료 측점만(87-1) — 기준 측점 칸 없음
|
||||
const [s0, s1] = labels[1].querySelectorAll("input");
|
||||
const [e0, e1] = labels[3].querySelectorAll("input");
|
||||
fire(s0, String(item.at[0]));
|
||||
fire(s1, String(item.at[1]));
|
||||
fire(e0, String(item.to[0]));
|
||||
fire(e1, String(item.to[1]));
|
||||
} else {
|
||||
const [no, dist] = labels[2].querySelectorAll("input");
|
||||
fire(no, String(item.at[0]));
|
||||
fire(dist, String(item.at[1]));
|
||||
}
|
||||
await w(300);
|
||||
if (item.typeId === "pavement_concrete") {
|
||||
fire(specCtl("spec"), "콘크리트");
|
||||
@@ -226,13 +246,17 @@
|
||||
!pave.missing &&
|
||||
JSON.stringify(pave.containers) === '["detail"]' &&
|
||||
pave.legend[0] === "상세 내용" &&
|
||||
JSON.stringify(pave.paveChoices) === '["콘크리트"]' &&
|
||||
JSON.stringify(pave.paveChoices) === '["콘크리트","아스콘","쇄석"]' &&
|
||||
JSON.stringify(pave.itemOrder) === '["detail.spec","detail.length","detail.height"]' &&
|
||||
Number(pave.lengthOut) === 20 &&
|
||||
pave.anchorHidden &&
|
||||
pave.startEndShown &&
|
||||
pave.paveSpec === "콘크리트" &&
|
||||
Number(pave.height) === 0.35 &&
|
||||
pave.containerLink &&
|
||||
!pave.typeSummaryVisible &&
|
||||
!pave.options.some((l) => /두께|줄눈|철망|비닐|포장 폭|확폭/.test(l)) &&
|
||||
["길이", "기준측점 전", "기준측점 후"].every((l) => pave.options.some((o) => o.startsWith(l)));
|
||||
!pave.options.some((l) => /^(길이|기준측점 전|기준측점 후)/.test(l)); // 87-1 입력 칸 없음
|
||||
out.etcOk =
|
||||
!!etc &&
|
||||
!etc.missing &&
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
(async () => {
|
||||
const MODE = window.__m5215 || "check";
|
||||
const PIPE = /^22\+0 배관/;
|
||||
const PAVE = /^21\+15~22\+5 콘크리트 포장/; // 기준 22+0 · 길이 10 m
|
||||
const PAVE = /^21\+15~22\+5 콘크리트 포장/; // 시작 21+15 · 종료 22+5 (10 m)
|
||||
const OTHER = /^4\+5 배관/;
|
||||
const w = (ms) => new Promise((r) => setTimeout(r, ms));
|
||||
const until = async (fn, ms = 15000) => {
|
||||
@@ -85,13 +85,16 @@
|
||||
await w(300);
|
||||
fire(t, "pavement_concrete");
|
||||
await w(1500);
|
||||
const anchor = () =>
|
||||
sec().querySelectorAll(".b05-structure__position-row > label")[2].querySelectorAll("input");
|
||||
fire(anchor()[0], "22");
|
||||
// 노면공 = 시작 · 종료 측점만(87-1) — 시작 21+15 · 종료 22+5(10 m)
|
||||
const pos = (n) =>
|
||||
sec().querySelectorAll(".b05-structure__position-row > label")[n].querySelectorAll("input");
|
||||
fire(pos(1)[0], "21");
|
||||
fire(pos(1)[1], "15");
|
||||
fire(pos(3)[0], "22");
|
||||
await w(300);
|
||||
fire(anchor()[1], "0");
|
||||
fire(pos(3)[1], "5");
|
||||
await w(500);
|
||||
out.anchor = [...anchor()].map((i) => i.value);
|
||||
out.anchor = [...pos(1), ...pos(3)].map((i) => i.value);
|
||||
fire(specCtl("spec"), "콘크리트");
|
||||
await w(200);
|
||||
fire(specCtl("height"), "0.35");
|
||||
|
||||
Reference in New Issue
Block a user