geopro/src/data/repo/LocalSample3dRepository.cpp

221 lines
9.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "repo/LocalSample3dRepository.hpp"
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <exception>
#include <limits>
#include <utility>
#include <vector>
#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<void(VolumeGrid, geopro::core::ColorScale)> onOk, OnError onErr) {
// P1 样本dsId 暂未使用,固定读同一组交叉剖面散点→体素(真实 Api 实现按 dsId 取)。
try {
// 1) 读两条交叉剖面散点 + 色阶;配准到世界局部米 + 深度,组装 IDW 输入点集。
const std::vector<ScatterField> 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<double> 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<void(SectionData)> 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<void(MapLine)> 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<void(TerrainPaths)> 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());
}
}
// ── 切片 CRUDspec §6.3 内存态 stub───────────────────────────────────────
void LocalSample3dRepository::createSlice(const SliceSpec& spec, const std::string& /*name*/,
std::function<void(std::string)> 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<void()> onOk, OnError /*onErr*/) {
slices_[dsId] = spec;
onOk();
}
void LocalSample3dRepository::deleteSlice(const std::string& dsId,
std::function<void()> onOk, OnError /*onErr*/) {
slices_.erase(dsId);
onOk();
}
// ── 异常 / 异常体spec §6.4 内存态 stub──────────────────────────────────
void LocalSample3dRepository::loadAnomalyTree(const std::string& /*objectId*/,
std::function<void(AnomalyTree)> onOk,
OnError /*onErr*/) {
onOk(AnomalyTree{}); // stub: 空树(无样本异常)
}
void LocalSample3dRepository::saveAnomaly(const geopro::core::Anomaly& a,
const std::string& /*screenshotPngPath*/,
std::function<void(std::string)> 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<void()> onOk, OnError /*onErr*/) {
anomalies_.erase(anomalyId);
onOk();
}
void LocalSample3dRepository::deleteAnomalyGroup(const std::string& /*bodyId*/,
std::function<void()> onOk, OnError /*onErr*/) {
// stub: 内存态无 AnomalyBody 存储bodyId 仅逻辑分组,真实 backend 实现时才有)
onOk();
}
// ── 任务管理spec §6.5 内存态 stub────────────────────────────────────────
void LocalSample3dRepository::loadTaskRecords(const std::string& /*dsId*/,
std::function<void(std::vector<TaskRecord>)> onOk,
OnError /*onErr*/) {
onOk({}); // stub: 无样本任务记录
}
void LocalSample3dRepository::loadUsableTasks(const std::string& /*ddCode*/,
std::function<void(std::vector<UsableTask>)> onOk,
OnError /*onErr*/) {
onOk({}); // stub: 空列表(真实实现按 ddCode 过滤 model/list 返回)
}
} // namespace geopro::data