fix(render): 数据详情#18修正 — 用colorBar真实非均匀分段值做等值线级(修一片蓝)+纵向夸张; ColorScale暴露stopValues
This commit is contained in:
parent
039c04a233
commit
2d7dfe3582
|
|
@ -33,6 +33,13 @@ void ColorScale::addStop(double value, Rgba color) {
|
|||
[](const Stop& x, const Stop& y) { return x.value < y.value; });
|
||||
}
|
||||
|
||||
std::vector<double> ColorScale::stopValues() const {
|
||||
std::vector<double> v;
|
||||
v.reserve(stops_.size());
|
||||
for (const auto& s : stops_) v.push_back(s.value); // stops_ 已升序
|
||||
return v;
|
||||
}
|
||||
|
||||
Rgba ColorScale::colorAt(double value) const {
|
||||
if (std::isnan(value)) return nan_.value_or(Rgba{0, 0, 0, 0});
|
||||
if (stops_.empty()) return Rgba{0, 0, 0, 0};
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@ class ColorScale {
|
|||
public:
|
||||
void addStop(double value, Rgba color); // 内部保持按 value 升序
|
||||
Rgba colorAt(double value) const; // 含 under/over/NaN 处理
|
||||
std::vector<double> stopValues() const; // 升序分段值(供等值线用真实非均匀级)
|
||||
std::size_t stopCount() const { return stops_.size(); }
|
||||
void setUnder(Rgba c) { under_ = c; }
|
||||
void setOver(Rgba c) { over_ = c; }
|
||||
void setNan(Rgba c) { nan_ = c; }
|
||||
|
|
|
|||
|
|
@ -50,17 +50,19 @@ GridActors buildGridContour(const geopro::core::Grid& g, const geopro::core::Col
|
|||
sgrid->SetPoints(points);
|
||||
sgrid->GetPointData()->SetScalars(sc);
|
||||
|
||||
// vmin/vmax 来自 Grid;若退化(==)则用数据极值兜底,避免 LUT/contour 退化。
|
||||
double vmin = g.vmin, vmax = g.vmax;
|
||||
if (vmin >= vmax) {
|
||||
const auto& vals = g.values();
|
||||
vmin = vals.empty() ? 0.0 : vals.front();
|
||||
vmax = vmin;
|
||||
for (double v : vals) {
|
||||
if (v < vmin) vmin = v;
|
||||
if (v > vmax) vmax = v;
|
||||
// 等值线级用 colorBar 的**真实非均匀分段值**(电阻率低值密集),而非均匀分级——
|
||||
// 否则数据全挤进低端、一片蓝。范围/色阶都以 colorBar 为准。
|
||||
const std::vector<double> stops = cs.stopValues();
|
||||
double vmin, vmax;
|
||||
if (stops.size() >= 2) { vmin = stops.front(); vmax = stops.back(); }
|
||||
else {
|
||||
vmin = g.vmin; vmax = g.vmax;
|
||||
if (vmin >= vmax) {
|
||||
const auto& vals = g.values();
|
||||
vmin = vals.empty() ? 0.0 : vals.front(); vmax = vmin;
|
||||
for (double v : vals) { if (v < vmin) vmin = v; if (v > vmax) vmax = v; }
|
||||
if (vmin >= vmax) vmax = vmin + 1.0;
|
||||
}
|
||||
if (vmin >= vmax) vmax = vmin + 1.0;
|
||||
}
|
||||
|
||||
auto lut = buildLut(cs, vmin, vmax, kLutLevels);
|
||||
|
|
@ -70,7 +72,12 @@ GridActors buildGridContour(const geopro::core::Grid& g, const geopro::core::Col
|
|||
|
||||
vtkNew<vtkBandedPolyDataContourFilter> banded;
|
||||
banded->SetInputConnection(surf->GetOutputPort());
|
||||
banded->GenerateValues(kBandCount, vmin, vmax);
|
||||
if (stops.size() >= 2) {
|
||||
banded->SetNumberOfContours(static_cast<int>(stops.size()));
|
||||
for (int i = 0; i < static_cast<int>(stops.size()); ++i) banded->SetValue(i, stops[i]);
|
||||
} else {
|
||||
banded->GenerateValues(kBandCount, vmin, vmax);
|
||||
}
|
||||
banded->GenerateContourEdgesOn();
|
||||
banded->SetScalarModeToValue();
|
||||
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
// 离屏渲染验证:把真实数据渲成 PNG,肉眼核对方向/2D-3D 差异(不靠"进程活着"自欺)。
|
||||
// 产出(D:/dev/spike_data/):
|
||||
// verify_section.png —— 平面反演剖面(#18, 数据详情),应浅部在上、深部在下
|
||||
// verify_curtain_top.png —— 帘面俯视(二维),应看到一条沿测线的带(像地图线)
|
||||
// verify_curtain_3d.png —— 帘面透视(三维),应看到立着的彩色断面墙
|
||||
// verify_section.png —— 平面反演剖面(#18, 数据详情), 浅部在上、深部在下, 纵向夸张填满
|
||||
// verify_curtain_top.png —— 帘面俯视(二维)
|
||||
// verify_curtain_3d.png —— 帘面透视(三维)
|
||||
#include <fstream>
|
||||
#include <numeric>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <numeric>
|
||||
|
||||
#include <vtkActor.h>
|
||||
#include <vtkNew.h>
|
||||
|
|
@ -15,12 +15,12 @@
|
|||
#include <vtkRenderer.h>
|
||||
#include <vtkWindowToImageFilter.h>
|
||||
|
||||
#include "parse/SampleParsers.hpp"
|
||||
#include "geo/GeoLocalFrame.hpp"
|
||||
#include "actors/GridContourActor.hpp"
|
||||
#include "actors/CurtainActor.hpp"
|
||||
#include "ColorLutBuilder.hpp"
|
||||
#include "CameraPreset.hpp"
|
||||
#include "ColorLutBuilder.hpp"
|
||||
#include "actors/CurtainActor.hpp"
|
||||
#include "actors/GridContourActor.hpp"
|
||||
#include "geo/GeoLocalFrame.hpp"
|
||||
#include "parse/SampleParsers.hpp"
|
||||
|
||||
static std::string slurp(const char* p) {
|
||||
std::ifstream f(p);
|
||||
|
|
@ -44,17 +44,18 @@ int main() {
|
|||
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) 平面剖面 (#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) ren->AddActor(a.bands);
|
||||
if (a.edges) ren->AddActor(a.edges);
|
||||
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, 320);
|
||||
renderToPng(ren, (dir + "verify_section.png").c_str(), 1100, 360);
|
||||
}
|
||||
|
||||
// GeoLocalFrame:原点取 lat/lon 均值
|
||||
// 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);
|
||||
|
|
|
|||
Loading…
Reference in New Issue