fix(render): 地形高程按测线地表基准 rebase + 切片改左键拖动移动切面
- 反馈1 地形浮空/偏位: 诊断确认 DEM 是 WGS84 经纬度(26x10, 覆盖~700x330m), 测线仅~70m 在其南缘 (横向"偏"实为地形覆盖远大于测线, 地理正确); 纵向浮空因地形用绝对高程(16-95m) vs 帘面深度。 → buildTerrain 加 zOffset(从高程减基准), app 传测线地表高程中位数 refElev, 使地形落在测线附近。 完整 Z 基准统一(与帘面/体素夸张一致)仍属 spec M-3 待办。 - 反馈2 切片交互: vtkImagePlaneWidget 默认左键=取值光标(十字), 不直观; 改 左键=移动切面 (VTK_SLICE_MOTION_ACTION)、中键=取值。现在左键拖动直接滑动切面。 - 全 40 测试绿; app 构建干净。
This commit is contained in:
parent
7007619bf2
commit
f57291a127
|
|
@ -167,6 +167,8 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
const double lat0 = median(baseGrid.lat);
|
const double lat0 = median(baseGrid.lat);
|
||||||
const double lon0 = median(baseGrid.lon);
|
const double lon0 = median(baseGrid.lon);
|
||||||
auto frame = std::make_shared<geopro::core::GeoLocalFrame>(lat0, lon0);
|
auto frame = std::make_shared<geopro::core::GeoLocalFrame>(lat0, lon0);
|
||||||
|
// 测线地表高程基准(地形 z rebase 用,使地形落在测线附近而非按绝对高程浮空)。
|
||||||
|
const double refElev = baseGrid.elevation.empty() ? 0.0 : median(baseGrid.elevation);
|
||||||
|
|
||||||
// ── 中央 QVTK + Scene(竖直帘面场景)─────────────────────────────────
|
// ── 中央 QVTK + Scene(竖直帘面场景)─────────────────────────────────
|
||||||
// Scene 非 QObject:堆分配,用 widget 销毁信号清理(widget 随 window 销毁)。
|
// Scene 非 QObject:堆分配,用 widget 销毁信号清理(widget 随 window 销毁)。
|
||||||
|
|
@ -348,7 +350,7 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
// frame/structure 全局共享;切视图/勾选变化都调用此函数重建当前视图。
|
// frame/structure 全局共享;切视图/勾选变化都调用此函数重建当前视图。
|
||||||
auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree,
|
auto rebuildCentral = [scene, rendererPtr, renderWindowPtr, viewMode, &repo, frame, tree,
|
||||||
structure, showCurtain, showVoxel, showTerrain, showSlice, slicePlane,
|
structure, showCurtain, showVoxel, showTerrain, showSlice, slicePlane,
|
||||||
crs]() {
|
crs, refElev]() {
|
||||||
// 先拆除上次的切片 widget(独立于 scene actor,须显式关闭),再按条件重建。
|
// 先拆除上次的切片 widget(独立于 scene actor,须显式关闭),再按条件重建。
|
||||||
if (*slicePlane) { (*slicePlane)->Off(); *slicePlane = nullptr; }
|
if (*slicePlane) { (*slicePlane)->Off(); *slicePlane = nullptr; }
|
||||||
scene->clear();
|
scene->clear();
|
||||||
|
|
@ -416,6 +418,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
plane->SetSliceIndex(dims[0] / 2);
|
plane->SetSliceIndex(dims[0] / 2);
|
||||||
plane->SetLookupTable(lut);
|
plane->SetLookupTable(lut);
|
||||||
plane->DisplayTextOn();
|
plane->DisplayTextOn();
|
||||||
|
// 左键拖动=移动切面(默认左键是取值光标十字,不直观);中键仍可取值。
|
||||||
|
plane->SetLeftButtonAction(vtkImagePlaneWidget::VTK_SLICE_MOTION_ACTION);
|
||||||
|
plane->SetMiddleButtonAction(vtkImagePlaneWidget::VTK_CURSOR_ACTION);
|
||||||
plane->On();
|
plane->On();
|
||||||
*slicePlane = plane;
|
*slicePlane = plane;
|
||||||
}
|
}
|
||||||
|
|
@ -424,7 +429,9 @@ void buildWorkbench(QMainWindow& window, geopro::data::LocalSampleRepository& re
|
||||||
|
|
||||||
// 三维「地形」图层:GDAL 读 DEM(高程)+影像(EPSG:3857),重投影到世界系,warp 面 + 纹理。
|
// 三维「地形」图层:GDAL 读 DEM(高程)+影像(EPSG:3857),重投影到世界系,warp 面 + 纹理。
|
||||||
if (!is2D && *showTerrain && crs) {
|
if (!is2D && *showTerrain && crs) {
|
||||||
auto terr = geopro::render::buildTerrain(repo.demPath(), repo.imagePath(), *frame, 1.0);
|
// zOffset=refElev 使地形落在测线地表高程附近(不按绝对高程浮空);zScale=1 真实起伏。
|
||||||
|
auto terr = geopro::render::buildTerrain(repo.demPath(), repo.imagePath(), *frame,
|
||||||
|
refElev, 1.0);
|
||||||
if (terr) scene->addActor(terr);
|
if (terr) scene->addActor(terr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,8 @@ Raster readGeo(GDALDataset* ds) {
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
vtkSmartPointer<vtkActor> buildTerrain(const std::string& demPath, const std::string& imagePath,
|
vtkSmartPointer<vtkActor> buildTerrain(const std::string& demPath, const std::string& imagePath,
|
||||||
const geopro::core::GeoLocalFrame& frame, double zScale)
|
const geopro::core::GeoLocalFrame& frame, double zOffset,
|
||||||
|
double zScale)
|
||||||
{
|
{
|
||||||
GDALAllRegister();
|
GDALAllRegister();
|
||||||
|
|
||||||
|
|
@ -152,7 +153,7 @@ vtkSmartPointer<vtkActor> buildTerrain(const std::string& demPath, const std::st
|
||||||
const vtkIdType id = static_cast<vtkIdType>(j) * dg.w + i;
|
const vtkIdType id = static_cast<vtkIdType>(j) * dg.w + i;
|
||||||
float z = elev[static_cast<size_t>(j) * dg.w + i];
|
float z = elev[static_cast<size_t>(j) * dg.w + i];
|
||||||
if (hasNoData && z == static_cast<float>(noData)) z = vmin;
|
if (hasNoData && z == static_cast<float>(noData)) z = vmin;
|
||||||
points->SetPoint(id, local.x, local.y, z * zScale);
|
points->SetPoint(id, local.x, local.y, (z - zOffset) * zScale); // rebase 到测线高程
|
||||||
sc->SetValue(id, z);
|
sc->SetValue(id, z);
|
||||||
if (hasImage) {
|
if (hasImage) {
|
||||||
const auto m = llTo3857.forward(ll.x, ll.y); // (mercX, mercY)
|
const auto m = llTo3857.forward(ll.x, ll.y); // (mercX, mercY)
|
||||||
|
|
|
||||||
|
|
@ -13,10 +13,13 @@ namespace geopro::render {
|
||||||
// 高程作 z 起伏(vtkStructuredGrid 面),影像按经纬→3857→像素 算纹理坐标贴面。
|
// 高程作 z 起伏(vtkStructuredGrid 面),影像按经纬→3857→像素 算纹理坐标贴面。
|
||||||
// 影像加载失败则退化为按高程上色(无纹理)。读不到 DEM 返回空 actor。
|
// 影像加载失败则退化为按高程上色(无纹理)。读不到 DEM 返回空 actor。
|
||||||
//
|
//
|
||||||
// 依赖 GDAL/PROJ;调用方运行时须有 PROJ_DATA。zScale 为高程纵向夸张(地形通常 1.0~数倍)。
|
// 依赖 GDAL/PROJ;调用方运行时须有 PROJ_DATA。
|
||||||
|
// zOffset:从高程减去的基准(米)——传测线地表高程使地形落在测线附近(否则按绝对高程浮空,
|
||||||
|
// spec M-3 Z 基准)。世界 z = (elev - zOffset) * zScale。zScale 为纵向夸张。
|
||||||
vtkSmartPointer<vtkActor> buildTerrain(const std::string& demPath,
|
vtkSmartPointer<vtkActor> buildTerrain(const std::string& demPath,
|
||||||
const std::string& imagePath,
|
const std::string& imagePath,
|
||||||
const geopro::core::GeoLocalFrame& frame,
|
const geopro::core::GeoLocalFrame& frame,
|
||||||
|
double zOffset = 0.0,
|
||||||
double zScale = 1.0);
|
double zScale = 1.0);
|
||||||
|
|
||||||
} // namespace geopro::render
|
} // namespace geopro::render
|
||||||
|
|
|
||||||
|
|
@ -18,7 +18,7 @@ static const std::string kDir =
|
||||||
// (需 PROJ_DATA + GDAL 运行时; tests CMake 注入 PROJ_DATA。)
|
// (需 PROJ_DATA + GDAL 运行时; tests CMake 注入 PROJ_DATA。)
|
||||||
TEST(Terrain, BuildsTexturedSurfaceFromSampleDemImage) {
|
TEST(Terrain, BuildsTexturedSurfaceFromSampleDemImage) {
|
||||||
GeoLocalFrame frame(22.546, 114.164); // 测区附近(香港)
|
GeoLocalFrame frame(22.546, 114.164); // 测区附近(香港)
|
||||||
auto actor = geopro::render::buildTerrain(kDir + "dem.tif", kDir + "image.tif", frame, 1.0);
|
auto actor = geopro::render::buildTerrain(kDir + "dem.tif", kDir + "image.tif", frame);
|
||||||
ASSERT_NE(actor.GetPointer(), nullptr);
|
ASSERT_NE(actor.GetPointer(), nullptr);
|
||||||
ASSERT_NE(actor->GetMapper(), nullptr); // 成功读 DEM → 有 mapper(空 actor 无 mapper)
|
ASSERT_NE(actor->GetMapper(), nullptr); // 成功读 DEM → 有 mapper(空 actor 无 mapper)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ int main() {
|
||||||
|
|
||||||
// 7) DEM 地形 + 影像贴图 — GDAL 读 + 重投影到世界系 + warp 面 + 纹理
|
// 7) DEM 地形 + 影像贴图 — GDAL 读 + 重投影到世界系 + warp 面 + 纹理
|
||||||
{
|
{
|
||||||
auto terr = render::buildTerrain(dir + "dem.tif", dir + "image.tif", frame, 1.0);
|
auto terr = render::buildTerrain(dir + "dem.tif", dir + "image.tif", frame, 0.0, 1.0);
|
||||||
vtkNew<vtkRenderer> ren; ren->SetBackground(0.50, 0.60, 0.72);
|
vtkNew<vtkRenderer> ren; ren->SetBackground(0.50, 0.60, 0.72);
|
||||||
if (terr) ren->AddActor(terr);
|
if (terr) ren->AddActor(terr);
|
||||||
render::applyFree3D(ren);
|
render::applyFree3D(ren);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue