Owner directive 2026-07-16: verify the K1 band-hall numbering assumption.
Decisive evidence: 832 electrical circuit labels (P{panel}-{hall}{zone}-{no})
in the trench drawing, zero exceptions: band1=hall5(165) band2=hall4(168)
band3=hall3(168) band4=hall2(168) band5=hall1(163) => band n = hall (6-n).
The previous assumption (band n = hall n) was WRONG - only hall 3 matched by
luck. Mirror features in official JPGs (notch corners, exterior entrances)
independently agree.
- V67: delete all K1 measured rows (old mapping) and reseed with corrected
generators (trench 875, pillars, obstacles, K1 exits). Assembly strips the
V61 y-flip UPDATE (would double-flip) and the global obstacle DELETE
(would wipe K2 rows)
- Swap DWG-tab underlays hall1<->hall5, hall2<->hall4
- All 5 generators now canonically map band = 6 - hall
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
109 lines
4.8 KiB
Python
109 lines
4.8 KiB
Python
# -*- coding: utf-8 -*-
|
|
"""기둥 실측 시드 생성기 — V62 (hall_pillar 테이블 + K1/K2 기둥 + V61 트렌치 y축 보정).
|
|
|
|
근거:
|
|
K1(H1~H5): CAD `전기,설비 트렌치.dwg` 레이어 4-COL-H 사각 폴리라인 중심(0.3~3m 각형).
|
|
공식 도면 주석(hall1.jpg: 기둥 Pillar ø2.5m, x=54m 치수)과 CAD 추출값(53.6m) 일치 검증.
|
|
K2(H7~H10): 공식 홀 도면 치수 주석 — midline(A/B 경계) 내부 기둥 1개.
|
|
H7/H8: 40m|44.5m 분할 → x=40.1m, y=63m(ø2.3m). H9/H10: 48.9m|44.6m → x=48.9m, y=66m.
|
|
H6: 도면에 내부 기둥 주석 없음 — 미시드(한계 기록).
|
|
|
|
좌표 규약: 홀 로컬 m, y=0은 도면 상단(DWG 언더레이 기준) — CAD y와 상하 반전:
|
|
local_y = BAND_H - (cad_y - band_y0). ★V61 트렌치가 이 반전을 누락 → 본 마이그레이션에서 보정.
|
|
|
|
사용:
|
|
python tools/cad/extract_pillar_seed.py <k1_trench.dxf> <out.sql>
|
|
"""
|
|
import io
|
|
import sys
|
|
|
|
import ezdxf
|
|
|
|
MM = 1000.0
|
|
FLOOR_X0, FLOOR_W = 293.5, 171.0
|
|
BAND_Y0, BAND_H = 80.1, 63.0
|
|
K1_HALLS = [1, 2, 3, 4, 5]
|
|
K1_RADIUS = 1.25 # ø2.5m (공식 주석)
|
|
|
|
# K2 내부 기둥 — 공식 도면 치수 주석(홀 로컬 m, y=0 상단)
|
|
K2_PILLARS = {
|
|
"H7": [(40.1, 63.0, 1.15)],
|
|
"H8": [(40.1, 63.0, 1.15)],
|
|
"H9": [(48.9, 66.0, 1.15)],
|
|
"H10": [(48.9, 66.0, 1.15)],
|
|
}
|
|
|
|
|
|
def k1_pillars(doc):
|
|
"""4-COL-H 사각 중심 → 홀 로컬(0.3~3m 각형, 0.8m 스냅 dedupe)."""
|
|
msp = doc.modelspace()
|
|
per_hall = {n: [] for n in K1_HALLS}
|
|
for e in msp:
|
|
if e.dxftype() != "LWPOLYLINE" or "COL" not in e.dxf.layer.upper():
|
|
continue
|
|
pts = [(p[0] / MM, p[1] / MM) for p in e.get_points()]
|
|
if len(pts) < 3:
|
|
continue
|
|
xs = [p[0] for p in pts]
|
|
ys = [p[1] for p in pts]
|
|
w, h = max(xs) - min(xs), max(ys) - min(ys)
|
|
if not (0.3 <= w <= 3.0 and 0.3 <= h <= 3.0):
|
|
continue
|
|
cx, cy = (min(xs) + max(xs)) / 2, (min(ys) + max(ys)) / 2
|
|
lx = cx - FLOOR_X0
|
|
if not (0 <= lx <= FLOOR_W):
|
|
continue
|
|
for n in K1_HALLS:
|
|
y0 = BAND_Y0 + (5 - n) * BAND_H # band = 6-n (홀번호 역순, 2026-07-16 확증)
|
|
if y0 <= cy < y0 + BAND_H:
|
|
ly = BAND_H - (cy - y0) # 상하 반전(도면 상단=0)
|
|
if not any(abs(px - lx) < 0.8 and abs(py - ly) < 0.8 for px, py, _ in per_hall[n]):
|
|
per_hall[n].append((round(lx, 2), round(ly, 2), K1_RADIUS))
|
|
return per_hall
|
|
|
|
|
|
def main():
|
|
src, out_sql = sys.argv[1], sys.argv[2]
|
|
doc = ezdxf.readfile(src)
|
|
per_hall = k1_pillars(doc)
|
|
|
|
sql = io.StringIO()
|
|
sql.write(
|
|
"-- V62: 기둥 실측 시드(hall_pillar) + V61 트렌치 y축 보정 — 자동배치 기둥 회피 근거.\n"
|
|
"-- 생성기: tools/cad/extract_pillar_seed.py (결정적 재생성). 근거: docs/analysis/cad-extraction.md.\n"
|
|
"-- K1=CAD 4-COL-H 추출(주석 교차검증), K2 H7~H10=공식 도면 치수 주석(midline 내부 기둥), H6=근거 없음(미시드).\n\n"
|
|
"CREATE TABLE IF NOT EXISTS hall_pillar (\n"
|
|
" id varchar(60) PRIMARY KEY, -- 예: H1-P-1\n"
|
|
" hall_id varchar(20) NOT NULL REFERENCES hall(id) ON DELETE CASCADE,\n"
|
|
" geom geometry(Point,0) NOT NULL, -- 홀 로컬 m(y=0 도면 상단)\n"
|
|
" radius_m numeric(4,2) NOT NULL,\n"
|
|
" is_assumed boolean NOT NULL DEFAULT false\n"
|
|
");\n"
|
|
"CREATE INDEX IF NOT EXISTS idx_hall_pillar_hall ON hall_pillar (hall_id);\n\n"
|
|
"-- V61 트렌치 y축 보정: RT 포인트가 CAD y(상하 미반전)로 시드됨 → 도면 상단 기준으로 반전(멱등:\n"
|
|
"-- 재실행 시 다시 뒤집히지 않도록 마이그레이션 1회 실행 특성(flyway)에 의존 — 값 자체는 63-y 대칭 변환).\n"
|
|
"UPDATE trench SET geom = ST_SetSRID(ST_MakePoint(ST_X(geom), 63.0 - ST_Y(geom)), 0)\n"
|
|
"WHERE id LIKE '%-RT-%';\n\n"
|
|
)
|
|
rows = []
|
|
for n in K1_HALLS:
|
|
for i, (x, y, r) in enumerate(sorted(per_hall[n]), 1):
|
|
rows.append(f"('H{n}-P-{i}', 'H{n}', ST_SetSRID(ST_MakePoint({x}, {y}), 0), {r}, false)")
|
|
for hall, plist in K2_PILLARS.items():
|
|
for i, (x, y, r) in enumerate(plist, 1):
|
|
rows.append(f"('{hall}-P-{i}', '{hall}', ST_SetSRID(ST_MakePoint({x}, {y}), 0), {r}, false)")
|
|
sql.write(
|
|
"INSERT INTO hall_pillar (id, hall_id, geom, radius_m, is_assumed)\nVALUES\n "
|
|
+ ",\n ".join(rows)
|
|
+ "\nON CONFLICT (id) DO UPDATE SET geom = EXCLUDED.geom, radius_m = EXCLUDED.radius_m;\n"
|
|
)
|
|
with open(out_sql, "w", encoding="utf-8") as f:
|
|
f.write(sql.getvalue())
|
|
for n in K1_HALLS:
|
|
print(f"H{n}: {len(per_hall[n])} pillars {sorted(per_hall[n])[:6]}")
|
|
print(f"OK -> {out_sql} (총 {len(rows)}개)")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|