#!/usr/bin/env python3 """Write a dependency-free SVG preview from src/model/block8.json.""" import json import math from pathlib import Path ROOT = Path(__file__).resolve().parents[1] MODEL = ROOT / "src/model/block8.json" OUTPUT = ROOT / "docs/BLOCK8_3D모델_미리보기.svg" COLORS = {"major": "#78917c", "minor": "#d0aa69", "insert": "#9a9074"} def point_at(unit, profile_a, profile_b, index, t): theta = math.radians(unit["startAngle"] + (unit["endAngle"] - unit["startAngle"]) * t) cx = unit["center"][0] + unit["radius"] * math.cos(theta) cz = unit["center"][1] + unit["radius"] * math.sin(theta) normal_x, normal_z = -math.cos(theta), -math.sin(theta) station_t = (0.010 + t * 19.980) / 20 u = profile_a[index][0] + (profile_b[index][0] - profile_a[index][0]) * station_t el = profile_a[index][1] + (profile_b[index][1] - profile_a[index][1]) * station_t return [cx + u * normal_x, el, cz + u * normal_z] def project(point): x, y, z = point yaw, pitch, scale = -0.66, 0.43, 14.0 x1 = x * math.cos(yaw) - z * math.sin(yaw) z1 = x * math.sin(yaw) + z * math.cos(yaw) y1 = y - 104 return [600 + x1 * scale, 330 - (y1 * math.cos(pitch) - z1 * math.sin(pitch)) * scale, y1 * math.sin(pitch) + z1 * math.cos(pitch)] def main(): model = json.loads(MODEL.read_text(encoding="utf-8")) faces = [] for unit in model["units"]: for part in unit["parts"]: if len(part["a"]) != len(part["b"]): continue for step in range(8): t0, t1 = step / 8, (step + 1) / 8 for edge in range(len(part["a"]) - 1): corners = [ point_at(unit, part["a"], part["b"], edge, t0), point_at(unit, part["a"], part["b"], edge + 1, t0), point_at(unit, part["a"], part["b"], edge + 1, t1), point_at(unit, part["a"], part["b"], edge, t1), ] projected = [project(point) for point in corners] depth = sum(point[2] for point in projected) / 4 faces.append((depth, part["group"], projected)) faces.sort(key=lambda face: face[0]) svg = [ '', '광터지하차도 BLOCK8 도면 기반 3D 구조 모델', '평면도와 상부평면도의 동일 구조물 중심선을 기준으로 시점과 종점 단면 구조선을 연결한 단일 열린 표면 검토 모델.', '', '', '광터지하차도 · 도면 기반 검토 모델', 'BLOCK8 · 구조선 연결 표면', '', ] for x in range(170, 1031, 60): svg.append(f'') for y in range(180, 541, 36): svg.append(f'') svg.append('') for depth, group, points in faces: coordinates = ' '.join(f'{p[0]:.1f},{p[1]:.1f}' for p in points) fill = COLORS.get(group, COLORS["major"]) opacity = 0.64 if group != "insert" else 0.46 svg.append(f'') for idx, unit in enumerate(model["units"]): left = point_at(unit, [[0, 104]], [[0, 104]], 0, 0) right = point_at(unit, [[0, 104]], [[0, 104]], 0, 1) p0, p1 = project(left), project(right) svg.append(f'BLOCK8 중심선 · STA 319.010STA 338.990') svg.extend([ '', '길이 19.980m · 평면 중심선 교점으로 계산 · 시점/종점 단면 구조선 114개씩 + 블록 내부 윤곽', '단일 구조물 모델입니다. 열린 표면이며 닫힌 체적이 아닙니다. 상부평면도 중심선은 같은 구조물 표현으로 해석했습니다.', '', ]) OUTPUT.write_text('\n'.join(svg) + '\n', encoding="utf-8") print(f"{OUTPUT.relative_to(ROOT)}: {len(faces)} polygons") if __name__ == "__main__": main()