diff --git a/B06_Section/B06_Section_Router.py b/B06_Section/B06_Section_Router.py index a1963de5a..bf1e7531a 100644 --- a/B06_Section/B06_Section_Router.py +++ b/B06_Section/B06_Section_Router.py @@ -12,7 +12,6 @@ from fastapi import APIRouter, Depends from fastapi.responses import JSONResponse from B03_FileInput.B03_FileInput_Repository import get_project_storage_relative_path -from B05_Profile.B05_Profile_Engine_Grade import GradeDesignOptions, resolve_grade_options from B05_Profile.B05_Profile_Engine_Grade_Profile import rebuild_alignment_profile from B05_Profile.B05_Profile_Engine_Sections import ( prune_stale_cross_files, @@ -59,6 +58,10 @@ from B06_Section.B06_Section_Router_Design import ( from B06_Section.B06_Section_Router_Design import ( stored_standard_cross_section as _stored_standard_cross_section, ) +from B06_Section.B06_Section_Router_Regenerate_Options import ( # noqa: F401 — 시험이 여기서 씀 + _regeneration_grade_options, + _regeneration_options, +) from B06_Section.B06_Section_Schema import ( CompanyStandardListResponse, CompanyStandardProject, @@ -371,67 +374,6 @@ async def get_section_detail( ) -def _regeneration_grade_options(stage_params: dict[str, Any] | None) -> GradeDesignOptions | None: - """재생성 시 종단 계획선 기준을 확정 당시 저장 파라미터(stage 2)로 재구성한다. - - grade_options 없이 재생성하면 종단 계획선(profile_alignment)이 통째로 소실돼 계획 - 횡단도선·유토곡선·테이블이 사라진다(2026-08-06 사용자 보고 — 옛 재계산 버튼 사고의 - 원인). B04 파일입력→B06 자동 계산 파이프라인이 쓰는 같은 엔진 경로를 재활용한다. - """ - if not stage_params: - return None - options = stage_params.get("options") or {} - grade_class = options.get("grade_class") - if not grade_class: - return None - stored = { - key: stage_params.get(key) - for key in ( - "max_grade_pct", - "min_vertical_radius_m", - "min_tangent_length_m", - "balance_segment_length_m", - "start_elevation_offset_m", - "end_elevation_offset_m", - # 횡단배수 최소고 강제 스위치도 확정 당시 값을 따라야 한다 — 빠뜨리면 재생성이 - # 기본(해제)으로 돌아가 켜 둔 계획선이 내려앉는다(2026-09-01). - "enforce_pipe_clearance", - ) - if stage_params.get(key) is not None - } - # 설계속도는 B05가 저장해 둔 값을 그대로 따른다 — 없으면 종류별 기본(20). - speed = options.get("design_speed_kph") - return resolve_grade_options( - str(grade_class), - terrain_type=str(options.get("terrain_type") or "normal"), - paved=bool(options.get("paved", False)), - design_speed_kph=int(speed) if speed is not None else None, - stored=stored, - ) - - -def _regeneration_options( - stored_options: dict[str, Any] | None, - stage_params: dict[str, Any] | None, - cross_half_width_m: float, -) -> SectionGenerationOptions: - """DB 저장 옵션(단일 소스) → stage 2 params → config 순으로 유지하고 반폭만 교체한다.""" - defaults = SectionGenerationOptions() - stored = stored_options or {} - params = stage_params or {} - - def pick(key: str, default: float) -> float: - return stored.get(key) or params.get(key) or default - - return SectionGenerationOptions( - station_interval_m=pick("station_interval_m", defaults.station_interval_m), - cross_half_width_m=cross_half_width_m, - cross_sample_interval_m=pick("cross_sample_interval_m", defaults.cross_sample_interval_m), - long_sample_interval_m=pick("long_sample_interval_m", defaults.long_sample_interval_m), - include_endpoint=defaults.include_endpoint, - ) - - @router.post("/{project_id}/sections/{route_id}/regenerate", response_model=SectionDetailResponse) async def regenerate_sections( project_id: UUID, route_id: int, request: SectionRegenerateRequest diff --git a/B06_Section/B06_Section_Router_Regenerate_Options.py b/B06_Section/B06_Section_Router_Regenerate_Options.py new file mode 100644 index 000000000..f0627caba --- /dev/null +++ b/B06_Section/B06_Section_Router_Regenerate_Options.py @@ -0,0 +1,72 @@ +"""B06 재생성 옵션 — 저장 옵션 · stage 2 파라미터 → 종단 계획선 기준 · 측점 생성 옵션. + +`B06_Section_Router.py` 에서 700줄 제한으로 분리(139-6). 라우터가 그대로 다시 씀. +""" + +from __future__ import annotations + +from typing import Any + +from B05_Profile.B05_Profile_Engine_Grade import GradeDesignOptions, resolve_grade_options +from B05_Profile.B05_Profile_Engine_Sections_Core import SectionGenerationOptions + + +def _regeneration_grade_options(stage_params: dict[str, Any] | None) -> GradeDesignOptions | None: + """재생성 시 종단 계획선 기준을 확정 당시 저장 파라미터(stage 2)로 재구성한다. + + grade_options 없이 재생성하면 종단 계획선(profile_alignment)이 통째로 소실돼 계획 + 횡단도선·유토곡선·테이블이 사라진다(2026-08-06 사용자 보고 — 옛 재계산 버튼 사고의 + 원인). B04 파일입력→B06 자동 계산 파이프라인이 쓰는 같은 엔진 경로를 재활용한다. + """ + if not stage_params: + return None + options = stage_params.get("options") or {} + grade_class = options.get("grade_class") + if not grade_class: + return None + stored = { + key: stage_params.get(key) + for key in ( + "max_grade_pct", + "min_vertical_radius_m", + "min_tangent_length_m", + "balance_segment_length_m", + "start_elevation_offset_m", + "end_elevation_offset_m", + # 횡단배수 최소고 강제 스위치도 확정 당시 값을 따라야 한다 — 빠뜨리면 재생성이 + # 기본(해제)으로 돌아가 켜 둔 계획선이 내려앉는다(2026-09-01). + "enforce_pipe_clearance", + ) + if stage_params.get(key) is not None + } + # 설계속도는 B05가 저장해 둔 값을 그대로 따른다 — 없으면 종류별 기본(20). + speed = options.get("design_speed_kph") + return resolve_grade_options( + str(grade_class), + terrain_type=str(options.get("terrain_type") or "normal"), + paved=bool(options.get("paved", False)), + design_speed_kph=int(speed) if speed is not None else None, + stored=stored, + ) + + +def _regeneration_options( + stored_options: dict[str, Any] | None, + stage_params: dict[str, Any] | None, + cross_half_width_m: float, +) -> SectionGenerationOptions: + """DB 저장 옵션(단일 소스) → stage 2 params → config 순으로 유지하고 반폭만 교체한다.""" + defaults = SectionGenerationOptions() + stored = stored_options or {} + params = stage_params or {} + + def pick(key: str, default: float) -> float: + return stored.get(key) or params.get(key) or default + + return SectionGenerationOptions( + station_interval_m=pick("station_interval_m", defaults.station_interval_m), + cross_half_width_m=cross_half_width_m, + cross_sample_interval_m=pick("cross_sample_interval_m", defaults.cross_sample_interval_m), + long_sample_interval_m=pick("long_sample_interval_m", defaults.long_sample_interval_m), + include_endpoint=defaults.include_endpoint, + )