geopro/tests/spike/render_verify.cpp

166 lines
7.3 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 离屏渲染验证:把真实数据渲成 PNG肉眼核对方向/2D-3D 差异(不靠"进程活着"自欺)。
// 产出(D:/dev/spike_data/):
// verify_section.png —— 平面反演剖面(#18, 数据详情), 浅部在上、深部在下, 纵向夸张填满
// verify_curtain_top.png —— 帘面俯视(二维)
// verify_curtain_3d.png —— 帘面透视(三维)
#include <fstream>
#include <numeric>
#include <sstream>
#include <string>
#include <vtkActor.h>
#include <vtkNew.h>
#include <vtkPNGWriter.h>
#include <vtkRenderWindow.h>
#include <vtkRenderer.h>
#include <vtkWindowToImageFilter.h>
#include "CameraPreset.hpp"
#include "ColorLutBuilder.hpp"
#include "VoxelFromScatters.hpp"
#include "actors/AnomalyActor.hpp"
#include "actors/CurtainActor.hpp"
#include "actors/ElectrodeActor.hpp"
#include "actors/GridContourActor.hpp"
#include "actors/MapLineActor.hpp"
#include "actors/ScatterActor.hpp"
#include "actors/TerrainActor.hpp"
#include "geo/CrsTransform.hpp"
#include "geo/GeoLocalFrame.hpp"
#include "parse/SampleParsers.hpp"
#include <vtkVolume.h>
static std::string slurp(const char* p) {
std::ifstream f(p);
std::stringstream s; s << f.rdbuf(); return s.str();
}
static void renderToPng(vtkRenderer* ren, const char* path, int w, int h) {
vtkNew<vtkRenderWindow> rw;
rw->SetOffScreenRendering(1);
rw->AddRenderer(ren);
rw->SetSize(w, h);
rw->Render();
vtkNew<vtkWindowToImageFilter> w2i; w2i->SetInput(rw);
vtkNew<vtkPNGWriter> png; png->SetFileName(path);
png->SetInputConnection(w2i->GetOutputPort()); png->Write();
}
int main() {
using namespace geopro;
const std::string dir = "D:/dev/spike_data/";
core::Grid g = data::parseGrid(slurp((dir + "grid.json").c_str()));
core::ColorScale cs = data::parseColorScale(slurp((dir + "colorbar.json").c_str()));
// 1) 平面剖面 (#18) — 俯视看 XY 平面(face-on); 纵向夸张 1.5x 填满宽面板(物探惯例)
{
auto a = render::buildGridContour(g, cs);
const double exag = 1.5;
vtkNew<vtkRenderer> ren; ren->SetBackground(1, 1, 1);
if (a.bands) { a.bands->SetScale(1.0, exag, 1.0); ren->AddActor(a.bands); }
if (a.edges) { a.edges->SetScale(1.0, exag, 1.0); ren->AddActor(a.edges); }
render::applyTop2D(ren);
renderToPng(ren, (dir + "verify_section.png").c_str(), 1100, 360);
}
// GeoLocalFrame: 原点取 lat/lon 均值
double lat0 = std::accumulate(g.lat.begin(), g.lat.end(), 0.0) / (g.lat.empty() ? 1 : g.lat.size());
double lon0 = std::accumulate(g.lon.begin(), g.lon.end(), 0.0) / (g.lon.empty() ? 1 : g.lon.size());
core::GeoLocalFrame frame(lat0, lon0);
// 2) 二维地图:测线折线俯视(浅灰底)
{
auto line = render::buildSurveyLine(g, frame);
vtkNew<vtkRenderer> ren; ren->SetBackground(0.96, 0.97, 0.99);
ren->AddActor(line);
render::applyTop2D(ren);
renderToPng(ren, (dir + "verify_map.png").c_str(), 700, 500);
}
// 3) 帘面透视(三维);纵向夸张 z*3使 15m 深度相对 62m 长度更像一道墙
{
auto a = render::buildCurtain(g, cs, frame);
a->SetScale(1.0, 1.0, 3.0);
vtkNew<vtkRenderer> ren; ren->SetBackground(1, 1, 1);
ren->AddActor(a);
render::applyFree3D(ren);
renderToPng(ren, (dir + "verify_curtain_3d.png").c_str(), 700, 500);
}
// 4) 散点 (#17) — 剖面原数据彩色方块散点; x=距离, y=深度(取负向下), face-on 俯视
{
core::ScatterField s = data::parseScatter(slurp((dir + "scatter.json").c_str()));
core::ColorScale scs = data::parseColorScale(slurp((dir + "scatter_colorbar.json").c_str()));
auto a = render::buildScatter(s, scs, 4.0F);
vtkNew<vtkRenderer> ren; ren->SetBackground(1, 1, 1);
ren->AddActor(a);
render::applyTop2D(ren);
renderToPng(ren, (dir + "verify_scatter.png").c_str(), 1100, 360);
std::printf("SCATTER pts=%zu\n", s.v.size());
}
// 5) 异常叠加 — #18 平面剖面 + 异常 dashed 折线叠加(同纵向夸张 1.5x 对齐)
{
std::vector<core::Anomaly> anomalies =
data::parseAnomalies(slurp((dir + "anomaly.json").c_str()));
auto a = render::buildGridContour(g, cs);
const double exag = 1.5;
vtkNew<vtkRenderer> ren; ren->SetBackground(1, 1, 1);
if (a.bands) { a.bands->SetScale(1.0, exag, 1.0); ren->AddActor(a.bands); }
if (a.edges) { a.edges->SetScale(1.0, exag, 1.0); ren->AddActor(a.edges); }
auto anomActors = render::buildAnomalies(anomalies);
for (auto& act : anomActors) {
act->SetScale(1.0, exag, 1.0);
ren->AddActor(act);
}
// 顶部电极标记 ▼(同纵向夸张对齐)。
auto elec = render::buildElectrodes(g);
if (elec) { elec->SetScale(1.0, exag, 1.0); ren->AddActor(elec); }
render::applyTop2D(ren);
renderToPng(ren, (dir + "verify_section_anomaly.png").c_str(), 1100, 360);
std::printf("ANOMALY n=%zu\n", anomalies.size());
}
// 6) dd_voxel — 两交叉剖面散点经 EPSG:4547→4326→GeoLocalFrame 配准 + IDW 成体素,
// 叠一条帘面(grid1,同系)做空间参照; 透视核对"十字片"与帘面配准(profile1 片应贴合帘面)。
{
std::vector<core::ScatterField> profs;
profs.push_back(data::parseScatter(slurp((dir + "scatter.json").c_str())));
profs.push_back(data::parseScatter(slurp((dir + "scatter2.json").c_str())));
core::ColorScale scs = data::parseColorScale(slurp((dir + "scatter_colorbar.json").c_str()));
core::CrsTransform crs("EPSG:4547", "EPSG:4326");
auto vr = render::buildVoxelFromScatters(profs, scs, crs, frame);
// 灰底使半透明体绘制可见(白底会冲淡)。3D体素 + 帘面(同系)核对 profile1 片贴合帘面。
vtkNew<vtkRenderer> ren; ren->SetBackground(0.22, 0.22, 0.26);
if (vr.valid()) ren->AddVolume(vr.volume);
auto curt = render::buildCurtain(g, cs, frame); // 原始米(不夸张)与体素同系
if (curt) ren->AddActor(curt);
render::applyFree3D(ren);
renderToPng(ren, (dir + "verify_voxel_3d.png").c_str(), 700, 500);
// 俯视:体素 footprint 应呈两测线相交的"X"(十字片)。
vtkNew<vtkRenderer> renTop; renTop->SetBackground(0.22, 0.22, 0.26);
if (vr.valid()) renTop->AddVolume(vr.volume);
render::applyTop2D(renTop);
renderToPng(renTop, (dir + "verify_voxel_top.png").c_str(), 600, 500);
int dims[3] = {0, 0, 0};
if (vr.valid()) vr.image->GetDimensions(dims);
std::printf("VOXEL valid=%d dims=%dx%dx%d pts=%zu\n", vr.valid() ? 1 : 0,
dims[0], dims[1], dims[2], profs[0].v.size() + profs[1].v.size());
}
// 7) DEM 地形 + 影像贴图 — GDAL 读 + 重投影到世界系 + warp 面 + 纹理
{
auto terr = render::buildTerrain(dir + "dem.tif", dir + "image.tif", frame, 1.0);
vtkNew<vtkRenderer> ren; ren->SetBackground(0.50, 0.60, 0.72);
if (terr) ren->AddActor(terr);
render::applyFree3D(ren);
renderToPng(ren, (dir + "verify_terrain_3d.png").c_str(), 800, 600);
std::printf("TERRAIN actor=%d\n", terr ? 1 : 0);
}
std::printf("RENDER_VERIFY_DONE grid=%dx%d lat0=%.5f lon0=%.5f\n", g.nx(), g.ny(), lat0, lon0);
return 0;
}