feat: replace 2 m placeholder with station pattern table from the workbook (Task 5)
Source: RAG 지보패턴현황_20260918.xlsx, sheet 참고_지보패턴현황, 당진방향 table (4+740..5+500, 42 contiguous rows). Lining pattern (M column) per station now drives the lining colour and the viewer readout. Daesan table kept as reference only (WL-4 there, not applied). Drawing patterns E-1, E-2, RP-2, WL-3 are in neither table and stay [미확정]. Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01A5Cun3RHQKna9qxE6ybZ4A
This commit is contained in:
1 parent
94a7f8226f
commit
f65c8ebabe
9 files changed
+311
-1736
No files matched your search
@@ -80,11 +80,13 @@ def ring_world(R, s):
|
||||
P = np.column_stack([x - ORIGIN[0] + xs * nx, y - ORIGIN[1] + xs * ny, zr + zs])
|
||||
return P
|
||||
|
||||
PAL = {"NP-4AD-1-D-2": (231, 111, 81, 255), "NP-4BD-1-D-2": (244, 162, 97, 255),
|
||||
"NP-5AE-1-WL-4": (233, 196, 106, 255), "NP-5BE-1-WL-4": (138, 177, 125, 255),
|
||||
"NP-6A": (42, 157, 143, 255), "NP-6B": (38, 70, 83, 255)}
|
||||
ZONES = [(int(r["seg_from"]), int(r["seg_to"]), r["pattern"], r["status"])
|
||||
for r in csv.DictReader(open(f"{ROOT}/data/pattern_zones_placeholder.csv", encoding="utf-8"))]
|
||||
PAL = {"A": (42, 157, 143, 255), "B-1": (231, 111, 81, 255), "B-2": (244, 162, 97, 255),
|
||||
"C-1": (233, 196, 106, 255), "C-2": (138, 177, 125, 255), "D-1": (38, 70, 83, 255),
|
||||
"D-2": (100, 130, 160, 255), "P-2": (190, 110, 140, 255), "P-3": (150, 90, 60, 255),
|
||||
"RP-1": (80, 170, 200, 255), "WL-1": (200, 200, 120, 255), "WL-2": (120, 90, 170, 255),
|
||||
"개착부": (170, 170, 170, 255)}
|
||||
ZONES = [(int(float(r["sta_from"])), int(float(r["sta_to"])), r["lining_pattern"], "엑셀 지보패턴표(당진방향)")
|
||||
for r in csv.DictReader(open(f"{ROOT}/data/pattern_stations_dangjin.csv", encoding="utf-8"))]
|
||||
|
||||
def pattern_of(sta):
|
||||
for a, b, pat, _ in ZONES:
|
||||
@@ -168,7 +170,7 @@ checks["road_z_5480_m"] = round(float(np.interp(S1, dg_s, dg_v)), 3)
|
||||
L_chord = float(np.sum([math.dist(cn[i, 1:], cn[i + 1, 1:]) for i in range(len(cn) - 1)]))
|
||||
checks["plan_chord_length_total_m (4+700..5+500)"] = round(L_chord, 3)
|
||||
checks["station_range_modelled"] = f"{S0} .. {S1} (ring step {DS} m, {len(stations)} rings)"
|
||||
checks["pattern_zones (2 m, placeholder)"] = len(ZONES)
|
||||
checks["pattern_zones (지보패턴표 당진방향)"] = len(ZONES)
|
||||
checks["pattern_coverage_all_stations"] = bool(all(pattern_of(x) in PAL for x in stations))
|
||||
checks["pattern_counts"] = {k: sum(1 for z in ZONES if z[2] == k) for k in PAL}
|
||||
checks["glb_bytes"] = int(__import__("os").path.getsize(glb))
|
||||
@@ -188,9 +190,9 @@ meta = {
|
||||
"superelevation sign convention assumed (z += S/100 * x, x = left of tangent)"],
|
||||
"layers": [p.metadata["name"] for p in parts],
|
||||
"ring_step_m": DS, "ring_points": int(parts[0].metadata["ring_points"]), "first_station": S0,
|
||||
"pattern_status": "PLACEHOLDER: 2 m 임의 배정. 실제 측점 구간 아님 (사용자 결정 2026-10-21). data/pattern_zones_placeholder.csv 를 수정 후 재빌드",
|
||||
"pattern_status": "지보패턴: 엑셀 참고_지보패턴현황 당진방향 표(4+740~5+500, 42행, 빈틈 없음) 적용. 출처 data/pattern_stations_dangjin.csv (사용자 결정 2026-10-21)",
|
||||
"patterns": [{"from": a, "to": b, "pattern": pat} for a, b, pat, _ in ZONES],
|
||||
"open": ["4+700~4+745 and 5+480~5+500 excluded ([미확정])", "pattern zones (03-003~008) pending Task 5",
|
||||
"open": ["4+700~4+745 and 5+480~5+500 excluded ([미확정])", "지보패턴 측점표 적용(당진). 도면 E-1~2, RP-2, WL-3~4 는 당진 표에 없어 [미확정]. 대산 표 WL-4(4+758.85~4+768.85)는 참고만 [확인 필요]",
|
||||
"lining reference recorded (meta.lining_reference, 04-004~009); sheet-to-station mapping [미확정]",
|
||||
"[확정 2026-10-21] R1 6,982 mm 유지 (사용자 결정). 라이닝 도면 6장의 R1 6.892 m 표기는 확인 대상 오기로 기록", "pattern-group to excavation-pattern mapping: user explanation conflicts with filename (WL-4) - re-confirm [확인 필요]"]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Extract the 당진방향 station pattern table from 참고_지보패턴현황 (read-only).
|
||||
Rows 55..96 of the sheet: C=start STA, G=end STA, J=length, M=lining pattern
|
||||
(지보패턴), O=실시설계 excavation class (blank = continues the row above),
|
||||
Q=굴착공법, T=비고. Also extracts the 대산방향 table (rows 13..49) for reference.
|
||||
Usage: extract_pattern_table.py <xlsx> <out_dir>"""
|
||||
import csv, os, sys
|
||||
import openpyxl
|
||||
|
||||
SRC, OUT = sys.argv[1], sys.argv[2]
|
||||
wb = openpyxl.load_workbook(SRC, read_only=True, data_only=True)
|
||||
ws = wb["참고_지보패턴현황"]
|
||||
rows = {r: row for r, row in enumerate(ws.iter_rows(min_row=1, max_row=114, max_col=33, values_only=True), start=1)}
|
||||
|
||||
|
||||
def table(r0, r1, tag):
|
||||
out, last_o = [], None
|
||||
for r in range(r0, r1 + 1):
|
||||
row = rows[r]
|
||||
try:
|
||||
a, b = float(row[2]), float(row[6])
|
||||
except (TypeError, ValueError):
|
||||
continue
|
||||
m = (row[12] or "").strip() if isinstance(row[12], str) else row[12]
|
||||
o_raw = row[14]
|
||||
o = o_raw if o_raw not in (None, "") else last_o
|
||||
last_o = o
|
||||
remark = (row[19] or "") if isinstance(row[19], str) else ""
|
||||
out.append({"direction": tag, "source_row": r, "sta_from": a, "sta_to": b,
|
||||
"length_m": row[9], "lining_pattern": m or ("개착부" if "개착" in remark else ""),
|
||||
"excavation": o or "", "excavation_inherited": o_raw in (None, ""),
|
||||
"method": (row[16] or "") if isinstance(row[16], str) else "",
|
||||
"remark": remark})
|
||||
return out
|
||||
|
||||
|
||||
south = table(55, 96, "당진")
|
||||
north = table(13, 49, "대산")
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
cols = list(south[0].keys())
|
||||
for name, data in [("pattern_stations_dangjin.csv", south), ("pattern_stations_daesan_ref.csv", north)]:
|
||||
with open(os.path.join(OUT, name), "w", encoding="utf-8", newline="") as fh:
|
||||
w = csv.DictWriter(fh, fieldnames=cols)
|
||||
w.writeheader()
|
||||
w.writerows(data)
|
||||
print("dangjin rows", len(south), "range", south[0]["sta_from"], "->", south[-1]["sta_to"])
|
||||
print("daesan rows", len(north), "range", north[0]["sta_from"], "->", north[-1]["sta_to"])
|
||||
print("blank lining pattern rows (dangjin):", [(d["source_row"], d["remark"]) for d in south if not d["lining_pattern"]])
|
||||
@@ -0,0 +1,56 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Render the station-by-station lining pattern report (DOC/03_설계) from the
|
||||
CSVs written by extract_pattern_table.py. Values are read, not typed.
|
||||
Usage: make_pattern_doc.py <dangjin.csv> <daesan_ref.csv> <lining_spec.json> <out.md>"""
|
||||
import csv
|
||||
import json
|
||||
import sys
|
||||
|
||||
DJ, DS, LS, OUT = sys.argv[1:5]
|
||||
dj = list(csv.DictReader(open(DJ, encoding="utf-8")))
|
||||
ds = list(csv.DictReader(open(DS, encoding="utf-8")))
|
||||
lin = json.load(open(LS, encoding="utf-8"))["sheets"]
|
||||
drawing_groups = sorted({g["group"] for s in lin for g in s["pattern_details"] if g["group"]})
|
||||
dj_names = {r["lining_pattern"] for r in dj}
|
||||
ds_names = {r["lining_pattern"] for r in ds}
|
||||
# Drawing group labels (read from the sheet notes, 04-004..009) -> member patterns.
|
||||
# Explicit table: the labels mix letter ranges (A~C-2) and number ranges (WL-1~2).
|
||||
DRAWING_MEMBERS = {"A~C-2": ["A", "B-1", "B-2", "C-1", "C-2"], "D-1~2": ["D-1", "D-2"],
|
||||
"E-1~2": ["E-1", "E-2"], "WL-1~2": ["WL-1", "WL-2"], "WL-1~2,RP-1~2": ["WL-1", "WL-2", "RP-1", "RP-2"],
|
||||
"WL-3~4": ["WL-3", "WL-4"], "P-2~3": ["P-2", "P-3"], "RP-1~2": ["RP-1", "RP-2"]}
|
||||
members = set()
|
||||
for g in drawing_groups:
|
||||
members |= set(DRAWING_MEMBERS.get(g, [g]))
|
||||
missing_dj = sorted(m for m in members if m not in dj_names)
|
||||
only_ds = sorted(m for m in missing_dj if m in ds_names)
|
||||
none_any = sorted(m for m in missing_dj if m not in ds_names)
|
||||
L = ["# 측점별 콘크리트 라이닝 지보패턴표 (당진방향) (초안)\n",
|
||||
"| 버전 | 일자 | 변경 내용 |", "|---|---|---|",
|
||||
"| v0.1.00 | 2026-10-21 | 최초 작성. 엑셀 `참고_지보패턴현황` 당진방향 표를 측점별로 정리 (사용자 결정: 모델 placeholder 대체) |\n",
|
||||
"## 1. 출처와 범위",
|
||||
"- 원본: `RAG/03_터널명(대산2터널)/지보패턴현황_20260918.xlsx`, 시트 `참고_지보패턴현황`, 당진방향 표 (원본 행 55~96)",
|
||||
f"- 행 {len(dj)}개, 측점 {dj[0]['sta_from']} ~ {dj[-1]['sta_to']}, 빈틈 없음 (각 행 끝 = 다음 행 시작)",
|
||||
"- 모델 적용 범위 4+745 ~ 5+480 은 이 표로 전 구간 덮임 (735 m)",
|
||||
"- 지보패턴(M열) = 라이닝 패턴, 실시설계(O열) = 굴착 등급. 실시설계 칸이 빈 행은 위 행의 값을 이어 받음 (병합 셀 해석, [추론])\n",
|
||||
"## 2. 측점별 표",
|
||||
"| 측점 from | 측점 to | 연장(m) | 지보패턴 | 실시설계 | 굴착공법 | 비고 |",
|
||||
"|---|---|---|---|---|---|---|"]
|
||||
def sta(x):
|
||||
v = int(float(x)); return f"{v // 1000}+{v % 1000:03d}"
|
||||
for r in dj:
|
||||
exc = r["excavation"] + (" (이어받음)" if r["excavation_inherited"] == "True" and r["excavation"] else "")
|
||||
L.append(f"| {sta(r['sta_from'])} | {sta(r['sta_to'])} | {float(r['length_m']):g} | {r['lining_pattern']} | {exc} | {r['method'].replace(chr(10), ' ')} | {r['remark']} |")
|
||||
L += ["", "## 3. 도면과 표의 대응",
|
||||
f"- 라이닝 도면(04-004~009)의 패턴 {len(members)}개 중 당진 표에 있는 것: {len(members) - len(missing_dj)}개",
|
||||
f"- 당진 표에 없고 대산 표에만 있는 것: {', '.join(only_ds) if only_ds else '없음'} (대산 표 값 참고만, 적용 안 함 — 아래 4항)",
|
||||
f"- 두 표 모두 없는 것: {', '.join(none_any) if none_any else '없음'} → 측점 지정 불가, [미확정]\n",
|
||||
"## 4. 확인 필요 (HITL)",
|
||||
"- [확인 필요] 대산방향 표의 WL-4 (4+758.85~4+768.85, NP-5) 를 당진 측점에 적용할지. 두 방향이 별도 튜브라는 점은 [추론]이며 확인되지 않았다. 당진 표는 같은 측점에 WL-2/WL-1 을 보여 준다.",
|
||||
"- [확인 필요] 말씀하신 `NP-5BE-1-WL-4` 의 풀이 (NP-5B 의 E-1 ~ WL-4). 당진 NP-5 구간은 WL-2·WL-1 뿐이고, E-1 은 두 표 어디에도 없다.",
|
||||
"- [확인 필요] 엑셀 `개요2`·`1` 시트: 굴착 등급은 NP-4/5/6 (A·B 접미사 포함), 괄호 안은 지보 하위 패턴이라는 표기. 이 해석은 엑셀 표기와 일치하는 것으로 보이나 도면 명칭 대응은 확정하지 않았다.\n",
|
||||
"## 5. 적용 결과 (골격 모델)",
|
||||
"- placeholder 2 m 구간은 폐기하고 이 표로 대체 (사용자 결정 2026-10-21)",
|
||||
"- 뷰어의 라이닝 클릭 값: 측점, 지보패턴(본 표), 라이닝 사양 (C0060304-004~009)",
|
||||
""]
|
||||
open(OUT, "w", encoding="utf-8").write("\n".join(L))
|
||||
print("written", OUT, "rows", len(dj), "drawing groups", len(members), "missing in dangjin", missing_dj)
|
||||
Reference in new issue
Block a user