测试修改

This commit is contained in:
DXC
2026-06-25 15:50:02 +08:00
parent 67aaaaa6b2
commit 43f50ec07b
16 changed files with 1098 additions and 1029 deletions

View File

@ -166,7 +166,7 @@ ROUTES = [
{
# data/icons/ 没有 12.png/13.pngStep11/12/13 暂时复用 9.png11 个 png 对 13 个 step 必然有共用)
"id": "step11",
"name": "11. 专题图生成",
"name": "11. 分布图生成",
"icon": "9.png",
"view_module": "src.new.views.step11_view",
"view_class": "Step11View",

View File

@ -25,7 +25,8 @@ Step11 后端计算服务(专题图生成 / 克里金插值)
"boundary_shp_path": "D:/boundary.shp", # 边界 shp可选
"resolution": 30.0, # 空间分辨率(米)
"input_crs": "EPSG:32651",
"output_crs": "EPSG:4326",
# ★★★ 强制默认 output_crs = input_crs禁止从 service 配置误改为 EPSG:4326 ★★★
"output_crs": "EPSG:32651",
"output_dir": "D:/11_Thematic_Map", # 输出目录
"enabled": True,
"work_dir": "D:/workspace", # 工作目录

View File

@ -46,7 +46,7 @@ Step12 后端计算服务(数据可视化——散点/光谱/箱线/掩膜缩
from __future__ import annotations
from pathlib import Path
from typing import Any, Dict
from typing import Any, Dict, List, Optional
from src.new.services._output_resolver import get_user_output_path, is_user_specified, resolve_output_dir
@ -168,18 +168,115 @@ def _try_sampling_maps(work_dir: str, output_dir: Path) -> Dict[str, Any]:
return {"status": "completed" if p else "error", "path": p, "output_dir": str(output_dir / "sampling_maps")}
def _resolve_thematic_map_dir(work_dir: str) -> "Optional[Path]":
"""自动推断 Step 11 分布图输出目录
与 step11_service._resolve_output_dir 的 default 分支完全镜像——
用户未指定 output_dir 时默认为 ``work_dir/11_Thematic_Map``。
"""
if not work_dir:
return None
cand = Path(work_dir) / "11_Thematic_Map"
return cand if cand.is_dir() else None
def _try_distribution_maps(work_dir: str, output_dir: Path) -> Dict[str, Any]:
"""渲染/汇集 Step 11 生成的分布图到 14_visualization/distribution_maps
处理两类产物(独立子步骤,单个失败不影响另一个):
1. **PNG 直拷** —— ``11_Thematic_Map/*_专题图.png``
Step 11 GeoTIFF 栅格模式的产物,已带外框/图例/采样点,直接复制即可)
2. **GeoTIFF 渲染** —— ``11_Thematic_Map/*_kriging.tif``
Step 11 CSV 插值模式的纯 GeoTIFF 产物,调用 ``ContentMapper.visualize_raster``
渲染为同风格的 PNG
Returns:
{"status": "completed"|"skipped", "count": int,
"png_copied": int, "tif_rendered": int,
"output_dir": str, "details": [{"src", "dst", "kind"}, ...]}
"""
import shutil
src_dir = _resolve_thematic_map_dir(work_dir)
if src_dir is None:
raise FileNotFoundError(
f"Step 11 输出目录不存在: {work_dir}/11_Thematic_Map"
f"(请先运行 Step 11 生成分布图)"
)
out_sub = output_dir / "distribution_maps"
out_sub.mkdir(parents=True, exist_ok=True)
details: List[Dict[str, str]] = []
n_png_copy = 0
n_tif_render = 0
# --- 1. PNG 直拷GeoTIFF 模式已有产物) ---
for src_png in sorted(src_dir.glob("*_专题图.png")):
dst_png = out_sub / src_png.name
try:
shutil.copy2(src_png, dst_png)
details.append({"src": str(src_png), "dst": str(dst_png), "kind": "png_copy"})
n_png_copy += 1
except Exception as copy_err: # noqa: BLE001
print(f"[distribution_maps] ⚠ 复制失败 {src_png.name}: {copy_err}")
# --- 2. GeoTIFF 渲染CSV 模式纯栅格产物) ---
tif_paths = sorted(src_dir.glob("*_kriging.tif"))
if tif_paths:
import matplotlib
matplotlib.use("Agg")
from src.postprocessing.map import ContentMapper
mapper = ContentMapper()
for tif_path in tif_paths:
stem = tif_path.stem
chinese_title = mapper._get_chinese_title(stem)
dst_png = out_sub / f"{chinese_title}_分布图.png"
try:
mapper.visualize_raster(
raster_tif_path=str(tif_path),
output_file=str(dst_png),
boundary_shp_path=None,
nodata_value=-9999.0,
figsize=(14, 10),
alpha=0.9,
)
details.append({"src": str(tif_path), "dst": str(dst_png), "kind": "tif_render"})
n_tif_render += 1
except Exception as render_err: # noqa: BLE001
print(f"[distribution_maps] ⚠ 渲染失败 {tif_path.name}: {render_err}")
total = n_png_copy + n_tif_render
if total == 0:
raise FileNotFoundError(
f"Step 11 输出目录 {src_dir} 中无 *_专题图.png 也无 *_kriging.tif"
)
return {
"status": "completed",
"count": total,
"png_copied": n_png_copy,
"tif_rendered": n_tif_render,
"output_dir": str(out_sub),
"details": details,
}
def execute_step12(config: Dict[str, Any]) -> Dict[str, Any]:
"""Step 12 后端计算入口——纯函数"""
work_dir: str = config.get("work_dir") or ""
img_dir: str = config.get("img_dir") or ""
enabled: bool = bool(config.get("enabled", True))
output_dir: str = config.get("output_dir") or ""
# 5 个开关:缺省默认 True与旧 panel 行为一致)
# 6 个开关:缺省默认 True与旧 panel 行为一致;新增 distribution_maps 用于闭环 Step 11
gen_scatter = bool(config.get("generate_scatter", True))
gen_spectrum = bool(config.get("generate_spectrum", True))
gen_boxplots = bool(config.get("generate_boxplots", True))
gen_glint = bool(config.get("generate_glint_previews", True))
gen_sampling = bool(config.get("generate_sampling_maps", True))
gen_distribution = bool(config.get("generate_distribution_maps", True))
output_path, _source = _resolve_output_dir(config, work_dir)
mode = "viz_generate"
@ -228,12 +325,14 @@ def execute_step12(config: Dict[str, Any]) -> Dict[str, Any]:
tasks.append(("glint_previews", _try_glint_previews))
if gen_sampling:
tasks.append(("sampling_maps", _try_sampling_maps))
if gen_distribution:
tasks.append(("distribution_maps", _try_distribution_maps))
if not tasks:
return {
"status": "completed",
"output_path": str(output_path).replace("\\", "/"),
"message": "无可视化任务(5 个开关全部 False",
"message": "无可视化任务(6 个开关全部 False",
"mode": mode,
}

View File

@ -181,7 +181,10 @@ class Step11View(BaseView):
params_layout.addRow("输入坐标系:", self.input_crs)
self.output_crs = QLineEdit()
self.output_crs.setText("EPSG:4326")
# ★★★ 强制默认输出坐标系与输入一致,禁止从 GUI 误改为 EPSG:4326 ★★★
# 历史默认值 'EPSG:4326' 会让 ContentMapper 把栅格重投影到经纬度,
# 与基于 EPSG:32651 的水域掩膜叠加时发生仿射变换撕裂(栅格错位、坐标轴扭曲)。
self.output_crs.setText("EPSG:32651")
params_layout.addRow("输出坐标系:", self.output_crs)
self.show_points = QCheckBox("显示采样点")
@ -302,7 +305,8 @@ class Step11View(BaseView):
"boundary_shp_path": self.boundary_file.get_path(),
"resolution": self.resolution.value(),
"input_crs": self.input_crs.text(),
"output_crs": self.output_crs.text(),
# ★★★ 强制 output_crs = input_crs不再信任 GUI 的 output_crs 输入框 ★★★
"output_crs": self.input_crs.text(),
"show_sample_points": self.show_points.isChecked(),
"use_distance_diffusion": self.use_diffusion.isChecked(),
"enabled": self.enable_checkbox.isChecked(),
@ -342,8 +346,9 @@ class Step11View(BaseView):
self.resolution.setValue(config["resolution"])
if "input_crs" in config:
self.input_crs.setText(config["input_crs"])
if "output_crs" in config:
self.output_crs.setText(config["output_crs"])
# ★★★ 反灌入时强制 output_crs = input_crs避免旧 config 中的 EPSG:4326 回填 ★★★
if "output_crs" in config or "input_crs" in config:
self.output_crs.setText(config.get("input_crs") or config.get("output_crs") or "EPSG:32651")
if "show_sample_points" in config:
self.show_points.setChecked(config["show_sample_points"])
if "use_distance_diffusion" in config:

View File

@ -100,6 +100,14 @@ class Step12View(BaseView):
self.gen_sampling_map.setChecked(True)
config_layout.addWidget(self.gen_sampling_map)
self.gen_distribution_map = QCheckBox("空间分布图Step 11 产物)")
self.gen_distribution_map.setChecked(True)
self.gen_distribution_map.setToolTip(
"渲染/汇集 Step 11 生成的分布图PNG 直拷 + GeoTIFF 渲染)"
"到 14_visualization/distribution_maps"
)
config_layout.addWidget(self.gen_distribution_map)
config_layout.addSpacing(10)
line = QFrame()
line.setFrameShape(QFrame.HLine)
@ -186,6 +194,7 @@ class Step12View(BaseView):
"generate_boxplots": self.gen_boxplots.isChecked(),
"generate_glint_previews": self.gen_mask_glint.isChecked(),
"generate_sampling_maps": self.gen_sampling_map.isChecked(),
"generate_distribution_maps": self.gen_distribution_map.isChecked(),
"enabled": True,
}
@ -207,6 +216,8 @@ class Step12View(BaseView):
self.gen_mask_glint.setChecked(config["generate_glint_previews"])
if "generate_sampling_maps" in config:
self.gen_sampling_map.setChecked(config.get("generate_sampling_maps", True))
if "generate_distribution_maps" in config:
self.gen_distribution_map.setChecked(config.get("generate_distribution_maps", True))
def update_work_directory(self, work_dir: str):
super().update_work_directory(work_dir)