diff --git a/src/app/TileBasemap.cpp b/src/app/TileBasemap.cpp index 181bee5..6101ddc 100644 --- a/src/app/TileBasemap.cpp +++ b/src/app/TileBasemap.cpp @@ -259,6 +259,7 @@ void TileBasemap::refresh() { } purgeStale(); + ren->ResetCameraClippingRange(); // 交互后扩裁剪面以含新载入的底图瓦片(防被"蒙版"切) if (rw_) rw_->Render(); refreshing_ = false; } @@ -380,7 +381,8 @@ vtkSmartPointer 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 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 diff --git a/src/app/VtkSceneView.cpp b/src/app/VtkSceneView.cpp index 08c4512..248ed28 100644 --- a/src/app/VtkSceneView.cpp +++ b/src/app/VtkSceneView.cpp @@ -5,6 +5,7 @@ #include #include +#include #include #include #include @@ -68,6 +69,18 @@ void VtkSceneView::removeProps(std::vector>& 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(); } diff --git a/src/app/VtkSceneView.hpp b/src/app/VtkSceneView.hpp index b24c600..ae67e60 100644 --- a/src/app/VtkSceneView.hpp +++ b/src/app/VtkSceneView.hpp @@ -66,6 +66,8 @@ private: // 按当前坐标轴设置 + 场景包围盒重建坐标轴 prop(render 末尾调)。 void rebuildAxes(); void removeProps(std::vector>& props); // 从 renderer 移除并清空 + // 仅数据图元(剖面/体素/地形/测线)的包围盒,不含底图 → 坐标轴/取景不被~公里级底图撑大。 + bool computeDataBounds(double out[6]) const; geopro::render::Scene& scene_; vtkRenderWindow* renderWindow_;