Quetzal-CoaTL
The Coalescence Template Library
Loading...
Searching...
No Matches
landscape.hpp
1// Copyright 2021 Arnaud Becheler <abechele@umich.edu>
2
3/*********************************************************************** * This program is free software; you can
4 *redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free
5 *Software Foundation; either version 2 of the License, or * (at your option) any later version. *
6 * *
7 ***************************************************************************/
8
9#pragma once
10
11#include "raster.hpp"
12
13#include <algorithm>
14#include <assert.h>
15#include <functional> // std::cref
16#include <iostream>
17#include <map>
18#include <optional>
19#include <set>
20#include <stdexcept>
21#include <string>
22#include <tuple> // std::forward_as_tuple
23
24namespace quetzal::geography
25{
41template <typename Key = std::string, typename Time = int> class landscape
42{
43
44 public:
46 using key_type = Key;
47
49 using time_type = Time;
50
52 using location_descriptor = typename raster<time_type>::location_descriptor;
53
55 using time_descriptor = typename raster<time_type>::time_descriptor;
56
58 using latlon = typename raster<time_type>::latlon;
59
61 using lonlat = typename raster<time_type>::lonlat;
62
64 using colrow = typename raster<time_type>::colrow;
65
67 using rowcol = typename raster<time_type>::rowcol;
68
70 using decimal_degree = typename raster<time_type>::decimal_degree;
71
72 private:
73 std::map<key_type, raster<Time>> _variables;
74
76 landscape(const std::map<key_type, std::filesystem::path> &files, const std::vector<time_type> &times)
77 : _variables()
78 {
79
80 for (auto const &it : files)
81 {
82 _variables.emplace(std::piecewise_construct, std::forward_as_tuple(it.first),
83 std::forward_as_tuple(it.second, times));
84 }
85
86 auto have_same_origin = [this](auto const &it) {
87 return it.second.origin() == _variables.cbegin()->second.origin();
88 };
89
90 if (!all_of(_variables.cbegin(), _variables.cend(), have_same_origin))
91 {
92 throw std::runtime_error("all ecological quantities dataset must have same origin");
93 }
94
95 auto have_same_extent = [this](auto const &it) {
96 return it.second.get_extent() == _variables.cbegin()->second.get_extent();
97 };
98
99 if (!all_of(_variables.cbegin(), _variables.cend(), have_same_extent))
100 {
101 throw std::runtime_error("all ecological quantities dataset must have same extent");
102 }
103
104 auto have_same_resolution = [this](auto const &it) {
105 return it.second.get_resolution() == _variables.cbegin()->second.get_resolution();
106 };
107
108 if (!all_of(_variables.cbegin(), _variables.cend(), have_same_resolution))
109 {
110 throw std::runtime_error("all ecological quantities dataset must have same resolution");
111 }
112
113 auto have_same_depth = [this](auto const &it) {
114 return it.second.depth() == _variables.cbegin()->second.depth();
115 };
116
117 if (!all_of(_variables.cbegin(), _variables.cend(), have_same_depth))
118 {
119 throw std::runtime_error("all ecological quantities dataset must have same depth");
120 }
121 }
122
123 public:
126
135 inline static landscape from_file(const std::map<key_type, std::filesystem::path> &files,
136 const std::vector<time_type> &times)
137 {
138 return landscape(files, times);
139 }
140
147 template <typename Callable>
148 requires std::invocable<Callable, location_descriptor, time_descriptor, std::optional<double>>
149 inline void to_geotiff(Callable f, time_descriptor start, time_descriptor end, const std::filesystem::path &file) const
150 {
151 _variables.cbegin()->second.to_geotiff(f, start, end, file);
152 }
153
157 inline void to_shapefile(std::vector<latlon> points, const std::filesystem::path &file) const
158 {
159 _variables.cbegin()->second.to_shapefile(points, file);
160 }
161
165 inline void to_shapefile(std::map<latlon, int> counts, const std::filesystem::path &file) const
166 {
167 _variables.cbegin()->second.to_shapefile(counts, file);
168 }
169
171 std::ostream &write(std::ostream &stream) const
172 {
173 stream << "Landscape of " << _variables.size() << " aligned rasters:\n";
174
175 for (const auto &it : _variables)
176 stream << it.first << " ";
177
178 stream << "\nOrigin: " << origin() << "\nWidth: " << width() << "\nHeight: " << height()
179 << "\nDepth: " << depth() << "\nResolution: "
180 << "\n\tLat: " << get_resolution().lat() << "\n\tLon: " << get_resolution().lon() << "\nExtent:"
181 << "\n\tLat min: " << get_extent().lat_min() << "\n\tLat max: " << get_extent().lat_max()
182 << "\n\tLon min: " << get_extent().lon_min() << "\n\tLon max: " << get_extent().lon_max();
183 return stream;
184 }
185
187
190
193 inline auto num_variables() const noexcept
194 {
195 return _variables.size();
196 }
197
200 inline auto num_locations() const noexcept
201 {
202 return this->width() * this->height();
203 }
204
206
209
214 inline const raster<time_type> &operator[](const key_type &key) const
215 {
216 return _variables.at(key);
217 }
218
223 inline raster<time_type> &operator[](const key_type &key)
224 {
225 return _variables.at(key);
226 }
227
229
232
234 inline latlon origin() const noexcept
235 {
236 return _variables.cbegin()->second.origin();
237 }
238
241 {
242 return _variables.cbegin()->second.get_resolution();
243 }
244
246 inline extent<decimal_degree> get_extent() const noexcept
247 {
248 return _variables.cbegin()->second.get_extent();
249 }
250
252 inline int width() const noexcept
253 {
254 return _variables.cbegin()->second.width();
255 }
256
258 inline int height() const noexcept
259 {
260 return _variables.cbegin()->second.height();
261 }
262
264 inline int depth() const noexcept
265 {
266 return _variables.cbegin()->second.depth();
267 }
268
270
273
276 inline auto locations() const noexcept
277 {
278 return _variables.cbegin()->second.locations();
279 }
280
283 inline auto times() const noexcept
284 {
285 return _variables.cbegin()->second.times();
286 }
287
291 inline bool is_valid(location_descriptor x) const noexcept
292 {
293 return _variables.cbegin()->second.is_valid(x);
294 }
295
299 inline bool is_valid(const colrow &x) const noexcept
300 {
301 return _variables.cbegin()->second.is_valid(x);
302 }
303
307 inline bool is_valid(const rowcol &x) const noexcept
308 {
309 return _variables.cbegin()->second.is_valid(x);
310 }
311
315 inline bool contains(const latlon &x) const noexcept
316 {
317 return _variables.cbegin()->second.contains(x);
318 }
319
323 inline bool contains(const lonlat &x) const noexcept
324 {
325 return _variables.cbegin()->second.contains(x);
326 }
327
331 inline bool is_valid(time_descriptor t) const noexcept
332 {
333 return _variables.cbegin()->second.is_valid(t);
334 }
335
339 inline bool is_recorded(const time_type &t) const noexcept
340 {
341 return _variables.cbegin()->second.is_recorded(t);
342 }
343
347 inline bool is_in_interval(const time_type &t) const noexcept
348 {
349 return _variables.cbegin()->second.is_in_interval(t);
350 }
351
353
356
361 inline location_descriptor to_descriptor(const colrow &x) const noexcept
362 {
363 assert( is_valid(x) );
364 return _variables.cbegin()->second.to_descriptor(x);
365 }
366
371 inline location_descriptor to_descriptor(const latlon &x) const noexcept
372 {
373 assert( contains(x) );
374 return _variables.cbegin()->second.to_descriptor(x);
375 }
376
381 colrow to_colrow(const latlon &x) const noexcept
382 {
383 assert( contains(x) );
384 return _variables.cbegin()->second.to_colrow(x);
385 }
386
391 inline rowcol to_rowcol(const latlon &x) const noexcept
392 {
393 assert( contains(x) );
394 return _variables.cbegin()->second.to_rowcol(x);
395 }
396
401 inline colrow to_colrow(location_descriptor x) const noexcept
402 {
403 assert( is_valid(x) );
404 return _variables.cbegin()->second.to_colrow(x);
405 }
406
411 inline latlon to_latlon(location_descriptor x) const noexcept
412 {
413 assert( is_valid(x) );
414 return _variables.cbegin()->second.to_latlon(x);
415 }
416
421 inline lonlat to_lonlat(location_descriptor x) const noexcept
422 {
423 assert( is_valid(x) );
424 return _variables.cbegin()->second.to_lonlat(x);
425 }
426
431 inline latlon to_latlon(const colrow &x) const noexcept
432 {
433 assert( is_valid(x) );
434 return _variables.cbegin()->second.to_latlon(x);
435 }
436
441 inline lonlat to_lonlat(const colrow &x) const noexcept
442 {
443 assert( is_valid(x) );
444 return _variables.cbegin()->second.to_lonlat(x);
445 }
446
452 inline latlon to_centroid(const latlon &x) const
453 {
454 assert(this->contains(x));
455 return _variables.cbegin()->second.to_centroid(x);
456 }
457
459};
460
461template <typename Key, typename Time> std::ostream &operator<<(std::ostream &os, const landscape<Key, Time> &l)
462{
463 return l.write(os);
464}
465
466} // namespace quetzal::geography
extent of a raster grid object
Definition extent.hpp:19
Discrete spatio-temporal variations of a set of environmental variables.
Definition landscape.hpp:42
colrow to_colrow(location_descriptor x) const noexcept
Column and row of the cell to which the given descriptor belongs.
Definition landscape.hpp:401
static landscape from_file(const std::map< key_type, std::filesystem::path > &files, const std::vector< time_type > &times)
Read the rasters from a set of input geotiff files.
Definition landscape.hpp:135
const raster< time_type > & operator[](const key_type &key) const
Returns a const reference to the mapped raster with key equivalent to key. If no such raster exists,...
Definition landscape.hpp:214
auto num_locations() const noexcept
Number of cells in the raster.
Definition landscape.hpp:200
latlon origin() const noexcept
Origin of the spatial grid.
Definition landscape.hpp:234
lonlat to_lonlat(location_descriptor x) const noexcept
Longitude and latitude of the cell to which the given coordinate belongs.
Definition landscape.hpp:421
auto times() const noexcept
Time descriptors (unique identifiers) of the dataset bands.
Definition landscape.hpp:283
bool is_recorded(const time_type &t) const noexcept
Search for the exact time in the list of time points recorded by the raster.
Definition landscape.hpp:339
bool is_valid(location_descriptor x) const noexcept
Check if a descriptor describes a valid location of the spatial grid.
Definition landscape.hpp:291
std::ostream & write(std::ostream &stream) const
Landscape is streamable.
Definition landscape.hpp:171
latlon to_latlon(location_descriptor x) const noexcept
Latitude and longitude of the cell to which the given coordinate belongs.
Definition landscape.hpp:411
resolution< decimal_degree > get_resolution() const noexcept
Resolution of the spatial grid.
Definition landscape.hpp:240
void to_geotiff(Callable f, time_descriptor start, time_descriptor end, const std::filesystem::path &file) const
Export a spatio-temporal raster to a Geotiff file.
Definition landscape.hpp:149
int height() const noexcept
Height of the spatial grid.
Definition landscape.hpp:258
auto num_variables() const noexcept
Retrieves the number of variables (rasters)
Definition landscape.hpp:193
raster< time_type > & operator[](const key_type &key)
Returns a reference to the mapped raster with key equivalent to key. If no such raster exists,...
Definition landscape.hpp:223
location_descriptor to_descriptor(const latlon &x) const noexcept
Location descriptor of the cell to which the given coordinate belongs.
Definition landscape.hpp:371
bool contains(const lonlat &x) const noexcept
Check if the raster contains a coordinate.
Definition landscape.hpp:323
bool is_valid(const rowcol &x) const noexcept
Check if the coordinate describes a valid location of the spatial grid.
Definition landscape.hpp:307
latlon to_centroid(const latlon &x) const
Reprojects a coordinate to the centroid of the cell it belongs.
Definition landscape.hpp:452
colrow to_colrow(const latlon &x) const noexcept
Column and row of the cell to which the given coordinate belongs.
Definition landscape.hpp:381
int depth() const noexcept
Depth of the spatial grid.
Definition landscape.hpp:264
extent< decimal_degree > get_extent() const noexcept
Extent of the spatial grid.
Definition landscape.hpp:246
location_descriptor to_descriptor(const colrow &x) const noexcept
Location descriptor of the cell identified by its column/row.
Definition landscape.hpp:361
bool contains(const latlon &x) const noexcept
Check if the raster contains a coordinate.
Definition landscape.hpp:315
lonlat to_lonlat(const colrow &x) const noexcept
Longitude and latitude of the deme identified by its column/row.
Definition landscape.hpp:441
auto locations() const noexcept
Location descriptors (unique identifiers) of the grid cells.
Definition landscape.hpp:276
void to_shapefile(std::vector< latlon > points, const std::filesystem::path &file) const
Export spatial points to a shapefile.
Definition landscape.hpp:157
void to_shapefile(std::map< latlon, int > counts, const std::filesystem::path &file) const
Export geolocalized counts as spatial-points to a shapefile.
Definition landscape.hpp:165
bool is_valid(const colrow &x) const noexcept
Check if the coordinate describes a valid location of the spatial grid.
Definition landscape.hpp:299
latlon to_latlon(const colrow &x) const noexcept
Latitude and longitude of the cell identified by its column/row.
Definition landscape.hpp:431
bool is_in_interval(const time_type &t) const noexcept
Check if the exact time point falls between the first and last date of record.
Definition landscape.hpp:347
int width() const noexcept
Width of the spatial grid.
Definition landscape.hpp:252
rowcol to_rowcol(const latlon &x) const noexcept
Row and column of the cell to which the given coordinate belongs.
Definition landscape.hpp:391
bool is_valid(time_descriptor t) const noexcept
Check if the time descriptor is a valid index.
Definition landscape.hpp:331
Discrete spatio-temporal variations of an environmental variable.
Definition raster.hpp:38
Resolution of a spatial grid.
Definition resolution.hpp:16
constexpr value_type lat() const noexcept
Gets latitude resolution.
Definition resolution.hpp:35
constexpr value_type lon() const noexcept
Gets longitude resolution.
Definition resolution.hpp:41
Geospatial data formatting and processing.
Definition geography.hpp:17
std::ostream & operator<<(std::ostream &stream, const C &c)
GridCoordinates are streamable.
Definition coordinates.hpp:51
Grid coordinates.
Definition coordinates.hpp:82
Geographic coordinates.
Definition coordinates.hpp:179
Geographic coordinates.
Definition coordinates.hpp:218
Grid coordinates.
Definition coordinates.hpp:61