#pragma once #include #include #include #include #include #include #include #include #include #include "I3dSceneView.hpp" #include "model/ColorScale.hpp" namespace geopro::core { class GeoLocalFrame; } namespace geopro::render { class Scene; } class vtkRenderer; class vtkRenderWindow; class vtkProp; class vtkActor; class vtkVolume; namespace geopro::app { // I3dSceneView 的真实实现:把编排层的"加图元"指令翻译为 render actor + Scene 调用。 // 持有 Scene / renderer / renderWindow(非拥有)+ 共享 GeoLocalFrame(多视图空间配准)。 // 纵向夸张统一作用:帘面/地形 actor SetScale(1,1,VE),体素 z 原点/间距烤入 VE。 // render 层零业务:actor 只吃 core::*,本类负责装配。 class VtkSceneView : public geopro::controller::I3dSceneView { public: // 入参生命周期须覆盖本对象(由调用方保证)。zRefElev:地形 z 基准(测线地表高程)。 VtkSceneView(geopro::render::Scene& scene, vtkRenderWindow* renderWindow, std::shared_ptr frame, double zRefElev); void clear() override; void setVerticalExaggeration(double ve) override; void setVolumeOpacity(double maxOpacity) override; // 运行时调已渲染体 + 后续新体的最大不透明度 double zRefElev() const override { return zRefElev_; } void addSurveyLine(const geopro::core::Grid& grid) override; void addCurtain(const std::string& dsId, const geopro::core::Grid& grid, const geopro::core::ColorScale& cs) override; void addVolume(const std::string& dsId, const geopro::data::VolumeGrid& vol, const geopro::core::ColorScale& cs) override; bool updateVolumeColorInPlace(const std::string& dsId, const geopro::core::ColorScale& cs) override; void addMapLine(const std::string& dsId, const geopro::data::MapLine& line, double worldZ) override; void addTerrain(const geopro::data::TerrainPaths& paths) override; void removeDataset(const std::string& dsId) override; void addAnomaly(const geopro::core::Anomaly& a) override; void removeAnomaly(const std::string& anomalyId) override; void clearAnomalies() override; void setAnomalyVisible(const std::string& anomalyId, bool visible) override; void setSelectedAnomaly(const std::string& anomalyId) override; void setAxes(geopro::controller::AxesMode mode, geopro::controller::AxesUnit unit, int fontSize) override; void setAxesRanges(const geopro::controller::AxisRangeCfg& x, const geopro::controller::AxisRangeCfg& y, const geopro::controller::AxisRangeCfg& z) override; void applyCameraView(geopro::controller::ViewDir dir) override; void zoom(double factor) override; void fitView() override; void render(bool is2D, bool resetCamera = true) override; void renderIncremental() override; // ── P3 切片交互:暴露当前体素 image(含 VE 烤入的 origin/spacing)供切片附着 ── // addVolume 用暴露 image 的 buildVoxel 重载保留;clear/无体素时置空。 vtkImageData* currentVolumeImage() const { return currentVolumeImage_.Get(); } const geopro::core::ColorScale& currentColorScale() const { return currentColorScale_; } double currentVmin() const { return currentVmin_; } double currentVmax() const { return currentVmax_; } bool hasVolume() const { return currentVolumeImage_ != nullptr; } const std::string& currentVolumeDsId() const { return volumeOwnerDs_; } // 当前体归属 ds(保存切片用) // 体素 image 变化(addVolume 附着新 image / clear 置空)时回调,供上层把新 image 推给 // InteractionManager(重附着或关闭切片)。clear 时以 nullptr 触发。 std::function onVolumeChanged; // frame 原点重锚(首个带经纬剖面到达)后回调,供底图等随之刷新到数据所在位置。 std::function onFrameReanchored; // 复位"已按数据重锚"标志:切换项目清场后调,使新项目首个数据重新触发重锚(→ onFrameReanchored // → 底图按新项目位置重显)。否则增量勾选不走 clear(),旧标志残留 → 不重锚 → 底图不再显示。 void resetFrameAnchor() { frameAnchoredToData_ = false; } // 相机程序化变化(取景/预设/缩放)后回调,供底图按新视锥重算覆盖(否则首帧部分瓦片要手动微动才出)。 std::function onCameraChanged; // ── 二维分析改造 A 期:一场景两相机 ────────────────────────────────────────── // 切「二维分析」(is2D=true):相机锁近俯视、显 2D 足迹/隐 3D(体/帘面/异常);切回反之。 // 只翻 actor 可见标志(不清空、不重建)→ 切换瞬时、零重插值。地形/底图常驻不动。 // 切片显隐 + 交互锁由 InteractionManager::setMode2D 配合(上层在同一处调两者)。 void setAnalysisMode2D(bool is2D); bool isAnalysisMode2D() const { return analysisMode2D_; } // ── 二维分析改造 B 期:选中 2D 足迹沿高程 Z 拖动 ─────────────────────────────── // 仅二维分析下用。pickMapLineAt:在屏幕(x,y)拾取足迹(只考虑可见足迹,不被地形/底图干扰);命中则 // 选中(additive=Ctrl 多选切换,否则单选替换)并高亮,返回是否有选中(交互样式据此决定 Z 拖动/平移)。 // nudgeSelectedMapLinesZ:选中足迹世界 Z += worldDz(锁 XY);偏移按 dsId 持久(切走再回/全量重建保留)。 // selectedMapLineZ:代表性当前世界 Z(高程读数浮层用);无选中返回 0。 bool pickMapLineAt(int screenX, int screenY, bool additive); void clearMapLineSelection(); bool hasMapLineSelection() const { return !selectedMapLines_.empty(); } void nudgeSelectedMapLinesZ(double worldDz); double selectedMapLineZ() const; // 双向选择联动:列表↔VTK。selectedMapLines 取当前选中 dsId;setSelectedMapLines 由列表设置选中 // (高亮,不回调,避免环)。VTK 内拾取改变选中时触发 onMapLineSelectionChanged → 上层同步列表。 std::vector selectedMapLines() const; void setSelectedMapLines(const std::vector& dsIds); std::function onMapLineSelectionChanged; private: // 首个带经纬数据(剖面/足迹)到达时把共享 frame 重锚到其 lat/lon 包围盒中心:使数据落在世界原点近旁 // (否则样本默认原点可能离真实数据数百公里→图元在视锥外、移动视角也找不到)。已锚或无经纬则跳过。 void anchorFrameIfNeeded(const std::vector& lat, const std::vector& lon, int n); // 按当前坐标轴设置 + 场景包围盒重建坐标轴 prop(render 末尾调)。 void rebuildAxes(); void removeProps(std::vector>& props); // 从 renderer 移除并清空 // 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。 bool computeDataBounds(double out[6]) const; public: // 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。 double dataHorizontalRadius() const; private: geopro::render::Scene& scene_; vtkRenderWindow* renderWindow_; std::shared_ptr frame_; double zRefElev_; double verticalExaggeration_ = 1.0; // 是否已按真实剖面 lat/lon 重锚 frame 原点(每次 clear 重置):默认原点取自样本、可能离真实数据 // 很远→局部坐标巨大、轴刻度无意义;首个带经纬剖面到达时重锚到其中心,同选择内多剖面共用配准。 bool frameAnchoredToData_ = false; // 坐标轴设置(P2):默认标准 + 米。 geopro::controller::AxesMode axesMode_ = geopro::controller::AxesMode::Standard; geopro::controller::AxesUnit axesUnit_ = geopro::controller::AxesUnit::Meter; int axesFontSize_ = 12; geopro::controller::AxisRangeCfg axisX_, axisY_, axisZ_; // per-axis 可见性 + 自定义范围 // 当前坐标轴 prop:render 可能多次调用 rebuildAxes(rebuild 末尾 + 异步回灌), // 持引用以便重建前移除旧 prop,避免叠加(评审 HIGH)。 vtkSmartPointer currentAxes_; // 当前体素 image + 色阶(P3 切片附着源);无体素时为空。「当前」=最后添加/活动的体(保存切片/ // 创建异常的默认归属)。多体并发下各体 image 另存 volumes_。 vtkSmartPointer currentVolumeImage_; geopro::core::ColorScale currentColorScale_; double currentVmin_ = 0.0; double currentVmax_ = 0.0; // 多体并发:按 dsId 持各已渲染体的 image + 色阶(供 InteractionManager 让各体切片各用自己的 image)。 struct VolumeRec { vtkSmartPointer image; geopro::core::ColorScale cs; double vmin = 0.0, vmax = 0.0; vtkSmartPointer volume; // 体 actor(运行时调不透明度:改其 property 的不透明度传递函数) }; std::map volumes_; public: const std::map& volumes() const { return volumes_; } // 已渲染各体 image/色阶 bool isVolumeRendered(const std::string& dsId) const { return volumes_.count(dsId) > 0; } const VolumeRec* volume(const std::string& dsId) const { // 取指定已渲染体的 image/色阶(缺=nullptr) auto it = volumes_.find(dsId); return it != volumes_.end() ? &it->second : nullptr; } private: // 增量渲染:按 dsId 跟踪该数据集的 props(帘面/体素),支持单独移除而不全量重建; // miscProps_ 为非数据集 prop(地形/测线),仅随 clear 全量移除。底图由 TileBasemap 自管、不在此。 std::map>> dsProps_; std::vector> miscProps_; std::string volumeOwnerDs_; // 当前 currentVolumeImage_ 归属的 ds(其被移除时置空切片源) std::map> anomalyProps_; // 异常 id → 3D actor // ── 二维分析改造 A 期 ── // 哪些 dsProps_ 条目是 2D 足迹(addMapLine):切 tab 按此区分维度翻可见(其余 dsProps_=帘面/体=3D)。 std::set mapLineDs_; bool analysisMode2D_ = false; // 当前是否处二维分析(默认三维:启动在「三维分析」tab) // B 期:选中的足迹 dsId(Z 拖动目标) + 各足迹累计 Z 偏移(持久,全量重建后 addMapLine 复用)。 std::set selectedMapLines_; std::map mapLineZOffset_; void applyMapLineSelectionVisual(); // 选中足迹加粗变亮、其余复原(橙 3.0) }; } // namespace geopro::app