feat(B07): 종단면도를 작성 척도(1/1,000 x 1/200)로 고정
도면에 척도 개념이 없어 도각을 콘텐츠 크기에 맞춰 늘렸다 줄였다. 사용자가 정한 작성 척도로 그림 크기가 결정되도록 좌표를 종이 밀리미터로 옮긴다. - config_system에 DRAWING_SCALE_* 상수 추가 (종단 1/1,000 x 1/200, 횡단 1/100, A1) - 종단 좌표를 종이 mm로: 거리 x1.0, 표고는 기준선 기준 x5.0 (세로 5배 과장) - 기준선(datum)을 종이 y=0으로 정규화, Y축 눈금 라벨은 실제 표고 유지 - frame_entities(fit=False) 추가 — 도각을 실치수 1:1로 두고 위치만 맞춘다. 콘텐츠가 작도 영역(693x468mm)을 넘으면 경고 로그 - 실측: 도각 840x594mm(A1 실치수), 콘텐츠 370x213mm (노선 350m = 350mm) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,6 +10,7 @@ A1 템플릿 기하(변환 시점 고정값): 전체 840x594, 하단 y17~47 표
|
||||
"""
|
||||
|
||||
import json
|
||||
import logging
|
||||
from functools import lru_cache
|
||||
from pathlib import Path
|
||||
from typing import Any
|
||||
@@ -22,6 +23,8 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
|
||||
|
||||
_TEMPLATE_DIR = Path(__file__).resolve().parent.parent / "resources" / "template_2dDrawing"
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
A1_TEMPLATE = "00_template_A1"
|
||||
# A1 내부 작도 영역(템플릿 좌표) — 콘텐츠가 이 영역 중앙에 오도록 배치한다.
|
||||
_A1_INNER = (42.0, 47.0, 812.0, 567.0)
|
||||
@@ -94,12 +97,27 @@ def _transform_entity(
|
||||
return out
|
||||
|
||||
|
||||
def usable_area() -> tuple[float, float]:
|
||||
"""A1 내부 작도 영역에서 여백을 뺀 유효 크기(mm). 척도 고정 도면의 수용 한도."""
|
||||
ix0, iy0, ix1, iy1 = _A1_INNER
|
||||
return (
|
||||
(ix1 - ix0) * (1.0 - 2.0 * _CONTENT_MARGIN),
|
||||
(iy1 - iy0) * (1.0 - 2.0 * _CONTENT_MARGIN),
|
||||
)
|
||||
|
||||
|
||||
def frame_entities(
|
||||
drawing_id: str,
|
||||
content_bbox: tuple[float, float, float, float],
|
||||
template_name: str = A1_TEMPLATE,
|
||||
fit: bool = True,
|
||||
) -> list[dict[str, Any]]:
|
||||
"""콘텐츠 bbox를 감싸는 도각 프레임 엔티티 목록(잠금 레이어). 템플릿 없으면 빈 목록."""
|
||||
"""콘텐츠 bbox를 감싸는 도각 프레임 엔티티 목록(잠금 레이어). 템플릿 없으면 빈 목록.
|
||||
|
||||
fit=False면 도각을 **실치수(1:1)** 로 두고 위치만 맞춘다 — 콘텐츠가 이미 종이
|
||||
밀리미터로 그려진 척도 고정 도면(종단·횡단)용. fit=True는 척도가 없는 도면을
|
||||
도각에 맞춰 늘리던 기존 동작이다.
|
||||
"""
|
||||
template = _load_template(template_name)
|
||||
if not template:
|
||||
return []
|
||||
@@ -108,9 +126,17 @@ def frame_entities(
|
||||
content_h = max(max_y - min_y, 1e-6)
|
||||
|
||||
ix0, iy0, ix1, iy1 = _A1_INNER
|
||||
usable_w = (ix1 - ix0) * (1.0 - 2.0 * _CONTENT_MARGIN)
|
||||
usable_h = (iy1 - iy0) * (1.0 - 2.0 * _CONTENT_MARGIN)
|
||||
scale = max(content_w / usable_w, content_h / usable_h)
|
||||
usable_w, usable_h = usable_area()
|
||||
scale = max(content_w / usable_w, content_h / usable_h) if fit else 1.0
|
||||
if not fit and (content_w > usable_w or content_h > usable_h):
|
||||
logger.warning(
|
||||
"도면 콘텐츠가 A1 작도 영역을 넘습니다: %s (%.0fx%.0f mm > %.0fx%.0f mm)",
|
||||
drawing_id,
|
||||
content_w,
|
||||
content_h,
|
||||
usable_w,
|
||||
usable_h,
|
||||
)
|
||||
|
||||
# 콘텐츠 중심 = 내부 작도 영역 중심이 되도록 이동량 산출.
|
||||
dx = (min_x + max_x) / 2.0 - (ix0 + ix1) / 2.0 * scale
|
||||
|
||||
Reference in New Issue
Block a user