geopro/src/app/VtkSceneView.hpp

177 lines
10 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.

#pragma once
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <string>
#include <vector>
#include <vtkCubeAxesActor.h>
#include <vtkImageData.h>
#include <vtkSmartPointer.h>
#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<geopro::core::GeoLocalFrame> 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 setMapLinesZ(const std::vector<std::string>& dsIds, double z) 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;
// ── 视图导航基元spec §3.1T1──────────────────────────────────────────────
// 给定 dsIds 的已渲染 actor 世界包围盒并集;无有效返回 false否则填 out=[xmin,xmax,…,zmax]。
bool datasetBounds(const std::vector<std::string>& dsIds, double outB[6]) const;
// 相机适配到指定包围盒保持当前朝向ResetCamera(b)),用于双击适配/贴合。
void fitToBounds(const double b[6]);
// 绕 pivot 转到沿 dir 轴看向 pivot保留当前 focal-to-camera 距离(缩放不变)。
void orbitToAxis(geopro::controller::ViewDir dir, const double pivot[3]);
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<void()> onVolumeChanged;
// frame 原点重锚(首个带经纬剖面到达)后回调,供底图等随之刷新到数据所在位置。
std::function<void()> onFrameReanchored;
// 复位"已按数据重锚"标志:切换项目清场后调,使新项目首个数据重新触发重锚(→ onFrameReanchored
// → 底图按新项目位置重显)。否则增量勾选不走 clear(),旧标志残留 → 不重锚 → 底图不再显示。
void resetFrameAnchor() { frameAnchoredToData_ = false; }
// 相机程序化变化(取景/预设/缩放)后回调,供底图按新视锥重算覆盖(否则首帧部分瓦片要手动微动才出)。
std::function<void()> onCameraChanged;
// ── B 方案#2沿线位置巡航雷达超长测线──────────────────────────────────────
// t∈[0,1] 沿数据【最长轴】定位;取景到该位置一段【窗口】(windowFrac=窗口占长轴比例)
// 保持当前朝向(ResetCamera 只重定位+缩放、不转向)→ 像滚动读长 radargram。短轴满幅、长轴只取一段。
void focusAlongLongAxis(double t, double windowFrac);
// 数据包围盒长短轴比(max/min 跨度)。用于判是否细长(雷达)→ 决定沿线滑块显隐。无数据返回 0。
double longAxisElongation() const;
private:
// 首个带经纬数据(剖面/足迹)到达时把共享 frame 重锚到其 lat/lon 包围盒中心:使数据落在世界原点近旁
// (否则样本默认原点可能离真实数据数百公里→图元在视锥外、移动视角也找不到)。已锚或无经纬则跳过。
void anchorFrameIfNeeded(const std::vector<double>& lat, const std::vector<double>& lon, int n);
// 按当前坐标轴设置 + 场景包围盒重建坐标轴 proprender 末尾调)。
void rebuildAxes();
void removeProps(std::vector<vtkSmartPointer<vtkProp>>& props); // 从 renderer 移除并清空
// 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。
bool computeDataBounds(double out[6]) const;
public:
// 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。
double dataHorizontalRadius() const;
private:
geopro::render::Scene& scene_;
vtkRenderWindow* renderWindow_;
std::shared_ptr<geopro::core::GeoLocalFrame> 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 可见性 + 自定义范围
// 当前坐标轴 proprender 可能多次调用 rebuildAxesrebuild 末尾 + 异步回灌),
// 持引用以便重建前移除旧 prop避免叠加评审 HIGH
vtkSmartPointer<vtkCubeAxesActor> currentAxes_;
// 当前体素 image + 色阶P3 切片附着源);无体素时为空。「当前」=最后添加/活动的体(保存切片/
// 创建异常的默认归属)。多体并发下各体 image 另存 volumes_。
vtkSmartPointer<vtkImageData> currentVolumeImage_;
geopro::core::ColorScale currentColorScale_;
double currentVmin_ = 0.0;
double currentVmax_ = 0.0;
// 多体并发:按 dsId 持各已渲染体的 image + 色阶(供 InteractionManager 让各体切片各用自己的 image
struct VolumeRec {
vtkSmartPointer<vtkImageData> image;
geopro::core::ColorScale cs;
double vmin = 0.0, vmax = 0.0;
vtkSmartPointer<vtkVolume> volume; // 体 actor运行时调不透明度改其 property 的不透明度传递函数)
};
std::map<std::string, VolumeRec> volumes_;
public:
const std::map<std::string, VolumeRec>& 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<std::string, std::vector<vtkSmartPointer<vtkProp>>> dsProps_;
std::vector<vtkSmartPointer<vtkProp>> miscProps_;
std::string volumeOwnerDs_; // 当前 currentVolumeImage_ 归属的 ds其被移除时置空切片源
std::map<std::string, vtkSmartPointer<vtkActor>> anomalyProps_; // 异常 id → 3D actor
// 哪些 dsProps_ 条目是 2D 足迹(addMapLine):供足迹 actor 归属识别(Task E2/F2 用)。
std::set<std::string> mapLineDs_;
};
} // namespace geopro::app