OGS
VtkImageDataToPointCloudFilter.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: Copyright (c) OpenGeoSys Community (opengeosys.org)
2// SPDX-License-Identifier: BSD-3-Clause
3
4// ** INCLUDES **
6
7#include <vtkDoubleArray.h>
8#include <vtkIdList.h>
9#include <vtkImageData.h>
10#include <vtkInformation.h>
11#include <vtkInformationVector.h>
12#include <vtkLine.h>
13#include <vtkObjectFactory.h>
14#include <vtkPointData.h>
15#include <vtkPolyData.h>
16#include <vtkSmartPointer.h>
17
18#include <algorithm>
19#include <vector>
20
22
24
25void VtkImageDataToPointCloudFilter::PrintSelf(ostream& os, vtkIndent indent)
26{
27 this->Superclass::PrintSelf(os, indent);
28}
29
31 int /*port*/, vtkInformation* info)
32{
33 info->Set(vtkAlgorithm::INPUT_REQUIRED_DATA_TYPE(), "vtkImageData");
34 return 1;
35}
36
38 vtkInformation* /*request*/,
39 vtkInformationVector** inputVector,
40 vtkInformationVector* outputVector)
41{
42 vtkDebugMacro(<< "Executing VtkImageDataToPointCloudFilter");
43
44 vtkInformation* input_info = inputVector[0]->GetInformationObject(0);
45 vtkInformation* output_info = outputVector->GetInformationObject(0);
46 vtkImageData* input = vtkImageData::SafeDownCast(
47 input_info->Get(vtkDataObject::DATA_OBJECT()));
48 vtkPolyData* output = vtkPolyData::SafeDownCast(
49 output_info->Get(vtkDataObject::DATA_OBJECT()));
50
51 if (input->GetScalarSize() != sizeof(float))
52 {
53 vtkDebugMacro(
54 "Existing data does not have float-type and cannot be processed. "
55 "Aborting filter process...");
56 return 0;
57 }
58 float* pixvals = static_cast<float*>(input->GetScalarPointer());
59 int const n_comp = input->GetNumberOfScalarComponents();
60 if (n_comp < 1)
61 {
62 vtkDebugMacro("Error reading number of components.");
63 }
64 if (n_comp > 2)
65 {
66 vtkDebugMacro(
67 "RGB colours detected. Using only first channel for computation.");
68 }
69
70 vtkIdType const n_points = input->GetNumberOfPoints();
71 if (n_points == 0)
72 {
73 vtkDebugMacro("No data found!");
74 return -1;
75 }
76
77 double spacing[3];
78 input->GetSpacing(spacing);
79
80 if (MinValueRange == -1 || MaxValueRange == -1)
81 {
82 double range[2];
83 vtkPointData* input_data = input->GetPointData();
84 input_data->GetArray(0)->GetRange(range);
85 MinValueRange = range[0];
86 MaxValueRange = range[1];
87 }
88
89 std::vector<vtkIdType> density;
90 density.reserve(n_points);
91 for (vtkIdType i = 0; i < n_points; ++i)
92 {
93 // Skip transparent pixels
94 if (n_comp == 2 || n_comp == 4)
95 {
96 if (pixvals[(i + 1) * n_comp - 1] < 0.00000001f)
97 {
98 density.push_back(0);
99 continue;
100 }
101 }
102 double const val(pixvals[i * n_comp]);
103 double const calc_gamma = (IsLinear) ? 1 : Gamma;
104 std::size_t const pnts_per_cell =
105 interpolate(MinValueRange, MaxValueRange, val, calc_gamma);
106 density.push_back(static_cast<vtkIdType>(
107 std::floor(pnts_per_cell * GetPointScaleFactor())));
108 }
109
110 // Allocate the space needed for output objects
111 auto const sum =
112 std::accumulate(density.begin(), density.end(), vtkIdType{0});
113 vtkSmartPointer<vtkPoints> new_points = vtkSmartPointer<vtkPoints>::New();
114 new_points->SetNumberOfPoints(sum);
115 vtkSmartPointer<vtkCellArray> cells = vtkSmartPointer<vtkCellArray>::New();
116 cells->Allocate(sum);
117 vtkSmartPointer<vtkDoubleArray> intensity =
118 vtkSmartPointer<vtkDoubleArray>::New();
119 intensity->Allocate(sum);
120 intensity->SetName("Intensity");
121 double const half_cellsize(spacing[0] / 2.0);
122 std::size_t pnt_idx(0);
123 for (std::size_t i = 0; i < static_cast<std::size_t>(n_points); ++i)
124 {
125 if (density[i] == 0)
126 {
127 continue;
128 }
129 double p[3];
130 input->GetPoint(i, p);
131
132 MathLib::Point3d min_pnt{std::array<double, 3>{
133 {p[0] - half_cellsize, p[1] - half_cellsize, MinHeight}}};
134 MathLib::Point3d max_pnt{std::array<double, 3>{
135 {p[0] + half_cellsize, p[1] + half_cellsize, MaxHeight}}};
136 createPoints(new_points, cells, pnt_idx, density[i], min_pnt, max_pnt);
137 for (vtkIdType j = 0; j < density[i]; ++j)
138 {
139 intensity->InsertValue(pnt_idx + j, pixvals[i * n_comp]);
140 }
141 pnt_idx += density[i];
142 }
143
144 output->SetPoints(new_points);
145 output->SetVerts(cells);
146 output->GetPointData()->AddArray(intensity);
147 output->GetPointData()->SetActiveAttribute("Intensity",
148 vtkDataSetAttributes::SCALARS);
149 output->Squeeze();
150
151 vtkDebugMacro(<< "Created " << new_points->GetNumberOfPoints()
152 << " points.");
153 return 1;
154}
155
157 vtkSmartPointer<vtkPoints>& points,
158 vtkSmartPointer<vtkCellArray>& cells,
159 std::size_t pnt_idx,
160 std::size_t n_points,
161 MathLib::Point3d const& min_pnt,
162 MathLib::Point3d const& max_pnt) const
163{
164 for (std::size_t i = 0; i < n_points; ++i)
165 {
166 double p[3];
167 p[0] = getRandomNumber(min_pnt[0], max_pnt[0]);
168 p[1] = getRandomNumber(min_pnt[1], max_pnt[1]);
169 p[2] = getRandomNumber(min_pnt[2], max_pnt[2]);
170 points->SetPoint(pnt_idx + i, p);
171 cells->InsertNextCell(1);
172 cells->InsertCellPoint(pnt_idx + i);
173 }
174}
175
177 double const& max) const
178{
179 return (static_cast<double>(std::rand()) / RAND_MAX) * (max - min) + min;
180}
181
183 double high,
184 double p,
185 double gamma) const
186{
187 p = std::clamp(p, low, high);
188 double const r = (p - low) / (high - low);
189 return static_cast<std::size_t>(
191 std::pow(r, gamma) +
193}
vtkStandardNewMacro(VtkImageDataToPointCloudFilter)
int FillInputPortInformation(int port, vtkInformation *info) override
Sets input port to vtkImageData.
void PrintSelf(ostream &os, vtkIndent indent) override
Prints information about the filter.
void createPoints(vtkSmartPointer< vtkPoints > &points, vtkSmartPointer< vtkCellArray > &cells, std::size_t pnt_idx, std::size_t n_points, MathLib::Point3d const &min_pnt, MathLib::Point3d const &max_pnt) const
Creates the point objects based on the parameters set by the user.
double getRandomNumber(double const &min, double const &max) const
Returns a random number in [min, max].
std::size_t interpolate(double low, double high, double p, double gamma) const
int RequestData(vtkInformation *request, vtkInformationVector **inputVector, vtkInformationVector *outputVector) override
Updates the graphical object.