Skip to content

Commit 7e368df

Browse files
Merge pull request #150 from Geode-solutions/fix/gdal-dem
feat(DEM): add input support for dem files
2 parents ee2b746 + 5aa7c9d commit 7e368df

File tree

10 files changed

+322
-25
lines changed

10 files changed

+322
-25
lines changed

.vscode/settings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
"${workspaceFolder:OpenGeode}/include",
77
"${workspaceFolder:OpenGeode}/build/opengeode/install/include",
88
"${workspaceFolder:OpenGeode-IO}/include",
9-
"${workspaceFolder:OpenGeode-IO}/build/opengeode/install/include",
9+
"${workspaceFolder:OpenGeode-IO}/build/opengeode-io/install/include",
1010
"${workspaceFolder:OpenGeode-Geosciences}/include",
1111
"${workspaceFolder:OpenGeode-Geosciences}/build"
1212
],
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2019 - 2025 Geode-solutions
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*
22+
*/
23+
24+
#pragma once
25+
26+
#include <geode/geosciences_io/mesh/common.hpp>
27+
28+
#include <geode/mesh/io/polygonal_surface_input.hpp>
29+
30+
namespace geode
31+
{
32+
namespace internal
33+
{
34+
class DEMInput final : public PolygonalSurfaceInput< 3 >
35+
{
36+
public:
37+
explicit DEMInput( std::string_view filename )
38+
: PolygonalSurfaceInput< 3 >( filename )
39+
{
40+
}
41+
42+
static std::string_view extension()
43+
{
44+
static constexpr auto EXT = "dem";
45+
return EXT;
46+
}
47+
48+
std::unique_ptr< PolygonalSurface< 3 > > read(
49+
const MeshImpl& impl ) final;
50+
};
51+
} // namespace internal
52+
} // namespace geode

src/geode/geosciences_io/mesh/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ add_geode_library(
2323
FOLDER "geode/geosciences_io/mesh"
2424
SOURCES
2525
"common.cpp"
26+
"dem_input.cpp"
2627
"fem_output.cpp"
2728
"geotiff_input.cpp"
2829
"gocad_common.cpp"
@@ -41,6 +42,7 @@ add_geode_library(
4142
PUBLIC_HEADERS
4243
"common.hpp"
4344
INTERNAL_HEADERS
45+
"internal/dem_input.hpp"
4446
"internal/fem_output.hpp"
4547
"internal/geotiff_input.hpp"
4648
"internal/gocad_common.hpp"

src/geode/geosciences_io/mesh/common.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,12 @@
2222
*/
2323

2424
#include <geode/geosciences_io/mesh/common.hpp>
25+
26+
#include <gdal.h>
27+
2528
#include <geode/io/image/common.hpp>
2629

30+
#include <geode/geosciences_io/mesh/internal/dem_input.hpp>
2731
#include <geode/geosciences_io/mesh/internal/fem_output.hpp>
2832
#include <geode/geosciences_io/mesh/internal/geotiff_input.hpp>
2933
#include <geode/geosciences_io/mesh/internal/grdecl_input.hpp>
@@ -55,6 +59,13 @@ namespace
5559
geode::internal::TSOutput::extension().data() );
5660
}
5761

