fix(vtk): 导航gnomon重做为固定右下角叠加渲染器(无边框可点转视角+业界样式)
This commit is contained in:
parent
0e449e082d
commit
e1a10a1a73
|
|
@ -9,21 +9,19 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
#include <vtkAssemblyNode.h>
|
#include <vtkBillboardTextActor3D.h>
|
||||||
#include <vtkAssemblyPath.h>
|
|
||||||
#include <vtkAxesActor.h>
|
|
||||||
#include <vtkCallbackCommand.h>
|
#include <vtkCallbackCommand.h>
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
#include <vtkCommand.h>
|
#include <vtkCommand.h>
|
||||||
#include <vtkProperty.h>
|
#include <vtkProperty.h>
|
||||||
#include <vtkBoundingBox.h>
|
#include <vtkBoundingBox.h>
|
||||||
#include <vtkCubeAxesActor.h>
|
#include <vtkCubeAxesActor.h>
|
||||||
|
#include <vtkLineSource.h>
|
||||||
#include <vtkNew.h>
|
#include <vtkNew.h>
|
||||||
#include <vtkOrientationMarkerWidget.h>
|
|
||||||
#include <vtkPolyDataMapper.h>
|
#include <vtkPolyDataMapper.h>
|
||||||
#include <vtkProp.h>
|
#include <vtkProp.h>
|
||||||
#include <vtkPropAssembly.h>
|
|
||||||
#include <vtkPropPicker.h>
|
#include <vtkPropPicker.h>
|
||||||
|
#include <vtkTextProperty.h>
|
||||||
#include <vtkPiecewiseFunction.h>
|
#include <vtkPiecewiseFunction.h>
|
||||||
#include <vtkColorTransferFunction.h>
|
#include <vtkColorTransferFunction.h>
|
||||||
#include <vtkGPUVolumeRayCastMapper.h>
|
#include <vtkGPUVolumeRayCastMapper.h>
|
||||||
|
|
@ -92,7 +90,7 @@ VtkSceneView::VtkSceneView(geopro::render::Scene& scene, vtkRenderWindow* render
|
||||||
}
|
}
|
||||||
|
|
||||||
VtkSceneView::~VtkSceneView() {
|
VtkSceneView::~VtkSceneView() {
|
||||||
// 摘除左键观察者(其 clientData=this,本对象析构后若留存会悬垂)+ 禁用 marker widget。
|
// 摘除左键/相机观察者(clientData=this,本对象析构后若留存会悬垂)+ 移除叠加渲染器。
|
||||||
// 渲染窗口/交互器可能已在 Qt 拆台中先行析构,全程判空。
|
// 渲染窗口/交互器可能已在 Qt 拆台中先行析构,全程判空。
|
||||||
if (renderWindow_) {
|
if (renderWindow_) {
|
||||||
if (auto* iren = renderWindow_->GetInteractor()) {
|
if (auto* iren = renderWindow_->GetInteractor()) {
|
||||||
|
|
@ -100,7 +98,11 @@ VtkSceneView::~VtkSceneView() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
gnomonClickTag_ = 0;
|
gnomonClickTag_ = 0;
|
||||||
if (gnomonWidget_) gnomonWidget_->SetEnabled(0);
|
// 主相机由 scene_ 渲染器持有、生命周期覆盖本对象(构造契约),析构时仍在 → 可安全摘观察者。
|
||||||
|
if (gnomonObservedCam_ && gnomonCamTag_ != 0) gnomonObservedCam_->RemoveObserver(gnomonCamTag_);
|
||||||
|
gnomonCamTag_ = 0;
|
||||||
|
gnomonObservedCam_ = nullptr;
|
||||||
|
if (renderWindow_ && gnomonRenderer_) renderWindow_->RemoveRenderer(gnomonRenderer_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneView::removeProps(std::vector<vtkSmartPointer<vtkProp>>& props) {
|
void VtkSceneView::removeProps(std::vector<vtkSmartPointer<vtkProp>>& props) {
|
||||||
|
|
@ -501,61 +503,100 @@ void VtkSceneView::orbitToCurrentPivot(geopro::controller::ViewDir dir) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneView::ensureGnomon() {
|
void VtkSceneView::ensureGnomon() {
|
||||||
// 幂等装配:交互器就绪后建一次。marker widget 把内部渲染器叠加到主渲染器另一图层,其相机随主相机
|
// 幂等装配:交互器就绪后建一次。用【专用叠加渲染器】(非 vtkOrientationMarkerWidget):图层1、固定
|
||||||
// 同步 → 三向标随场景朝向转(widget 的核心价值)。6 个方向球组进同一 vtkPropAssembly 作可点击热区。
|
// 右下角视口、InteractiveOff、透明背景 → 无 widget 外框、不可拖动/缩放;相机由 syncGnomonCamera
|
||||||
|
// 镜像主相机朝向 → gizmo 随场景旋转同步转。三轴线 + 6 方向球(仅球可拾取) + 正向 XYZ 标签。
|
||||||
if (gnomonReady_ || !renderWindow_) return;
|
if (gnomonReady_ || !renderWindow_) return;
|
||||||
auto* iren = renderWindow_->GetInteractor();
|
auto* iren = renderWindow_->GetInteractor();
|
||||||
if (!iren) return; // QVTK 尚未提供交互器 → 下一帧 render 再补装
|
if (!iren) return; // QVTK 尚未提供交互器 → 下一帧 render 再补装
|
||||||
|
|
||||||
// 经典 XYZ 三箭头 + 轴标签作视觉主体(不参与拾取,避免命中箭头无方向语义)。
|
// 叠加渲染器:图层1 固定右下角(x∈[0.85,1.0]、y∈[0.10,0.30]) —— 避开底部满宽沿线滑块条(仅雷达体
|
||||||
vtkNew<vtkAxesActor> axes;
|
// 时显示、约占底 46px)。透明背景只显 gizmo 图元;FXAA 抗锯齿使边缘平滑;非交互不响应任何输入。
|
||||||
axes->SetPickable(0);
|
renderWindow_->SetNumberOfLayers(2);
|
||||||
axes->AxisLabelsOn();
|
gnomonRenderer_ = vtkSmartPointer<vtkRenderer>::New();
|
||||||
|
gnomonRenderer_->SetLayer(1);
|
||||||
|
gnomonRenderer_->InteractiveOff();
|
||||||
|
gnomonRenderer_->SetViewport(0.85, 0.10, 1.0, 0.30);
|
||||||
|
gnomonRenderer_->SetBackgroundAlpha(0.0); // 透明合成到主场景之上,无背景块
|
||||||
|
gnomonRenderer_->SetUseFXAA(true); // 抗锯齿:轴线/球边缘平滑
|
||||||
|
renderWindow_->AddRenderer(gnomonRenderer_);
|
||||||
|
|
||||||
vtkNew<vtkPropAssembly> marker;
|
const double L = 1.0; // 球心到原点距离(= 轴线长度)
|
||||||
marker->AddPart(axes);
|
|
||||||
|
|
||||||
// 6 个方向球:±X/±Y/±Z。位置对称于原点(widget 要求 marker 包围盒关于原点对称以正确同步相机)。
|
// 三根过原点的轴线:X=红、Y=绿、Z=蓝(无光照纯色、加粗、不可拾取)。
|
||||||
// 正向球置于对应箭头尖端(与 axes 默认 TotalLength≈1 匹配)、稍亮;负向球在对侧、稍暗但仍可见可点。
|
struct AxisLine { double to[3]; double col[3]; };
|
||||||
|
const AxisLine lines[3] = {
|
||||||
|
{{L, 0, 0}, {0.90, 0.26, 0.26}}, // X 红
|
||||||
|
{{0, L, 0}, {0.32, 0.78, 0.36}}, // Y 绿
|
||||||
|
{{0, 0, L}, {0.36, 0.56, 0.96}}, // Z 蓝
|
||||||
|
};
|
||||||
|
for (const auto& ln : lines) {
|
||||||
|
vtkNew<vtkLineSource> src;
|
||||||
|
src->SetPoint1(0.0, 0.0, 0.0);
|
||||||
|
src->SetPoint2(ln.to[0], ln.to[1], ln.to[2]);
|
||||||
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
|
mapper->SetInputConnection(src->GetOutputPort());
|
||||||
|
vtkNew<vtkActor> a;
|
||||||
|
a->SetMapper(mapper);
|
||||||
|
a->GetProperty()->SetColor(ln.col[0], ln.col[1], ln.col[2]);
|
||||||
|
a->GetProperty()->SetLineWidth(2.6f);
|
||||||
|
a->GetProperty()->SetLighting(false);
|
||||||
|
a->SetPickable(0); // 轴线不参与拾取(仅方向球有方向语义)
|
||||||
|
gnomonRenderer_->AddViewProp(a);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6 个方向球:正向亮色填充 + XYZ 黑标签、稍大;负向暗色、稍小、无标签(业界导航 gizmo 风格)。
|
||||||
// 方向 → ViewDir 与 CameraPreset 语义一致:+Z=Top、−Z=Bottom、+Y=Back、−Y=Front、+X=Right、−X=Left。
|
// 方向 → ViewDir 与 CameraPreset 语义一致:+Z=Top、−Z=Bottom、+Y=Back、−Y=Front、+X=Right、−X=Left。
|
||||||
struct DirSpec {
|
struct DirSpec {
|
||||||
geopro::controller::ViewDir dir;
|
geopro::controller::ViewDir dir;
|
||||||
double pos[3];
|
double pos[3];
|
||||||
double col[3];
|
double col[3];
|
||||||
|
bool positive;
|
||||||
|
const char* label; // 正向标签;负向 nullptr
|
||||||
};
|
};
|
||||||
const double L = 1.0; // 球心到原点距离(与轴长匹配)
|
|
||||||
const DirSpec specs[6] = {
|
const DirSpec specs[6] = {
|
||||||
{geopro::controller::ViewDir::Right, {L, 0, 0}, {1.0, 0.30, 0.30}}, // +X
|
{geopro::controller::ViewDir::Right, {L, 0, 0}, {0.92, 0.27, 0.27}, true, "X"}, // +X
|
||||||
{geopro::controller::ViewDir::Left, {-L, 0, 0}, {0.55, 0.16, 0.16}}, // −X
|
{geopro::controller::ViewDir::Left, {-L, 0, 0}, {0.46, 0.17, 0.17}, false, nullptr}, // −X
|
||||||
{geopro::controller::ViewDir::Back, {0, L, 0}, {0.30, 1.0, 0.30}}, // +Y
|
{geopro::controller::ViewDir::Back, {0, L, 0}, {0.31, 0.78, 0.35}, true, "Y"}, // +Y
|
||||||
{geopro::controller::ViewDir::Front, {0, -L, 0}, {0.16, 0.55, 0.16}}, // −Y
|
{geopro::controller::ViewDir::Front, {0, -L, 0}, {0.17, 0.41, 0.19}, false, nullptr}, // −Y
|
||||||
{geopro::controller::ViewDir::Top, {0, 0, L}, {0.40, 0.55, 1.0}}, // +Z
|
{geopro::controller::ViewDir::Top, {0, 0, L}, {0.35, 0.57, 0.96}, true, "Z"}, // +Z
|
||||||
{geopro::controller::ViewDir::Bottom, {0, 0, -L}, {0.22, 0.30, 0.60}}, // −Z
|
{geopro::controller::ViewDir::Bottom, {0, 0, -L}, {0.19, 0.29, 0.52}, false, nullptr}, // −Z
|
||||||
};
|
};
|
||||||
gnomonDirs_.clear();
|
gnomonDirs_.clear();
|
||||||
for (const auto& s : specs) {
|
for (const auto& s : specs) {
|
||||||
vtkNew<vtkSphereSource> sphere;
|
vtkNew<vtkSphereSource> sphere;
|
||||||
sphere->SetRadius(0.18);
|
sphere->SetRadius(s.positive ? 0.30 : 0.22); // 正向大、负向小(hollow-looking)
|
||||||
sphere->SetThetaResolution(16);
|
sphere->SetThetaResolution(32);
|
||||||
sphere->SetPhiResolution(16);
|
sphere->SetPhiResolution(32);
|
||||||
sphere->SetCenter(s.pos[0], s.pos[1], s.pos[2]);
|
sphere->SetCenter(s.pos[0], s.pos[1], s.pos[2]);
|
||||||
vtkNew<vtkPolyDataMapper> mapper;
|
vtkNew<vtkPolyDataMapper> mapper;
|
||||||
mapper->SetInputConnection(sphere->GetOutputPort());
|
mapper->SetInputConnection(sphere->GetOutputPort());
|
||||||
auto actor = vtkSmartPointer<vtkActor>::New();
|
auto actor = vtkSmartPointer<vtkActor>::New();
|
||||||
actor->SetMapper(mapper);
|
actor->SetMapper(mapper);
|
||||||
actor->GetProperty()->SetColor(s.col[0], s.col[1], s.col[2]);
|
auto* prop = actor->GetProperty();
|
||||||
actor->SetPickable(1);
|
prop->SetColor(s.col[0], s.col[1], s.col[2]);
|
||||||
marker->AddPart(actor);
|
prop->SetAmbient(0.45); // 高环境光 → 颜色读数接近本色、球体仍有微弱立体感
|
||||||
gnomonDirs_[actor.Get()] = s.dir; // 组装体持 actor 保活;此处仅记裸指针→方向
|
prop->SetDiffuse(0.60);
|
||||||
}
|
prop->SetSpecular(0.20);
|
||||||
|
prop->SetSpecularPower(20.0);
|
||||||
|
actor->SetPickable(1); // 仅方向球可拾取
|
||||||
|
gnomonRenderer_->AddViewProp(actor);
|
||||||
|
gnomonDirs_[actor.Get()] = s.dir; // 渲染器持 actor 保活;此处仅记裸指针→方向
|
||||||
|
|
||||||
gnomonWidget_ = vtkSmartPointer<vtkOrientationMarkerWidget>::New();
|
if (s.positive && s.label) { // 正向轴标签:始终朝相机的公告板文字,黑色粗体、居中于球心
|
||||||
gnomonWidget_->SetOrientationMarker(marker);
|
auto lbl = vtkSmartPointer<vtkBillboardTextActor3D>::New();
|
||||||
gnomonWidget_->SetDefaultRenderer(scene_.renderer()); // 父渲染器(相机同步源)
|
lbl->SetInput(s.label);
|
||||||
gnomonWidget_->SetInteractor(iren);
|
lbl->SetPosition(s.pos[0], s.pos[1], s.pos[2]);
|
||||||
gnomonWidget_->SetViewport(0.82, 0.80, 1.0, 1.0); // 右上角:避开左上工具条 + 底部沿线条
|
auto* tp = lbl->GetTextProperty();
|
||||||
gnomonWidget_->SetInteractive(0); // 禁 widget 自身拖动/缩放,仅作方向选择器
|
tp->SetFontSize(15);
|
||||||
gnomonWidget_->SetEnabled(1);
|
tp->SetBold(true);
|
||||||
|
tp->SetColor(0.06, 0.06, 0.06);
|
||||||
|
tp->SetJustificationToCentered();
|
||||||
|
tp->SetVerticalJustificationToCentered();
|
||||||
|
lbl->SetPickable(0);
|
||||||
|
gnomonRenderer_->AddViewProp(lbl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
gnomonPicker_ = vtkSmartPointer<vtkPropPicker>::New();
|
gnomonPicker_ = vtkSmartPointer<vtkPropPicker>::New();
|
||||||
|
|
||||||
|
|
@ -567,36 +608,63 @@ void VtkSceneView::ensureGnomon() {
|
||||||
});
|
});
|
||||||
gnomonClickTag_ = iren->AddObserver(vtkCommand::LeftButtonPressEvent, gnomonClickCmd_, 1.0);
|
gnomonClickTag_ = iren->AddObserver(vtkCommand::LeftButtonPressEvent, gnomonClickCmd_, 1.0);
|
||||||
|
|
||||||
|
// 相机同步:观察主相机 ModifiedEvent,每次朝向变化把 gizmo 相机镜像到同朝向 → gizmo 随场景转。
|
||||||
|
gnomonCamCmd_ = vtkSmartPointer<vtkCallbackCommand>::New();
|
||||||
|
gnomonCamCmd_->SetClientData(this);
|
||||||
|
gnomonCamCmd_->SetCallback([](vtkObject*, unsigned long, void* client, void*) {
|
||||||
|
static_cast<VtkSceneView*>(client)->syncGnomonCamera();
|
||||||
|
});
|
||||||
|
if (auto* mainCam = scene_.renderer() ? scene_.renderer()->GetActiveCamera() : nullptr) {
|
||||||
|
gnomonObservedCam_ = mainCam;
|
||||||
|
gnomonCamTag_ = mainCam->AddObserver(vtkCommand::ModifiedEvent, gnomonCamCmd_);
|
||||||
|
}
|
||||||
|
syncGnomonCamera(); // 初始一次:装配即与当前朝向对齐
|
||||||
|
|
||||||
gnomonReady_ = true;
|
gnomonReady_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VtkSceneView::syncGnomonCamera() {
|
||||||
|
if (!gnomonRenderer_ || !scene_.renderer()) return;
|
||||||
|
auto* mainCam = scene_.renderer()->GetActiveCamera();
|
||||||
|
auto* gcam = gnomonRenderer_->GetActiveCamera();
|
||||||
|
if (!mainCam || !gcam) return;
|
||||||
|
// 复制主相机投影方向 + view-up:gizmo 相机置于 -dir*dist、焦点在原点 → 与主相机同朝向看向 gizmo。
|
||||||
|
double dir[3];
|
||||||
|
mainCam->GetDirectionOfProjection(dir); // 已归一化(F−P)
|
||||||
|
double up[3];
|
||||||
|
mainCam->GetViewUp(up);
|
||||||
|
const double dist = 10.0;
|
||||||
|
gcam->SetParallelProjection(1); // 正交投影:gizmo 无透视畸变(业界标准)
|
||||||
|
gcam->SetParallelScale(1.8); // 取景半高:球到 ±(L+r)≈1.3 + 标签留边
|
||||||
|
gcam->SetFocalPoint(0.0, 0.0, 0.0);
|
||||||
|
gcam->SetPosition(-dir[0] * dist, -dir[1] * dist, -dir[2] * dist);
|
||||||
|
gcam->SetViewUp(up[0], up[1], up[2]);
|
||||||
|
gnomonRenderer_->ResetCameraClippingRange();
|
||||||
|
}
|
||||||
|
|
||||||
void VtkSceneView::handleGnomonClick() {
|
void VtkSceneView::handleGnomonClick() {
|
||||||
if (!gnomonWidget_ || !gnomonPicker_ || !renderWindow_) return;
|
if (!gnomonRenderer_ || !gnomonPicker_ || !renderWindow_) return;
|
||||||
auto* iren = renderWindow_->GetInteractor();
|
auto* iren = renderWindow_->GetInteractor();
|
||||||
auto* gren = gnomonWidget_->GetRenderer();
|
if (!iren) return;
|
||||||
if (!iren || !gren) return;
|
|
||||||
const int ex = iren->GetEventPosition()[0];
|
const int ex = iren->GetEventPosition()[0];
|
||||||
const int ey = iren->GetEventPosition()[1];
|
const int ey = iren->GetEventPosition()[1];
|
||||||
// 仅当点击落在 gnomon 角落视口矩形内才拾取(否则放行正常场景交互,且省去全场景每次左键的硬件拾取)。
|
// 仅当点击落在 gnomon 角落视口矩形内才拾取(否则放行正常场景交互,且省去全场景每次左键的硬件拾取)。
|
||||||
const double* vp = gren->GetViewport(); // 归一化 [xmin,ymin,xmax,ymax](已含父视口换算)
|
const double* vp = gnomonRenderer_->GetViewport(); // 归一化 [xmin,ymin,xmax,ymax]
|
||||||
const int* sz = renderWindow_->GetSize();
|
const int* sz = renderWindow_->GetSize();
|
||||||
if (sz[0] <= 0 || sz[1] <= 0) return;
|
if (sz[0] <= 0 || sz[1] <= 0) return;
|
||||||
const double fx = static_cast<double>(ex) / sz[0];
|
const double fx = static_cast<double>(ex) / sz[0];
|
||||||
const double fy = static_cast<double>(ey) / sz[1];
|
const double fy = static_cast<double>(ey) / sz[1];
|
||||||
if (fx < vp[0] || fx > vp[2] || fy < vp[1] || fy > vp[3]) return; // 不在角落 → 放行
|
if (fx < vp[0] || fx > vp[2] || fy < vp[1] || fy > vp[3]) return; // 不在角落 → 不 abort,放行
|
||||||
// 角落内硬件拾取:命中某方向球 → 取其 ViewDir → 绕当前轴盒中心转到该轴(保留缩放)。
|
// 角落内硬件拾取(仅方向球可拾):命中某方向球 → 取其 ViewDir → 绕当前轴盒中心转到该轴(保留缩放)。
|
||||||
if (gnomonPicker_->PickProp(ex, ey, gren)) {
|
if (gnomonPicker_->PickProp(ex, ey, gnomonRenderer_)) {
|
||||||
vtkProp* leaf = nullptr;
|
vtkProp* leaf = gnomonPicker_->GetViewProp(); // 叠加渲染器内为裸 actor,直取即方向球
|
||||||
if (auto* path = gnomonPicker_->GetPath()) {
|
|
||||||
if (auto* node = path->GetLastNode()) leaf = node->GetViewProp(); // 组装体叶子=方向球
|
|
||||||
}
|
|
||||||
if (!leaf) leaf = gnomonPicker_->GetViewProp();
|
|
||||||
auto it = gnomonDirs_.find(leaf);
|
auto it = gnomonDirs_.find(leaf);
|
||||||
if (it != gnomonDirs_.end()) {
|
if (it != gnomonDirs_.end()) {
|
||||||
orbitToCurrentPivot(it->second);
|
orbitToCurrentPivot(it->second);
|
||||||
if (gnomonClickCmd_) gnomonClickCmd_->SetAbortFlag(1); // 消费:不触发相机旋转/场景拾取
|
if (gnomonClickCmd_) gnomonClickCmd_->SetAbortFlag(1); // 命中才消费:不触发相机旋转/场景拾取
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 未命中球 → 不 abort:左键继续走正常交互(旋转/平移/缩放/切片/拾取),保证非干扰。
|
||||||
}
|
}
|
||||||
|
|
||||||
void VtkSceneView::rebuildAxes() {
|
void VtkSceneView::rebuildAxes() {
|
||||||
|
|
|
||||||
|
|
@ -20,9 +20,9 @@ class vtkRenderWindow;
|
||||||
class vtkProp;
|
class vtkProp;
|
||||||
class vtkActor;
|
class vtkActor;
|
||||||
class vtkVolume;
|
class vtkVolume;
|
||||||
class vtkOrientationMarkerWidget;
|
|
||||||
class vtkPropPicker;
|
class vtkPropPicker;
|
||||||
class vtkCallbackCommand;
|
class vtkCallbackCommand;
|
||||||
|
class vtkCamera;
|
||||||
|
|
||||||
namespace geopro::app {
|
namespace geopro::app {
|
||||||
|
|
||||||
|
|
@ -35,7 +35,7 @@ public:
|
||||||
// 入参生命周期须覆盖本对象(由调用方保证)。zRefElev:地形 z 基准(测线地表高程)。
|
// 入参生命周期须覆盖本对象(由调用方保证)。zRefElev:地形 z 基准(测线地表高程)。
|
||||||
VtkSceneView(geopro::render::Scene& scene, vtkRenderWindow* renderWindow,
|
VtkSceneView(geopro::render::Scene& scene, vtkRenderWindow* renderWindow,
|
||||||
std::shared_ptr<geopro::core::GeoLocalFrame> frame, double zRefElev);
|
std::shared_ptr<geopro::core::GeoLocalFrame> frame, double zRefElev);
|
||||||
~VtkSceneView() override; // 摘除 gnomon 左键观察者(clientData=this),禁用 marker widget
|
~VtkSceneView() override; // 摘除 gnomon 左键/相机观察者(clientData=this),移除叠加渲染器
|
||||||
|
|
||||||
void clear() override;
|
void clear() override;
|
||||||
void setVerticalExaggeration(double ve) override;
|
void setVerticalExaggeration(double ve) override;
|
||||||
|
|
@ -126,12 +126,16 @@ private:
|
||||||
void removeProps(std::vector<vtkSmartPointer<vtkProp>>& props); // 从 renderer 移除并清空
|
void removeProps(std::vector<vtkSmartPointer<vtkProp>>& props); // 从 renderer 移除并清空
|
||||||
// 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。
|
// 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。
|
||||||
bool computeDataBounds(double out[6]) const;
|
bool computeDataBounds(double out[6]) const;
|
||||||
// 角落可点击方向标 gnomon(T3):首次(交互器就绪)时装配 marker widget + 6 向可拾取球 + 左键观察者。
|
// 角落可点击方向标 gnomon(T3):首次(交互器就绪)时装配【专用叠加渲染器】(图层1、固定右下角、
|
||||||
|
// 非交互无边框) + 三轴线 + 6 向可拾取球 + 正向标签 + 左键/相机观察者。
|
||||||
// 幂等:装配后置 gnomonReady_,重复调直接返回。render/renderIncremental/构造均可安全调用。
|
// 幂等:装配后置 gnomonReady_,重复调直接返回。render/renderIncremental/构造均可安全调用。
|
||||||
void ensureGnomon();
|
void ensureGnomon();
|
||||||
// 左键按下高优先级(先于交互样式)回调:点在 gnomon 角落视口且命中方向球 → orbitToCurrentPivot + abort
|
// 左键按下高优先级(先于交互样式)回调:点在 gnomon 角落视口且命中方向球 → orbitToCurrentPivot + abort
|
||||||
// (消费事件,阻止相机旋转/场景拾取);否则放行正常交互。
|
// (消费事件,阻止相机旋转/场景拾取);否则不 abort,放行正常交互(旋转/平移/缩放/切片/拾取)。
|
||||||
void handleGnomonClick();
|
void handleGnomonClick();
|
||||||
|
// 把主相机朝向(投影方向 + view-up)镜像到 gnomon 叠加渲染器相机(定距、焦点在 gizmo 原点),
|
||||||
|
// 使 gizmo 随场景旋转同步转。主相机 ModifiedEvent 观察者与初始装配各调一次。
|
||||||
|
void syncGnomonCamera();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。
|
// 当前所有数据图元(剖面等)合并范围的水平半径(米);无数据返回 0。供底图动态定最大范围。
|
||||||
|
|
@ -197,14 +201,18 @@ private:
|
||||||
std::set<std::string> mapLineDs_;
|
std::set<std::string> mapLineDs_;
|
||||||
|
|
||||||
// ── 可点击方向标 gnomon(T3)──────────────────────────────────────────────────
|
// ── 可点击方向标 gnomon(T3)──────────────────────────────────────────────────
|
||||||
// marker widget(内部叠加渲染器,相机随主相机同步 → 三向标随场景转);SetInteractive(false)
|
// 专用叠加渲染器:图层1、固定右下角视口、InteractiveOff、透明背景、无边框 —— 不是 widget,
|
||||||
// 禁自身拖动/缩放,仅作可点击方向选择器。gnomonPicker_ 在其内部渲染器上做硬件拾取。
|
// 故无外框、不可拖动/缩放;相机由 syncGnomonCamera 镜像主相机朝向 → gizmo 随场景转。
|
||||||
vtkSmartPointer<vtkOrientationMarkerWidget> gnomonWidget_;
|
// gnomonPicker_ 在此渲染器上做硬件拾取(仅方向球可拾取)。
|
||||||
|
vtkSmartPointer<vtkRenderer> gnomonRenderer_;
|
||||||
vtkSmartPointer<vtkPropPicker> gnomonPicker_;
|
vtkSmartPointer<vtkPropPicker> gnomonPicker_;
|
||||||
vtkSmartPointer<vtkCallbackCommand> gnomonClickCmd_; // 左键观察者命令(可条件 SetAbortFlag 消费)
|
vtkSmartPointer<vtkCallbackCommand> gnomonClickCmd_; // 左键观察者命令(可条件 SetAbortFlag 消费)
|
||||||
unsigned long gnomonClickTag_ = 0; // 观察者句柄(析构时摘除)
|
unsigned long gnomonClickTag_ = 0; // 左键观察者句柄(析构时摘除)
|
||||||
|
vtkSmartPointer<vtkCallbackCommand> gnomonCamCmd_; // 主相机 ModifiedEvent 观察者命令
|
||||||
|
unsigned long gnomonCamTag_ = 0; // 相机观察者句柄(析构时摘除)
|
||||||
|
vtkCamera* gnomonObservedCam_ = nullptr; // 被观察的主相机(非拥有;析构摘观察者用)
|
||||||
bool gnomonReady_ = false; // 已装配(幂等 ensureGnomon)
|
bool gnomonReady_ = false; // 已装配(幂等 ensureGnomon)
|
||||||
// 6 个方向球 actor → ViewDir 映射(拾取命中球 → 该方向)。actor 由 marker 组装体持有保活。
|
// 6 个方向球 actor → ViewDir 映射(拾取命中球 → 该方向)。actor 由叠加渲染器持有保活。
|
||||||
std::map<vtkProp*, geopro::controller::ViewDir> gnomonDirs_;
|
std::map<vtkProp*, geopro::controller::ViewDir> gnomonDirs_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue