OGS
RasterToMesh.cpp
Go to the documentation of this file.
1 
11 #include "RasterToMesh.h"
12 
13 #include <vtkCell.h>
14 #include <vtkCellData.h>
15 #include <vtkDataArray.h>
16 #include <vtkImageData.h>
17 #include <vtkPointData.h>
18 #include <vtkSmartPointer.h>
19 
20 #include "BaseLib/Logging.h"
22 #include "MeshLib/Mesh.h"
26 #include "MeshLib/Node.h"
27 
28 namespace MeshLib
29 {
30 std::unique_ptr<MeshLib::Mesh> RasterToMesh::convert(
31  GeoLib::Raster const& raster,
32  MeshElemType elem_type,
33  UseIntensityAs intensity_type,
34  std::string const& array_name)
35 {
36  return convert(raster.begin(),
37  raster.getHeader(),
38  elem_type,
39  intensity_type,
40  array_name);
41 }
42 
43 std::unique_ptr<MeshLib::Mesh> RasterToMesh::convert(
44  vtkImageData* img,
45  const double origin[3],
46  const double scalingFactor,
47  MeshElemType elem_type,
48  UseIntensityAs intensity_type,
49  std::string const& array_name)
50 {
51  if ((elem_type != MeshElemType::TRIANGLE) &&
52  (elem_type != MeshElemType::QUAD) &&
53  (elem_type != MeshElemType::HEXAHEDRON) &&
54  (elem_type != MeshElemType::PRISM))
55  {
56  ERR("Invalid Mesh Element Type.");
57  return nullptr;
58  }
59 
60  int* dims = img->GetDimensions();
61  if (((elem_type == MeshElemType::TRIANGLE) ||
62  (elem_type == MeshElemType::QUAD)) &&
63  dims[2] != 1)
64  {
65  ERR("Triangle or Quad elements cannot be used to construct meshes from "
66  "3D rasters.");
67  return nullptr;
68  }
69 
70  vtkSmartPointer<vtkDataArray> pixelData =
71  vtkSmartPointer<vtkDataArray>(img->GetPointData()->GetScalars());
72  int nTuple = pixelData->GetNumberOfComponents();
73  if (nTuple < 1 || nTuple > 4)
74  {
75  ERR("VtkMeshConverter::convertImgToMesh(): Unsupported pixel "
76  "composition!");
77  return nullptr;
78  }
79 
80  MathLib::Point3d const orig(
81  std::array<double, 3>{{origin[0] - 0.5 * scalingFactor,
82  origin[1] - 0.5 * scalingFactor, origin[2]}});
83  GeoLib::RasterHeader const header = {static_cast<std::size_t>(dims[0]),
84  static_cast<std::size_t>(dims[1]),
85  static_cast<std::size_t>(dims[2]),
86  orig,
87  scalingFactor,
88  -9999};
89 
90  std::vector<double> pix(header.n_cols * header.n_rows * header.n_depth, 0);
91  for (std::size_t k = 0; k < header.n_depth; k++)
92  {
93  std::size_t const layer_idx = (k * header.n_rows * header.n_cols);
94  for (std::size_t i = 0; i < header.n_rows; i++)
95  {
96  std::size_t const idx = i * header.n_cols + layer_idx;
97  for (std::size_t j = 0; j < header.n_cols; j++)
98  {
99  double* colour = pixelData->GetTuple(idx + j);
100  bool const visible = (nTuple == 2 || nTuple == 4)
101  ? (colour[nTuple - 1] != 0)
102  : true;
103  if (!visible)
104  {
105  pix[idx + j] = header.no_data;
106  }
107  else
108  {
109  pix[idx + j] = (nTuple < 3) ? colour[0] : // grey (+ alpha)
110  (0.3 * colour[0] + 0.6 * colour[1] +
111  0.1 * colour[2]); // rgb(a)
112  }
113  }
114  }
115  }
116 
117  return convert(pix.data(), header, elem_type, intensity_type, array_name);
118 }
119 
120 std::unique_ptr<MeshLib::Mesh> RasterToMesh::convert(
121  double const* const img,
122  GeoLib::RasterHeader const& header,
123  MeshElemType elem_type,
124  UseIntensityAs intensity_type,
125  std::string const& array_name)
126 {
127  if ((elem_type != MeshElemType::TRIANGLE) &&
128  (elem_type != MeshElemType::QUAD) &&
129  (elem_type != MeshElemType::HEXAHEDRON) &&
130  (elem_type != MeshElemType::PRISM))
131  {
132  ERR("Invalid Mesh Element Type.");
133  return nullptr;
134  }
135 
136  if (((elem_type == MeshElemType::TRIANGLE) ||
137  (elem_type == MeshElemType::QUAD)) &&
138  header.n_depth != 1)
139  {
140  ERR("Triangle or Quad elements cannot be used to construct meshes from "
141  "3D rasters.");
142  return nullptr;
143  }
144 
145  if (intensity_type == UseIntensityAs::ELEVATION &&
146  ((elem_type == MeshElemType::PRISM) ||
147  (elem_type == MeshElemType::HEXAHEDRON)))
148  {
149  ERR("Elevation mapping can only be performed for 2D meshes.");
150  return nullptr;
151  }
152 
153  std::unique_ptr<MeshLib::Mesh> mesh;
154  if (elem_type == MeshElemType::TRIANGLE)
155  {
156  mesh.reset(
158  header.n_rows,
159  header.cell_size,
160  header.origin,
161  "RasterDataMesh"));
162  }
163  else if (elem_type == MeshElemType::QUAD)
164  {
165  mesh.reset(
167  header.n_rows,
168  header.cell_size,
169  header.origin,
170  "RasterDataMesh"));
171  }
172  else if (elem_type == MeshElemType::PRISM)
173  {
174  mesh.reset(
176  header.n_rows,
177  header.n_depth,
178  header.cell_size,
179  header.origin,
180  "RasterDataMesh"));
181  }
182  else if (elem_type == MeshElemType::HEXAHEDRON)
183  {
184  mesh.reset(
186  header.n_rows,
187  header.n_depth,
188  header.cell_size,
189  header.origin,
190  "RasterDataMesh"));
191  }
192 
193  std::unique_ptr<MeshLib::Mesh> new_mesh;
194  std::vector<std::size_t> elements_to_remove;
195  if (intensity_type == UseIntensityAs::ELEVATION)
196  {
197  std::vector<MeshLib::Node*> const& nodes(mesh->getNodes());
198  std::vector<MeshLib::Element*> const& elems(mesh->getElements());
199  std::size_t const n_nodes(elems[0]->getNumberOfNodes());
200  bool const double_idx = (elem_type == MeshElemType::TRIANGLE) ||
201  (elem_type == MeshElemType::PRISM);
202  std::size_t const m = (double_idx) ? 2 : 1;
203  for (std::size_t k = 0; k < header.n_depth; k++)
204  {
205  std::size_t const layer_idx = (k * header.n_rows * header.n_cols);
206  for (std::size_t i = 0; i < header.n_cols; i++)
207  {
208  std::size_t const idx(i * header.n_rows + layer_idx);
209  for (std::size_t j = 0; j < header.n_rows; j++)
210  {
211  double const val(img[idx + j]);
212  if (val == header.no_data)
213  {
214  elements_to_remove.push_back(m * (idx + j));
215  if (double_idx)
216  {
217  elements_to_remove.push_back(m * (idx + j) + 1);
218  }
219  continue;
220  }
221  for (std::size_t n = 0; n < n_nodes; ++n)
222  {
223  (*(nodes[getNodeIndex(*elems[m * (idx + j)], n)]))[2] =
224  val;
225  if (double_idx)
226  {
227  (*(nodes[getNodeIndex(*elems[m * (idx + j) + 1],
228  n)]))[2] = val;
229  }
230  }
231  }
232  }
233  }
234  }
235  else
236  {
237  MeshLib::Properties& properties = mesh->getProperties();
238  MeshLib::ElementSearch ex(*mesh);
239  if (array_name == "MaterialIDs")
240  {
241  auto* const prop_vec = properties.createNewPropertyVector<int>(
242  array_name, MeshLib::MeshItemType::Cell, 1);
243  fillPropertyVector<int>(*prop_vec, img, header, elem_type);
244  ex.searchByPropertyValue<int>(array_name,
245  static_cast<int>(header.no_data));
246  }
247  else
248  {
249  auto* const prop_vec = properties.createNewPropertyVector<double>(
250  array_name, MeshLib::MeshItemType::Cell, 1);
251  fillPropertyVector<double>(*prop_vec, img, header, elem_type);
252  ex.searchByPropertyValue<double>(array_name, header.no_data);
253  }
254  elements_to_remove = ex.getSearchedElementIDs();
255  }
256  if (!elements_to_remove.empty())
257  {
258  new_mesh.reset(MeshLib::removeElements(
259  *mesh, elements_to_remove, mesh->getName()));
260  }
261  else
262  {
263  new_mesh = std::move(mesh);
264  }
265 
266  if (intensity_type == UseIntensityAs::NONE)
267  {
268  new_mesh->getProperties().removePropertyVector(array_name);
269  }
270 
271  return new_mesh;
272 }
273 
274 } // end namespace MeshLib
void ERR(char const *fmt, Args const &... args)
Definition: Logging.h:42
Definition of the Mesh class.
Definition of the Node class.
Class Raster is used for managing raster data.
Definition: Raster.h:42
const_iterator begin() const
Definition: Raster.h:81
RasterHeader const & getHeader() const
Returns the complete header information.
Definition: Raster.h:70
Element search class.
Definition: ElementSearch.h:28
std::size_t searchByPropertyValue(std::string const &property_name, PROPERTY_TYPE const property_value)
Definition: ElementSearch.h:46
const std::vector< std::size_t > & getSearchedElementIDs() const
return marked elements
Definition: ElementSearch.h:33
Property manager on mesh items. Class Properties manages scalar, vector or matrix properties....
Definition: Properties.h:36
PropertyVector< T > * createNewPropertyVector(std::string const &name, MeshItemType mesh_item_type, std::size_t n_components=1)
static std::unique_ptr< MeshLib::Mesh > convert(GeoLib::Raster const &raster, MeshElemType elem_type, UseIntensityAs intensity_type, std::string const &array_name="Colour")
Mesh * generateRegularPrismMesh(const double x_length, const double y_length, const double z_length, const std::size_t x_subdivision, const std::size_t y_subdivision, const std::size_t z_subdivision, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
Mesh * generateRegularTriMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
Mesh * generateRegularQuadMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
Mesh * generateRegularHexMesh(const BaseLib::ISubdivision &div_x, const BaseLib::ISubdivision &div_y, const BaseLib::ISubdivision &div_z, MathLib::Point3d const &origin=MathLib::ORIGIN, std::string const &mesh_name="mesh")
MeshLib::Mesh * removeElements(const MeshLib::Mesh &mesh, const std::vector< std::size_t > &removed_element_ids, const std::string &new_mesh_name)
std::size_t getNodeIndex(Element const &element, unsigned const idx)
Definition: Element.cpp:225
UseIntensityAs
Selection of possible interpretations for intensities.
Definition: MeshEnums.h:83
MeshElemType
Types of mesh elements supported by OpenGeoSys. Values are from VTKCellType enum.
Definition: MeshEnums.h:27
Contains the relevant information when storing a geoscientific raster data.
Definition: Raster.h:25
std::size_t n_depth
Definition: Raster.h:28
double cell_size
Definition: Raster.h:30
MathLib::Point3d origin
Definition: Raster.h:29
std::size_t n_cols
Definition: Raster.h:26
std::size_t n_rows
Definition: Raster.h:27