data_raster.hpp
Go to the documentation of this file.
1
31#ifndef CCGL_DATA_RASTER_H
32#define CCGL_DATA_RASTER_H
33
34// include base headers
35#include <string>
36#include <map>
37#include <set>
38#include <fstream>
39#include <iomanip>
40#include <typeinfo>
41#include <cassert>
42// include openmp if supported
43#ifdef SUPPORT_OMP
44#include <omp.h>
45#endif /* SUPPORT_OMP */
46
47// include GDAL, optional
48#ifdef USE_GDAL
49#include "gdal.h"
50#include "gdal_priv.h"
51#include "cpl_string.h"
52#include "ogr_spatialref.h"
53#endif /* USE_GDAL */
54
55#include "basic.h"
56#include "utils_filesystem.h"
57#include "utils_string.h"
58#include "utils_array.h"
59#include "utils_math.h"
60// include MongoDB, optional
61#ifdef USE_MONGODB
62#include "db_mongoc.h"
63#endif /* USE_MONGODB */
64
65using std::map;
66using std::set;
67#ifndef HAS_VARIADIC_TEMPLATES // Not support emplace(), e.g., MSVC2010
68using std::make_pair;
69#endif
70using std::setprecision;
71
72#ifndef CONST_CHARS
73#define CONST_CHARS static const char*
74#endif
75
76namespace ccgl {
77using namespace utils_string;
78using namespace utils_filesystem;
79using namespace utils_array;
80using namespace utils_math;
81#ifdef USE_MONGODB
82using namespace db_mongoc;
83#endif /* USE_MONGODB */
84
89namespace data_raster {
90CONST_CHARS HEADER_RS_NODATA = "NODATA_VALUE";
104CONST_CHARS HEADER_INC_NODATA = "INCLUDE_NODATA";
106CONST_CHARS STATS_RS_VALIDNUM = "VALID_CELLNUMBER";
114
115typedef std::pair<int, int> ROW_COL;
116typedef std::pair<double, double> XY_COOR;
117
121typedef enum {
134
140string RasterDataTypeToString(int type);
141
145RasterDataType StringToRasterDataType(const string& stype);
146
150RasterDataType TypeToRasterDataType(const std::type_info& t);
151
156
157#ifdef USE_GDAL
158GDALDataType CvtToGDALDataType(RasterDataType type);
159#endif
160
165
171void CopyHeader(const STRDBL_MAP& refers, STRDBL_MAP& dst);
172
176template <typename T>
177void UpdateHeader(STRDBL_MAP& header, const string& key, T val) {
178 if (header.find(key) == header.end()) {
179#ifdef HAS_VARIADIC_TEMPLATES
180 header.emplace(key, CVT_DBL(val));
181#else
182 header.insert(make_pair(key, CVT_DBL(val)));
183#endif
184 }
185 else { header.at(key) = CVT_DBL(val); }
186}
187
192
196void UpdateStrHeader(STRING_MAP& strheader, const string& key, const string& val);
201
205void InitialStatsMap(STRDBL_MAP& stats, map<string, double*>& stats2d);
206
214template <typename T>
215bool ReadAscFile(const string& filename, STRDBL_MAP& header, T*& values) {
216 StatusMessage(("Read " + filename + "...").c_str());
217 vector<string> content_strs;
218 if (!LoadPlainTextFile(filename, content_strs)) { return false; }
219 if (content_strs.size() < 7) {
220 StatusMessage("Error: ASCII raster data requires at least 7 lines!");
221 return false;
222 }
223 double cellsize = -1.;
224 double xll = MISSINGFLOAT;
225 double yll = MISSINGFLOAT;
226 double nodata = MISSINGFLOAT;
227 bool xllcorner = false;
228 bool yllcorner = false;
229 int rows = -1;
230 int cols = -1;
231 int vidx = 0;
232 for (auto iter = content_strs.begin(); iter != content_strs.end(); ++iter) {
233 vector<string> tokens = SplitString(*iter);
234 if (tokens.empty()) { continue; }
235 bool str2value = false;
236 if (StringMatch(tokens[0], HEADER_RS_NCOLS)) {
237 if (tokens.size() < 2) { return false; }
238 cols = CVT_INT(IsInt(tokens[1], str2value));
239 if (!str2value) { return false; }
240 }
241 else if (StringMatch(tokens[0], HEADER_RS_NROWS)) {
242 if (tokens.size() < 2) { return false; }
243 rows = CVT_INT(IsInt(tokens[1], str2value));
244 if (!str2value) { return false; }
245 }
246 else if (StringMatch(tokens[0], HEADER_RS_XLL) ||
247 StringMatch(tokens[0], HEADER_RS_XLLCOR)) {
248 if (tokens.size() < 2) { return false; }
249 xll = IsDouble(tokens[1], str2value);
250 if (StringMatch(tokens[0], HEADER_RS_XLLCOR)) { xllcorner = true; }
251 if (!str2value) { return false; }
252 }
253 else if (StringMatch(tokens[0], HEADER_RS_YLL) ||
254 StringMatch(tokens[0], HEADER_RS_YLLCOR)) {
255 if (tokens.size() < 2) { return false; }
256 yll = IsDouble(tokens[1], str2value);
257 if (StringMatch(tokens[0], HEADER_RS_YLLCOR)) { yllcorner = true; }
258 if (!str2value) { return false; }
259 }
260 else if (StringMatch(tokens[0], HEADER_RS_CELLSIZE)) {
261 if (tokens.size() < 2) { return false; }
262 cellsize = IsDouble(tokens[1], str2value);
263 if (!str2value) { return false; }
264 }
265 else if (StringMatch(tokens[0], HEADER_RS_NODATA)) {
266 if (tokens.size() < 2) { return false; }
267 nodata = IsDouble(tokens[1], str2value);
268 if (!str2value) { return false; }
269 }
270 else {
271 if (rows < 0 || cols < 0) {
272 StatusMessage("Warning: NCOLS and NROWS should be defined first!");
273 }
274 if (nullptr == values) { Initialize1DArray(rows * cols, values, nodata); }
275 for (auto it_value = tokens.begin(); it_value != tokens.end(); ++it_value) {
276 double tmpv = IsDouble(*it_value, str2value);
277 if (!str2value) {
278 StatusMessage("Error: No value occurred in Raster data matrix!");
279 if (nullptr != values) { Release1DArray(values); }
280 return false;
281 }
282 if (vidx == rows * cols) {
283 StatusMessage("Error: Count of values MUST equal to rows * cols!");
284 if (nullptr != values) { Release1DArray(values); }
285 return false;
286 }
287 values[vidx++] = static_cast<T>(tmpv);
288 }
289 }
290 }
291 if (rows < 0 || cols < 0 || cellsize < 0 ||
293 StatusMessage("Error: Header information incomplete!");
294 return false;
295 }
296 // default is center, if corner, then:
297 if (xllcorner) { xll += 0.5 * cellsize; }
298 if (yllcorner) { yll += 0.5 * cellsize; }
299 UpdateHeader(header, HEADER_RS_NCOLS, cols);
300 UpdateHeader(header, HEADER_RS_NROWS, rows);
301 UpdateHeader(header, HEADER_RS_XLL, xll);
302 UpdateHeader(header, HEADER_RS_YLL, yll);
303 UpdateHeader(header, HEADER_RS_CELLSIZE, cellsize);
304 UpdateHeader(header, HEADER_RS_NODATA, nodata);
305 UpdateHeader(header, HEADER_RS_LAYERS, 1);
306 UpdateHeader(header, HEADER_RS_CELLSNUM, cols * rows);
307
308 return true;
309}
310
316bool WriteAscHeaders(const string& filename, const STRDBL_MAP& header);
317
324template <typename T>
325bool WriteSingleAsc(const string& filename, const STRDBL_MAP& header, T* values) {
326 string abs_filename = GetAbsolutePath(filename);
327 string dirname = GetPathFromFullName(abs_filename);
328 if (!PathExists(dirname)) { MakeDirectory(dirname); }
329 if (!WriteAscHeaders(abs_filename, header)) { return false; }
330 std::ofstream raster_file(abs_filename.c_str(), std::ios::app | std::ios::out);
331 if (!raster_file.is_open()) {
332 StatusMessage("Error opening file: " + abs_filename);
333 return false;
334 }
335 int rows = CVT_INT(header.at(HEADER_RS_NROWS));
336 int cols = CVT_INT(header.at(HEADER_RS_NCOLS));
337 for (int i = 0; i < rows; i++) {
338 for (int j = 0; j < cols; j++) {
339 raster_file << setprecision(6) << values[i * cols + j] << " ";
340 }
341 raster_file << endl;
342 }
343 raster_file << endl;
344 raster_file.close();
345 return true;
346}
347
348#ifdef USE_GDAL
358template <typename T>
359bool ReadRasterFileByGdal(const string& filename, STRDBL_MAP& header, T*& values,
360 RasterDataType& in_type, string& srs) {
361 StatusMessage(("Read " + filename + "...").c_str());
362 GDALDataset* po_dataset = static_cast<GDALDataset*>(GDALOpen(filename.c_str(),
363 GA_ReadOnly));
364 if (nullptr == po_dataset) {
365 StatusMessage("Open file " + filename + " failed.");
366 return false;
367 }
368 GDALRasterBand* po_band = po_dataset->GetRasterBand(1);
369 int n_rows = po_band->GetYSize();
370 int n_cols = po_band->GetXSize();
371 int get_value_flag = false;
372 double nodata = po_band->GetNoDataValue(&get_value_flag);
373 int approx_minmax = false;
374 double minmax[2];
375 T* tmprasterdata = nullptr;
376 bool read_as_signedbyte = false;
377 unsigned char* uchar_data = nullptr;
378 signed char* char_data = nullptr; // DO NOT use char*
379 vuint16_t* uint16_data = nullptr; // 16-bit unsigned integer
380 vint16_t* int16_data = nullptr; // 16-bit signed integer
381 vuint32_t* uint32_data = nullptr; // 32-bit unsigned integer
382 vint32_t* int32_data = nullptr; // 32-bit signed integer
383 vuint64_t* uint64_data = nullptr; // 64-bit unsigned integer
384 vint64_t* int64_data = nullptr; // 64-bit signed integer
385 float* float_data = nullptr;
386 double* double_data = nullptr;
387 CPLErr result;
388 switch (po_band->GetRasterDataType()) {
389 case GDT_Byte:
390 // In GDAL, GDT_Byte is an 8-bit unsigned integer (unsigned char), ranges from 0 to 255.
391 // While in ArcGIS, both 8-bit signed char (ranges from -128 to 127) and unsigned char
392 // are supported. Both types will be recognized as GDT_Byte by GDAL.
393 //
394 // So,
395 // 1) maximum <= 127 and minimum < 0 ==> signed char
396 // 2) maximum <= 127 and minimum >= 0 and no_data_value_ < 0 ==> signed char
397 // Otherwise, unsigned char.
398 //
399 // Update (08/09/2023): GDAL>=3.7 added the support of GDT_Int8. Keep this code for compatibility!
400 //
401 po_band->ComputeRasterMinMax(approx_minmax, minmax);
402 if ((minmax[1] <= 127 && minmax[0] < 0)
403 || (minmax[1] <= 127 && minmax[0] >= 0 && (!get_value_flag || (get_value_flag && nodata < 0)))) {
404 read_as_signedbyte = true;
405 }
406 uchar_data = static_cast<unsigned char*>(CPLMalloc(sizeof(unsigned char) * n_cols * n_rows));
407 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, uchar_data,
408 n_cols, n_rows, GDT_Byte, 0, 0);
409 if (result != CE_None) {
410 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
411 GDALClose(po_dataset);
412 return false;
413 }
414 if (read_as_signedbyte) {
415 StatusMessage("Read GDT_Byte raster as signed char!");
416 Initialize1DArray(n_rows * n_cols, char_data, uchar_data);
417 Initialize1DArray(n_rows * n_cols, tmprasterdata, char_data);
418 Release1DArray(char_data);
419 in_type = RDT_Int8;
420 } else {
421 StatusMessage("Read GDT_Byte raster as unsigned char!");
422 Initialize1DArray(n_rows * n_cols, tmprasterdata, uchar_data);
423 in_type = RDT_UInt8;
424 }
425 CPLFree(uchar_data);
426 break;
427#if GDAL_VERSION_MAJOR >= 3 && GDAL_VERSION_MINOR >= 7
428 case GDT_Int8:
429 char_data = static_cast<signed char*>(CPLMalloc(sizeof(signed char) * n_cols * n_rows));
430 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, char_data,
431 n_cols, n_rows, GDT_Int8, 0, 0);
432 if (result != CE_None) {
433 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
434 GDALClose(po_dataset);
435 return false;
436 }
437 Initialize1DArray(n_rows * n_cols, tmprasterdata, char_data);
438 CPLFree(char_data);
439 in_type = RDT_Int8;
440 break;
441#endif
442 case GDT_UInt16:
443 uint16_data = static_cast<vuint16_t*>(CPLMalloc(sizeof(vuint16_t) * n_cols * n_rows));
444 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, uint16_data,
445 n_cols, n_rows, GDT_UInt16, 0, 0);
446 if (result != CE_None) {
447 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
448 GDALClose(po_dataset);
449 return false;
450 }
451 Initialize1DArray(n_rows * n_cols, tmprasterdata, uint16_data);
452 CPLFree(uint16_data);
453 in_type = RDT_UInt16;
454 break;
455 case GDT_Int16:
456 int16_data = static_cast<vint16_t*>(CPLMalloc(sizeof(vint16_t) * n_cols * n_rows));
457 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, int16_data,
458 n_cols, n_rows, GDT_Int16, 0, 0);
459 if (result != CE_None) {
460 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
461 GDALClose(po_dataset);
462 return false;
463 }
464 Initialize1DArray(n_rows * n_cols, tmprasterdata, int16_data);
465 CPLFree(int16_data);
466 in_type = RDT_Int16;
467 break;
468 case GDT_UInt32:
469 uint32_data = static_cast<vuint32_t*>(CPLMalloc(sizeof(vuint32_t) * n_cols * n_rows));
470 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, uint32_data,
471 n_cols, n_rows, GDT_UInt32, 0, 0);
472 if (result != CE_None) {
473 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
474 GDALClose(po_dataset);
475 return false;
476 }
477 Initialize1DArray(n_rows * n_cols, tmprasterdata, uint32_data);
478 CPLFree(uint32_data);
479 in_type = RDT_UInt32;
480 break;
481 case GDT_Int32:
482 int32_data = static_cast<vint32_t*>(CPLMalloc(sizeof(vint32_t) * n_cols * n_rows));
483 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, int32_data,
484 n_cols, n_rows, GDT_Int32, 0, 0);
485 if (result != CE_None) {
486 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
487 GDALClose(po_dataset);
488 return false;
489 }
490 Initialize1DArray(n_rows * n_cols, tmprasterdata, int32_data);
491 CPLFree(int32_data);
492 in_type = RDT_Int32;
493 break;
494#if GDAL_VERSION_MAJOR >= 3 && GDAL_VERSION_MINOR >= 5
495 case GDT_UInt64:
496 uint64_data = static_cast<vuint64_t*>(CPLMalloc(sizeof(vuint64_t) * n_cols * n_rows));
497 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, uint64_data,
498 n_cols, n_rows, GDT_UInt64, 0, 0);
499 if (result != CE_None) {
500 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
501 GDALClose(po_dataset);
502 return false;
503 }
504 Initialize1DArray(n_rows * n_cols, tmprasterdata, uint64_data);
505 CPLFree(uint64_data);
506 in_type = RDT_UInt64;
507 break;
508 case GDT_Int64:
509 int64_data = static_cast<vint64_t*>(CPLMalloc(sizeof(vint64_t) * n_cols * n_rows));
510 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, int64_data,
511 n_cols, n_rows, GDT_Int64, 0, 0);
512 if (result != CE_None) {
513 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
514 GDALClose(po_dataset);
515 return false;
516 }
517 Initialize1DArray(n_rows * n_cols, tmprasterdata, int64_data);
518 CPLFree(int64_data);
519 in_type = RDT_Int64;
520 break;
521#endif
522 case GDT_Float32:
523 float_data = static_cast<float*>(CPLMalloc(sizeof(float) * n_cols * n_rows));
524 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, float_data,
525 n_cols, n_rows, GDT_Float32, 0, 0);
526 if (result != CE_None) {
527 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
528 GDALClose(po_dataset);
529 return false;
530 }
531 Initialize1DArray(n_rows * n_cols, tmprasterdata, float_data);
532 CPLFree(float_data);
533 in_type = RDT_Float;
534 break;
535 case GDT_Float64:
536 double_data = static_cast<double*>(CPLMalloc(sizeof(double) * n_cols * n_rows));
537 result = po_band->RasterIO(GF_Read, 0, 0, n_cols, n_rows, double_data,
538 n_cols, n_rows, GDT_Float64, 0, 0);
539 if (result != CE_None) {
540 StatusMessage("RaterIO trouble: " + string(CPLGetLastErrorMsg()));
541 GDALClose(po_dataset);
542 return false;
543 }
544 Initialize1DArray(n_rows * n_cols, tmprasterdata, double_data);
545 CPLFree(double_data);
546 in_type = RDT_Double;
547 break;
548 default:
549 StatusMessage("Unexpected GDALDataType: " + string(RasterDataTypeToString(in_type)));
550 GDALClose(po_dataset);
551 return false;
552 }
553
554 if (!get_value_flag) { // NoData value is not defined!
555 nodata = DefaultNoDataByType(in_type);
556 }
557
558 double geo_trans[6];
559 po_dataset->GetGeoTransform(geo_trans);
560 UpdateHeader(header, HEADER_RS_NCOLS, n_cols);
561 UpdateHeader(header, HEADER_RS_NROWS, n_rows);
562 UpdateHeader(header, HEADER_RS_NODATA, nodata);
563 UpdateHeader(header, HEADER_RS_CELLSIZE, geo_trans[1]);
564 UpdateHeader(header, HEADER_RS_XLL, geo_trans[0] + 0.5 * geo_trans[1]);
565 UpdateHeader(header, HEADER_RS_YLL, geo_trans[3] + (n_rows - 0.5) * geo_trans[5]);
566 UpdateHeader(header, HEADER_RS_LAYERS, 1.);
567 UpdateHeader(header, HEADER_RS_CELLSNUM, n_cols * n_rows);
568 srs = string(po_dataset->GetProjectionRef());
569
570 GDALClose(po_dataset);
571
572 values = tmprasterdata;
573 return true;
574}
575
584template <typename T>
585bool WriteSingleGeotiff(const string& filename, const STRDBL_MAP& header,
586 const STRING_MAP& opts, T* values) {
587 int n_rows = CVT_INT(header.at(HEADER_RS_NROWS));
588 int n_cols = CVT_INT(header.at(HEADER_RS_NCOLS));
589 char** papsz_options = nullptr;
590 void* new_values = nullptr;
591 bool recreate_flag = true; // recreate data array because inconsistent of datatypes
592 double old_nodata = header.at(HEADER_RS_NODATA);
593 bool change_nodata = false;
594 double new_nodata = old_nodata; // change nodata when convert signed datatype to unsigned
595 bool convert_permit = true; // DO NOT allow negative cell values be converted to unsigned datatype
596 RasterDataType tmptype = TypeToRasterDataType(typeid(T));
598 if (outtype == RDT_Unknown) {
599 outtype = tmptype;
600 recreate_flag = false;
601 }
602 else if (outtype == tmptype && outtype != RDT_Int8) { // RDT_Int8 need special handling
603 recreate_flag = false;
604 }
605 else {
606 if (outtype == RDT_UInt8) { // [0, 255] --> GDT_Byte in GDAL, use unsigned char
607 new_values = static_cast<unsigned char*>(CPLMalloc(sizeof(unsigned char) * n_cols * n_rows));
608 unsigned char* values_uchar = static_cast<unsigned char*>(new_values);
609 if (old_nodata < 0 || old_nodata > UINT8_MAX) {
610 new_nodata = UINT8_MAX;
611 change_nodata = true;
612 }
613 int illegal_count = 0;
614#pragma omp parallel for reduction(+:illegal_count)
615 for (int i = 0; i < n_cols * n_rows; i++) {
616 if (FloatEqual(values[i], old_nodata) && change_nodata) {
617 values_uchar[i] = UINT8_MAX;
618 continue;
619 }
620 if (values[i] < 0 || values[i] > UINT8_MAX) illegal_count += 1;
621 values_uchar[i] = static_cast<unsigned char>(values[i]);
622 }
623 if (illegal_count > 0) convert_permit = false;
624 }
625 else if (outtype == RDT_Int8) { // [-128, 127]
626 // https://gdal.org/drivers/raster/gtiff.html
627#if GDAL_VERSION_MAJOR < 3 || (GDAL_VERSION_MAJOR == 3 && GDAL_VERSION_MINOR < 7)
628 papsz_options = CSLSetNameValue(papsz_options, "PIXELTYPE", "SIGNEDBYTE");
629#endif
630 new_values = static_cast<signed char*>(CPLMalloc(sizeof(signed char) * n_cols * n_rows));
631 signed char* values_char = static_cast<signed char*>(new_values);
632 if (old_nodata < INT8_MIN || old_nodata > INT8_MAX) {
633 new_nodata = INT8_MIN;
634 change_nodata = true;
635 }
636 int illegal_count = 0;
637#pragma omp parallel for reduction(+:illegal_count)
638 for (int i = 0; i < n_cols * n_rows; i++) {
639 if (FloatEqual(values[i], old_nodata) && change_nodata) {
640 values_char[i] = INT8_MIN;
641 continue;
642 }
643 if (values[i] < INT8_MIN || values[i] > INT8_MAX) { illegal_count += 1; }
644 values_char[i] = static_cast<signed char>(values[i]);
645 }
646 if (illegal_count > 0) convert_permit = false;
647 }
648 else if (outtype == RDT_UInt16) { // [0, 65535]
649 new_values = static_cast<vuint16_t*>(CPLMalloc(sizeof(vuint16_t) * n_cols * n_rows));
650 vuint16_t* values_uint16 = static_cast<vuint16_t*>(new_values);
651 if (old_nodata < 0 || old_nodata > UINT16_MAX) {
652 new_nodata = UINT16_MAX;
653 change_nodata = true;
654 }
655 int illegal_count = 0;
656#pragma omp parallel for reduction(+:illegal_count)
657 for (int i = 0; i < n_cols * n_rows; i++) {
658 if (FloatEqual(values[i], old_nodata) && change_nodata) {
659 values_uint16[i] = UINT16_MAX;
660 continue;
661 }
662 if (values[i] < 0 || values[i] > UINT16_MAX) illegal_count += 1;
663 values_uint16[i] = static_cast<vuint16_t>(values[i]);
664 }
665 if (illegal_count > 0) convert_permit = false;
666 }
667 else if (outtype == RDT_Int16) { // [-32768, 32767]
668 new_values = static_cast<vint16_t*>(CPLMalloc(sizeof(vint16_t) * n_cols * n_rows));
669 vint16_t* values_int16 = static_cast<vint16_t*>(new_values);
670 if (old_nodata < INT16_MIN || old_nodata > INT16_MAX) {
671 new_nodata = INT16_MIN;
672 change_nodata = true;
673 }
674 int illegal_count = 0;
675#pragma omp parallel for reduction(+:illegal_count)
676 for (int i = 0; i < n_cols * n_rows; i++) {
677 if (FloatEqual(values[i], old_nodata) && change_nodata) {
678 values_int16[i] = INT16_MIN;
679 continue;
680 }
681 if (values[i] < INT16_MIN || values[i] > INT16_MAX) illegal_count += 1;
682 values_int16[i] = static_cast<vint16_t>(values[i]);
683 }
684 if (illegal_count > 0) convert_permit = false;
685 }
686 else if (outtype == RDT_UInt32) { // [0, 4294967295]
687 new_values = static_cast<vuint32_t*>(CPLMalloc(sizeof(vuint32_t) * n_cols * n_rows));
688 vuint32_t* values_uint32 = static_cast<vuint32_t*>(new_values);
689 if (old_nodata < 0 || old_nodata > UINT32_MAX) {
690 new_nodata = UINT32_MAX;
691 change_nodata = true;
692 }
693 int illegal_count = 0;
694#pragma omp parallel for reduction(+:illegal_count)
695 for (int i = 0; i < n_cols * n_rows; i++) {
696 if (FloatEqual(values[i], old_nodata) && change_nodata) {
697 values_uint32[i] = UINT32_MAX;
698 continue;
699 }
700 if (values[i] < 0 || values[i] > UINT32_MAX) illegal_count += 1;
701 values_uint32[i] = static_cast<vuint32_t>(values[i]);
702 }
703 if (illegal_count > 0) convert_permit = false;
704 }
705 else if (outtype == RDT_Int32) { // [-2147483648, 2147483647]
706 new_values = static_cast<vint32_t*>(CPLMalloc(sizeof(vint32_t) * n_cols * n_rows));
707 vint32_t* values_int32 = static_cast<vint32_t*>(new_values);
708 if (old_nodata < INT32_MIN || old_nodata > INT32_MAX) {
709 new_nodata = INT32_MIN;
710 change_nodata = true;
711 }
712 int illegal_count = 0;
713#pragma omp parallel for reduction(+:illegal_count)
714 for (int i = 0; i < n_cols * n_rows; i++) {
715 if (FloatEqual(values[i], old_nodata) && change_nodata) {
716 values_int32[i] = INT32_MIN;
717 continue;
718 }
719 if (values[i] < INT32_MIN || values[i] > INT32_MAX) illegal_count += 1;
720 values_int32[i] = static_cast<vint32_t>(values[i]);
721 }
722 if (illegal_count > 0) convert_permit = false;
723 }
724#if GDAL_VERSION_MAJOR >= 3 && GDAL_VERSION_MINOR >=5
725 else if (outtype == RDT_UInt64) { // [0, 18446744073709551615]
726 new_values = static_cast<vuint64_t*>(CPLMalloc(sizeof(vuint64_t) * n_cols * n_rows));
727 vuint64_t* values_uint64 = static_cast<vuint64_t*>(new_values);
728 if (old_nodata < 0 || old_nodata > UINT64_MAX) {
729 new_nodata = UINT64_MAX;
730 change_nodata = true;
731 }
732 int illegal_count = 0;
733#pragma omp parallel for reduction(+:illegal_count)
734 for (int i = 0; i < n_cols * n_rows; i++) {
735 if (FloatEqual(values[i], old_nodata) && change_nodata) {
736 values_uint64[i] = UINT64_MAX;
737 continue;
738 }
739 if (values[i] < 0 || values[i] > UINT64_MAX) illegal_count += 1;
740 values_uint64[i] = static_cast<vuint64_t>(values[i]);
741 }
742 if (illegal_count > 0) convert_permit = false;
743 }
744 else if (outtype == RDT_Int64) { // [-18446744073709551615, 18446744073709551615]
745 new_values = static_cast<vint64_t*>(CPLMalloc(sizeof(vint64_t) * n_cols * n_rows));
746 vint64_t* values_int64 = static_cast<vint64_t*>(new_values);
747 if (old_nodata < INT64_MIN || old_nodata > INT64_MAX) {
748 new_nodata = INT64_MIN;
749 change_nodata = true;
750 }
751 int illegal_count = 0;
752#pragma omp parallel for reduction(+:illegal_count)
753 for (int i = 0; i < n_cols * n_rows; i++) {
754 if (FloatEqual(values[i], old_nodata) && change_nodata) {
755 values_int64[i] = INT64_MIN;
756 continue;
757 }
758 if (values[i] < INT64_MIN || values[i] > INT64_MAX) illegal_count += 1;
759 values_int64[i] = static_cast<vint64_t>(values[i]);
760 }
761 if (illegal_count > 0) convert_permit = false;
762 }
763#endif
764 else if (outtype == RDT_Float) {
765 new_values = static_cast<float*>(CPLMalloc(sizeof(float) * n_cols * n_rows));
766 float* values_float = static_cast<float*>(new_values);
767#pragma omp parallel for
768 for (int i = 0; i < n_cols * n_rows; i++) values_float[i] = static_cast<float>(values[i]);
769 }
770 else if (outtype == RDT_Double) {
771 new_values = static_cast<double*>(CPLMalloc(sizeof(double) * n_cols * n_rows));
772 double* values_double = static_cast<double*>(new_values);
773#pragma omp parallel for
774 for (int i = 0; i < n_cols * n_rows; i++) values_double[i] = static_cast<double>(values[i]);
775 }
776 }
777 if ((outtype == RDT_Unknown || (recreate_flag && nullptr == new_values))
778 || (!convert_permit)) {
779 cout << "Error: The specific raster output data type is not allowed!\n";
780 if (papsz_options != nullptr) { CSLDestroy(papsz_options); }
781 if (new_values != nullptr) { CPLFree(new_values); }
782 return false;
783 }
784 GDALDriver* po_driver = GetGDALDriverManager()->GetDriverByName("GTiff");
785 if (nullptr == po_driver) { return false; }
786 string dirname = GetPathFromFullName(filename);
787 if (!PathExists(dirname)) { MakeDirectory(dirname); }
788 GDALDataset* po_dst_ds = po_driver->Create(filename.c_str(), n_cols, n_rows, 1,
789 CvtToGDALDataType(outtype), papsz_options);
790 if (nullptr == po_dst_ds) { return false; }
791 GDALRasterBand* po_dst_band = po_dst_ds->GetRasterBand(1);
792 CPLErr result = CE_None;
793 if (!recreate_flag) {
794 result = po_dst_band->RasterIO(GF_Write, 0, 0, n_cols, n_rows, values,
795 n_cols, n_rows, CvtToGDALDataType(outtype), 0, 0);
796 }
797 else {
798 result = po_dst_band->RasterIO(GF_Write, 0, 0, n_cols, n_rows, new_values,
799 n_cols, n_rows, CvtToGDALDataType(outtype), 0, 0);
800 }
801 if (result != CE_None || nullptr == po_dst_band) {
802 StatusMessage("RaterIO Error: " + string(CPLGetLastErrorMsg()));
803 if (papsz_options != nullptr) { CSLDestroy(papsz_options); }
804 if (new_values != nullptr) { CPLFree(new_values); }
805 GDALClose(po_dst_ds);
806 return false;
807 }
808 po_dst_band->SetNoDataValue(new_nodata);
809
810 double geo_trans[6]; // Write header information
811 geo_trans[0] = header.at(HEADER_RS_XLL) - 0.5 * header.at(HEADER_RS_CELLSIZE);
812 geo_trans[1] = header.at(HEADER_RS_CELLSIZE);
813 geo_trans[2] = 0.;
814 geo_trans[3] = header.at(HEADER_RS_YLL) + (n_rows - 0.5) * header.at(HEADER_RS_CELLSIZE);
815 geo_trans[4] = 0.;
816 geo_trans[5] = -header.at(HEADER_RS_CELLSIZE);
817 po_dst_ds->SetGeoTransform(geo_trans);
818 if (opts.find(HEADER_RS_SRS) == opts.end()) {
819 po_dst_ds->SetProjection("");
820 } else {
821 po_dst_ds->SetProjection(opts.at(HEADER_RS_SRS).c_str());
822 }
823 if (papsz_options != nullptr) { CSLDestroy(papsz_options); }
824 if (new_values != nullptr) { CPLFree(new_values); }
825 GDALClose(po_dst_ds);
826
827 return true;
828}
829#endif /* USE_GDAL */
830
838template <typename T>
839bool WriteRasterToFile(const string& filename, const STRDBL_MAP& header,
840 const STRING_MAP& opts, T* values) {
841 if (GetPathFromFullName(filename).empty()) { return false; }
842 string abs_filename = GetAbsolutePath(filename);
843 string filetype = GetUpper(GetSuffix(abs_filename));
844 if (StringMatch(filetype, ASCIIExtension)) {
845 return WriteSingleAsc(abs_filename, header, values);
846 }
847#ifdef USE_GDAL
848 if (StringMatch(filetype, GTiffExtension)) {
849 return WriteSingleGeotiff(abs_filename, header, opts, values);
850 }
851 return WriteSingleGeotiff(ReplaceSuffix(abs_filename, GTiffExtension),
852 header, opts, values);
853#else
854 StatusMessage("Warning: Without GDAL, ASC file will be exported as default!");
855 return WriteSingleAsc(ReplaceSuffix(abs_filename, ASCIIExtension), header, values);
856#endif /* USE_GDAL */
857}
858
859#ifdef USE_MONGODB
869template <typename T>
870bool ReadGridFsFile(MongoGridFs* gfs, const string& filename,
871 T*& data, STRDBL_MAP& header,
872 STRING_MAP& header_str,
873 const STRING_MAP& opts /* = STRING_MAP() */) {
874 // Get stream data and metadata by file name
875 vint length;
876 char* buf = nullptr;
877 if (!gfs->GetStreamData(filename, buf, length, nullptr, &opts) ||
878 nullptr == buf) {
879 return false;
880 }
881 bson_t* bmeta = gfs->GetFileMetadata(filename, nullptr, opts);
882
883 // Retrieve raster header values
884 bson_iter_t iter; // Loop the metadata, add to `header_str` or `header`
885 if (nullptr != bmeta && bson_iter_init(&iter, bmeta)) {
886 while (bson_iter_next(&iter)) {
887 const char* key = bson_iter_key(&iter);
888 if (header.find(key) != header.end()) {
889 GetNumericFromBsonIterator(&iter, header[key]);
890 }
891 else {
892 header_str[key] = GetStringFromBsonIterator(&iter);
893 }
894 }
895 }
896 bson_destroy(bmeta); // Destroy bson of metadata immediately after use
897
898 int n_rows = CVT_INT(header.at(HEADER_RS_NROWS));
899 int n_cols = CVT_INT(header.at(HEADER_RS_NCOLS));
900 int n_lyrs = CVT_INT(header.at(HEADER_RS_LAYERS));
901 int n_cells = CVT_INT(header.at(HEADER_RS_CELLSNUM));
902 if (n_rows < 0 || n_cols < 0 || n_lyrs < 0) { // missing essential metadata
903 delete[] buf;
904 return false;
905 }
906 int value_count = n_cells * n_lyrs;
907 size_t size_dtype = length / value_count;
908
910 if (header_str.find(HEADER_RSOUT_DATATYPE) != header_str.end()) {
911 rstype = StringToRasterDataType(header_str.at(HEADER_RSOUT_DATATYPE));
912 }
913 if (rstype == RDT_Unknown) {
914 StatusMessage("Unknown data type in MongoDB GridFS!");
915 delete[] buf;
916 return false;
917 }
918
919 if (rstype == RDT_Double && size_dtype == sizeof(double)) {
920 double* data_dbl = reinterpret_cast<double*>(buf);
921 Initialize1DArray(value_count, data, data_dbl);
922 //Release1DArray(data_dbl);
923 }
924 else if (rstype == RDT_Float && size_dtype == sizeof(float)) {
925 float* data_flt = reinterpret_cast<float*>(buf);
926 Initialize1DArray(value_count, data, data_flt);
927 //Release1DArray(data_flt);
928 }
929 else if (rstype == RDT_Int32 && size_dtype == sizeof(vint32_t)) {
930 vint32_t* data_int32 = reinterpret_cast<vint32_t*>(buf);
931 Initialize1DArray(value_count, data, data_int32);
932 //Release1DArray(data_int32);
933 }
934 else if (rstype == RDT_UInt32 && size_dtype == sizeof(vuint32_t)) {
935 vuint32_t* data_uint32 = reinterpret_cast<vuint32_t*>(buf);
936 Initialize1DArray(value_count, data, data_uint32);
937 //Release1DArray(data_uint32);
938 }
939 else if (rstype == RDT_Int64 && size_dtype == sizeof(vint64_t)) {
940 vint64_t* data_int64 = reinterpret_cast<vint64_t*>(buf);
941 Initialize1DArray(value_count, data, data_int64);
942 //Release1DArray(data_int64);
943 }
944 else if (rstype == RDT_UInt64 && size_dtype == sizeof(vuint64_t)) {
945 vuint64_t* data_uint64 = reinterpret_cast<vuint64_t*>(buf);
946 Initialize1DArray(value_count, data, data_uint64);
947 //Release1DArray(data_uint64);
948 }
949 else if (rstype == RDT_Int16 && size_dtype == sizeof(vint16_t)) {
950 vint16_t* data_int16 = reinterpret_cast<vint16_t*>(buf);
951 Initialize1DArray(value_count, data, data_int16);
952 //Release1DArray(data_int16);
953 }
954 else if (rstype == RDT_UInt16 && size_dtype == sizeof(vuint16_t)) {
955 vuint16_t* data_uint16 = reinterpret_cast<vuint16_t*>(buf);
956 Initialize1DArray(value_count, data, data_uint16);
957 //Release1DArray(data_uint16);
958 }
959 else if (rstype == RDT_Int8 && size_dtype == sizeof(vint8_t)) {
960 vint8_t* data_int8 = reinterpret_cast<vint8_t*>(buf);
961 Initialize1DArray(value_count, data, data_int8);
962 //Release1DArray(data_int8);
963 }
964 else if (rstype == RDT_UInt8 && size_dtype == sizeof(vuint8_t)) {
965 vuint8_t* data_uint8 = reinterpret_cast<vuint8_t*>(buf);
966 Initialize1DArray(value_count, data, data_uint8);
967 //Release1DArray(data_uint8);
968 }
969 else {
970 StatusMessage("Unconsistent of data type and size!");
971 delete[] buf;
972 return false;
973 }
974 delete[] buf;
975 return true;
976}
977
988template <typename T>
989bool WriteStreamDataAsGridfs(MongoGridFs* gfs, const string& filename,
990 STRDBL_MAP& header, T* values, const int datalength,
991 const STRING_MAP& opts = STRING_MAP()) {
992 STRING_MAP curopts;
993 CopyStringMap(opts, curopts);
994 RasterDataType temp_type = TypeToRasterDataType(typeid(T));
995 if (curopts.find(HEADER_RSOUT_DATATYPE) == curopts.end()) {
997 }
998 gfs->RemoveFile(filename, nullptr, curopts);
999 bson_t p = BSON_INITIALIZER;
1000 double intpart; // https://stackoverflow.com/a/1521682/4837280
1001 for (auto iter = header.begin(); iter != header.end(); ++iter) {
1002 if (!StringMatch(HEADER_RS_NODATA, iter->first)
1003 && std::modf(iter->second, &intpart) == 0.0) {
1004 // std::modf consider inf as an integer,
1005 // hence cannot handle -3.40282346639e+38 which is one of commonly used Nodata
1006 BSON_APPEND_INT32(&p, iter->first.c_str(), CVT_INT(iter->second));
1007 }
1008 else {
1009 BSON_APPEND_DOUBLE(&p, iter->first.c_str(), iter->second);
1010 }
1011 }
1012 // Check DATATYPE in metadata is consistent with T, transform if necessary
1013 char* buf = nullptr;
1014 vint buflength = -1;
1015 bool transformed = true;
1017 if (opt_type == temp_type) {
1018 buf = reinterpret_cast<char*>(values);
1019 buflength = datalength * sizeof(T);
1020 transformed = false;
1021 } else {
1022 if (opt_type == RDT_UInt8) {
1023 vuint8_t* newdata = nullptr;
1024 Initialize1DArray(datalength, newdata, values);
1025 buf = reinterpret_cast<char*>(newdata);
1026 buflength = datalength * sizeof(vuint8_t);
1027 } else if (opt_type == RDT_Int8) {
1028 vint8_t* newdata = nullptr;
1029 Initialize1DArray(datalength, newdata, values);
1030 buf = reinterpret_cast<char*>(newdata);
1031 buflength = datalength * sizeof(vint8_t);
1032 } else if (opt_type == RDT_UInt16) {
1033 vuint16_t* newdata = nullptr;
1034 Initialize1DArray(datalength, newdata, values);
1035 buf = reinterpret_cast<char*>(newdata);
1036 buflength = datalength * sizeof(vuint16_t);
1037 } else if (opt_type == RDT_Int16) {
1038 vint16_t* newdata = nullptr;
1039 Initialize1DArray(datalength, newdata, values);
1040 buf = reinterpret_cast<char*>(newdata);
1041 buflength = datalength * sizeof(vint16_t);
1042 } else if (opt_type == RDT_UInt32) {
1043 vuint32_t* newdata = nullptr;
1044 Initialize1DArray(datalength, newdata, values);
1045 buf = reinterpret_cast<char*>(newdata);
1046 buflength = datalength * sizeof(vuint32_t);
1047 } else if (opt_type == RDT_Int32) {
1048 vint32_t* newdata = nullptr;
1049 Initialize1DArray(datalength, newdata, values);
1050 buf = reinterpret_cast<char*>(newdata);
1051 buflength = datalength * sizeof(vint32_t);
1052 } else if (opt_type == RDT_Float) {
1053 float* newdata = nullptr;
1054 Initialize1DArray(datalength, newdata, values);
1055 buf = reinterpret_cast<char*>(newdata);
1056 buflength = datalength * sizeof(float);
1057 } else if (opt_type == RDT_Double) {
1058 double* newdata = nullptr;
1059 Initialize1DArray(datalength, newdata, values);
1060 buf = reinterpret_cast<char*>(newdata);
1061 buflength = datalength * sizeof(double);
1062 }
1063 }
1064 // Add user-specific key-values into metadata
1065 AppendStringOptionsToBson(&p, curopts);
1066
1067 int try_times = 0;
1068 bool gstatus = false;
1069 while (try_times <= 3) { // Try 3 times
1070 gstatus = gfs->WriteStreamData(filename, buf, buflength, &p);
1071 if (gstatus) { break; }
1072 SleepMs(2); // Sleep 0.002 sec and retry
1073 try_times++;
1074 }
1075 bson_destroy(&p);
1076 if (transformed) { delete[] buf; }
1077 return gstatus;
1078}
1079
1080#endif /* USE_MONGODB */
1081
1087public:
1089
1090 SubsetPositions(int srow, int erow, int scol, int ecol);
1091
1092 explicit SubsetPositions(SubsetPositions*& src, bool deep_copy = false);
1093
1095
1096 bool Initialization();
1097
1098 template <typename T>
1099 bool SetData(const int n, T* data) {
1100 if (n != n_cells) { return false; }
1101 if (nullptr == data) { return false; }
1102 if (1 != n_lyrs) { n_lyrs = 1; }
1103 if (nullptr != data_) {
1104 for (int i = 0; i < n_cells; i++) { data_[i] = CVT_DBL(data[i]); }
1105 } else {
1107 }
1108 usable = true;
1109 return true;
1110 }
1111
1112 template <typename T>
1113 bool Set2DData(const int n, const int lyr, T** data2d) {
1114 if (n != n_cells) { return false; }
1115 if (nullptr == data2d) { return false; }
1116 if (lyr != n_lyrs) { n_lyrs = lyr; }
1117 if (nullptr != data2d_) {
1118 for (int i = 0; i < n_cells; i++) {
1119 for (int j = 0; j < n_lyrs; j++) {
1120 data2d_[i][j] = CVT_DBL(data2d[i][j]);
1121 }
1122 }
1123 } else {
1125 }
1126 usable = true;
1127 return true;
1128 }
1129#ifdef USE_MONGODB
1130 bool ReadFromMongoDB(MongoGridFs* gfs, const string& fname,
1131 const STRING_MAP& opts = STRING_MAP());
1132#endif
1133 void GetHeader(double gxll, double gyll, int gnrows, double cellsize,
1134 double nodata, STRDBL_MAP& subheader);
1135 template <typename T>
1136 void Output(T nodata, vector<T*>& fulldata) {
1137 if (nullptr == data_ && nullptr == data2d_) { return; }
1138 int nrows = g_erow - g_srow + 1;
1139 int ncols = g_ecol - g_scol + 1;
1140 int fullsize = nrows * ncols;
1141 for (int ilyr = 0; ilyr < n_lyrs; ilyr++) {
1142 T* tmpdata = nullptr;
1143 Initialize1DArray(fullsize, tmpdata, nodata);
1144 for (int vi = 0; vi < n_cells; vi++) {
1145 //int j = local_pos_[vi][0] * ncols + local_pos_[vi][1];
1146 int j = local_posidx_[vi];
1147 if (n_lyrs > 1 && nullptr != data2d_) {
1148 tmpdata[j] = static_cast<T>(data2d_[vi][ilyr]);
1149 }
1150 else if (n_lyrs == 1 && nullptr != data_) {
1151 tmpdata[j] = static_cast<T>(data_[vi]);
1152 }
1153 }
1154 fulldata.emplace_back(tmpdata);
1155 }
1156 }
1157
1158 bool usable;
1165 bool alloc_;
1168 int* global_;
1169 double* data_;
1170 double** data2d_;
1171};
1172
1178template <typename T, typename MASK_T = T>
1180public:
1181 /************* Construct functions ***************/
1182
1186 explicit clsRasterData(bool is_2d = false);
1187
1191 clsRasterData(T* data, int cols, int rows, T nodata, double dx, double xll,
1192 double yll, const STRING_MAP& opts = STRING_MAP());
1193
1198 clsRasterData(T* data, int cols, int rows, T nodata, double dx, double xll,
1199 double yll, const string& srs);
1200
1204 clsRasterData(T** data2d, int cols, int rows, int nlayers, T nodata,
1205 double dx, double xll, double yll, const STRING_MAP& opts = STRING_MAP());
1206
1211 clsRasterData(T** data2d, int cols, int rows, int nlayers, T nodata,
1212 double dx, double xll, double yll, const string& srs);
1213
1225 explicit clsRasterData(const string& filename, bool calc_pos = false,
1226 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1227 double default_value = NODATA_VALUE, const STRING_MAP& opts = STRING_MAP());
1228
1242 static clsRasterData<T, MASK_T>* Init(const string& filename, bool calc_pos = false,
1243 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1244 double default_value = NODATA_VALUE, const STRING_MAP& opts = STRING_MAP());
1245
1257 explicit clsRasterData(vector<string>& filenames, bool calc_pos = false,
1258 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1259 double default_value = NODATA_VALUE, const STRING_MAP& opts = STRING_MAP());
1260
1276 static clsRasterData<T, MASK_T>* Init(vector<string>& filenames, bool calc_pos = false,
1277 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1278 double default_value = NODATA_VALUE, const STRING_MAP& opts = STRING_MAP());
1279
1283 clsRasterData(clsRasterData<MASK_T>* mask, T* values, int len,
1284 const STRING_MAP& opts = STRING_MAP());
1285
1289 clsRasterData(clsRasterData<MASK_T>* mask, T** values, int len, int lyrs,
1290 const STRING_MAP& opts = STRING_MAP());
1291
1292#ifdef USE_MONGODB
1293
1306 clsRasterData(MongoGridFs* gfs, const char* remote_filename, bool calc_pos = false,
1307 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1308 double default_value = NODATA_VALUE, const STRING_MAP& opts = STRING_MAP());
1309
1313 static clsRasterData<T, MASK_T>* Init(MongoGridFs* gfs, const char* remote_filename,
1314 bool calc_pos = false, clsRasterData<MASK_T>* mask = nullptr,
1315 bool use_mask_ext = true, double default_value = NODATA_VALUE,
1316 const STRING_MAP& opts = STRING_MAP());
1317#endif
1318
1333 explicit clsRasterData(clsRasterData<T, MASK_T>* another);
1334
1337
1338 /************* Read functions ***************/
1348 bool ReadFromFile(const string& filename, bool calc_pos = false, clsRasterData<MASK_T>* mask = nullptr,
1349 bool use_mask_ext = true, double default_value = NODATA_VALUE,
1350 const STRING_MAP& opts = STRING_MAP());
1355 bool ReadFromFiles(vector<string>& filenames, bool calc_pos = false, clsRasterData<MASK_T>* mask = nullptr,
1356 bool use_mask_ext = true, double default_value = NODATA_VALUE,
1357 const STRING_MAP& opts = STRING_MAP());
1358
1359#ifdef USE_MONGODB
1370 bool ReadFromMongoDB(MongoGridFs* gfs, const string& filename, bool calc_pos = false,
1371 clsRasterData<MASK_T>* mask = nullptr, bool use_mask_ext = true,
1372 double default_value = NODATA_VALUE,
1373 const STRING_MAP& opts = STRING_MAP());
1374
1375#endif /* USE_MONGODB */
1376 /************* Write functions ***************/
1377
1383 bool OutputToFile(const string& filename, bool out_origin = true);
1384
1393 bool OutputSubsetToFile(bool out_origin = false, bool out_combined = true,
1394 const string& outname = string(),
1395 const map<vint, vector<double> >& recls = map<vint, vector<double> >(),
1396 double default_value = NODATA_VALUE);
1397
1401 bool OutputAscFile(const string& filename);
1402
1403#ifdef USE_GDAL
1407 bool OutputFileByGdal(const string& filename);
1408#endif /* USE_GDAL */
1409
1410#ifdef USE_MONGODB
1411
1420 bool OutputToMongoDB(MongoGridFs* gfs, const string& filename = string(),
1421 const STRING_MAP& opts = STRING_MAP(),
1422 bool include_nodata = true,
1423 bool out_origin = true);
1424
1440 bool OutputSubsetToMongoDB(MongoGridFs* gfs, const string& filename = string(),
1441 const STRING_MAP& opts = STRING_MAP(),
1442 bool include_nodata = true,
1443 bool out_origin = false, bool out_combined = true,
1444 const map<vint, vector<double> >& recls = map<vint, vector<double> >(),
1445 double default_value = NODATA_VALUE);
1446
1447#endif /* USE_MONGODB */
1448
1449 /************************************************************************/
1450 /* Set information functions */
1451 /************************************************************************/
1452
1453 void SetHeader(const STRDBL_MAP& refers);
1454
1456 void SetCoreName(const string& name) { core_name_ = name; }
1457
1461 void SetValue(int row, int col, T value, int lyr = 1);
1462
1467 bool SetCalcPositions();
1468
1472 bool SetPositions(int len, int** pdata);
1473 bool SetPositions(int len, int* pdata);
1474
1479 bool SetUseMaskExt();
1480
1482 void SetDataType(RasterDataType const type) { rs_type_ = type; }
1483
1485 void SetDataType(const string& strtype) { rs_type_ = StringToRasterDataType(strtype); }
1486
1488 void SetOutDataType(RasterDataType type);
1489
1491 void SetOutDataType(const string& strtype);
1492
1494 void SetDefaultValue(const double defaultv) { default_value_ = defaultv; }
1495
1499 bool BuildSubSet(map<int, int> groups = map<int, int>());
1500
1504 bool ReleaseSubset();
1505
1509 bool RebuildSubSet(map<int, int> groups = map<int, int>());
1510
1511 /************************************************************************/
1512 /* Get information functions */
1513 /************************************************************************/
1514
1519 void CalculateStatistics();
1520
1525 void UpdateStatistics();
1526
1530 void ReleaseStatsMap2D();
1531
1539 double GetStatistics(string sindex, int lyr = 1);
1540
1548 void GetStatistics(string sindex, int* lyrnum, double** values);
1549
1554 double GetAverage(const int lyr = 1) { return GetStatistics(STATS_RS_MEAN, lyr); }
1555
1560 double GetMaximum(const int lyr = 1) { return GetStatistics(STATS_RS_MAX, lyr); }
1561
1566 double GetMinimum(const int lyr = 1) { return GetStatistics(STATS_RS_MIN, lyr); }
1567
1572 double GetStd(const int lyr = 1) { return GetStatistics(STATS_RS_STD, lyr); }
1573
1579 double GetRange(const int lyr = 1) { return GetStatistics(STATS_RS_RANGE, lyr); }
1580
1586 void GetAverage(int* lyrnum, double** values) { GetStatistics(STATS_RS_MEAN, lyrnum, values); }
1587
1592 void GetMaximum(int* lyrnum, double** values) { GetStatistics(STATS_RS_MAX, lyrnum, values); }
1593
1598 void GetMinimum(int* lyrnum, double** values) { GetStatistics(STATS_RS_MIN, lyrnum, values); }
1599
1604 void GetStd(int* lyrnum, double** values) { GetStatistics(STATS_RS_STD, lyrnum, values); }
1605
1610 void GetRange(int* lyrnum, double** values) { GetStatistics(STATS_RS_RANGE, lyrnum, values); }
1611
1616 void GetValidNumber(int* lyrnum, double** values) { GetStatistics(STATS_RS_VALIDNUM, lyrnum, values); }
1617
1623 int GetValidNumber(const int lyr = 1) { return CVT_INT(GetStatistics(STATS_RS_VALIDNUM, lyr)); }
1624
1625 int GetCellNumber() const { return n_cells_; }
1627 int GetDataLength() const { return n_cells_ < 0 || n_lyrs_ < 0 ? -1 : n_cells_ * n_lyrs_; }
1628 int GetCols() const { return CVT_INT(headers_.at(HEADER_RS_NCOLS)); }
1629 int GetRows() const { return CVT_INT(headers_.at(HEADER_RS_NROWS)); }
1630 double GetCellWidth() const { return headers_.at(HEADER_RS_CELLSIZE); }
1631
1633 double GetXllCenter() const {
1634 if (headers_.find(HEADER_RS_XLL) != headers_.end()) {
1635 return headers_.at(HEADER_RS_XLL);
1636 }
1637 if (headers_.find(HEADER_RS_XLLCOR) != headers_.end()) {
1638 return headers_.at(HEADER_RS_XLLCOR) + 0.5 * GetCellWidth();
1639 }
1640 return NODATA_VALUE;
1641 }
1642
1644 double GetYllCenter() const {
1645 if (headers_.find(HEADER_RS_YLL) != headers_.end()) {
1646 return headers_.at(HEADER_RS_YLL);
1647 }
1648 if (headers_.find(HEADER_RS_YLLCOR) != headers_.end()) {
1649 return headers_.at(HEADER_RS_YLLCOR) + 0.5 * GetCellWidth();
1650 }
1651 return NODATA_VALUE;
1652 }
1653
1654 int GetLayers() const { return n_lyrs_; }
1655 RasterDataType GetDataType() const { return rs_type_; }
1656 RasterDataType GetOutDataType() const { return rs_type_out_; }
1657 T GetNoDataValue() const { return no_data_value_; }
1658 double GetDefaultValue() const { return default_value_; }
1659
1665 int GetPosition(int row, int col);
1666
1668 int GetPosition(float x, float y);
1669
1671 int GetPosition(double x, double y);
1672
1674 map<int, SubsetPositions*>& GetSubset() { return subset_; }
1675
1679 bool GetRasterData(int* n_cells, T** data);
1680
1685 bool Get2DRasterData(int* n_cells, int* n_lyrs, T*** data);
1686
1688 const STRDBL_MAP& GetRasterHeader() const { return headers_; }
1689
1691 const STRDBL_MAP& GetStatistics() const { return stats_; }
1692
1694 const map<string, double *>& GetStatistics2D() const { return stats_2d_; };
1695
1697 string GetFilePath() const { return full_path_; }
1698
1700 string GetCoreName() const { return core_name_; }
1701
1707 void GetRasterPositionData(int* datalength, int*** positiondata);
1708
1709 void GetRasterPositionData(int* datalength, int** positiondata);
1710
1711 T* GetRasterDataPointer() const { return raster_; }
1712 int** GetRasterPositionDataPointer() const { return pos_data_; }
1713 int* GetRasterPositionIndexPointer() const { return pos_idx_; }
1714 T** Get2DRasterDataPointer() const { return raster_2d_; }
1715 const char* GetSrs();
1716 string GetSrsString();
1717 string GetOption(const char* key);
1718 const STRING_MAP& GetOptions() const { return options_; }
1719
1724 T GetValueByIndex(int cell_index, int lyr = 1);
1725
1731 void GetValueByIndex(int cell_index, T*& values);
1732
1737 T GetValue(int row, int col, int lyr = 1);
1738
1745 void GetValue(int row, int col, T*& values);
1746
1751 bool IsNoData(const int row, const int col, const int lyr = 1) {
1752 return FloatEqual(GetValue(row, col, lyr), no_data_value_);
1753 }
1754
1755 bool Is2DRaster() const { return is_2draster; }
1756 bool PositionsCalculated() const { return calc_pos_; }
1757 bool PositionsAllocated() const { return store_pos_; }
1758 bool MaskExtented() const { return use_mask_ext_; }
1759 bool StatisticsCalculated() const { return stats_calculated_; }
1760 bool Initialized() const { return initialized_; }
1761
1766 if ((!is_2draster && nullptr != raster_) || // Valid 1D raster
1767 (is_2draster && nullptr != raster_2d_)) // Valid 2D raster
1768 { return true; }
1769 StatusMessage("Error: Please initialize the raster object first.");
1770 return false;
1771 }
1772
1776 bool ValidateRowCol(const int row, const int col) {
1777 if ((row < 0 || row >= GetRows()) || (col < 0 || col >= GetCols())) {
1778 StatusMessage("The row must between 0 and " + ValueToString(GetRows() - 1) +
1779 ", and the col must between 0 and " + ValueToString(GetCols() - 1));
1780 return false;
1781 }
1782 return true;
1783 }
1784
1788 bool ValidateLayer(const int lyr) {
1789 if (lyr <= 0 || lyr > n_lyrs_) {
1790 StatusMessage("The layer must be 1 ");
1791 if (n_lyrs_ > 1) StatusMessage(" or between 1 and " +
1793 return false;
1794 }
1795 return true;
1796 }
1797
1801 bool ValidateIndex(const int idx) {
1802 if (idx < 0 || idx >= n_cells_) {
1803 StatusMessage("The index must between 0 and " + utils_string::ValueToString(n_cells_ - 1));
1804 return false;
1805 }
1806 return true;
1807 }
1808
1810 string GetFullFileName() const { return full_path_; }
1811
1813 clsRasterData<MASK_T>* GetMask() const { return mask_; }
1814
1818 void Copy(clsRasterData<T, MASK_T>* orgraster);
1819
1823 void ReplaceNoData(T replacedv);
1824
1828 void Reclassify(map<int, T> reclass_map);
1829
1830 /************* Utility functions ***************/
1831
1839 XY_COOR GetCoordinateByRowCol(int row, int col);
1840
1849 ROW_COL GetPositionByCoordinate(double x, double y, STRDBL_MAP* header = nullptr);
1850
1851private:
1855 void InitializeRasterClass(bool is_2d = false);
1856
1860 void InitializeReadFunction(const string& filename, bool calc_pos = false, clsRasterData<MASK_T>* mask = nullptr,
1861 bool use_mask_ext = true, double default_value = NODATA_VALUE,
1862 const STRING_MAP& opts = STRING_MAP());
1863
1875 bool ConstructFromSingleFile(const string& filename, bool calc_pos = false, clsRasterData<MASK_T>* mask = nullptr,
1876 bool use_mask_ext = true, double default_value = NODATA_VALUE,
1877 const STRING_MAP& opts = STRING_MAP());
1878
1887 int MaskAndCalculateValidPosition();
1888
1894 void CalculateValidPositionsFromGridData();
1895
1899 bool PrepareCombSubsetData(T**values, int* datalen, int* datalyrs,
1900 bool out_origin = false, bool include_nodata = true,
1901 const map<vint, vector<double> >&recls = map<vint, vector<double> >(),
1902 double default_value = NODATA_VALUE);
1903
1907 bool PrepareSubsetData(int sub_id, SubsetPositions* sub,
1908 T** values, int* datalen, int* datalyrs,
1909 bool out_origin = false, bool include_nodata = true,
1910 const map<vint, vector<double> >& recls = map<vint, vector<double> >(),
1911 double default_value = NODATA_VALUE);
1912
1916 bool OutputFullsizeToFiles(T* fullsizedata, int fsize, int datalyrs,
1917 const string& fullfilename, const STRDBL_MAP& header,
1918 const STRING_MAP& opts);
1919
1929 void AddOtherLayerRasterData(int row, int col, int cellidx, int lyr,
1930 STRDBL_MAP lyrheader, T* lyrdata);
1931
1935 void CheckDefaultValue() {
1936 if (FloatEqual(default_value_, NODATA_VALUE) && !FloatEqual(no_data_value_, NODATA_VALUE)) {
1937 default_value_ = CVT_DBL(no_data_value_);
1938 }
1939 }
1940
1944 clsRasterData& operator=(const clsRasterData&) { }
1945
1952 int n_cells_;
1954 int n_lyrs_;
1956 RasterDataType rs_type_;
1958 RasterDataType rs_type_out_;
1960 T no_data_value_;
1962 double default_value_;
1964 string full_path_;
1966 string core_name_;
1968 T* raster_;
1970 T** raster_2d_;
1972 int** pos_data_;
1974 int* pos_idx_;
1976 STRING_MAP options_;
1978 STRDBL_MAP headers_;
1980 STRDBL_MAP stats_;
1982 map<string, double *> stats_2d_;
1984 clsRasterData<MASK_T>* mask_;
1986 map<int, SubsetPositions*> subset_;
1988 bool initialized_;
1990 bool is_2draster;
1992 bool calc_pos_;
1994 bool store_pos_;
1996 bool use_mask_ext_;
1998 bool stats_calculated_;
1999};
2000
2001/******** Define common used raster types **************/
2002#ifndef IntRaster
2003#define IntRaster clsRasterData<int>
2004#endif
2005#ifndef FltRaster
2006#define FltRaster clsRasterData<float>
2007#endif
2008#ifndef DblRaster
2009#define DblRaster clsRasterData<double>
2010#endif
2011#ifndef IntIntRaster
2012#define IntIntRaster clsRasterData<int, int>
2013#endif
2014#ifndef FltIntRaster
2015#define FltIntRaster clsRasterData<float, int>
2016#endif
2017#ifndef DblIntRaster
2018#define DblIntRaster clsRasterData<double, int>
2019#endif
2020
2021/*******************************************************/
2022/************* Implementation Code Begin ***************/
2023/*******************************************************/
2024
2025/************* Construct functions ***************/
2026
2027template <typename T, typename MASK_T>
2028void clsRasterData<T, MASK_T>::InitializeRasterClass(bool is_2d /* = false */) {
2029 full_path_ = "";
2030 core_name_ = "";
2031 n_cells_ = -1;
2032 rs_type_ = RDT_Unknown;
2033 rs_type_out_ = RDT_Unknown;
2034 no_data_value_ = DefaultNoDataByType(TypeToRasterDataType(typeid(T)));
2035 //no_data_value_ = static_cast<T>(NODATA_VALUE); // Be careful of unsigned data type!
2036 default_value_ = NODATA_VALUE;
2037 raster_ = nullptr;
2038 pos_data_ = nullptr;
2039 pos_idx_ = nullptr;
2040 mask_ = nullptr;
2041 subset_ = map<int, SubsetPositions*>();
2042 n_lyrs_ = -1;
2043 is_2draster = is_2d;
2044 raster_2d_ = nullptr;
2045 calc_pos_ = false;
2046 store_pos_ = false;
2047 use_mask_ext_ = false;
2048 stats_calculated_ = false;
2049 headers_ = InitialHeader();
2050 options_ = InitialStrHeader();
2051 InitialStatsMap(stats_, stats_2d_);
2052 initialized_ = true;
2053}
2054
2055template <typename T, typename MASK_T>
2056void clsRasterData<T, MASK_T>::InitializeReadFunction(const string& filename, const bool calc_pos /* = false */,
2057 clsRasterData<MASK_T>* mask /* = nullptr */,
2058 const bool use_mask_ext /* = true */,
2059 double default_value /* NODATA_VALUE */,
2060 const STRING_MAP& opts /* = STRING_MAP() */) {
2061 if (!initialized_) { InitializeRasterClass(); }
2062 full_path_ = filename;
2063 mask_ = mask;
2064 calc_pos_ = calc_pos;
2065 use_mask_ext_ = use_mask_ext;
2066 if (nullptr == mask_) { use_mask_ext_ = false; }
2067 default_value_ = default_value;
2068 rs_type_out_ = RasterDataTypeInOptionals(opts);
2069 core_name_ = GetCoreFileName(full_path_);
2070 CopyStringMap(opts, options_);
2071}
2072
2073template <typename T, typename MASK_T>
2075 InitializeRasterClass(is_2d);
2076}
2077
2078template <typename T, typename MASK_T>
2079clsRasterData<T, MASK_T>::clsRasterData(T* data, int cols, int rows, T nodata,
2080 double dx, double xll, double yll,
2081 const string& srs) {
2083 UpdateStrHeader(opts, HEADER_RS_SRS, srs);
2084 clsRasterData(data, cols, rows, nodata, dx, xll, yll, opts);
2085}
2086
2087template <typename T, typename MASK_T>
2088clsRasterData<T, MASK_T>::clsRasterData(T* data, const int cols, const int rows, T nodata,
2089 const double dx, const double xll, const double yll,
2090 const STRING_MAP& opts /* = STRING_MAP() */) {
2091 InitializeRasterClass(false);
2092 rs_type_out_ = RasterDataTypeInOptionals(opts);
2093 raster_ = data;
2094 no_data_value_ = nodata;
2095 CopyStringMap(opts, options_);
2096 n_cells_ = cols * rows;
2097 n_lyrs_ = 1;
2098 UpdateHeader(headers_, HEADER_RS_NCOLS, cols);
2099 UpdateHeader(headers_, HEADER_RS_NROWS, rows);
2100 UpdateHeader(headers_, HEADER_RS_XLL, xll);
2101 UpdateHeader(headers_, HEADER_RS_YLL, yll);
2102 UpdateHeader(headers_, HEADER_RS_CELLSIZE, dx);
2103 UpdateHeader(headers_, HEADER_RS_NODATA, nodata);
2104 UpdateHeader(headers_, HEADER_RS_LAYERS, 1);
2105 UpdateHeader(headers_, HEADER_RS_CELLSNUM, n_cells_);
2106}
2107
2108template <typename T, typename MASK_T>
2109clsRasterData<T, MASK_T>::clsRasterData(T** data2d, const int cols, const int rows, const int nlayers,
2110 T nodata, const double dx, const double xll, const double yll,
2111 const string& srs) {
2113 UpdateStrHeader(opts, HEADER_RS_SRS, srs);
2114 clsRasterData(data2d, cols, rows, nlayers, nodata, dx, xll, yll, opts);
2115}
2116
2117template <typename T, typename MASK_T>
2118clsRasterData<T, MASK_T>::clsRasterData(T** data2d, const int cols, const int rows, const int nlayers,
2119 T nodata, const double dx, const double xll, const double yll,
2120 const STRING_MAP& opts /* = STRING_MAP() */) {
2121 InitializeRasterClass(true);
2122 rs_type_out_ = RasterDataTypeInOptionals(opts);
2123 raster_2d_ = data2d;
2124 no_data_value_ = nodata;
2125 CopyStringMap(opts, options_);
2126 n_cells_ = cols * rows;
2127 n_lyrs_ = nlayers;
2128 headers_[HEADER_RS_NCOLS] = cols;
2129 headers_[HEADER_RS_NROWS] = rows;
2130 headers_[HEADER_RS_XLL] = xll;
2131 headers_[HEADER_RS_YLL] = yll;
2132 headers_[HEADER_RS_CELLSIZE] = dx;
2133 headers_[HEADER_RS_NODATA] = no_data_value_;
2134 headers_[HEADER_RS_LAYERS] = n_lyrs_;
2135 headers_[HEADER_RS_CELLSNUM] = n_cells_;
2136}
2137
2138template <typename T, typename MASK_T>
2139clsRasterData<T, MASK_T>::clsRasterData(const string& filename, const bool calc_pos /* = false */,
2140 clsRasterData<MASK_T>* mask /* = nullptr */,
2141 const bool use_mask_ext /* = true */,
2142 double default_value /* NODATA_VALUE */,
2143 const STRING_MAP& opts /* = STRING_MAP() */) {
2144 InitializeRasterClass();
2145 rs_type_out_ = RasterDataTypeInOptionals(opts);
2146 ReadFromFile(filename, calc_pos, mask, use_mask_ext, default_value, opts);
2147}
2148
2149template <typename T, typename MASK_T>
2151 const bool calc_pos /* = false */,
2152 clsRasterData<MASK_T>* mask /* = nullptr */,
2153 const bool use_mask_ext /* = true */,
2154 double default_value /* = NODATA_VALUE */,
2155 const STRING_MAP& opts /* = STRING_MAP() */) {
2156 if (!FileExists(filename)) { return nullptr; }
2159 if (!rs->ReadFromFile(filename, calc_pos, mask, use_mask_ext, default_value, opts)) {
2160 delete rs;
2161 return nullptr;
2162 }
2163 return rs;
2164}
2165
2166template <typename T, typename MASK_T>
2168 const bool calc_pos /* = false */,
2169 clsRasterData<MASK_T>* mask /* = nullptr */,
2170 const bool use_mask_ext /* = true */,
2171 double default_value /* = NODATA_VALUE */,
2172 const STRING_MAP& opts /* = STRING_MAP() */) {
2173 if (!FilesExist(filenames)) {
2174 StatusMessage("Please make sure all file path existed!");
2175 return;
2176 }
2177 if (filenames.size() == 1) {
2178 ReadFromFile(filenames[0], calc_pos, mask,
2179 use_mask_ext, default_value, opts);
2180 }
2181 ReadFromFiles(filenames, calc_pos, mask,
2182 use_mask_ext, default_value, opts);
2183}
2184
2185template <typename T, typename MASK_T>
2187 bool calc_pos /* = false */,
2188 clsRasterData<MASK_T>* mask /* = nullptr */,
2189 bool use_mask_ext /* = true */,
2190 double default_value /* = NODATA_VALUE */,
2191 const STRING_MAP& opts /* = STRING_MAP() */) {
2192 if (!FilesExist(filenames)) {
2193 StatusMessage("Please make sure all file path existed!");
2194 return nullptr;
2195 }
2196 if (filenames.size() == 1) {
2197 return clsRasterData<T, MASK_T>::Init(filenames[0], calc_pos, mask, use_mask_ext,
2198 default_value, opts);
2199 }
2202 if (!rs2d->ReadFromFiles(filenames, calc_pos, mask, use_mask_ext, default_value, opts)) {
2203 delete rs2d;
2204 return nullptr;
2205 }
2206 return rs2d;
2207}
2208
2209template <typename T, typename MASK_T>
2211 const STRING_MAP& opts /* = STRING_MAP() */) {
2212 InitializeRasterClass(false);
2213 rs_type_out_ = RasterDataTypeInOptionals(opts);
2214 calc_pos_ = false;
2215 mask_ = mask;
2216 use_mask_ext_ = true;
2217 n_lyrs_ = 1;
2218 mask->GetRasterPositionData(&n_cells_, &pos_data_);
2219 mask->GetRasterPositionData(&n_cells_, &pos_idx_);
2220 if (n_cells_ != len) {
2221 StatusMessage("Input data length MUST EQUALS TO valid cell's number of mask!");
2222 initialized_ = false;
2223 return;
2224 }
2225 Initialize1DArray(n_cells_, raster_, values); // DO NOT ASSIGN ARRAY DIRECTLY!
2226 default_value_ = mask_->GetDefaultValue();
2227 CopyHeader(mask_->GetRasterHeader(), headers_);
2228 no_data_value_ = static_cast<T>(mask_->GetNoDataValue());
2229 UpdateStrHeader(options_, HEADER_RS_SRS, mask_->GetSrsString());
2230 CopyStringMap(opts, options_);
2231}
2232
2233template <typename T, typename MASK_T>
2235 const int lyrs, const STRING_MAP& opts /* = STRING_MAP() */) {
2236 InitializeRasterClass(true);
2237 calc_pos_ = false;
2238 mask_ = mask;
2239 use_mask_ext_ = true;
2240 n_lyrs_ = lyrs;
2241 mask->GetRasterPositionData(&n_cells_, &pos_data_);
2242 mask->GetRasterPositionData(&n_cells_, &pos_idx_);
2243 if (n_cells_ != len) {
2244 StatusMessage("Input data length MUST EQUALS TO valid cell's number of mask!");
2245 initialized_ = false;
2246 return;
2247 }
2248 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_, values); // DO NOT ASSIGN ARRAY DIRECTLY!
2249 CopyHeader(mask_->GetRasterHeader(), headers_);
2250 no_data_value_ = static_cast<T>(mask_->GetNoDataValue());
2251 UpdateHeader(headers_, HEADER_RS_LAYERS, n_lyrs_);
2252 CopyStringMap(opts, options_);
2253 UpdateStrHeader(options_, HEADER_RS_SRS, mask_->GetSrsString());
2254}
2255
2256#ifdef USE_MONGODB
2257
2258template <typename T, typename MASK_T>
2260 const bool calc_pos /* = false */,
2261 clsRasterData<MASK_T>* mask /* = nullptr */,
2262 const bool use_mask_ext /* = true */,
2263 double default_value /* NODATA_VALUE */,
2264 const STRING_MAP& opts /* = STRING_MAP() */) {
2265 InitializeRasterClass();
2266 rs_type_out_ = RasterDataTypeInOptionals(opts);
2267 ReadFromMongoDB(gfs, remote_filename, calc_pos, mask, use_mask_ext, default_value, opts);
2268}
2269
2270template <typename T, typename MASK_T>
2272 const bool calc_pos /* = false */,
2273 clsRasterData<MASK_T>* mask /* = nullptr */,
2274 const bool use_mask_ext /* = true */,
2275 double default_value /* NODATA_VALUE */,
2276 const STRING_MAP& opts /* = STRING_MAP() */) {
2279 if (!rs_mongo->ReadFromMongoDB(gfs, remote_filename, calc_pos, mask, use_mask_ext, default_value, opts)) {
2280 delete rs_mongo;
2281 return nullptr;
2282 }
2283 return rs_mongo;
2284}
2285
2286#endif /* USE_MONGODB */
2287
2288template <typename T, typename MASK_T>
2289bool clsRasterData<T, MASK_T>::ConstructFromSingleFile(const string& filename,
2290 const bool calc_pos /* = false */,
2291 clsRasterData<MASK_T>* mask /* = nullptr */,
2292 const bool use_mask_ext /* = true */,
2293 double default_value /* NODATA_VALUE */,
2294 const STRING_MAP& opts /* = STRING_MAP() */) {
2295 InitializeReadFunction(filename, calc_pos, mask, use_mask_ext, default_value, opts);
2296
2297 bool readflag = false;
2298 string srs = string();
2299 if (StringMatch(GetUpper(GetSuffix(filename)), ASCIIExtension)) {
2300 readflag = ReadAscFile(full_path_, headers_, raster_);
2301 } else {
2302#ifdef USE_GDAL
2303 readflag = ReadRasterFileByGdal(full_path_, headers_, raster_, rs_type_, srs);
2304#else
2305 StatusMessage("Warning: Only ASC format is supported without GDAL!");
2306 return false;
2307#endif /* USE_GDAL */
2308 }
2309 // After read raster data from ASCII file or GeoTiff.
2310 no_data_value_ = static_cast<T>(headers_.at(HEADER_RS_NODATA));
2311 UpdateStrHeader(options_, HEADER_RS_SRS, srs);
2312 // if not specified, set output data type the same as input
2313 if (rs_type_out_ == 0) {
2314 rs_type_out_ = rs_type_;
2316 }
2317 CheckDefaultValue();
2318 if (readflag) {
2319 if (n_lyrs_ < 0) { n_lyrs_ = 1; }
2320 if (is_2draster) { is_2draster = false; }
2321 return MaskAndCalculateValidPosition() >= 0;
2322 }
2323 return false;
2324}
2325
2326template <typename T, typename MASK_T>
2328 if (!core_name_.empty()) { StatusMessage(("Release raster: " + core_name_).c_str()); }
2329 if (nullptr != raster_) { Release1DArray(raster_); }
2330 if (nullptr != pos_data_ && store_pos_) { Release2DArray(pos_data_); }
2331 if (nullptr != pos_idx_ && store_pos_) { Release1DArray(pos_idx_); }
2332 if (nullptr != raster_2d_ && is_2draster) { Release2DArray(raster_2d_); }
2333 if (is_2draster && stats_calculated_) { ReleaseStatsMap2D(); }
2334 ReleaseSubset();
2335}
2336
2337template <typename T, typename MASK_T>
2338bool clsRasterData<T, MASK_T>::BuildSubSet(map<int, int> groups /* = map<int, int>() */) {
2339 if (!ValidateRasterData()) { return false; }
2340 if (nullptr == pos_data_ || nullptr == pos_idx_) {
2341 if (!SetCalcPositions()) { return false; }
2342 }
2343 if (!subset_.empty()) { return true; }
2344
2345 int global_ncols = GetCols();
2346 map<int, vector<int> > global_idx;
2347 for (int vi = 0; vi < n_cells_; vi++) {
2348 T curv = GetValueByIndex(vi); // compatible with 2D Raster
2349 if (FloatEqual(curv, no_data_value_)) { continue; }
2350 int groupv = CVT_INT(curv); // By default, group value is original raster value
2351 if (!groups.empty() && groups.find(groupv) != groups.end()) {
2352 groupv = groups.at(groupv); // original raster value --> specified group ID
2353 }
2354 //int currow = pos_data_[vi][0];
2355 //int curcol = pos_data_[vi][1];
2356 int currow = pos_idx_[vi] / global_ncols;
2357 int curcol = pos_idx_[vi] % global_ncols;
2358 if (subset_.find(groupv) == subset_.end()) {
2359#ifdef HAS_VARIADIC_TEMPLATES
2360 subset_.emplace(groupv, new SubsetPositions(currow, currow, curcol, curcol));
2361#else
2362 subset_.insert(make_pair(groupv, new SubsetPositions(currow, currow, curcol, curcol)));
2363#endif
2364 }
2365 SubsetPositions*& cursubset = subset_.at(groupv);
2366 if (currow > cursubset->g_erow) { cursubset->g_erow = currow; }
2367 if (currow < cursubset->g_srow) { cursubset->g_srow = currow; }
2368 if (curcol > cursubset->g_ecol) { cursubset->g_ecol = curcol; }
2369 if (curcol < cursubset->g_scol) { cursubset->g_scol = curcol; }
2370 if (global_idx.find(groupv) == global_idx.end()) {
2371#ifdef HAS_VARIADIC_TEMPLATES
2372 global_idx.emplace(groupv, vector<int>());
2373#else
2374 global_idx.insert(make_pair(groupv, vector<int>()));
2375#endif
2376 }
2377 global_idx[groupv].emplace_back(vi);
2378 cursubset->n_cells += 1;
2379 }
2380 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2381 Initialize1DArray(it->second->n_cells, it->second->global_, 0);
2382 for (auto it2 = global_idx[it->first].begin(); it2 != global_idx[it->first].end(); ++it2) {
2383 it->second->global_[it2 - global_idx[it->first].begin()] = *it2;
2384 }
2385 }
2386 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2387 Initialize2DArray(it->second->n_cells, 2, it->second->local_pos_, -1);
2388 Initialize1DArray(it->second->n_cells, it->second->local_posidx_, -1);
2389
2390 int nrows = it->second->g_erow - it->second->g_srow + 1;
2391 int local_ncols = it->second->g_ecol - it->second->g_scol + 1;
2392 for (int gidx = 0; gidx < it->second->n_cells; gidx++) {
2393 //it->second->local_pos_[gidx][0] = pos_data_[it->second->global_[gidx]][0] - it->second->g_srow;
2394 //it->second->local_pos_[gidx][1] = pos_data_[it->second->global_[gidx]][1] - it->second->g_scol;
2395 int local_row = pos_idx_[it->second->global_[gidx]] / global_ncols - it->second->g_srow;
2396 int local_col = pos_idx_[it->second->global_[gidx]] % global_ncols - it->second->g_scol;
2397 it->second->local_pos_[gidx][0] = local_row;
2398 it->second->local_pos_[gidx][1] = local_col;
2399 it->second->local_posidx_[gidx] = local_row * local_ncols + local_col;
2400 }
2401 it->second->alloc_ = true;
2402 }
2403 return true;
2404}
2405
2406template <typename T, typename MASK_T>
2408 if (!subset_.empty()) {
2409 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2410 delete it->second;
2411 it->second = nullptr;
2412 }
2413 subset_.clear();
2414 }
2415 return true;
2416}
2417
2418template <typename T, typename MASK_T>
2419bool clsRasterData<T, MASK_T>::RebuildSubSet(const map<int, int> groups /* = map<int, int>() */) {
2420 return ReleaseSubset() && BuildSubSet(groups);
2421}
2422
2423/************* Set information functions ***************/
2424
2425template <typename T, typename MASK_T>
2427 rs_type_out_ = type;
2429}
2430
2431template <typename T, typename MASK_T>
2432void clsRasterData<T, MASK_T>::SetOutDataType(const string& strtype) {
2433 rs_type_out_ = StringToRasterDataType(strtype);
2435}
2436
2437/************* Get information functions ***************/
2438template <typename T, typename MASK_T>
2440 if (stats_calculated_) { return; }
2441 if (stats_.empty() || stats_2d_.empty()) { InitialStatsMap(stats_, stats_2d_); }
2442 if (is_2draster && nullptr != raster_2d_) {
2443 double** derivedvs = nullptr;
2444 BasicStatistics(raster_2d_, n_cells_, n_lyrs_, &derivedvs, no_data_value_);
2445 stats_2d_.at(STATS_RS_VALIDNUM) = derivedvs[0];
2446 stats_2d_.at(STATS_RS_MEAN) = derivedvs[1];
2447 stats_2d_.at(STATS_RS_MAX) = derivedvs[2];
2448 stats_2d_.at(STATS_RS_MIN) = derivedvs[3];
2449 stats_2d_.at(STATS_RS_STD) = derivedvs[4];
2450 stats_2d_.at(STATS_RS_RANGE) = derivedvs[5];
2451 // 1D array elements of derivedvs will be released by the destructor: releaseStatsMap2D()
2452 Release1DArray(derivedvs);
2453 } else {
2454 double* derivedv = nullptr;
2455 BasicStatistics(raster_, n_cells_, &derivedv, no_data_value_);
2456 stats_.at(STATS_RS_VALIDNUM) = derivedv[0];
2457 stats_.at(STATS_RS_MEAN) = derivedv[1];
2458 stats_.at(STATS_RS_MAX) = derivedv[2];
2459 stats_.at(STATS_RS_MIN) = derivedv[3];
2460 stats_.at(STATS_RS_STD) = derivedv[4];
2461 stats_.at(STATS_RS_RANGE) = derivedv[5];
2462 Release1DArray(derivedv);
2463 }
2464 stats_calculated_ = true;
2465}
2466
2467template <typename T, typename MASK_T>
2469 for (auto it = stats_2d_.begin(); it != stats_2d_.end(); ++it) {
2470 if (nullptr != it->second) {
2471 Release1DArray(it->second);
2472 }
2473 }
2474 stats_2d_.clear();
2475}
2476
2477template <typename T, typename MASK_T>
2479 if (is_2draster && stats_calculated_) ReleaseStatsMap2D();
2480 stats_calculated_ = false;
2481 CalculateStatistics();
2482}
2483
2484template <typename T, typename MASK_T>
2485double clsRasterData<T, MASK_T>::GetStatistics(string sindex, const int lyr /* = 1 */) {
2486 sindex = GetUpper(sindex);
2487 if (!ValidateRasterData() || !ValidateLayer(lyr)) {
2488 StatusMessage("No available raster statistics!");
2489 return CVT_DBL(default_value_);
2490 }
2491 if (is_2draster && nullptr != raster_2d_) {
2492 // for 2D raster data
2493 auto it = stats_2d_.find(sindex);
2494 if (it != stats_2d_.end()) {
2495 if (nullptr == it->second) {
2496 stats_calculated_ = false;
2497 CalculateStatistics();
2498 }
2499 return stats_2d_.at(sindex)[lyr - 1];
2500 }
2501 StatusMessage("WARNING: " + ValueToString(sindex) + " is not supported currently.");
2502 return CVT_DBL(default_value_);
2503 }
2504 // Else, for 1D raster data
2505 auto it = stats_.find(sindex);
2506 if (it != stats_.end()) {
2507 if (FloatEqual(it->second, CVT_DBL(NODATA_VALUE)) || !stats_calculated_) {
2508 CalculateStatistics();
2509 }
2510 return stats_.at(sindex);
2511 }
2512 StatusMessage("WARNING: " + ValueToString(sindex) + " is not supported currently.");
2513 return CVT_DBL(default_value_);
2514}
2515
2516template <typename T, typename MASK_T>
2517void clsRasterData<T, MASK_T>::GetStatistics(string sindex, int* lyrnum, double** values) {
2518 if (!is_2draster || nullptr != raster_2d_) {
2519 StatusMessage("Please initialize the raster object first.");
2520 *values = nullptr;
2521 return;
2522 }
2523 sindex = GetUpper(sindex);
2524 *lyrnum = n_lyrs_;
2525 auto it = stats_2d_.find(sindex);
2526 if (!Is2DRaster()) {
2527 *values = nullptr;
2528 return;
2529 }
2530 if (it == stats_2d_.end()) {
2531 *values = nullptr;
2532 StatusMessage("WARNING: " + ValueToString(sindex) + " is not supported currently.");
2533 return;
2534 }
2535 if (nullptr == it->second || !stats_calculated_) {
2536 CalculateStatistics();
2537 }
2538 *values = it->second;
2539}
2540
2541template <typename T, typename MASK_T>
2542int clsRasterData<T, MASK_T>::GetPosition(const int row, const int col) {
2543 if (!ValidateRasterData() || !ValidateRowCol(row, col)) {
2544 return -2; // means error occurred!
2545 }
2546 int pos_idx = GetCols() * row + col;
2547 if (!calc_pos_ || nullptr == pos_data_ || nullptr == pos_idx_) {
2548 return pos_idx;
2549 }
2550// previous low-efficiency code
2551// for (int i = 0; i < n_cells_; i++) {
2552// if (row == pos_data_[i][0] && col == pos_data_[i][1]) {
2553// return i;
2554// }
2555// }
2556 // Use binary search method, refers to https://leetcode.cn/problems/binary-search
2557 //int search(vector<int>& nums, int target) {
2558 int left = 0;
2559 int right = n_cells_ - 1; // assumes pos_idx belongs to pos_idx_[left, right]
2560 while (left <= right) { // when left==right,[left, right] still works,so use <=
2561 int middle = left + ((right - left) / 2); // equals to (left + right)/2
2562 if (pos_idx_[middle] > pos_idx) {
2563 right = middle - 1; // pos_idx belongs to [left, middle - 1]
2564 } else if (pos_idx_[middle] < pos_idx) {
2565 left = middle + 1; // pos_idx belongs to [middle + 1, right]
2566 } else { // pos_idx_[middle] == pos_idx
2567 return middle;
2568 }
2569 }
2570 return -1; // means the location of the raster data or mask data is NODATA
2571}
2572
2573template <typename T, typename MASK_T>
2574int clsRasterData<T, MASK_T>::GetPosition(const float x, const float y) {
2575 return GetPosition(CVT_DBL(x), CVT_DBL(y));
2576}
2577
2578template <typename T, typename MASK_T>
2579int clsRasterData<T, MASK_T>::GetPosition(const double x, const double y) {
2580 if (!initialized_) return -2;
2581 double xll_center = GetXllCenter();
2582 double yll_center = GetYllCenter();
2583 double dx = GetCellWidth();
2584 double dy = GetCellWidth();
2585 int n_rows = GetRows();
2586 int n_cols = GetCols();
2587
2588 if (FloatEqual(xll_center, CVT_DBL(NODATA_VALUE))
2589 || FloatEqual(yll_center, CVT_DBL(NODATA_VALUE))
2591 || n_rows < 0 || n_cols < 0) {
2592 StatusMessage("No available header information!");
2593 return -2;
2594 }
2595
2596 double x_min = xll_center - dx / 2.;
2597 double x_max = x_min + dx * n_cols;
2598 if (x > x_max || x < x_min) {
2599 return -2;
2600 }
2601
2602 double y_min = yll_center - dy / 2.;
2603 double y_max = y_min + dy * n_rows;
2604 if (y > y_max || y < y_min) {
2605 return -2;
2606 }
2607
2608 int n_row = CVT_INT((y_max - y) / dy); //calculate from ymax
2609 int n_col = CVT_INT((x - x_min) / dx); //calculate from xmin
2610
2611 return GetPosition(n_row, n_col);
2612}
2613
2614template <typename T, typename MASK_T>
2615bool clsRasterData<T, MASK_T>::GetRasterData(int* n_cells, T** data) {
2616 if (ValidateRasterData() && !is_2draster) {
2617 *n_cells = n_cells_;
2618 *data = raster_;
2619 return true;
2620 }
2621 *n_cells = -1;
2622 *data = nullptr;
2623 return false;
2624}
2625
2626template <typename T, typename MASK_T>
2627bool clsRasterData<T, MASK_T>::Get2DRasterData(int* n_cells, int* n_lyrs, T*** data) {
2628 if (ValidateRasterData() && is_2draster) {
2629 *n_cells = n_cells_;
2630 *n_lyrs = n_lyrs_;
2631 *data = raster_2d_;
2632 return true;
2633 }
2634 *n_cells = -1;
2635 *n_lyrs = -1;
2636 *data = nullptr;
2637 return false;
2638}
2639
2640template <typename T, typename MASK_T>
2641void clsRasterData<T, MASK_T>::GetRasterPositionData(int* datalength, int*** positiondata) {
2642 if (nullptr != pos_data_) {
2643 *datalength = n_cells_;
2644 *positiondata = pos_data_;
2645 } else {
2646 // reCalculate position data
2647 if (!ValidateRasterData()) {
2648 *datalength = -1;
2649 *positiondata = nullptr;
2650 return;
2651 }
2652 CalculateValidPositionsFromGridData();
2653 *datalength = n_cells_;
2654 *positiondata = pos_data_;
2655 }
2656}
2657
2658template <typename T, typename MASK_T>
2659void clsRasterData<T, MASK_T>::GetRasterPositionData(int* datalength, int** positiondata) {
2660 if (nullptr != pos_idx_) {
2661 *datalength = n_cells_;
2662 *positiondata = pos_idx_;
2663 } else {
2664 // reCalculate position data
2665 if (!ValidateRasterData()) {
2666 *datalength = -1;
2667 *positiondata = nullptr;
2668 return;
2669 }
2670 CalculateValidPositionsFromGridData();
2671 *datalength = n_cells_;
2672 *positiondata = pos_idx_;
2673 }
2674}
2675
2676template <typename T, typename MASK_T>
2678 return GetSrsString().c_str();
2679}
2680
2681template <typename T, typename MASK_T>
2683 return GetOption(HEADER_RS_SRS);
2684}
2685
2686template <typename T, typename MASK_T>
2688 if (options_.find(key) == options_.end()) {
2689 StatusMessage((string(key) + " is not existed in the options of the raster data!").c_str());
2690 return "";
2691 }
2692 return options_.at(key);
2693}
2694
2695template <typename T, typename MASK_T>
2696T clsRasterData<T, MASK_T>::GetValueByIndex(const int cell_index, const int lyr /* = 1 */) {
2697 if (!ValidateRasterData() || !ValidateIndex(cell_index) || !ValidateLayer(lyr)) {
2698 return no_data_value_;
2699 }
2700 if (is_2draster) {
2701 return raster_2d_[cell_index][lyr - 1];
2702 }
2703 return raster_[cell_index];
2704}
2705
2706template <typename T, typename MASK_T>
2707void clsRasterData<T, MASK_T>::GetValueByIndex(const int cell_index, T*& values) {
2708 if (!ValidateRasterData() || !ValidateIndex(cell_index)) {
2709 if (nullptr != values) { Release1DArray(values); }
2710 values = nullptr;
2711 return;
2712 }
2713 if (nullptr == values) {
2714 Initialize1DArray(n_lyrs_, values, no_data_value_);
2715 }
2716 if (is_2draster) {
2717 for (int i = 0; i < n_lyrs_; i++) {
2718 values[i] = raster_2d_[cell_index][i];
2719 }
2720 } else {
2721 values[0] = raster_[cell_index];
2722 }
2723}
2724
2725template <typename T, typename MASK_T>
2726T clsRasterData<T, MASK_T>::GetValue(const int row, const int col, const int lyr /* = 1 */) {
2727 if (!ValidateRasterData() || !ValidateRowCol(row, col) || !ValidateLayer(lyr)) {
2728 return no_data_value_;
2729 }
2730 // get index according to position data if possible
2731 if (calc_pos_ && (nullptr != pos_data_ || nullptr != pos_idx_)) {
2732 int valid_cell_index = GetPosition(row, col);
2733 if (valid_cell_index < 0) { return no_data_value_; }// error or NODATA
2734 return GetValueByIndex(valid_cell_index, lyr);
2735 }
2736 // get data directly from row and col
2737 if (is_2draster) { return raster_2d_[row * GetCols() + col][lyr - 1]; }
2738 return raster_[row * GetCols() + col];
2739}
2740
2741template <typename T, typename MASK_T>
2742void clsRasterData<T, MASK_T>::GetValue(const int row, const int col, T*& values) {
2743 if (!ValidateRasterData() || !ValidateRowCol(row, col)) {
2744 if (nullptr != values) { Release1DArray(values); }
2745 values = nullptr;
2746 return;
2747 }
2748 if (nullptr == values) {
2749 Initialize1DArray(n_lyrs_, values, no_data_value_);
2750 }
2751 if (calc_pos_ && (nullptr != pos_data_ || nullptr != pos_idx_)) {
2752 int valid_cell_index = GetPosition(row, col);
2753 if (valid_cell_index == -1) {
2754 for (int i = 0; i < n_lyrs_; i++) {
2755 values[i] = no_data_value_; // NODATA
2756 }
2757 } else {
2758 GetValueByIndex(valid_cell_index, values);
2759 }
2760 } else {
2761 // get data directly from row and col
2762 if (is_2draster) {
2763 for (int i = 0; i < n_lyrs_; i++) {
2764 values[i] = raster_2d_[row * GetCols() + col][i];
2765 }
2766 } else {
2767 values[0] = raster_[row * GetCols() + col];
2768 }
2769 }
2770}
2771
2772template <typename T, typename MASK_T>
2774 CopyHeader(refers, headers_);
2775 // Update header related variables
2776 auto it = headers_.find(HEADER_RS_CELLSNUM);
2777 if (it != headers_.end()) { n_cells_ = CVT_INT(it->second); }
2778 it = headers_.find(HEADER_RS_LAYERS);
2779 if (it != headers_.end()) { n_lyrs_ = CVT_INT(it->second); }
2780 it = headers_.find(HEADER_RS_NODATA);
2781 if (it != headers_.end()) { no_data_value_ = static_cast<T>(it->second); }
2782}
2783
2784
2785template <typename T, typename MASK_T>
2786void clsRasterData<T, MASK_T>::SetValue(const int row, const int col, T value, const int lyr /* = 1 */) {
2787 if (!ValidateRasterData() || !ValidateRowCol(row, col) || !ValidateLayer(lyr)) {
2788 StatusMessage("Set value failed!");
2789 return;
2790 }
2791 int idx = GetPosition(row, col);
2792 if (idx == -1) {
2793 // the origin value is NODATA, and positions of valid values are calculated
2794 StatusMessage("Current version do not support to setting value to NoDATA location!");
2795 } else {
2796 if (is_2draster) {
2797 raster_2d_[idx][lyr - 1] = value;
2798 } else {
2799 raster_[idx] = value;
2800 }
2801 }
2802}
2803
2804template <typename T, typename MASK_T>
2806 if (!ValidateRasterData()) { return false; }
2807 if (calc_pos_ && (nullptr != pos_data_ || nullptr != pos_idx_)) {
2808 // already set as True, no need to recalculate.
2809 return false;
2810 }
2811 calc_pos_ = true;
2812 return MaskAndCalculateValidPosition() >= 0;
2813}
2814
2815template <typename T, typename MASK_T>
2816bool clsRasterData<T, MASK_T>::SetPositions(int len, int** pdata) {
2817 if (nullptr != pos_data_) {
2818 if (len != n_cells_) { return false; } // cannot change origin n_cells_
2819 Release2DArray(pos_data_);
2820 }
2821 pos_data_ = pdata;
2822 calc_pos_ = true;
2823 store_pos_ = false;
2824 return true;
2825}
2826
2827template <typename T, typename MASK_T>
2828bool clsRasterData<T, MASK_T>::SetPositions(int len, int* pdata) {
2829 if (nullptr != pos_idx_) {
2830 if (len != n_cells_) { return false; } // cannot change origin n_cells_
2831 Release1DArray(pos_idx_);
2832 }
2833 pos_idx_ = pdata;
2834 calc_pos_ = true;
2835 store_pos_ = false;
2836 return true;
2837}
2838
2839template <typename T, typename MASK_T>
2841 if (!ValidateRasterData()) return false;
2842 if (nullptr == mask_) return false;
2843 if (use_mask_ext_) return false; // already set as True, no need to recalculate.
2844 use_mask_ext_ = true;
2845 return MaskAndCalculateValidPosition() >= 0;
2846}
2847
2848/************* Output to file functions ***************/
2849
2850template <typename T, typename MASK_T>
2851bool clsRasterData<T, MASK_T>::OutputToFile(const string& filename, const bool out_origin /* = true */) {
2852 if (GetPathFromFullName(filename).empty()) { return false; }
2853 string abs_filename = GetAbsolutePath(filename);
2854 if (!ValidateRasterData()) { return false; }
2855 if (!out_origin) { return OutputSubsetToFile(false, true, filename); }
2856 string filetype = GetUpper(GetSuffix(abs_filename));
2857 if (StringMatch(filetype, ASCIIExtension)) {
2858 return OutputAscFile(abs_filename);
2859 }
2860#ifdef USE_GDAL
2861 if (StringMatch(filetype, GTiffExtension)) {
2862 return OutputFileByGdal(abs_filename);
2863 }
2864 return OutputFileByGdal(ReplaceSuffix(abs_filename, GTiffExtension));
2865#else
2866 StatusMessage("Warning: Without GDAL, ASC file will be exported as default!");
2867 return OutputAscFile(ReplaceSuffix(abs_filename, ASCIIExtension));
2868#endif /* USE_GDAL */
2869}
2870
2871template <typename T, typename MASK_T>
2872bool clsRasterData<T, MASK_T>::OutputSubsetToFile(const bool out_origin /* = false */,
2873 const bool out_combined /* = true */,
2874 const string& outname /* = string() */,
2875 const map<vint, vector<double> >& recls /* map() */,
2876 const double default_value /* = NODATA_VALUE */) {
2877 if (!ValidateRasterData()) { return false; }
2878 if (subset_.empty()) { return false; }
2879 string outpathact = outname.empty() ? full_path_ : outname;
2880 // output combined subsets
2881 bool out_comb = out_combined;
2882 if (out_comb) {
2883 T* data1d = nullptr;
2884 int sublyrs;
2885 int sublen;
2886 if (!PrepareCombSubsetData(&data1d, &sublen, &sublyrs,
2887 out_origin, true, recls, default_value)) {
2888 return false;
2889 }
2890 STRDBL_MAP tmpheader;
2891 CopyHeader(headers_, tmpheader);
2892 UpdateHeader(tmpheader, HEADER_RS_LAYERS, sublyrs);
2893 UpdateHeader(tmpheader, HEADER_RS_CELLSNUM, sublen / sublyrs);
2894 bool combflag = OutputFullsizeToFiles(data1d, sublen / sublyrs, sublyrs,
2895 PrefixCoreFileName(outpathact, 0),
2896 tmpheader, options_);
2897 Release1DArray(data1d);
2898 return combflag;
2899 }
2900 STRDBL_MAP subheader;
2901 bool flag = true;
2902 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2903 if (!it->second->usable) { continue; }
2904 it->second->GetHeader(GetXllCenter(), GetYllCenter(), GetRows(),
2905 GetCellWidth(), CVT_DBL(no_data_value_), subheader);
2906 T* tmpdata1d = nullptr;
2907 int tmpdatalen;
2908 int tmplyrs;
2909 if (!PrepareSubsetData(it->first, it->second, &tmpdata1d, &tmpdatalen, &tmplyrs,
2910 out_origin, true, recls, default_value)) {
2911 continue;
2912 }
2913 UpdateHeader(subheader, HEADER_RS_LAYERS, tmplyrs);
2914 UpdateHeader(subheader, HEADER_RS_CELLSNUM, tmpdatalen / tmplyrs);
2915 flag = flag && OutputFullsizeToFiles(tmpdata1d, tmpdatalen / tmplyrs, tmplyrs,
2916 PrefixCoreFileName(outpathact, it->first),
2917 subheader, options_);
2918 Release1DArray(tmpdata1d);
2919 }
2920 return flag;
2921}
2922
2923template <typename T, typename MASK_T>
2924bool clsRasterData<T, MASK_T>::PrepareCombSubsetData(T** values, int* datalen, int* datalyrs,
2925 bool out_origin /* false */, bool include_nodata /* true */,
2926 const map<vint, vector<double> >& recls /* map() */,
2927 double default_value /* NODATA_VALUE*/) {
2928 if (subset_.empty()) { return false; }
2929 T* data1d = nullptr; // Both raster 1D and 2D data can be combined as 1D array
2930 int lyr_recls = -1;
2931 if (!recls.empty()) {
2932 for (auto it = recls.begin(); it != recls.end(); ++it) {
2933 if (lyr_recls < 0) { lyr_recls = CVT_INT(it->second.size()); }
2934 else if (lyr_recls != it->second.size()) {
2935 StatusMessage("Error: Reclassification layer count MUST be consistent!");
2936 return false;
2937 }
2938 }
2939 }
2940 int lyrs_subset = -1;
2941 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2942 if (!it->second->usable) { continue; }
2943 if (!(nullptr != it->second->data_ // Only if all subset have data_
2944 || nullptr != it->second->data2d_ // or data2d_,
2945 || !recls.empty())) { // or reclassification map specified
2946 return false;
2947 }
2948 if (lyrs_subset < 0) { lyrs_subset = it->second->n_lyrs; }
2949 else if (it->second->n_lyrs != lyrs_subset) {
2950 StatusMessage("Error: Subset's layer count MUST be consistent!");
2951 return false;
2952 }
2953 }
2954 int lyrs = -1;
2955 if (out_origin) {
2956 lyrs = n_lyrs_;
2957 if (lyr_recls > 0) { lyrs = lyr_recls; }
2958 } else {
2959 lyrs = lyrs_subset;
2960 if (lyrs < 0 && lyr_recls > 0) {
2961 lyrs = lyr_recls;
2962 }
2963 }
2964 if (lyrs < 0) {
2965 StatusMessage("Error: Cannot determine valid layer count!");
2966 return false;
2967 }
2968
2969 int gnrows = GetRows();
2970 int gncols = GetCols();
2971 if (FloatEqual(default_value, NODATA_VALUE)) {
2972 default_value = default_value_;
2973 }
2974 int gncells = include_nodata ? gnrows * gncols : n_cells_;
2975 int data_length = gncells * lyrs;
2976 Initialize1DArray(data_length, data1d, no_data_value_);
2977 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
2978 bool use_defaultv_directly = false;
2979 if (!it->second->usable) {
2980 if (!FloatEqual(no_data_value_, default_value)) {
2981 use_defaultv_directly = true;
2982 } else {
2983 continue;
2984 }
2985 }
2986 for (int vi = 0; vi < it->second->n_cells; vi++) {
2987 for (int ilyr = 0; ilyr < lyrs; ilyr++) {
2988 int gidx = it->second->global_[vi];
2989 //int tmpr = pos_data_[gidx][0];
2990 //int tmpc = pos_data_[gidx][1];
2991 //int tmprc = tmpr * gncols + tmpc;
2992 int tmprc = pos_idx_[gidx];
2993 if (!include_nodata) { tmprc = gidx; }
2994 if (!recls.empty()) { // first priority
2995 double uniqe_value = default_value;
2996 int recls_key = it->first; // default reclassification key is subset's ID
2997 if (out_origin) {
2998 if (nullptr != raster_) { recls_key = CVT_INT(raster_[gidx]); }
2999 else if (nullptr != raster_2d_) {
3000 recls_key = CVT_INT(raster_2d_[gidx][ilyr]);
3001 }
3002 }
3003 if (recls.count(recls_key) > 0 && recls.at(recls_key).size() > ilyr) {
3004 uniqe_value = recls.at(recls_key).at(ilyr);
3005 }
3006 data1d[tmprc * lyrs + ilyr] = static_cast<T>(uniqe_value);
3007 }
3008 else if (use_defaultv_directly) {
3009 data1d[tmprc * lyrs + ilyr] = static_cast<T>(default_value);
3010 }
3011 else if (!out_origin && lyrs > 1 && nullptr != it->second->data2d_) { // raster 2D
3012 data1d[tmprc * lyrs + ilyr] = static_cast<T>(it->second->data2d_[vi][ilyr]);
3013 }
3014 else if (!out_origin && lyrs == 1 && nullptr != it->second->data_) { // raster 1D
3015 data1d[tmprc * lyrs + ilyr] = static_cast<T>(it->second->data_[vi]);
3016 }
3017 else { // Will not happen
3018 StatusMessage("Error: No subset or reclassification map can be output!");
3019 if (nullptr != data1d) { Release1DArray(data1d); }
3020 return false;
3021 }
3022 }
3023 }
3024 }
3025 *values = data1d;
3026 *datalen = data_length;
3027 *datalyrs = lyrs;
3028 return true;
3029}
3030
3031template <typename T, typename MASK_T>
3032bool clsRasterData<T, MASK_T>::PrepareSubsetData(const int sub_id, SubsetPositions* sub,
3033 T** values, int* datalen, int* datalyrs,
3034 bool out_origin /* false */, bool include_nodata /* true */,
3035 const map<vint, vector<double> >& recls /* map() */,
3036 double default_value /* NODATA_VALUE*/) {
3037 if (nullptr == sub) { return false; }
3038 T* data1d = nullptr; // Both raster 1D and 2D data can be combined as 1D array
3039 int lyr_recls = -1;
3040 if (!recls.empty()) {
3041 for (auto it = recls.begin(); it != recls.end(); ++it) {
3042 if (lyr_recls < 0) { lyr_recls = CVT_INT(it->second.size()); }
3043 else if (lyr_recls != it->second.size()) {
3044 StatusMessage("Error: Reclassification layer count MUST be consistent!");
3045 return false;
3046 }
3047 }
3048 }
3049 int lyrs = - 1;
3050 if (out_origin) {
3051 lyrs = n_lyrs_;
3052 if (lyr_recls > 0) { lyrs = lyr_recls; }
3053 } else {
3054 lyrs = sub->n_lyrs;
3055 }
3056 if (lyrs < 0) {
3057 StatusMessage("Error: Cannot determine valid layer count!");
3058 return false;
3059 }
3060 int nrows = sub->g_erow - sub->g_srow + 1;
3061 int ncols = sub->g_ecol - sub->g_scol + 1;
3062 if (FloatEqual(default_value, NODATA_VALUE)) {
3063 default_value = default_value_;
3064 }
3065 int ncells = include_nodata ? nrows * ncols : sub->n_cells;
3066 int data_length = ncells * lyrs;
3067 Initialize1DArray(data_length, data1d, no_data_value_);
3068 for (int vi = 0; vi < sub->n_cells; vi++) {
3069 for (int ilyr = 0; ilyr < lyrs; ilyr++) {
3070 //int j = sub->local_pos_[vi][0] * ncols + sub->local_pos_[vi][1];
3071 int j = sub->local_posidx_[vi];
3072 int gidx = sub->global_[vi];
3073 if (!include_nodata) { j = vi; }
3074 if (!recls.empty()) { // first priority
3075 double uniqe_value = default_value;
3076 int recls_key = sub_id;
3077 if (out_origin) {
3078 if (nullptr != raster_) { recls_key = CVT_INT(raster_[gidx]); }
3079 else if (nullptr != raster_2d_) {
3080 recls_key = CVT_INT(raster_2d_[gidx][ilyr]);
3081 }
3082 }
3083 if (recls.count(recls_key) > 0 && recls.at(recls_key).size() > ilyr) {
3084 uniqe_value = recls.at(recls_key).at(ilyr);
3085 }
3086 data1d[j * lyrs + ilyr] = static_cast<T>(uniqe_value);
3087 }
3088 else if (out_origin && lyrs > 1 && nullptr != raster_2d_) {
3089 data1d[j * lyrs + ilyr] = raster_2d_[gidx][ilyr];
3090 }
3091 else if (out_origin && lyrs == 1 && nullptr != raster_) {
3092 data1d[j * lyrs + ilyr] = raster_[gidx];
3093 }
3094 else if (!out_origin && lyrs > 1 && nullptr != sub->data2d_) { // raster 2D
3095 data1d[j * lyrs + ilyr] = static_cast<T>(sub->data2d_[vi][ilyr]);
3096 }
3097 else if (!out_origin && lyrs == 1 && nullptr != sub->data_) { // raster 1D
3098 data1d[j * lyrs + ilyr] = static_cast<T>(sub->data_[vi]);
3099 }
3100 else { // Will not happen
3101 StatusMessage("Error: No subset or reclassification map can be output!");
3102 if (nullptr != data1d) { Release1DArray(data1d); }
3103 return false;
3104 }
3105 }
3106 }
3107 *values = data1d;
3108 *datalen = data_length;
3109 *datalyrs = lyrs;
3110 return true;
3111}
3112
3113template <typename T, typename MASK_T>
3114bool clsRasterData<T, MASK_T>::OutputFullsizeToFiles(T* fullsizedata, const int fsize, const int datalyrs,
3115 const string& fullfilename,
3116 const STRDBL_MAP& header, const STRING_MAP& opts) {
3117 if (nullptr == fullsizedata) { return false; }
3118 if (datalyrs < 1) { return false; }
3119 if (datalyrs == 1) {
3120 return WriteRasterToFile(fullfilename, header, opts, fullsizedata);
3121 }
3122 T* tmpdata1d = nullptr;
3123 Initialize1DArray(fsize, tmpdata1d, NODATA_VALUE);
3124 bool flag = true;
3125 for (int ilyr = 0; ilyr < datalyrs; ilyr++) {
3126 for (int gi = 0; gi < fsize; gi++) {
3127 tmpdata1d[gi] = fullsizedata[gi * datalyrs + ilyr];
3128 }
3129 flag = flag && WriteRasterToFile(AppendCoreFileName(fullfilename, ilyr + 1),
3130 header, opts, tmpdata1d);
3131 }
3132 if (nullptr != tmpdata1d) { Release1DArray(tmpdata1d); }
3133 return flag;
3134}
3135
3136template <typename T, typename MASK_T>
3137bool clsRasterData<T, MASK_T>::OutputAscFile(const string& filename) {
3138 string abs_filename = GetAbsolutePath(filename);
3139 // Is there need to calculate valid position index?
3140 int count;
3141 int** position = nullptr;
3142 int* position_idx = nullptr;
3143 bool outputdirectly = true;
3144 if ((nullptr != pos_data_ || nullptr != pos_idx_)) {
3145 GetRasterPositionData(&count, &position);
3146 GetRasterPositionData(&count, &position_idx);
3147 outputdirectly = false;
3148 assert(nullptr != position);
3149 assert(nullptr != position_idx);
3150 }
3151 // Begin to write raster data
3152 int rows = CVT_INT(headers_.at(HEADER_RS_NROWS));
3153 int cols = CVT_INT(headers_.at(HEADER_RS_NCOLS));
3154 if (is_2draster) { // 3.1 2D raster data
3155 string pre_path = GetPathFromFullName(abs_filename);
3156 if (StringMatch(pre_path, "")) { return false; }
3157 for (int lyr = 0; lyr < n_lyrs_; lyr++) {
3158 string tmpfilename = AppendCoreFileName(abs_filename, itoa(CVT_VINT(lyr)));
3159 if (!WriteAscHeaders(tmpfilename, headers_)) { return false; }
3160 std::ofstream raster_file(tmpfilename.c_str(), std::ios::app | std::ios::out);
3161 if (!raster_file.is_open()) {
3162 StatusMessage("Error opening file: " + tmpfilename);
3163 return false;
3164 }
3165 int index = 0;
3166 for (int i = 0; i < rows; ++i) {
3167 for (int j = 0; j < cols; ++j) {
3168 if (outputdirectly) {
3169 index = i * cols + j;
3170 raster_file << setprecision(6) << raster_2d_[index][lyr] << " ";
3171 continue;
3172 }
3173 if (index < n_cells_ && (position[index][0] == i && position[index][1] == j)) {
3174 raster_file << setprecision(6) << raster_2d_[index][lyr] << " ";
3175 index++;
3176 } else { raster_file << setprecision(6) << NODATA_VALUE << " "; }
3177 }
3178 raster_file << endl;
3179 }
3180 raster_file.close();
3181 }
3182 } else { // 1D raster data
3183 if (!WriteAscHeaders(abs_filename, headers_)) { return false; }
3184 std::ofstream raster_file(filename.c_str(), std::ios::app | std::ios::out);
3185 if (!raster_file.is_open()) {
3186 StatusMessage("Error opening file: " + abs_filename);
3187 return false;
3188 }
3189 int index = 0;
3190 for (int i = 0; i < rows; ++i) {
3191 for (int j = 0; j < cols; ++j) {
3192 if (outputdirectly) {
3193 index = i * cols + j;
3194 raster_file << setprecision(6) << raster_[index] << " ";
3195 continue;
3196 }
3197 if (index < n_cells_) {
3198 if (position[index][0] == i && position[index][1] == j) {
3199 raster_file << setprecision(6) << raster_[index] << " ";
3200 index++;
3201 } else { raster_file << setprecision(6) << no_data_value_ << " "; }
3202 } else { raster_file << setprecision(6) << no_data_value_ << " "; }
3203 }
3204 raster_file << endl;
3205 }
3206 raster_file.close();
3207 }
3208 position = nullptr;
3209 return true;
3210}
3211
3212#ifdef USE_GDAL
3213template <typename T, typename MASK_T>
3215 string abs_filename = GetAbsolutePath(filename);
3216 bool outputdirectly = (nullptr == pos_data_ || nullptr == pos_idx_);
3217 int n_rows = CVT_INT(headers_.at(HEADER_RS_NROWS));
3218 int n_cols = CVT_INT(headers_.at(HEADER_RS_NCOLS));
3219 bool outflag = false;
3220 T* data_1d = nullptr;
3221 if (is_2draster) {
3222 string pre_path = GetPathFromFullName(abs_filename);
3223 if (StringMatch(pre_path, "")) { return false; }
3224 for (int lyr = 0; lyr < n_lyrs_; lyr++) {
3225 string tmpfilename = AppendCoreFileName(abs_filename, lyr + 1);
3226 if (outputdirectly) {
3227 if (nullptr == data_1d) {
3228 Initialize1DArray(n_rows * n_cols, data_1d, no_data_value_);
3229 }
3230 for (int gi = 0; gi < n_rows * n_cols; gi++) {
3231 data_1d[gi] = raster_2d_[gi][lyr];
3232 }
3233 } else {
3234 if (nullptr == data_1d) {
3235 Initialize1DArray(n_rows * n_cols, data_1d, no_data_value_);
3236 }
3237 for (int vi = 0; vi < n_cells_; vi++) {
3238 //data_1d[pos_data_[vi][0] * n_cols + pos_data_[vi][1]] = raster_2d_[vi][lyr];
3239 data_1d[pos_idx_[vi]] = raster_2d_[vi][lyr];
3240 }
3241 }
3242 outflag = WriteSingleGeotiff(tmpfilename, headers_, options_, data_1d);
3243 if (!outflag) {
3244 Release1DArray(data_1d);;
3245 return false;
3246 }
3247 }
3248 Release1DArray(data_1d);
3249 } else {
3250 if (outputdirectly) {
3251 outflag = WriteSingleGeotiff(abs_filename, headers_, options_, raster_);
3252 } else {
3253 Initialize1DArray(n_rows * n_cols, data_1d, no_data_value_);
3254 for (int vi = 0; vi < n_cells_; vi++) {
3255 //data_1d[pos_data_[vi][0] * n_cols + pos_data_[vi][1]] = raster_[vi];
3256 data_1d[pos_idx_[vi]] = raster_[vi];
3257 }
3258 outflag = WriteSingleGeotiff(abs_filename, headers_, options_, data_1d);
3259 Release1DArray(data_1d);
3260 }
3261 if (!outflag) { return false; }
3262 }
3263 return true;
3264}
3265#endif /* USE_GDAL */
3266
3267#ifdef USE_MONGODB
3268template <typename T, typename MASK_T>
3269bool clsRasterData<T, MASK_T>::OutputToMongoDB(MongoGridFs* gfs, const string& filename /* = string() */,
3270 const STRING_MAP& opts /* = STRING_MAP() */,
3271 bool include_nodata /* = true */,
3272 bool out_origin /* true */) {
3273 if (nullptr == gfs) { return false; }
3274 if (!out_origin) { // Output subset's data
3275 return OutputSubsetToMongoDB(gfs, filename, opts, include_nodata, false, true);
3276 }
3277 CopyStringMap(opts, options_); // Update metadata
3278 if (options_.find(HEADER_RSOUT_DATATYPE) == options_.end()
3279 || StringMatch("Unknown", options_.at(HEADER_RSOUT_DATATYPE))) {
3282 }
3283 // Check if we can output directly: 1) pos_data_ is not NULL and include_nodata is false;
3284 // 2) pos_data_ is NULL and include_nodata is true.
3285 bool outputdirectly = true; // output directly or create new full size array
3286 int cnt;
3287 int** pos = nullptr;
3288 if ((nullptr != pos_data_ || nullptr != pos_idx_) && include_nodata) {
3289 outputdirectly = false;
3290 GetRasterPositionData(&cnt, &pos);
3291 }
3292 if ((nullptr == pos_data_ || nullptr == pos_idx_) && !include_nodata) {
3293 SetCalcPositions();
3294 GetRasterPositionData(&cnt, &pos);
3295 }
3296 int n_rows = GetRows();
3297 int n_cols = GetCols();
3298 int n_fullsize = n_rows * n_cols;
3299 if (include_nodata) {
3300 UpdateStringMap(options_, HEADER_INC_NODATA, "TRUE");
3301 } else {
3302 UpdateStringMap(options_, HEADER_INC_NODATA, "FALSE");
3303 }
3304 // 2. Get raster data
3305 T* data_1d = nullptr;
3306 T no_data_value = GetNoDataValue();
3307 int datalength;
3308 string core_name = filename.empty() ? core_name_ : filename;
3309 if (is_2draster) { // 2.1 2D raster data
3310 if (outputdirectly) {
3311 data_1d = raster_2d_[0]; // refers to Initialize2DArray() for why we can do this assignment
3312 datalength = n_lyrs_ * n_cells_; // can be n_lyrs_ * (n_rows*n_cols or valid cells' number)
3313 } else {
3314 datalength = n_lyrs_ * n_fullsize;
3315 Initialize1DArray(datalength, data_1d, no_data_value);
3316 for (int idx = 0; idx < n_cells_; idx++) {
3317 int rowcol_index = pos[idx][0] * n_cols + pos[idx][1];
3318 for (int k = 0; k < n_lyrs_; k++) {
3319 data_1d[n_lyrs_ * rowcol_index + k] = raster_2d_[idx][k];
3320 }
3321 }
3322 }
3323 } else { // 3.2 1D raster data
3324 if (outputdirectly) {
3325 data_1d = raster_;
3326 datalength = n_cells_; // can be n_rows*n_cols or valid cells' number
3327 } else {
3328 datalength = n_fullsize;
3329 Initialize1DArray(datalength, data_1d, no_data_value);
3330 for (int idx = 0; idx < n_cells_; idx++) {
3331 data_1d[pos[idx][0] * n_cols + pos[idx][1]] = raster_[idx];
3332 }
3333 }
3334 }
3335 STRDBL_MAP tmpheader;
3336 CopyHeader(headers_, tmpheader);
3337 if (include_nodata) { UpdateHeader(tmpheader, HEADER_RS_CELLSNUM, n_fullsize); }
3338 bool saved = WriteStreamDataAsGridfs(gfs, core_name, tmpheader,
3339 data_1d, datalength, options_);
3340 if (outputdirectly) {
3341 data_1d = nullptr;
3342 } else {
3343 Release1DArray(data_1d);
3344 }
3345 return saved;
3346}
3347
3348template <typename T, typename MASK_T>
3350 const string& filename /* string() */,
3351 const STRING_MAP& opts /* STRING_MAP() */,
3352 bool include_nodata /* true */,
3353 bool out_origin /* false */,
3354 bool out_combined /* true */,
3355 const map<vint, vector<double> >& recls /* map()*/,
3356 double default_value /* = NODATA_VALUE */) {
3357 if (!ValidateRasterData()) { return false; }
3358 if (nullptr == gfs) { return false; }
3359 if (subset_.empty()) { return false; }
3360 CopyStringMap(opts, options_); // Update metadata
3361 if (include_nodata) {
3362 UpdateStringMap(options_, HEADER_INC_NODATA, "TRUE");
3363 }
3364 else {
3365 UpdateStringMap(options_, HEADER_INC_NODATA, "FALSE");
3366 }
3367 if (options_.find(HEADER_RSOUT_DATATYPE) == options_.end()
3368 || StringMatch("Unknown", options_.at(HEADER_RSOUT_DATATYPE))) {
3371 }
3372
3373
3374 int grows = GetRows();
3375 string outnameact = filename.empty() ? core_name_ : filename;
3376 bool out_comb = out_combined;
3377 if (out_comb) {
3378 T* data1d = nullptr;
3379 int sublyrs;
3380 int sublen;
3381 bool flag = PrepareCombSubsetData(&data1d, &sublen, &sublyrs,
3382 out_origin, include_nodata, recls, default_value);
3383 STRDBL_MAP tmpheader;
3384 CopyHeader(headers_, tmpheader);
3385 UpdateHeader(tmpheader, HEADER_RS_LAYERS, sublyrs);
3386 UpdateHeader(tmpheader, HEADER_RS_CELLSNUM, sublen / sublyrs);
3387 flag = flag && WriteStreamDataAsGridfs(gfs, "0_" + outnameact,
3388 tmpheader, data1d, sublen, options_);
3389 Release1DArray(data1d);
3390 return flag;
3391 }
3392 // output each subset
3393 STRDBL_MAP subheader;
3394 bool flag = true;
3395 for (auto it = subset_.begin(); it != subset_.end(); ++it) {
3396 if (!it->second->usable) { continue; }
3397 it->second->GetHeader(GetXllCenter(), GetYllCenter(), grows,
3398 GetCellWidth(), CVT_DBL(no_data_value_), subheader);
3399 T* tmpdata1d = nullptr;
3400 int tmpdatalen;
3401 int tmplyrs;
3402 if (!PrepareSubsetData(it->first, it->second, &tmpdata1d, &tmpdatalen, &tmplyrs,
3403 out_origin, include_nodata, recls, default_value)) {
3404 continue;
3405 }
3406 UpdateHeader(subheader, HEADER_RS_LAYERS, tmplyrs);
3407 UpdateHeader(subheader, HEADER_RS_CELLSNUM, tmpdatalen / tmplyrs);
3408 string tmpfname = itoa(CVT_VINT(it->first)) + "_" + outnameact;
3409 flag = flag && WriteStreamDataAsGridfs(gfs, tmpfname, subheader, tmpdata1d, tmpdatalen, options_);
3410 if (nullptr != tmpdata1d) { Release1DArray(tmpdata1d); }
3411 }
3412 return true;
3413}
3414
3415#endif /* USE_MONGODB */
3416
3417/************* Read functions ***************/
3418template <typename T, typename MASK_T>
3419bool clsRasterData<T, MASK_T>::ReadFromFile(const string& filename, const bool calc_pos /* = false */,
3420 clsRasterData<MASK_T>* mask /* = nullptr */,
3421 const bool use_mask_ext /* = true */,
3422 double default_value /* NODATA_VALUE */,
3423 const STRING_MAP& opts /* = STRING_MAP() */) {
3424 if (!FileExists(filename)) { return false; }
3425 if (!initialized_) { InitializeRasterClass(); }
3426 rs_type_out_ = RasterDataTypeInOptionals(opts);
3427 return ConstructFromSingleFile(filename, calc_pos, mask, use_mask_ext, default_value, opts);
3428}
3429
3430template <typename T, typename MASK_T>
3431bool clsRasterData<T, MASK_T>::ReadFromFiles(vector<string>& filenames, const bool calc_pos /* = false */,
3432 clsRasterData<MASK_T>* mask /* = nullptr */,
3433 const bool use_mask_ext /* = true */,
3434 double default_value /* NODATA_VALUE */,
3435 const STRING_MAP& opts /* = STRING_MAP() */) {
3436 if (!FilesExist(filenames)) { return false; }
3437 n_lyrs_ = CVT_INT(filenames.size());
3438 if (n_lyrs_ == 1) { return ReadFromFile(filenames[0], calc_pos, mask, use_mask_ext, default_value, opts); }
3439 if (!initialized_) { InitializeRasterClass(true); }
3440 rs_type_out_ = RasterDataTypeInOptionals(opts);
3441 // 1. firstly, take the first layer as the main input, to calculate position index or extract by mask.
3442 if (!ConstructFromSingleFile(filenames[0], calc_pos, mask, use_mask_ext, default_value, opts)) {
3443 return false;
3444 }
3445 // 2. change corename and filepath template which format is: `<file dir>/CoreName_%d.<suffix>`
3446 // support "corename.tif or corename_1.tif", "corename_2.tif", and "corename_3.tif", etc.
3447 string::size_type last_underline = core_name_.find_last_of('_');
3448 if (last_underline == string::npos) {
3449 last_underline = core_name_.length();
3450 }
3451 core_name_ = core_name_.substr(0, last_underline);
3452 full_path_ = GetPathFromFullName(filenames[0]) + core_name_ + "_%d." + GetSuffix(filenames[0]);
3453 // 3. initialize raster_2d_ and read the other layers according to position data if stated,
3454 // or just read by row and col
3455 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_, no_data_value_);
3456#pragma omp parallel for
3457 for (int i = 0; i < n_cells_; i++) {
3458 raster_2d_[i][0] = raster_[i];
3459 }
3460 Release1DArray(raster_);
3461 int rows = GetRows();
3462 int cols = GetCols();
3463 // take the first layer as mask, and use_mask_ext is true, and no need to calculate position data
3464 for (int fileidx = 1; fileidx < CVT_INT(filenames.size()); fileidx++) {
3465 STRDBL_MAP tmpheader;
3466 T* tmplyrdata = nullptr;
3467 string curfilename = filenames[fileidx];
3468 if (StringMatch(GetUpper(GetSuffix(curfilename)), string(ASCIIExtension))) {
3469 ReadAscFile(curfilename, tmpheader, tmplyrdata);
3470 }
3471 else {
3472#ifdef USE_GDAL
3473 RasterDataType tmpintype;
3474 string tmpsrs;
3475 ReadRasterFileByGdal(curfilename, tmpheader, tmplyrdata, tmpintype, tmpsrs);
3476#else
3477 StatusMessage("Warning: Only ASC format is supported without GDAL!");
3478 return false;
3479#endif
3480 }
3481 if (nullptr != pos_data_ || nullptr != pos_idx_) {
3482#pragma omp parallel for
3483 for (int i = 0; i < n_cells_; ++i) {
3484 //int tmp_row = pos_data_[i][0]; // row * ncols + col,
3485 //int tmp_col = pos_data_[i][1];
3486 int tmp_row = pos_idx_[i] / cols;
3487 int tmp_col = pos_idx_[i] % cols;
3488 AddOtherLayerRasterData(tmp_row, tmp_col, i, fileidx, tmpheader, tmplyrdata);
3489 }
3490 }
3491 else {
3492#pragma omp parallel for
3493 for (int i = 0; i < rows; i++) {
3494 for (int j = 0; j < cols; j++) {
3495 int cellidx = i * cols + j;
3496 if (FloatEqual(no_data_value_, raster_2d_[cellidx][0])) {
3497 raster_2d_[cellidx][fileidx] = no_data_value_;
3498 continue;
3499 }
3500 AddOtherLayerRasterData(i, j, cellidx, fileidx, tmpheader, tmplyrdata);
3501 }
3502 }
3503 }
3504 Release1DArray(tmplyrdata);
3505 }
3506 if(!is_2draster) is_2draster = true;
3507 UpdateHeader(headers_, HEADER_RS_LAYERS, n_lyrs_); // repair layers count in headers
3508 return true;
3509}
3510
3511#ifdef USE_MONGODB
3512
3513template <typename T, typename MASK_T>
3515 const string& filename,
3516 const bool calc_pos /* = false */,
3517 clsRasterData<MASK_T>* mask /* = nullptr */,
3518 const bool use_mask_ext /* = true */,
3519 double default_value /* NODATA_VALUE */,
3520 const STRING_MAP& opts /* = STRING_MAP() */) {
3521 InitializeReadFunction(filename, calc_pos, mask, use_mask_ext, default_value, opts);
3522 T* dbdata = nullptr;
3523 STRDBL_MAP header_dbl = InitialHeader();
3524 STRING_MAP header_str = InitialStrHeader();
3525 STRING_MAP opts_upd;
3526 CopyStringMap(opts, opts_upd);
3527 if (opts.empty() || opts.count(HEADER_INC_NODATA) < 1) { // GFS file include nodata by default
3528 UpdateStringMap(opts_upd, HEADER_INC_NODATA, "TRUE");
3529 }
3530 if (!ReadGridFsFile(gfs, filename, dbdata, header_dbl, header_str, opts_upd)) { return false; }
3531
3532 if (headers_.at(HEADER_RS_NROWS) > 0 && headers_.at(HEADER_RS_NCOLS) > 0
3533 && headers_.at(HEADER_RS_LAYERS) > 0 && headers_.at(HEADER_RS_CELLSNUM) > 0) {
3534 // means the raster is preassigned header information, and this function is used for read data only
3535 if (!FloatEqual(headers_.at(HEADER_RS_NROWS), header_dbl.at(HEADER_RS_NROWS))
3536 || !FloatEqual(headers_.at(HEADER_RS_NCOLS), header_dbl.at(HEADER_RS_NCOLS))
3537 || !FloatEqual(headers_.at(HEADER_RS_LAYERS), header_dbl.at(HEADER_RS_LAYERS))
3538 || !FloatEqual(headers_.at(HEADER_RS_CELLSNUM), header_dbl.at(HEADER_RS_CELLSNUM))) {
3539 Release1DArray(dbdata);
3540 return false;
3541 }
3542 } else {
3543 CopyHeader(header_dbl, headers_);
3544 }
3545 CopyStringMap(header_str, options_);
3546
3547 bool include_nodata = !StringMatch(options_.at(HEADER_INC_NODATA), "FALSE");
3548
3549 int n_rows = CVT_INT(headers_.at(HEADER_RS_NROWS));
3550 int n_cols = CVT_INT(headers_.at(HEADER_RS_NCOLS));
3551 n_lyrs_ = CVT_INT(headers_.at(HEADER_RS_LAYERS));
3552 // if (n_rows < 0 || n_cols < 0 || n_lyrs_ < 0) { return false; } // Needless
3553 int fullsize = n_rows * n_cols;
3554 no_data_value_ = static_cast<T>(headers_.at(HEADER_RS_NODATA));
3555 n_cells_ = CVT_INT(headers_.at(HEADER_RS_CELLSNUM));
3556
3557 if (include_nodata && n_cells_ != fullsize) { return false; }
3558 if (n_cells_ != fullsize) { calc_pos_ = true; }
3559
3560 // check the valid values count and determine whether we can read directly.
3561 bool mask_pos_subset = true;
3562 if (nullptr != mask_ && calc_pos_ && use_mask_ext_ && n_cells_ == mask_->GetValidNumber()) {
3563 store_pos_ = false;
3564 mask_->GetRasterPositionData(&n_cells_, &pos_data_);
3565 mask_->GetRasterPositionData(&n_cells_, &pos_idx_);
3566 if (!mask->GetSubset().empty()) {
3567 map<int, SubsetPositions*>& mask_subset = mask_->GetSubset();
3568 for (auto it = mask_subset.begin(); it != mask_subset.end(); ++it) {
3569 SubsetPositions* tmp = new SubsetPositions(it->second, true);
3570 tmp->n_lyrs = n_lyrs_;
3571#ifdef HAS_VARIADIC_TEMPLATES
3572 subset_.emplace(it->first, tmp);
3573#else
3574 subset_.insert(make_pair(it->first, tmp));
3575#endif
3576 }
3577 }
3578 mask_pos_subset = false;
3579 }
3580
3581 if (!include_nodata && (nullptr == pos_data_ || nullptr == pos_idx_)) { return false; }
3582
3583 if (n_lyrs_ == 1) {
3584 is_2draster = false;
3585 if (include_nodata && !mask_pos_subset) {
3586 Initialize1DArray(n_cells_, raster_, no_data_value_);
3587#pragma omp parallel for
3588 for (int i = 0; i < n_cells_; i++) {
3589 //int tmpidx = pos_data_[i][0] * n_cols + pos_data_[i][1];
3590 int tmpidx = pos_idx_[i];
3591 raster_[i] = static_cast<T>(dbdata[tmpidx]);
3592 }
3593 Release1DArray(dbdata);
3594 } else {
3595 raster_ = dbdata;
3596 }
3597 } else {
3598 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_, no_data_value_);
3599#pragma omp parallel for
3600 for (int i = 0; i < n_cells_; i++) {
3601 int tmpidx = i;
3602 if (include_nodata && !mask_pos_subset) {
3603 //tmpidx = pos_data_[i][0] * n_cols + pos_data_[i][1];
3604 tmpidx = pos_idx_[i];
3605 }
3606 for (int j = 0; j < n_lyrs_; j++) {
3607 int idx = tmpidx * n_lyrs_ + j;
3608 raster_2d_[i][j] = dbdata[idx];
3609 }
3610 }
3611 is_2draster = true;
3612 Release1DArray(dbdata);
3613 }
3614 CheckDefaultValue();
3615 if (include_nodata && mask_pos_subset) {
3616 return MaskAndCalculateValidPosition() >= 0;
3617 }
3618 return true;
3619}
3620
3621#endif /* USE_MONGODB */
3622
3623template <typename T, typename MASK_T>
3624void clsRasterData<T, MASK_T>::AddOtherLayerRasterData(const int row, const int col,
3625 const int cellidx, const int lyr,
3626 STRDBL_MAP lyrheader, T* lyrdata) {
3627 int tmpcols = CVT_INT(lyrheader.at(HEADER_RS_NCOLS));
3628 double tmpnodata = lyrheader.at(HEADER_RS_NODATA);
3629 XY_COOR tmp_xy = GetCoordinateByRowCol(row, col);
3630 // get current raster layer's value by XY
3631 ROW_COL tmp_pos = GetPositionByCoordinate(tmp_xy.first, tmp_xy.second, &lyrheader);
3632 if (tmp_pos.first == -1 || tmp_pos.second == -1) {
3633 raster_2d_[cellidx][lyr] = no_data_value_;
3634 } else {
3635 T tmpvalue = lyrdata[tmp_pos.first * tmpcols + tmp_pos.second];
3636 raster_2d_[cellidx][lyr] = FloatEqual(tmpvalue, tmpnodata) ? no_data_value_ : tmpvalue;
3637 }
3638}
3639
3640template <typename T, typename MASK_T>
3642 InitializeRasterClass();
3643 Copy(another);
3644}
3645
3646template <typename T, typename MASK_T>
3648 // Release current data
3649 if (is_2draster && nullptr != raster_2d_ && n_cells_ > 0) {
3650 Release2DArray(raster_2d_);
3651 }
3652 if (!is_2draster && nullptr != raster_) {
3653 Release1DArray(raster_);
3654 }
3655 if (nullptr != pos_data_) {
3656 Release2DArray(pos_data_);
3657 }
3658 if (nullptr != pos_idx_) {
3659 Release1DArray(pos_idx_);
3660 }
3661 if (stats_calculated_) {
3662 ReleaseStatsMap2D();
3663 stats_calculated_ = false;
3664 }
3665 if (!subset_.empty()) {
3666 ReleaseSubset();
3667 }
3668 // Initialize now Raster and copy data
3669 InitializeReadFunction(orgraster->GetFilePath(), orgraster->PositionsCalculated(),
3670 orgraster->GetMask(), orgraster->MaskExtented(),
3671 orgraster->GetDefaultValue(), orgraster->GetOptions());
3672 n_cells_ = orgraster->GetCellNumber();
3673 n_lyrs_ = orgraster->GetLayers();
3674 rs_type_ = orgraster->GetDataType();
3675 rs_type_out_ = orgraster->GetOutDataType();
3676 no_data_value_ = orgraster->GetNoDataValue();
3677 if (orgraster->Is2DRaster()) {
3678 is_2draster = true;
3679 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_,
3680 orgraster->Get2DRasterDataPointer());
3681 } else {
3682 Initialize1DArray(n_cells_, raster_, orgraster->GetRasterDataPointer());
3683 }
3684 if (calc_pos_) {
3685 store_pos_ = true;
3686 Initialize2DArray(n_cells_, 2, pos_data_, orgraster->GetRasterPositionDataPointer());
3687 Initialize1DArray(n_cells_, pos_idx_, orgraster->GetRasterPositionIndexPointer());
3688 }
3689 stats_calculated_ = orgraster->StatisticsCalculated();
3690 if (stats_calculated_) {
3691 if (is_2draster) {
3692 map<string, double *> stats2D = orgraster->GetStatistics2D();
3693 for (auto iter = stats2D.begin(); iter != stats2D.end(); ++iter) {
3694 double* tmpstatvalues = nullptr;
3695 Initialize1DArray(n_lyrs_, tmpstatvalues, iter->second);
3696 stats_2d_.at(iter->first) = tmpstatvalues;
3697 }
3698 } else {
3699 STRDBL_MAP stats = orgraster->GetStatistics();
3700 for (auto iter = stats.begin(); iter != stats.end(); ++iter) {
3701 stats_[iter->first] = iter->second;
3702 }
3703 }
3704 }
3705 CopyHeader(orgraster->GetRasterHeader(), headers_);
3706 // deep copy subset
3707 if (!orgraster->GetSubset().empty()) {
3708 for (auto it = orgraster->GetSubset().begin(); it != orgraster->GetSubset().end(); ++it) {
3709 SubsetPositions* tmp = new SubsetPositions(it->second, true);
3710#ifdef HAS_VARIADIC_TEMPLATES
3711 subset_.emplace(it->first, tmp);
3712#else
3713 subset_.insert(make_pair(it->first, tmp));
3714#endif
3715 }
3716 }
3717}
3718
3719template <typename T, typename MASK_T>
3721#pragma omp parallel for
3722 for (int i = 0; i < n_cells_; i++) {
3723 for (int lyr = 0; lyr < n_lyrs_; lyr++) {
3724 bool flag = is_2draster && nullptr != raster_2d_
3725 ? FloatEqual(raster_2d_[i][lyr], no_data_value_)
3726 : FloatEqual(raster_[i], no_data_value_);
3727 if (!flag) { continue; }
3728 if (is_2draster && nullptr != raster_2d_) {
3729 raster_2d_[i][lyr] = replacedv;
3730 } else if (nullptr != raster_) {
3731 raster_[i] = replacedv;
3732 }
3733 }
3734 }
3735 no_data_value_ = replacedv;
3736 default_value_ = CVT_DBL(replacedv);
3737 UpdateHeader(headers_, HEADER_RS_NODATA, replacedv);
3738}
3739
3740template <typename T, typename MASK_T>
3741void clsRasterData<T, MASK_T>::Reclassify(const map<int, T> reclass_map) {
3742 map<int, T> recls;
3743 for(auto it = reclass_map.begin(); it != reclass_map.end(); ++it) {
3744#ifdef HAS_VARIADIC_TEMPLATES
3745 recls.emplace(it->first, it->second);
3746#else
3747 recls.insert(make_pair(it->first, it->second));
3748#endif
3749 }
3750 for (int i = 0; i < n_cells_; i++) {
3751 for (int lyr = 0; lyr < n_lyrs_; lyr++) {
3752 T curv = is_2draster && nullptr != raster_2d_
3753 ? CVT_INT(raster_2d_[i][lyr])
3754 : CVT_INT(raster_[i]);
3755 if (recls.count(curv) < 0) {
3756#ifdef HAS_VARIADIC_TEMPLATES
3757 recls.emplace(curv, no_data_value_);
3758#else
3759 recls.insert(make_pair(curv, no_data_value_));
3760#endif
3761 }
3762 if (is_2draster && nullptr != raster_2d_) {
3763 raster_2d_[i][lyr] = recls.at(curv);
3764 } else if (nullptr != raster_) {
3765 raster_[i] = recls.at(curv);
3766 }
3767 }
3768 }
3769}
3770
3771/************* Utility functions ***************/
3772
3773template <typename T, typename MASK_T>
3775 return XY_COOR(GetXllCenter() + col * GetCellWidth(),
3776 GetYllCenter() + (GetRows() - row - 1) * GetCellWidth());
3777}
3778
3779template <typename T, typename MASK_T>
3781 STRDBL_MAP* header /* = nullptr */) {
3782 if (nullptr == header) { header = &headers_; }
3783 double xll_center = (*header).at(HEADER_RS_XLL);
3784 double yll_center = (*header).at(HEADER_RS_YLL);
3785 double dx = (*header).at(HEADER_RS_CELLSIZE);
3786 double dy = dx;
3787 int n_rows = CVT_INT((*header).at(HEADER_RS_NROWS));
3788 int n_cols = CVT_INT((*header).at(HEADER_RS_NCOLS));
3789
3790 double x_min = xll_center - dx / 2.;
3791 double x_max = x_min + dx * n_cols;
3792
3793 double y_min = yll_center - dy / 2.;
3794 double y_max = y_min + dy * n_rows;
3795 if ((x > x_max || x < xll_center) || (y > y_max || y < yll_center)) {
3796 return ROW_COL(-1, -1);
3797 }
3798 return ROW_COL(CVT_INT((y_max - y) / dy), CVT_INT((x - x_min) / dx));
3799}
3800
3801template <typename T, typename MASK_T>
3803 vector<T> values; // store 1st layer for both Rater1D and Raster2D
3804 vector<vector<T> > values_2d; // store layer 2~n
3805 vector<int> pos_rows;
3806 vector<int> pos_cols;
3807 int nrows = CVT_INT(headers_.at(HEADER_RS_NROWS));
3808 int ncols = CVT_INT(headers_.at(HEADER_RS_NCOLS));
3809 // get all valid values (i.e., exclude NODATA_VALUE)
3810 for (int i = 0; i < nrows; ++i) {
3811 for (int j = 0; j < ncols; ++j) {
3812 int idx = i * ncols + j;
3813 T tmp_value;
3814 if (is_2draster) {
3815 tmp_value = raster_2d_[idx][0];
3816 } else {
3817 tmp_value = raster_[idx];
3818 }
3819 if (FloatEqual(tmp_value, static_cast<T>(no_data_value_))) continue;
3820 values.emplace_back(tmp_value);
3821 if (is_2draster && n_lyrs_ > 1) {
3822 vector<T> tmpv(n_lyrs_ - 1);
3823 for (int lyr = 1; lyr < n_lyrs_; lyr++) {
3824 tmpv[lyr - 1] = raster_2d_[idx][lyr];
3825 }
3826 values_2d.emplace_back(tmpv);
3827 }
3828 pos_rows.emplace_back(i);
3829 pos_cols.emplace_back(j);
3830 }
3831 }
3832 vector<T>(values).swap(values);
3833 if (is_2draster && n_lyrs_ > 1) {
3834 vector<vector<T> >(values_2d).swap(values_2d);
3835 }
3836 vector<int>(pos_rows).swap(pos_rows);
3837 vector<int>(pos_cols).swap(pos_cols);
3838 // reCreate raster data array
3839 n_cells_ = CVT_INT(values.size());
3840 UpdateHeader(headers_, HEADER_RS_CELLSNUM, n_cells_);
3841 if (is_2draster) {
3842 Release2DArray(raster_2d_);
3843 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_, no_data_value_);
3844 } else {
3845 Release1DArray(raster_);
3846 Initialize1DArray(n_cells_, raster_, no_data_value_);
3847 }
3848 // pos_data_ is nullptr till now.
3849 Initialize2DArray(n_cells_, 2, pos_data_, 0);
3850 Initialize1DArray(n_cells_, pos_idx_, 0);
3851 store_pos_ = true;
3852#pragma omp parallel for
3853 for (int i = 0; i < n_cells_; ++i) {
3854 if (is_2draster) {
3855 raster_2d_[i][0] = values.at(i);
3856 if (n_lyrs_ > 1) {
3857 for (int lyr = 1; lyr < n_lyrs_; lyr++) {
3858 raster_2d_[i][lyr] = values_2d[i][lyr - 1];
3859 }
3860 }
3861 } else {
3862 raster_[i] = values.at(i);
3863 }
3864 pos_data_[i][0] = pos_rows.at(i);
3865 pos_data_[i][1] = pos_cols.at(i);
3866 pos_idx_[i] = pos_rows.at(i) * ncols + pos_cols.at(i);
3867 }
3868 calc_pos_ = true;
3869}
3870
3871template <typename T, typename MASK_T>
3872int clsRasterData<T, MASK_T>::MaskAndCalculateValidPosition() {
3873 int old_fullsize = GetRows() * GetCols();
3874 if (nullptr == mask_) {
3875 if (calc_pos_) {
3876 if (nullptr == pos_data_ || nullptr == pos_idx_) {
3877 CalculateValidPositionsFromGridData();
3878 return 1;
3879 }
3880 return 0;
3881 }
3882 n_cells_ = old_fullsize;
3883 UpdateHeader(headers_, HEADER_RS_CELLSNUM, n_cells_);
3884 // do nothing
3885 return 0;
3886 }
3887 // Use mask data
3888 // 1. Get new values, positions, and subsets (if exist) according to Mask's position data
3889 int mask_ncells;
3890 int** valid_pos = nullptr;
3891 int mask_rows = mask_->GetRows();
3892 int mask_cols = mask_->GetCols();
3893 // Get the position data from mask
3894 if (!mask_->PositionsCalculated()) { mask_->SetCalcPositions(); }
3895 mask_->GetRasterPositionData(&mask_ncells, &valid_pos);
3896 // Masked raster data have the same size with mask's valid positions
3897 vector<T> values(mask_ncells); // store layer 1 data
3898 vector<vector<T> > values_2d(mask_ncells); // store layer 2~n data (excluding the first layer)
3899 vector<int> pos_rows(mask_ncells); // position rows in mask
3900 vector<int> pos_cols(mask_ncells); // position cols in mask
3901 // calculate the intersection extent between mask and the raster data
3902 int max_row = -1;
3903 int min_row = mask_rows;
3904 int max_col = -1;
3905 int min_col = mask_cols;
3906 int masked_count = 0; // position matched count
3907 int matched_count = 0; // valid value matched count
3908 // Get the valid data according to coordinate
3909 for (int i = 0; i < mask_ncells; i++) {
3910 int tmp_row = valid_pos[i][0];
3911 int tmp_col = valid_pos[i][1];
3912 XY_COOR tmp_xy = mask_->GetCoordinateByRowCol(tmp_row, tmp_col);
3913 ROW_COL tmp_pos = GetPositionByCoordinate(tmp_xy.first, tmp_xy.second);
3914 T tmp_value;
3915 if (tmp_pos.first == -1 || tmp_pos.second == -1) {
3916 tmp_value = no_data_value_; // location exceeds the extent of raster data
3917 if (is_2draster && n_lyrs_ > 1) {
3918 vector<T> tmp_values(n_lyrs_ - 1);
3919 for (int lyr = 1; lyr < n_lyrs_; lyr++) { tmp_values[lyr - 1] = no_data_value_; }
3920 values_2d[i] = tmp_values;
3921 }
3922 values[i] = tmp_value;
3923 pos_rows[i] = tmp_row;
3924 pos_cols[i] = tmp_col;
3925 continue;
3926 }
3927 tmp_value = GetValue(tmp_pos.first, tmp_pos.second, 1);
3928 if (FloatEqual(tmp_value, no_data_value_)) {
3929 if (!FloatEqual(default_value_, no_data_value_)) {
3930 tmp_value = static_cast<T>(default_value_);
3931 SetValue(tmp_pos.first, tmp_pos.second, tmp_value);
3932 }
3933 } else { // the intersect extents dependent on the valid raster values
3934 matched_count++;
3935 if (max_row < tmp_row) max_row = tmp_row;
3936 if (min_row > tmp_row) min_row = tmp_row;
3937 if (max_col < tmp_col) max_col = tmp_col;
3938 if (min_col > tmp_col) min_col = tmp_col;
3939 }
3940 if (is_2draster && n_lyrs_ > 1) {
3941 vector<T> tmp_values(n_lyrs_ - 1);
3942 for (int lyr = 1; lyr < n_lyrs_; lyr++) {
3943 tmp_values[lyr - 1] = GetValue(tmp_pos.first, tmp_pos.second, lyr + 1);
3944 if (FloatEqual(tmp_values[lyr - 1], no_data_value_)
3945 && !FloatEqual(default_value_, no_data_value_)) {
3946 tmp_values[lyr - 1] = static_cast<T>(default_value_);
3947 SetValue(tmp_pos.first, tmp_pos.second, tmp_values[lyr - 1], lyr - 1);
3948 }
3949 }
3950 values_2d[i] = tmp_values;
3951 }
3952 values[i] = tmp_value;
3953 pos_rows[i] = tmp_row;
3954 pos_cols[i] = tmp_col;
3955 masked_count++;
3956 }
3957 if (masked_count == 0) { return -1; }
3958 n_cells_ = masked_count;
3959
3960 // Priority Copy header of mask data, and update NoData, SRS, and Layers' count
3961 CopyHeader(mask_->GetRasterHeader(), headers_);
3962 UpdateHeader(headers_, HEADER_RS_NODATA, no_data_value_);
3963 UpdateStrHeader(options_, HEADER_RS_SRS, mask_->GetSrsString());
3964 UpdateHeader(headers_, HEADER_RS_LAYERS, n_lyrs_);
3965
3966 // Priority DEEP Copy subset of mask data
3967 map<int, SubsetPositions*>& mask_subset = mask_->GetSubset();
3968 bool mask_has_subset = !mask_subset.empty(); // if mask data has subsets
3969 if (mask_has_subset) {
3970 ReleaseSubset();
3971 for (auto it = mask_subset.begin(); it != mask_subset.end(); ++it) {
3972 SubsetPositions* tmp = new SubsetPositions(it->second, true);
3973 tmp->n_lyrs = n_lyrs_;
3974#ifdef HAS_VARIADIC_TEMPLATES
3975 subset_.emplace(it->first, tmp);
3976#else
3977 subset_.insert(make_pair(it->first, tmp));
3978#endif
3979 }
3980 }
3981
3982 // Set several flags
3983 // Flag 1: If masked cells' count equals valid positions' count of the mask layer
3984 bool match_exactly = matched_count == mask_ncells;
3985 // Flag2 : Is the valid grid extent same as the mask data, which means the mask
3986 // is within the extent of the raster data
3987 bool within_ext = true;
3988 int new_rows = max_row - min_row + 1;
3989 int new_cols = max_col - min_col + 1;
3990 if (new_rows != mask_rows || new_cols != mask_cols) {
3991 within_ext = false;
3992 } else { // within_ext is true means
3993 // masked cells' count equals valid positions' count of the mask layer
3994 assert(masked_count == mask_ncells);
3995 }
3996 bool upd_header_rowcol = false; // need to update row and col counts in header info?
3997 bool recalc_pos = false; // need to recalculate valid positions? If true, set mask to nullptr!
3998 bool upd_header_valid_num = false; // need to update valid cell count in header info?
3999 bool store_fullsize = false; // need to store full size raster data after masked?
4000 bool recalc_subset = false; // need to recalculate subset? TODO, need more unittests
4001
4002 // Although this if-then may redundancy, I think this still necessary for clearly thinking.
4003 if (within_ext) {
4004 upd_header_rowcol = false;
4005 if (use_mask_ext_) { // use_mask_ext_ has the highest priority
4006 if (calc_pos_) {
4007 recalc_pos = !match_exactly;
4008 upd_header_valid_num = recalc_pos;
4009 store_fullsize = false;
4010 //recalc_subset = mask_has_subset && !match_exactly;
4011 } else { // calc_pos_ = false
4012 recalc_pos = false;
4013 upd_header_valid_num = false;
4014 store_fullsize = false;
4015 calc_pos_ = true; // use_mask_ext_ is priority
4016 //recalc_subset = mask_has_subset && !match_exactly;
4017 }
4018 } else { // use_mask_ext_ is false
4019 if (calc_pos_) {
4020 recalc_pos = !match_exactly;
4021 upd_header_valid_num = recalc_pos;
4022 store_fullsize = false;
4023 //recalc_subset = mask_has_subset && !match_exactly;
4024 } else { // calc_pos_ = false
4025 recalc_pos = false;
4026 upd_header_valid_num = true;
4027 store_fullsize = false;
4028 calc_pos_ = true; // use_mask_ext_ is priority
4029 //recalc_subset = mask_has_subset && !match_exactly;
4030 }
4031 }
4032 } else { // within_ext is false
4033 if (use_mask_ext_) { // use_mask_ext_ has the highest priority
4034 upd_header_rowcol = false;
4035 if (calc_pos_) {
4036 recalc_pos = !match_exactly;
4037 upd_header_valid_num = recalc_pos;
4038 store_fullsize = false;
4039 //recalc_subset = mask_has_subset && !match_exactly;
4040 } else { // calc_pos_ = false
4041 recalc_pos = false;
4042 upd_header_valid_num = false;
4043 store_fullsize = false;
4044 calc_pos_ = true; // use_mask_ext_ is priority
4045 //recalc_subset = mask_has_subset && !match_exactly;
4046 }
4047 } else { // use_mask_ext_ is false
4048 upd_header_rowcol = true;
4049 upd_header_valid_num = true;
4050 if (calc_pos_) {
4051 recalc_pos = true;
4052 store_fullsize = false;
4053 //recalc_subset = mask_has_subset && !match_exactly;
4054 } else { // calc_pos_ = false
4055 recalc_pos = false;
4056 store_fullsize = true;
4057 //recalc_subset = mask_has_subset && !match_exactly;
4058 }
4059 }
4060 }
4061 if (mask_has_subset && !match_exactly && upd_header_rowcol) {
4062 recalc_subset = true;
4063 }
4064 // Update row and col counts in header information firstly.
4065 if (upd_header_rowcol) {
4066 UpdateHeader(headers_, HEADER_RS_NROWS, new_rows);
4067 UpdateHeader(headers_, HEADER_RS_NCOLS, new_cols);
4068 headers_.at(HEADER_RS_XLL) += min_col * mask_->GetCellWidth();
4069 headers_.at(HEADER_RS_YLL) += (mask_rows - max_row - 1) * mask_->GetCellWidth();
4070 headers_.at(HEADER_RS_CELLSIZE) = mask_->GetCellWidth();
4071 }
4072
4073 // ReCalculate valid position
4074 if (recalc_pos) {
4075 // clean redundant values (i.e., NODATA)
4076 auto rit = pos_rows.begin();
4077 auto cit = pos_cols.begin();
4078 auto vit = values.begin();
4079 auto data2dit = values_2d.begin();
4080 for (auto it = values.begin(); it != values.end();) {
4081 size_t idx = distance(vit, it);
4082 int tmpr = pos_rows.at(idx);
4083 int tmpc = pos_cols.at(idx);
4084 if (tmpr > max_row || tmpr < min_row || tmpc > max_col || tmpc < min_col
4085 || FloatEqual(static_cast<T>(*it), no_data_value_)) {
4086 it = values.erase(it);
4087 if (is_2draster && n_lyrs_ > 1) {
4088 values_2d.erase(data2dit + idx);
4089 data2dit = values_2d.begin();
4090 }
4091 pos_cols.erase(cit + idx);
4092 pos_rows.erase(rit + idx);
4093 rit = pos_rows.begin(); // reset the iterators
4094 cit = pos_cols.begin();
4095 vit = values.begin();
4096 } else {
4097 pos_rows[idx] -= min_row; // get new column and row number
4098 pos_cols[idx] -= min_col;
4099 ++it;
4100 }
4101 }
4102 vector<T>(values).swap(values);
4103 if (is_2draster && n_lyrs_ > 1) { vector<vector<T> >(values_2d).swap(values_2d); }
4104 vector<int>(pos_rows).swap(pos_rows);
4105 vector<int>(pos_cols).swap(pos_cols);
4106
4107 store_pos_ = true;
4108 n_cells_ = CVT_INT(values.size());
4109 if (nullptr != pos_data_) { Release2DArray(pos_data_); }
4110 if (nullptr != pos_idx_) { Release1DArray(pos_idx_); }
4111 Initialize2DArray(n_cells_, 2, pos_data_, 0);
4112 Initialize1DArray(n_cells_, pos_idx_, 0);
4113 for (size_t k = 0; k < pos_rows.size(); ++k) {
4114 pos_data_[k][0] = pos_rows.at(k);
4115 pos_data_[k][1] = pos_cols.at(k);
4116 if (upd_header_rowcol) {
4117 pos_idx_[k] = pos_rows.at(k) * new_cols + pos_cols.at(k);
4118 } else {
4119 pos_idx_[k] = pos_rows.at(k) * mask_cols + pos_cols.at(k);
4120 }
4121 }
4122 } else {
4123 if (nullptr != pos_data_) { Release2DArray(pos_data_); }
4124 if (nullptr != pos_idx_) { Release1DArray(pos_idx_); }
4125 if (calc_pos_) {
4126 mask_->GetRasterPositionData(&n_cells_, &pos_data_);
4127 mask_->GetRasterPositionData(&n_cells_, &pos_idx_);
4128 }
4129 store_pos_ = false;
4130 }
4131
4132 // Release the original raster values, and create new
4133 // raster array and positions data array (if necessary)
4134 assert(ValidateRasterData());
4135 int ncols = CVT_INT(headers_.at(HEADER_RS_NCOLS));
4136 int nrows = CVT_INT(headers_.at(HEADER_RS_NROWS));
4137 if (store_fullsize) {
4138 n_cells_ = ncols * nrows;
4139 }
4140 bool release_origin = true;
4141 if (store_fullsize && old_fullsize == n_cells_) {
4142 release_origin = false;
4143 }
4144 if (release_origin) {
4145 if (is_2draster && nullptr != raster_2d_) { // multiple layers
4146 Release2DArray(raster_2d_);
4147 Initialize2DArray(n_cells_, n_lyrs_, raster_2d_, no_data_value_);
4148 } else { // single layer
4149 Release1DArray(raster_);
4150 Initialize1DArray(n_cells_, raster_, no_data_value_);
4151 }
4152 // Loop the masked raster values
4153 size_t synthesis_idx = 0;
4154 for (size_t k = 0; k < pos_rows.size(); ++k) {
4155 synthesis_idx = k;
4156 int tmpr = pos_rows.at(k);
4157 int tmpc = pos_cols.at(k);
4158 if (store_fullsize) {
4159 if (tmpr > max_row || tmpr < min_row || tmpc > max_col || tmpc < min_col) {
4160 continue;
4161 }
4162 synthesis_idx = (tmpr - min_row) * ncols + tmpc - min_col;
4163 if (synthesis_idx > n_cells_ - 1) {
4164 continue; // error may occurred!
4165 }
4166 }
4167 if (is_2draster) { // multiple layers
4168 raster_2d_[synthesis_idx][0] = values.at(k);
4169 if (n_lyrs_ > 1) {
4170 for (int lyr = 1; lyr < n_lyrs_; lyr++) {
4171 raster_2d_[synthesis_idx][lyr] = values_2d[k][lyr - 1];
4172 }
4173 }
4174 } else { // single layer
4175 raster_[synthesis_idx] = values.at(k);
4176 }
4177 }
4178 }
4179
4180 if (upd_header_valid_num) {
4181 UpdateHeader(headers_, HEADER_RS_CELLSNUM, n_cells_);
4182 }
4183
4184 if (mask_has_subset) { // check former assigned mask's subset
4185 for (auto it = subset_.begin(); it != subset_.end();) {
4186 int count = 0;
4187 int srow = nrows;
4188 int erow = -1;
4189 int scol = ncols;
4190 int ecol = -1;
4191 vector<int> globalpos;
4192 for (int i = 0; i < it->second->n_cells; i++) {
4193 int gi = it->second->global_[i];
4194 int tmprow = valid_pos[gi][0];
4195 int tmpcol = valid_pos[gi][1];
4196 XY_COOR tmpxy = mask_->GetCoordinateByRowCol(tmprow, tmpcol);
4197 if (GetPosition(tmpxy.first, tmpxy.second) < 0) { continue; }
4198 ROW_COL tmppos = GetPositionByCoordinate(tmpxy.first, tmpxy.second);
4199 if (IsNoData(tmppos.first, tmppos.second)) { continue; }
4200 if (tmppos.first < srow) { srow = tmppos.first; }
4201 if (tmppos.first > erow) { erow = tmppos.first; }
4202 if (tmppos.second < scol) { scol = tmppos.second; }
4203 if (tmppos.second > ecol) { ecol = tmppos.second; }
4204 globalpos.emplace_back(GetPosition(tmppos.first, tmppos.second));
4205 count++;
4206 }
4207 if (count == 0) {
4208 delete it->second;
4209 subset_.erase(it++);
4210 continue;
4211 }
4212 if (recalc_subset) {
4213 it->second->g_srow = srow;
4214 it->second->g_erow = erow;
4215 it->second->g_scol = scol;
4216 it->second->g_ecol = ecol;
4217 it->second->n_cells = count;
4218 it->second->n_lyrs = n_lyrs_;
4219 int local_ncols = ecol - scol + 1;
4220 if (it->second->alloc_) {
4221 Release1DArray(it->second->global_);
4222 Release2DArray(it->second->local_pos_);
4223 Release1DArray(it->second->local_posidx_);
4224 }
4225 it->second->global_ = nullptr; // not affect mask's subset
4226 it->second->local_pos_ = nullptr;
4227 it->second->local_posidx_ = nullptr;
4228 it->second->alloc_ = true;
4229 Initialize1DArray(count, it->second->global_, -1);
4230 Initialize2DArray(count, 2, it->second->local_pos_, -1);
4231 Initialize1DArray(count, it->second->local_posidx_, -1);
4232 for (int ii = 0; ii < count; ii++) {
4233 it->second->global_[ii] = globalpos[ii];
4234 int local_row = -1;
4235 int local_col = -1;
4236 if (nullptr == pos_data_ || nullptr == pos_idx_) {
4237 local_row = globalpos[ii] / ncols - it->second->g_srow;
4238 local_col = globalpos[ii] % ncols - it->second->g_scol;
4239 } else {
4240 //local_row = pos_data_[globalpos[ii]][0] - it->second->g_srow;
4241 //local_col = pos_data_[globalpos[ii]][1] - it->second->g_scol;
4242 local_row = pos_idx_[globalpos[ii]] / ncols - it->second->g_srow;
4243 local_col = pos_idx_[globalpos[ii]] % ncols - it->second->g_scol;
4244 }
4245 it->second->local_pos_[ii][0] = local_row;
4246 it->second->local_pos_[ii][1] = local_col;
4247 it->second->local_posidx_[ii] = local_row * local_ncols + local_col;
4248 }
4249 it->second->data_ = nullptr;
4250 it->second->data2d_ = nullptr;
4251 it->second->alloc_ = true;
4252 }
4253 ++it;
4254 }
4255 }
4256 if (store_fullsize || recalc_pos) {
4257 mask_ = nullptr;
4258 }
4259 return 2; // all situations that use mask data
4260}
4261
4262} // namespace data_raster
4263} // namespace ccgl
4264#endif /* CCGL_DATA_RASTER_H */
Basic definitions.
#define CVT_INT(param)
A reference to the postfix of executable file for RELWITHDEBINFO mode.
Definition: basic.h:325
#define MISSINGFLOAT
Missing float value.
Definition: basic.h:250
#define CVT_DBL(param)
Convert to double double
Definition: basic.h:331
#define CVT_VINT(param)
Convert to 8-byte (64-bit) signed integer vint
Definition: basic.h:340
#define NODATA_VALUE
Global utility definitions.
Definition: basic.h:245
Base class for classes that cannot be copied.
Definition: basic.h:385
Subset positions of raster data.
Definition: data_raster.hpp:1086
int * global_
global position index
Definition: data_raster.hpp:1168
int * local_posidx_
local position index
Definition: data_raster.hpp:1167
double ** data2d_
valid 2d data array
Definition: data_raster.hpp:1170
int n_cells
valid cell count
Definition: data_raster.hpp:1159
int g_erow
end row in global data
Definition: data_raster.hpp:1162
bool alloc_
local_pos_ and global_ are allocated?
Definition: data_raster.hpp:1165
bool usable
flag for usable subset data
Definition: data_raster.hpp:1158
int g_ecol
end col in global data
Definition: data_raster.hpp:1164
int ** local_pos_
local position data
Definition: data_raster.hpp:1166
double * data_
valid data array
Definition: data_raster.hpp:1169
int g_srow
start row in global data
Definition: data_raster.hpp:1161
int n_lyrs
layer count
Definition: data_raster.hpp:1160
int g_scol
start col in global data
Definition: data_raster.hpp:1163
Raster data (1D and 2D) I/O class Support I/O among ASCII file, TIFF, and MongoDB database.
Definition: data_raster.hpp:1179
const STRDBL_MAP & GetRasterHeader() const
Get raster header information.
Definition: data_raster.hpp:1688
clsRasterData(bool is_2d=false)
Constructor an empty clsRasterData instance for 1D or 2D raster.
Definition: data_raster.hpp:2074
bool OutputFileByGdal(const string &filename)
Write 1D or 2D raster data into TIFF file by GDAL.
Definition: data_raster.hpp:3214
RasterDataType GetOutDataType() const
Get data type of source.
Definition: data_raster.hpp:1656
XY_COOR GetCoordinateByRowCol(int row, int col)
Calculate XY coordinates by given row and col number.
Definition: data_raster.hpp:3774
bool SetUseMaskExt()
Set the flag of use_mask_ext_ to true and recalculate positions and stored raster data if necessary.
Definition: data_raster.hpp:2840
~clsRasterData()
Destructor.
Definition: data_raster.hpp:2327
bool ReleaseSubset()
Release subsets.
Definition: data_raster.hpp:2407
bool MaskExtented() const
position data is allocated or a pointer
Definition: data_raster.hpp:1758
string GetFullFileName() const
Get full filename.
Definition: data_raster.hpp:1810
double GetCellWidth() const
Get row number.
Definition: data_raster.hpp:1630
int ** GetRasterPositionDataPointer() const
Get pointer of raster 1D data.
Definition: data_raster.hpp:1712
bool SetPositions(int len, int **pdata)
Set valid positions data, without mask raster layer.
Definition: data_raster.hpp:2816
int * GetRasterPositionIndexPointer() const
Get pointer of position data.
Definition: data_raster.hpp:1713
double GetYllCenter() const
Get Y coordinate of left lower center of raster data.
Definition: data_raster.hpp:1644
string GetCoreName() const
Get core name.
Definition: data_raster.hpp:1700
bool OutputAscFile(const string &filename)
Write 1D or 2D raster data into ASC file(s)
Definition: data_raster.hpp:3137
bool ReadFromMongoDB(MongoGridFs *gfs, const string &filename, bool calc_pos=false, clsRasterData< MASK_T > *mask=nullptr, bool use_mask_ext=true, double default_value=NODATA_VALUE, const STRING_MAP &opts=STRING_MAP())
Read raster data from MongoDB.
Definition: data_raster.hpp:3514
int GetDataLength() const
Get the first dimension size.
Definition: data_raster.hpp:1627
bool GetRasterData(int *n_cells, T **data)
Get raster data, include valid cell number and data.
Definition: data_raster.hpp:2615
bool StatisticsCalculated() const
Use mask extent or not.
Definition: data_raster.hpp:1759
string GetFilePath() const
Get full path name.
Definition: data_raster.hpp:1697
double GetRange(const int lyr=1)
Get the range of raster data.
Definition: data_raster.hpp:1579
string GetSrsString()
Get the spatial reference (char*)
Definition: data_raster.hpp:2682
void SetDataType(RasterDataType const type)
Set raster data type.
Definition: data_raster.hpp:1482
static clsRasterData< T, MASK_T > * Init(const string &filename, bool calc_pos=false, clsRasterData< MASK_T > *mask=nullptr, bool use_mask_ext=true, double default_value=NODATA_VALUE, const STRING_MAP &opts=STRING_MAP())
Validation check before the construction of clsRasterData, i.e., the raster file is existed and the d...
Definition: data_raster.hpp:2150
double GetStatistics(string sindex, int lyr=1)
Get basic statistics value Mean, Max, Min, STD, Range, etc.
Definition: data_raster.hpp:2485
void GetStd(int *lyrnum, double **values)
Get the standard derivation of 2D raster data.
Definition: data_raster.hpp:1604
clsRasterData< MASK_T > * GetMask() const
Get mask data pointer.
Definition: data_raster.hpp:1813
void SetDefaultValue(const double defaultv)
Set default value.
Definition: data_raster.hpp:1494
double GetMinimum(const int lyr=1)
Get the minimum of raster data.
Definition: data_raster.hpp:1566
bool ValidateRowCol(const int row, const int col)
Validate the input row and col.
Definition: data_raster.hpp:1776
int GetPosition(int row, int col)
Get default value.
Definition: data_raster.hpp:2542
bool OutputToMongoDB(MongoGridFs *gfs, const string &filename=string(), const STRING_MAP &opts=STRING_MAP(), bool include_nodata=true, bool out_origin=true)
Write the whole raster data to MongoDB, name format: corename__LyrNum.
Definition: data_raster.hpp:3269
const STRDBL_MAP & GetStatistics() const
Get raster statistics information.
Definition: data_raster.hpp:1691
void SetValue(int row, int col, T value, int lyr=1)
Set value to the given position and layer.
Definition: data_raster.hpp:2786
T ** Get2DRasterDataPointer() const
Get pointer of position data.
Definition: data_raster.hpp:1714
void ReleaseStatsMap2D()
Release statistics map of 2D raster data.
Definition: data_raster.hpp:2468
bool ValidateLayer(const int lyr)
Validate the input layer number.
Definition: data_raster.hpp:1788
ROW_COL GetPositionByCoordinate(double x, double y, STRDBL_MAP *header=nullptr)
Calculate position by given coordinate.
Definition: data_raster.hpp:3780
bool PositionsAllocated() const
Calculate positions or not.
Definition: data_raster.hpp:1757
void Reclassify(map< int, T > reclass_map)
classify raster
Definition: data_raster.hpp:3741
const map< string, double * > & GetStatistics2D() const
Get raster statistics information of 2D raster.
Definition: data_raster.hpp:1694
double GetAverage(const int lyr=1)
Get the average of raster data.
Definition: data_raster.hpp:1554
T GetValueByIndex(int cell_index, int lyr=1)
Get options.
Definition: data_raster.hpp:2696
void GetAverage(int *lyrnum, double **values)
Get the average of 2D raster data.
Definition: data_raster.hpp:1586
void SetDataType(const string &strtype)
Set raster data type.
Definition: data_raster.hpp:1485
bool RebuildSubSet(map< int, int > groups=map< int, int >())
Re-build subsets by given groups (cell value->group ID) or by discrete values.
Definition: data_raster.hpp:2419
const char * GetSrs()
Get pointer of raster 2D data.
Definition: data_raster.hpp:2677
int GetValidNumber(const int lyr=1)
Get the non-NoDATA cells number of the given raster layer data.
Definition: data_raster.hpp:1623
void UpdateStatistics()
Force to update basic statistics values Mean, Max, Min, STD, Range, etc.
Definition: data_raster.hpp:2478
int GetRows() const
Get column number.
Definition: data_raster.hpp:1629
void ReplaceNoData(T replacedv)
Replace NoData value by the given value.
Definition: data_raster.hpp:3720
void SetOutDataType(RasterDataType type)
Set output raster data type.
Definition: data_raster.hpp:2426
T GetNoDataValue() const
Get data type of output.
Definition: data_raster.hpp:1657
map< int, SubsetPositions * > & GetSubset()
Get subset.
Definition: data_raster.hpp:1674
RasterDataType GetDataType() const
Get layer number.
Definition: data_raster.hpp:1655
bool ReadFromFiles(vector< string > &filenames, bool calc_pos=false, clsRasterData< MASK_T > *mask=nullptr, bool use_mask_ext=true, double default_value=NODATA_VALUE, const STRING_MAP &opts=STRING_MAP())
Read raster data from two or more files, mask data is optional.
Definition: data_raster.hpp:3431
bool OutputToFile(const string &filename, bool out_origin=true)
Write the whole raster to raster file, if 2D raster, output name will be corename_LyrNum.
Definition: data_raster.hpp:2851
void GetValidNumber(int *lyrnum, double **values)
Get the non-NoDATA number of 2D raster data.
Definition: data_raster.hpp:1616
double GetMaximum(const int lyr=1)
Get the maximum of raster data.
Definition: data_raster.hpp:1560
void Copy(clsRasterData< T, MASK_T > *orgraster)
Copy clsRasterData object.
Definition: data_raster.hpp:3647
bool OutputSubsetToFile(bool out_origin=false, bool out_combined=true, const string &outname=string(), const map< vint, vector< double > > &recls=map< vint, vector< double > >(), double default_value=NODATA_VALUE)
Write one or more raster's subset to files, default name format: corename_SubID_LyrNum.
Definition: data_raster.hpp:2872
bool ValidateIndex(const int idx)
Validate the input index.
Definition: data_raster.hpp:1801
double GetXllCenter() const
Get cell size.
Definition: data_raster.hpp:1633
void GetRange(int *lyrnum, double **values)
Get the range of 2D raster data.
Definition: data_raster.hpp:1610
double GetDefaultValue() const
Get NoDATA value.
Definition: data_raster.hpp:1658
const STRING_MAP & GetOptions() const
Get option by key, including the spatial reference by "SRS".
Definition: data_raster.hpp:1718
bool Get2DRasterData(int *n_cells, int *n_lyrs, T ***data)
Get 2D raster data, include valid cell number of each layer, layer number, and data.
Definition: data_raster.hpp:2627
T GetValue(int row, int col, int lyr=1)
Get raster data via row and col The default lyr is 1, which means the 1D raster data,...
Definition: data_raster.hpp:2726
string GetOption(const char *key)
Get the spatial reference (string)
Definition: data_raster.hpp:2687
void CalculateStatistics()
Calculate basic statistics values in one time Mean, Max, Min, STD, Range, etc.
Definition: data_raster.hpp:2439
bool IsNoData(const int row, const int col, const int lyr=1)
Check if the raster data is NoData via row and col The default lyr is 1, which means the 1D raster da...
Definition: data_raster.hpp:1751
void GetMinimum(int *lyrnum, double **values)
Get the minimum of 2D raster data.
Definition: data_raster.hpp:1598
bool PositionsCalculated() const
Is 2D raster data?
Definition: data_raster.hpp:1756
bool Initialized() const
Basic statistics calculated?
Definition: data_raster.hpp:1760
bool ValidateRasterData()
Instance of clsRasterData initialized?
Definition: data_raster.hpp:1765
bool OutputSubsetToMongoDB(MongoGridFs *gfs, const string &filename=string(), const STRING_MAP &opts=STRING_MAP(), bool include_nodata=true, bool out_origin=false, bool out_combined=true, const map< vint, vector< double > > &recls=map< vint, vector< double > >(), double default_value=NODATA_VALUE)
Write one or more raster's subset to MongoDB,.
Definition: data_raster.hpp:3349
double GetStd(const int lyr=1)
Get the stand derivation of raster data.
Definition: data_raster.hpp:1572
void SetCoreName(const string &name)
Set new core file name.
Definition: data_raster.hpp:1456
void GetMaximum(int *lyrnum, double **values)
Get the maximum of 2D raster data.
Definition: data_raster.hpp:1592
bool SetCalcPositions()
Set the flag of calc_pos_ to true and recalculate positions and stored raster data if necessary.
Definition: data_raster.hpp:2805
bool BuildSubSet(map< int, int > groups=map< int, int >())
Build subsets by given groups (cell value->group ID) or by discrete values (default)
Definition: data_raster.hpp:2338
bool ReadFromFile(const string &filename, bool calc_pos=false, clsRasterData< MASK_T > *mask=nullptr, bool use_mask_ext=true, double default_value=NODATA_VALUE, const STRING_MAP &opts=STRING_MAP())
Read raster data from file, mask data is optional.
Definition: data_raster.hpp:3419
void GetRasterPositionData(int *datalength, int ***positiondata)
Get position index data and the data length.
Definition: data_raster.hpp:2641
A simple wrapper of the class of MongoDB database mongoc_gridfs_t.
Definition: db_mongoc.h:141
bool RemoveFile(string const &gfilename, mongoc_gridfs_t *gfs=NULL, STRING_MAP opts=STRING_MAP())
Remove GridFS all matching files and their data chunks.
Definition: db_mongoc.cpp:336
bool GetStreamData(string const &gfilename, char *&databuf, vint &datalength, mongoc_gridfs_t *gfs=NULL, const STRING_MAP *opts=nullptr)
Get stream data of a given GridFS file name.
Definition: db_mongoc.cpp:411
bool WriteStreamData(const string &gfilename, char *&buf, vint length, const bson_t *p, mongoc_gridfs_t *gfs=NULL)
Write stream data to a GridFS file.
Definition: db_mongoc.cpp:442
bson_t * GetFileMetadata(string const &gfilename, mongoc_gridfs_t *gfs=NULL, STRING_MAP opts=STRING_MAP())
Get metadata of a given GridFS file name, remember to destory bson_t after use.
Definition: db_mongoc.cpp:391
#define CONST_CHARS
const string
Definition: data_raster.hpp:73
Simple wrappers of the API of MongoDB C driver mongo-c-driver, see MongoDB C Driver for more informat...
void UpdateStrHeader(STRING_MAP &strheader, const string &key, const string &val)
Update header information in string.
Definition: data_raster.cpp:155
CONST_CHARS HEADER_INC_NODATA
Desired output data type of raster.
Definition: data_raster.hpp:104
bool WriteStreamDataAsGridfs(MongoGridFs *gfs, const string &filename, STRDBL_MAP &header, T *values, const int datalength, const STRING_MAP &opts=STRING_MAP())
Write array data (both valid and full-sized raster data) as GridFS file.
Definition: data_raster.hpp:989
bool ReadRasterFileByGdal(const string &filename, STRDBL_MAP &header, T *&values, RasterDataType &in_type, string &srs)
Read single raster file by GDAL.
Definition: data_raster.hpp:359
bool WriteSingleGeotiff(const string &filename, const STRDBL_MAP &header, const STRING_MAP &opts, T *values)
Write single geotiff file If the file exists, delete it first.
Definition: data_raster.hpp:585
STRING_MAP InitialStrHeader()
Initialize header information in string.
Definition: data_raster.cpp:137
bool WriteRasterToFile(const string &filename, const STRDBL_MAP &header, const STRING_MAP &opts, T *values)
Write single raster file, if the file exists, delete it first.
Definition: data_raster.hpp:839
CONST_CHARS STATS_RS_MEAN
Valid cell number.
Definition: data_raster.hpp:107
CONST_CHARS HEADER_RS_CELLSNUM
Layers number.
Definition: data_raster.hpp:99
CONST_CHARS HEADER_RS_PARAM_ABSTRACTION_TYPE
SRS.
Definition: data_raster.hpp:101
CONST_CHARS HEADER_RS_YLL
X coordinate value of left low center.
Definition: data_raster.hpp:92
CONST_CHARS STATS_RS_VALIDNUM
Mask layer's name if only store valid values.
Definition: data_raster.hpp:106
RasterDataType
Coordinate pair.
Definition: data_raster.hpp:121
@ RDT_UInt16
GDT_UInt16.
Definition: data_raster.hpp:125
@ RDT_Int32
GDT_Int32.
Definition: data_raster.hpp:128
@ RDT_UInt32
GDT_UInt32.
Definition: data_raster.hpp:127
@ RDT_Int64
GDT_Int64, GDAL>=3.5.
Definition: data_raster.hpp:130
@ RDT_Float
GDT_Float32.
Definition: data_raster.hpp:131
@ RDT_UInt64
GDT_UInt64, GDAL>=3.5.
Definition: data_raster.hpp:129
@ RDT_Double
GDT_Float64.
Definition: data_raster.hpp:132
@ RDT_Int16
GDT_Int16.
Definition: data_raster.hpp:126
@ RDT_Unknown
GDT_Unknown.
Definition: data_raster.hpp:122
@ RDT_Int8
GDT_Int8, GDAL>=3.7.
Definition: data_raster.hpp:124
@ RDT_UInt8
GDT_Byte.
Definition: data_raster.hpp:123
void CopyHeader(const STRDBL_MAP &refers, STRDBL_MAP &dst)
Copy header information from one to another.
Definition: data_raster.cpp:121
bool WriteSingleAsc(const string &filename, const STRDBL_MAP &header, T *values)
Write raster data as a single ASC file.
Definition: data_raster.hpp:325
CONST_CHARS GTiffExtension
ASCII extension.
Definition: data_raster.hpp:113
STRDBL_MAP InitialHeader()
Initialize header information in double.
Definition: data_raster.cpp:105
double DefaultNoDataByType(const RasterDataType type)
Default NoData value by data type.
Definition: data_raster.cpp:62
CONST_CHARS HEADER_RS_DATATYPE
spatial parameter type, physical or conceptual
Definition: data_raster.hpp:102
CONST_CHARS STATS_RS_MIN
Mean value.
Definition: data_raster.hpp:108
RasterDataType TypeToRasterDataType(const std::type_info &t)
Convert C++ data type to RasterDataType.
Definition: data_raster.cpp:48
CONST_CHARS HEADER_RS_LAYERS
Cell size (length)
Definition: data_raster.hpp:98
CONST_CHARS STATS_RS_RANGE
Standard derivation value.
Definition: data_raster.hpp:111
CONST_CHARS ASCIIExtension
Range value.
Definition: data_raster.hpp:112
CONST_CHARS HEADER_RSOUT_DATATYPE
Data type of original raster.
Definition: data_raster.hpp:103
CONST_CHARS HEADER_RS_SRS
Number of the first layer's valid cells.
Definition: data_raster.hpp:100
void InitialStatsMap(STRDBL_MAP &stats, map< string, double * > &stats2d)
Initialize statistics values for 1D and 2D raster data.
Definition: data_raster.cpp:173
std::pair< int, int > ROW_COL
GeoTIFF extension.
Definition: data_raster.hpp:115
bool WriteAscHeaders(const string &filename, const STRDBL_MAP &header)
Write raster header information into a ASC file.
Definition: data_raster.cpp:189
CONST_CHARS STATS_RS_STD
Maximum value.
Definition: data_raster.hpp:110
CONST_CHARS HEADER_RS_CELLSIZE
Column number.
Definition: data_raster.hpp:97
RasterDataType StringToRasterDataType(const string &stype)
Convert string to RasterDataType.
Definition: data_raster.cpp:32
string RasterDataTypeToString(const int type)
Common functions independent to clsRasterData.
Definition: data_raster.cpp:16
CONST_CHARS HEADER_RS_YLLCOR
X coordinate value of left low center.
Definition: data_raster.hpp:94
CONST_CHARS HEADER_MASK_NAME
Include nodata ("TRUE") or not ("FALSE"), for DB only.
Definition: data_raster.hpp:105
CONST_CHARS STATS_RS_MAX
Minimum value.
Definition: data_raster.hpp:109
std::pair< double, double > XY_COOR
Row and Col pair.
Definition: data_raster.hpp:116
void UpdateHeader(STRDBL_MAP &header, const string &key, T val)
Update value in header information.
Definition: data_raster.hpp:177
bool ReadGridFsFile(MongoGridFs *gfs, const string &filename, T *&data, STRDBL_MAP &header, STRING_MAP &header_str, const STRING_MAP &opts)
Read GridFs file from MongoDB.
Definition: data_raster.hpp:870
CONST_CHARS HEADER_RS_NCOLS
Rows number.
Definition: data_raster.hpp:96
CONST_CHARS HEADER_RS_XLLCOR
Y coordinate value of left low center.
Definition: data_raster.hpp:93
CONST_CHARS HEADER_RS_NROWS
Y coordinate value of left low center.
Definition: data_raster.hpp:95
bool ReadAscFile(const string &filename, STRDBL_MAP &header, T *&values)
Read raster data from ASC file, the simply usage.
Definition: data_raster.hpp:215
RasterDataType RasterDataTypeInOptionals(const STRING_MAP &opts)
Get output raster data type from optional inputs.
Definition: data_raster.cpp:166
CONST_CHARS HEADER_RS_XLL
NoData value.
Definition: data_raster.hpp:91
void AppendStringOptionsToBson(bson_t *bson_opts, const STRING_MAP &opts, const string &prefix)
Append options to bson_t
Definition: db_mongoc.cpp:481
string GetStringFromBsonIterator(bson_iter_t *iter)
Get String from the iterator (bson_iter_t) of bson_t
Definition: db_mongoc.cpp:503
bool GetNumericFromBsonIterator(bson_iter_t *iter, T &numericvalue)
Get numeric value from the iterator (bson_iter_t) of bson_taccording to a given key.
Definition: db_mongoc.h:191
void Release1DArray(T *&data)
Release DT_Array1D data.
Definition: utils_array.h:460
bool Initialize1DArray(int row, T *&data, INI_T init_value)
Initialize DT_Array1D data.
Definition: utils_array.h:331
bool Initialize2DArray(int row, int col, T **&data, INI_T init_value)
Initialize DT_Array2D data.
Definition: utils_array.h:381
void Release2DArray(T **&data)
Release DT_Array2D data.
Definition: utils_array.h:468
bool FileExists(string const &filename)
Return a flag indicating if the given file exists.
Definition: utils_filesystem.cpp:23
string GetSuffix(string const &full_filename)
Return the suffix of a given file's path without dot, e.g., "tif", "asc".
Definition: utils_filesystem.cpp:311
string GetAbsolutePath(string const &full_filename)
Return the absolute file path from a given file path.
Definition: utils_filesystem.cpp:283
bool PathExists(string const &fullpath)
Return a flag indicating if the given path (directory or file) exists.
Definition: utils_filesystem.cpp:43
string AppendCoreFileName(string const &full_filename, string const &endstr, char deli)
Append a given string to the core filename.
Definition: utils_filesystem.cpp:328
string GetPathFromFullName(string const &full_filename)
Get Path From full file path string.
Definition: utils_filesystem.cpp:350
string ReplaceSuffix(string const &full_filename, string const &new_suffix)
Replace the suffix by a given suffix.
Definition: utils_filesystem.cpp:320
string GetCoreFileName(string const &full_filename)
Return the file name from a given file's path.
Definition: utils_filesystem.cpp:296
string PrefixCoreFileName(string const &full_filename, string const &prestr, char deli)
Add a prefix to the core filename.
Definition: utils_filesystem.cpp:339
bool FilesExist(vector< string > &filenames)
Return a flag indicating if given files exist.
Definition: utils_filesystem.cpp:35
bool MakeDirectory(const string &dirpath)
Make directory if not exists.
Definition: utils_filesystem.cpp:139
bool LoadPlainTextFile(const string &filepath, vector< string > &content_strs)
Load short plain text file as string vector, ignore comments begin with '#' and empty lines.
Definition: utils_filesystem.cpp:372
void BasicStatistics(const T *values, int num, double **derivedvalues, T exclude=static_cast< T >(NODATA_VALUE))
calculate basic statistics at one time_funcs
Definition: utils_math.h:382
bool FloatEqual(T1 v1, T2 v2)
Whether v1 is equal to v2.
Definition: utils_math.h:141
string ValueToString(const T &val)
Convert value to string.
Definition: utils_string.h:88
void CopyStringMap(const STRING_MAP &in_opts, STRING_MAP &out_opts)
Copy string map.
Definition: utils_string.cpp:78
void UpdateStringMap(STRING_MAP &opts, const string &key, const string &value)
Add or modify element in a string map.
Definition: utils_string.cpp:94
string itoa(vint number)
Convert a signed integer to a string.
Definition: utils_string.cpp:152
vint IsInt(const string &num_str, bool &success)
Check if a string is an signed integer, if ture, return the converted integer.
Definition: utils_string.cpp:250
string GetUpper(const string &str)
Get Uppercase of given string.
Definition: utils_string.cpp:16
vector< string > SplitString(const string &item, const char delimiter)
Splits the given string based on the given delimiter.
Definition: utils_string.cpp:35
bool StringMatch(const char *a, const char *b)
Match char ignore cases.
Definition: utils_string.cpp:61
double IsDouble(const string &num_str, bool &success)
Convert an Ansi string to 64-bits floating point number.
Definition: utils_string.cpp:306
Common Cross-platform Geographic Library (CCGL)
Definition: basic.cpp:17
std::map< string, string > STRING_MAP
Map of string key and string value.
Definition: basic.h:349
void StatusMessage(const char *msg)
Print status messages for Debug.
Definition: basic.cpp:136
std::map< string, double > STRDBL_MAP
Map of string key and double value.
Definition: basic.h:352
void SleepMs(const int millisecs)
Sleep milliseconds.
Definition: basic.h:491
Template functions to initialize and release arrays.
File system related functions in CCGL.
Useful math equations in CCGL.
Handling string related issues in CCGL.