fix(vtk): 帘面消隐无数据(NaN)格,根治真实反演剖面渲染崩溃(0xc0000005)

真实反演 v 矩阵大量 null→Grid 存 NaN→vtkBandedPolyDataContourFilter 裁剪运算崩(经真实API数据+崩溃栈定位)。
消隐含 NaN 的点(ghost)使其不入表面/色带滤镜+标量填0兜底;顺带清洗色带等值线值(去非有限/去重)。保留色带功能。
This commit is contained in:
gaozheng 2026-06-16 20:41:13 +08:00
parent 5d1cf07882
commit 37b433208e
1 changed files with 29 additions and 3 deletions

View File

@ -9,6 +9,8 @@
#include <vtkPolyDataMapper.h> #include <vtkPolyDataMapper.h>
#include <vtkStructuredGrid.h> #include <vtkStructuredGrid.h>
#include <algorithm>
#include <cmath>
#include <vector> #include <vector>
#include <cstddef> #include <cstddef>
@ -47,6 +49,10 @@ vtkSmartPointer<vtkActor> buildCurtain(const geopro::core::Grid& g,
sc->SetName("v"); sc->SetName("v");
sc->SetNumberOfTuples(static_cast<vtkIdType>(nx) * ny); sc->SetNumberOfTuples(static_cast<vtkIdType>(nx) * ny);
// 无数据格v 为 null → Grid 存 NaN反演不规则区大量如此记录待消隐NaN 标量喂给
// vtkBandedPolyDataContourFilter 的裁剪运算会崩(0xc0000005)。消隐后这些格不入表面/色带,
// 既不崩、又把空洞正确显示为透明。标量同时填 0有限值以防任何读取路径再触 NaN。
std::vector<vtkIdType> blanks;
for (int j = 0; j < ny; ++j) { for (int j = 0; j < ny; ++j) {
for (int i = 0; i < nx; ++i) { for (int i = 0; i < nx; ++i) {
double px, py; double px, py;
@ -62,15 +68,35 @@ vtkSmartPointer<vtkActor> buildCurtain(const geopro::core::Grid& g,
const vtkIdType id = static_cast<vtkIdType>(j) * nx + i; const vtkIdType id = static_cast<vtkIdType>(j) * nx + i;
// g.y 是深度(越大越深)VTK Z 向上 → 取负,使深部在下、浅部在上(剖面不倒置)。 // g.y 是深度(越大越深)VTK Z 向上 → 取负,使深部在下、浅部在上(剖面不倒置)。
points->SetPoint(id, px, py, -g.y[j]); points->SetPoint(id, px, py, -g.y[j]);
sc->SetValue(id, g.valueAt(i, j)); const double val = g.valueAt(i, j);
if (std::isfinite(val)) {
sc->SetValue(id, val);
} else {
sc->SetValue(id, 0.0);
blanks.push_back(id);
}
} }
} }
sgrid->SetPoints(points); sgrid->SetPoints(points);
sgrid->GetPointData()->SetScalars(sc); sgrid->GetPointData()->SetScalars(sc);
// 消隐无数据点vtkStructuredGrid 消隐(ghost)→ 含该点的 cell 不被 vtkDataSetSurfaceFilter 输出,
// 故 NaN 永不进入 banded contour。282/1900 有效的不规则反演区→渲染出正确的梯形帘面。
for (vtkIdType id : blanks) sgrid->BlankPoint(id);
// 用 colorBar 真实分段值做色带(与数据详情#18一致的清晰色带而非连续插值的糊色)。 // 用 colorBar 真实分段值做色带(与数据详情#18一致的清晰色带而非连续插值的糊色)。
const std::vector<double> stops = cs.stopValues(); // 清洗等值线值vtkBandedPolyDataContourFilter 要求值严格升序且有限——真实色阶可能含重复值
// (addStop 排序不去重)或非有限值,未清洗会在 Update() 时崩(0xc0000005)。去非有限 + 去重保序。
std::vector<double> stops;
{
std::vector<double> raw = cs.stopValues();
raw.erase(std::remove_if(raw.begin(), raw.end(),
[](double v) { return !std::isfinite(v); }),
raw.end());
std::sort(raw.begin(), raw.end());
raw.erase(std::unique(raw.begin(), raw.end()), raw.end());
stops = std::move(raw);
}
double vmin, vmax; double vmin, vmax;
if (stops.size() >= 2) { vmin = stops.front(); vmax = stops.back(); } if (stops.size() >= 2) { vmin = stops.front(); vmax = stops.back(); }
else { else {
@ -85,7 +111,7 @@ vtkSmartPointer<vtkActor> buildCurtain(const geopro::core::Grid& g,
auto lut = buildLut(cs, vmin, vmax, kLutLevels); auto lut = buildLut(cs, vmin, vmax, kLutLevels);
// structuredGrid → 表面 polydata → banded contour(分段色带) // structuredGrid → 表面 polydata(消隐格已剔除) → banded contour(分段色带,色带#18)
vtkNew<vtkDataSetSurfaceFilter> surf; vtkNew<vtkDataSetSurfaceFilter> surf;
surf->SetInputData(sgrid); surf->SetInputData(sgrid);
vtkNew<vtkBandedPolyDataContourFilter> banded; vtkNew<vtkBandedPolyDataContourFilter> banded;