FireSTARR
Loading...
Searching...
No Matches
ConstantGrid.h
1/* Copyright (c) Queen's Printer for Ontario, 2020. */
2/* Copyright (c) His Majesty the King in Right of Canada as represented by the Minister of Natural Resources, 2021-2025. */
3
4/* SPDX-License-Identifier: AGPL-3.0-or-later */
5
6#pragma once
7#include <algorithm>
8#include <string>
9#include <tiffio.h>
10#include <geotiffio.h>
11#include <utility>
12#include <vector>
13#include "Grid.h"
14#include "Util.h"
15#include "Settings.h"
16#include "FuelType.h"
17namespace fs::data
18{
24template <class T, class V = T>
26 : public GridData<T, V, const vector<T>>
27{
28public:
34 [[nodiscard]] constexpr T at(const Location& location) const noexcept override
35 {
36#ifdef DEBUG_GRIDS
37 logging::check_fatal(location.row() >= this->rows() || location.column() >= this->columns(), "Out of bounds (%d, %d)", location.row(), location.column());
38#endif
39#ifdef DEBUG_POINTS
40 {
41 const Location loc{location.row(), location.column()};
42 logging::check_equal(
43 loc.column(),
44 location.column(),
45 "column");
46 logging::check_equal(
47 loc.row(),
48 location.row(),
49 "row");
50 // if we're going to use the hash then we need to make sure it actually matches
51 logging::check_equal(
52 loc.hash(),
53 location.hash(),
54 "hash");
55 }
56#endif
57 // return at(location.hash());
58 return this->data.at(location.hash());
59 }
60 template <class P>
61 [[nodiscard]] constexpr T at(const Position<P>& position) const noexcept
62 {
63 return at(Location{position.hash()});
64 }
70 // [[nodiscard]] constexpr T at(const HashSize hash) const noexcept
71 // {
72 // return this->data.at(hash);
73 // }
77 // ! @cond Doxygen_Suppress
78 void set(const Location&, const T) override
79 // ! @endcond
80 {
81 throw runtime_error("Cannot change ConstantGrid");
82 }
83 ~ConstantGrid() = default;
84 ConstantGrid(const ConstantGrid& rhs) noexcept = delete;
85 ConstantGrid(ConstantGrid&& rhs) noexcept = delete;
86 ConstantGrid& operator=(const ConstantGrid& rhs) noexcept = delete;
87 ConstantGrid& operator=(ConstantGrid&& rhs) noexcept = delete;
102 ConstantGrid(const MathSize cell_size,
103 const Idx rows,
104 const Idx columns,
105 const V nodata_input,
106 const T nodata_value,
107 const MathSize xllcorner,
108 const MathSize yllcorner,
109 const MathSize xurcorner,
110 const MathSize yurcorner,
111 string&& proj4,
112 vector<T>&& data)
113 : GridData<T, V, const vector<T>>(cell_size,
114 rows,
115 columns,
116 nodata_input,
117 nodata_value,
118 xllcorner,
119 yllcorner,
120 xurcorner,
121 yurcorner,
122 std::forward<string>(proj4),
123 std::move(data))
124 {
125 }
138 ConstantGrid(const MathSize cell_size,
139 const Idx rows,
140 const Idx columns,
141 const V nodata_input,
142 const T nodata_value,
143 const MathSize xllcorner,
144 const MathSize yllcorner,
145 const string& proj4,
146 const T& initialization_value) noexcept
147 : ConstantGrid(cell_size,
148 rows,
149 columns,
150 nodata_input,
151 nodata_value,
152 xllcorner,
153 yllcorner,
154 proj4,
155 std::move(vector<T>(static_cast<size_t>(MAX_ROWS) * MAX_COLUMNS,
156 initialization_value)))
157 {
158 }
168 [[nodiscard]] static ConstantGrid<T, V>* readTiff(const string& filename,
169 TIFF* tif,
170 GTIF* gtif,
171 const topo::Point& point,
172 std::function<T(V, V)> convert)
173 {
174 logging::info("Reading file %s", filename.c_str());
175#ifdef DEBUG_GRIDS
176 // auto min_value = std::numeric_limits<int16_t>::max();
177 // auto max_value = std::numeric_limits<int16_t>::min();
178 auto min_value = std::numeric_limits<V>::max();
179 auto max_value = std::numeric_limits<V>::min();
180#endif
181 logging::debug("Reading a raster where T = %s, V = %s",
182 typeid(T).name(),
183 typeid(V).name());
184 logging::debug("Raster type V has limits %ld, %ld",
185 std::numeric_limits<V>::min(),
186 std::numeric_limits<V>::max());
187 const GridBase grid_info = read_header(tif, gtif);
188 uint32_t tile_width;
189 uint32_t tile_length;
190 TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width);
191 TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_length);
192 void* data;
193 uint32_t count;
194 TIFFGetField(tif, TIFFTAG_GDAL_NODATA, &count, &data);
195 logging::check_fatal(0 == count, "NODATA value is not set in input");
196 logging::debug("NODATA value is '%s'", static_cast<char*>(data));
197 const auto nodata_orig = stoi(string(static_cast<char*>(data)));
198 logging::debug("NODATA value is originally parsed as %d", nodata_orig);
199 const auto nodata_input = static_cast<V>(stoi(string(static_cast<char*>(data))));
200 logging::debug("NODATA value is parsed as %d", nodata_input);
201 auto actual_rows = grid_info.calculateRows();
202 auto actual_columns = grid_info.calculateColumns();
203 const auto coordinates = grid_info.findFullCoordinates(point, true);
204 logging::note("Coordinates before reading are (%d, %d => %f, %f)",
205 std::get<0>(*coordinates),
206 std::get<1>(*coordinates),
207 std::get<0>(*coordinates) + std::get<2>(*coordinates) / 1000.0,
208 std::get<1>(*coordinates) + std::get<3>(*coordinates) / 1000.0);
209 auto min_column = max(static_cast<FullIdx>(0),
210 static_cast<FullIdx>(std::get<1>(*coordinates) - static_cast<FullIdx>(MAX_COLUMNS) / static_cast<FullIdx>(2)));
211 if (min_column + MAX_COLUMNS >= actual_columns)
212 {
213 min_column = max(static_cast<FullIdx>(0), actual_columns - MAX_COLUMNS);
214 }
215 // make sure we're at the start of a tile
216 const auto tile_column = tile_width * static_cast<FullIdx>(min_column / tile_width);
217 const auto max_column = static_cast<FullIdx>(min(min_column + MAX_COLUMNS - 1, actual_columns));
218#ifdef DEBUG_GRIDS
219 logging::check_fatal(min_column < 0, "Column can't be less than 0");
220 logging::check_fatal(max_column - min_column > MAX_COLUMNS, "Can't have more than %d columns", MAX_COLUMNS);
221 logging::check_fatal(max_column > actual_columns, "Can't have more than actual %d columns", actual_columns);
222#endif
223 auto min_row = max(static_cast<FullIdx>(0),
224 static_cast<FullIdx>(std::get<0>(*coordinates) - static_cast<FullIdx>(MAX_ROWS) / static_cast<FullIdx>(2)));
225 if (min_row + MAX_COLUMNS >= actual_rows)
226 {
227 min_row = max(static_cast<FullIdx>(0), actual_rows - MAX_ROWS);
228 }
229 const auto tile_row = tile_width * static_cast<FullIdx>(min_row / tile_width);
230 const auto max_row = static_cast<FullIdx>(min(min_row + MAX_ROWS - 1, actual_rows));
231#ifdef DEBUG_GRIDS
232 logging::check_fatal(min_row < 0, "Row can't be less than 0 but is %d", min_row);
233 logging::check_fatal(max_row - min_row > MAX_ROWS, "Can't have more than %d rows but have %d", MAX_ROWS, max_row - min_row);
234 logging::check_fatal(max_row > actual_rows, "Can't have more than actual %d rows", actual_rows);
235#endif
236 T nodata_value = convert(nodata_input, nodata_input);
237 logging::check_fatal(
238 convert(nodata_input, nodata_input) != nodata_value,
239 "Expected nodata value to be returned from convert()");
240 vector<T> values(static_cast<size_t>(MAX_ROWS) * MAX_COLUMNS, nodata_value);
241 logging::verbose("%s: malloc start", filename.c_str());
242 int bps = std::numeric_limits<V>::digits + (1 * std::numeric_limits<V>::is_signed);
243 uint16_t bps_file;
244 TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps_file);
245 logging::check_fatal(bps != bps_file,
246 "Raster %s type is not expected type (%d bits instead of %d)",
247 filename.c_str(),
248 bps_file,
249 bps);
250#ifdef DEBUG_GRIDS
251 int bps_int16_t = std::numeric_limits<int16_t>::digits + (1 * std::numeric_limits<int16_t>::is_signed);
252 logging::debug("Size of pointer to int is %ld vs %ld", sizeof(int16_t*), sizeof(V*));
253 logging::debug("Raster %s calculated bps for type V is %ld; tif says bps is %ld; int16_t is %ld",
254 filename.c_str(),
255 bps,
256 bps_file,
257 bps_int16_t);
258#endif
259 const auto tile_size = TIFFTileSize(tif);
260 logging::debug("Tile size for reading %s is %ld", filename.c_str(), tile_size);
261 const auto buf = _TIFFmalloc(tile_size);
262 logging::verbose("%s: read start", filename.c_str());
263 const tsample_t smp{};
264 logging::debug("Want to clip grid to (%d, %d) => (%d, %d) for a %dx%d raster",
265 min_row,
266 min_column,
267 max_row,
268 max_column,
269 actual_rows,
270 actual_columns);
271 for (auto h = tile_row; h <= max_row; h += tile_length)
272 {
273 for (auto w = tile_column; w <= max_column; w += tile_width)
274 {
275 TIFFReadTile(tif, buf, static_cast<uint32_t>(w), static_cast<uint32_t>(h), 0, smp);
276 for (
277 FullIdx y = 0;
278 (y < static_cast<FullIdx>(tile_length)) && (y + h <= max_row);
279 ++y)
280 {
281 // read in so that (0, 0) has a hash of 0
282 const auto y_row = static_cast<HashSize>((h - min_row) + y);
283 const auto actual_row = (max_row - min_row) - y_row;
284 if (actual_row >= 0 && actual_row < MAX_ROWS)
285 {
286 for (
287 auto x = 0;
288 (x < static_cast<FullIdx>(tile_width)) && (x + w <= max_column);
289 ++x)
290 {
291 const auto offset = y * tile_width + x;
292 const auto actual_column = ((w - min_column) + x);
293 if (actual_column >= 0 && actual_column < MAX_ROWS)
294 {
295 const auto cur_hash = actual_row * MAX_COLUMNS + actual_column;
296 auto cur = *(static_cast<V*>(buf) + offset);
297#ifdef DEBUG_GRIDS
298 min_value = min(cur, min_value);
299 max_value = max(cur, max_value);
300#endif
301 // try
302 // {
303 values.at(cur_hash) = convert(cur, nodata_input);
304 // logging::check_fatal(Settings::fuelLookup().values.at(cur_hash));
305 // }
306 // // catch (const std::out_of_range& err)
307 // catch (const std::exception& err)
308 // {
309 // logging::error("Error trying to read tiff");
310 // logging::debug("cur = %d", cur);
311 // logging::debug("nodata_input = %d", nodata_input);
312 // logging::debug("T = %s, V = %s", typeid(T).name(), typeid(V).name());
313 // if constexpr (std::is_same_v<T, const fs::fuel::FuelType*>)
314 // {
315 // auto f = static_cast<const fs::fuel::FuelType*>(values.at(cur_hash));
316 // logging::debug("fuel %s has code %d",
317 // fs::fuel::FuelType::safeName(f),
318 // fs::fuel::FuelType::safeCode(f));
319 // }
320 // logging::warning(err.what());
321 // // logging::fatal(err.what());
322 // fs::sim::Settings::fuelLookup().listFuels();
323 // throw err;
324 // }
325 }
326 }
327 }
328 }
329 }
330 }
331 logging::verbose("%s: read end", filename.c_str());
332 _TIFFfree(buf);
333 logging::verbose("%s: free end", filename.c_str());
334 const auto new_xll = grid_info.xllcorner() + (static_cast<MathSize>(min_column) * grid_info.cellSize());
335 const auto new_yll = grid_info.yllcorner()
336 + (static_cast<MathSize>(actual_rows) - static_cast<MathSize>(max_row))
337 * grid_info.cellSize();
338#ifdef DEBUG_GRIDS
339 logging::check_fatal(new_yll < grid_info.yllcorner(),
340 "New yllcorner is outside original grid");
341#endif
342 logging::verbose("Translated lower left is (%f, %f) from (%f, %f)",
343 new_xll,
344 new_yll,
345 grid_info.xllcorner(),
346 grid_info.yllcorner());
347 const auto num_rows = max_row - min_row + 1;
348 const auto num_columns = max_column - min_column + 1;
349 auto result = new ConstantGrid<T, V>(grid_info.cellSize(),
350 num_rows,
351 num_columns,
352 nodata_input,
353 nodata_value,
354 new_xll,
355 new_yll,
356 new_xll + (static_cast<MathSize>(num_columns) + 1) * grid_info.cellSize(),
357 new_yll + (static_cast<MathSize>(num_rows) + 1) * grid_info.cellSize(),
358 string(grid_info.proj4()),
359 std::move(values));
360 auto new_location = result->findCoordinates(point, false);
361#ifdef DEBUG_GRIDS
362 logging::check_fatal(nullptr == new_location, "Invalid location after reading");
363#endif
364 logging::note("Coordinates are (%d, %d => %f, %f)",
365 std::get<0>(*new_location),
366 std::get<1>(*new_location),
367 std::get<0>(*new_location) + std::get<2>(*new_location) / 1000.0,
368 std::get<1>(*new_location) + std::get<3>(*new_location) / 1000.0);
369#ifdef DEBUG_GRIDS
370 logging::note("Values for %s range from %d to %d",
371 filename.c_str(),
372 min_value,
373 max_value);
374#endif
375 return result;
376 }
384 [[nodiscard]] static ConstantGrid<T, V>* readTiff(const string& filename,
385 const topo::Point& point,
386 std::function<T(V, V)> convert)
387 {
388 return with_tiff<ConstantGrid<T, V>*>(
389 filename,
390 [&filename, &convert, &point](TIFF* tif, GTIF* gtif) { return readTiff(filename, tif, gtif, point, convert); });
391 }
398 [[nodiscard]] static ConstantGrid<T, T>* readTiff(const string& filename,
399 const topo::Point& point)
400 {
401 return readTiff(filename, point, util::no_convert<T>);
402 }
403protected:
404 tuple<Idx, Idx, Idx, Idx> dataBounds() const override
405 {
406 Idx min_row = 0;
407 Idx max_row = this->rows();
408 Idx min_column = 0;
409 Idx max_column = this->columns();
410 // const Location loc_min{min_row, min_column};
411 // const Location loc_max{max_row, max_column};
412 // // #ifdef DEBUG_POINTS
413 // logging::check_equal(
414 // loc_min.column(),
415 // min_column,
416 // "min_column");
417 // logging::check_equal(
418 // loc_min.row(),
419 // min_row,
420 // "min_row");
421 // logging::check_equal(
422 // loc_max.column(),
423 // max_column,
424 // "max_column");
425 // logging::check_equal(
426 // loc_max.row(),
427 // max_row,
428 // "max_row");
429 // // #endif
430 return tuple<Idx, Idx, Idx, Idx>{
431 min_column,
432 min_row,
433 max_column,
434 max_row};
435 }
436private:
444 ConstantGrid(const GridBase& grid_info,
445 const V nodata_input,
446 const T nodata_value,
447 vector<T>&& values)
448 : ConstantGrid(grid_info.cellSize(),
449 nodata_input,
450 nodata_value,
451 grid_info.xllcorner(),
452 grid_info.yllcorner(),
453 grid_info.xurcorner(),
454 grid_info.yurcorner(),
455 string(grid_info.proj4()),
456 std::move(values))
457 {
458#ifdef DEBUG_GRIDS
459 logging::check_fatal(
460 this->data.size() != static_cast<size_t>(MAX_ROWS) * MAX_COLUMNS,
461 "Invalid grid size");
462#endif
463 }
464};
465}
A GridData<T, V, const vector<T>> that cannot change once initialized.
Definition ConstantGrid.h:27
static ConstantGrid< T, T > * readTiff(const string &filename, const topo::Point &point)
Read a section of a TIFF into a ConstantGrid.
Definition ConstantGrid.h:398
~ConstantGrid()=default
Value for grid at given Location.
static ConstantGrid< T, V > * readTiff(const string &filename, TIFF *tif, GTIF *gtif, const topo::Point &point, std::function< T(V, V)> convert)
Read a section of a TIFF into a ConstantGrid.
Definition ConstantGrid.h:168
ConstantGrid(const MathSize cell_size, const Idx rows, const Idx columns, const V nodata_input, const T nodata_value, const MathSize xllcorner, const MathSize yllcorner, const MathSize xurcorner, const MathSize yurcorner, string &&proj4, vector< T > &&data)
Constructor.
Definition ConstantGrid.h:102
static ConstantGrid< T, V > * readTiff(const string &filename, const topo::Point &point, std::function< T(V, V)> convert)
Read a section of a TIFF into a ConstantGrid.
Definition ConstantGrid.h:384
constexpr T at(const Location &location) const noexcept override
Value for grid at given Location.
Definition ConstantGrid.h:34
ConstantGrid(const MathSize cell_size, const Idx rows, const Idx columns, const V nodata_input, const T nodata_value, const MathSize xllcorner, const MathSize yllcorner, const string &proj4, const T &initialization_value) noexcept
Constructor.
Definition ConstantGrid.h:138
ConstantGrid(const GridBase &grid_info, const V nodata_input, const T nodata_value, vector< T > &&values)
Constructor.
Definition ConstantGrid.h:444
The base class with information for a grid of data with geographic coordinates.
Definition Grid.h:43
constexpr MathSize xurcorner() const noexcept
Upper right corner X coordinate in meters.
Definition Grid.h:116
unique_ptr< FullCoordinates > findFullCoordinates(const topo::Point &point, bool flipped) const
Find FullCoordinates for Point.
Definition Grid.cpp:127
constexpr const string & proj4() const noexcept
Proj4 string defining coordinate system for this grid. Must be a UTM projection.
Definition Grid.h:132
constexpr FullIdx calculateRows() const noexcept
Number of rows in the GridBase.
Definition Grid.h:80
constexpr MathSize cellSize() const noexcept
Cell size used for GridBase.
Definition Grid.h:72
constexpr MathSize yllcorner() const noexcept
Lower left corner Y coordinate in meters.
Definition Grid.h:108
constexpr MathSize xllcorner() const noexcept
Lower left corner X coordinate in meters.
Definition Grid.h:100
constexpr MathSize yurcorner() const noexcept
Upper right corner Y coordinate in meters.
Definition Grid.h:124
constexpr FullIdx calculateColumns() const noexcept
Number of columns in the GridBase.
Definition Grid.h:90
A Grid that defines the data structure used for storing values.
Definition Grid.h:408
const vector< T > data
Definition Grid.h:506
constexpr Idx rows() const noexcept
Definition Grid.h:257
constexpr Idx columns() const noexcept
Definition Grid.h:265
virtual void set(const Location &location, T value)=0
Definition Location.h:229
A geographic location in lat/long coordinates.
Definition Point.h:13
A Position with a row and column.
Definition Location.h:57