feat(B07): 표준 횡단면도 — 치수·측구 확대도·암반선 2단
빈 도각이던 표준 횡단면도를 실제 도면으로 만듦. - 본 그림: B06 좌측 패널 모식도와 같은 배치를 실치수로 그림(1/50). 노폭·노견· 측구 상단폭·노면 전폭에 치수선(눈금+치수값)을 붙이고, 절토·성토 경사비와 횡단경사를 표기. 값은 B06 표준 횡단면 설정을 그대로 읽고 없으면 config 기본값. - 측구 부분 확대도(1/10): 상단폭·저폭·깊이 치수 + 확대 축척 표기. - 암반 2단 절토: 아래는 암반 경사(1:0.4), 위는 토사 경사(1:1), 갈리는 높이에 암반선을 파선으로 긋고 각도를 함께 적음. - 암 L형 측구·포장 횡단경사는 주기(※)로 적음 — 본 그림은 토사 기준. 곁들여: Router_Support 가 700줄을 넘어 재수출 import 를 한 문장으로 합쳐 681줄로 줄임(기능 변화 없음). 검증: 치수값이 STANDARD_CROSS_SECTION 과 일치(500·3000·500·900·4000), 확대도 900·300·300 + S=1/10, 2단 절토선 꺾임점 1개, 콘텐츠 358.2x172.6 mm ≤ A1 작도영역. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -14,6 +14,7 @@ export interface DesignDrawingItem {
|
|||||||
| "plan"
|
| "plan"
|
||||||
| "landuse"
|
| "landuse"
|
||||||
| "plan_lidar"
|
| "plan_lidar"
|
||||||
|
| "cross_standard"
|
||||||
| "blank";
|
| "blank";
|
||||||
label: string;
|
label: string;
|
||||||
chainage_m: number | null;
|
chainage_m: number | null;
|
||||||
@@ -101,6 +102,7 @@ export interface DesignDrawingResponse {
|
|||||||
| "plan"
|
| "plan"
|
||||||
| "landuse"
|
| "landuse"
|
||||||
| "plan_lidar"
|
| "plan_lidar"
|
||||||
|
| "cross_standard"
|
||||||
| "blank";
|
| "blank";
|
||||||
label: string;
|
label: string;
|
||||||
drawing: CadDrawing;
|
drawing: CadDrawing;
|
||||||
|
|||||||
@@ -0,0 +1,581 @@
|
|||||||
|
"""B07 표준 횡단면도 CAD 조립 — 변수 모식도에 치수를 넣고, 측구 확대도·암반선 2단을 함께 낸다.
|
||||||
|
|
||||||
|
사용자 지시(2026-09-04) — 「표준 횡단면도 좌상단에 기본값으로 B06 좌측 패널의 변수 위치
|
||||||
|
안내와 비슷한 그림을 넣고, 변수 이름 자리에 도면처럼 치수를 적을 것. 측구는 작으니 부분
|
||||||
|
확대도로. 발파·암반이면 암반선과 각도를 넣어 절토측이 2단(토사 각도 + 암반 각도)으로
|
||||||
|
표현될 것」.
|
||||||
|
|
||||||
|
배치는 B06 좌측 패널 모식도(`B06_Section_UI_Standard_Diagram.ts`)와 같다 — 좌가 절토·측구,
|
||||||
|
우가 성토, 가운데가 계획고. 다른 점은 **실치수**라는 것이다. 모식도는 위치 안내라 비율이
|
||||||
|
없지만 도면은 축척(본 그림 1/50, 측구 확대도 1/10)대로 그리고 치수선을 붙인다.
|
||||||
|
|
||||||
|
값은 B06 「표준 횡단면 설정」(`standard_cross_section`)을 그대로 읽는다 — 여기서 기하를
|
||||||
|
다시 정하지 않는다. 저장값이 없으면 config 기본값을 쓴다.
|
||||||
|
|
||||||
|
좌표 규약: 종이 mm = 실거리 m x MM. 원점은 계획고(노면 중심).
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad import (
|
||||||
|
DRAWING_FORMAT,
|
||||||
|
FRAME_LAYER_ID,
|
||||||
|
TABLE_LABEL_COLOR,
|
||||||
|
_layer,
|
||||||
|
_text_entity,
|
||||||
|
polyline_entity,
|
||||||
|
)
|
||||||
|
from B07_DesignDetail.B07_DesignDetail_Engine_Template import (
|
||||||
|
entities_bbox,
|
||||||
|
frame_entities,
|
||||||
|
scale_fields,
|
||||||
|
)
|
||||||
|
from config.config_system import (
|
||||||
|
DRAWING_SCALE_CROSS_STANDARD,
|
||||||
|
DRAWING_SCALE_DITCH_DETAIL,
|
||||||
|
STANDARD_CROSS_SECTION,
|
||||||
|
)
|
||||||
|
|
||||||
|
STANDARD_KIND = "cross_standard"
|
||||||
|
STANDARD_LABEL = "표준 횡단면도"
|
||||||
|
|
||||||
|
# 도면 좌표 = 종이 mm. 본 그림 1/50 -> 1 m = 20 mm, 측구 확대도 1/10 -> 1 m = 100 mm.
|
||||||
|
MM = 1000.0 / DRAWING_SCALE_CROSS_STANDARD
|
||||||
|
DETAIL_MM = 1000.0 / DRAWING_SCALE_DITCH_DETAIL
|
||||||
|
|
||||||
|
SECTION_LAYER_ID = "b07-std-section"
|
||||||
|
ROCK_LAYER_ID = "b07-std-rock"
|
||||||
|
DIM_LAYER_ID = "b07-std-dim"
|
||||||
|
DETAIL_LAYER_ID = "b07-std-detail"
|
||||||
|
NOTE_LAYER_ID = "b07-std-note"
|
||||||
|
TITLE_LAYER_ID = "b07-std-title"
|
||||||
|
|
||||||
|
SECTION_COLOR = "#111111"
|
||||||
|
ROCK_COLOR = "#a63d3d"
|
||||||
|
DIM_COLOR = "#2f6fb0"
|
||||||
|
DETAIL_COLOR = "#111111"
|
||||||
|
NOTE_COLOR = "#333333"
|
||||||
|
|
||||||
|
_LINE_WIDTH = 2
|
||||||
|
_TITLE_FONT_SIZE = 7.0
|
||||||
|
_LABEL_FONT_SIZE = 3.0
|
||||||
|
_DIM_FONT_SIZE = 2.6
|
||||||
|
_NOTE_FONT_SIZE = 2.8
|
||||||
|
|
||||||
|
# 그림에 세울 절·성토 높이(m) — 표준도는 실제 지형이 없으므로 대표 높이로 그린다.
|
||||||
|
_CUT_HEIGHT_M = 3.0
|
||||||
|
_FILL_HEIGHT_M = 3.0
|
||||||
|
# 암반 구간: 절토 밑에서 이만큼이 암반이고 그 위가 토사다(2단 절토).
|
||||||
|
_ROCK_HEIGHT_M = 1.5
|
||||||
|
|
||||||
|
_DIM_TICK_MM = 1.6 # 치수선 끝 눈금 반길이
|
||||||
|
_DIM_OFFSET_MM = 8.0 # 치수선을 그림에서 띄우는 거리
|
||||||
|
_DIM_GAP_MM = 6.0 # 치수선 단 사이
|
||||||
|
|
||||||
|
|
||||||
|
def _ground(kind: str, standard: dict[str, Any] | None) -> dict[str, Any]:
|
||||||
|
"""표준 횡단면 설정에서 한 지반유형 값을 꺼낸다. 없으면 config 기본값."""
|
||||||
|
stored = (standard or {}).get(kind)
|
||||||
|
if isinstance(stored, dict) and stored:
|
||||||
|
merged = dict(STANDARD_CROSS_SECTION.get(kind) or {})
|
||||||
|
merged.update(stored)
|
||||||
|
return merged
|
||||||
|
return dict(STANDARD_CROSS_SECTION.get(kind) or {})
|
||||||
|
|
||||||
|
|
||||||
|
def _number(value: Any, fallback: float) -> float:
|
||||||
|
return float(value) if isinstance(value, (int, float)) else fallback
|
||||||
|
|
||||||
|
|
||||||
|
def _dim_entities(
|
||||||
|
drawing_id: str,
|
||||||
|
tag: str,
|
||||||
|
start: tuple[float, float],
|
||||||
|
end: tuple[float, float],
|
||||||
|
label: str,
|
||||||
|
layer_id: str = DIM_LAYER_ID,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""치수선 한 벌(치수선 + 양끝 눈금 + 치수값). 좌표는 종이 mm."""
|
||||||
|
entities: list[dict[str, Any]] = []
|
||||||
|
line = polyline_entity(drawing_id, [start, end], layer_id, DIM_COLOR, suffix=f":dim:{tag}")
|
||||||
|
if line:
|
||||||
|
entities.append(line)
|
||||||
|
dx, dy = end[0] - start[0], end[1] - start[1]
|
||||||
|
length = math.hypot(dx, dy) or 1.0
|
||||||
|
nx, ny = -dy / length, dx / length
|
||||||
|
for index, point in enumerate((start, end)):
|
||||||
|
tick = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[
|
||||||
|
(point[0] - nx * _DIM_TICK_MM, point[1] - ny * _DIM_TICK_MM),
|
||||||
|
(point[0] + nx * _DIM_TICK_MM, point[1] + ny * _DIM_TICK_MM),
|
||||||
|
],
|
||||||
|
layer_id,
|
||||||
|
DIM_COLOR,
|
||||||
|
suffix=f":dim:{tag}:tick:{index}",
|
||||||
|
)
|
||||||
|
if tick:
|
||||||
|
entities.append(tick)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:dim:{tag}:text",
|
||||||
|
label,
|
||||||
|
(start[0] + end[0]) / 2.0 + nx * 2.2,
|
||||||
|
(start[1] + end[1]) / 2.0 + ny * 2.2,
|
||||||
|
layer_id,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
DIM_COLOR,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return entities
|
||||||
|
|
||||||
|
|
||||||
|
def _section_geometry(values: dict[str, Any]) -> dict[str, Any]:
|
||||||
|
"""표준 단면의 실좌표(m) 꼭짓점. 좌가 절토·측구, 우가 성토(B06 모식도와 같은 배치)."""
|
||||||
|
road = _number(values.get("road_width_m"), 3.0)
|
||||||
|
shoulder_left = _number(values.get("shoulder_left_m"), 0.5)
|
||||||
|
shoulder_right = _number(values.get("shoulder_right_m"), 0.5)
|
||||||
|
ditch = values.get("ditch") if isinstance(values.get("ditch"), dict) else {}
|
||||||
|
top_width = _number(ditch.get("top_width_m"), 0.9)
|
||||||
|
bottom_width = _number(ditch.get("bottom_width_m"), 0.3)
|
||||||
|
depth = _number(ditch.get("depth_m"), 0.3)
|
||||||
|
slope = values.get("cross_slope_pct") if isinstance(values.get("cross_slope_pct"), dict) else {}
|
||||||
|
cross_pct = _number(slope.get("max"), _number(slope.get("min"), 3.0))
|
||||||
|
cut_ratio = _number(values.get("cut_slope_ratio"), 1.0)
|
||||||
|
fill_ratio = _number(values.get("fill_slope_ratio"), 1.2)
|
||||||
|
|
||||||
|
road_left = -(road / 2.0 + shoulder_left)
|
||||||
|
road_right = road / 2.0 + shoulder_right
|
||||||
|
# 횡단경사는 측구(좌) 쪽으로 내려간다 — 노면 좌끝이 계획고보다 낮다.
|
||||||
|
drop = abs(road_left) * cross_pct / 100.0
|
||||||
|
surface = [(road_right, 0.0), (road_left, -drop)]
|
||||||
|
|
||||||
|
ditch_top_left = road_left - top_width
|
||||||
|
ditch_bottom_y = -drop - depth
|
||||||
|
inset = (top_width - bottom_width) / 2.0
|
||||||
|
ditch_line = [
|
||||||
|
(road_left, -drop),
|
||||||
|
(road_left - inset, ditch_bottom_y),
|
||||||
|
(ditch_top_left + inset, ditch_bottom_y),
|
||||||
|
(ditch_top_left, -drop),
|
||||||
|
]
|
||||||
|
cut_top = (ditch_top_left - _CUT_HEIGHT_M * cut_ratio, -drop + _CUT_HEIGHT_M)
|
||||||
|
fill_toe = (road_right + _FILL_HEIGHT_M * fill_ratio, -_FILL_HEIGHT_M)
|
||||||
|
return {
|
||||||
|
"road": road,
|
||||||
|
"shoulder_left": shoulder_left,
|
||||||
|
"shoulder_right": shoulder_right,
|
||||||
|
"top_width": top_width,
|
||||||
|
"bottom_width": bottom_width,
|
||||||
|
"depth": depth,
|
||||||
|
"cross_pct": cross_pct,
|
||||||
|
"cut_ratio": cut_ratio,
|
||||||
|
"fill_ratio": fill_ratio,
|
||||||
|
"road_left": road_left,
|
||||||
|
"road_right": road_right,
|
||||||
|
"drop": drop,
|
||||||
|
"surface": surface,
|
||||||
|
"ditch_line": ditch_line,
|
||||||
|
"ditch_top_left": ditch_top_left,
|
||||||
|
"cut_start": (ditch_top_left, -drop),
|
||||||
|
"cut_top": cut_top,
|
||||||
|
"fill_toe": fill_toe,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def _rock_entities(
|
||||||
|
drawing_id: str, geometry: dict[str, Any], rock_ratio: float, paper: Any
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""암반선과 2단 절토(아래=암반각, 위=토사각)를 절토측에 덧그린다."""
|
||||||
|
entities: list[dict[str, Any]] = []
|
||||||
|
start_x, start_y = geometry["cut_start"]
|
||||||
|
soil_ratio = geometry["cut_ratio"]
|
||||||
|
# 아래 단: 암반각으로 _ROCK_HEIGHT_M 만큼 올라간다.
|
||||||
|
bench = (start_x - _ROCK_HEIGHT_M * rock_ratio, start_y + _ROCK_HEIGHT_M)
|
||||||
|
# 위 단: 그 위는 토사각.
|
||||||
|
upper = (
|
||||||
|
bench[0] - (_CUT_HEIGHT_M - _ROCK_HEIGHT_M) * soil_ratio,
|
||||||
|
bench[1] + (_CUT_HEIGHT_M - _ROCK_HEIGHT_M),
|
||||||
|
)
|
||||||
|
two_stage = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[paper((start_x, start_y)), paper(bench), paper(upper)],
|
||||||
|
ROCK_LAYER_ID,
|
||||||
|
ROCK_COLOR,
|
||||||
|
suffix=":rock:cut",
|
||||||
|
width=_LINE_WIDTH,
|
||||||
|
)
|
||||||
|
if two_stage:
|
||||||
|
entities.append(two_stage)
|
||||||
|
# 암반선 — 2단이 갈리는 높이의 수평 파선.
|
||||||
|
boundary = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[paper((bench[0] - 1.5, bench[1])), paper((geometry["road_right"], bench[1]))],
|
||||||
|
ROCK_LAYER_ID,
|
||||||
|
ROCK_COLOR,
|
||||||
|
suffix=":rock:boundary",
|
||||||
|
dash=[6, 4],
|
||||||
|
)
|
||||||
|
if boundary:
|
||||||
|
entities.append(boundary)
|
||||||
|
label_x, label_y = paper((bench[0] - 1.6, bench[1]))
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:rock:boundary:text",
|
||||||
|
"암반선",
|
||||||
|
label_x,
|
||||||
|
label_y + 2.5,
|
||||||
|
ROCK_LAYER_ID,
|
||||||
|
_LABEL_FONT_SIZE,
|
||||||
|
ROCK_COLOR,
|
||||||
|
align="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
mid_lower = paper(((start_x + bench[0]) / 2.0, (start_y + bench[1]) / 2.0))
|
||||||
|
mid_upper = paper(((bench[0] + upper[0]) / 2.0, (bench[1] + upper[1]) / 2.0))
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:rock:lower",
|
||||||
|
f"암반 1:{rock_ratio:g}",
|
||||||
|
mid_lower[0] - 6.0,
|
||||||
|
mid_lower[1],
|
||||||
|
ROCK_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
ROCK_COLOR,
|
||||||
|
align="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:rock:upper",
|
||||||
|
f"토사 1:{soil_ratio:g}",
|
||||||
|
mid_upper[0] - 6.0,
|
||||||
|
mid_upper[1],
|
||||||
|
ROCK_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
ROCK_COLOR,
|
||||||
|
align="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return entities
|
||||||
|
|
||||||
|
|
||||||
|
def _ditch_detail_entities(
|
||||||
|
drawing_id: str, geometry: dict[str, Any], origin: tuple[float, float]
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
"""측구 부분 확대도(1/10) — 작아서 본 그림에서는 치수를 읽을 수 없다."""
|
||||||
|
entities: list[dict[str, Any]] = []
|
||||||
|
top_width = geometry["top_width"]
|
||||||
|
bottom_width = geometry["bottom_width"]
|
||||||
|
depth = geometry["depth"]
|
||||||
|
inset = (top_width - bottom_width) / 2.0
|
||||||
|
ox, oy = origin
|
||||||
|
|
||||||
|
def paper(point: tuple[float, float]) -> tuple[float, float]:
|
||||||
|
return (ox + point[0] * DETAIL_MM, oy + point[1] * DETAIL_MM)
|
||||||
|
|
||||||
|
shape = [
|
||||||
|
(0.0, 0.0),
|
||||||
|
(inset, -depth),
|
||||||
|
(inset + bottom_width, -depth),
|
||||||
|
(top_width, 0.0),
|
||||||
|
]
|
||||||
|
outline = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[paper(point) for point in shape],
|
||||||
|
DETAIL_LAYER_ID,
|
||||||
|
DETAIL_COLOR,
|
||||||
|
suffix=":detail:ditch",
|
||||||
|
width=_LINE_WIDTH,
|
||||||
|
)
|
||||||
|
if outline:
|
||||||
|
entities.append(outline)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"detail-top",
|
||||||
|
paper((0.0, 0.0 + 0.06)),
|
||||||
|
paper((top_width, 0.0 + 0.06)),
|
||||||
|
f"{top_width * 1000:.0f}",
|
||||||
|
DETAIL_LAYER_ID,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"detail-bottom",
|
||||||
|
paper((inset, -depth - 0.06)),
|
||||||
|
paper((inset + bottom_width, -depth - 0.06)),
|
||||||
|
f"{bottom_width * 1000:.0f}",
|
||||||
|
DETAIL_LAYER_ID,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"detail-depth",
|
||||||
|
paper((top_width + 0.08, 0.0)),
|
||||||
|
paper((top_width + 0.08, -depth)),
|
||||||
|
f"{depth * 1000:.0f}",
|
||||||
|
DETAIL_LAYER_ID,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
title = paper((top_width / 2.0, 0.3))
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:detail:title",
|
||||||
|
f"측구 상세도 (S = 1/{DRAWING_SCALE_DITCH_DETAIL})",
|
||||||
|
title[0],
|
||||||
|
title[1],
|
||||||
|
DETAIL_LAYER_ID,
|
||||||
|
_LABEL_FONT_SIZE,
|
||||||
|
TABLE_LABEL_COLOR,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return entities
|
||||||
|
|
||||||
|
|
||||||
|
def build_standard_cross_drawing(
|
||||||
|
drawing_id: str, label: str, standard: dict[str, Any] | None = None
|
||||||
|
) -> dict[str, Any]:
|
||||||
|
"""표준 횡단면도 한 장을 만든다 — 본 그림 + 치수 + 측구 확대도 + 암반 2단 + 주기."""
|
||||||
|
soil = _ground("soil", standard)
|
||||||
|
rock = _ground("rock", standard)
|
||||||
|
paved = _ground("paved", standard)
|
||||||
|
geometry = _section_geometry(soil)
|
||||||
|
|
||||||
|
def paper(point: tuple[float, float]) -> tuple[float, float]:
|
||||||
|
return (point[0] * MM, point[1] * MM)
|
||||||
|
|
||||||
|
entities: list[dict[str, Any]] = []
|
||||||
|
# 본 그림: 절토면 - 측구 - 노면 - 성토면을 한 줄로 잇는다.
|
||||||
|
outline = [
|
||||||
|
geometry["cut_top"],
|
||||||
|
*geometry["ditch_line"][::-1],
|
||||||
|
*geometry["surface"][::-1],
|
||||||
|
geometry["fill_toe"],
|
||||||
|
]
|
||||||
|
body = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[paper(point) for point in outline],
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
SECTION_COLOR,
|
||||||
|
suffix=":section",
|
||||||
|
width=_LINE_WIDTH,
|
||||||
|
)
|
||||||
|
if body:
|
||||||
|
entities.append(body)
|
||||||
|
# 중심선(계획고).
|
||||||
|
center = polyline_entity(
|
||||||
|
drawing_id,
|
||||||
|
[paper((0.0, 1.2)), paper((0.0, -1.2))],
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
SECTION_COLOR,
|
||||||
|
suffix=":center",
|
||||||
|
dash=[10, 3, 2, 3],
|
||||||
|
)
|
||||||
|
if center:
|
||||||
|
entities.append(center)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:center:text",
|
||||||
|
"계획고",
|
||||||
|
*paper((0.0, 1.45)),
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
_LABEL_FONT_SIZE,
|
||||||
|
SECTION_COLOR,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 치수선 — 노면 아래 두 단(위: 노견·노폭·노견, 아래: 노면 전폭).
|
||||||
|
base_y = min(geometry["fill_toe"][1], -geometry["drop"] - geometry["depth"])
|
||||||
|
dim_y = base_y * MM - _DIM_OFFSET_MM
|
||||||
|
half = geometry["road"] / 2.0
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"shoulder-left",
|
||||||
|
(geometry["road_left"] * MM, dim_y),
|
||||||
|
(-half * MM, dim_y),
|
||||||
|
f"{geometry['shoulder_left'] * 1000:.0f}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"road",
|
||||||
|
(-half * MM, dim_y),
|
||||||
|
(half * MM, dim_y),
|
||||||
|
f"{geometry['road'] * 1000:.0f}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"shoulder-right",
|
||||||
|
(half * MM, dim_y),
|
||||||
|
(geometry["road_right"] * MM, dim_y),
|
||||||
|
f"{geometry['shoulder_right'] * 1000:.0f}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"ditch-top",
|
||||||
|
(geometry["ditch_top_left"] * MM, dim_y),
|
||||||
|
(geometry["road_left"] * MM, dim_y),
|
||||||
|
f"{geometry['top_width'] * 1000:.0f}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
roadbed_width_m = geometry["road"] + geometry["shoulder_left"] + geometry["shoulder_right"]
|
||||||
|
entities.extend(
|
||||||
|
_dim_entities(
|
||||||
|
drawing_id,
|
||||||
|
"roadbed",
|
||||||
|
(geometry["road_left"] * MM, dim_y - _DIM_GAP_MM),
|
||||||
|
(geometry["road_right"] * MM, dim_y - _DIM_GAP_MM),
|
||||||
|
f"{roadbed_width_m * 1000:.0f}",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 경사·횡단경사 표기.
|
||||||
|
cut_mid = paper(
|
||||||
|
(
|
||||||
|
(geometry["cut_start"][0] + geometry["cut_top"][0]) / 2.0,
|
||||||
|
(geometry["cut_start"][1] + geometry["cut_top"][1]) / 2.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
fill_mid = paper(
|
||||||
|
(
|
||||||
|
(geometry["road_right"] + geometry["fill_toe"][0]) / 2.0,
|
||||||
|
(0.0 + geometry["fill_toe"][1]) / 2.0,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:cut:text",
|
||||||
|
f"절토 1:{geometry['cut_ratio']:g}",
|
||||||
|
cut_mid[0] - 4.0,
|
||||||
|
cut_mid[1] + 3.0,
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
SECTION_COLOR,
|
||||||
|
align="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:fill:text",
|
||||||
|
f"성토 1:{geometry['fill_ratio']:g}",
|
||||||
|
fill_mid[0] + 4.0,
|
||||||
|
fill_mid[1] + 3.0,
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
SECTION_COLOR,
|
||||||
|
align="left",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:cross-slope:text",
|
||||||
|
f"횡단경사 {geometry['cross_pct']:g}%",
|
||||||
|
*paper((geometry["road_left"] / 2.0, 0.6)),
|
||||||
|
SECTION_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
SECTION_COLOR,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
# 암반 구간 2단 절토.
|
||||||
|
entities.extend(
|
||||||
|
_rock_entities(drawing_id, geometry, _number(rock.get("cut_slope_ratio"), 0.4), paper)
|
||||||
|
)
|
||||||
|
|
||||||
|
body_bbox = entities_bbox(entities)
|
||||||
|
right = body_bbox[2] if body_bbox else 0.0
|
||||||
|
top = body_bbox[3] if body_bbox else 0.0
|
||||||
|
|
||||||
|
# 측구 부분 확대도 — 본 그림 오른쪽 위.
|
||||||
|
entities.extend(_ditch_detail_entities(drawing_id, geometry, (right + 28.0, top - 30.0)))
|
||||||
|
|
||||||
|
# 주기: 구간별로 달라지는 값만 적는다(기본은 토사).
|
||||||
|
notes = [
|
||||||
|
"※ 본 그림은 토사 구간 기준임.",
|
||||||
|
f"※ 암 구간 — 절토 1:{_number(rock.get('cut_slope_ratio'), 0.4):g}, "
|
||||||
|
f"L형 측구 {_number((rock.get('ditch_l_type') or {}).get('width_m'), 0.5) * 1000:.0f}"
|
||||||
|
f"×{_number((rock.get('ditch_l_type') or {}).get('depth_m'), 0.1) * 1000:.0f}mm "
|
||||||
|
"(횡단면도에서 일반·L형 중 선택).",
|
||||||
|
f"※ 포장 구간 — 절·성토 경사는 토사와 같고 횡단경사만 "
|
||||||
|
f"{_number((paved.get('cross_slope_pct') or {}).get('min'), 1.5):g}~"
|
||||||
|
f"{_number((paved.get('cross_slope_pct') or {}).get('max'), 2.0):g}% 임.",
|
||||||
|
"※ 치수 단위 mm.",
|
||||||
|
]
|
||||||
|
note_bbox = entities_bbox(entities)
|
||||||
|
note_x = note_bbox[0] if note_bbox else 0.0
|
||||||
|
note_y = (note_bbox[1] if note_bbox else 0.0) - 12.0
|
||||||
|
for index, note in enumerate(notes):
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:note:{index}",
|
||||||
|
note,
|
||||||
|
note_x,
|
||||||
|
note_y - index * 5.0,
|
||||||
|
NOTE_LAYER_ID,
|
||||||
|
_NOTE_FONT_SIZE,
|
||||||
|
NOTE_COLOR,
|
||||||
|
align="left",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
bbox = entities_bbox(entities)
|
||||||
|
if bbox:
|
||||||
|
min_bx, _min_by, max_bx, max_by = bbox
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:title",
|
||||||
|
label,
|
||||||
|
(min_bx + max_bx) / 2.0,
|
||||||
|
max_by + 12.0,
|
||||||
|
TITLE_LAYER_ID,
|
||||||
|
_TITLE_FONT_SIZE,
|
||||||
|
TABLE_LABEL_COLOR,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.append(
|
||||||
|
_text_entity(
|
||||||
|
f"{drawing_id}:scale",
|
||||||
|
f"S = 1/{DRAWING_SCALE_CROSS_STANDARD}",
|
||||||
|
max_bx,
|
||||||
|
max_by + 5.0,
|
||||||
|
TITLE_LAYER_ID,
|
||||||
|
_DIM_FONT_SIZE,
|
||||||
|
TABLE_LABEL_COLOR,
|
||||||
|
align="right",
|
||||||
|
)
|
||||||
|
)
|
||||||
|
entities.extend(
|
||||||
|
frame_entities(
|
||||||
|
drawing_id,
|
||||||
|
entities_bbox(entities) or bbox,
|
||||||
|
fit=False,
|
||||||
|
fields={
|
||||||
|
"도면명": label,
|
||||||
|
**scale_fields(("", DRAWING_SCALE_CROSS_STANDARD)),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"format": DRAWING_FORMAT,
|
||||||
|
"entities": entities,
|
||||||
|
"layers": [
|
||||||
|
_layer(SECTION_LAYER_ID, "표준 단면"),
|
||||||
|
_layer(ROCK_LAYER_ID, "암반선·2단 절토"),
|
||||||
|
_layer(DIM_LAYER_ID, "치수"),
|
||||||
|
_layer(DETAIL_LAYER_ID, "측구 상세도"),
|
||||||
|
_layer(NOTE_LAYER_ID, "주기"),
|
||||||
|
_layer(TITLE_LAYER_ID, "표제"),
|
||||||
|
_layer(FRAME_LAYER_ID, "도각", locked=True),
|
||||||
|
],
|
||||||
|
}
|
||||||
@@ -17,6 +17,7 @@ from B06_Section.B06_Section_Repository import (
|
|||||||
get_cross_section_design,
|
get_cross_section_design,
|
||||||
get_cross_section_designs,
|
get_cross_section_designs,
|
||||||
get_longitudinal_section,
|
get_longitudinal_section,
|
||||||
|
get_project_standard_cross_section,
|
||||||
merge_cross_section_design_by_round,
|
merge_cross_section_design_by_round,
|
||||||
)
|
)
|
||||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
||||||
@@ -34,6 +35,7 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Template import (
|
|||||||
use_title_fields,
|
use_title_fields,
|
||||||
)
|
)
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support import (
|
from B07_DesignDetail.B07_DesignDetail_Router_Support import (
|
||||||
|
CROSS_STANDARD_ID,
|
||||||
LANDUSE_ID,
|
LANDUSE_ID,
|
||||||
LIDAR_ID,
|
LIDAR_ID,
|
||||||
MASS_HAUL_ID,
|
MASS_HAUL_ID,
|
||||||
@@ -307,6 +309,21 @@ async def get_design_drawing(
|
|||||||
if context is None:
|
if context is None:
|
||||||
return JSONResponse(status_code=404, content={"status": "error", "message": reason})
|
return JSONResponse(status_code=404, content={"status": "error", "message": reason})
|
||||||
source_design = await asyncio.to_thread(watershed_source, context)
|
source_design = await asyncio.to_thread(watershed_source, context)
|
||||||
|
elif drawing_id == CROSS_STANDARD_ID:
|
||||||
|
# 표준 횡단면도는 B06 「표준 횡단면 설정」 저장값으로 그린다(없으면 config 기본값).
|
||||||
|
pool = get_db_pool()
|
||||||
|
async with pool.acquire() as connection:
|
||||||
|
async with connection.cursor() as cursor:
|
||||||
|
await cursor.execute(
|
||||||
|
"SELECT company_id FROM projects WHERE id = %s AND deleted_at IS NULL",
|
||||||
|
(str(project_id),),
|
||||||
|
)
|
||||||
|
row = await cursor.fetchone()
|
||||||
|
source_design = (
|
||||||
|
await get_project_standard_cross_section(connection, int(row[0]), project_id)
|
||||||
|
if row
|
||||||
|
else None
|
||||||
|
)
|
||||||
elif LIDAR_ID.fullmatch(drawing_id):
|
elif LIDAR_ID.fullmatch(drawing_id):
|
||||||
# 라이다 계획평면도는 확정 DTM 격자로 음영기복 그림을 만들어 넘긴다.
|
# 라이다 계획평면도는 확정 DTM 격자로 음영기복 그림을 만들어 넘긴다.
|
||||||
context, reason = await load_drainage_context(project_id)
|
context, reason = await load_drainage_context(project_id)
|
||||||
|
|||||||
@@ -47,66 +47,36 @@ from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Sheet import (
|
|||||||
plan_cross_sheets,
|
plan_cross_sheets,
|
||||||
section_block_size,
|
section_block_size,
|
||||||
)
|
)
|
||||||
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Standard import (
|
||||||
|
STANDARD_LABEL,
|
||||||
|
build_standard_cross_drawing,
|
||||||
|
)
|
||||||
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Table import (
|
from B07_DesignDetail.B07_DesignDetail_Engine_Cad_Table import (
|
||||||
QUANTITY_VALUE_KEYS,
|
QUANTITY_VALUE_KEYS,
|
||||||
)
|
)
|
||||||
from B07_DesignDetail.B07_DesignDetail_Engine_Template import add_title_fields
|
from B07_DesignDetail.B07_DesignDetail_Engine_Template import add_title_fields
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
_BASIN_MAX_DISTANCE_M as _BASIN_MAX_DISTANCE_M,
|
|
||||||
)
|
|
||||||
|
|
||||||
# 유역도 배경·파일 입출력 조각은 700줄 제한으로 떼어냈다(2026-09-04).
|
# 유역도 배경·파일 입출력 조각은 700줄 제한으로 떼어냈다(2026-09-04).
|
||||||
# 여기서 그대로 다시 내보내 호출부(`B07_DesignDetail_Router.py`)의 import 경로는 불변이다.
|
# 여기서 그대로 다시 내보내 호출부(`B07_DesignDetail_Router.py`)의 import 경로는 불변이다.
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import ( # noqa: F401
|
||||||
CONTOUR_FILE as CONTOUR_FILE,
|
_BASIN_MAX_DISTANCE_M,
|
||||||
)
|
CONTOUR_FILE,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
LANDUSE_ID,
|
||||||
LANDUSE_ID as LANDUSE_ID,
|
LIDAR_ID,
|
||||||
)
|
PLAN_ID,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
STREAM_FILE,
|
||||||
LIDAR_ID as LIDAR_ID,
|
_basins_crs,
|
||||||
)
|
_clip_segment,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
_geojson_features,
|
||||||
PLAN_ID as PLAN_ID,
|
_geojson_payload,
|
||||||
)
|
_geometry_lines,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
_too_far_from_route,
|
||||||
STREAM_FILE as STREAM_FILE,
|
clip_line_to_box,
|
||||||
)
|
landuse_source,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
lidar_source,
|
||||||
_basins_crs as _basins_crs,
|
plan_source,
|
||||||
)
|
plan_stations,
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
watershed_source,
|
||||||
_clip_segment as _clip_segment,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
_geojson_features as _geojson_features,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
_geojson_payload as _geojson_payload,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
_geometry_lines as _geometry_lines,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
_too_far_from_route as _too_far_from_route,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
clip_line_to_box as clip_line_to_box,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
landuse_source as landuse_source,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
lidar_source as lidar_source,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
plan_source as plan_source,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
plan_stations as plan_stations,
|
|
||||||
)
|
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Basin import (
|
|
||||||
watershed_source as watershed_source,
|
|
||||||
)
|
)
|
||||||
from B07_DesignDetail.B07_DesignDetail_Router_Support_Io import (
|
from B07_DesignDetail.B07_DesignDetail_Router_Support_Io import (
|
||||||
_cross_files,
|
_cross_files,
|
||||||
@@ -132,13 +102,12 @@ _LONG_ID = re.compile(r"^longitudinal(?:_(\d+))?$")
|
|||||||
MASS_HAUL_ID = "mass_haul"
|
MASS_HAUL_ID = "mass_haul"
|
||||||
WATERSHED_ID = "watershed"
|
WATERSHED_ID = "watershed"
|
||||||
COVER_ID = "cover"
|
COVER_ID = "cover"
|
||||||
|
# 표준 횡단면도 — 노선 자료가 아니라 B06 표준 횡단면 설정값으로 그리는 한 장.
|
||||||
|
CROSS_STANDARD_ID = "cross_standard"
|
||||||
|
|
||||||
# 아직 내용을 만들지 않은 도면 — 도각만 실어 연다(2026-09-01 사용자 지시).
|
# 아직 내용을 만들지 않은 도면 — 도각만 실어 연다(2026-09-01 사용자 지시).
|
||||||
# 화면 순서(DRAWING_GROUPS)와 같은 이름을 쓴다.
|
# 화면 순서(DRAWING_GROUPS)와 같은 이름을 쓴다.
|
||||||
BLANK_DRAWINGS: tuple[tuple[str, str], ...] = (
|
BLANK_DRAWINGS: tuple[tuple[str, str], ...] = (("blank_standard", "표준도"),)
|
||||||
("blank_cross_standard", "표준 횡단면도"),
|
|
||||||
("blank_standard", "표준도"),
|
|
||||||
)
|
|
||||||
BLANK_LABELS: dict[str, str] = dict(BLANK_DRAWINGS)
|
BLANK_LABELS: dict[str, str] = dict(BLANK_DRAWINGS)
|
||||||
|
|
||||||
|
|
||||||
@@ -224,6 +193,7 @@ def _drawing_list(
|
|||||||
# 노선 전장 1장짜리 도면 — 자료가 없으면 여는 시점에 404로 알린다(목록에는 항상 둔다).
|
# 노선 전장 1장짜리 도면 — 자료가 없으면 여는 시점에 404로 알린다(목록에는 항상 둔다).
|
||||||
for drawing_id, kind, label in (
|
for drawing_id, kind, label in (
|
||||||
(COVER_ID, "cover", "표지"),
|
(COVER_ID, "cover", "표지"),
|
||||||
|
(CROSS_STANDARD_ID, "cross_standard", STANDARD_LABEL),
|
||||||
(MASS_HAUL_ID, "mass_haul", "토적도(유토곡선)"),
|
(MASS_HAUL_ID, "mass_haul", "토적도(유토곡선)"),
|
||||||
(WATERSHED_ID, "watershed", "유역도(배수 유역도)"),
|
(WATERSHED_ID, "watershed", "유역도(배수 유역도)"),
|
||||||
):
|
):
|
||||||
@@ -449,7 +419,7 @@ def _read_drawing(
|
|||||||
# 포맷 버전이 다르면(테이블·레이어 구성 변경 전 저장본) 캐시를 버리고
|
# 포맷 버전이 다르면(테이블·레이어 구성 변경 전 저장본) 캐시를 버리고
|
||||||
# 아래에서 원본 기준으로 재생성한다. 확정 상태도 무효로 응답해 재확정 유도.
|
# 아래에서 원본 기준으로 재생성한다. 확정 상태도 무효로 응답해 재확정 유도.
|
||||||
if saved.get("format") == DRAWING_FORMAT:
|
if saved.get("format") == DRAWING_FORMAT:
|
||||||
if drawing_id in (COVER_ID, MASS_HAUL_ID, WATERSHED_ID):
|
if drawing_id in (COVER_ID, MASS_HAUL_ID, WATERSHED_ID, CROSS_STANDARD_ID):
|
||||||
kind = drawing_id # id와 kind가 같은 단장 도면
|
kind = drawing_id # id와 kind가 같은 단장 도면
|
||||||
elif PLAN_ID.fullmatch(drawing_id):
|
elif PLAN_ID.fullmatch(drawing_id):
|
||||||
kind = "plan"
|
kind = "plan"
|
||||||
@@ -485,6 +455,17 @@ def _read_drawing(
|
|||||||
None,
|
None,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if drawing_id == CROSS_STANDARD_ID:
|
||||||
|
# stored_design = B06 표준 횡단면 설정값(라우터가 실어 준다). 없으면 config 기본값.
|
||||||
|
standard = stored_design if isinstance(stored_design, dict) else None
|
||||||
|
return (
|
||||||
|
"cross_standard",
|
||||||
|
STANDARD_LABEL,
|
||||||
|
build_standard_cross_drawing(drawing_id, STANDARD_LABEL, standard),
|
||||||
|
False,
|
||||||
|
None,
|
||||||
|
)
|
||||||
|
|
||||||
if LIDAR_ID.fullmatch(drawing_id):
|
if LIDAR_ID.fullmatch(drawing_id):
|
||||||
# stored_design = lidar_source()가 만든 노선 + 지표면 음영기복 그림.
|
# stored_design = lidar_source()가 만든 노선 + 지표면 음영기복 그림.
|
||||||
if not isinstance(stored_design, dict):
|
if not isinstance(stored_design, dict):
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ class DesignDrawingItem(BaseModel):
|
|||||||
"plan",
|
"plan",
|
||||||
"landuse",
|
"landuse",
|
||||||
"plan_lidar",
|
"plan_lidar",
|
||||||
|
"cross_standard",
|
||||||
"blank",
|
"blank",
|
||||||
]
|
]
|
||||||
label: str
|
label: str
|
||||||
@@ -52,6 +53,7 @@ class DesignDrawingResponse(BaseModel):
|
|||||||
"plan",
|
"plan",
|
||||||
"landuse",
|
"landuse",
|
||||||
"plan_lidar",
|
"plan_lidar",
|
||||||
|
"cross_standard",
|
||||||
"blank",
|
"blank",
|
||||||
]
|
]
|
||||||
label: str
|
label: str
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const DRAWING_GROUPS: readonly {
|
|||||||
{ label: "계획평면도(배치도)", idPrefix: "plan_layout" },
|
{ label: "계획평면도(배치도)", idPrefix: "plan_layout" },
|
||||||
{ label: "계획평면도(라이다)", idPrefix: "plan_lidar" },
|
{ label: "계획평면도(라이다)", idPrefix: "plan_lidar" },
|
||||||
{ label: "종단면도", kind: "longitudinal" },
|
{ label: "종단면도", kind: "longitudinal" },
|
||||||
{ label: "표준 횡단면도", blankId: "blank_cross_standard" },
|
{ label: "표준 횡단면도", kind: "cross_standard" },
|
||||||
{ label: "횡단면도", kind: "cross" },
|
{ label: "횡단면도", kind: "cross" },
|
||||||
{ label: "토적도(유토곡선)", kind: "mass_haul" },
|
{ label: "토적도(유토곡선)", kind: "mass_haul" },
|
||||||
{ label: "유역도(배수 유역도)", kind: "watershed" },
|
{ label: "유역도(배수 유역도)", kind: "watershed" },
|
||||||
|
|||||||
@@ -178,6 +178,10 @@ DRAWING_SCALE_BASIN = 6000 # 유역도 평면 축척 분모 (실거리 1 m = 1/
|
|||||||
# 계획평면도·용지도 평면 축척 분모 — 지식DB 「설계제원_총괄」 측량·도면 기준 1/1,200.
|
# 계획평면도·용지도 평면 축척 분모 — 지식DB 「설계제원_총괄」 측량·도면 기준 1/1,200.
|
||||||
# 횡단면도와 같은 원칙: 축척은 줄이지 않고, 한 장에 안 들어가면 **장을 나눈다**.
|
# 횡단면도와 같은 원칙: 축척은 줄이지 않고, 한 장에 안 들어가면 **장을 나눈다**.
|
||||||
DRAWING_SCALE_PLAN = 1200
|
DRAWING_SCALE_PLAN = 1200
|
||||||
|
# 표준 횡단면도 — 상세도라 지식DB에 지정 축척이 없다. 본 그림 1/50, 측구 부분확대도
|
||||||
|
# 1/10 (2026-09-04). 노폭 4 m 기준 본 그림이 A1 작도영역에 여유 있게 든다.
|
||||||
|
DRAWING_SCALE_CROSS_STANDARD = 50
|
||||||
|
DRAWING_SCALE_DITCH_DETAIL = 10
|
||||||
|
|
||||||
# 시스템 리소스 로그 (루트 log 폴더에 단일 파일, 1개월 보관)
|
# 시스템 리소스 로그 (루트 log 폴더에 단일 파일, 1개월 보관)
|
||||||
LOG_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "log")
|
LOG_BASE_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "log")
|
||||||
|
|||||||
Reference in New Issue
Block a user