feat: StationOverlay 렌더링 최적화 및 스무딩 적용 close #1

- 텍스트(측점/POI) 전 프레임 사전 계산 Map (requestIdleCallback 백그라운드)
- 드론 데이터 이동 평균 스무딩 (smoothFrame ±N프레임)
- 30fps→60fps 프레임 간 선형 보간 (performance.now() 기반)
- EMA(지수이동평균) 표시 위치 스무딩 (α=0.01 기본값)
- 글씨 2배 크기, bold, strokeText 테두리, 배경 박스 제거
- 카메라 파라미터 패널에 smooth/EMA α 슬라이더 추가

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
minsung
2026-04-01 15:11:39 +09:00
commit 2aae3d1c0d
89 changed files with 15739 additions and 0 deletions

View File

@@ -0,0 +1,80 @@
# -*- coding: utf-8 -*-
"""
PostToolUse(Write) 훅: 히스토리 파일 필수 필드 검증
path.json 의 history_path 하위 *.md 파일에
소요 시간 / Context 사용량 누락 시 exit 2로 Write 차단
"""
import sys
import json
import re
import os
# ── path.json 로드 ────────────────────────────────────────────────────────────
HOOKS_DIR = os.path.dirname(os.path.abspath(__file__))
PATH_JSON = os.path.join(HOOKS_DIR, "path.json")
try:
with open(PATH_JSON, encoding="utf-8") as f:
paths = json.load(f)
except Exception:
paths = {}
history_path = paths.get("history_path", "docs/history").replace("\\", "/").rstrip("/")
# history_path 하위 어느 깊이든 *.md 이면 검사
history_pattern = re.escape(history_path) + r"/.+\.md$"
# ── 훅 입력 파싱 ──────────────────────────────────────────────────────────────
try:
data = json.load(sys.stdin)
except Exception:
sys.exit(0)
tool_input = data.get("tool_input", {})
file_path = tool_input.get("file_path", "")
content = tool_input.get("content", "")
normalized = file_path.replace("\\", "/")
if not re.search(history_pattern, normalized):
sys.exit(0)
missing = []
if not re.search(
r"\*\*소요\s*시간\*\*|^##\s*소요\s*시간|소요\s*시간\s*:",
content,
re.MULTILINE,
):
missing.append("소요 시간")
if not re.search(
r"\*\*Context\s*사용량\*\*|^##\s*Context\s*사용량|Context\s*사용량\s*:",
content,
re.MULTILINE | re.IGNORECASE,
):
missing.append("Context 사용량")
if missing:
sys.stderr.write("[BLOCKED] 히스토리 파일 필수 항목 누락: " + ", ".join(missing) + "\n")
sys.stderr.write("\n")
sys.stderr.write("파일 상단에 다음 항목을 반드시 포함하세요:\n")
sys.stderr.write("\n")
sys.stderr.write(" **소요 시간**: X분\n")
sys.stderr.write(" **Context 사용량**: input Xk / output Xk tokens\n")
sys.stderr.write("\n")
sys.stderr.write("파일: " + file_path + "\n")
sys.exit(2)
# ── 이슈 번호 검사 (없으면 사용자에게 질문 요청) ──────────────────────────────
if not re.search(r"\*\*이슈\*\*\s*[:\s]+#\d+", content, re.MULTILINE):
sys.stderr.write("[이슈 번호 필요] 히스토리 파일에 이슈 번호가 없습니다.\n")
sys.stderr.write("\n")
sys.stderr.write("사용자에게 다음을 질문하세요:\n")
sys.stderr.write(" '이 작업과 관련된 Gitea 이슈 번호가 있나요? (예: #1 / 없으면 #0)'\n")
sys.stderr.write("\n")
sys.stderr.write("답변 후 파일 상단에 추가하고 다시 저장하세요:\n")
sys.stderr.write(" **이슈**: #N\n")
sys.stderr.write("\n")
sys.stderr.write("파일: " + file_path + "\n")
sys.exit(2)
sys.exit(0)