Merge remote-tracking branch 'origin/main_desktop_1' into sub_desktop_1
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
두 화면이 같은 관 목록과 같은 세부유역을 보여 주려면 **입력이 한 글자도 달라선 안 된다**
|
||||
(2026-08-01 사용자 지시). 그래서 노선·종단 Z·좌표계를 여기 한 곳에서 만들어 양쪽에 넘긴다.
|
||||
|
||||
노선 기준선은 B05가 푼 최적 경로가 아니라 **B03이 업로드한 원청 계획노선 CSV**다. B04 격자
|
||||
노선 기준선은 B05가 푼 최적 경로가 아니라 **B03이 받은 원청 계획노선(정본)**이다. B04 격자
|
||||
해석이 그 노선으로 도로 셀을 구웠으므로, 다른 노선의 누가거리를 쓰면 도로 셀과 관 위치가
|
||||
어긋난다. 종단 Z만 상황에 따라 갈아 끼운다 → [[common_util_route_profile]].
|
||||
"""
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
종단 Z가 달라지지만 관이 놓인 자리는 그대로여야 하고, 그때는 세부유역만 다시 나누면 된다.
|
||||
|
||||
좌표를 같이 남기는 이유(2026-08-30 사용자 지적 — "결국 노선 위에 위치해야 한다"): 관 자리를
|
||||
정한 선(계획노선 CSV)과 화면에 그려지는 선(B05 최적 경로)은 **같은 자리를 지나면서 연장이
|
||||
정한 선(계획노선 정본)과 화면에 그려지는 선(B05 최적 경로)은 **같은 자리를 지나면서 연장이
|
||||
다르다**(실측 350.11m vs 354.83m). 누가거리만 남기면 읽는 쪽이 쥔 선에 따라 같은 값이 3~4m
|
||||
미끄러져 관이 선 옆에 떨어진 것처럼 보인다. 좌표를 남겨 두면 어느 선으로 읽든 그 좌표를
|
||||
투영해 **항상 선 위에** 앉힐 수 있다.
|
||||
@@ -416,7 +416,7 @@ def save_detail_basins(stored_path: str, features: list[dict[str, Any]], crs: st
|
||||
"""세부유역을 GeoJSON으로 남긴다(파생물 — 관 지점만 있으면 언제든 다시 만든다).
|
||||
|
||||
`crs`는 좌표를 WGS84로 바꿀 때 쓴 **사업지 좌표계**다. 되읽는 쪽(B07 유역도)이 같은
|
||||
좌표계로 되돌려야 하는데, 예전에는 이 값을 안 남겨 노선 CSV의 EPSG 라벨로 되돌렸다
|
||||
좌표계로 되돌려야 하는데, 예전에는 이 값을 안 남겨 노선 정본의 EPSG 라벨로 되돌렸다
|
||||
(2026-09-01: 라벨과 실좌표계가 갈린 프로젝트에서 유역이 딴 자리로 갔다).
|
||||
"""
|
||||
path = detail_basins_path(stored_path)
|
||||
|
||||
@@ -213,7 +213,9 @@ def find_planned_route_file(input_dir: Path) -> Path | None:
|
||||
|
||||
|
||||
def load_design_route(
|
||||
project_root: Path, surface_params: dict[str, Any] | None = None
|
||||
project_root: Path,
|
||||
surface_params: dict[str, Any] | None = None,
|
||||
route_range: tuple[float | None, float | None] | None = None,
|
||||
) -> PlannedRoute | None:
|
||||
"""설계가 쓸 계획노선 한 벌을 만든다 — 읽기·좌표계 변환·트림·조밀화를 여기서 끝낸다.
|
||||
|
||||
@@ -225,6 +227,9 @@ def load_design_route(
|
||||
`surface_params`(확정 필터·방식·스무딩)를 주면 지표면이 덮지 못하는 구간을 잘라 내고,
|
||||
B05 격자 탐색이 계획노선을 바꾸지 않도록 정점 간격을 직결 문턱 아래로 좁힌다.
|
||||
주지 않으면 읽어서 좌표계만 맞춘 원본을 돌려준다.
|
||||
|
||||
`route_range`(시작·종료 누가거리 m)를 주면 **서피스 트림보다 먼저** 그 구간만 남긴다
|
||||
(2026-09-04 사용자 지시). 순서가 바뀌면 사용자가 정한 시점이 서피스 트림에 밀린다.
|
||||
"""
|
||||
from B04_PreProcess.B04_PreProcess_Engine_Extent import project_epsg_from_prj
|
||||
from common_util.common_util_initial_snapshot import design_route_csv_path
|
||||
@@ -264,6 +269,10 @@ def load_design_route(
|
||||
transformer = Transformer.from_crs(source_crs, target_crs, always_xy=True)
|
||||
points = [transformer.transform(x, y) for x, y in points]
|
||||
|
||||
# 사용자가 정한 범위가 먼저다 — 그 다음에 서피스 밖을 깎는다.
|
||||
if route_range:
|
||||
points = clip_route_by_chainage(points, route_range[0], route_range[1])
|
||||
|
||||
if surface_params:
|
||||
from common_util.common_util_surface_sampler import build_surface_sampler
|
||||
|
||||
@@ -311,6 +320,57 @@ def replace_vertices(
|
||||
)
|
||||
|
||||
|
||||
def clip_route_by_chainage(
|
||||
points: list[tuple[float, float]],
|
||||
start_m: float | None,
|
||||
end_m: float | None,
|
||||
) -> list[tuple[float, float]]:
|
||||
"""사용자가 정한 누가거리 구간만 남긴다 (2026-09-04 사용자 지시).
|
||||
|
||||
계획노선 자료가 공사지 전체일 수 있어 **쓸 구간을 사용자가 정한다**(B02 등록 화면).
|
||||
경계는 정점 사이에 떨어질 수 있으므로 그 자리에 점을 하나 만들어 끼운다.
|
||||
둘 다 없으면 원본 그대로. 남는 구간이 2점 미만이면 원본을 돌려준다 — 범위가 자료를
|
||||
벗어난 경우까지 여기서 노선을 지우면 원인을 못 찾는다(판정·안내는 화면·라우터 몫).
|
||||
"""
|
||||
if len(points) < 2 or (start_m is None and end_m is None):
|
||||
return list(points)
|
||||
low = max(0.0, float(start_m)) if start_m is not None else 0.0
|
||||
high = float(end_m) if end_m is not None else float("inf")
|
||||
if high <= low:
|
||||
return list(points)
|
||||
|
||||
clipped: list[tuple[float, float]] = []
|
||||
travelled = 0.0
|
||||
for index in range(1, len(points)):
|
||||
ax, ay = points[index - 1]
|
||||
bx, by = points[index]
|
||||
length = math.dist((ax, ay), (bx, by))
|
||||
if length <= 0.0:
|
||||
continue
|
||||
seg_start, seg_end = travelled, travelled + length
|
||||
travelled = seg_end
|
||||
if seg_end < low or seg_start > high:
|
||||
continue
|
||||
# 이 구간에서 남길 부분의 시작·끝 비율.
|
||||
t0 = max(0.0, (low - seg_start) / length)
|
||||
t1 = min(1.0, (high - seg_start) / length)
|
||||
if t1 <= t0:
|
||||
continue
|
||||
first = (ax + (bx - ax) * t0, ay + (by - ay) * t0)
|
||||
last = (ax + (bx - ax) * t1, ay + (by - ay) * t1)
|
||||
if not clipped:
|
||||
clipped.append(first)
|
||||
clipped.append(last)
|
||||
if len(clipped) < 2:
|
||||
logger.warning(
|
||||
"계획노선 범위 절단: 남는 구간이 없어 전 구간을 씁니다 — 범위 %s~%s m",
|
||||
start_m,
|
||||
end_m,
|
||||
)
|
||||
return list(points)
|
||||
return clipped
|
||||
|
||||
|
||||
def _log_trim_wipeout(points: list[tuple[float, float]], sampler: Any, target_crs: str) -> None:
|
||||
"""트림이 노선을 통째로 지운 이유를 **수치로** 남긴다.
|
||||
|
||||
|
||||
@@ -168,7 +168,16 @@ async def fail_stage(
|
||||
|
||||
|
||||
async def get_workflow_state(cursor: aiomysql.DictCursor, project_id: str) -> Dict[str, Any]:
|
||||
"""프로젝트의 모든 단계 상태를 조회하여 요약 및 배열로 반환한다."""
|
||||
"""프로젝트의 모든 단계 상태를 조회하여 요약 및 배열로 반환한다.
|
||||
|
||||
프로젝트 이름도 함께 싣는다 (2026-09-04 사용자 지시) — B03~B08 좌측 제목 줄 오른쪽에
|
||||
이름을 붙이는데, 화면이 들고 있는 것은 프로젝트 id 뿐이라 여기서 내려 준다. 새로고침·
|
||||
주소 직접 입력으로 들어와도 같은 값이 따라온다.
|
||||
"""
|
||||
await cursor.execute("SELECT name FROM projects WHERE id = %s", (project_id,))
|
||||
name_row = await cursor.fetchone()
|
||||
project_name = name_row["name"] if name_row else None
|
||||
|
||||
await cursor.execute(
|
||||
"""
|
||||
SELECT stage_no, stage_key, state, progress_percent, params, message,
|
||||
@@ -183,7 +192,12 @@ async def get_workflow_state(cursor: aiomysql.DictCursor, project_id: str) -> Di
|
||||
rows = await cursor.fetchall()
|
||||
|
||||
if not rows:
|
||||
return {"project_id": project_id, "current_stage": 0, "stages": []}
|
||||
return {
|
||||
"project_id": project_id,
|
||||
"project_name": project_name,
|
||||
"current_stage": 0,
|
||||
"stages": [],
|
||||
}
|
||||
|
||||
stages_list = []
|
||||
for r in rows:
|
||||
@@ -221,6 +235,7 @@ async def get_workflow_state(cursor: aiomysql.DictCursor, project_id: str) -> Di
|
||||
|
||||
return {
|
||||
"project_id": project_id,
|
||||
"project_name": project_name,
|
||||
"current_stage": current_stage,
|
||||
"stages": stages_list,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user