From 77f1b5543ef1d1b2d87c5b1298623271c7cc77a7 Mon Sep 17 00:00:00 2001 From: gaozheng Date: Tue, 16 Jun 2026 18:11:21 +0800 Subject: [PATCH] =?UTF-8?q?feat(vtk):=20I3dSceneRepository=20=E8=A1=A5?= =?UTF-8?q?=E9=BD=90=E5=88=87=E7=89=87/=E5=BC=82=E5=B8=B8/=E4=BB=BB?= =?UTF-8?q?=E5=8A=A1=E6=8E=A5=E5=8F=A3=E8=AE=BE=E8=AE=A1(spec=20=C2=A76.3-?= =?UTF-8?q?6.5)+LocalSample=E5=86=85=E5=AD=98=E6=80=81stub?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/data/repo/I3dSceneRepository.hpp | 80 ++++++++++++++++++- src/data/repo/LocalSample3dRepository.cpp | 65 +++++++++++++++ src/data/repo/LocalSample3dRepository.hpp | 35 ++++++++ .../controller/test_vtk_scene_controller.cpp | 20 +++++ 4 files changed, 199 insertions(+), 1 deletion(-) diff --git a/src/data/repo/I3dSceneRepository.hpp b/src/data/repo/I3dSceneRepository.hpp index 9054aeb..dd26f81 100644 --- a/src/data/repo/I3dSceneRepository.hpp +++ b/src/data/repo/I3dSceneRepository.hpp @@ -1,8 +1,11 @@ #pragma once #include #include +#include #include +#include +#include "model/Anomaly.hpp" #include "model/Field.hpp" #include "repo/RepoTypes.hpp" @@ -31,7 +34,7 @@ struct TerrainPaths { // **契约:onOk/onErr 必须在主(GUI)线程调用**——上层(VtkSceneController)回调内直接操作 // 场景/发 Qt 信号,依赖主线程亲和;Api 实现若在工作线程完成须 post 回主线程再回调。 // dimensionOf 是同步纯函数(无 I/O,只做类型→维度映射)。 -// 切片/异常/任务等签名本期不在接口内(留 P3/P4)。 +// 切片/异常/任务接口已按 spec §6.3–6.5 完整设计(见下方),LocalSample 内存态 stub,将来 Api3dRepository 换实现。 class I3dSceneRepository { public: using OnError = std::function; @@ -47,6 +50,81 @@ public: // 异步:加载地形 DEM/影像路径。 virtual void loadTerrainPaths(std::function onOk, OnError onErr) = 0; + + // ── 切片数据集 CRUD(spec §6.3)────────────────────────────────────────── + // 切面位姿(原点 + 法向,用 std::array 去裸 double[])。 + struct SliceSpec { + std::string volumeDsId; // 所属三维体 dsId + std::array origin{{0, 0, 0}}; // 切面上一点(世界米) + std::array normal{{0, 0, 1}}; // 切面法向(单位向量) + std::string colorScaleId; + }; + // 切片数据集(持久化态):dsId/名字 + 位姿 + 采样网格。 + struct SliceDataset { + std::string dsId, name; + SliceSpec spec; + geopro::core::Grid section{0, 0}; // 切面着色网格(保存后才填) + }; + + // 保存为新切片数据集 → onOk(newDsId)。 + virtual void createSlice(const SliceSpec& spec, const std::string& name, + std::function onOk, + OnError onErr) = 0; + // 覆盖已有切片位姿。 + virtual void saveSlice(const std::string& dsId, const SliceSpec& spec, + std::function onOk, OnError onErr) = 0; + // 删除切片数据集。 + virtual void deleteSlice(const std::string& dsId, + std::function onOk, OnError onErr) = 0; + + // ── 异常 / 异常体(spec §6.4)──────────────────────────────────────────── + // 异常体(树中间层):含该体下的多个 Anomaly。 + struct AnomalyBody { + std::string id, name, typeName; + std::vector members; + }; + // 异常树:对象 → 异常体分组 → 异常,以及未分组异常。 + struct AnomalyTree { + std::vector bodies; + std::vector loose; // 未分组异常 + }; + + // 加载对象的完整异常树。 + virtual void loadAnomalyTree(const std::string& objectId, + std::function onOk, OnError onErr) = 0; + // 保存/新建异常(含截图属性)→ onOk(anomalyId)。 + virtual void saveAnomaly(const geopro::core::Anomaly& a, + const std::string& screenshotPngPath, + std::function onOk, + OnError onErr) = 0; + // 删除单个异常。 + virtual void deleteAnomaly(const std::string& anomalyId, + std::function onOk, OnError onErr) = 0; + // 删除异常体分组(及其下异常)。 + virtual void deleteAnomalyGroup(const std::string& bodyId, + std::function onOk, OnError onErr) = 0; + + // ── 任务管理(spec §6.5)───────────────────────────────────────────────── + // 任务调用记录(当前数据集历史)。 + struct TaskRecord { + std::string id, taskName, status, createTime; + }; + // 可使用任务(与 ds 类型 ddCode 相符的任务插件;复用 model/list 语义)。 + struct UsableTask { + std::string scriptId, scriptCode, name; + int opType = 0; + }; + + // 加载当前数据集的任务调用记录。 + virtual void loadTaskRecords(const std::string& dsId, + std::function)> onOk, + OnError onErr) = 0; + // 加载与 ddCode 匹配的可用任务插件列表。 + virtual void loadUsableTasks(const std::string& ddCode, + std::function)> onOk, + OnError onErr) = 0; }; +// 注:以上切片/异常/任务接口已按 spec §6.3–6.5 完整设计; +// LocalSample3dRepository 提供内存态 stub;真实后端 = 将来 Api3dRepository(上层不变)。 } // namespace geopro::data diff --git a/src/data/repo/LocalSample3dRepository.cpp b/src/data/repo/LocalSample3dRepository.cpp index 795d295..87da76e 100644 --- a/src/data/repo/LocalSample3dRepository.cpp +++ b/src/data/repo/LocalSample3dRepository.cpp @@ -156,4 +156,69 @@ void LocalSample3dRepository::loadTerrainPaths(std::function } } +// ── 切片 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 diff --git a/src/data/repo/LocalSample3dRepository.hpp b/src/data/repo/LocalSample3dRepository.hpp index 22353b9..667ed0d 100644 --- a/src/data/repo/LocalSample3dRepository.hpp +++ b/src/data/repo/LocalSample3dRepository.hpp @@ -1,6 +1,8 @@ #pragma once #include +#include #include +#include #include "repo/I3dSceneRepository.hpp" @@ -25,10 +27,43 @@ public: OnError onErr) override; void loadTerrainPaths(std::function onOk, OnError onErr) override; + // 切片 CRUD(spec §6.3 内存态 stub) + void createSlice(const SliceSpec& spec, const std::string& name, + std::function onOk, OnError onErr) override; + void saveSlice(const std::string& dsId, const SliceSpec& spec, + std::function onOk, OnError onErr) override; + void deleteSlice(const std::string& dsId, + std::function onOk, OnError onErr) override; + + // 异常 / 异常体(spec §6.4 内存态 stub) + void loadAnomalyTree(const std::string& objectId, + std::function onOk, OnError onErr) override; + void saveAnomaly(const geopro::core::Anomaly& a, const std::string& screenshotPngPath, + std::function onOk, OnError onErr) override; + void deleteAnomaly(const std::string& anomalyId, + std::function onOk, OnError onErr) override; + void deleteAnomalyGroup(const std::string& bodyId, + std::function onOk, OnError onErr) override; + + // 任务管理(spec §6.5 内存态 stub) + void loadTaskRecords(const std::string& dsId, + std::function)> onOk, + OnError onErr) override; + void loadUsableTasks(const std::string& ddCode, + std::function)> onOk, + OnError onErr) override; + private: LocalSampleRepository& base_; std::string projectCrs_; double baseLat_, baseLon_; + + // 内存态存储(stub,无持久化;重启清空) + int sliceCounter_ = 0; + std::map slices_; // dsId → spec + + int anomalyCounter_ = 0; + std::map anomalies_; // anomalyId → Anomaly }; } // namespace geopro::data diff --git a/tests/controller/test_vtk_scene_controller.cpp b/tests/controller/test_vtk_scene_controller.cpp index 66363ce..9a6daeb 100644 --- a/tests/controller/test_vtk_scene_controller.cpp +++ b/tests/controller/test_vtk_scene_controller.cpp @@ -96,6 +96,26 @@ struct FakeSceneRepo : data::I3dSceneRepository { void loadTerrainPaths(std::function onOk, OnError) override { onOk(data::TerrainPaths{"dem.tif", "image.tif"}); } + + // 切片/异常/任务 stub(满足纯虚,行为同 LocalSample3dRepository) + void createSlice(const SliceSpec&, const std::string&, + std::function onOk, OnError) override { onOk("slice-0"); } + void saveSlice(const std::string&, const SliceSpec&, + std::function onOk, OnError) override { onOk(); } + void deleteSlice(const std::string&, + std::function onOk, OnError) override { onOk(); } + void loadAnomalyTree(const std::string&, + std::function onOk, OnError) override { onOk({}); } + void saveAnomaly(const core::Anomaly&, const std::string&, + std::function onOk, OnError) override { onOk("anomaly-0"); } + void deleteAnomaly(const std::string&, + std::function onOk, OnError) override { onOk(); } + void deleteAnomalyGroup(const std::string&, + std::function onOk, OnError) override { onOk(); } + void loadTaskRecords(const std::string&, + std::function)> onOk, OnError) override { onOk({}); } + void loadUsableTasks(const std::string&, + std::function)> onOk, OnError) override { onOk({}); } }; } // namespace