feat(3d-view): 二维分析B期(足迹高程Z拖动)+选择联动/滚轮升降/工具条禁用
- B期:二维分析里选中足迹(单击/Ctrl 多选)→ 竖向拖动只改世界 Z(锁 XY)、 顶部实时高程读数浮层;Z 偏移按 dsId 持久(切走再回/全量重建保留)。 VtkSceneView 加 pickMapLineAt/nudgeSelectedMapLinesZ/selectedMapLineZ(vtkCellPicker +PickFromList 只拾可见足迹、选中黄高亮加粗、mapLineZOffset_ 持久);PickInteractorStyle lock2D 下命中足迹→Z 拖动(onPick2D/onDrag2D/onDrag2DEnd + worldPerPixelZ 像素→世界Z); InteractionManager::pickStyle() 暴露样式;main.cpp 接回调 + 读数浮层。 - 列表↔VTK 双向选择联动:Column2DDataset 多选行 + selectedDatasetsChanged/setSelectedDsIds; VtkSceneView onMapLineSelectionChanged/setSelectedMapLines;两向各自断环。 - 滚轮升降:onWheel2D——有选中足迹时滚轮改其 Z(一格≈拖动24px)、消费滚轮,否则缩放; 读数浮层滚轮后 1.2s 自动隐藏。 - 工具条:二维分析激活禁用 6 向快捷视图(会改朝向破坏近俯视锁定),切回三维恢复。
This commit is contained in:
parent
6a10975b6b
commit
bdebe54859
|
|
@ -9,9 +9,10 @@
|
||||||
- **A(已实现 ✅,build+439测试全绿,未提交)**:一场景两相机。切「二维分析」tab → 近俯视(下压12°≈78°俯角)+禁旋转(左键改平移、仅平移/缩放);按维度翻 actor `SetVisibility`(轨迹↔体/帘面/异常,**不清空**);切片 `SetEnabled` 显隐(不销毁);地形+底图常驻;切回三维还原相机快照。**待用户实跑**:①近俯视角度是否合适②切换是否瞬时③左键平移手感④切回三维视角还原是否自然。
|
- **A(已实现 ✅,build+439测试全绿,未提交)**:一场景两相机。切「二维分析」tab → 近俯视(下压12°≈78°俯角)+禁旋转(左键改平移、仅平移/缩放);按维度翻 actor `SetVisibility`(轨迹↔体/帘面/异常,**不清空**);切片 `SetEnabled` 显隐(不销毁);地形+底图常驻;切回三维还原相机快照。**待用户实跑**:①近俯视角度是否合适②切换是否瞬时③左键平移手感④切回三维视角还原是否自然。
|
||||||
- 改动文件:`CameraPreset.{hpp,cpp}`(applyNearTop2D)、`PickInteractorStyle.{hpp,cpp}`(setLock2D)、`SliceTool.{hpp,cpp}`(setVisible)、`InteractionManager.{hpp,cpp}`(setMode2D)、`VtkSceneView.{hpp,cpp}`(setAnalysisMode2D+mapLineDs_+相机快照)、`ColumnDrawer.{hpp,cpp}`(analysisModeChanged 信号)、`main.cpp`(接信号)。
|
- 改动文件:`CameraPreset.{hpp,cpp}`(applyNearTop2D)、`PickInteractorStyle.{hpp,cpp}`(setLock2D)、`SliceTool.{hpp,cpp}`(setVisible)、`InteractionManager.{hpp,cpp}`(setMode2D)、`VtkSceneView.{hpp,cpp}`(setAnalysisMode2D+mapLineDs_+相机快照)、`ColumnDrawer.{hpp,cpp}`(analysisModeChanged 信号)、`main.cpp`(接信号)。
|
||||||
- 已知小风险:2D 取景 `computeDataBounds` 含隐藏的 3D 体包围盒(地形主导,影响小);切片 `SetEnabled` 显隐属 GUI 不可自测项。
|
- 已知小风险:2D 取景 `computeDataBounds` 含隐藏的 3D 体包围盒(地形主导,影响小);切片 `SetEnabled` 显隐属 GUI 不可自测项。
|
||||||
- **B(下一步)**:二维里选中 2D 内容(单/多选)→ 竖向拖动只改**高程 Z**、锁 XY、实时高程读数。锚点:新增 2D 拾取-拖动交互(仅 Z 平移),可参考切片 widget;用 `PickInteractorStyle` 在 lock2D 下保留拾取(A 期为简化已禁拾取,B 期需放开 2D 内容拾取)。
|
- **B(已实现 ✅,build+441测试全绿,未提交,待实跑)**:二维里选中足迹(单/Ctrl 多选)→ 竖向拖动只改**高程 Z**、锁 XY、顶部实时高程读数浮层;Z 偏移按 dsId 持久(切走再回/全量重建保留)。手势:单击足迹=选中、Ctrl+单击=多选切换、点空白=取消+平移、(多)选后竖向拖动=整体改 Z。
|
||||||
- **注意**:A 期 lock2D 下 `OnLeftButtonDown` 直接 StartPan、跳过拾取。B 期要支持选中 2D 内容拖动,需改为「命中 2D 足迹→进入 Z 拖动;否则平移」。
|
- 实现:`VtkSceneView` 加 `pickMapLineAt/nudgeSelectedMapLinesZ/selectedMapLineZ/clearMapLineSelection`(vtkCellPicker+PickFromList 只拾可见足迹、选中高亮黄加粗、`mapLineZOffset_` 持久);`PickInteractorStyle` lock2D 下命中足迹→Z 拖动(`onPick2D/onDrag2D/onDrag2DEnd`+`worldPerPixelZ` 像素→世界Z)、否则平移;`InteractionManager::pickStyle()` 暴露样式;`main.cpp` 接回调 + 高程读数浮层(复用提示样式)。
|
||||||
- **C**:dd_raster 纳入 2D 过滤 + 按 ddCode 分派渲染 + 栅格地理配准贴地形。**阻塞:dd_raster 数据端点未确认**。
|
- **待用户实跑**:①拾取灵敏度(tol 0.012)②拖动 Z 灵敏度/方向(上移=抬高)③多选拖动④读数是否合理(现为 actor 包围盒中心世界 Z,含 placement+偏移,未除 VE)。
|
||||||
|
- **C(下一步)**:dd_raster 纳入 2D 过滤 + 按 ddCode 分派渲染 + 栅格地理配准贴地形。**阻塞:dd_raster 数据端点未确认**(需后端给「像素 + 四至/投影」端点)。
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,9 @@
|
||||||
#include <vtkActor.h>
|
#include <vtkActor.h>
|
||||||
#include <vtkProperty.h>
|
#include <vtkProperty.h>
|
||||||
#include <vtkBoundingBox.h>
|
#include <vtkBoundingBox.h>
|
||||||
|
#include <vtkCellPicker.h>
|
||||||
#include <vtkCubeAxesActor.h>
|
#include <vtkCubeAxesActor.h>
|
||||||
|
#include <vtkNew.h>
|
||||||
#include <vtkProp.h>
|
#include <vtkProp.h>
|
||||||
#include <vtkRenderWindow.h>
|
#include <vtkRenderWindow.h>
|
||||||
#include <vtkRenderer.h>
|
#include <vtkRenderer.h>
|
||||||
|
|
@ -104,7 +106,8 @@ void VtkSceneView::clear() {
|
||||||
// 只移除数据 prop(按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。
|
// 只移除数据 prop(按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。
|
||||||
for (auto& kv : dsProps_) removeProps(kv.second);
|
for (auto& kv : dsProps_) removeProps(kv.second);
|
||||||
dsProps_.clear();
|
dsProps_.clear();
|
||||||
mapLineDs_.clear(); // 2D 足迹维度记录随数据图元一并清(模式标志/相机快照保留)
|
mapLineDs_.clear(); // 2D 足迹维度记录随数据图元一并清(模式标志保留)
|
||||||
|
selectedMapLines_.clear(); // 选中态随图元清(actor 已销毁);Z 偏移 mapLineZOffset_ 保留→重建后复位高度
|
||||||
removeProps(miscProps_);
|
removeProps(miscProps_);
|
||||||
clearAnomalies(); // 异常 actor 随清场一并移除
|
clearAnomalies(); // 异常 actor 随清场一并移除
|
||||||
if (currentAxes_) {
|
if (currentAxes_) {
|
||||||
|
|
@ -193,6 +196,8 @@ void VtkSceneView::addMapLine(const std::string& dsId, const geopro::data::MapLi
|
||||||
auto actor = geopro::render::buildMapLine(line.lat, line.lon, worldZ, *frame_);
|
auto actor = geopro::render::buildMapLine(line.lat, line.lon, worldZ, *frame_);
|
||||||
if (actor) {
|
if (actor) {
|
||||||
actor->SetVisibility(analysisMode2D_ ? 1 : 0); // 足迹=2D内容:仅二维分析下显示
|
actor->SetVisibility(analysisMode2D_ ? 1 : 0); // 足迹=2D内容:仅二维分析下显示
|
||||||
|
auto off = mapLineZOffset_.find(dsId); // B 期:复用持久 Z 偏移(全量重建后仍在该高度)
|
||||||
|
if (off != mapLineZOffset_.end()) actor->AddPosition(0.0, 0.0, off->second);
|
||||||
scene_.addActor(actor);
|
scene_.addActor(actor);
|
||||||
dsProps_[dsId].push_back(actor);
|
dsProps_[dsId].push_back(actor);
|
||||||
mapLineDs_.insert(dsId); // 记录此 ds 为 2D 足迹(切 tab 按维度翻可见)
|
mapLineDs_.insert(dsId); // 记录此 ds 为 2D 足迹(切 tab 按维度翻可见)
|
||||||
|
|
@ -317,6 +322,7 @@ void VtkSceneView::fitView() {
|
||||||
void VtkSceneView::setAnalysisMode2D(bool is2D) {
|
void VtkSceneView::setAnalysisMode2D(bool is2D) {
|
||||||
if (is2D == analysisMode2D_) return; // 幂等:同模式重复切不做事
|
if (is2D == analysisMode2D_) return; // 幂等:同模式重复切不做事
|
||||||
analysisMode2D_ = is2D;
|
analysisMode2D_ = is2D;
|
||||||
|
if (!is2D) clearMapLineSelection(); // 离开二维分析:清足迹选中(三维下不可拖 Z);Z 偏移仍持久
|
||||||
|
|
||||||
// ① 按维度翻可见标志(不清空、不重建→切换瞬时):2D 足迹↔3D 帘面/体;异常属 3D。
|
// ① 按维度翻可见标志(不清空、不重建→切换瞬时):2D 足迹↔3D 帘面/体;异常属 3D。
|
||||||
// 地形/测线(miscProps_)与底图(TileBasemap 自管)两边常驻、不动。
|
// 地形/测线(miscProps_)与底图(TileBasemap 自管)两边常驻、不动。
|
||||||
|
|
@ -335,6 +341,115 @@ void VtkSceneView::setAnalysisMode2D(bool is2D) {
|
||||||
render(/*is2D ViewMode=*/false, /*resetCamera=*/true);
|
render(/*is2D ViewMode=*/false, /*resetCamera=*/true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ── 二维分析改造 B 期:选中 2D 足迹沿高程 Z 拖动 ───────────────────────────────────
|
||||||
|
void VtkSceneView::applyMapLineSelectionVisual() {
|
||||||
|
for (auto& kv : dsProps_) {
|
||||||
|
if (!mapLineDs_.count(kv.first)) continue;
|
||||||
|
const bool sel = selectedMapLines_.count(kv.first) > 0;
|
||||||
|
for (auto& p : kv.second) {
|
||||||
|
auto* a = vtkActor::SafeDownCast(p);
|
||||||
|
if (!a) continue;
|
||||||
|
if (sel) { // 选中:黄高亮 + 加粗
|
||||||
|
a->GetProperty()->SetColor(1.0, 0.85, 0.2);
|
||||||
|
a->GetProperty()->SetLineWidth(6.0);
|
||||||
|
} else { // 未选:复原 buildMapLine 默认(橙 3.0)
|
||||||
|
a->GetProperty()->SetColor(0.95, 0.55, 0.10);
|
||||||
|
a->GetProperty()->SetLineWidth(3.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VtkSceneView::clearMapLineSelection() {
|
||||||
|
if (selectedMapLines_.empty()) return;
|
||||||
|
selectedMapLines_.clear();
|
||||||
|
applyMapLineSelectionVisual();
|
||||||
|
if (renderWindow_) renderWindow_->Render();
|
||||||
|
if (onMapLineSelectionChanged) onMapLineSelectionChanged(); // VTK→列表:同步清空
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::string> VtkSceneView::selectedMapLines() const {
|
||||||
|
return std::vector<std::string>(selectedMapLines_.begin(), selectedMapLines_.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void VtkSceneView::setSelectedMapLines(const std::vector<std::string>& dsIds) {
|
||||||
|
// 列表→VTK:按 dsId 设选中(仅已渲染足迹),高亮+渲染;不回调 onMapLineSelectionChanged(防回环)。
|
||||||
|
selectedMapLines_.clear();
|
||||||
|
for (const auto& id : dsIds)
|
||||||
|
if (mapLineDs_.count(id)) selectedMapLines_.insert(id);
|
||||||
|
applyMapLineSelectionVisual();
|
||||||
|
if (renderWindow_) renderWindow_->Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool VtkSceneView::pickMapLineAt(int screenX, int screenY, bool additive) {
|
||||||
|
auto* ren = scene_.renderer();
|
||||||
|
if (!ren) return false;
|
||||||
|
// 只在"可见足迹"中拾取(PickFromList):避免地形/底图/隐藏的 3D 体抢命中。
|
||||||
|
vtkNew<vtkCellPicker> picker;
|
||||||
|
picker->SetTolerance(0.012);
|
||||||
|
picker->PickFromListOn();
|
||||||
|
bool any = false;
|
||||||
|
for (auto& kv : dsProps_) {
|
||||||
|
if (!mapLineDs_.count(kv.first)) continue;
|
||||||
|
for (auto& p : kv.second)
|
||||||
|
if (p && p->GetVisibility()) { picker->AddPickList(p); any = true; }
|
||||||
|
}
|
||||||
|
if (!any) return false; // 无可见足迹 → 不拦截(交由平移)
|
||||||
|
if (!picker->Pick(screenX, screenY, 0.0, ren)) {
|
||||||
|
if (!additive) clearMapLineSelection(); // 点空白(非多选)→ 取消选中
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
vtkProp* hit = picker->GetViewProp();
|
||||||
|
std::string hitDs;
|
||||||
|
for (auto& kv : dsProps_) {
|
||||||
|
if (!mapLineDs_.count(kv.first)) continue;
|
||||||
|
for (auto& p : kv.second)
|
||||||
|
if (p.Get() == hit) { hitDs = kv.first; break; }
|
||||||
|
if (!hitDs.empty()) break;
|
||||||
|
}
|
||||||
|
if (hitDs.empty()) {
|
||||||
|
if (!additive) clearMapLineSelection();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (additive) { // Ctrl 多选:切换该足迹
|
||||||
|
if (selectedMapLines_.count(hitDs)) selectedMapLines_.erase(hitDs);
|
||||||
|
else selectedMapLines_.insert(hitDs);
|
||||||
|
} else if (!selectedMapLines_.count(hitDs)) { // 单击未选中的线 → 替换为它
|
||||||
|
selectedMapLines_.clear();
|
||||||
|
selectedMapLines_.insert(hitDs);
|
||||||
|
}
|
||||||
|
// 单击已选中的线(可能为多选之一):保持当前选中集 → 起手即可整体拖动,不塌缩为单选。
|
||||||
|
applyMapLineSelectionVisual();
|
||||||
|
if (renderWindow_) renderWindow_->Render();
|
||||||
|
if (onMapLineSelectionChanged) onMapLineSelectionChanged(); // VTK→列表:同步选中
|
||||||
|
return !selectedMapLines_.empty(); // 有选中 → 交互样式进入 Z 拖动
|
||||||
|
}
|
||||||
|
|
||||||
|
void VtkSceneView::nudgeSelectedMapLinesZ(double worldDz) {
|
||||||
|
if (selectedMapLines_.empty() || worldDz == 0.0) return;
|
||||||
|
for (const auto& dsId : selectedMapLines_) {
|
||||||
|
mapLineZOffset_[dsId] += worldDz; // 持久累计(全量重建后 addMapLine 复用)
|
||||||
|
auto it = dsProps_.find(dsId);
|
||||||
|
if (it == dsProps_.end()) continue;
|
||||||
|
for (auto& p : it->second) {
|
||||||
|
auto* a = vtkActor::SafeDownCast(p);
|
||||||
|
if (a) a->AddPosition(0.0, 0.0, worldDz); // 仅改 Z,锁 XY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (scene_.renderer()) scene_.renderer()->ResetCameraClippingRange(); // Z 抬升后防被裁剪面切
|
||||||
|
if (renderWindow_) renderWindow_->Render();
|
||||||
|
}
|
||||||
|
|
||||||
|
double VtkSceneView::selectedMapLineZ() const {
|
||||||
|
if (selectedMapLines_.empty()) return 0.0;
|
||||||
|
// 代表性 Z = 任一选中足迹 actor 的包围盒中心 Z(含 placement worldZ + 已累计偏移)。
|
||||||
|
auto it = dsProps_.find(*selectedMapLines_.begin());
|
||||||
|
if (it == dsProps_.end()) return 0.0;
|
||||||
|
for (const auto& p : it->second)
|
||||||
|
if (p) { if (double* b = p->GetBounds()) return 0.5 * (b[4] + b[5]); }
|
||||||
|
return 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
void VtkSceneView::rebuildAxes() {
|
void VtkSceneView::rebuildAxes() {
|
||||||
// 先移除上一次的坐标轴 prop:render 可能在一次 rebuild 内多次调用(末尾统一 render +
|
// 先移除上一次的坐标轴 prop:render 可能在一次 rebuild 内多次调用(末尾统一 render +
|
||||||
// 异步回灌 render),不先移除会叠加坐标轴(评审 HIGH)。移除后再算 bounds(仅数据图元)。
|
// 异步回灌 render),不先移除会叠加坐标轴(评审 HIGH)。移除后再算 bounds(仅数据图元)。
|
||||||
|
|
|
||||||
|
|
@ -90,6 +90,22 @@ public:
|
||||||
void setAnalysisMode2D(bool is2D);
|
void setAnalysisMode2D(bool is2D);
|
||||||
bool isAnalysisMode2D() const { return analysisMode2D_; }
|
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<std::string> selectedMapLines() const;
|
||||||
|
void setSelectedMapLines(const std::vector<std::string>& dsIds);
|
||||||
|
std::function<void()> onMapLineSelectionChanged;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 首个带经纬数据(剖面/足迹)到达时把共享 frame 重锚到其 lat/lon 包围盒中心:使数据落在世界原点近旁
|
// 首个带经纬数据(剖面/足迹)到达时把共享 frame 重锚到其 lat/lon 包围盒中心:使数据落在世界原点近旁
|
||||||
// (否则样本默认原点可能离真实数据数百公里→图元在视锥外、移动视角也找不到)。已锚或无经纬则跳过。
|
// (否则样本默认原点可能离真实数据数百公里→图元在视锥外、移动视角也找不到)。已锚或无经纬则跳过。
|
||||||
|
|
@ -159,6 +175,11 @@ private:
|
||||||
// 哪些 dsProps_ 条目是 2D 足迹(addMapLine):切 tab 按此区分维度翻可见(其余 dsProps_=帘面/体=3D)。
|
// 哪些 dsProps_ 条目是 2D 足迹(addMapLine):切 tab 按此区分维度翻可见(其余 dsProps_=帘面/体=3D)。
|
||||||
std::set<std::string> mapLineDs_;
|
std::set<std::string> mapLineDs_;
|
||||||
bool analysisMode2D_ = false; // 当前是否处二维分析(默认三维:启动在「三维分析」tab)
|
bool analysisMode2D_ = false; // 当前是否处二维分析(默认三维:启动在「三维分析」tab)
|
||||||
|
|
||||||
|
// B 期:选中的足迹 dsId(Z 拖动目标) + 各足迹累计 Z 偏移(持久,全量重建后 addMapLine 复用)。
|
||||||
|
std::set<std::string> selectedMapLines_;
|
||||||
|
std::map<std::string, double> mapLineZOffset_;
|
||||||
|
void applyMapLineSelectionVisual(); // 选中足迹加粗变亮、其余复原(橙 3.0)
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -61,8 +61,9 @@ VtkViewToolbar::VtkViewToolbar(QWidget* parent) : QWidget(parent) {
|
||||||
{"下", ViewDir::Bottom}, {"左", ViewDir::Left}, {"右", ViewDir::Right}};
|
{"下", ViewDir::Bottom}, {"左", ViewDir::Left}, {"右", ViewDir::Right}};
|
||||||
for (const V& v : views) {
|
for (const V& v : views) {
|
||||||
const ViewDir d = v.d;
|
const ViewDir d = v.d;
|
||||||
connect(textBtn(QString::fromUtf8(v.t)), &QToolButton::clicked, this,
|
auto* b = textBtn(QString::fromUtf8(v.t));
|
||||||
[this, d] { emit viewRequested(d); });
|
connect(b, &QToolButton::clicked, this, [this, d] { emit viewRequested(d); });
|
||||||
|
viewDirButtons_.push_back(b); // 二维分析下禁用(会改朝向、破坏近俯视锁定)
|
||||||
}
|
}
|
||||||
sep();
|
sep();
|
||||||
// ── 段3:缩放 / 复位 ──
|
// ── 段3:缩放 / 复位 ──
|
||||||
|
|
@ -84,4 +85,12 @@ VtkViewToolbar::VtkViewToolbar(QWidget* parent) : QWidget(parent) {
|
||||||
adjustSize();
|
adjustSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void VtkViewToolbar::setAnalysisMode2D(bool is2D) {
|
||||||
|
for (auto* b : viewDirButtons_) {
|
||||||
|
if (!b) continue;
|
||||||
|
b->setEnabled(!is2D);
|
||||||
|
b->setToolTip(is2D ? QStringLiteral("二维分析下不可用(已锁定近俯视)") : QString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,10 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
#include <vector>
|
||||||
#include "I3dSceneView.hpp" // geopro::controller::ViewDir
|
#include "I3dSceneView.hpp" // geopro::controller::ViewDir
|
||||||
|
|
||||||
|
class QToolButton;
|
||||||
|
|
||||||
namespace geopro::app {
|
namespace geopro::app {
|
||||||
|
|
||||||
// VTK 画布竖排工具条(spec §9):全局视图控制——设置(坐标轴)/前后上下左右/放大缩小复位。
|
// VTK 画布竖排工具条(spec §9):全局视图控制——设置(坐标轴)/前后上下左右/放大缩小复位。
|
||||||
|
|
@ -11,12 +14,20 @@ class VtkViewToolbar : public QWidget {
|
||||||
public:
|
public:
|
||||||
explicit VtkViewToolbar(QWidget* parent = nullptr);
|
explicit VtkViewToolbar(QWidget* parent = nullptr);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
// 二维分析激活时禁用不适用的工具:6 向快捷视图会改相机朝向→破坏二维近俯视锁定,故二维下禁用;
|
||||||
|
// 缩放/适配/坐标轴设置(含 VE)仍可用。切回三维恢复。
|
||||||
|
void setAnalysisMode2D(bool is2D);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void axesSettingsRequested(); // 设置 → 弹 AxesSettingsDialog
|
void axesSettingsRequested(); // 设置 → 弹 AxesSettingsDialog
|
||||||
void viewRequested(geopro::controller::ViewDir dir); // 前/后/上/下/左/右
|
void viewRequested(geopro::controller::ViewDir dir); // 前/后/上/下/左/右
|
||||||
void zoomInRequested();
|
void zoomInRequested();
|
||||||
void zoomOutRequested();
|
void zoomOutRequested();
|
||||||
void fitRequested(); // 复位=适配
|
void fitRequested(); // 复位=适配
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::vector<QToolButton*> viewDirButtons_; // 6 向快捷视图按钮:二维分析下禁用
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -152,6 +152,7 @@
|
||||||
#include "Scene.hpp"
|
#include "Scene.hpp"
|
||||||
#include "VoxelFromScatters.hpp"
|
#include "VoxelFromScatters.hpp"
|
||||||
#include "interact/InteractionManager.hpp"
|
#include "interact/InteractionManager.hpp"
|
||||||
|
#include "interact/PickInteractorStyle.hpp"
|
||||||
#include "interact/SlicePlaneMath.hpp"
|
#include "interact/SlicePlaneMath.hpp"
|
||||||
#include "actors/AnomalyActor.hpp"
|
#include "actors/AnomalyActor.hpp"
|
||||||
#include "actors/CurtainActor.hpp"
|
#include "actors/CurtainActor.hpp"
|
||||||
|
|
@ -410,6 +411,62 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
"border:1px solid {{accent/primary}};padding:8px 12px;}"));
|
"border:1px solid {{accent/primary}};padding:8px 12px;}"));
|
||||||
anomalyHint->hide();
|
anomalyHint->hide();
|
||||||
|
|
||||||
|
// ── 二维分析 B 期:高程 Z 拖动读数浮层(顶部居中)+ 足迹拾取/拖动回调注入交互样式 ──────────
|
||||||
|
// 拖动选中足迹时显示其当前世界 Z,松开隐藏;不挡画布鼠标。深底方角(同异常提示坑规避)。
|
||||||
|
auto* elevHint = new QLabel(vtkWidget);
|
||||||
|
elevHint->setObjectName(QStringLiteral("elevHint"));
|
||||||
|
elevHint->setAttribute(Qt::WA_TransparentForMouseEvents);
|
||||||
|
geopro::app::applyTokenizedStyleSheet(
|
||||||
|
elevHint, QStringLiteral("QLabel#elevHint{background:#0E1A2D;color:#E6ECF5;"
|
||||||
|
"border:1px solid {{accent/primary}};padding:6px 12px;}"));
|
||||||
|
elevHint->hide();
|
||||||
|
// 滚轮升降时读数浮层 1.2s 后自动隐藏(拖动则在松开时隐藏)。
|
||||||
|
auto* zHideTimer = new QTimer(vtkWidget);
|
||||||
|
zHideTimer->setSingleShot(true);
|
||||||
|
QObject::connect(zHideTimer, &QTimer::timeout, elevHint, [elevHint]() { elevHint->hide(); });
|
||||||
|
auto showZReadout = std::make_shared<std::function<void()>>([sceneView, elevHint, vtkWidget]() {
|
||||||
|
elevHint->setText(
|
||||||
|
QStringLiteral("高程 Z:%1 m").arg(sceneView->selectedMapLineZ(), 0, 'f', 1));
|
||||||
|
elevHint->adjustSize();
|
||||||
|
elevHint->move((vtkWidget->width() - elevHint->width()) / 2, 12); // 顶部居中
|
||||||
|
elevHint->show();
|
||||||
|
elevHint->raise();
|
||||||
|
});
|
||||||
|
if (auto* style = interactionMgr->pickStyle()) {
|
||||||
|
// 命中可见足迹→选中(Ctrl 多选)并返回是否进入 Z 拖动;未命中(返回 false)→交互样式回退平移。
|
||||||
|
style->onPick2D = [sceneView](int x, int y, bool additive) {
|
||||||
|
return sceneView->pickMapLineAt(x, y, additive);
|
||||||
|
};
|
||||||
|
// 拖动中:施加世界 Z 增量(仅改 Z),并把选中足迹当前高程显示在顶部读数浮层。
|
||||||
|
style->onDrag2D = [sceneView, showZReadout](double worldDz) {
|
||||||
|
sceneView->nudgeSelectedMapLinesZ(worldDz);
|
||||||
|
(*showZReadout)();
|
||||||
|
};
|
||||||
|
style->onDrag2DEnd = [elevHint]() { elevHint->hide(); };
|
||||||
|
// 滚轮升降:有选中足迹则施加 Z 增量并显示读数(1.2s 后自动隐藏),返回 true 消费滚轮;否则缩放。
|
||||||
|
style->onWheel2D = [sceneView, showZReadout, zHideTimer](double worldDz) {
|
||||||
|
if (!sceneView->hasMapLineSelection()) return false;
|
||||||
|
sceneView->nudgeSelectedMapLinesZ(worldDz);
|
||||||
|
(*showZReadout)();
|
||||||
|
zHideTimer->start(1200);
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
// 双向选择联动:列表行选中 ↔ VTK 足迹高亮。两向各自屏蔽回环(setSelectedMapLines 不回调、
|
||||||
|
// setSelectedDsIds 屏蔽信号),故无需额外守卫。
|
||||||
|
QObject::connect(drawer->col2D(), &geopro::app::Column2DDataset::selectedDatasetsChanged, &window,
|
||||||
|
[sceneView](const QStringList& ids) {
|
||||||
|
std::vector<std::string> v;
|
||||||
|
for (const QString& s : ids) v.push_back(s.toStdString());
|
||||||
|
sceneView->setSelectedMapLines(v);
|
||||||
|
});
|
||||||
|
sceneView->onMapLineSelectionChanged = [sceneView, drawer]() {
|
||||||
|
QStringList ids;
|
||||||
|
for (const std::string& s : sceneView->selectedMapLines())
|
||||||
|
ids << QString::fromStdString(s);
|
||||||
|
drawer->col2D()->setSelectedDsIds(ids);
|
||||||
|
};
|
||||||
|
|
||||||
// 坐标轴设置抽屉面板:叠加 vtkWidget、工具条右侧滑出,默认隐藏(点设置 toggle)。
|
// 坐标轴设置抽屉面板:叠加 vtkWidget、工具条右侧滑出,默认隐藏(点设置 toggle)。
|
||||||
auto* axesPanel = new geopro::app::AxesSettingsPanel(vtkWidget);
|
auto* axesPanel = new geopro::app::AxesSettingsPanel(vtkWidget);
|
||||||
axesPanel->hide();
|
axesPanel->hide();
|
||||||
|
|
@ -1084,10 +1141,11 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// 渲染 [VtkSceneView]。顺序:先 ①②(都不渲染),最后 ③ 收尾统一渲染。只翻可见标志、不清空/重建 →
|
// 渲染 [VtkSceneView]。顺序:先 ①②(都不渲染),最后 ③ 收尾统一渲染。只翻可见标志、不清空/重建 →
|
||||||
// 切换瞬时;地形+底图常驻。
|
// 切换瞬时;地形+底图常驻。
|
||||||
QObject::connect(drawer, &geopro::app::ColumnDrawer::analysisModeChanged, &window,
|
QObject::connect(drawer, &geopro::app::ColumnDrawer::analysisModeChanged, &window,
|
||||||
[interactionMgr, sceneCtrl, sceneView](bool is2D) {
|
[interactionMgr, sceneCtrl, sceneView, viewToolbar](bool is2D) {
|
||||||
interactionMgr->setMode2D(is2D);
|
interactionMgr->setMode2D(is2D);
|
||||||
sceneCtrl->onAnalysisModeChanged(is2D);
|
sceneCtrl->onAnalysisModeChanged(is2D);
|
||||||
sceneView->setAnalysisMode2D(is2D);
|
sceneView->setAnalysisMode2D(is2D);
|
||||||
|
viewToolbar->setAnalysisMode2D(is2D); // 二维下禁用 6 向快捷视图
|
||||||
});
|
});
|
||||||
|
|
||||||
// 首个真实剖面到达 → frame 重锚到数据 lat/lon 后,把选中的底图加载到数据所在位置
|
// 首个真实剖面到达 → frame 重锚到数据 lat/lon 后,把选中的底图加载到数据所在位置
|
||||||
|
|
|
||||||
|
|
@ -72,6 +72,7 @@ Column2DDataset::Column2DDataset(QWidget* parent) : QWidget(parent) {
|
||||||
list_ = new QTreeWidget();
|
list_ = new QTreeWidget();
|
||||||
list_->setHeaderHidden(true);
|
list_->setHeaderHidden(true);
|
||||||
list_->setRootIsDecorated(true);
|
list_->setRootIsDecorated(true);
|
||||||
|
list_->setSelectionMode(QAbstractItemView::ExtendedSelection); // 多选行(与 VTK 多选拖动联动)
|
||||||
applyDatasetCardDelegate(list_);
|
applyDatasetCardDelegate(list_);
|
||||||
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) {
|
connect(list_, &QTreeWidget::itemChanged, this, [this](QTreeWidgetItem*, int) {
|
||||||
QStringList ids;
|
QStringList ids;
|
||||||
|
|
@ -81,6 +82,13 @@ Column2DDataset::Column2DDataset(QWidget* parent) : QWidget(parent) {
|
||||||
}
|
}
|
||||||
emit checkedDatasetsChanged(ids);
|
emit checkedDatasetsChanged(ids);
|
||||||
});
|
});
|
||||||
|
// 行选中变化 → 上抛选中 dsId(高亮联动 VTK;与勾选/渲染独立)。
|
||||||
|
connect(list_, &QTreeWidget::itemSelectionChanged, this, [this]() {
|
||||||
|
QStringList ids;
|
||||||
|
for (QTreeWidgetItem* it : list_->selectedItems())
|
||||||
|
ids << it->data(0, kDsIdRole).toString();
|
||||||
|
emit selectedDatasetsChanged(ids);
|
||||||
|
});
|
||||||
root->addWidget(list_, 1);
|
root->addWidget(list_, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -111,4 +119,11 @@ void Column2DDataset::setDatasets(const std::vector<geopro::data::DsRow>& rows)
|
||||||
emit checkedDatasetsChanged(ids);
|
emit checkedDatasetsChanged(ids);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Column2DDataset::setSelectedDsIds(const QStringList& dsIds) {
|
||||||
|
QSignalBlocker blocker(list_); // 防回环:VTK→列表 设置选中不再上抛 selectedDatasetsChanged
|
||||||
|
list_->clearSelection();
|
||||||
|
for (QTreeWidgetItemIterator it(list_); *it; ++it)
|
||||||
|
if (dsIds.contains((*it)->data(0, kDsIdRole).toString())) (*it)->setSelected(true);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace geopro::app
|
} // namespace geopro::app
|
||||||
|
|
|
||||||
|
|
@ -14,12 +14,15 @@ class Column2DDataset : public QWidget {
|
||||||
public:
|
public:
|
||||||
explicit Column2DDataset(QWidget* parent = nullptr);
|
explicit Column2DDataset(QWidget* parent = nullptr);
|
||||||
void setDatasets(const std::vector<geopro::data::DsRow>& rows);
|
void setDatasets(const std::vector<geopro::data::DsRow>& rows);
|
||||||
|
// VTK→列表 选择联动:按 dsId 选中对应行(高亮),内部屏蔽信号避免回环。
|
||||||
|
void setSelectedDsIds(const QStringList& dsIds);
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void basemapChanged(int index); // 0 天地图 / 1 Google / 2 隐藏
|
void basemapChanged(int index); // 0 天地图 / 1 Google / 2 隐藏
|
||||||
void view2DModeChanged(int index); // 0 关闭 /1 Z=0 /2 顶部 /3 底部 /4 自定义
|
void view2DModeChanged(int index); // 0 关闭 /1 Z=0 /2 顶部 /3 底部 /4 自定义
|
||||||
void customZChanged(double z); // 世界绝对高程(米),向上为正
|
void customZChanged(double z); // 世界绝对高程(米),向上为正
|
||||||
void checkedDatasetsChanged(const QStringList& dsIds);
|
void checkedDatasetsChanged(const QStringList& dsIds); // 勾选(渲染开关)变化
|
||||||
|
void selectedDatasetsChanged(const QStringList& dsIds); // 行选中(高亮联动)变化,非勾选
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTreeWidget* list_ = nullptr;
|
QTreeWidget* list_ = nullptr;
|
||||||
|
|
|
||||||
|
|
@ -260,6 +260,8 @@ void InteractionManager::closeAll() {
|
||||||
safeRender();
|
safeRender();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PickInteractorStyle* InteractionManager::pickStyle() const { return style_; }
|
||||||
|
|
||||||
void InteractionManager::setMode2D(bool is2D) {
|
void InteractionManager::setMode2D(bool is2D) {
|
||||||
// 切片属三维内容:二维分析隐藏(不销毁→切回零重建)、三维分析显示。
|
// 切片属三维内容:二维分析隐藏(不销毁→切回零重建)、三维分析显示。
|
||||||
for (auto& s : slices_)
|
for (auto& s : slices_)
|
||||||
|
|
|
||||||
|
|
@ -112,6 +112,10 @@ public:
|
||||||
void installStyle();
|
void installStyle();
|
||||||
void uninstallStyle();
|
void uninstallStyle();
|
||||||
|
|
||||||
|
// 暴露交互样式:供 app 层注入二维分析 B 期的足迹拾取/Z 拖动回调(onPick2D/onDrag2D/onDrag2DEnd)。
|
||||||
|
// 定义在 .cpp(此处 PickInteractorStyle 仅前置声明,vtkSmartPointer→裸指针下转需完整类型)。
|
||||||
|
PickInteractorStyle* pickStyle() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// 拾取回调实现(PickInteractorStyle 注入)。
|
// 拾取回调实现(PickInteractorStyle 注入)。
|
||||||
void onPicked(const Vec3& worldPoint); // 选中所在切片 + 焦点
|
void onPicked(const Vec3& worldPoint); // 选中所在切片 + 焦点
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
#include "interact/PickInteractorStyle.hpp"
|
#include "interact/PickInteractorStyle.hpp"
|
||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
#include <vtkCallbackCommand.h>
|
#include <vtkCallbackCommand.h>
|
||||||
#include <vtkCamera.h>
|
#include <vtkCamera.h>
|
||||||
|
|
@ -48,12 +49,19 @@ bool PickInteractorStyle::pickWorld(Vec3& out) {
|
||||||
|
|
||||||
void PickInteractorStyle::OnLeftButtonDown() {
|
void PickInteractorStyle::OnLeftButtonDown() {
|
||||||
auto* iren = this->GetInteractor();
|
auto* iren = this->GetInteractor();
|
||||||
// 二维分析:左键拖动=平移(等同中键),不拾取/不旋转 → 仅平移+缩放。抬键由基类按 State 收尾。
|
// 二维分析:左键命中足迹→进入高程 Z 拖动(B 期);否则=平移(等同中键),禁旋转。抬键由 OnLeftButtonUp 收尾。
|
||||||
if (lock2D_) {
|
if (lock2D_) {
|
||||||
const int* p = iren ? iren->GetEventPosition() : nullptr;
|
const int* p = iren ? iren->GetEventPosition() : nullptr;
|
||||||
if (p) this->FindPokedRenderer(p[0], p[1]);
|
if (p) this->FindPokedRenderer(p[0], p[1]);
|
||||||
if (!this->CurrentRenderer) return;
|
if (!this->CurrentRenderer) return;
|
||||||
this->GrabFocus(this->EventCallbackCommand);
|
const bool additive = iren && iren->GetControlKey(); // Ctrl=多选
|
||||||
|
if (onPick2D && p && onPick2D(p[0], p[1], additive)) { // 命中足迹 → Z 拖动
|
||||||
|
dragging2D_ = true;
|
||||||
|
lastDragY_ = p[1];
|
||||||
|
this->GrabFocus(this->EventCallbackCommand);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this->GrabFocus(this->EventCallbackCommand); // 未命中 → 平移
|
||||||
this->StartPan();
|
this->StartPan();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -137,12 +145,62 @@ void PickInteractorStyle::Rotate() {
|
||||||
rwi->Render();
|
rwi->Render();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
double PickInteractorStyle::worldPerPixelZ() const {
|
||||||
|
if (!this->CurrentRenderer) return 1.0;
|
||||||
|
auto* cam = this->CurrentRenderer->GetActiveCamera();
|
||||||
|
auto* rw = this->CurrentRenderer->GetRenderWindow();
|
||||||
|
if (!cam || !rw) return 1.0;
|
||||||
|
const int* sz = rw->GetSize();
|
||||||
|
const double h = (sz && sz[1] > 0) ? static_cast<double>(sz[1]) : 800.0;
|
||||||
|
if (cam->GetParallelProjection())
|
||||||
|
return 2.0 * cam->GetParallelScale() / h; // 平行投影:可见世界高度=2*parallelScale
|
||||||
|
// 透视:可见世界高度 = 2*d*tan(viewAngle/2),d=相机到焦点距离。
|
||||||
|
double pos[3], fp[3];
|
||||||
|
cam->GetPosition(pos);
|
||||||
|
cam->GetFocalPoint(fp);
|
||||||
|
const double dx = pos[0] - fp[0], dy = pos[1] - fp[1], dz = pos[2] - fp[2];
|
||||||
|
const double d = std::sqrt(dx * dx + dy * dy + dz * dz);
|
||||||
|
const double va = vtkMath::RadiansFromDegrees(cam->GetViewAngle());
|
||||||
|
return 2.0 * d * std::tan(va * 0.5) / h;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PickInteractorStyle::OnMouseMove() {
|
||||||
|
if (dragging2D_) { // B 期:竖向拖动 → 选中足迹 Z 增量(仅改 Z)。鼠标上移(y 增)→ 抬高。
|
||||||
|
auto* rwi = this->Interactor;
|
||||||
|
if (rwi) {
|
||||||
|
const int y = rwi->GetEventPosition()[1];
|
||||||
|
const int dyPix = y - lastDragY_;
|
||||||
|
lastDragY_ = y;
|
||||||
|
if (dyPix != 0 && onDrag2D) onDrag2D(worldPerPixelZ() * dyPix);
|
||||||
|
}
|
||||||
|
return; // 不走基类(不平移/不旋转)
|
||||||
|
}
|
||||||
|
Superclass::OnMouseMove();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PickInteractorStyle::OnLeftButtonUp() {
|
||||||
|
if (dragging2D_) { // 结束 Z 拖动
|
||||||
|
dragging2D_ = false;
|
||||||
|
if (this->Interactor) this->ReleaseFocus();
|
||||||
|
if (onDrag2DEnd) onDrag2DEnd();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Superclass::OnLeftButtonUp(); // 平移/旋转/缩放等由基类按 State 收尾
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
constexpr double kWheelStepPx = 24.0; // 滚轮一格升降 ≈ 拖动 24 像素的世界 Z 量(与拖动手感一致)
|
||||||
|
}
|
||||||
|
|
||||||
void PickInteractorStyle::OnMouseWheelForward() {
|
void PickInteractorStyle::OnMouseWheelForward() {
|
||||||
|
// 二维分析有选中足迹 → 滚轮抬升其高程(消费滚轮);否则按切片推进 / 默认缩放。
|
||||||
|
if (lock2D_ && onWheel2D && onWheel2D(worldPerPixelZ() * kWheelStepPx)) return;
|
||||||
if (onWheelStep && onWheelStep(+1)) return; // 有选中切片 → 推进,消费滚轮
|
if (onWheelStep && onWheelStep(+1)) return; // 有选中切片 → 推进,消费滚轮
|
||||||
Superclass::OnMouseWheelForward(); // 否则默认缩放
|
Superclass::OnMouseWheelForward(); // 否则默认缩放
|
||||||
}
|
}
|
||||||
|
|
||||||
void PickInteractorStyle::OnMouseWheelBackward() {
|
void PickInteractorStyle::OnMouseWheelBackward() {
|
||||||
|
if (lock2D_ && onWheel2D && onWheel2D(-worldPerPixelZ() * kWheelStepPx)) return;
|
||||||
if (onWheelStep && onWheelStep(-1)) return;
|
if (onWheelStep && onWheelStep(-1)) return;
|
||||||
Superclass::OnMouseWheelBackward();
|
Superclass::OnMouseWheelBackward();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -35,6 +35,19 @@ public:
|
||||||
void setLock2D(bool on) { lock2D_ = on; }
|
void setLock2D(bool on) { lock2D_ = on; }
|
||||||
bool isLock2D() const { return lock2D_; }
|
bool isLock2D() const { return lock2D_; }
|
||||||
|
|
||||||
|
// ── 二维分析 B 期:选中足迹沿高程 Z 拖动 ──(仅 lock2D 下生效;回调由 app 层注入)
|
||||||
|
// onPick2D:左键按下时在(x,y)拾取足迹(additive=Ctrl 多选),返回是否有选中→有则进入 Z 拖动、否则平移。
|
||||||
|
// onDrag2D:拖动中把竖向像素换算成的世界 Z 增量(本类按相机算)交给 app 施加到选中足迹(仅改 Z)。
|
||||||
|
// onDrag2DEnd:松开结束拖动(供 app 收起高程读数浮层)。
|
||||||
|
std::function<bool(int x, int y, bool additive)> onPick2D;
|
||||||
|
std::function<void(double worldDz)> onDrag2D;
|
||||||
|
std::function<void()> onDrag2DEnd;
|
||||||
|
// 滚轮升降:有选中足迹时滚轮改其高程 Z(本类按相机算 worldDz);app 施加并返回是否消费(无选中→false→默认缩放)。
|
||||||
|
std::function<bool(double worldDz)> onWheel2D;
|
||||||
|
|
||||||
|
void OnMouseMove() override;
|
||||||
|
void OnLeftButtonUp() override;
|
||||||
|
|
||||||
void OnLeftButtonDown() override;
|
void OnLeftButtonDown() override;
|
||||||
void OnMouseWheelForward() override;
|
void OnMouseWheelForward() override;
|
||||||
void OnMouseWheelBackward() override;
|
void OnMouseWheelBackward() override;
|
||||||
|
|
@ -48,6 +61,8 @@ protected:
|
||||||
private:
|
private:
|
||||||
// 在当前鼠标位置拾取世界点;命中返回 true 并填 out。
|
// 在当前鼠标位置拾取世界点;命中返回 true 并填 out。
|
||||||
bool pickWorld(Vec3& out);
|
bool pickWorld(Vec3& out);
|
||||||
|
// 当前相机下:竖向一屏幕像素对应的世界 Z(米/像素),用于把拖动像素换算成 Z 增量。
|
||||||
|
double worldPerPixelZ() const;
|
||||||
|
|
||||||
// 手动双击判定:QVTK+Windows 下 vtkRenderWindowInteractor::GetRepeatCount() 不可靠(评审 M5)。
|
// 手动双击判定:QVTK+Windows 下 vtkRenderWindowInteractor::GetRepeatCount() 不可靠(评审 M5)。
|
||||||
// 记上次左键按下时刻+屏幕位置,两次按下间隔 < kDoubleClickMs 且位置相近视为双击。
|
// 记上次左键按下时刻+屏幕位置,两次按下间隔 < kDoubleClickMs 且位置相近视为双击。
|
||||||
|
|
@ -56,6 +71,10 @@ private:
|
||||||
|
|
||||||
// 二维分析模式:左键=平移、禁旋转(仅平移+缩放)。由 InteractionManager 在切 tab 时设。
|
// 二维分析模式:左键=平移、禁旋转(仅平移+缩放)。由 InteractionManager 在切 tab 时设。
|
||||||
bool lock2D_ = false;
|
bool lock2D_ = false;
|
||||||
|
|
||||||
|
// B 期足迹 Z 拖动状态:左键命中足迹时进入,记上次鼠标 y 以算增量。
|
||||||
|
bool dragging2D_ = false;
|
||||||
|
int lastDragY_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace geopro::render::interact
|
} // namespace geopro::render::interact
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue