#include <vtkActor.h>
#include <vtkCamera.h>
#include <vtkDataSetAttributes.h>
#include <vtkGeometryFilter.h>
#include <vtkImageData.h>
#include <vtkInteractorStyleTrackballCamera.h>
#include <vtkLookupTable.h>
#include <vtkNew.h>
#include <vtkPointData.h>
#include <vtkPolyData.h>
#include <vtkPolyDataMapper.h>
#include <vtkRenderWindow.h>
#include <vtkRenderWindowInteractor.h>
#include <vtkRenderer.h>
#include <vtkSmartPointer.h>
#include <vtkUnsignedCharArray.h>
#include <vtkWarpScalar.h>
#include <algorithm>
#include <array>
#include <cmath>
#include <iostream>
#include <memory>
#include <stdexcept>
#include <string>
namespace
{
{
{
+ message);
}
}
Reader create_reader()
{
}
float *heights_of(vtkImageData *image)
{
return static_cast<float *>(image->GetScalarPointer());
}
vtkSmartPointer<vtkImageData> read_image(
sdfio_reader *reader)
{
auto image = vtkSmartPointer<vtkImageData>::New();
image->SetOrigin(0.0, 0.0, 0.0);
image->AllocateScalars(VTK_FLOAT, 1);
heights_of(image)),
return image;
}
void hide_points_not_measured(vtkImageData *image)
{
const vtkIdType count = image->GetNumberOfPoints();
const float *heights = heights_of(image);
vtkNew<vtkUnsignedCharArray> hidden;
hidden->SetName(vtkDataSetAttributes::GhostArrayName());
hidden->SetNumberOfValues(count);
for (vtkIdType i = 0; i < count; ++i)
{
hidden->SetValue(
i, std::isnan(heights[i]) ? vtkDataSetAttributes::HIDDENPOINT : 0);
}
image->GetPointData()->AddArray(hidden);
}
vtkSmartPointer<vtkPolyData> height_field(vtkImageData *image, double factor)
{
vtkNew<vtkImageData> patched;
patched->DeepCopy(image);
float *heights = heights_of(patched);
const vtkIdType count = patched->GetNumberOfPoints();
for (vtkIdType i = 0; i < count; ++i)
{
heights[i] = std::isnan(heights[i]) ? 0.0F : heights[i];
}
vtkNew<vtkGeometryFilter> surface;
surface->SetInputData(patched);
vtkNew<vtkWarpScalar> warp;
warp->SetInputConnection(surface->GetOutputPort());
warp->SetScaleFactor(factor);
warp->UseNormalOff();
warp->SetNormal(0.0, 0.0, 1.0);
warp->Update();
return vtkPolyData::SafeDownCast(warp->GetOutput());
}
std::array<double, 2> z_range(vtkImageData *image)
{
double bounds[6];
height_field(image, 1.0)->GetBounds(bounds);
return {bounds[4], bounds[5]};
}
void view(vtkImageData *image)
{
const std::array<double, 2> z = z_range(image);
double bounds[6];
image->GetBounds(bounds);
const double width = std::max(bounds[1] - bounds[0], bounds[3] - bounds[2]);
const double raise = z[1] > z[0] ? 0.25 * width / (z[1] - z[0]) : 1.0;
vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(height_field(image, raise));
vtkNew<vtkLookupTable> colours;
colours->SetHueRange(0.667, 0.0);
colours->Build();
mapper->SetLookupTable(colours);
mapper->SetScalarRange(z[0], z[1]);
vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
vtkNew<vtkRenderer> renderer;
renderer->AddActor(actor);
renderer->SetBackground(0.1, 0.1, 0.15);
renderer->GetActiveCamera()->Elevation(-40.0);
renderer->GetActiveCamera()->OrthogonalizeViewUp();
renderer->ResetCamera();
vtkNew<vtkRenderWindow> window;
window->AddRenderer(renderer);
window->SetSize(800, 600);
vtkNew<vtkRenderWindowInteractor> interactor;
vtkNew<vtkInteractorStyleTrackballCamera> style;
interactor->SetRenderWindow(window);
interactor->SetInteractorStyle(style);
window->Render();
interactor->Start();
}
}
int main(int argc, char **argv)
{
if (argc < 2)
{
std::cerr << "usage: " << argv[0] << " file.sdf\n";
return 1;
}
const char *path = argv[1];
try
{
Reader reader = create_reader();
vtkSmartPointer<vtkImageData> image = read_image(reader.get());
hide_points_not_measured(image);
view(image);
}
catch (const std::exception &error)
{
std::cerr << error.what() << "\n";
return 1;
}
}
Files by path, and the stream over a C file.
sdfio_status sdfio_open_file(sdfio_reader *reader, const char *path)
Opens the file at a path as the source and reads its header, as sdfio_open_stream() does for a stream...
const sdfio_layout * sdfio_layout_packed(sdfio_data_type type)
Returns the layout of a plain array: the elements follow each other and the rows follow each other.
sdfio_status sdfio_reader_add_binary(sdfio_reader *reader)
Adds the binary format to the formats that the reader reads, the version numbers bISO-1....
const sdfio_header * sdfio_reader_header(const sdfio_reader *reader)
Returns the header of the opened file, or null if no file is open.
struct sdfio_reader sdfio_reader
Opaque handle of a reader.
Definition reader.h:58
sdfio_status sdfio_reader_add_ascii(sdfio_reader *reader)
Adds the ASCII format to the formats that the reader reads, the version numbers aISO-1....
sdfio_status sdfio_reader_create(const sdfio_allocator *allocator, sdfio_reader **reader)
Creates a reader.
sdfio_status sdfio_read_heights(sdfio_reader *reader, const sdfio_layout *layout, void *dst)
Reads the remaining rows as heights in metres into a buffer that lies in memory as the layout describ...
const char * sdfio_reader_error_message(const sdfio_reader *reader)
Returns a description of the most recent failure of the reader, or an empty string if none occurred.
void sdfio_reader_free(sdfio_reader *reader)
Releases a reader and closes the file that sdfio_open_file() opened, if any.
Reading and writing of ISO 25178-71 SDF surface data files.
const char * sdfio_status_string(sdfio_status status)
Returns a constant description of a status.
sdfio_status
Result of a function call.
Definition types.h:31
@ SDFIO_OK
The call succeeded.
Definition types.h:33
const sdfio_allocator * sdfio_default_allocator(void)
Returns the allocator that uses malloc() and free().
@ SDFIO_TYPE_FLOAT
float: IEEE 754 binary32.
Definition types.h:114