feat/dataset-detail-chart #5
|
|
@ -1,7 +1,7 @@
|
||||||
find_package(VTK REQUIRED COMPONENTS CommonCore CommonDataModel FiltersGeometry FiltersModeling RenderingCore RenderingOpenGL2 RenderingVolumeOpenGL2 InteractionStyle InteractionWidgets IOImage)
|
find_package(VTK REQUIRED COMPONENTS CommonCore CommonDataModel FiltersGeometry FiltersModeling RenderingCore RenderingOpenGL2 RenderingVolumeOpenGL2 InteractionStyle InteractionWidgets IOImage)
|
||||||
find_package(GDAL CONFIG REQUIRED)
|
find_package(GDAL CONFIG REQUIRED)
|
||||||
add_library(geopro_render STATIC
|
add_library(geopro_render STATIC
|
||||||
Scene.cpp ColorLutBuilder.cpp CameraPreset.cpp VoxelFromScatters.cpp actors/GridContourActor.cpp actors/VoxelActor.cpp actors/CurtainActor.cpp actors/MapLineActor.cpp actors/ScatterActor.cpp actors/AnomalyActor.cpp actors/ElectrodeActor.cpp actors/TerrainActor.cpp)
|
Scene.cpp ColorLutBuilder.cpp CameraPreset.cpp VoxelFromScatters.cpp ContourBands.cpp actors/GridContourActor.cpp actors/VoxelActor.cpp actors/CurtainActor.cpp actors/MapLineActor.cpp actors/ScatterActor.cpp actors/AnomalyActor.cpp actors/ElectrodeActor.cpp actors/TerrainActor.cpp)
|
||||||
target_include_directories(geopro_render PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(geopro_render PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_link_libraries(geopro_render PUBLIC geopro_core ${VTK_LIBRARIES} GDAL::GDAL)
|
target_link_libraries(geopro_render PUBLIC geopro_core ${VTK_LIBRARIES} GDAL::GDAL)
|
||||||
target_compile_features(geopro_render PUBLIC cxx_std_17)
|
target_compile_features(geopro_render PUBLIC cxx_std_17)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,100 @@
|
||||||
|
#include "ContourBands.hpp"
|
||||||
|
|
||||||
|
#include <vtkBandedPolyDataContourFilter.h>
|
||||||
|
#include <vtkCell.h>
|
||||||
|
#include <vtkCellData.h>
|
||||||
|
#include <vtkDataSetSurfaceFilter.h>
|
||||||
|
#include <vtkDoubleArray.h>
|
||||||
|
#include <vtkIdList.h>
|
||||||
|
#include <vtkNew.h>
|
||||||
|
#include <vtkPointData.h>
|
||||||
|
#include <vtkPoints.h>
|
||||||
|
#include <vtkPolyData.h>
|
||||||
|
#include <vtkStructuredGrid.h>
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
|
||||||
|
namespace geopro::render {
|
||||||
|
using geopro::core::Grid;
|
||||||
|
using geopro::core::ColorScale;
|
||||||
|
using geopro::core::Vec2;
|
||||||
|
using geopro::core::Rgba;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
// 用 Grid 构 vtkStructuredGrid(点 (x[i], y[j], 0);NaN 值置 0 但记录于掩膜——
|
||||||
|
// 首版裁剪在 Task 1.4 接入,这里先全量)。
|
||||||
|
vtkSmartPointer<vtkStructuredGrid> toStructuredGrid(const Grid& g) {
|
||||||
|
const int nx = g.nx(), ny = g.ny();
|
||||||
|
auto sg = vtkSmartPointer<vtkStructuredGrid>::New();
|
||||||
|
sg->SetDimensions(nx, ny, 1);
|
||||||
|
vtkNew<vtkPoints> pts; pts->SetNumberOfPoints(static_cast<vtkIdType>(nx) * ny);
|
||||||
|
vtkNew<vtkDoubleArray> sc; sc->SetName("v");
|
||||||
|
sc->SetNumberOfTuples(static_cast<vtkIdType>(nx) * ny);
|
||||||
|
for (int j = 0; j < ny; ++j)
|
||||||
|
for (int i = 0; i < nx; ++i) {
|
||||||
|
const vtkIdType id = static_cast<vtkIdType>(j) * nx + i;
|
||||||
|
pts->SetPoint(id, g.x[i], g.y[j], 0.0);
|
||||||
|
const double v = g.valueAt(i, j);
|
||||||
|
sc->SetValue(id, std::isnan(v) ? 0.0 : v);
|
||||||
|
}
|
||||||
|
sg->SetPoints(pts);
|
||||||
|
sg->GetPointData()->SetScalars(sc);
|
||||||
|
return sg;
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
ContourBandsResult buildContourBands(const Grid& g, const ColorScale& cs, const ContourOptions&) {
|
||||||
|
ContourBandsResult out;
|
||||||
|
const int nx = g.nx(), ny = g.ny();
|
||||||
|
if (nx < 2 || ny < 2 || g.x.size() < 2 || g.y.size() < 2) return out;
|
||||||
|
|
||||||
|
const std::vector<double> stops = cs.stopValues();
|
||||||
|
if (stops.size() < 2) return out;
|
||||||
|
|
||||||
|
auto sg = toStructuredGrid(g);
|
||||||
|
vtkNew<vtkDataSetSurfaceFilter> surf; surf->SetInputData(sg);
|
||||||
|
vtkNew<vtkBandedPolyDataContourFilter> banded;
|
||||||
|
banded->SetInputConnection(surf->GetOutputPort());
|
||||||
|
banded->SetNumberOfContours(static_cast<int>(stops.size()));
|
||||||
|
for (int i = 0; i < static_cast<int>(stops.size()); ++i) banded->SetValue(i, stops[i]);
|
||||||
|
banded->GenerateContourEdgesOn();
|
||||||
|
banded->SetScalarModeToValue();
|
||||||
|
banded->Update();
|
||||||
|
|
||||||
|
// port0:色带多边形(cell 标量=带的代表值)→ 按 ColorScale 上色。
|
||||||
|
vtkPolyData* poly = banded->GetOutput();
|
||||||
|
vtkDataArray* cellScalars = poly->GetCellData()->GetScalars();
|
||||||
|
const vtkIdType nCells = poly->GetNumberOfCells();
|
||||||
|
for (vtkIdType c = 0; c < nCells; ++c) {
|
||||||
|
vtkCell* cell = poly->GetCell(c);
|
||||||
|
vtkPoints* cp = cell->GetPoints();
|
||||||
|
if (cp->GetNumberOfPoints() < 3) continue;
|
||||||
|
BandPolygon bp;
|
||||||
|
const double val = cellScalars ? cellScalars->GetTuple1(c) : 0.0;
|
||||||
|
bp.color = cs.colorAt(val);
|
||||||
|
for (vtkIdType p = 0; p < cp->GetNumberOfPoints(); ++p) {
|
||||||
|
double xyz[3]; cp->GetPoint(p, xyz);
|
||||||
|
bp.ring.push_back(Vec2{xyz[0], xyz[1]});
|
||||||
|
}
|
||||||
|
out.bands.push_back(std::move(bp));
|
||||||
|
}
|
||||||
|
|
||||||
|
// port1:等值线(polylines)。
|
||||||
|
vtkPolyData* edges = banded->GetContourEdgesOutput();
|
||||||
|
if (edges) {
|
||||||
|
edges->BuildCells();
|
||||||
|
const vtkIdType nLines = edges->GetNumberOfCells();
|
||||||
|
for (vtkIdType c = 0; c < nLines; ++c) {
|
||||||
|
vtkCell* cell = edges->GetCell(c);
|
||||||
|
vtkPoints* cp = cell->GetPoints();
|
||||||
|
ContourLine cl; cl.level = 0.0;
|
||||||
|
for (vtkIdType p = 0; p < cp->GetNumberOfPoints(); ++p) {
|
||||||
|
double xyz[3]; cp->GetPoint(p, xyz);
|
||||||
|
cl.pts.push_back(Vec2{xyz[0], xyz[1]});
|
||||||
|
}
|
||||||
|
if (cl.pts.size() >= 2) out.lines.push_back(std::move(cl));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
} // namespace geopro::render
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
#pragma once
|
||||||
|
#include <vector>
|
||||||
|
#include "model/Field.hpp"
|
||||||
|
#include "model/ColorScale.hpp"
|
||||||
|
#include "model/Anomaly.hpp"
|
||||||
|
namespace geopro::render {
|
||||||
|
|
||||||
|
struct BandPolygon {
|
||||||
|
geopro::core::Rgba color;
|
||||||
|
std::vector<geopro::core::Vec2> ring; // 单环多边形(局部坐标,y=高程向上为正)
|
||||||
|
};
|
||||||
|
struct ContourLine {
|
||||||
|
double level;
|
||||||
|
std::vector<geopro::core::Vec2> pts;
|
||||||
|
};
|
||||||
|
struct ContourBandsResult {
|
||||||
|
std::vector<BandPolygon> bands;
|
||||||
|
std::vector<ContourLine> lines;
|
||||||
|
};
|
||||||
|
struct ContourOptions {
|
||||||
|
int upsample = 2; // 双线性上采样倍数(1=不采样)
|
||||||
|
double smooth = 0.3; // 平滑强度 0..1(0=不平滑)
|
||||||
|
double simplifyTol = 0.5; // 等值线简化容差(数据单位,0=不简化)
|
||||||
|
bool makeLines = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// core::Grid(NaN=无效)+ ColorScale 分段 → 色带多边形 + 等值线几何。
|
||||||
|
// VTK 仅作算法(vtkBandedPolyDataContourFilter),无 render window。
|
||||||
|
ContourBandsResult buildContourBands(const geopro::core::Grid& g,
|
||||||
|
const geopro::core::ColorScale& cs,
|
||||||
|
const ContourOptions& opt = {});
|
||||||
|
} // namespace geopro::render
|
||||||
|
|
@ -61,6 +61,7 @@ endif()
|
||||||
# 需 vtkLookupTable(VTK::CommonCore);geopro_render 已 PUBLIC 传递其余 VTK 组件。
|
# 需 vtkLookupTable(VTK::CommonCore);geopro_render 已 PUBLIC 传递其余 VTK 组件。
|
||||||
find_package(VTK REQUIRED COMPONENTS CommonCore CommonDataModel RenderingCore)
|
find_package(VTK REQUIRED COMPONENTS CommonCore CommonDataModel RenderingCore)
|
||||||
target_sources(geopro_tests PRIVATE render/test_color_lut.cpp)
|
target_sources(geopro_tests PRIVATE render/test_color_lut.cpp)
|
||||||
|
target_sources(geopro_tests PRIVATE render/test_contour_bands.cpp)
|
||||||
# dd_voxel:buildVoxel(ScalarVolume->vtkImageData->GPU 体绘制) 构建不崩 + dims 正确。
|
# dd_voxel:buildVoxel(ScalarVolume->vtkImageData->GPU 体绘制) 构建不崩 + dims 正确。
|
||||||
target_sources(geopro_tests PRIVATE render/test_voxel_build.cpp)
|
target_sources(geopro_tests PRIVATE render/test_voxel_build.cpp)
|
||||||
# dd_voxel 回归:buildVoxelFromScatters(散点 projX/Y -EPSG:4547-> 世界系 + IDW) 配准+充填(需 PROJ_DATA)。
|
# dd_voxel 回归:buildVoxelFromScatters(散点 projX/Y -EPSG:4547-> 世界系 + IDW) 配准+充填(需 PROJ_DATA)。
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include "ContourBands.hpp"
|
||||||
|
using namespace geopro::core;
|
||||||
|
using namespace geopro::render;
|
||||||
|
|
||||||
|
// 2x2 平滑梯度网格 + 2 段色阶 → 至少 1 个色带多边形,多边形顶点 >=3。
|
||||||
|
TEST(ContourBands, ProducesNonEmptyBands) {
|
||||||
|
Grid g(3, 3);
|
||||||
|
g.x = {0, 1, 2}; g.y = {0, 1, 2};
|
||||||
|
for (int j = 0; j < 3; ++j)
|
||||||
|
for (int i = 0; i < 3; ++i) g.valueAt(i, j) = static_cast<double>(i + j); // 0..4
|
||||||
|
g.vmin = 0; g.vmax = 4;
|
||||||
|
ColorScale cs;
|
||||||
|
cs.addStop(0.0, Rgba{0, 0, 255, 255});
|
||||||
|
cs.addStop(2.0, Rgba{0, 255, 0, 255});
|
||||||
|
cs.addStop(4.0, Rgba{255, 0, 0, 255});
|
||||||
|
|
||||||
|
ContourOptions opt; opt.upsample = 1; opt.smooth = 0; opt.simplifyTol = 0;
|
||||||
|
auto r = buildContourBands(g, cs, opt);
|
||||||
|
ASSERT_FALSE(r.bands.empty());
|
||||||
|
for (const auto& b : r.bands) EXPECT_GE(b.ring.size(), 3u);
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue