- B05_Profile_Engine._route_geojson x · y 3 → 4자리(z 3자리 그대로) · 짝 머리 표시 - draftLine 그린 선 x · y 4자리 · 곡선 start · apex · end 4자리 · R 3자리(= RouteCurve.as_dict) · 파이썬 round 짝(toFixed) - 교점 끌기 재현 브라우저 ↔ 서버 차 0.81 → 0.00 ㎥ · 옹벽 + 추가 측점 0.88 → 0.00 ㎥(test_475_1_route_digits) - 472-1 헬퍼 — 옮김 인자 · 페이지 배선(stationsAt · storedPvi) · 단면 모양 = 따라간 구조물(헛 차 덤 고침) · golden 값 그대로 - 옛 시험 두 곳(346_1) — 안 깎은 선 단언 → 서버 저장 자리 단언 - 관 지문 허용오차 주석 · calculations R1 줄 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
179 lines
8.0 KiB
Python
179 lines
8.0 KiB
Python
"""475-1 헬퍼 — 노선 저장 체인(DB 없이) · 노드 하나 옮긴 초안 → 서버 정본 값.
|
|
|
|
`helper_472_1_paths.server_route` 꼴에 노선 바뀜 갈래를 더함 —
|
|
`_write_planned_polyline`(csv 4자리 · 곡선표) → 노선 geojson(`_route_geojson`) → 관 따라감 ·
|
|
구조물 따라감 · 추가 측점 → `run_section_generation` → `_carry_profile`(옛 · 새 계획 폴리라인 ·
|
|
`carry_base` · `seat_route_moved`) → `_carry_cross` →
|
|
상세 읽기 → `_save_tail`. 짝 = `helper_472_1_browser.mjs` 옮김 인자 · `test_475_1_route_digits.py`.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
from typing import Any
|
|
|
|
import helper_472_1_paths as P
|
|
|
|
|
|
def server_moved(root: Path, move: dict[str, Any]) -> dict[str, Any]:
|
|
from B05_Profile.B05_Profile_Engine import _route_geojson
|
|
from B05_Profile.B05_Profile_Engine_AsPlanned import _vertex_z
|
|
from B05_Profile.B05_Profile_Engine_Grade import GradeDesignOptions
|
|
from B05_Profile.B05_Profile_Engine_Grade_Carry import (
|
|
carry_base,
|
|
carry_edits,
|
|
carry_policy,
|
|
changed_span,
|
|
)
|
|
from B05_Profile.B05_Profile_Engine_Sections import run_section_generation
|
|
from B05_Profile.B05_Profile_Engine_Sections_Core import SectionGenerationOptions
|
|
from B05_Profile.B05_Profile_Plus_Stations import save_plus_stations
|
|
from B05_Profile.B05_Profile_Route_Save_Parts import (
|
|
carry_cross_inputs,
|
|
follow_pipes,
|
|
route_moved_stations,
|
|
seat_route_moved,
|
|
station_keys,
|
|
vertices_of,
|
|
)
|
|
from B05_Profile.B05_Profile_Router import _apply_alignment_edits
|
|
from B05_Profile.B05_Profile_Router_Replan import _vertices_of, _write_planned_polyline
|
|
from B05_Profile.B05_Profile_Structures_Repository import load_structures
|
|
from B05_Profile.B05_Profile_Structures_Router import follow_structures_to_route
|
|
from B06_Section.B06_Section_Engine_Design import ROUTE_CARRY_KEYS
|
|
from B06_Section.B06_Section_Router import _read_section_detail
|
|
from B06_Section.B06_Section_Router_Confirm import _rowless_station_chainages
|
|
from B06_Section.B06_Section_Router_Design import (
|
|
CARRY_INPUT_KEYS,
|
|
STRUCTURE_ADJUST_KEYS,
|
|
attach_default_designs,
|
|
compute_default_designs,
|
|
)
|
|
from common_util.common_util_drainage_pipes import (
|
|
pipe_points_path_in,
|
|
read_pipe_points_file,
|
|
route_signature,
|
|
)
|
|
from common_util.common_util_json import atomic_write_json
|
|
from common_util.common_util_route_geometry import (
|
|
planned_route_initial_path,
|
|
planned_route_working_path,
|
|
)
|
|
|
|
saved = P.read("detail.json")
|
|
summary = P.read("summary.json")["longitudinal"]["data"]
|
|
options = {k: v for k, v in summary["options"].items() if k != "extra_stations"}
|
|
old_line = _vertices_of(planned_route_working_path(root)) or _vertices_of(
|
|
planned_route_initial_path(root)
|
|
)
|
|
old_geo = [
|
|
[c[0], c[1]]
|
|
for c in json.loads((root / P.ROUTE).read_text(encoding="utf-8"))["geometry"]["coordinates"]
|
|
]
|
|
old_pipes = read_pipe_points_file(pipe_points_path_in(root))
|
|
if move.get("structures"):
|
|
atomic_write_json(
|
|
root / "B05_Profile" / "route" / "structures.json",
|
|
{"revision": 1, "structures": move["structures"], "definition_version": None},
|
|
)
|
|
old_structures = load_structures(str(root))[1]
|
|
# 노선 저장 = 초안 노드 그대로(브라우저 `flattenServerPlan` 초안 · 헬퍼 출력 draft_nodes)
|
|
draft = move["draft"]
|
|
working = planned_route_working_path(root)
|
|
_write_planned_polyline(
|
|
working,
|
|
[tuple(n) for n in draft["nodes"]],
|
|
12.0,
|
|
simplify=False,
|
|
curve_flags=list(draft["curveOn"]),
|
|
radii=list(draft["curveRadius"]),
|
|
station_snap=draft["stationSnap"],
|
|
station_snap_step=draft["stationSnapStep"],
|
|
locks=list(draft["curveLock"]),
|
|
arcs=list(draft["curveArc"]),
|
|
)
|
|
points = _vertices_of(working)
|
|
if move.get("structures"):
|
|
follow_structures_to_route(root, P.ROUTE, [{"x": x, "y": y} for x, y in points])
|
|
z = _vertex_z(root, "classification", "dtm", True, [tuple(p) for p in points])
|
|
atomic_write_json(root / P.ROUTE, _route_geojson([[x, y, h] for (x, y), h in zip(points, z)]))
|
|
verts = vertices_of(points)
|
|
pairs = follow_pipes(old_pipes, verts)
|
|
doc = json.loads(pipe_points_path_in(root).read_text(encoding="utf-8"))
|
|
doc["route_signature"] = route_signature(verts)
|
|
doc["points"] = [p.as_dict() for _, p in pairs]
|
|
atomic_write_json(pipe_points_path_in(root), doc)
|
|
if move.get("plus"):
|
|
save_plus_stations(root, move["plus"], points)
|
|
run_section_generation(
|
|
root,
|
|
P.ROUTE,
|
|
*P.SURFACE,
|
|
options=SectionGenerationOptions(**options),
|
|
grade_options=GradeDesignOptions(**summary["grade_options"]),
|
|
crs=f"EPSG:{P.read('context.json')['crs_epsg']}",
|
|
)
|
|
# _carry_profile — 옛 · 새 계획 폴리라인
|
|
old_alignment = saved["longitudinal"]["profile_alignment"]
|
|
longitudinal = json.loads((root / P.LONG).read_text(encoding="utf-8"))
|
|
alignment = longitudinal.get("profile_alignment") or {}
|
|
span = changed_span([tuple(p) for p in old_line], [tuple(p) for p in points])
|
|
if span is None:
|
|
base, edits = old_alignment["base_pvi"], old_alignment.get("edits") or {}
|
|
else:
|
|
stations = [float(r["chainage_m"]) for r in longitudinal.get("stations") or []]
|
|
half = float((alignment.get("policy") or {}).get("station_interval_m") or 20.0) / 2
|
|
base = carry_base(old_line, points, old_alignment["base_pvi"], alignment["base_pvi"])
|
|
edits = carry_edits(
|
|
old_line, points, old_alignment["base_pvi"], old_alignment.get("edits"), stations, half
|
|
)
|
|
alignment["policy"] = carry_policy(old_line, points, old_alignment, alignment)
|
|
alignment["base_pvi"] = base
|
|
if span is not None:
|
|
born = route_moved_stations(longitudinal.get("stations") or [], old_line, points)
|
|
held = [float(k) for k in (edits.get("station_offsets") or {})]
|
|
alignment["base_pvi"] = seat_route_moved(alignment, born, held)
|
|
longitudinal["profile_alignment"] = alignment
|
|
atomic_write_json(root / P.LONG, longitudinal)
|
|
alignment, _s, _d = _apply_alignment_edits(root, P.LONG, edits)
|
|
# _carry_cross
|
|
new_long = json.loads((root / P.LONG).read_text(encoding="utf-8"))
|
|
_, structures = load_structures(str(root))
|
|
interval = float(options["station_interval_m"])
|
|
old_keys = station_keys(
|
|
saved["longitudinal"]["stations"],
|
|
[p for _, p in follow_pipes(old_pipes, vertices_of(old_geo))],
|
|
old_structures,
|
|
interval,
|
|
)
|
|
new_keys = station_keys(
|
|
new_long.get("stations") or [], [p for _, p in pairs], structures, interval
|
|
)
|
|
designs = {
|
|
round(float(s["chainage_m"]), 3): s["design"]
|
|
for s in saved["cross_sections"]
|
|
if isinstance(s.get("design"), dict)
|
|
}
|
|
inputs, adjusts, _dropped = carry_cross_inputs(
|
|
old_keys, new_keys, designs, (*CARRY_INPUT_KEYS, *ROUTE_CARRY_KEYS), STRUCTURE_ADJUST_KEYS
|
|
)
|
|
chainages = _rowless_station_chainages(root, P.LONG, [])
|
|
entries = compute_default_designs(root, P.LONG, chainages, None, inputs)
|
|
by_m = {round(at, 3): {**d, **adjusts.get(round(at, 3), {})} for at, d in entries}
|
|
detail = _read_section_detail(root, P.LONG, P.ROUTE)
|
|
for section in detail["cross_sections"]:
|
|
hit = next(
|
|
(d for at, d in by_m.items() if abs(at - float(section["chainage_m"])) < 0.01), None
|
|
)
|
|
if hit is not None:
|
|
section["design"] = hit
|
|
attach_default_designs(detail["longitudinal"], detail["cross_sections"], root, None)
|
|
keys = P._keys(detail["longitudinal"], detail["cross_sections"], root)
|
|
sections, haul = P._save_tail(detail, root)
|
|
out = P.values_of(
|
|
sections, keys, haul, alignment.get("warnings") or [], alignment.get("violations") or []
|
|
)
|
|
out["route_line"] = [list(p) for p in points]
|
|
return out
|