1 /*
2  *
3  * WKTRaster - Raster Types for PostGIS
4  * http://trac.osgeo.org/postgis/wiki/WKTRaster
5  *
6  * Copyright (C) 2011-2013 Regents of the University of California
7  *   <bkpark@ucdavis.edu>
8  * Copyright (C) 2010-2011 Jorge Arevalo <jorge.arevalo@deimos-space.com>
9  * Copyright (C) 2010-2011 David Zwarg <dzwarg@azavea.com>
10  * Copyright (C) 2009-2011 Pierre Racine <pierre.racine@sbf.ulaval.ca>
11  * Copyright (C) 2009-2011 Mateusz Loskot <mateusz@loskot.net>
12  * Copyright (C) 2008-2009 Sandro Santilli <strk@kbt.io>
13  *
14  * This program is free software; you can redistribute it and/or
15  * modify it under the terms of the GNU General Public License
16  * as published by the Free Software Foundation; either version 2
17  * of the License, or (at your option) any later version.
18  *
19  * This program is distributed in the hope that it will be useful,
20  * but WITHOUT ANY WARRANTY; without even the implied warranty of
21  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22  * GNU General Public License for more details.
23  *
24  * You should have received a copy of the GNU General Public License
25  * along with this program; if not, write to the Free Software Foundation,
26  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
27  *
28  */
29 
30 #include <postgres.h> /* for palloc */
31 #include <fmgr.h>
32 #include <utils/builtins.h>
33 
34 #include "../../postgis_config.h"
35 
36 #include "lwgeom_pg.h"
37 #include "rtpostgis.h"
38 
39 /* determine if two rasters intersect */
40 Datum RASTER_intersects(PG_FUNCTION_ARGS);
41 
42 /* determine if two rasters overlap */
43 Datum RASTER_overlaps(PG_FUNCTION_ARGS);
44 
45 /* determine if two rasters touch */
46 Datum RASTER_touches(PG_FUNCTION_ARGS);
47 
48 /* determine if the first raster contains the second raster */
49 Datum RASTER_contains(PG_FUNCTION_ARGS);
50 
51 /* determine if the first raster contains properly the second raster */
52 Datum RASTER_containsProperly(PG_FUNCTION_ARGS);
53 
54 /* determine if the first raster covers the second raster */
55 Datum RASTER_covers(PG_FUNCTION_ARGS);
56 
57 /* determine if the first raster is covered by the second raster */
58 Datum RASTER_coveredby(PG_FUNCTION_ARGS);
59 
60 /* determine if the two rasters are within the specified distance of each other */
61 Datum RASTER_dwithin(PG_FUNCTION_ARGS);
62 
63 /* determine if the two rasters are fully within the specified distance of each other */
64 Datum RASTER_dfullywithin(PG_FUNCTION_ARGS);
65 
66 /* determine if two rasters are aligned */
67 Datum RASTER_sameAlignment(PG_FUNCTION_ARGS);
68 Datum RASTER_notSameAlignmentReason(PG_FUNCTION_ARGS);
69 
70 /**
71  * See if two rasters intersect
72  */
73 PG_FUNCTION_INFO_V1(RASTER_intersects);
RASTER_intersects(PG_FUNCTION_ARGS)74 Datum RASTER_intersects(PG_FUNCTION_ARGS)
75 {
76 	const uint32_t set_count = 2;
77 	rt_pgraster *pgrast[2];
78 	int pgrastpos[2] = {-1, -1};
79 	rt_raster rast[2] = {NULL};
80 	uint32_t bandindex[2] = {0};
81 	uint32_t hasbandindex[2] = {0};
82 
83 	uint32_t i;
84 	uint32_t j;
85 	uint32_t k;
86 	uint32_t numBands;
87 	int rtn;
88 	int result;
89 
90 	for (i = 0, j = 0; i < set_count; i++) {
91 		/* pgrast is null, return null */
92 		if (PG_ARGISNULL(j)) {
93 			for (k = 0; k < i; k++) {
94 				rt_raster_destroy(rast[k]);
95 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
96 			}
97 			PG_RETURN_NULL();
98 		}
99 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
100 		pgrastpos[i] = j;
101 		j++;
102 
103 		/* raster */
104 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
105 		if (!rast[i]) {
106 			for (k = 0; k <= i; k++) {
107 				if (k < i)
108 					rt_raster_destroy(rast[k]);
109 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
110 			}
111 			elog(ERROR, "RASTER_intersects: Could not deserialize the %s raster", i < 1 ? "first" : "second");
112 			PG_RETURN_NULL();
113 		}
114 
115 		/* numbands */
116 		numBands = rt_raster_get_num_bands(rast[i]);
117 		if (numBands < 1) {
118 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
119 			if (i > 0) i++;
120 			for (k = 0; k < i; k++) {
121 				rt_raster_destroy(rast[k]);
122 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
123 			}
124 			PG_RETURN_NULL();
125 		}
126 
127 		/* band index */
128 		if (!PG_ARGISNULL(j)) {
129 			bandindex[i] = PG_GETARG_INT32(j);
130 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
131 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
132 				if (i > 0) i++;
133 				for (k = 0; k < i; k++) {
134 					rt_raster_destroy(rast[k]);
135 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
136 				}
137 				PG_RETURN_NULL();
138 			}
139 			hasbandindex[i] = 1;
140 		}
141 		else
142 			hasbandindex[i] = 0;
143 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
144 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
145 		j++;
146 	}
147 
148 	/* hasbandindex must be balanced */
149 	if (
150 		(hasbandindex[0] && !hasbandindex[1]) ||
151 		(!hasbandindex[0] && hasbandindex[1])
152 	) {
153 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
154 		for (k = 0; k < set_count; k++) {
155 			rt_raster_destroy(rast[k]);
156 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
157 		}
158 		PG_RETURN_NULL();
159 	}
160 
161 	/* SRID must match */
162 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
163 		for (k = 0; k < set_count; k++) {
164 			rt_raster_destroy(rast[k]);
165 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
166 		}
167 		elog(ERROR, "The two rasters provided have different SRIDs");
168 		PG_RETURN_NULL();
169 	}
170 
171 	rtn = rt_raster_intersects(
172 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
173 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
174 		&result
175 	);
176 	for (k = 0; k < set_count; k++) {
177 		rt_raster_destroy(rast[k]);
178 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
179 	}
180 
181 	if (rtn != ES_NONE) {
182 		elog(ERROR, "RASTER_intersects: Could not test for intersection on the two rasters");
183 		PG_RETURN_NULL();
184 	}
185 
186 	PG_RETURN_BOOL(result);
187 }
188 
189 /**
190  * See if two rasters overlap
191  */
192 PG_FUNCTION_INFO_V1(RASTER_overlaps);
RASTER_overlaps(PG_FUNCTION_ARGS)193 Datum RASTER_overlaps(PG_FUNCTION_ARGS)
194 {
195 	const uint32_t set_count = 2;
196 	rt_pgraster *pgrast[2];
197 	int pgrastpos[2] = {-1, -1};
198 	rt_raster rast[2] = {NULL};
199 	uint32_t bandindex[2] = {0};
200 	uint32_t hasbandindex[2] = {0};
201 
202 	uint32_t i;
203 	uint32_t j;
204 	uint32_t k;
205 	uint32_t numBands;
206 	int rtn;
207 	int result;
208 
209 	for (i = 0, j = 0; i < set_count; i++) {
210 		/* pgrast is null, return null */
211 		if (PG_ARGISNULL(j)) {
212 			for (k = 0; k < i; k++) {
213 				rt_raster_destroy(rast[k]);
214 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
215 			}
216 			PG_RETURN_NULL();
217 		}
218 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
219 		pgrastpos[i] = j;
220 		j++;
221 
222 		/* raster */
223 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
224 		if (!rast[i]) {
225 			for (k = 0; k <= i; k++) {
226 				if (k < i)
227 					rt_raster_destroy(rast[k]);
228 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
229 			}
230 			elog(ERROR, "RASTER_overlaps: Could not deserialize the %s raster", i < 1 ? "first" : "second");
231 			PG_RETURN_NULL();
232 		}
233 
234 		/* numbands */
235 		numBands = rt_raster_get_num_bands(rast[i]);
236 		if (numBands < 1) {
237 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
238 			if (i > 0) i++;
239 			for (k = 0; k < i; k++) {
240 				rt_raster_destroy(rast[k]);
241 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
242 			}
243 			PG_RETURN_NULL();
244 		}
245 
246 		/* band index */
247 		if (!PG_ARGISNULL(j)) {
248 			bandindex[i] = PG_GETARG_INT32(j);
249 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
250 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
251 				if (i > 0) i++;
252 				for (k = 0; k < i; k++) {
253 					rt_raster_destroy(rast[k]);
254 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
255 				}
256 				PG_RETURN_NULL();
257 			}
258 			hasbandindex[i] = 1;
259 		}
260 		else
261 			hasbandindex[i] = 0;
262 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
263 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
264 		j++;
265 	}
266 
267 	/* hasbandindex must be balanced */
268 	if (
269 		(hasbandindex[0] && !hasbandindex[1]) ||
270 		(!hasbandindex[0] && hasbandindex[1])
271 	) {
272 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
273 		for (k = 0; k < set_count; k++) {
274 			rt_raster_destroy(rast[k]);
275 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
276 		}
277 		PG_RETURN_NULL();
278 	}
279 
280 	/* SRID must match */
281 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
282 		for (k = 0; k < set_count; k++) {
283 			rt_raster_destroy(rast[k]);
284 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
285 		}
286 		elog(ERROR, "The two rasters provided have different SRIDs");
287 		PG_RETURN_NULL();
288 	}
289 
290 	rtn = rt_raster_overlaps(
291 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
292 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
293 		&result
294 	);
295 	for (k = 0; k < set_count; k++) {
296 		rt_raster_destroy(rast[k]);
297 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
298 	}
299 
300 	if (rtn != ES_NONE) {
301 		elog(ERROR, "RASTER_overlaps: Could not test for overlap on the two rasters");
302 		PG_RETURN_NULL();
303 	}
304 
305 	PG_RETURN_BOOL(result);
306 }
307 
308 /**
309  * See if two rasters touch
310  */
311 PG_FUNCTION_INFO_V1(RASTER_touches);
RASTER_touches(PG_FUNCTION_ARGS)312 Datum RASTER_touches(PG_FUNCTION_ARGS)
313 {
314 	const uint32_t set_count = 2;
315 	rt_pgraster *pgrast[2];
316 	int pgrastpos[2] = {-1, -1};
317 	rt_raster rast[2] = {NULL};
318 	uint32_t bandindex[2] = {0};
319 	uint32_t hasbandindex[2] = {0};
320 
321 	uint32_t i;
322 	uint32_t j;
323 	uint32_t k;
324 	uint32_t numBands;
325 	int rtn;
326 	int result;
327 
328 	for (i = 0, j = 0; i < set_count; i++) {
329 		/* pgrast is null, return null */
330 		if (PG_ARGISNULL(j)) {
331 			for (k = 0; k < i; k++) {
332 				rt_raster_destroy(rast[k]);
333 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
334 			}
335 			PG_RETURN_NULL();
336 		}
337 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
338 		pgrastpos[i] = j;
339 		j++;
340 
341 		/* raster */
342 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
343 		if (!rast[i]) {
344 			for (k = 0; k <= i; k++) {
345 				if (k < i)
346 					rt_raster_destroy(rast[k]);
347 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
348 			}
349 			elog(ERROR, "RASTER_touches: Could not deserialize the %s raster", i < 1 ? "first" : "second");
350 			PG_RETURN_NULL();
351 		}
352 
353 		/* numbands */
354 		numBands = rt_raster_get_num_bands(rast[i]);
355 		if (numBands < 1) {
356 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
357 			if (i > 0) i++;
358 			for (k = 0; k < i; k++) {
359 				rt_raster_destroy(rast[k]);
360 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
361 			}
362 			PG_RETURN_NULL();
363 		}
364 
365 		/* band index */
366 		if (!PG_ARGISNULL(j)) {
367 			bandindex[i] = PG_GETARG_INT32(j);
368 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
369 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
370 				if (i > 0) i++;
371 				for (k = 0; k < i; k++) {
372 					rt_raster_destroy(rast[k]);
373 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
374 				}
375 				PG_RETURN_NULL();
376 			}
377 			hasbandindex[i] = 1;
378 		}
379 		else
380 			hasbandindex[i] = 0;
381 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
382 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
383 		j++;
384 	}
385 
386 	/* hasbandindex must be balanced */
387 	if (
388 		(hasbandindex[0] && !hasbandindex[1]) ||
389 		(!hasbandindex[0] && hasbandindex[1])
390 	) {
391 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
392 		for (k = 0; k < set_count; k++) {
393 			rt_raster_destroy(rast[k]);
394 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
395 		}
396 		PG_RETURN_NULL();
397 	}
398 
399 	/* SRID must match */
400 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
401 		for (k = 0; k < set_count; k++) {
402 			rt_raster_destroy(rast[k]);
403 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
404 		}
405 		elog(ERROR, "The two rasters provided have different SRIDs");
406 		PG_RETURN_NULL();
407 	}
408 
409 	rtn = rt_raster_touches(
410 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
411 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
412 		&result
413 	);
414 	for (k = 0; k < set_count; k++) {
415 		rt_raster_destroy(rast[k]);
416 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
417 	}
418 
419 	if (rtn != ES_NONE) {
420 		elog(ERROR, "RASTER_touches: Could not test for touch on the two rasters");
421 		PG_RETURN_NULL();
422 	}
423 
424 	PG_RETURN_BOOL(result);
425 }
426 
427 /**
428  * See if the first raster contains the second raster
429  */
430 PG_FUNCTION_INFO_V1(RASTER_contains);
RASTER_contains(PG_FUNCTION_ARGS)431 Datum RASTER_contains(PG_FUNCTION_ARGS)
432 {
433 	const uint32_t set_count = 2;
434 	rt_pgraster *pgrast[2];
435 	int pgrastpos[2] = {-1, -1};
436 	rt_raster rast[2] = {NULL};
437 	uint32_t bandindex[2] = {0};
438 	uint32_t hasbandindex[2] = {0};
439 
440 	uint32_t i;
441 	uint32_t j;
442 	uint32_t k;
443 	uint32_t numBands;
444 	int rtn;
445 	int result;
446 
447 	for (i = 0, j = 0; i < set_count; i++) {
448 		/* pgrast is null, return null */
449 		if (PG_ARGISNULL(j)) {
450 			for (k = 0; k < i; k++) {
451 				rt_raster_destroy(rast[k]);
452 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
453 			}
454 			PG_RETURN_NULL();
455 		}
456 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
457 		pgrastpos[i] = j;
458 		j++;
459 
460 		/* raster */
461 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
462 		if (!rast[i]) {
463 			for (k = 0; k <= i; k++) {
464 				if (k < i)
465 					rt_raster_destroy(rast[k]);
466 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
467 			}
468 			elog(ERROR, "RASTER_contains: Could not deserialize the %s raster", i < 1 ? "first" : "second");
469 			PG_RETURN_NULL();
470 		}
471 
472 		/* numbands */
473 		numBands = rt_raster_get_num_bands(rast[i]);
474 		if (numBands < 1) {
475 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
476 			if (i > 0) i++;
477 			for (k = 0; k < i; k++) {
478 				rt_raster_destroy(rast[k]);
479 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
480 			}
481 			PG_RETURN_NULL();
482 		}
483 
484 		/* band index */
485 		if (!PG_ARGISNULL(j)) {
486 			bandindex[i] = PG_GETARG_INT32(j);
487 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
488 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
489 				if (i > 0) i++;
490 				for (k = 0; k < i; k++) {
491 					rt_raster_destroy(rast[k]);
492 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
493 				}
494 				PG_RETURN_NULL();
495 			}
496 			hasbandindex[i] = 1;
497 		}
498 		else
499 			hasbandindex[i] = 0;
500 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
501 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
502 		j++;
503 	}
504 
505 	/* hasbandindex must be balanced */
506 	if (
507 		(hasbandindex[0] && !hasbandindex[1]) ||
508 		(!hasbandindex[0] && hasbandindex[1])
509 	) {
510 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
511 		for (k = 0; k < set_count; k++) {
512 			rt_raster_destroy(rast[k]);
513 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
514 		}
515 		PG_RETURN_NULL();
516 	}
517 
518 	/* SRID must match */
519 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
520 		for (k = 0; k < set_count; k++) {
521 			rt_raster_destroy(rast[k]);
522 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
523 		}
524 		elog(ERROR, "The two rasters provided have different SRIDs");
525 		PG_RETURN_NULL();
526 	}
527 
528 	rtn = rt_raster_contains(
529 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
530 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
531 		&result
532 	);
533 	for (k = 0; k < set_count; k++) {
534 		rt_raster_destroy(rast[k]);
535 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
536 	}
537 
538 	if (rtn != ES_NONE) {
539 		elog(ERROR, "RASTER_contains: Could not test that the first raster contains the second raster");
540 		PG_RETURN_NULL();
541 	}
542 
543 	PG_RETURN_BOOL(result);
544 }
545 
546 /**
547  * See if the first raster contains properly the second raster
548  */
549 PG_FUNCTION_INFO_V1(RASTER_containsProperly);
RASTER_containsProperly(PG_FUNCTION_ARGS)550 Datum RASTER_containsProperly(PG_FUNCTION_ARGS)
551 {
552 	const uint32_t set_count = 2;
553 	rt_pgraster *pgrast[2];
554 	int pgrastpos[2] = {-1, -1};
555 	rt_raster rast[2] = {NULL};
556 	uint32_t bandindex[2] = {0};
557 	uint32_t hasbandindex[2] = {0};
558 
559 	uint32_t i;
560 	uint32_t j;
561 	uint32_t k;
562 	uint32_t numBands;
563 	int rtn;
564 	int result;
565 
566 	for (i = 0, j = 0; i < set_count; i++) {
567 		/* pgrast is null, return null */
568 		if (PG_ARGISNULL(j)) {
569 			for (k = 0; k < i; k++) {
570 				rt_raster_destroy(rast[k]);
571 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
572 			}
573 			PG_RETURN_NULL();
574 		}
575 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
576 		pgrastpos[i] = j;
577 		j++;
578 
579 		/* raster */
580 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
581 		if (!rast[i]) {
582 			for (k = 0; k <= i; k++) {
583 				if (k < i)
584 					rt_raster_destroy(rast[k]);
585 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
586 			}
587 			elog(ERROR, "RASTER_containsProperly: Could not deserialize the %s raster", i < 1 ? "first" : "second");
588 			PG_RETURN_NULL();
589 		}
590 
591 		/* numbands */
592 		numBands = rt_raster_get_num_bands(rast[i]);
593 		if (numBands < 1) {
594 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
595 			if (i > 0) i++;
596 			for (k = 0; k < i; k++) {
597 				rt_raster_destroy(rast[k]);
598 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
599 			}
600 			PG_RETURN_NULL();
601 		}
602 
603 		/* band index */
604 		if (!PG_ARGISNULL(j)) {
605 			bandindex[i] = PG_GETARG_INT32(j);
606 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
607 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
608 				if (i > 0) i++;
609 				for (k = 0; k < i; k++) {
610 					rt_raster_destroy(rast[k]);
611 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
612 				}
613 				PG_RETURN_NULL();
614 			}
615 			hasbandindex[i] = 1;
616 		}
617 		else
618 			hasbandindex[i] = 0;
619 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
620 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
621 		j++;
622 	}
623 
624 	/* hasbandindex must be balanced */
625 	if (
626 		(hasbandindex[0] && !hasbandindex[1]) ||
627 		(!hasbandindex[0] && hasbandindex[1])
628 	) {
629 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
630 		for (k = 0; k < set_count; k++) {
631 			rt_raster_destroy(rast[k]);
632 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
633 		}
634 		PG_RETURN_NULL();
635 	}
636 
637 	/* SRID must match */
638 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
639 		for (k = 0; k < set_count; k++) {
640 			rt_raster_destroy(rast[k]);
641 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
642 		}
643 		elog(ERROR, "The two rasters provided have different SRIDs");
644 		PG_RETURN_NULL();
645 	}
646 
647 	rtn = rt_raster_contains_properly(
648 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
649 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
650 		&result
651 	);
652 	for (k = 0; k < set_count; k++) {
653 		rt_raster_destroy(rast[k]);
654 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
655 	}
656 
657 	if (rtn != ES_NONE) {
658 		elog(ERROR, "RASTER_containsProperly: Could not test that the first raster contains properly the second raster");
659 		PG_RETURN_NULL();
660 	}
661 
662 	PG_RETURN_BOOL(result);
663 }
664 
665 /**
666  * See if the first raster covers the second raster
667  */
668 PG_FUNCTION_INFO_V1(RASTER_covers);
RASTER_covers(PG_FUNCTION_ARGS)669 Datum RASTER_covers(PG_FUNCTION_ARGS)
670 {
671 	const uint32_t set_count = 2;
672 	rt_pgraster *pgrast[2];
673 	int pgrastpos[2] = {-1, -1};
674 	rt_raster rast[2] = {NULL};
675 	uint32_t bandindex[2] = {0};
676 	uint32_t hasbandindex[2] = {0};
677 
678 	uint32_t i;
679 	uint32_t j;
680 	uint32_t k;
681 	uint32_t numBands;
682 	int rtn;
683 	int result;
684 
685 	for (i = 0, j = 0; i < set_count; i++) {
686 		/* pgrast is null, return null */
687 		if (PG_ARGISNULL(j)) {
688 			for (k = 0; k < i; k++) {
689 				rt_raster_destroy(rast[k]);
690 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
691 			}
692 			PG_RETURN_NULL();
693 		}
694 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
695 		pgrastpos[i] = j;
696 		j++;
697 
698 		/* raster */
699 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
700 		if (!rast[i]) {
701 			for (k = 0; k <= i; k++) {
702 				if (k < i)
703 					rt_raster_destroy(rast[k]);
704 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
705 			}
706 			elog(ERROR, "RASTER_covers: Could not deserialize the %s raster", i < 1 ? "first" : "second");
707 			PG_RETURN_NULL();
708 		}
709 
710 		/* numbands */
711 		numBands = rt_raster_get_num_bands(rast[i]);
712 		if (numBands < 1) {
713 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
714 			if (i > 0) i++;
715 			for (k = 0; k < i; k++) {
716 				rt_raster_destroy(rast[k]);
717 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
718 			}
719 			PG_RETURN_NULL();
720 		}
721 
722 		/* band index */
723 		if (!PG_ARGISNULL(j)) {
724 			bandindex[i] = PG_GETARG_INT32(j);
725 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
726 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
727 				if (i > 0) i++;
728 				for (k = 0; k < i; k++) {
729 					rt_raster_destroy(rast[k]);
730 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
731 				}
732 				PG_RETURN_NULL();
733 			}
734 			hasbandindex[i] = 1;
735 		}
736 		else
737 			hasbandindex[i] = 0;
738 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
739 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
740 		j++;
741 	}
742 
743 	/* hasbandindex must be balanced */
744 	if (
745 		(hasbandindex[0] && !hasbandindex[1]) ||
746 		(!hasbandindex[0] && hasbandindex[1])
747 	) {
748 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
749 		for (k = 0; k < set_count; k++) {
750 			rt_raster_destroy(rast[k]);
751 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
752 		}
753 		PG_RETURN_NULL();
754 	}
755 
756 	/* SRID must match */
757 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
758 		for (k = 0; k < set_count; k++) {
759 			rt_raster_destroy(rast[k]);
760 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
761 		}
762 		elog(ERROR, "The two rasters provided have different SRIDs");
763 		PG_RETURN_NULL();
764 	}
765 
766 	rtn = rt_raster_covers(
767 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
768 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
769 		&result
770 	);
771 	for (k = 0; k < set_count; k++) {
772 		rt_raster_destroy(rast[k]);
773 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
774 	}
775 
776 	if (rtn != ES_NONE) {
777 		elog(ERROR, "RASTER_covers: Could not test that the first raster covers the second raster");
778 		PG_RETURN_NULL();
779 	}
780 
781 	PG_RETURN_BOOL(result);
782 }
783 
784 /**
785  * See if the first raster is covered by the second raster
786  */
787 PG_FUNCTION_INFO_V1(RASTER_coveredby);
RASTER_coveredby(PG_FUNCTION_ARGS)788 Datum RASTER_coveredby(PG_FUNCTION_ARGS)
789 {
790 	const uint32_t set_count = 2;
791 	rt_pgraster *pgrast[2];
792 	int pgrastpos[2] = {-1, -1};
793 	rt_raster rast[2] = {NULL};
794 	uint32_t bandindex[2] = {0};
795 	uint32_t hasbandindex[2] = {0};
796 
797 	uint32_t i;
798 	uint32_t j;
799 	uint32_t k;
800 	uint32_t numBands;
801 	int rtn;
802 	int result;
803 
804 	for (i = 0, j = 0; i < set_count; i++) {
805 		/* pgrast is null, return null */
806 		if (PG_ARGISNULL(j)) {
807 			for (k = 0; k < i; k++) {
808 				rt_raster_destroy(rast[k]);
809 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
810 			}
811 			PG_RETURN_NULL();
812 		}
813 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
814 		pgrastpos[i] = j;
815 		j++;
816 
817 		/* raster */
818 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
819 		if (!rast[i]) {
820 			for (k = 0; k <= i; k++) {
821 				if (k < i)
822 					rt_raster_destroy(rast[k]);
823 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
824 			}
825 			elog(ERROR, "RASTER_coveredby: Could not deserialize the %s raster", i < 1 ? "first" : "second");
826 			PG_RETURN_NULL();
827 		}
828 
829 		/* numbands */
830 		numBands = rt_raster_get_num_bands(rast[i]);
831 		if (numBands < 1) {
832 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
833 			if (i > 0) i++;
834 			for (k = 0; k < i; k++) {
835 				rt_raster_destroy(rast[k]);
836 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
837 			}
838 			PG_RETURN_NULL();
839 		}
840 
841 		/* band index */
842 		if (!PG_ARGISNULL(j)) {
843 			bandindex[i] = PG_GETARG_INT32(j);
844 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
845 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
846 				if (i > 0) i++;
847 				for (k = 0; k < i; k++) {
848 					rt_raster_destroy(rast[k]);
849 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
850 				}
851 				PG_RETURN_NULL();
852 			}
853 			hasbandindex[i] = 1;
854 		}
855 		else
856 			hasbandindex[i] = 0;
857 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
858 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
859 		j++;
860 	}
861 
862 	/* hasbandindex must be balanced */
863 	if (
864 		(hasbandindex[0] && !hasbandindex[1]) ||
865 		(!hasbandindex[0] && hasbandindex[1])
866 	) {
867 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
868 		for (k = 0; k < set_count; k++) {
869 			rt_raster_destroy(rast[k]);
870 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
871 		}
872 		PG_RETURN_NULL();
873 	}
874 
875 	/* SRID must match */
876 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
877 		for (k = 0; k < set_count; k++) {
878 			rt_raster_destroy(rast[k]);
879 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
880 		}
881 		elog(ERROR, "The two rasters provided have different SRIDs");
882 		PG_RETURN_NULL();
883 	}
884 
885 	rtn = rt_raster_coveredby(
886 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
887 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
888 		&result
889 	);
890 	for (k = 0; k < set_count; k++) {
891 		rt_raster_destroy(rast[k]);
892 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
893 	}
894 
895 	if (rtn != ES_NONE) {
896 		elog(ERROR, "RASTER_coveredby: Could not test that the first raster is covered by the second raster");
897 		PG_RETURN_NULL();
898 	}
899 
900 	PG_RETURN_BOOL(result);
901 }
902 
903 /**
904  * See if the two rasters are within the specified distance of each other
905  */
906 PG_FUNCTION_INFO_V1(RASTER_dwithin);
RASTER_dwithin(PG_FUNCTION_ARGS)907 Datum RASTER_dwithin(PG_FUNCTION_ARGS)
908 {
909 	const uint32_t set_count = 2;
910 	rt_pgraster *pgrast[2];
911 	int pgrastpos[2] = {-1, -1};
912 	rt_raster rast[2] = {NULL};
913 	uint32_t bandindex[2] = {0};
914 	uint32_t hasbandindex[2] = {0};
915 	double distance = 0;
916 
917 	uint32_t i;
918 	uint32_t j;
919 	uint32_t k;
920 	uint32_t numBands;
921 	int rtn;
922 	int result;
923 
924 	for (i = 0, j = 0; i < set_count; i++) {
925 		/* pgrast is null, return null */
926 		if (PG_ARGISNULL(j)) {
927 			for (k = 0; k < i; k++) {
928 				rt_raster_destroy(rast[k]);
929 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
930 			}
931 			PG_RETURN_NULL();
932 		}
933 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
934 		pgrastpos[i] = j;
935 		j++;
936 
937 		/* raster */
938 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
939 		if (!rast[i]) {
940 			for (k = 0; k <= i; k++) {
941 				if (k < i)
942 					rt_raster_destroy(rast[k]);
943 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
944 			}
945 			elog(ERROR, "RASTER_dwithin: Could not deserialize the %s raster", i < 1 ? "first" : "second");
946 			PG_RETURN_NULL();
947 		}
948 
949 		/* numbands */
950 		numBands = rt_raster_get_num_bands(rast[i]);
951 		if (numBands < 1) {
952 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
953 			if (i > 0) i++;
954 			for (k = 0; k < i; k++) {
955 				rt_raster_destroy(rast[k]);
956 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
957 			}
958 			PG_RETURN_NULL();
959 		}
960 
961 		/* band index */
962 		if (!PG_ARGISNULL(j)) {
963 			bandindex[i] = PG_GETARG_INT32(j);
964 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
965 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
966 				if (i > 0) i++;
967 				for (k = 0; k < i; k++) {
968 					rt_raster_destroy(rast[k]);
969 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
970 				}
971 				PG_RETURN_NULL();
972 			}
973 			hasbandindex[i] = 1;
974 		}
975 		else
976 			hasbandindex[i] = 0;
977 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
978 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
979 		j++;
980 	}
981 
982 	/* distance */
983 	if (PG_ARGISNULL(4)) {
984 		elog(NOTICE, "Distance cannot be NULL.  Returning NULL");
985 		for (k = 0; k < set_count; k++) {
986 			rt_raster_destroy(rast[k]);
987 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
988 		}
989 		PG_RETURN_NULL();
990 	}
991 
992 	distance = PG_GETARG_FLOAT8(4);
993 	if (distance < 0) {
994 		elog(NOTICE, "Distance cannot be less than zero.  Returning NULL");
995 		for (k = 0; k < set_count; k++) {
996 			rt_raster_destroy(rast[k]);
997 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
998 		}
999 		PG_RETURN_NULL();
1000 	}
1001 
1002 	/* hasbandindex must be balanced */
1003 	if (
1004 		(hasbandindex[0] && !hasbandindex[1]) ||
1005 		(!hasbandindex[0] && hasbandindex[1])
1006 	) {
1007 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
1008 		for (k = 0; k < set_count; k++) {
1009 			rt_raster_destroy(rast[k]);
1010 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1011 		}
1012 		PG_RETURN_NULL();
1013 	}
1014 
1015 	/* SRID must match */
1016 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
1017 		for (k = 0; k < set_count; k++) {
1018 			rt_raster_destroy(rast[k]);
1019 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1020 		}
1021 		elog(ERROR, "The two rasters provided have different SRIDs");
1022 		PG_RETURN_NULL();
1023 	}
1024 
1025 	rtn = rt_raster_within_distance(
1026 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
1027 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
1028 		distance,
1029 		&result
1030 	);
1031 	for (k = 0; k < set_count; k++) {
1032 		rt_raster_destroy(rast[k]);
1033 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1034 	}
1035 
1036 	if (rtn != ES_NONE) {
1037 		elog(ERROR, "RASTER_dwithin: Could not test that the two rasters are within the specified distance of each other");
1038 		PG_RETURN_NULL();
1039 	}
1040 
1041 	PG_RETURN_BOOL(result);
1042 }
1043 
1044 /**
1045  * See if the two rasters are fully within the specified distance of each other
1046  */
1047 PG_FUNCTION_INFO_V1(RASTER_dfullywithin);
RASTER_dfullywithin(PG_FUNCTION_ARGS)1048 Datum RASTER_dfullywithin(PG_FUNCTION_ARGS)
1049 {
1050 	const uint32_t set_count = 2;
1051 	rt_pgraster *pgrast[2];
1052 	int pgrastpos[2] = {-1, -1};
1053 	rt_raster rast[2] = {NULL};
1054 	uint32_t bandindex[2] = {0};
1055 	uint32_t hasbandindex[2] = {0};
1056 	double distance = 0;
1057 
1058 	uint32_t i;
1059 	uint32_t j;
1060 	uint32_t k;
1061 	uint32_t numBands;
1062 	int rtn;
1063 	int result;
1064 
1065 	for (i = 0, j = 0; i < set_count; i++) {
1066 		/* pgrast is null, return null */
1067 		if (PG_ARGISNULL(j)) {
1068 			for (k = 0; k < i; k++) {
1069 				rt_raster_destroy(rast[k]);
1070 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1071 			}
1072 			PG_RETURN_NULL();
1073 		}
1074 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM(PG_GETARG_DATUM(j));
1075 		pgrastpos[i] = j;
1076 		j++;
1077 
1078 		/* raster */
1079 		rast[i] = rt_raster_deserialize(pgrast[i], FALSE);
1080 		if (!rast[i]) {
1081 			for (k = 0; k <= i; k++) {
1082 				if (k < i)
1083 					rt_raster_destroy(rast[k]);
1084 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1085 			}
1086 			elog(ERROR, "RASTER_dfullywithin: Could not deserialize the %s raster", i < 1 ? "first" : "second");
1087 			PG_RETURN_NULL();
1088 		}
1089 
1090 		/* numbands */
1091 		numBands = rt_raster_get_num_bands(rast[i]);
1092 		if (numBands < 1) {
1093 			elog(NOTICE, "The %s raster provided has no bands", i < 1 ? "first" : "second");
1094 			if (i > 0) i++;
1095 			for (k = 0; k < i; k++) {
1096 				rt_raster_destroy(rast[k]);
1097 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1098 			}
1099 			PG_RETURN_NULL();
1100 		}
1101 
1102 		/* band index */
1103 		if (!PG_ARGISNULL(j)) {
1104 			bandindex[i] = PG_GETARG_INT32(j);
1105 			if (bandindex[i] < 1 || bandindex[i] > numBands) {
1106 				elog(NOTICE, "Invalid band index (must use 1-based) for the %s raster. Returning NULL", i < 1 ? "first" : "second");
1107 				if (i > 0) i++;
1108 				for (k = 0; k < i; k++) {
1109 					rt_raster_destroy(rast[k]);
1110 					PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1111 				}
1112 				PG_RETURN_NULL();
1113 			}
1114 			hasbandindex[i] = 1;
1115 		}
1116 		else
1117 			hasbandindex[i] = 0;
1118 		POSTGIS_RT_DEBUGF(4, "hasbandindex[%d] = %d", i, hasbandindex[i]);
1119 		POSTGIS_RT_DEBUGF(4, "bandindex[%d] = %d", i, bandindex[i]);
1120 		j++;
1121 	}
1122 
1123 	/* distance */
1124 	if (PG_ARGISNULL(4)) {
1125 		elog(NOTICE, "Distance cannot be NULL.  Returning NULL");
1126 		for (k = 0; k < set_count; k++) {
1127 			rt_raster_destroy(rast[k]);
1128 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1129 		}
1130 		PG_RETURN_NULL();
1131 	}
1132 
1133 	distance = PG_GETARG_FLOAT8(4);
1134 	if (distance < 0) {
1135 		elog(NOTICE, "Distance cannot be less than zero.  Returning NULL");
1136 		for (k = 0; k < set_count; k++) {
1137 			rt_raster_destroy(rast[k]);
1138 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1139 		}
1140 		PG_RETURN_NULL();
1141 	}
1142 
1143 	/* hasbandindex must be balanced */
1144 	if (
1145 		(hasbandindex[0] && !hasbandindex[1]) ||
1146 		(!hasbandindex[0] && hasbandindex[1])
1147 	) {
1148 		elog(NOTICE, "Missing band index.  Band indices must be provided for both rasters if any one is provided");
1149 		for (k = 0; k < set_count; k++) {
1150 			rt_raster_destroy(rast[k]);
1151 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1152 		}
1153 		PG_RETURN_NULL();
1154 	}
1155 
1156 	/* SRID must match */
1157 	if (rt_raster_get_srid(rast[0]) != rt_raster_get_srid(rast[1])) {
1158 		for (k = 0; k < set_count; k++) {
1159 			rt_raster_destroy(rast[k]);
1160 			PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1161 		}
1162 		elog(ERROR, "The two rasters provided have different SRIDs");
1163 		PG_RETURN_NULL();
1164 	}
1165 
1166 	rtn = rt_raster_fully_within_distance(
1167 		rast[0], (hasbandindex[0] ? (int)bandindex[0] - 1 : -1),
1168 		rast[1], (hasbandindex[1] ? (int)bandindex[1] - 1 : -1),
1169 		distance,
1170 		&result
1171 	);
1172 	for (k = 0; k < set_count; k++) {
1173 		rt_raster_destroy(rast[k]);
1174 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1175 	}
1176 
1177 	if (rtn != ES_NONE) {
1178 		elog(ERROR, "RASTER_dfullywithin: Could not test that the two rasters are fully within the specified distance of each other");
1179 		PG_RETURN_NULL();
1180 	}
1181 
1182 	PG_RETURN_BOOL(result);
1183 }
1184 
1185 /**
1186  * See if two rasters are aligned
1187  */
1188 PG_FUNCTION_INFO_V1(RASTER_sameAlignment);
RASTER_sameAlignment(PG_FUNCTION_ARGS)1189 Datum RASTER_sameAlignment(PG_FUNCTION_ARGS)
1190 {
1191 	const uint32_t set_count = 2;
1192 	rt_pgraster *pgrast[2];
1193 	int pgrastpos[2] = {-1, -1};
1194 	rt_raster rast[2] = {NULL};
1195 
1196 	uint32_t i;
1197 	uint32_t j;
1198 	uint32_t k;
1199 	int rtn;
1200 	int aligned = 0;
1201 	char *reason = NULL;
1202 
1203 	for (i = 0, j = 0; i < set_count; i++) {
1204 		/* pgrast is null, return null */
1205 		if (PG_ARGISNULL(j)) {
1206 			for (k = 0; k < i; k++) {
1207 				rt_raster_destroy(rast[k]);
1208 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1209 			}
1210 			PG_RETURN_NULL();
1211 		}
1212 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(j), 0, sizeof(struct rt_raster_serialized_t));
1213 		pgrastpos[i] = j;
1214 		j++;
1215 
1216 		/* raster */
1217 		rast[i] = rt_raster_deserialize(pgrast[i], TRUE);
1218 		if (!rast[i]) {
1219 			for (k = 0; k <= i; k++) {
1220 				if (k < i)
1221 					rt_raster_destroy(rast[k]);
1222 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1223 			}
1224 			elog(ERROR, "RASTER_sameAlignment: Could not deserialize the %s raster", i < 1 ? "first" : "second");
1225 			PG_RETURN_NULL();
1226 		}
1227 	}
1228 
1229 	rtn = rt_raster_same_alignment(
1230 		rast[0],
1231 		rast[1],
1232 		&aligned,
1233 		&reason
1234 	);
1235 	for (k = 0; k < set_count; k++) {
1236 		rt_raster_destroy(rast[k]);
1237 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1238 	}
1239 
1240 	if (rtn != ES_NONE) {
1241 		elog(ERROR, "RASTER_sameAlignment: Could not test for alignment on the two rasters");
1242 		PG_RETURN_NULL();
1243 	}
1244 
1245 	/* only output reason if not aligned */
1246 	if (reason != NULL && !aligned)
1247 		elog(NOTICE, "%s", reason);
1248 
1249 	PG_RETURN_BOOL(aligned);
1250 }
1251 
1252 /**
1253  * Return a reason why two rasters are not aligned
1254  */
1255 PG_FUNCTION_INFO_V1(RASTER_notSameAlignmentReason);
RASTER_notSameAlignmentReason(PG_FUNCTION_ARGS)1256 Datum RASTER_notSameAlignmentReason(PG_FUNCTION_ARGS)
1257 {
1258 	const uint32_t set_count = 2;
1259 	rt_pgraster *pgrast[2];
1260 	int pgrastpos[2] = {-1, -1};
1261 	rt_raster rast[2] = {NULL};
1262 
1263 	uint32_t i;
1264 	uint32_t j;
1265 	uint32_t k;
1266 	int rtn;
1267 	int aligned = 0;
1268 	char *reason = NULL;
1269 	text *result = NULL;
1270 
1271 	for (i = 0, j = 0; i < set_count; i++) {
1272 		/* pgrast is null, return null */
1273 		if (PG_ARGISNULL(j)) {
1274 			for (k = 0; k < i; k++) {
1275 				rt_raster_destroy(rast[k]);
1276 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1277 			}
1278 			PG_RETURN_NULL();
1279 		}
1280 		pgrast[i] = (rt_pgraster *) PG_DETOAST_DATUM_SLICE(PG_GETARG_DATUM(j), 0, sizeof(struct rt_raster_serialized_t));
1281 		pgrastpos[i] = j;
1282 		j++;
1283 
1284 		/* raster */
1285 		rast[i] = rt_raster_deserialize(pgrast[i], TRUE);
1286 		if (!rast[i]) {
1287 			for (k = 0; k <= i; k++) {
1288 				if (k < i)
1289 					rt_raster_destroy(rast[k]);
1290 				PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1291 			}
1292 			elog(ERROR, "RASTER_notSameAlignmentReason: Could not deserialize the %s raster", i < 1 ? "first" : "second");
1293 			PG_RETURN_NULL();
1294 		}
1295 	}
1296 
1297 	rtn = rt_raster_same_alignment(
1298 		rast[0],
1299 		rast[1],
1300 		&aligned,
1301 		&reason
1302 	);
1303 	for (k = 0; k < set_count; k++) {
1304 		rt_raster_destroy(rast[k]);
1305 		PG_FREE_IF_COPY(pgrast[k], pgrastpos[k]);
1306 	}
1307 
1308 	if (rtn != ES_NONE) {
1309 		elog(ERROR, "RASTER_notSameAlignmentReason: Could not test for alignment on the two rasters");
1310 		PG_RETURN_NULL();
1311 	}
1312 
1313 	result = cstring_to_text(reason);
1314 	PG_RETURN_TEXT_P(result);
1315 }
1316