#include "repo/LocalSample3dRepository.hpp" #include #include #include #include #include #include #include #include "algo/VolumeBuilder.hpp" #include "geo/CrsTransform.hpp" #include "geo/GeoLocalFrame.hpp" #include "model/ColorScale.hpp" #include "model/Field.hpp" #include "repo/LocalSampleRepository.hpp" namespace geopro::data { using geopro::core::ColorScale; using geopro::core::CrsTransform; using geopro::core::GeoLocalFrame; using geopro::core::PointSet; using geopro::core::ScatterField; namespace { // 与 render::VoxelFromScatters 的默认参数同口径(保持渲染/切片纵向一致)。 // 「散点→GridSpec→IDW→ScalarVolume」已提到 core::buildVolume 共享(与 Api3dRepository 同源, // 消除调参漂移);此处仅保留默认参数 + 本地样本配准。 constexpr double kCellXY = 1.0; constexpr double kCellZ = 0.5; constexpr double kPower = 2.0; constexpr double kMaxDist = 4.0; constexpr const char* kWgs84 = "EPSG:4326"; } // namespace LocalSample3dRepository::LocalSample3dRepository(LocalSampleRepository& base, std::string projectCrs, double baseLat, double baseLon) : base_(base), projectCrs_(std::move(projectCrs)), baseLat_(baseLat), baseLon_(baseLon) {} DsDimension LocalSample3dRepository::dimensionOf(const DsRow& ds) const { const std::string& c = ds.ddCode; // 真三维体 / 体素 / 帘面(dd_section/反演剖面摆成竖直帘面)入三维数据集。 if (c == "dd_voxel" || c == "dd_Structual3D" || c == "dd_Property3D" || c == "dd_section" || c == "dd_inversion_data") { return DsDimension::Dim3D; } // 切片:三维分析栏。 if (c == "dd_slice") return DsDimension::Analysis3D; // 足迹型 → 二维数据集。dd_trajectory_data = 统一通用轨迹(数据字典 DD0623「保留」,已并入 // dd_radar_rtk_trajectory);瞬变电磁/雷达通道/RTK 等轨迹型字典均标「删除」,不再单列。 if (c == "dd_trajectory_data") return DsDimension::Dim2D; return DsDimension::Other; } void LocalSample3dRepository::loadVolume( const std::string& /*dsId*/, std::function onOk, OnError onErr) { // P1 样本:dsId 暂未使用,固定读同一组交叉剖面散点→体素(真实 Api 实现按 dsId 取)。 try { // 1) 读两条交叉剖面散点 + 色阶;配准到世界局部米 + 深度,组装 IDW 输入点集。 const std::vector profiles = base_.loadVoxelScatters(); const CrsTransform crs(projectCrs_, kWgs84); const GeoLocalFrame frame(baseLat_, baseLon_); PointSet pts; for (const auto& s : profiles) { const std::size_t n = s.v.size(); if (s.projX.size() < n || s.projY.size() < n || s.y.size() < n) continue; for (std::size_t i = 0; i < n; ++i) { const auto ll = crs.forward(s.projX[i], s.projY[i]); // (lon, lat) const auto local = frame.toLocal(ll.y, ll.x); // (x East, y North) 米 pts.x.push_back(local.x); pts.y.push_back(local.y); pts.z.push_back(-s.y[i]); // 深度向下:z 取负 pts.v.push_back(s.v[i]); } } if (pts.v.empty()) { onErr("LocalSample3dRepository: no voxel points after registration"); return; } // 2) 点集 → GridSpec → IDW → 数据实测值域(共享 core::buildVolume)。 geopro::core::BuiltVolume bv = geopro::core::buildVolume(pts, kCellXY, kCellZ, kPower, kMaxDist); // 3) 值域:优先 colorBar 真实分段值,否则 buildVolume 的数据实测范围。 double vmin = bv.vmin, vmax = bv.vmax; ColorScale cs; try { cs = base_.loadScatterColorScale("grid1"); } catch (const std::exception&) { // 色阶缺失 → 沿用数据实测范围。 } const std::vector stops = cs.stopValues(); if (stops.size() >= 2) { vmin = stops.front(); vmax = stops.back(); } VolumeGrid out{std::move(bv.vol), {{bv.spec.ox, bv.spec.oy, bv.spec.oz}}, {{bv.spec.dx, bv.spec.dy, bv.spec.dz}}, vmin, vmax}; onOk(std::move(out), std::move(cs)); } catch (const std::exception& e) { onErr(std::string("LocalSample3dRepository::loadVolume: ") + e.what()); } } void LocalSample3dRepository::loadSection(const std::string& /*dsId*/, std::function onOk, OnError onErr) { // P1 样本:忽略入参 dsId(本地仅一份样本 grid1);真实 Api 实现走 ERT 反演端点按 dsId 取。 try { SectionData s; s.grid = base_.loadGrid("grid1"); // 样本 dd_section 网格 s.scale = base_.loadColorScale("grid1"); // 对应色阶 onOk(std::move(s)); // 本地同步回调 } catch (const std::exception& e) { onErr(std::string("LocalSample3dRepository::loadSection: ") + e.what()); } } void LocalSample3dRepository::loadMapLine(const std::string& /*dsId*/, std::function onOk, OnError onErr) { // P1 样本:取样本 grid1 的 lat/lon 作为足迹折线(测试/离线用,不依赖网络)。 // 真实 Api 实现走 dd/ert/trajectory/line 端点按 dsId 取经纬。 try { const core::Grid g = base_.loadGrid("grid1"); MapLine line; line.lat = g.lat; // 样本 grid 的测线经纬(与帘面同源 → 同系配准) line.lon = g.lon; if (!line.valid()) { onErr("LocalSample3dRepository::loadMapLine: 样本无有效经纬折线"); return; } onOk(std::move(line)); // 本地同步回调 } catch (const std::exception& e) { onErr(std::string("LocalSample3dRepository::loadMapLine: ") + e.what()); } } void LocalSample3dRepository::loadTerrainPaths(std::function onOk, OnError onErr) { try { TerrainPaths p{base_.demPath(), base_.imagePath()}; onOk(std::move(p)); } catch (const std::exception& e) { onErr(std::string("LocalSample3dRepository::loadTerrainPaths: ") + e.what()); } } // ── 切片 CRUD(spec §6.3 内存态 stub)─────────────────────────────────────── void LocalSample3dRepository::createSlice(const SliceSpec& spec, const std::string& /*name*/, std::function onOk, OnError /*onErr*/) { std::string newId = "slice-" + std::to_string(++sliceCounter_); slices_[newId] = spec; onOk(std::move(newId)); } void LocalSample3dRepository::saveSlice(const std::string& dsId, const SliceSpec& spec, std::function onOk, OnError /*onErr*/) { slices_[dsId] = spec; onOk(); } void LocalSample3dRepository::deleteSlice(const std::string& dsId, std::function onOk, OnError /*onErr*/) { slices_.erase(dsId); onOk(); } // ── 异常 / 异常体(spec §6.4 内存态 stub)────────────────────────────────── void LocalSample3dRepository::loadAnomalyTree(const std::string& /*objectId*/, std::function onOk, OnError /*onErr*/) { onOk(AnomalyTree{}); // stub: 空树(无样本异常) } void LocalSample3dRepository::saveAnomaly(const geopro::core::Anomaly& a, const std::string& /*screenshotPngPath*/, std::function onOk, OnError /*onErr*/) { std::string newId = "anomaly-" + std::to_string(++anomalyCounter_); anomalies_[newId] = a; onOk(std::move(newId)); } void LocalSample3dRepository::deleteAnomaly(const std::string& anomalyId, std::function onOk, OnError /*onErr*/) { anomalies_.erase(anomalyId); onOk(); } void LocalSample3dRepository::deleteAnomalyGroup(const std::string& /*bodyId*/, std::function onOk, OnError /*onErr*/) { // stub: 内存态无 AnomalyBody 存储(bodyId 仅逻辑分组,真实 backend 实现时才有) onOk(); } // ── 任务管理(spec §6.5 内存态 stub)──────────────────────────────────────── void LocalSample3dRepository::loadTaskRecords(const std::string& /*dsId*/, std::function)> onOk, OnError /*onErr*/) { onOk({}); // stub: 无样本任务记录 } void LocalSample3dRepository::loadUsableTasks(const std::string& /*ddCode*/, std::function)> onOk, OnError /*onErr*/) { onOk({}); // stub: 空列表(真实实现按 ddCode 过滤 model/list 返回) } } // namespace geopro::data