feat: 2 m placeholder pattern zones on lining, station/pattern readout in viewer (Task 5)
No pattern-to-station data exists in the drawings. Per user decision (2026-10-21) the modelled range 4+745..5+480 is split into 2 m segments with arbitrary pattern names, marked placeholder in CSV, meta and viewer, to be replaced later. Ring step reduced to 1 m so that the 2 m segments align. 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
c9de6f0ef3
commit
6c7e555c25
7 files changed
+2303
-10
No files matched your search
@@ -30,7 +30,7 @@ R1, R_OUT, R_EX = 6.982, 7.282, 7.402 # m (mm / 1000)
|
||||
CROWN_A = 6.615 # m above road
|
||||
CENTRE_C = CROWN_A - R1 # arch centre height above road (m)
|
||||
S0, S1 = 4745, 5480 # modelled range (fully determined)
|
||||
DS = 5.0 # station step for rings (m)
|
||||
DS = 1.0 # station step for rings (m); pattern segments are 2 m
|
||||
ANG = np.radians(np.linspace(40.0, 140.0, 41)) # arch arc, right springline -> left
|
||||
|
||||
def read_centre():
|
||||
@@ -80,18 +80,33 @@ def ring_world(R, s):
|
||||
P = np.column_stack([x - ORIGIN[0] + xs * nx, y - ORIGIN[1] + xs * ny, zr + zs])
|
||||
return P
|
||||
|
||||
def make_band(R, color, name):
|
||||
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"))]
|
||||
|
||||
def pattern_of(sta):
|
||||
for a, b, pat, _ in ZONES:
|
||||
if a <= sta < b:
|
||||
return pat
|
||||
return ZONES[-1][2]
|
||||
|
||||
def make_band_pattern(R, name):
|
||||
rings = [ring_world(R, s) for s in stations]
|
||||
n = len(rings[0]); m = len(rings)
|
||||
V = np.vstack(rings)
|
||||
F = []
|
||||
F, C = [], []
|
||||
for i in range(m - 1):
|
||||
col = PAL[pattern_of(stations[i])]
|
||||
for j in range(n - 1):
|
||||
a = i * n + j; b = a + 1; c = a + n; d = c + 1
|
||||
F += [[a, b, c], [b, d, c]]
|
||||
C += [col, col]
|
||||
mesh = trimesh.Trimesh(vertices=V, faces=np.array(F), process=False)
|
||||
mesh.visual.face_colors = np.tile(np.array(color, dtype=np.uint8), (len(F), 1))
|
||||
mesh.visual.face_colors = np.array(C, dtype=np.uint8)
|
||||
mesh.metadata["name"] = name
|
||||
mesh.metadata["ring_points"] = n
|
||||
return mesh
|
||||
|
||||
def make_ribbon(z_fn, half_w, color, name):
|
||||
@@ -111,9 +126,24 @@ def make_ribbon(z_fn, half_w, color, name):
|
||||
mesh.metadata["name"] = name
|
||||
return mesh
|
||||
|
||||
def make_band(R, color, name):
|
||||
"""uniform-colour band (excavation outline)."""
|
||||
rings = [ring_world(R, s) for s in stations]
|
||||
n = len(rings[0]); m = len(rings)
|
||||
V = np.vstack(rings)
|
||||
F = []
|
||||
for i in range(m - 1):
|
||||
for j in range(n - 1):
|
||||
a = i * n + j; b = a + 1; c = a + n; d = c + 1
|
||||
F += [[a, b, c], [b, d, c]]
|
||||
mesh = trimesh.Trimesh(vertices=V, faces=np.array(F), process=False)
|
||||
mesh.visual.face_colors = np.tile(np.array(color, dtype=np.uint8), (len(F), 1))
|
||||
mesh.metadata["name"] = name
|
||||
return mesh
|
||||
|
||||
parts = [
|
||||
make_band(R_OUT, (190, 190, 186, 255), "lining_outer_R7282"),
|
||||
make_band(R1, (235, 235, 230, 255), "lining_inner_R6982"),
|
||||
make_band_pattern(R_OUT, "lining_outer_R7282"),
|
||||
make_band_pattern(R1, "lining_inner_R6982"),
|
||||
make_band(R_EX, (150, 120, 90, 110), "excavation_R7402"),
|
||||
make_ribbon(lambda s: float(np.interp(s, dg_s, dg_v)), 5.0, (70, 70, 75, 255), "road_surface_계획고"),
|
||||
make_ribbon(lambda s: float(np.interp(s, gl_s, gl_v)), 20.0, (110, 150, 90, 200), "ground_GL_지반고"),
|
||||
@@ -138,6 +168,9 @@ 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_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))
|
||||
reload = trimesh.load(glb)
|
||||
checks["glb_reload_geometries"] = len(reload.geometry)
|
||||
@@ -154,6 +187,9 @@ meta = {
|
||||
"centreline and grade linearly interpolated between nodes",
|
||||
"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 를 수정 후 재빌드",
|
||||
"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",
|
||||
"lining details (04-004~009) pending Task 6"]
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user