fix(vtk): 根治底图被'蒙版'切=远裁剪面忽略底图(UseBounds=false所致);底图改回参与裁剪+坐标轴/取景改用数据自身包围盒,交互后ResetCameraClippingRange含底图

This commit is contained in:
gaozheng 2026-06-17 14:36:26 +08:00
parent 0ac2765fd7
commit 67eaade7bd
3 changed files with 35 additions and 8 deletions

View File

@ -259,6 +259,7 @@ void TileBasemap::refresh() {
}
purgeStale();
ren->ResetCameraClippingRange(); // 交互后扩裁剪面以含新载入的底图瓦片(防被"蒙版"切)
if (rw_) rw_->Render();
refreshing_ = false;
}
@ -380,7 +381,8 @@ vtkSmartPointer<vtkActor> TileBasemap::buildFlat(int z, int x, int y,
actor->SetMapper(mapper);
actor->SetTexture(tex);
actor->GetProperty()->LightingOff(); // 底图不受场景光照
actor->SetUseBounds(false); // 底图不参与包围盒/相机取景:否则坐标轴/适配被~公里级底图撑大
// 注意UseBounds 保持默认 true → 参与相机裁剪面计算,否则底图会被裁剪面"蒙版"切掉。
// 坐标轴/取景不被底图撑大,由 VtkSceneView 改用"数据自身包围盒"解决(非靠 UseBounds=false
return actor;
}
@ -493,8 +495,7 @@ vtkSmartPointer<vtkActor> TileBasemap::buildWarped(int sz, int sx, int sy, int d
actor->SetMapper(mapper);
actor->SetTexture(tex);
actor->GetProperty()->LightingOff();
actor->SetUseBounds(false); // 同 buildFlat底图不参与包围盒/相机取景
return actor;
return actor; // UseBounds 默认 true参与裁剪面避免被"蒙版"切掉
}
} // namespace geopro::app

View File

@ -5,6 +5,7 @@
#include <utility>
#include <vtkActor.h>
#include <vtkBoundingBox.h>
#include <vtkCubeAxesActor.h>
#include <vtkProp.h>
#include <vtkRenderWindow.h>
@ -68,6 +69,18 @@ void VtkSceneView::removeProps(std::vector<vtkSmartPointer<vtkProp>>& props) {
props.clear();
}
bool VtkSceneView::computeDataBounds(double out[6]) const {
vtkBoundingBox bb;
for (const auto& kv : dsProps_)
for (const auto& p : kv.second)
if (p) { if (double* b = p->GetBounds()) bb.AddBounds(b); }
for (const auto& p : miscProps_)
if (p) { if (double* b = p->GetBounds()) bb.AddBounds(b); }
if (!bb.IsValid()) return false;
bb.GetBounds(out);
return true;
}
void VtkSceneView::clear() {
// 只移除数据 prop按 ds 跟踪)+ 杂项(地形/测线)+ 坐标轴;不动底图(TileBasemap 自管)→ 重建不丢图。
for (auto& kv : dsProps_) removeProps(kv.second);
@ -179,7 +192,12 @@ void VtkSceneView::zoom(double factor) {
}
void VtkSceneView::fitView() {
geopro::render::fitView(scene_.renderer());
double bounds[6];
if (computeDataBounds(bounds))
scene_.renderer()->ResetCamera(bounds); // 取景到数据(不含底图)
else
geopro::render::fitView(scene_.renderer());
scene_.renderer()->ResetCameraClippingRange(); // 裁剪面含底图 → 不被"蒙版"切掉
if (renderWindow_) renderWindow_->Render();
}
@ -190,10 +208,10 @@ void VtkSceneView::rebuildAxes() {
scene_.renderer()->RemoveViewProp(currentAxes_);
currentAxes_ = nullptr;
}
// 坐标轴随数据包围盒重建:按已加入的数据图元算 bounds再造 vtkCubeAxesActor 入场。
// None 模式或无内容 → buildAxes 返回 nullptr场景无坐标轴。
// 坐标轴随数据包围盒重建:仅按数据图元算 bounds(不含底图,否则被~公里级底图撑大)
// 再造 vtkCubeAxesActor 入场。None 模式或无数据 → buildAxes 返回 nullptr场景无坐标轴。
double bounds[6];
scene_.renderer()->ComputeVisiblePropBounds(bounds);
if (!computeDataBounds(bounds)) return; // 无数据 → 不建坐标轴
geopro::render::AxesOptions opts;
opts.mode = toRenderMode(axesMode_);
opts.unit = toRenderUnit(axesUnit_);
@ -217,13 +235,19 @@ void VtkSceneView::render(bool is2D) {
geopro::render::applyTop2D(scene_.renderer());
else
geopro::render::applyFree3D(scene_.renderer());
scene_.renderer()->ResetCamera();
double bounds[6];
if (computeDataBounds(bounds))
scene_.renderer()->ResetCamera(bounds); // 取景到数据(不含底图,否则数据缩成小点)
else
scene_.renderer()->ResetCamera();
scene_.renderer()->ResetCameraClippingRange(); // 裁剪面含底图 → 不被"蒙版"切掉
if (renderWindow_) renderWindow_->Render();
}
void VtkSceneView::renderIncremental() {
// 增量渲染:仅按新包围盒重建坐标轴并提交,不动相机(勾选/取消时视角不跳)。
rebuildAxes();
scene_.renderer()->ResetCameraClippingRange(); // 数据/底图变化后扩裁剪面,防被切
if (renderWindow_) renderWindow_->Render();
}

View File

@ -66,6 +66,8 @@ private:
// 按当前坐标轴设置 + 场景包围盒重建坐标轴 proprender 末尾调)。
void rebuildAxes();
void removeProps(std::vector<vtkSmartPointer<vtkProp>>& props); // 从 renderer 移除并清空
// 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。
bool computeDataBounds(double out[6]) const;
geopro::render::Scene& scene_;
vtkRenderWindow* renderWindow_;