62+
void register_polygonal_surface_input()
63+
{
64+
geode::PolygonalSurfaceInputFactory3D::register_creator<
65+
geode::internal::DEMInput >(
66+
geode::internal::DEMInput::extension().data() );
67+
}
68+
5869
void register_tetrahedral_solid_output()
5970
{
6071
geode::TetrahedralSolidOutputFactory3D::register_creator<
@@ -134,6 +145,7 @@ namespace geode
134145
IOImageLibrary::initialize();
135146
register_triangulated_surface_input();
136147
register_triangulated_surface_output();
148+
register_polygonal_surface_input();
137149
register_tetrahedral_solid_output();
138150
register_edged_curve_input();
139151
register_edged_curve_output();
@@ -142,5 +154,6 @@ namespace geode
142154
register_hybrid_solid_input();
143155
register_point_set_input();
144156
register_point_set_output();
157+
GDALAllRegister();
145158
}
146159
} // namespace geode
Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,168 @@
1+
/*
2+
* Copyright (c) 2019 - 2025 Geode-solutions
3+
*
4+
* Permission is hereby granted, free of charge, to any person obtaining a copy
5+
* of this software and associated documentation files (the "Software"), to deal
6+
* in the Software without restriction, including without limitation the rights
7+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
* copies of the Software, and to permit persons to whom the Software is
9+
* furnished to do so, subject to the following conditions:
10+
*
11+
* The above copyright notice and this permission notice shall be included in
12+
* all copies or substantial portions of the Software.
13+
*
14+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
* SOFTWARE.
21+
*
22+
*/
23+
24+
#include <geode/geosciences_io/mesh/internal/dem_input.hpp>
25+
26+
#include <gdal.h>
27+
#include <gdal_priv.h>
28+
#include <gdal_utils.h>
29+
30+
#include <geode/geometry/point.hpp>
31+
#include <geode/geometry/vector.hpp>
32+
33+
#include <geode/mesh/builder/polygonal_surface_builder.hpp>
34+
#include <geode/mesh/core/polygonal_surface.hpp>
35+
36+
namespace
37+
{
38+
class DEMInputImpl
39+
{
40+
public:
41+
DEMInputImpl(
42+
geode::PolygonalSurface3D& surface, std::string_view filename )
43+
: surface_{ surface },
44+
builder_{ geode::PolygonalSurfaceBuilder3D::create( surface ) },
45+
gdal_data_{ GDALDataset::Open(
46+
geode::to_string( filename ).c_str(), GDAL_OF_READONLY ) }
47+
{
48+
OPENGEODE_EXCEPTION(
49+
gdal_data_, "[DEMInput] Failed to open file ", filename );
50+
}
51+
52+
void read_file()
53+
{
54+
read_metadata();
55+
const auto vertices = read_vertices();
56+
create_polygons( vertices );
57+
}
58+
59+
private:
60+
void create_polygons( absl::Span< const geode::index_t > vertices )
61+
{
62+
for( const auto i : geode::Range{ height_ - 1 } )
63+
{
64+
const auto i_offset = i * width_;
65+
for( const auto j : geode::Range{ width_ - 1 } )
66+
{
67+
const auto j_offset = j + width_;
68+
std::array polygon{ i_offset + j, i_offset + j + 1,
69+
i_offset + j_offset, i_offset + j_offset + 1 };
70+
bool found{ true };
71+
for( auto& vertex : polygon )
72+
{
73+
const auto vertex_id = vertices[vertex];
74+
if( vertex_id == geode::NO_ID )
75+
{
76+
found = false;
77+
break;
78+
}
79+
vertex = vertex_id;
80+
}
81+
if( !found )
82+
{
83+
continue;
84+
}
85+
builder_->create_polygon( polygon );
86+
}
87+
}
88+
}
89+
90+
absl::FixedArray< geode::index_t > read_vertices()
91+
{
92+
const auto nb_vertices = width_ * height_;
93+
const auto nb_bands = gdal_data_->GetRasterCount();
94+
OPENGEODE_EXCEPTION( nb_bands > 0, "[DEMInput] No bands found" );
95+
absl::FixedArray< float > elevation( nb_vertices );
96+
absl::FixedArray< geode::index_t > vertices(
97+
nb_vertices, geode::NO_ID );
98+
const auto band = gdal_data_->GetRasterBand( 1 );
99+
const auto status = band->RasterIO( GF_Read, 0, 0, width_, height_,
100+
elevation.data(), width_, height_, GDT_Float32, 0, 0 );
101+
const auto no_data_value = band->GetNoDataValue();
102+
OPENGEODE_EXCEPTION(
103+
status == CE_None, "[DEMInput] Failed to read elevation" );
104+
for( const auto i : geode::Range{ height_ } )
105+
{
106+
const auto i_contribution = y_direction_ * i;
107+
for( const auto j : geode::Range{ width_ } )
108+
{
109+
const auto vertex = i * width_ + j;
110+
const auto current_elevation = elevation[vertex];
111+
if( current_elevation == no_data_value )
112+
{
113+
continue;
114+
}
115+
const auto j_contribution = x_direction_ * j;
116+
const auto point =
117+
origin_ + i_contribution + j_contribution;
118+
vertices[vertex] = builder_->create_point(
119+
geode::Point3D{ { point.value( 0 ), point.value( 1 ),
120+
current_elevation } } );
121+
}
122+
}
123+
return vertices;
124+
}
125+
126+
void read_metadata()
127+
{
128+
std::array< double, 6 > geo_transform;
129+
const auto status =
130+
gdal_data_->GetGeoTransform( geo_transform.data() );
131+
OPENGEODE_EXCEPTION(
132+
status == CE_None, "[DEMInput] Failed to read geotransform" );
133+
for( const auto axis : geode::LRange{ 2 } )
134+
{
135+
origin_.set_value( axis, geo_transform[3 * axis] );
136+
x_direction_.set_value( axis, geo_transform[3 * axis + 1] );
137+
y_direction_.set_value( axis, geo_transform[3 * axis + 2] );
138+
}
139+
width_ = gdal_data_->GetRasterXSize();
140+
height_ = gdal_data_->GetRasterYSize();
141+
}
142+
143+
private:
144+
const geode::PolygonalSurface3D& surface_;
145+
std::unique_ptr< geode::PolygonalSurfaceBuilder3D > builder_;
146+
GDALDatasetUniquePtr gdal_data_;
147+
geode::Point2D origin_{ { 0., 0. } };
148+
geode::Vector2D x_direction_{ { 1., 0. } };
149+
geode::Vector2D y_direction_{ { 0., 1. } };
150+
geode::index_t width_{ 0 };
151+
geode::index_t height_{ 0 };
152+
};
153+
} // namespace
154+
155+
namespace geode
156+
{
157+
namespace internal
158+
{
159+
std::unique_ptr< PolygonalSurface3D > DEMInput::read(
160+
const MeshImpl& impl )
161+
{
162+
auto surface = PolygonalSurface3D::create( impl );
163+
DEMInputImpl reader{ *surface, this->filename() };
164+
reader.read_file();
165+
return surface;
166+
}
167+
} // namespace internal
168+
} // namespace geode

