PostGIS 3.7.0dev-r@@SVN_REVISION@@
Loading...
Searching...
No Matches
rt_band.c
Go to the documentation of this file.
1/*
2 *
3 * WKTRaster - Raster Types for PostGIS
4 * http://trac.osgeo.org/postgis/wiki/WKTRaster
5 *
6 * Copyright (C) 2018 Bborie Park <dustymugs@gmail.com>
7 * Copyright (C) 2011-2013 Regents of the University of California
8 * <bkpark@ucdavis.edu>
9 * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
10 * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
11 * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
12 * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
13 * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
14 * Copyright (C) 2025 Darafei Praliaskouski <me@komzpa.net>
15 *
16 * This program is free software; you can redistribute it and/or
17 * modify it under the terms of the GNU General Public License
18 * as published by the Free Software Foundation; either version 2
19 * of the License, or (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software Foundation,
28 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
29 *
30 */
31
32// For stat64()
33#define _LARGEFILE64_SOURCE 1
34
35#include <stdio.h>
36
37#include "librtcore.h"
38#include "librtcore_internal.h"
39
40#include "cpl_vsi.h"
41#include "gdal_vrt.h"
42
65 uint16_t width, uint16_t height,
66 rt_pixtype pixtype,
67 uint32_t hasnodata, double nodataval,
68 uint8_t* data
69) {
70 rt_band band = NULL;
71
72 assert(NULL != data);
73
74 band = rtalloc(sizeof(struct rt_band_t));
75 if (band == NULL) {
76 rterror("rt_band_new_inline: Out of memory allocating rt_band");
77 return NULL;
78 }
79
80 RASTER_DEBUGF(3, "Created rt_band @ %p with pixtype %s", band, rt_pixtype_name(pixtype));
81
82 band->pixtype = pixtype;
83 band->offline = 0;
84 band->width = width;
85 band->height = height;
86 band->hasnodata = hasnodata ? 1 : 0;
87 band->isnodata = FALSE; /* we don't know what is in data, so must be FALSE */
88 band->nodataval = 0;
89 band->data.mem = data;
90 band->ownsdata = 0; /* we do NOT own this data!!! */
91 band->raster = NULL;
92
93 RASTER_DEBUGF(3, "Created rt_band with dimensions %d x %d", band->width, band->height);
94
95 /* properly set nodataval as it may need to be constrained to the data type */
96 if (hasnodata && rt_band_set_nodata(band, nodataval, NULL) != ES_NONE) {
97 rterror("rt_band_new_inline: Could not set NODATA value");
98 rt_band_destroy(band);
99 return NULL;
100 }
101
102 return band;
103}
104
112void
114 rt_band band,
115 double initval
116) {
117 assert(band != NULL);
118 assert(band->data.mem != NULL);
119 rt_pixtype pixtype = band->pixtype;
120 uint32_t width = band->width;
121 uint32_t height = band->height;
122 uint32_t numval = width * height;
123 void *mem = band->data.mem;
124 size_t memsize = numval * rt_pixtype_size(pixtype);
125
126 /* initialize to nodataval */
127 int32_t checkvalint = 0;
128 uint32_t checkvaluint = 0;
129 double checkvaldouble = 0;
130 float checkvalfloat = 0;
131
132 /* initialize to zero */
133 if (FLT_EQ(initval, 0.0)) {
134 memset(mem, 0, memsize);
135 return;
136 }
137
138 switch (pixtype) {
139 case PT_1BB:
140 {
141 uint8_t *ptr = mem;
142 uint8_t clamped_initval = rt_util_clamp_to_1BB(initval);
143 for (uint32_t i = 0; i < numval; i++)
144 ptr[i] = clamped_initval;
145 checkvalint = ptr[0];
146 break;
147 }
148 case PT_2BUI:
149 {
150 uint8_t *ptr = mem;
151 uint8_t clamped_initval = rt_util_clamp_to_2BUI(initval);
152 for (uint32_t i = 0; i < numval; i++)
153 ptr[i] = clamped_initval;
154 checkvalint = ptr[0];
155 break;
156 }
157 case PT_4BUI:
158 {
159 uint8_t *ptr = mem;
160 uint8_t clamped_initval = rt_util_clamp_to_4BUI(initval);
161 for (uint32_t i = 0; i < numval; i++)
162 ptr[i] = clamped_initval;
163 checkvalint = ptr[0];
164 break;
165 }
166 case PT_8BSI:
167 {
168 int8_t *ptr = mem;
169 int8_t clamped_initval = rt_util_clamp_to_8BSI(initval);
170 for (uint32_t i = 0; i < numval; i++)
171 ptr[i] = clamped_initval;
172 checkvalint = ptr[0];
173 break;
174 }
175 case PT_8BUI:
176 {
177 uint8_t *ptr = mem;
178 uint8_t clamped_initval = rt_util_clamp_to_8BUI(initval);
179 for (uint32_t i = 0; i < numval; i++)
180 ptr[i] = clamped_initval;
181 checkvalint = ptr[0];
182 break;
183 }
184 case PT_16BSI:
185 {
186 int16_t *ptr = mem;
187 int16_t clamped_initval = rt_util_clamp_to_16BSI(initval);
188 for (uint32_t i = 0; i < numval; i++)
189 ptr[i] = clamped_initval;
190 checkvalint = ptr[0];
191 break;
192 }
193 case PT_16BUI: {
194 uint16_t *ptr = mem;
195 uint16_t clamped_initval = rt_util_clamp_to_16BUI(initval);
196 for (uint32_t i = 0; i < numval; i++)
197 ptr[i] = clamped_initval;
198 checkvalint = ptr[0];
199 break;
200 }
201 case PT_16BF: {
202 uint16_t *ptr = mem;
203 float clamped_initval = rt_util_clamp_to_16F(initval);
204 uint16_t packed = rt_util_float_to_float16(clamped_initval);
205 for (uint32_t i = 0; i < numval; i++)
206 ptr[i] = packed;
207 checkvalfloat = rt_util_float16_to_float(ptr[0]);
208 break;
209 }
210 case PT_32BSI: {
211 int32_t *ptr = mem;
212 int32_t clamped_initval = rt_util_clamp_to_32BSI(initval);
213 for (uint32_t i = 0; i < numval; i++)
214 ptr[i] = clamped_initval;
215 checkvalint = ptr[0];
216 break;
217 }
218 case PT_32BUI:
219 {
220 uint32_t *ptr = mem;
221 uint32_t clamped_initval = rt_util_clamp_to_32BUI(initval);
222 for (uint32_t i = 0; i < numval; i++)
223 ptr[i] = clamped_initval;
224 checkvaluint = ptr[0];
225 break;
226 }
227 case PT_32BF:
228 {
229 float *ptr = mem;
230 float clamped_initval = rt_util_clamp_to_32F(initval);
231 for (uint32_t i = 0; i < numval; i++)
232 ptr[i] = clamped_initval;
233 checkvalfloat = ptr[0];
234 break;
235 }
236 case PT_64BF:
237 {
238 double *ptr = mem;
239 for (uint32_t i = 0; i < numval; i++)
240 ptr[i] = initval;
241 checkvaldouble = ptr[0];
242 break;
243 }
244 default:
245 {
246 rterror("%s: Unknown pixeltype %d", __func__, pixtype);
247 return;
248 }
249 }
250
251 /* Overflow checking */
253 initval,
254 checkvalint, checkvaluint,
255 checkvalfloat, checkvaldouble,
256 pixtype
257 );
258
259 return;
260}
261
262
284 uint16_t width, uint16_t height,
285 rt_pixtype pixtype,
286 uint32_t hasnodata, double nodataval,
287 uint8_t bandNum, const char* path
288) {
289 rt_band band = NULL;
290 int pathlen = 0;
291
292 assert(NULL != path);
293
294 band = rtalloc(sizeof(struct rt_band_t));
295 if (band == NULL) {
296 rterror("rt_band_new_offline: Out of memory allocating rt_band");
297 return NULL;
298 }
299
300 RASTER_DEBUGF(3, "Created rt_band @ %p with pixtype %s",
301 band, rt_pixtype_name(pixtype)
302 );
303
304 band->pixtype = pixtype;
305 band->offline = 1;
306 band->width = width;
307 band->height = height;
308 band->hasnodata = hasnodata ? 1 : 0;
309 band->nodataval = 0;
310 band->isnodata = FALSE; /* we don't know if the offline band is NODATA */
311 band->ownsdata = 0; /* offline, flag is useless as all offline data cache is owned internally */
312 band->raster = NULL;
313
314 /* properly set nodataval as it may need to be constrained to the data type */
315 if (hasnodata && rt_band_set_nodata(band, nodataval, NULL) != ES_NONE) {
316 rterror("rt_band_new_offline: Could not set NODATA value");
317 rt_band_destroy(band);
318 return NULL;
319 }
320
321 band->data.offline.bandNum = bandNum;
322
323 /* memory for data.offline.path is managed internally */
324 pathlen = strlen(path);
325 band->data.offline.path = rtalloc(sizeof(char) * (pathlen + 1));
326 if (band->data.offline.path == NULL) {
327 rterror("rt_band_new_offline: Out of memory allocating offline path");
328 rt_band_destroy(band);
329 return NULL;
330 }
331 memcpy(band->data.offline.path, path, pathlen);
332 band->data.offline.path[pathlen] = '\0';
333
334 band->data.offline.mem = NULL;
335
336 return band;
337}
338
359 uint16_t width,
360 uint16_t height,
361 int hasnodata,
362 double nodataval,
363 uint8_t bandNum,
364 const char* path,
365 int force
366) {
367 GDALDatasetH hdsSrc = NULL;
368 int nband = 0;
369 GDALRasterBandH hbandSrc = NULL;
370
371 GDALDataType gdpixtype;
372 rt_pixtype pt = PT_END;
373
374 /* open outdb raster file */
376 hdsSrc = rt_util_gdal_open(path, GA_ReadOnly, 1);
377 if (hdsSrc == NULL && !force) {
378 rterror("rt_band_new_offline_from_path: Cannot open offline raster: %s", path);
379 return NULL;
380 }
381
382 nband = GDALGetRasterCount(hdsSrc);
383 if (!nband && !force) {
384 rterror("rt_band_new_offline_from_path: No bands found in offline raster: %s", path);
385 GDALClose(hdsSrc);
386 return NULL;
387 }
388 /* bandNum is 1-based */
389 else if (bandNum > nband && !force) {
390 rterror(
391 "rt_band_new_offline_from_path: Specified band %d not found in offline raster: %s",
392 bandNum,
393 path
394 );
395 GDALClose(hdsSrc);
396 return NULL;
397 }
398
399 hbandSrc = GDALGetRasterBand(hdsSrc, bandNum);
400 if (hbandSrc == NULL && !force) {
401 rterror(
402 "rt_band_new_offline_from_path: Cannot get band %d from GDAL dataset",
403 bandNum
404 );
405 GDALClose(hdsSrc);
406 return NULL;
407 }
408
409 gdpixtype = GDALGetRasterDataType(hbandSrc);
410 pt = rt_util_gdal_datatype_to_pixtype(gdpixtype);
411 if (pt == PT_END && !force) {
412 rterror(
413 "rt_band_new_offline_from_path: Unsupported pixel type %s of band %d from GDAL dataset",
414 GDALGetDataTypeName(gdpixtype),
415 bandNum
416 );
417 GDALClose(hdsSrc);
418 return NULL;
419 }
420
421 /* use out-db band's nodata value if nodataval not already set */
422 if (!hasnodata)
423 nodataval = GDALGetRasterNoDataValue(hbandSrc, &hasnodata);
424
425 GDALClose(hdsSrc);
426
427 return rt_band_new_offline(
428 width, height,
429 pt,
430 hasnodata, nodataval,
431 bandNum - 1, path
432 );
433}
434
447 rt_band rtn = NULL;
448
449 assert(band != NULL);
450
451 /* offline */
452 if (band->offline) {
454 band->width, band->height,
455 band->pixtype,
456 band->hasnodata, band->nodataval,
457 band->data.offline.bandNum, (const char *) band->data.offline.path
458 );
459 }
460 /* online */
461 else {
462 uint8_t *data = NULL;
463 data = rtalloc((size_t)rt_pixtype_size(band->pixtype) * band->width * band->height);
464 if (data == NULL) {
465 rterror("rt_band_duplicate: Out of memory allocating online band data");
466 return NULL;
467 }
468 memcpy(data, band->data.mem, (size_t)rt_pixtype_size(band->pixtype) * band->width * band->height);
469
470 rtn = rt_band_new_inline(
471 band->width, band->height,
472 band->pixtype,
473 band->hasnodata, band->nodataval,
474 data
475 );
476 rt_band_set_ownsdata_flag(rtn, 1); /* we DO own this data!!! */
477 }
478
479 if (rtn == NULL) {
480 rterror("rt_band_duplicate: Could not copy band");
481 return NULL;
482 }
483
484 return rtn;
485}
486
487int
489 assert(NULL != band);
490 return band->offline ? 1 : 0;
491}
492
498void
500 if (band == NULL)
501 return;
502
503 RASTER_DEBUGF(3, "Destroying rt_band @ %p", band);
504
505 /* offline band */
506 if (band->offline) {
507 /* memory cache */
508 if (band->data.offline.mem != NULL)
509 rtdealloc(band->data.offline.mem);
510 /* offline file path */
511 if (band->data.offline.path != NULL)
512 rtdealloc(band->data.offline.path);
513 }
514 /* inline band and band owns the data */
515 else if (band->data.mem != NULL && band->ownsdata)
516 rtdealloc(band->data.mem);
517
518 rtdealloc(band);
519}
520
521const char*
523
524 assert(NULL != band);
525
526
527 if (!band->offline) {
528 RASTER_DEBUG(3, "rt_band_get_ext_path: Band is not offline");
529 return NULL;
530 }
531 return band->data.offline.path;
532}
533
535rt_band_get_ext_band_num(rt_band band, uint8_t *bandnum) {
536 assert(NULL != band);
537 assert(NULL != bandnum);
538
539 *bandnum = 0;
540
541 if (!band->offline) {
542 RASTER_DEBUG(3, "rt_band_get_ext_band_num: Band is not offline");
543 return ES_ERROR;
544 }
545
546 *bandnum = band->data.offline.bandNum;
547
548 return ES_NONE;
549}
550
558void *
560 assert(NULL != band);
561
562 if (band->offline) {
563 if (band->data.offline.mem != NULL)
564 return band->data.offline.mem;
565
567 return NULL;
568 else
569 return band->data.offline.mem;
570 }
571 else
572 return band->data.mem;
573}
574
575/* variable for PostgreSQL GUC: postgis.enable_outdb_rasters */
577
589 GDALDatasetH hdsSrc = NULL;
590 int nband = 0;
591 VRTDatasetH hdsDst = NULL;
592 VRTSourcedRasterBandH hbandDst = NULL;
593 double ogt[6] = {0};
594 double offset[2] = {0};
595
596 rt_raster _rast = NULL;
597 rt_band _band = NULL;
598 int aligned = 0;
599 int err = ES_NONE;
600
601 assert(band != NULL);
602 assert(band->raster != NULL);
603
604 if (!band->offline) {
605 rterror("rt_band_load_offline_data: Band is not offline");
606 return ES_ERROR;
607 }
608 else if (!strlen(band->data.offline.path)) {
609 rterror("rt_band_load_offline_data: Offline band does not a have a specified file");
610 return ES_ERROR;
611 }
612
613 /* offline_data is disabled */
615 rterror("rt_band_load_offline_data: Access to offline bands disabled");
616 return ES_ERROR;
617 }
618
620 hdsSrc = rt_util_gdal_open(band->data.offline.path, GA_ReadOnly, 1);
621 if (hdsSrc == NULL) {
622 rterror("rt_band_load_offline_data: Cannot open offline raster: %s", band->data.offline.path);
623 return ES_ERROR;
624 }
625
626 /* # of bands */
627 nband = GDALGetRasterCount(hdsSrc);
628 if (!nband) {
629 rterror("rt_band_load_offline_data: No bands found in offline raster: %s", band->data.offline.path);
630 GDALClose(hdsSrc);
631 return ES_ERROR;
632 }
633 /* bandNum is 0-based */
634 else if (band->data.offline.bandNum + 1 > nband) {
635 rterror("rt_band_load_offline_data: Specified band %d not found in offline raster: %s", band->data.offline.bandNum, band->data.offline.path);
636 GDALClose(hdsSrc);
637 return ES_ERROR;
638 }
639
640 /* get offline raster's geotransform */
641 if (GDALGetGeoTransform(hdsSrc, ogt) != CE_None) {
642 RASTER_DEBUG(4, "Using default geotransform matrix (0, 1, 0, 0, 0, -1)");
643 ogt[0] = 0;
644 ogt[1] = 1;
645 ogt[2] = 0;
646 ogt[3] = 0;
647 ogt[4] = 0;
648 ogt[5] = -1;
649 }
650 RASTER_DEBUGF(3, "Offline geotransform (%f, %f, %f, %f, %f, %f)",
651 ogt[0], ogt[1], ogt[2], ogt[3], ogt[4], ogt[5]);
652
653 /* are rasters aligned? */
654 _rast = rt_raster_new(1, 1);
656 rt_raster_set_srid(_rast, band->raster->srid);
657 err = rt_raster_same_alignment(band->raster, _rast, &aligned, NULL);
658 rt_raster_destroy(_rast);
659
660 if (err != ES_NONE) {
661 rterror("rt_band_load_offline_data: Could not test alignment of in-db representation of out-db raster");
662 GDALClose(hdsSrc);
663 return ES_ERROR;
664 }
665 else if (!aligned) {
666 rtwarn("The in-db representation of the out-db raster is not aligned. Band data may be incorrect");
667 }
668
669 /* get offsets */
671 band->raster,
672 ogt[0], ogt[3],
673 &(offset[0]), &(offset[1]),
674 NULL
675 );
676
677 RASTER_DEBUGF(4, "offsets: (%f, %f)", offset[0], offset[1]);
678
679 /* create VRT dataset */
680 hdsDst = VRTCreate(band->width, band->height);
681 GDALSetGeoTransform(hdsDst, ogt);
682 /*
683 GDALSetDescription(hdsDst, "/tmp/offline.vrt");
684 */
685
686 /* add band as simple sources */
687 GDALAddBand(hdsDst, rt_util_pixtype_to_gdal_datatype(band->pixtype), NULL);
688 hbandDst = (VRTSourcedRasterBandH) GDALGetRasterBand(hdsDst, 1);
689
690 if (band->hasnodata)
691 GDALSetRasterNoDataValue(hbandDst, band->nodataval);
692
693 VRTAddSimpleSource(
694 hbandDst, GDALGetRasterBand(hdsSrc, band->data.offline.bandNum + 1),
695 fabs(offset[0]), fabs(offset[1]),
696 band->width, band->height,
697 0, 0,
698 band->width, band->height,
699 "near", VRT_NODATA_UNSET
700 );
701
702 /* make sure VRT reflects all changes */
703 VRTFlushCache(hdsDst);
704
705 /* convert VRT dataset to rt_raster */
706 _rast = rt_raster_from_gdal_dataset(hdsDst);
707
708 GDALClose(hdsDst);
709 GDALClose(hdsSrc);
710 /*
711 {
712 FILE *fp;
713 fp = fopen("/tmp/gdal_open_files.log", "w");
714 GDALDumpOpenDatasets(fp);
715 fclose(fp);
716 }
717 */
718
719 if (_rast == NULL) {
720 rterror("rt_band_load_offline_data: Cannot load data from offline raster: %s", band->data.offline.path);
721 return ES_ERROR;
722 }
723
724 _band = rt_raster_get_band(_rast, 0);
725 if (_band == NULL) {
726 rterror("rt_band_load_offline_data: Cannot load data from offline raster: %s", band->data.offline.path);
727 rt_raster_destroy(_rast);
728 return ES_ERROR;
729 }
730
731 /* band->data.offline.mem not NULL, free first */
732 if (band->data.offline.mem != NULL) {
733 rtdealloc(band->data.offline.mem);
734 band->data.offline.mem = NULL;
735 }
736
737 band->data.offline.mem = _band->data.mem;
738
739 rtdealloc(_band); /* cannot use rt_band_destroy */
740 rt_raster_destroy(_rast);
741
742 return ES_NONE;
743}
744
746 VSIStatBufL sStat;
747
748 assert(NULL != band);
749 if (!band->offline) {
750 rterror("rt_band_get_file_size: Band is not offline");
751 return 0;
752 }
753 /* offline_data is disabled */
755 rterror("rt_band_get_file_size: Access to offline bands disabled");
756 return 0;
757 }
758
759 if( VSIStatL(band->data.offline.path, &sStat) != 0 ) {
760 rterror("rt_band_get_file_size: Cannot access file");
761 return 0;
762 }
763
764 return sStat.st_size;
765}
766
768 VSIStatBufL sStat;
769
770 assert(NULL != band);
771 if (!band->offline) {
772 rterror("rt_band_get_file_timestamp: Band is not offline");
773 return 0;
774 }
775 /* offline_data is disabled */
777 rterror("rt_band_get_file_timestamp: Access to offline bands disabled");
778 return 0;
779 }
780
781 if( VSIStatL(band->data.offline.path, &sStat) != 0 ) {
782 rterror("rt_band_get_file_timestamp: Cannot access file");
783 return 0;
784 }
785
786 return sStat.st_mtime;
787}
788
791
792 assert(NULL != band);
793
794
795 return band->pixtype;
796}
797
798uint16_t
800
801 assert(NULL != band);
802
803
804 return band->width;
805}
806
807uint16_t
809
810 assert(NULL != band);
811
812
813 return band->height;
814}
815
816/* Get ownsdata flag */
817int
819 assert(NULL != band);
820
821 return band->ownsdata ? 1 : 0;
822}
823
824/* set ownsdata flag */
825void
827 assert(NULL != band);
828
829 band->ownsdata = flag ? 1 : 0;
830}
831
832int
834 assert(NULL != band);
835
836 return band->hasnodata ? 1 : 0;
837}
838
839void
841
842 assert(NULL != band);
843
844 band->hasnodata = (flag) ? 1 : 0;
845
846 /* isnodata depends on hasnodata */
847 if (!band->hasnodata && band->isnodata) {
848 RASTER_DEBUG(3, "Setting isnodata to FALSE as band no longer has NODATA");
849 band->isnodata = 0;
850 }
851}
852
855 assert(NULL != band);
856
857 if (!band->hasnodata) {
858 /* silently permit setting isnodata flag to FALSE */
859 if (!flag)
860 band->isnodata = 0;
861 else {
862 rterror("rt_band_set_isnodata_flag: Cannot set isnodata flag as band has no NODATA");
863 return ES_ERROR;
864 }
865 }
866 else
867 band->isnodata = (flag) ? 1 : 0;
868
869 return ES_NONE;
870}
871
872int
874 assert(NULL != band);
875
876 if (band->hasnodata)
877 return band->isnodata ? 1 : 0;
878 else
879 return 0;
880}
881
892rt_band_set_nodata(rt_band band, double val, int *converted) {
893 rt_pixtype pixtype = PT_END;
894 int32_t checkvalint = 0;
895 uint32_t checkvaluint = 0;
896 float checkvalfloat = 0;
897 double checkvaldouble = 0;
898
899 assert(NULL != band);
900
901 if (converted != NULL)
902 *converted = 0;
903
904 pixtype = band->pixtype;
905
906 RASTER_DEBUGF(3, "rt_band_set_nodata: setting nodata value %g with band type %s", val, rt_pixtype_name(pixtype));
907
908 /* return -1 on out of range */
909 switch (pixtype) {
910 case PT_1BB: {
911 band->nodataval = rt_util_clamp_to_1BB(val);
912 checkvalint = band->nodataval;
913 break;
914 }
915 case PT_2BUI: {
916 band->nodataval = rt_util_clamp_to_2BUI(val);
917 checkvalint = band->nodataval;
918 break;
919 }
920 case PT_4BUI: {
921 band->nodataval = rt_util_clamp_to_4BUI(val);
922 checkvalint = band->nodataval;
923 break;
924 }
925 case PT_8BSI: {
926 band->nodataval = rt_util_clamp_to_8BSI(val);
927 checkvalint = band->nodataval;
928 break;
929 }
930 case PT_8BUI: {
931 band->nodataval = rt_util_clamp_to_8BUI(val);
932 checkvalint = band->nodataval;
933 break;
934 }
935 case PT_16BSI: {
936 band->nodataval = rt_util_clamp_to_16BSI(val);
937 checkvalint = band->nodataval;
938 break;
939 }
940 case PT_16BUI: {
941 band->nodataval = rt_util_clamp_to_16BUI(val);
942 checkvalint = band->nodataval;
943 break;
944 }
945 case PT_32BSI: {
946 band->nodataval = rt_util_clamp_to_32BSI(val);
947 checkvalint = band->nodataval;
948 break;
949 }
950 case PT_32BUI: {
951 band->nodataval = rt_util_clamp_to_32BUI(val);
952 checkvaluint = band->nodataval;
953 break;
954 }
955 case PT_16BF: {
956 float half = rt_util_clamp_to_16F(val);
957 /* Persist the exact half-float encoding so nodata comparisons stay bitwise-stable. */
958 band->nodataval = rt_util_float16_to_float(rt_util_float_to_float16(half));
959 checkvalfloat = (float)band->nodataval;
960 break;
961 }
962 case PT_32BF: {
963 band->nodataval = rt_util_clamp_to_32F(val);
964 checkvalfloat = band->nodataval;
965 break;
966 }
967 case PT_64BF: {
968 band->nodataval = val;
969 checkvaldouble = band->nodataval;
970 break;
971 }
972 default: {
973 rterror("rt_band_set_nodata: Unknown pixeltype %d", pixtype);
974 band->hasnodata = 0;
975 return ES_ERROR;
976 }
977 }
978
979 RASTER_DEBUGF(3, "rt_band_set_nodata: band->hasnodata = %d", band->hasnodata);
980 RASTER_DEBUGF(3, "rt_band_set_nodata: band->nodataval = %f", band->nodataval);
981 /* the nodata value was just set, so this band has NODATA */
982 band->hasnodata = 1;
983
984 /* also set isnodata flag to false */
985 band->isnodata = 0;
986
988 val,
989 checkvalint, checkvaluint,
990 checkvalfloat, checkvaldouble,
991 pixtype
992 ) && converted != NULL) {
993 *converted = 1;
994 }
995
996 return ES_NONE;
997}
998
1020 rt_band band,
1021 int x, int y,
1022 void *vals, uint32_t len
1023) {
1024 rt_pixtype pixtype = PT_END;
1025 int size = 0;
1026 uint8_t *data = NULL;
1027 uint32_t offset = 0;
1028
1029 assert(NULL != band);
1030 assert(vals != NULL && len > 0);
1031
1032 RASTER_DEBUGF(3, "length of values = %d", len);
1033
1034 if (band->offline) {
1035 rterror("rt_band_set_pixel_line not implemented yet for OFFDB bands");
1036 return ES_ERROR;
1037 }
1038
1039 pixtype = band->pixtype;
1040 size = rt_pixtype_size(pixtype);
1041
1042 if (
1043 x < 0 || x >= band->width ||
1044 y < 0 || y >= band->height
1045 ) {
1046 rterror("rt_band_set_pixel_line: Coordinates out of range (%d, %d) vs (%d, %d)", x, y, band->width, band->height);
1047 return ES_ERROR;
1048 }
1049
1050 data = rt_band_get_data(band);
1051 offset = x + (y * band->width);
1052 RASTER_DEBUGF(4, "offset = %d", offset);
1053
1054 /* make sure len of values to copy don't exceed end of data */
1055 if (len > (band->width * band->height) - offset) {
1056 rterror("rt_band_set_pixel_line: Could not apply pixels as values length exceeds end of data");
1057 return ES_ERROR;
1058 }
1059
1060 switch (pixtype) {
1061 case PT_1BB:
1062 case PT_2BUI:
1063 case PT_4BUI:
1064 case PT_8BUI:
1065 case PT_8BSI: {
1066 uint8_t *ptr = data;
1067 ptr += offset;
1068 memcpy(ptr, vals, (size_t)size * len);
1069 break;
1070 }
1071 case PT_16BUI: {
1072 uint16_t *ptr = (uint16_t *) data;
1073 ptr += offset;
1074 memcpy(ptr, vals, (size_t)size * len);
1075 break;
1076 }
1077 case PT_16BSI: {
1078 int16_t *ptr = (int16_t *) data;
1079 ptr += offset;
1080 memcpy(ptr, vals, (size_t)size * len);
1081 break;
1082 }
1083 case PT_32BUI: {
1084 uint32_t *ptr = (uint32_t *) data;
1085 ptr += offset;
1086 memcpy(ptr, vals, (size_t)size * len);
1087 break;
1088 }
1089 case PT_32BSI: {
1090 int32_t *ptr = (int32_t *) data;
1091 ptr += offset;
1092 memcpy(ptr, vals, (size_t)size * len);
1093 break;
1094 }
1095 case PT_32BF: {
1096 float *ptr = (float *) data;
1097 ptr += offset;
1098 memcpy(ptr, vals, (size_t)size * len);
1099 break;
1100 }
1101 case PT_64BF: {
1102 double *ptr = (double *) data;
1103 ptr += offset;
1104 memcpy(ptr, vals, (size_t)size * len);
1105 break;
1106 }
1107 default: {
1108 rterror("rt_band_set_pixel_line: Unknown pixeltype %d", pixtype);
1109 return ES_ERROR;
1110 }
1111 }
1112
1113#if POSTGIS_DEBUG_LEVEL > 0
1114 {
1115 double value;
1116 rt_band_get_pixel(band, x, y, &value, NULL);
1117 RASTER_DEBUGF(4, "pixel at (%d, %d) = %f", x, y, value);
1118 }
1119#endif
1120
1121 /* set band's isnodata flag to FALSE */
1124
1125 return ES_NONE;
1126}
1127
1141 rt_band band,
1142 int x, int y,
1143 double val,
1144 int *converted
1145) {
1146 rt_pixtype pixtype = PT_END;
1147 uint8_t *data = NULL;
1148 uint32_t offset = 0;
1149
1150 int32_t checkvalint = 0;
1151 uint32_t checkvaluint = 0;
1152 float checkvalfloat = 0;
1153 double checkvaldouble = 0;
1154
1155 assert(NULL != band);
1156
1157 if (converted != NULL)
1158 *converted = 0;
1159
1160 if (band->offline) {
1161 rterror("rt_band_set_pixel not implemented yet for OFFDB bands");
1162 return ES_ERROR;
1163 }
1164
1165 pixtype = band->pixtype;
1166
1167 if (
1168 x < 0 || x >= band->width ||
1169 y < 0 || y >= band->height
1170 ) {
1171 rterror("rt_band_set_pixel: Coordinates out of range");
1172 return ES_ERROR;
1173 }
1174
1175 /* check that clamped value isn't clamped NODATA */
1176 if (band->hasnodata && pixtype != PT_64BF) {
1177 double newval;
1178 int corrected;
1179
1180 rt_band_corrected_clamped_value(band, val, &newval, &corrected);
1181
1182 if (corrected) {
1183#if POSTGIS_RASTER_WARN_ON_TRUNCATION > 0
1184 rtwarn("Value for pixel %d x %d has been corrected as clamped value becomes NODATA", x, y);
1185#endif
1186 val = newval;
1187
1188 if (converted != NULL)
1189 *converted = 1;
1190 }
1191 }
1192
1193 data = rt_band_get_data(band);
1194 offset = x + (y * band->width);
1195
1196 switch (pixtype)
1197 {
1198 case PT_1BB: {
1199 data[offset] = rt_util_clamp_to_1BB(val);
1200 checkvalint = data[offset];
1201 break;
1202 }
1203 case PT_2BUI: {
1204 data[offset] = rt_util_clamp_to_2BUI(val);
1205 checkvalint = data[offset];
1206 break;
1207 }
1208 case PT_4BUI: {
1209 data[offset] = rt_util_clamp_to_4BUI(val);
1210 checkvalint = data[offset];
1211 break;
1212 }
1213 case PT_8BSI: {
1214 data[offset] = (uint8_t)rt_util_clamp_to_8BSI(val);
1215 checkvalint = (int8_t) data[offset];
1216 break;
1217 }
1218 case PT_8BUI: {
1219 data[offset] = rt_util_clamp_to_8BUI(val);
1220 checkvalint = data[offset];
1221 break;
1222 }
1223 case PT_16BSI: {
1224 int16_t *ptr = (int16_t*) data; /* we assume correct alignment */
1225 ptr[offset] = rt_util_clamp_to_16BSI(val);
1226 checkvalint = (int16_t) ptr[offset];
1227 break;
1228 }
1229 case PT_16BUI: {
1230 uint16_t *ptr = (uint16_t*) data; /* we assume correct alignment */
1231 ptr[offset] = rt_util_clamp_to_16BUI(val);
1232 checkvalint = ptr[offset];
1233 break;
1234 }
1235 case PT_32BSI: {
1236 int32_t *ptr = (int32_t*) data; /* we assume correct alignment */
1237 ptr[offset] = rt_util_clamp_to_32BSI(val);
1238 checkvalint = (int32_t) ptr[offset];
1239 break;
1240 }
1241 case PT_32BUI: {
1242 uint32_t *ptr = (uint32_t *)data; /* we assume correct alignment */
1243 ptr[offset] = rt_util_clamp_to_32BUI(val);
1244 checkvaluint = ptr[offset];
1245 break;
1246 }
1247 case PT_16BF: {
1248 uint16_t *ptr = (uint16_t *)data; /* we assume correct alignment */
1249 float clamped = rt_util_clamp_to_16F(val);
1250 /* Pack via explicit converter to mirror GDAL's Float16 representation. */
1251 ptr[offset] = rt_util_float_to_float16(clamped);
1252 checkvalfloat = rt_util_float16_to_float(ptr[offset]);
1253 break;
1254 }
1255 case PT_32BF: {
1256 float *ptr = (float *)data; /* we assume correct alignment */
1257 ptr[offset] = rt_util_clamp_to_32F(val);
1258 checkvalfloat = ptr[offset];
1259 break;
1260 }
1261 case PT_64BF: {
1262 double *ptr = (double*) data; /* we assume correct alignment */
1263 ptr[offset] = val;
1264 checkvaldouble = ptr[offset];
1265 break;
1266 }
1267 default: {
1268 rterror("rt_band_set_pixel: Unknown pixeltype %d", pixtype);
1269 return ES_ERROR;
1270 }
1271 }
1272
1273 /* If the stored value is not NODATA, reset the isnodata flag */
1274 if (!rt_band_clamped_value_is_nodata(band, val)) {
1275 RASTER_DEBUG(3, "Band has a value that is not NODATA. Setting isnodata to FALSE");
1276 band->isnodata = FALSE;
1277 }
1278
1279 /* Overflow checking */
1281 val,
1282 checkvalint, checkvaluint,
1283 checkvalfloat, checkvaldouble,
1284 pixtype
1285 ) && converted != NULL) {
1286 *converted = 1;
1287 }
1288
1289 return ES_NONE;
1290}
1291
1313 rt_band band,
1314 int x, int y,
1315 uint16_t len,
1316 void **vals, uint16_t *nvals
1317) {
1318 uint8_t *_vals = NULL;
1319 int pixsize = 0;
1320 uint8_t *data = NULL;
1321 uint32_t offset = 0;
1322 uint16_t _nvals = 0;
1323 int maxlen = 0;
1324 uint8_t *ptr = NULL;
1325
1326 assert(NULL != band);
1327 assert(vals != NULL && nvals != NULL);
1328
1329 /* initialize to no values */
1330 *nvals = 0;
1331
1332 if (
1333 x < 0 || x >= band->width ||
1334 y < 0 || y >= band->height
1335 ) {
1336 rtwarn("Attempting to get pixel values with out of range raster coordinates: (%d, %d)", x, y);
1337 return ES_ERROR;
1338 }
1339
1340 if (len < 1)
1341 return ES_NONE;
1342
1343 data = rt_band_get_data(band);
1344 if (data == NULL) {
1345 rterror("rt_band_get_pixel_line: Cannot get band data");
1346 return ES_ERROR;
1347 }
1348
1349 /* +1 for the nodata value */
1350 offset = x + (y * band->width);
1351 RASTER_DEBUGF(4, "offset = %d", offset);
1352
1353 pixsize = rt_pixtype_size(band->pixtype);
1354 RASTER_DEBUGF(4, "pixsize = %d", pixsize);
1355
1356 /* cap _nvals so that it doesn't overflow */
1357 _nvals = len;
1358 maxlen = band->width * band->height;
1359
1360 if (((int) (offset + _nvals)) > maxlen) {
1361 _nvals = maxlen - offset;
1362 rtwarn("Limiting returning number values to %d", _nvals);
1363 }
1364 RASTER_DEBUGF(4, "_nvals = %d", _nvals);
1365
1366 ptr = data + ((size_t)offset * pixsize);
1367
1368 _vals = rtalloc((size_t)_nvals * pixsize);
1369 if (_vals == NULL) {
1370 rterror("rt_band_get_pixel_line: Could not allocate memory for pixel values");
1371 return ES_ERROR;
1372 }
1373
1374 /* copy pixels */
1375 memcpy(_vals, ptr, (size_t)_nvals * pixsize);
1376
1377 *vals = _vals;
1378 *nvals = _nvals;
1379
1380 return ES_NONE;
1381}
1382
1397 rt_band band,
1398 double xr, double yr,
1399 rt_resample_type resample,
1400 double *r_value, int *r_nodata
1401)
1402{
1403 if (resample == RT_BILINEAR) {
1405 band, xr, yr, r_value, r_nodata
1406 );
1407 }
1408 else if (resample == RT_NEAREST) {
1409 return rt_band_get_pixel(
1410 band, floor(xr), floor(yr),
1411 r_value, r_nodata
1412 );
1413 }
1414 else {
1415 rtwarn("Invalid resample type requested %d", resample);
1416 return ES_ERROR;
1417 }
1418
1419}
1420
1436 rt_band band,
1437 double xr, double yr,
1438 double *r_value, int *r_nodata)
1439{
1440 double xcenter, ycenter;
1441 double values[2][2];
1442 double nodatavalue = 0.0;
1443 int nodatas[2][2];
1444 int x[2][2];
1445 int y[2][2];
1446 int xcell, ycell;
1447 int xdir, ydir;
1448 int i, j;
1449 uint16_t width, height;
1450
1451 /* Cell coordinates */
1452 xcell = (int)floor(xr);
1453 ycell = (int)floor(yr);
1454 xcenter = xcell + 0.5;
1455 ycenter = ycell + 0.5;
1456
1457 /* Raster geometry */
1458 width = rt_band_get_width(band);
1459 height = rt_band_get_height(band);
1460
1461 /* Reject out-of-range sample */
1462 if(xcell < 0 || ycell < 0 || xcell >= width || ycell >= height) {
1463 rtwarn("Attempting to get pixel value with out of range raster coordinates: (%d, %d)", xcell, ycell);
1464 return ES_ERROR;
1465 }
1466
1467 /* Quadrant of 2x2 grid the raster coordinate falls in */
1468 xdir = xr < xcenter ? 1 : 0;
1469 ydir = yr < ycenter ? 1 : 0;
1470
1471 if (rt_band_get_hasnodata_flag(band) != FALSE) {
1472 rt_band_get_nodata(band, &nodatavalue);
1473 }
1474 else {
1475 nodatavalue = 0.0;
1476 }
1477
1478 /* Read the 2x2 values from the band */
1479 for (i = 0; i < 2; i++) {
1480 for (j = 0; j < 2; j++) {
1481 double value = nodatavalue;
1482 int nodata = 0;
1483 int xij = xcell + (i - xdir);
1484 int yij = ycell + (j - ydir);
1485
1486 if(xij < 0 || yij < 0 || xij >= width || yij >= height) {
1487 nodata = 1;
1488 }
1489 else {
1491 band, xij, yij,
1492 &value, &nodata
1493 );
1494 if (err != ES_NONE)
1495 nodata = 1;
1496 }
1497 x[i][j] = xij;
1498 y[i][j] = yij;
1499 values[i][j] = value;
1500 nodatas[i][j] = nodata;
1501 }
1502 }
1503
1504 /* Point falls in nodata cell, just return nodata */
1505 if (nodatas[xdir][ydir]) {
1506 *r_value = nodatavalue;
1507 *r_nodata = 1;
1508 return ES_NONE;
1509 }
1510
1511 /* Normalize raster coordinate to the bottom left */
1512 /* so we are working on a unit square */
1513 xr = xr - (x[0][0] + 0.5);
1514 yr = yr - (y[0][0] + 0.5);
1515
1516 /* Point is in cell with values, so we take nodata */
1517 /* neighbors off the table by matching them to the */
1518 /* most controlling cell */
1519 for (i = 0; i < 2; i++) {
1520 for (j = 0; j < 2; j++) {
1521 if (nodatas[i][j])
1522 values[i][j] = values[xdir][ydir];
1523 }
1524 }
1525
1526 /* Calculate bilinear value */
1527 /* https://en.wikipedia.org/wiki/Bilinear_interpolation#Unit_square */
1528 *r_nodata = 0;
1529 *r_value = values[0][0] * (1-xr) * (1-yr) +
1530 values[1][0] * (1-yr) * xr +
1531 values[0][1] * (1-xr) * yr +
1532 values[1][1] * xr * yr;
1533
1534 return ES_NONE;
1535}
1536
1537
1552 rt_band band,
1553 int x, int y,
1554 double *value,
1555 int *nodata
1556) {
1557 rt_pixtype pixtype = PT_END;
1558 uint8_t* data = NULL;
1559 uint32_t offset = 0;
1560
1561 assert(NULL != band);
1562 assert(NULL != value);
1563
1564 /* set nodata to 0 */
1565 if (nodata != NULL)
1566 *nodata = 0;
1567
1568 if (
1569 x < 0 || x >= band->width ||
1570 y < 0 || y >= band->height
1571 ) {
1572 rtwarn("Attempting to get pixel value with out of range raster coordinates: (%d, %d)", x, y);
1573 return ES_ERROR;
1574 }
1575
1576 /* band is NODATA */
1577 if (band->isnodata) {
1578 RASTER_DEBUG(3, "Band's isnodata flag is TRUE. Returning NODATA value");
1579 *value = band->nodataval;
1580 if (nodata != NULL) *nodata = 1;
1581 return ES_NONE;
1582 }
1583
1584 data = rt_band_get_data(band);
1585 if (data == NULL) {
1586 rterror("rt_band_get_pixel: Cannot get band data");
1587 return ES_ERROR;
1588 }
1589
1590 /* +1 for the nodata value */
1591 offset = x + (y * band->width);
1592
1593 pixtype = band->pixtype;
1594
1595 switch (pixtype) {
1596 case PT_1BB:
1597#ifdef OPTIMIZE_SPACE
1598 {
1599 int byteOffset = offset / 8;
1600 int bitOffset = offset % 8;
1601 data += byteOffset;
1602
1603 /* Bit to set is bitOffset into data */
1604 *value = getBits(data, val, 1, bitOffset);
1605 break;
1606 }
1607#endif
1608 case PT_2BUI:
1609#ifdef OPTIMIZE_SPACE
1610 {
1611 int byteOffset = offset / 4;
1612 int bitOffset = offset % 4;
1613 data += byteOffset;
1614
1615 /* Bits to set start at bitOffset into data */
1616 *value = getBits(data, val, 2, bitOffset);
1617 break;
1618 }
1619#endif
1620 case PT_4BUI:
1621#ifdef OPTIMIZE_SPACE
1622 {
1623 int byteOffset = offset / 2;
1624 int bitOffset = offset % 2;
1625 data += byteOffset;
1626
1627 /* Bits to set start at bitOffset into data */
1628 *value = getBits(data, val, 2, bitOffset);
1629 break;
1630 }
1631#endif
1632 case PT_8BSI: {
1633 int8_t val = (int8_t)data[offset];
1634 *value = val;
1635 break;
1636 }
1637 case PT_8BUI: {
1638 uint8_t val = data[offset];
1639 *value = val;
1640 break;
1641 }
1642 case PT_16BSI: {
1643 int16_t *ptr = (int16_t*) data; /* we assume correct alignment */
1644 *value = ptr[offset];
1645 break;
1646 }
1647 case PT_16BUI: {
1648 uint16_t *ptr = (uint16_t*) data; /* we assume correct alignment */
1649 *value = ptr[offset];
1650 break;
1651 }
1652 case PT_32BSI: {
1653 int32_t *ptr = (int32_t*) data; /* we assume correct alignment */
1654 *value = ptr[offset];
1655 break;
1656 }
1657 case PT_32BUI: {
1658 uint32_t *ptr = (uint32_t *)data; /* we assume correct alignment */
1659 *value = ptr[offset];
1660 break;
1661 }
1662 case PT_16BF: {
1663 uint16_t *ptr = (uint16_t *)data; /* we assume correct alignment */
1664 *value = rt_util_float16_to_float(ptr[offset]);
1665 break;
1666 }
1667 case PT_32BF: {
1668 float *ptr = (float *)data; /* we assume correct alignment */
1669 *value = ptr[offset];
1670 break;
1671 }
1672 case PT_64BF: {
1673 double *ptr = (double*) data; /* we assume correct alignment */
1674 *value = ptr[offset];
1675 break;
1676 }
1677 default: {
1678 rterror("rt_band_get_pixel: Unknown pixeltype %d", pixtype);
1679 return ES_ERROR;
1680 }
1681 }
1682
1683 /* set NODATA flag */
1684 if (band->hasnodata && nodata != NULL) {
1685 if (rt_band_clamped_value_is_nodata(band, *value))
1686 *nodata = 1;
1687 }
1688
1689 return ES_NONE;
1690}
1691
1710 rt_band band,
1711 int x, int y,
1712 uint16_t distancex, uint16_t distancey,
1713 int exclude_nodata_value,
1714 rt_pixel *npixels
1715) {
1716 rt_pixel npixel = NULL;
1717 int extent[4] = {0};
1718 int max_extent[4] = {0};
1719 int d0 = 0;
1720 uint32_t distance[2] = {0};
1721 uint32_t _d[2] = {0};
1722 uint32_t i = 0;
1723 uint32_t j = 0;
1724 uint32_t k = 0;
1725 int _max = 0;
1726 int _x = 0;
1727 int _y = 0;
1728 int *_min = NULL;
1729 double pixval = 0;
1730 double minval = 0;
1731 uint32_t count = 0;
1732 int isnodata = 0;
1733
1734 int inextent = 0;
1735
1736 assert(NULL != band);
1737 assert(NULL != npixels);
1738
1739 RASTER_DEBUG(3, "Starting");
1740
1741 /* process distance */
1742 distance[0] = distancex;
1743 distance[1] = distancey;
1744
1745 /* no distance, means get nearest pixels and return */
1746 if (!distance[0] && !distance[1])
1747 d0 = 1;
1748
1749 RASTER_DEBUGF(4, "Selected pixel: %d x %d", x, y);
1750 RASTER_DEBUGF(4, "Distances: %d x %d", distance[0], distance[1]);
1751
1752 /* shortcuts if outside band extent */
1753 if (
1754 exclude_nodata_value && (
1755 (x < 0 || x > band->width) ||
1756 (y < 0 || y > band->height)
1757 )
1758 ) {
1759 /* no distances specified, jump to pixel close to extent */
1760 if (d0) {
1761 if (x < 0)
1762 x = -1;
1763 else if (x > band->width)
1764 x = band->width;
1765
1766 if (y < 0)
1767 y = -1;
1768 else if (y > band->height)
1769 y = band->height;
1770
1771 RASTER_DEBUGF(4, "Moved selected pixel: %d x %d", x, y);
1772 }
1773 /*
1774 distances specified
1775 if distances won't capture extent of band, return 0
1776 */
1777 else if (
1778 ((x < 0 && (uint32_t) abs(x) > distance[0]) || (x - band->width >= (int)distance[0])) ||
1779 ((y < 0 && (uint32_t) abs(y) > distance[1]) || (y - band->height >= (int)distance[1]))
1780 ) {
1781 RASTER_DEBUG(4, "No nearest pixels possible for provided pixel and distances");
1782 return 0;
1783 }
1784 }
1785
1786 /* no NODATA, exclude is FALSE */
1787 if (!band->hasnodata)
1788 exclude_nodata_value = FALSE;
1789 /* band is NODATA and excluding NODATA */
1790 else if (exclude_nodata_value && band->isnodata) {
1791 RASTER_DEBUG(4, "No nearest pixels possible as band is NODATA and excluding NODATA values");
1792 return 0;
1793 }
1794
1795 /* determine the maximum distance to prevent an infinite loop */
1796 if (d0) {
1797 int a, b;
1798
1799 /* X axis */
1800 a = abs(x);
1801 b = abs(x - band->width);
1802
1803 if (a > b)
1804 distance[0] = a;
1805 else
1806 distance[0] = b;
1807
1808 /* Y axis */
1809 a = abs(y);
1810 b = abs(y - band->height);
1811 if (a > b)
1812 distance[1] = a;
1813 else
1814 distance[1] = b;
1815
1816 RASTER_DEBUGF(4, "Maximum distances: %d x %d", distance[0], distance[1]);
1817 }
1818
1819 /* minimum possible value for pixel type */
1820 minval = rt_pixtype_get_min_value(band->pixtype);
1821 RASTER_DEBUGF(4, "pixtype: %s", rt_pixtype_name(band->pixtype));
1822 RASTER_DEBUGF(4, "minval: %f", minval);
1823
1824 /* set variables */
1825 count = 0;
1826 *npixels = NULL;
1827
1828 /* maximum extent */
1829 max_extent[0] = x - (int)distance[0]; /* min X */
1830 max_extent[1] = y - (int)distance[1]; /* min Y */
1831 max_extent[2] = x + (int)distance[0]; /* max X */
1832 max_extent[3] = y + (int)distance[1]; /* max Y */
1833 RASTER_DEBUGF(4, "Maximum Extent: (%d, %d, %d, %d)",
1834 max_extent[0], max_extent[1], max_extent[2], max_extent[3]);
1835
1836 _d[0] = 0;
1837 _d[1] = 0;
1838 do {
1839 _d[0]++;
1840 _d[1]++;
1841
1842 extent[0] = x - (int)_d[0]; /* min x */
1843 extent[1] = y - (int)_d[1]; /* min y */
1844 extent[2] = x + (int)_d[0]; /* max x */
1845 extent[3] = y + (int)_d[1]; /* max y */
1846
1847 RASTER_DEBUGF(4, "Processing distances: %d x %d", _d[0], _d[1]);
1848 RASTER_DEBUGF(4, "Extent: (%d, %d, %d, %d)",
1849 extent[0], extent[1], extent[2], extent[3]);
1850
1851 for (i = 0; i < 2; i++) {
1852
1853 /* by row */
1854 if (i < 1)
1855 _max = extent[2] - extent[0] + 1;
1856 /* by column */
1857 else
1858 _max = extent[3] - extent[1] + 1;
1859 _max = abs(_max);
1860
1861 for (j = 0; j < 2; j++) {
1862 /* by row */
1863 if (i < 1) {
1864 _x = extent[0];
1865 _min = &_x;
1866
1867 /* top row */
1868 if (j < 1)
1869 _y = extent[1];
1870 /* bottom row */
1871 else
1872 _y = extent[3];
1873 }
1874 /* by column */
1875 else {
1876 _y = extent[1] + 1;
1877 _min = &_y;
1878
1879 /* left column */
1880 if (j < 1) {
1881 _x = extent[0];
1882 _max -= 2;
1883 }
1884 /* right column */
1885 else
1886 _x = extent[2];
1887 }
1888
1889 RASTER_DEBUGF(4, "_min, _max: %d, %d", *_min, _max);
1890 for (k = 0; k < (uint32_t) _max; k++) {
1891 /* check that _x and _y are not outside max extent */
1892 if (
1893 _x < max_extent[0] || _x > max_extent[2] ||
1894 _y < max_extent[1] || _y > max_extent[3]
1895 ) {
1896 (*_min)++;
1897 continue;
1898 }
1899
1900 /* outside band extent, set to NODATA */
1901 if (
1902 (_x < 0 || _x >= band->width) ||
1903 (_y < 0 || _y >= band->height)
1904 ) {
1905 /* no NODATA, set to minimum possible value */
1906 if (!band->hasnodata)
1907 pixval = minval;
1908 /* has NODATA, use NODATA */
1909 else
1910 pixval = band->nodataval;
1911 RASTER_DEBUGF(4, "NODATA pixel outside band extent: (x, y, val) = (%d, %d, %f)", _x, _y, pixval);
1912 inextent = 0;
1913 isnodata = 1;
1914 }
1915 else {
1917 band,
1918 _x, _y,
1919 &pixval,
1920 &isnodata
1921 ) != ES_NONE) {
1922 rterror("rt_band_get_nearest_pixel: Could not get pixel value");
1923 if (count) rtdealloc(*npixels);
1924 return -1;
1925 }
1926 RASTER_DEBUGF(4, "Pixel: (x, y, val) = (%d, %d, %f)", _x, _y, pixval);
1927 inextent = 1;
1928 }
1929
1930 /* use pixval? */
1931 if (!exclude_nodata_value || (exclude_nodata_value && !isnodata)) {
1932 /* add pixel to result set */
1933 RASTER_DEBUGF(4, "Adding pixel to set of nearest pixels: (x, y, val) = (%d, %d, %f)", _x, _y, pixval);
1934 count++;
1935
1936 if (*npixels == NULL)
1937 *npixels = (rt_pixel) rtalloc(sizeof(struct rt_pixel_t) * count);
1938 else
1939 *npixels = (rt_pixel) rtrealloc(*npixels, sizeof(struct rt_pixel_t) * count);
1940 if (*npixels == NULL) {
1941 rterror("rt_band_get_nearest_pixel: Could not allocate memory for nearest pixel(s)");
1942 return -1;
1943 }
1944
1945 npixel = &((*npixels)[count - 1]);
1946 npixel->x = _x;
1947 npixel->y = _y;
1948 npixel->value = pixval;
1949
1950 /* special case for when outside band extent */
1951 if (!inextent && !band->hasnodata)
1952 npixel->nodata = 1;
1953 else
1954 npixel->nodata = 0;
1955 }
1956
1957 (*_min)++;
1958 }
1959 }
1960 }
1961
1962 /* distance thresholds met */
1963 if (_d[0] >= distance[0] && _d[1] >= distance[1])
1964 break;
1965 else if (d0 && count)
1966 break;
1967 }
1968 while (1);
1969
1970 RASTER_DEBUGF(3, "Nearest pixels in return: %d", count);
1971
1972 return count;
1973}
1974
1975
1976
1988int
1990 rt_band band, int exclude_nodata_value,
1991 double *searchset, int searchcount,
1992 rt_pixel *pixels
1993) {
1994 int x;
1995 int y;
1996 int i;
1997 double pixval;
1998 int err;
1999 int count = 0;
2000 int isnodata = 0;
2001 int isequal = 0;
2002
2003 rt_pixel pixel = NULL;
2004
2005 assert(NULL != band);
2006 assert(NULL != pixels);
2007 assert(NULL != searchset && searchcount > 0);
2008
2009 if (!band->hasnodata)
2010 exclude_nodata_value = FALSE;
2011 /* band is NODATA and exclude_nodata_value = TRUE, nothing to search */
2012 else if (exclude_nodata_value && band->isnodata) {
2013 RASTER_DEBUG(4, "Pixels cannot be searched as band is NODATA and excluding NODATA values");
2014 return 0;
2015 }
2016
2017 for (x = 0; x < band->width; x++) {
2018 for (y = 0; y < band->height; y++) {
2019 err = rt_band_get_pixel(band, x, y, &pixval, &isnodata);
2020 if (err != ES_NONE) {
2021 rterror("rt_band_get_pixel_of_value: Cannot get band pixel");
2022 return -1;
2023 }
2024 else if (exclude_nodata_value && isnodata)
2025 continue;
2026
2027 for (i = 0; i < searchcount; i++) {
2028 if (rt_pixtype_compare_clamped_values(band->pixtype, searchset[i], pixval, &isequal) != ES_NONE) {
2029 continue;
2030 }
2031
2032 if (FLT_NEQ(pixval, searchset[i]) || !isequal)
2033 continue;
2034
2035 /* match found */
2036 count++;
2037 if (*pixels == NULL)
2038 *pixels = (rt_pixel) rtalloc(sizeof(struct rt_pixel_t) * count);
2039 else
2040 *pixels = (rt_pixel) rtrealloc(*pixels, sizeof(struct rt_pixel_t) * count);
2041 if (*pixels == NULL) {
2042 rterror("rt_band_get_pixel_of_value: Could not allocate memory for pixel(s)");
2043 return -1;
2044 }
2045
2046 pixel = &((*pixels)[count - 1]);
2047 pixel->x = x;
2048 pixel->y = y;
2049 pixel->nodata = 0;
2050 pixel->value = pixval;
2051 }
2052 }
2053 }
2054
2055 return count;
2056}
2057
2067rt_band_get_nodata(rt_band band, double *nodata) {
2068 assert(NULL != band);
2069 assert(NULL != nodata);
2070
2071 *nodata = band->nodataval;
2072
2073 if (!band->hasnodata) {
2074 rterror("rt_band_get_nodata: Band has no NODATA value");
2075 return ES_ERROR;
2076 }
2077
2078 return ES_NONE;
2079}
2080
2081double
2083 assert(NULL != band);
2084
2085 return rt_pixtype_get_min_value(band->pixtype);
2086}
2087
2088int
2090 int i, j, err;
2091 double pxValue;
2092 int isnodata = 0;
2093
2094 assert(NULL != band);
2095 band->isnodata = FALSE;
2096
2097 /* Check if band has nodata value */
2098 if (!band->hasnodata) {
2099 RASTER_DEBUG(3, "Band has no NODATA value");
2100 return FALSE;
2101 }
2102
2103 pxValue = band->nodataval;
2104
2105 /* Check all pixels */
2106 for (i = 0; i < band->width; i++) {
2107 for (j = 0; j < band->height; j++) {
2108 err = rt_band_get_pixel(band, i, j, &pxValue, &isnodata);
2109 if (err != ES_NONE) {
2110 rterror("rt_band_check_is_nodata: Cannot get band pixel");
2111 return FALSE;
2112 }
2113 else if (!isnodata) {
2114 band->isnodata = FALSE;
2115 return FALSE;
2116 }
2117 }
2118 }
2119
2120 band->isnodata = TRUE;
2121 return TRUE;
2122}
2123
2134int
2136 int isequal = 0;
2137
2138 assert(NULL != band);
2139
2140 /* no NODATA, so never equal */
2141 if (!band->hasnodata)
2142 return 0;
2143
2144 /* value is exactly NODATA */
2145 if (FLT_EQ(val, band->nodataval))
2146 return 2;
2147
2148 /* ignore error from rt_pixtype_compare_clamped_values */
2150 band->pixtype,
2151 val, band->nodataval,
2152 &isequal
2153 );
2154
2155 return isequal ? 1 : 0;
2156}
2157
2172 rt_band band,
2173 double val,
2174 double *newval, int *corrected
2175) {
2176 double minval = 0.;
2177
2178 assert(NULL != band);
2179 assert(NULL != newval);
2180
2181 if (corrected != NULL)
2182 *corrected = 0;
2183
2184 /* no need to correct if clamped values IS NOT clamped NODATA */
2185 if (rt_band_clamped_value_is_nodata(band, val) != 1) {
2186 *newval = val;
2187 return ES_NONE;
2188 }
2189
2190 minval = rt_pixtype_get_min_value(band->pixtype);
2191 *newval = val;
2192
2193 switch (band->pixtype) {
2194 case PT_1BB:
2195 *newval = !band->nodataval;
2196 break;
2197 case PT_2BUI:
2198 if (rt_util_clamp_to_2BUI(val) == rt_util_clamp_to_2BUI(minval))
2199 (*newval)++;
2200 else
2201 (*newval)--;
2202 break;
2203 case PT_4BUI:
2204 if (rt_util_clamp_to_4BUI(val) == rt_util_clamp_to_4BUI(minval))
2205 (*newval)++;
2206 else
2207 (*newval)--;
2208 break;
2209 case PT_8BSI:
2210 if (rt_util_clamp_to_8BSI(val) == rt_util_clamp_to_8BSI(minval))
2211 (*newval)++;
2212 else
2213 (*newval)--;
2214 break;
2215 case PT_8BUI:
2216 if (rt_util_clamp_to_8BUI(val) == rt_util_clamp_to_8BUI(minval))
2217 (*newval)++;
2218 else
2219 (*newval)--;
2220 break;
2221 case PT_16BSI:
2223 (*newval)++;
2224 else
2225 (*newval)--;
2226 break;
2227 case PT_16BUI:
2229 (*newval)++;
2230 else
2231 (*newval)--;
2232 break;
2233 case PT_32BSI:
2235 (*newval)++;
2236 else
2237 (*newval)--;
2238 break;
2239 case PT_32BUI:
2241 (*newval)++;
2242 else
2243 (*newval)--;
2244 break;
2245 case PT_16BF:
2247 *newval += FLT_EPSILON;
2248 else
2249 *newval -= FLT_EPSILON;
2250 break;
2251 case PT_32BF:
2253 *newval += FLT_EPSILON;
2254 else
2255 *newval -= FLT_EPSILON;
2256 break;
2257 case PT_64BF:
2258 break;
2259 default:
2260 rterror("rt_band_corrected_clamped_value: Unknown pixeltype %d", band->pixtype);
2261 return ES_ERROR;
2262 }
2263
2264 if (corrected != NULL)
2265 *corrected = 1;
2266
2267 return ES_NONE;
2268}
#define TRUE
Definition dbfopen.c:73
#define FALSE
Definition dbfopen.c:72
void rterror(const char *fmt,...) __attribute__((format(printf
Wrappers used for reporting errors and info.
void * rtalloc(size_t size)
Wrappers used for managing memory.
Definition rt_context.c:191
rt_pixtype rt_util_gdal_datatype_to_pixtype(GDALDataType gdt)
Convert GDALDataType to rt_pixtype.
Definition rt_util.c:255
#define FLT_NEQ(x, y)
Definition librtcore.h:2435
#define RASTER_DEBUG(level, msg)
Definition librtcore.h:304
int rt_util_gdal_register_all(int force_register_all)
Definition rt_util.c:444
#define RASTER_DEBUGF(level, msg,...)
Definition librtcore.h:308
void rt_raster_set_geotransform_matrix(rt_raster raster, double *gt)
Set raster's geotransform using 6-element array.
Definition rt_raster.c:609
int8_t rt_util_clamp_to_8BSI(double value)
Definition rt_util.c:51
uint8_t rt_util_clamp_to_1BB(double value)
Definition rt_util.c:36
float rt_util_clamp_to_16F(double value)
Definition rt_util.c:88
void void void rtwarn(const char *fmt,...) __attribute__((format(printf
int32_t rt_util_clamp_to_32BSI(double value)
Definition rt_util.c:71
uint16_t rt_util_float_to_float16(float value)
Definition rt_util.c:101
float rt_util_float16_to_float(uint16_t value)
Definition rt_util.c:134
rt_errorstate rt_raster_geopoint_to_cell(rt_raster raster, double xw, double yw, double *xr, double *yr, double *igt)
Convert an xw, yw map point to a xr, yr raster point.
Definition rt_raster.c:686
void rt_raster_destroy(rt_raster raster)
Release memory associated to a raster.
Definition rt_raster.c:86
rt_pixtype
Definition librtcore.h:188
@ PT_32BUI
Definition librtcore.h:197
@ PT_16BF
Definition librtcore.h:198
@ PT_2BUI
Definition librtcore.h:190
@ PT_32BSI
Definition librtcore.h:196
@ PT_END
Definition librtcore.h:201
@ PT_4BUI
Definition librtcore.h:191
@ PT_32BF
Definition librtcore.h:199
@ PT_1BB
Definition librtcore.h:189
@ PT_16BUI
Definition librtcore.h:195
@ PT_8BSI
Definition librtcore.h:192
@ PT_16BSI
Definition librtcore.h:194
@ PT_64BF
Definition librtcore.h:200
@ PT_8BUI
Definition librtcore.h:193
rt_raster rt_raster_new(uint32_t width, uint32_t height)
Construct a raster with given dimensions.
Definition rt_raster.c:52
int rt_util_dbl_trunc_warning(double initialvalue, int32_t checkvalint, uint32_t checkvaluint, float checkvalfloat, double checkvaldouble, rt_pixtype pixtype)
Definition rt_util.c:778
GDALDataType rt_util_pixtype_to_gdal_datatype(rt_pixtype pt)
Convert rt_pixtype to GDALDataType.
Definition rt_util.c:213
double rt_pixtype_get_min_value(rt_pixtype pixtype)
Return minimum value possible for pixel type.
Definition rt_pixel.c:156
struct rt_pixel_t * rt_pixel
Definition librtcore.h:148
#define FLT_EQ(x, y)
Definition librtcore.h:2436
rt_raster rt_raster_from_gdal_dataset(GDALDatasetH ds)
Return a raster from a GDAL dataset.
Definition rt_raster.c:2175
rt_resample_type
Definition librtcore.h:1478
@ RT_BILINEAR
Definition librtcore.h:1480
@ RT_NEAREST
Definition librtcore.h:1479
uint8_t rt_util_clamp_to_2BUI(double value)
Definition rt_util.c:41
const char * rt_pixtype_name(rt_pixtype pixtype)
Definition rt_pixel.c:114
rt_errorstate rt_pixtype_compare_clamped_values(rt_pixtype pixtype, double val, double refval, int *isequal)
Test to see if two values are equal when clamped.
Definition rt_pixel.c:211
uint8_t rt_util_clamp_to_8BUI(double value)
Definition rt_util.c:56
GDALDatasetH rt_util_gdal_open(const char *fn, GDALAccess fn_access, int shared)
Definition rt_util.c:491
rt_errorstate
Enum definitions.
Definition librtcore.h:181
@ ES_NONE
Definition librtcore.h:182
@ ES_ERROR
Definition librtcore.h:183
int16_t rt_util_clamp_to_16BSI(double value)
Definition rt_util.c:61
void * rtrealloc(void *mem, size_t size)
Definition rt_context.c:199
void rt_raster_set_srid(rt_raster raster, int32_t srid)
Set raster's SRID.
Definition rt_raster.c:367
uint8_t rt_util_clamp_to_4BUI(double value)
Definition rt_util.c:46
void rtdealloc(void *mem)
Definition rt_context.c:206
uint16_t rt_util_clamp_to_16BUI(double value)
Definition rt_util.c:66
uint32_t rt_util_clamp_to_32BUI(double value)
Definition rt_util.c:76
float rt_util_clamp_to_32F(double value)
Definition rt_util.c:81
rt_errorstate rt_raster_same_alignment(rt_raster rast1, rt_raster rast2, int *aligned, char **reason)
int rt_pixtype_size(rt_pixtype pixtype)
Return size in bytes of a value in the given pixtype.
Definition rt_pixel.c:40
rt_band rt_raster_get_band(rt_raster raster, int bandNum)
Return Nth band, or NULL if unavailable.
Definition rt_raster.c:385
This library is the generic raster handling section of PostGIS.
static double distance(double x1, double y1, double x2, double y2)
Definition lwtree.c:1032
void rt_band_init_value(rt_band band, double initval)
Fill in the cells of a band with a starting value frequently used to init with nodata value.
Definition rt_band.c:113
rt_band rt_band_new_inline(uint16_t width, uint16_t height, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, uint8_t *data)
Create an in-db rt_band with no data.
Definition rt_band.c:64
void rt_band_set_ownsdata_flag(rt_band band, int flag)
Definition rt_band.c:826
int rt_band_get_pixel_of_value(rt_band band, int exclude_nodata_value, double *searchset, int searchcount, rt_pixel *pixels)
Search band for pixel(s) with search values.
Definition rt_band.c:1989
rt_band rt_band_duplicate(rt_band band)
Create a new band duplicated from source band.
Definition rt_band.c:446
uint16_t rt_band_get_width(rt_band band)
Return width of this band.
Definition rt_band.c:799
void rt_band_set_hasnodata_flag(rt_band band, int flag)
Set hasnodata flag value.
Definition rt_band.c:840
rt_errorstate rt_band_set_isnodata_flag(rt_band band, int flag)
Set isnodata flag value.
Definition rt_band.c:854
rt_errorstate rt_band_load_offline_data(rt_band band)
Load offline band's data.
Definition rt_band.c:588
int rt_band_get_hasnodata_flag(rt_band band)
Get hasnodata flag value.
Definition rt_band.c:833
void * rt_band_get_data(rt_band band)
Get pointer to raster band data.
Definition rt_band.c:559
rt_errorstate rt_band_get_pixel(rt_band band, int x, int y, double *value, int *nodata)
Get pixel value.
Definition rt_band.c:1551
int rt_band_get_isnodata_flag(rt_band band)
Get isnodata flag value.
Definition rt_band.c:873
double rt_band_get_min_value(rt_band band)
Returns the minimal possible value for the band according to the pixel type.
Definition rt_band.c:2082
uint64_t rt_band_get_file_size(rt_band band)
Return file size in bytes.
Definition rt_band.c:745
bool enable_outdb_rasters
Definition rt_band.c:576
int rt_band_check_is_nodata(rt_band band)
Returns TRUE if the band is only nodata values.
Definition rt_band.c:2089
rt_errorstate rt_band_set_nodata(rt_band band, double val, int *converted)
Set nodata value.
Definition rt_band.c:892
rt_errorstate rt_band_set_pixel(rt_band band, int x, int y, double val, int *converted)
Set single pixel's value.
Definition rt_band.c:1140
rt_errorstate rt_band_set_pixel_line(rt_band band, int x, int y, void *vals, uint32_t len)
Set values of multiple pixels.
Definition rt_band.c:1019
void rt_band_destroy(rt_band band)
Destroy a raster band.
Definition rt_band.c:499
rt_errorstate rt_band_corrected_clamped_value(rt_band band, double val, double *newval, int *corrected)
Correct value when clamped value is equal to clamped NODATA value.
Definition rt_band.c:2171
rt_band rt_band_new_offline(uint16_t width, uint16_t height, rt_pixtype pixtype, uint32_t hasnodata, double nodataval, uint8_t bandNum, const char *path)
Create an out-db rt_band.
Definition rt_band.c:283
rt_errorstate rt_band_get_ext_band_num(rt_band band, uint8_t *bandnum)
Return bands' external band number (only valid when rt_band_is_offline returns non-zero).
Definition rt_band.c:535
uint64_t rt_band_get_file_timestamp(rt_band band)
Return file timestamp.
Definition rt_band.c:767
rt_errorstate rt_band_get_pixel_resample(rt_band band, double xr, double yr, rt_resample_type resample, double *r_value, int *r_nodata)
Retrieve a point value from the raster using a world coordinate and selected interpolation.
Definition rt_band.c:1396
rt_errorstate rt_band_get_nodata(rt_band band, double *nodata)
Get NODATA value.
Definition rt_band.c:2067
rt_pixtype rt_band_get_pixtype(rt_band band)
Return pixeltype of this band.
Definition rt_band.c:790
const char * rt_band_get_ext_path(rt_band band)
Return band's external path (only valid when rt_band_is_offline returns non-zero).
Definition rt_band.c:522
rt_band rt_band_new_offline_from_path(uint16_t width, uint16_t height, int hasnodata, double nodataval, uint8_t bandNum, const char *path, int force)
Create an out-db rt_band from path.
Definition rt_band.c:358
uint32_t rt_band_get_nearest_pixel(rt_band band, int x, int y, uint16_t distancex, uint16_t distancey, int exclude_nodata_value, rt_pixel *npixels)
Get nearest pixel(s) with value (not NODATA) to specified pixel.
Definition rt_band.c:1709
rt_errorstate rt_band_get_pixel_bilinear(rt_band band, double xr, double yr, double *r_value, int *r_nodata)
Retrieve a point value from the raster using a world coordinate and bilinear interpolation.
Definition rt_band.c:1435
int rt_band_clamped_value_is_nodata(rt_band band, double val)
Compare clamped value to band's clamped NODATA value.
Definition rt_band.c:2135
int rt_band_get_ownsdata_flag(rt_band band)
Return 0 (FALSE) or non-zero (TRUE) indicating if rt_band is responsible for managing the memory for ...
Definition rt_band.c:818
int rt_band_is_offline(rt_band band)
Return non-zero if the given band data is on the filesystem.
Definition rt_band.c:488
uint16_t rt_band_get_height(rt_band band)
Return height of this band.
Definition rt_band.c:808
rt_errorstate rt_band_get_pixel_line(rt_band band, int x, int y, uint16_t len, void **vals, uint16_t *nvals)
Get values of multiple pixels.
Definition rt_band.c:1312
union rt_band_t::@12 data
void * mem
Definition librtcore.h:2529
double value
Definition librtcore.h:2540
uint8_t nodata
Definition librtcore.h:2539