-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathgraster.hpp
353 lines (309 loc) · 10.2 KB
/
graster.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
/*
* PoPS model - Reading and writing GRASS GIS rasters as Raster
*
* Copyright (C) 2019 by the authors.
*
* Authors: Vaclav Petras (wenzeslaus gmail com)
*
* The code contained herein is licensed under the GNU General Public
* License. You may obtain a copy of the GNU General Public License
* Version 2 or later at the following locations:
*
* http://www.opensource.org/licenses/gpl-license.html
* http://www.gnu.org/copyleft/gpl.html
*/
#ifndef GRASTER_HPP
#define GRASTER_HPP
#include "pops/raster.hpp"
#include "pops/date.hpp"
extern "C" {
#include <grass/gis.h>
#include <grass/glocale.h>
#include <grass/raster.h>
}
#include <vector>
#include <string>
#include <type_traits>
/** Convert pops::Date to GRASS GIS TimeStamp */
void date_to_grass(pops::Date date, struct TimeStamp* timestamp)
{
struct DateTime date_time;
datetime_set_type(&date_time, DATETIME_ABSOLUTE, DATETIME_YEAR, DATETIME_DAY, 0);
datetime_set_year(&date_time, date.year());
datetime_set_month(&date_time, date.month());
datetime_set_day(&date_time, date.day());
G_init_timestamp(timestamp);
G_set_timestamp(timestamp, &date_time);
}
// The right C function to call in function templates is picked using
// the following overloads based on the type of buffer.
/** Overload for get row function */
inline void grass_raster_get_row(int fd, DCELL* buffer, int row)
{
Rast_get_d_row(fd, buffer, row);
}
/** Overload for get row function */
inline void grass_raster_get_row(int fd, FCELL* buffer, int row)
{
Rast_get_f_row(fd, buffer, row);
}
/** Overload for get row function */
inline void grass_raster_get_row(int fd, CELL* buffer, int row)
{
Rast_get_c_row(fd, buffer, row);
}
/** Overload for is null value function */
inline bool grass_raster_is_null_value(const DCELL* value)
{
return Rast_is_d_null_value(value);
}
/** Overload for is null value function */
inline bool grass_raster_is_null_value(const FCELL* value)
{
return Rast_is_f_null_value(value);
}
/** Overload for is null value function */
inline bool grass_raster_is_null_value(const CELL* value)
{
return Rast_is_c_null_value(value);
}
/** Set a value to zero (0) if it is null (GRASS GIS NULL) */
template<typename Number>
inline void set_null_to_zero(Number* value)
{
if (grass_raster_is_null_value(value))
*value = 0;
}
/** Overload for put row function */
inline void grass_raster_put_row(int fd, DCELL* buffer)
{
Rast_put_d_row(fd, buffer);
}
/** Overload for put row function */
inline void grass_raster_put_row(int fd, FCELL* buffer)
{
Rast_put_f_row(fd, buffer);
}
/** Overload for put row function */
inline void grass_raster_put_row(int fd, CELL* buffer)
{
Rast_put_c_row(fd, buffer);
}
/** Overload for set null value function */
inline void grass_raster_set_null(DCELL* buffer, int num_values = 1)
{
Rast_set_d_null_value(buffer, num_values);
}
/** Overload for set null value function */
inline void grass_raster_set_null(FCELL* buffer, int num_values = 1)
{
Rast_set_f_null_value(buffer, num_values);
}
/** Overload for set null value function */
inline void grass_raster_set_null(CELL* buffer, int num_values = 1)
{
Rast_set_c_null_value(buffer, num_values);
}
/** Policy settings for handling null values in the input */
enum class NullInputPolicy
{
NullsAsZeros, ///< Convert null values to zeros
NoConversions ///< Don't do any conversions
};
// Null values in all inputs we have mean 0 for the model, so using it
// as our default everywhere.
constexpr auto DefaultNullInputPolicy = NullInputPolicy::NullsAsZeros;
/** Policy settings for handling null values in the output */
enum class NullOutputPolicy
{
ZerosAsNulls, ///< Convert zeros to null values
NoConversions ///< Don't do any conversions
};
// We are not producing any null values in the model, so there is no
// point in doing any conversions, so using it as default.
constexpr auto DefaultNullOutputPolicy = NullOutputPolicy::NoConversions;
/** Read a GRASS GIS raster map to the Raster
*
* The caller is required to specify the type of the raster as a
* template parameter:
*
* ```
* raster_from_grass<double>(name)
* ````
*
* Given the types of GRASS GIS raster maps, it supports only
* int, float, and double (CELL, FCELL, and DCELL).
*/
template<typename Number>
inline pops::Raster<Number> raster_from_grass(
const char* name, NullInputPolicy null_policy = DefaultNullInputPolicy)
{
unsigned rows = Rast_window_rows();
unsigned cols = Rast_window_cols();
pops::Raster<Number> rast(rows, cols);
Number* data = rast.data();
int fd = Rast_open_old(name, "");
for (unsigned row = 0; row < rows; row++) {
auto row_pointer = data + (row * cols);
grass_raster_get_row(fd, row_pointer, row);
if (null_policy == NullInputPolicy::NullsAsZeros) {
for (unsigned col = 0; col < cols; ++col) {
set_null_to_zero(row_pointer + col);
}
}
}
Rast_close(fd);
return rast;
}
/** Overload of raster_from_grass(const char *) */
template<typename Number>
inline pops::Raster<Number> raster_from_grass(
const std::string& name, NullInputPolicy null_policy = DefaultNullInputPolicy)
{
return raster_from_grass<Number>(name.c_str(), null_policy);
}
/** Converts type to GRASS GIS raster map type identifier.
*
* Use `::value` to obtain the map type identifier.
* When conversion is not possible, compile error about `value` not
* being a member of this struct is issued.
*/
template<typename Number>
struct GrassRasterMapType
{
};
/** Specialization for GRASS GIS raster map type convertor */
template<>
struct GrassRasterMapType<CELL> : std::integral_constant<RASTER_MAP_TYPE, CELL_TYPE>
{
};
/** Specialization for GRASS GIS raster map type convertor */
template<>
struct GrassRasterMapType<FCELL> : std::integral_constant<RASTER_MAP_TYPE, FCELL_TYPE>
{
};
/** Specialization for GRASS GIS raster map type convertor */
template<>
struct GrassRasterMapType<DCELL> : std::integral_constant<RASTER_MAP_TYPE, DCELL_TYPE>
{
};
/** Write a Raster to a GRASS GIS raster map.
*
* When used, the template is resolved based on the parameter.
*/
template<typename Number>
void inline raster_to_grass(
pops::Raster<Number> raster,
const char* name,
NullOutputPolicy null_policy = DefaultNullOutputPolicy,
const char* title = nullptr,
struct TimeStamp* timestamp = nullptr)
{
Number* data = raster.data();
unsigned rows = raster.rows();
unsigned cols = raster.cols();
int fd = Rast_open_new(name, GrassRasterMapType<Number>::value);
for (unsigned i = 0; i < rows; i++) {
auto row_pointer = data + (i * cols);
if (null_policy == NullOutputPolicy::ZerosAsNulls) {
for (unsigned j = 0; j < cols; ++j) {
if (*(row_pointer + j) == 0)
grass_raster_set_null(row_pointer + j);
}
}
grass_raster_put_row(fd, row_pointer);
}
Rast_close(fd);
// writing map title and history
if (title)
Rast_put_cell_title(name, title);
struct History history;
Rast_short_history(name, "raster", &history);
Rast_command_history(&history);
Rast_write_history(name, &history);
if (timestamp)
G_write_raster_timestamp(name, timestamp);
else
G_remove_raster_timestamp(name);
// we remove timestamp, because overwriting does not remove it
// it is a no-op when it does not exist
}
/** Overload of raster_to_grass() */
template<typename Number>
inline void raster_to_grass(
pops::Raster<Number> raster,
const std::string& name,
NullOutputPolicy null_policy = DefaultNullOutputPolicy)
{
raster_to_grass<Number>(raster, name.c_str(), null_policy);
}
/** Overload of raster_to_grass() */
template<typename Number>
inline void raster_to_grass(
pops::Raster<Number> raster,
const std::string& name,
const std::string& title,
NullOutputPolicy null_policy = DefaultNullOutputPolicy)
{
raster_to_grass<Number>(raster, name.c_str(), null_policy, title.c_str());
}
/** Overload of raster_to_grass()
*
* Converts PoPS date to GRASS GIS timestamp.
*/
template<typename Number>
inline void raster_to_grass(
pops::Raster<Number> raster,
const std::string& name,
const std::string& title,
const pops::Date& date,
NullOutputPolicy null_policy = DefaultNullOutputPolicy)
{
struct TimeStamp timestamp;
date_to_grass(date, ×tamp);
raster_to_grass<Number>(
raster, name.c_str(), null_policy, title.c_str(), ×tamp);
}
// these two determine the types of numbers used to represent the
// rasters (using terminology already used in the library)
typedef double Float;
typedef int Integer;
// The following wrappers are to avoid the need specify template
// parameters using the <> syntax and it is one place to change
// the types being read.
// The string parameter is a template parameter which in turn is used
// to find the right function template overload, so there is no extra
// cost when using const char* as it would be if we use
// const std::string& as parameter while supporting both.
/** Wrapper to read GRASS GIS raster into floating point Raster */
template<typename String>
inline pops::Raster<Float> raster_from_grass_float(
String name, NullInputPolicy null_policy = DefaultNullInputPolicy)
{
return raster_from_grass<Float>(name, null_policy);
}
/** Wrapper to read GRASS GIS raster into integer type Raster */
template<typename String>
inline pops::Raster<Integer> raster_from_grass_integer(
String name, NullInputPolicy null_policy = DefaultNullInputPolicy)
{
return raster_from_grass<Integer>(name, null_policy);
}
/** Get indices of suitable cell as a list (vector) of pairs (vectors of 2) */
std::vector<std::vector<int>> get_suitable_cells(pops::Raster<Integer> raster)
{
std::vector<std::vector<int>> cells;
for (int row = 0; row < raster.rows(); ++row) {
for (int col = 0; col < raster.cols(); ++col) {
if (raster(row, col) > 0) {
cells.push_back({row, col});
}
}
}
return cells;
}
// TODO: update names
// convenient definitions, names for backwards compatibility
typedef pops::Raster<Integer> Img;
typedef pops::Raster<Float> DImg;
#endif // GRASTER_HPP