src/geode/geosciences_io/mesh/fem_output.cpp

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -86,19 +86,16 @@ namespace
8686

8787
class SolidFemOutputImpl
8888
{
89-
static constexpr const char CDATA_TAG_START[]{ "<![CDATA[" };
90-
static constexpr const char CDATA_TAG_END[]{ "]]>" };
91-
static constexpr const char APERTURE_ATTRIBUTE_NAME[]{
92-
"diagres_discontinuity_aperture"
93-
};
94-
static constexpr const char CONDUIT_AREA_ATTRIBUTE_NAME[]{
95-
"diagres_conduit_area"
96-
};
97-
static constexpr const char CONDUCTIVITY_ATTRIBUTE_NAME[]{
98-
"diagres_conductivity"
99-
};
100-
static constexpr const char SURFACE_NAME_ATTRIBUTE[]{ "surface_name" };
101-
static constexpr const char LINE_NAME_ATTRIBUTE[]{ "line_name" };
89+
static constexpr auto CDATA_TAG_START = "<![CDATA[";
90+
static constexpr auto CDATA_TAG_END = "]]>";
91+
static constexpr auto APERTURE_ATTRIBUTE_NAME =
92+
"diagres_discontinuity_aperture";
93+
static constexpr auto CONDUIT_AREA_ATTRIBUTE_NAME =
94+
"diagres_conduit_area";
95+
static constexpr auto CONDUCTIVITY_ATTRIBUTE_NAME =
96+
"diagres_conductivity";
97+
static constexpr auto SURFACE_NAME_ATTRIBUTE = "surface_name";
98+
static constexpr auto LINE_NAME_ATTRIBUTE = "line_name";
10299

103100
public:
104101
static constexpr geode::index_t OFFSET_START{ 1 };

src/geode/geosciences_io/model/internal/brep_fem_output.cpp

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,14 @@ namespace
5252

5353
class BRepFemOutputImpl
5454
{
55-
static constexpr const char APERTURE_ATTRIBUTE_NAME[]{
56-
"diagres_discontinuity_aperture"
57-
};
58-
static constexpr const char CONDUIT_AREA_ATTRIBUTE_NAME[]{
59-
"diagres_conduit_area"
60-
};
61-
static constexpr const char CONDUCTIVITY_ATTRIBUTE_NAME[]{
62-
"diagres_conductivity"
63-
};
64-
static constexpr const char SURFACE_NAME_ATTRIBUTE[]{ "surface_name" };
65-
static constexpr const char LINE_NAME_ATTRIBUTE[]{ "line_name" };
55+
static constexpr auto APERTURE_ATTRIBUTE_NAME =
56+
"diagres_discontinuity_aperture";
57+
static constexpr auto CONDUIT_AREA_ATTRIBUTE_NAME =
58+
"diagres_conduit_area";
59+
static constexpr auto CONDUCTIVITY_ATTRIBUTE_NAME =
60+
"diagres_conductivity";
61+
static constexpr auto SURFACE_NAME_ATTRIBUTE = "surface_name";
62+
static constexpr auto LINE_NAME_ATTRIBUTE = "line_name";
6663

6764
public:
6865
static constexpr geode::index_t OFFSET_START{ 1 };

tests/data/bathy_IrishSea_DEM.dem

Lines changed: 1 addition & 0 deletions
Large diffs are not rendered by default.

tests/mesh/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ add_geode_test(
2525
OpenGeode::mesh
2626
${PROJECT_NAME}::mesh
2727
)
28+
add_geode_test(
29+
SOURCE "test-dem.cpp"
30+
DEPENDENCIES
31+
OpenGeode::basic
32+
OpenGeode::mesh
33+
OpenGeode-IO::mesh
34+
${PROJECT_NAME}::mesh
35+
)
2836
add_geode_test(
2937
SOURCE "test-geotiff.cpp"
3038
DEPENDENCIES

0 commit comments

Comments
 (0)