Phase 0 of expert feedback (#1~#11): infrastructure + design + 1차 fixes

Implementations (즉시 동작):
- #1 crash logging: harness/crash_logger.py (sys.excepthook + threading +
  faulthandler, 회전 파일 logs/scanvas.log). main 진입점 통합.
- #2 smooth curves (1차): gate_3d_builder ogee profile를 arc-length parametric
  CubicSpline로 4× densify (8pt→32pt, 36→132 cells, 60 FPS 안전).
- #3 TIN colormap: matplotlib "terrain"의 파란색 범위 제거 → 짙은갈색→황토→
  모래→능선 LinearSegmentedColormap. 9 사이트 교체. 회귀 테스트 추가.
- #5 uv: pyproject.toml + UV_GUIDE.md. base/[py313]/[dev]/[build] extras + hatchling.
- #6,#7,#8 dev cycle infra: .pre-commit-config.yaml (ruff+secrets+위생),
  .gitea/workflows/ci.yml (Py3.11+3.13 matrix), tests/test_regressions.py
  (18 회귀 테스트, iter=1~7 fix 박제), CONTRIBUTING.md (Red→Green 알고리즘).

Design docs (다음 세션 마이그레이션 청사진):
- #4 UI/UX 전면 수정: UI_REDESIGN_PLAN.md (12 popup→1 inspector, vtkTkRenderWidget
  embedding 게이트, 4 phase × 7 sessions).
- #10 Core/Plugin: ARCHITECTURE_PLAN.md (Core 14 / Plugin 7 구조물 + 2 렌더 + 1 QA,
  STRUCTURE_REGISTRY 확장, manifest 기반 디스커버리).
- #11 perf hotspots: PERFORMANCE_BASELINE.md (19 핫스팟, P1: 타일 직렬DL 5~30s,
  캡처 직렬 4.5~15s, numpy 벡터화 가능 Python loops, 텍스처 4회 반복read).

Behavior preservation: ruff 0 errors, pytest 17 passed/1 skipped(bpy),
import 33/33 OK on Py3.13.13.

Item #2 P2/P3 곡선, #4 UI 마이그레이션, #10 Phase 1 추출, #11 P1 최적화는 차기 세션.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-08 11:45:30 +09:00
parent b9342f6726
commit e9cc6bfcf4
15 changed files with 2617 additions and 15 deletions

View File

@@ -78,7 +78,9 @@ class GateBuilder:
def _build_spillway_body(self):
"""Ogee 프로파일을 span 방향으로 extrude하여 본체 생성."""
p = self.params
profile = p.ogee_profile
# 매끄러운 곡면을 위해 ogee 프로파일을 CubicSpline으로 4× densify
# (사용자 피드백 #2: 곡선 직선 분절 → spline 보간으로 매끄럽게)
profile = self._densify_profile(p.ogee_profile, n_factor=4)
if len(profile) < 3:
return
@@ -101,6 +103,50 @@ class GateBuilder:
if mesh is not None:
self.meshes.append((mesh, COLORS["concrete"], 1.0))
@staticmethod
def _densify_profile(profile_2d, n_factor: int = 4, n_min: int = 4):
"""(x, z) 프로파일 점을 arc-length parametric CubicSpline로 보간.
Ogee 단면은 단조 함수가 아닐 수 있어(상류 옹벽 수직 구간에서 동일 x 다중 z)
parametric (s, x), (s, z) 곡선이 안전하다. 호 길이 누적을 매개변수로 사용해
균등하게 재샘플링한다.
Args:
profile_2d: [(x, z), ...] 원본 단면 점.
n_factor: 출력 점 개수 = max(n_factor * len(profile), n_min).
n_min: 출력 최소 점 개수.
Returns:
[(x, z), ...] 보간된 점 리스트. scipy 미설치 등 실패 시 원본 반환.
"""
if profile_2d is None:
return []
if len(profile_2d) < 4:
# 점이 너무 적으면 spline 의미 없음 — 원본 그대로
return list(profile_2d)
try:
from scipy.interpolate import CubicSpline
except Exception:
return list(profile_2d)
pts = np.asarray(profile_2d, dtype=float)
diffs = np.diff(pts, axis=0)
seg_len = np.sqrt((diffs ** 2).sum(axis=1))
s = np.concatenate([[0.0], np.cumsum(seg_len)])
if s[-1] <= 1e-9:
return list(profile_2d)
s_norm = s / s[-1]
try:
cs_x = CubicSpline(s_norm, pts[:, 0], bc_type="natural")
cs_z = CubicSpline(s_norm, pts[:, 1], bc_type="natural")
except Exception:
return list(profile_2d)
n_out = max(n_factor * len(profile_2d), n_min)
s_new = np.linspace(0.0, 1.0, n_out)
return list(zip(cs_x(s_new).tolist(), cs_z(s_new).tolist(), strict=False))
def _extrude_2d_profile(self, profile_2d: list, span: float) -> np.ndarray:
"""(y, z) 프로파일 점들을 X 방향으로 2개 평면(start/end) 생성.