feat: draft main-line centreline stations from plan sheets (Task 3, HITL)
extract_alignment_plan.py takes the midpoint of each station's two side ticks (CA-ALGN-STSM) as the centreline point. Sheet 001 gives 4+700..5+500 with consecutive residual <= 0.02 m. Sheet 002 gives identical output, so the duplicate question is left to HITL. Profile EL is not yet extracted. 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
14a4c4a37a
commit
f144d53f79
5 files changed
+193
No files matched your search
@@ -0,0 +1,81 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Task 3 (HITL draft): main-line centreline station table from a plan sheet.
|
||||
|
||||
Method (layers CA-ALGN-TEXT labels and CA-ALGN-STSM station ticks):
|
||||
1. Station labels: 'N+mmm' is explicit; bare numbers take the km of the next
|
||||
explicit label when they precede it (700 before 5+000 -> 4+700), otherwise
|
||||
the km of the previous explicit label.
|
||||
2. Each station has two labels (one per side of the road). Each label is
|
||||
paired with its nearest tick; the centreline point is the midpoint of the
|
||||
two tick points.
|
||||
3. Checks reported (not forced): side offset per station, and consecutive
|
||||
centreline distance vs station difference (residual).
|
||||
DRAFT for HITL review. No value is adjusted to fit."""
|
||||
import csv
|
||||
import math
|
||||
import re
|
||||
import sys
|
||||
from collections import defaultdict
|
||||
|
||||
import ezdxf
|
||||
|
||||
SRC, OUT = sys.argv[1], sys.argv[2]
|
||||
msp = ezdxf.readfile(SRC).modelspace()
|
||||
explicit_re = re.compile(r"^(\d+)\+(\d{3})$")
|
||||
|
||||
labels = [(e.dxf.insert.x, e.dxf.insert.y, e.dxf.text.strip())
|
||||
for e in msp.query("TEXT") if e.dxf.layer == "CA-ALGN-TEXT"]
|
||||
ticks = []
|
||||
for e in msp.query("LINE"):
|
||||
if e.dxf.layer == "CA-ALGN-STSM":
|
||||
a, b = e.dxf.start, e.dxf.end
|
||||
ticks.append(((a.x + b.x) / 2, (a.y + b.y) / 2))
|
||||
|
||||
labels = [l for l in labels if explicit_re.match(l[2]) or l[2].isdigit()]
|
||||
labels.sort(key=lambda t: -t[1]) # along the sheet, NNE -> SSW
|
||||
explicit_idx = [i for i, l in enumerate(labels) if explicit_re.match(l[2])]
|
||||
station_of = {}
|
||||
for i, (x, y, s) in enumerate(labels):
|
||||
if explicit_re.match(s):
|
||||
m = explicit_re.match(s)
|
||||
station_of[i] = int(m.group(1)) * 1000 + int(m.group(2))
|
||||
continue
|
||||
v = int(s)
|
||||
nxt = next((j for j in explicit_idx if j > i), None)
|
||||
prv = next((j for j in reversed(explicit_idx) if j < i), None)
|
||||
if prv is not None:
|
||||
km = int(explicit_re.match(labels[prv][2]).group(1))
|
||||
else:
|
||||
km = int(explicit_re.match(labels[nxt][2]).group(1)) - 1
|
||||
station_of[i] = km * 1000 + v
|
||||
|
||||
groups = defaultdict(list)
|
||||
for i, (x, y, s) in enumerate(labels):
|
||||
groups[station_of[i]].append((x, y))
|
||||
|
||||
|
||||
def nearest_tick(pt):
|
||||
return min(ticks, key=lambda t: math.hypot(t[0] - pt[0], t[1] - pt[1]))
|
||||
|
||||
centre = []
|
||||
for sta in sorted(groups):
|
||||
pts = groups[sta]
|
||||
if len(pts) != 2:
|
||||
continue
|
||||
t1, t2 = nearest_tick(pts[0]), nearest_tick(pts[1])
|
||||
side_gap = math.dist(t1, t2)
|
||||
mid = ((t1[0] + t2[0]) / 2, (t1[1] + t2[1]) / 2)
|
||||
centre.append((sta, mid[0], mid[1], side_gap))
|
||||
|
||||
with open(OUT, "w", newline="", encoding="utf-8") as fh:
|
||||
w = csv.writer(fh)
|
||||
w.writerow(["station_m", "centre_x", "centre_y", "side_gap_m"])
|
||||
for sta, x, y, g in centre:
|
||||
w.writerow([sta, round(x, 3), round(y, 3), round(g, 3)])
|
||||
|
||||
print(f"stations={len(centre)} (labels={len(labels)}, ticks={len(ticks)})")
|
||||
prev = None
|
||||
for sta, x, y, g in centre:
|
||||
step = "" if prev is None else f" d={math.dist(prev[1:3], (x, y)):8.3f} dSTA={sta - prev[0]:5d} res={math.dist(prev[1:3], (x, y)) - (sta - prev[0]):+.3f}"
|
||||
print(f" STA {sta:>5} ({x:12.3f}, {y:12.3f}) side_gap={g:6.2f}{step}")
|
||||
prev = (sta, x, y)
|
||||
Reference in new issue
Block a user