GRASS 8 Programmer's Manual 8.6.0dev(2026)-1878fdfec5
Loading...
Searching...
No Matches
rect.c
Go to the documentation of this file.
1/****************************************************************************
2 * MODULE: R-Tree library
3 *
4 * AUTHOR(S): Antonin Guttman - original code
5 * Daniel Green (green@superliminal.com) - major clean-up
6 * and implementation of bounding spheres
7 * Markus Metz - file-based and memory-based R*-tree
8 *
9 * PURPOSE: Multidimensional index
10 *
11 * SPDX-FileCopyrightText: 2010 GRASS Development Team
12 * SPDX-License-Identifier: GPL-2.0-or-later
13 *****************************************************************************/
14
15#include <stdio.h>
16#include <stdlib.h>
17#include <assert.h>
18#include "index.h"
19
20#include <float.h>
21#include <math.h>
22#include <grass/gis.h>
23
24#define BIG_NUM (FLT_MAX / 4.0)
25
26#define Undefined(x, t) ((x)->boundary[0] > (x)->boundary[t->ndims_alloc])
27
28/*!
29 \brief Create a new rectangle for a given tree
30
31 This method allocates a new rectangle and initializes
32 the internal boundary coordinates based on the tree dimension.
33
34 Hence a call to RTreeNewBoundary() is not necessary.
35
36 \param t The pointer to a RTree struct
37 \return A new allocated RTree_Rect struct
38 */
40{
41 struct RTree_Rect *r;
42
43 assert(t);
44
45 r = (struct RTree_Rect *)malloc(sizeof(struct RTree_Rect));
46
47 assert(r);
48
49 r->boundary = RTreeAllocBoundary(t);
50 return r;
51}
52
53/*!
54 \brief Delete a rectangle
55
56 This method deletes (free) the allocated memory of a rectangle.
57
58 \param r The pointer to the rectangle to be deleted
59 */
61{
62 assert(r);
64 free(r);
65}
66
67/*!
68 \brief Allocate the boundary array of a rectangle for a given tree
69
70 This method allocated the boundary coordinates array in
71 provided rectangle. It does not release previously allocated memory.
72
73 \param r The pointer to rectangle to initialize the boundary coordinates.
74 This is usually a rectangle that was created on the stack or
75 self allocated.
76 \param t The pointer to a RTree struct
77 */
79{
80 RectReal *boundary = (RectReal *)malloc(t->rectsize);
81
83
84 return boundary;
85}
86
87/*!
88 \brief Delete the boundary of a rectangle
89
90 This method deletes (free) the memory of the boundary of a rectangle
91 and sets the boundary pointer to NULL.
92
93 \param r The pointer to the rectangle to delete the boundary from.
94 */
96{
97 assert(r);
98 if (r->boundary)
99 free(r->boundary);
100 r->boundary = NULL;
101}
102
103/*!
104 \brief Initialize a rectangle to have all 0 coordinates.
105 */
106void RTreeInitRect(struct RTree_Rect *r, struct RTree *t)
107{
108 register int i;
109
110 for (i = 0; i < t->ndims_alloc; i++)
111 r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal)0;
112}
113
114/*!
115 \brief Set one dimensional coordinates of a rectangle for a given tree.
116
117 All coordinates of the rectangle will be initialized to 0 before
118 the x coordinates are set.
119
120 \param r The pointer to the rectangle
121 \param t The pointer to the RTree
122 \param x_min The lower x coordinate
123 \param x_max The higher x coordinate
124 */
125void RTreeSetRect1D(struct RTree_Rect *r, struct RTree *t, double x_min,
126 double x_max)
127{
128 RTreeInitRect(r, t);
129 r->boundary[0] = (RectReal)x_min;
130 r->boundary[t->ndims_alloc] = (RectReal)x_max;
131}
132
133/*!
134 \brief Set two dimensional coordinates of a rectangle for a given tree.
135
136 All coordinates of the rectangle will be initialized to 0 before
137 the x and y coordinates are set.
138
139 \param r The pointer to the rectangle
140 \param t The pointer to the RTree
141 \param x_min The lower x coordinate
142 \param x_max The higher x coordinate
143 \param y_min The lower y coordinate
144 \param y_max The higher y coordinate
145 */
146void RTreeSetRect2D(struct RTree_Rect *r, struct RTree *t, double x_min,
147 double x_max, double y_min, double y_max)
148{
149 RTreeInitRect(r, t);
150 r->boundary[0] = (RectReal)x_min;
151 r->boundary[t->ndims_alloc] = (RectReal)x_max;
152 r->boundary[1] = (RectReal)y_min;
153 r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
154}
155
156/*!
157 \brief Set three dimensional coordinates of a rectangle for a given tree.
158
159 All coordinates of the rectangle will be initialized to 0 before
160 the x,y and z coordinates are set.
161
162 \param r The pointer to the rectangle
163 \param t The pointer to the RTree
164 \param x_min The lower x coordinate
165 \param x_max The higher x coordinate
166 \param y_min The lower y coordinate
167 \param y_max The higher y coordinate
168 \param z_min The lower z coordinate
169 \param z_max The higher z coordinate
170 */
171void RTreeSetRect3D(struct RTree_Rect *r, struct RTree *t, double x_min,
172 double x_max, double y_min, double y_max, double z_min,
173 double z_max)
174{
175 RTreeInitRect(r, t);
176 r->boundary[0] = (RectReal)x_min;
177 r->boundary[t->ndims_alloc] = (RectReal)x_max;
178 r->boundary[1] = (RectReal)y_min;
179 r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
180 r->boundary[2] = (RectReal)z_min;
181 r->boundary[2 + t->ndims_alloc] = (RectReal)z_max;
182}
183
184/*!
185 \brief Set 4 dimensional coordinates of a rectangle for a given tree.
186
187 All coordinates of the rectangle will be initialized to 0 before
188 the x,y,z and t coordinates are set.
189
190 \param r The pointer to the rectangle
191 \param t The pointer to the RTree
192 \param x_min The lower x coordinate
193 \param x_max The higher x coordinate
194 \param y_min The lower y coordinate
195 \param y_max The higher y coordinate
196 \param z_min The lower z coordinate
197 \param z_max The higher z coordinate
198 \param t_min The lower t coordinate
199 \param t_max The higher t coordinate
200 */
201void RTreeSetRect4D(struct RTree_Rect *r, struct RTree *t, double x_min,
202 double x_max, double y_min, double y_max, double z_min,
203 double z_max, double t_min, double t_max)
204{
205 assert(t->ndims >= 4);
206
207 RTreeInitRect(r, t);
208 r->boundary[0] = (RectReal)x_min;
209 r->boundary[t->ndims_alloc] = (RectReal)x_max;
210 r->boundary[1] = (RectReal)y_min;
211 r->boundary[1 + t->ndims_alloc] = (RectReal)y_max;
212 r->boundary[2] = (RectReal)z_min;
213 r->boundary[2 + t->ndims_alloc] = (RectReal)z_max;
214 r->boundary[3] = (RectReal)t_min;
215 r->boundary[3 + t->ndims_alloc] = (RectReal)t_max;
216}
217
218/*
219 Return a rect whose first low side is higher than its opposite side -
220 interpreted as an undefined rect.
221 */
222void RTreeNullRect(struct RTree_Rect *r, struct RTree *t)
223{
224 register int i;
225
226 /* assert(r); */
227
228 r->boundary[0] = (RectReal)1;
229 r->boundary[t->nsides_alloc - 1] = (RectReal)-1;
230 for (i = 1; i < t->ndims_alloc; i++)
231 r->boundary[i] = r->boundary[i + t->ndims_alloc] = (RectReal)0;
232
233 return;
234}
235
236#if 0
237
238/*
239 Fills in random coordinates in a rectangle.
240 The low side is guaranteed to be less than the high side.
241 */
242void RTreeRandomRect(struct RTree_Rect *R)
243{
244 register struct RTree_Rect *r = R;
245 register int i;
246 register RectReal width;
247
248 for (i = 0; i < NUMDIMS; i++) {
249 /* width from 1 to 1000 / 4, more small ones
250 */
251 width = drand48() * (1000 / 4) + 1;
252
253 /* sprinkle a given size evenly but so they stay in [0,100]
254 */
255 r->boundary[i] = drand48() * (1000 - width); /* low side */
256 r->boundary[i + NUMDIMS] = r->boundary[i] + width; /* high side */
257 }
258}
259
260
261/*
262 Fill in the boundaries for a random search rectangle.
263 Pass in a pointer to a rect that contains all the data,
264 and a pointer to the rect to be filled in.
265 Generated rect is centered randomly anywhere in the data area,
266 and has size from 0 to the size of the data area in each dimension,
267 i.e. search rect can stick out beyond data area.
268 */
269void RTreeSearchRect(struct RTree_Rect *Search, struct RTree_Rect *Data)
270{
271 register struct RTree_Rect *search = Search, *data = Data;
272 register int i, j;
273 register RectReal size, center;
274
275 assert(search);
276 assert(data);
277
278 for (i = 0; i < NUMDIMS; i++) {
279 j = i + NUMDIMS; /* index for high side boundary */
280 if (data->boundary[i] > -BIG_NUM && data->boundary[j] < BIG_NUM) {
281 size = (drand48() * (data->boundary[j] -
282 data->boundary[i] + 1)) / 2;
283 center = data->boundary[i] + drand48() *
284 (data->boundary[j] - data->boundary[i] + 1);
285 search->boundary[i] = center - size / 2;
286 search->boundary[j] = center + size / 2;
287 }
288 else { /* some open boundary, search entire dimension */
289
290 search->boundary[i] = -BIG_NUM;
291 search->boundary[j] = BIG_NUM;
292 }
293 }
294}
295
296#endif
297
298/*
299 Print out the data for a rectangle.
300 */
301void RTreePrintRect(struct RTree_Rect *R, int depth, struct RTree *t)
302{
303 register struct RTree_Rect *r = R;
304 register int i;
305
306 assert(r);
307
308 RTreeTabIn(depth);
309 fprintf(stdout, "rect:\n");
310 for (i = 0; i < t->ndims_alloc; i++) {
311 RTreeTabIn(depth + 1);
312 fprintf(stdout, "%f\t%f\n", r->boundary[i],
313 r->boundary[i + t->ndims_alloc]);
314 }
315}
316
317/*
318 Calculate the n-dimensional volume of a rectangle
319 */
321{
322 register struct RTree_Rect *r = R;
323 register int i;
324 register RectReal volume = (RectReal)1;
325
326 /* assert(r); */
327
328 if (Undefined(r, t))
329 return (RectReal)0;
330
331 for (i = 0; i < t->ndims; i++)
332 volume *= r->boundary[i + t->ndims_alloc] - r->boundary[i];
333 assert(volume >= 0.0);
334
335 return volume;
336}
337
338/*
339 Define the NUMDIMS-dimensional volume the unit sphere in that dimension into
340 the symbol "UnitSphereVolume"
341 Note that if the gamma function is available in the math library and if the
342 compiler supports static initialization using functions, this is
343 easily computed for any dimension. If not, the value can be precomputed and
344 taken from a table. The following code can do it either way.
345 */
346
347#ifdef gamma
348
349/* computes the volume of an N-dimensional sphere. */
350/* derived from formula in "Regular Polytopes" by H.S.M Coxeter */
351static double sphere_volume(double dimension)
352{
353 double log_gamma, log_volume;
354
355 log_gamma = gamma(dimension / 2.0 + 1);
356 log_volume = dimension / 2.0 * log(M_PI) - log_gamma;
357 return exp(log_volume);
358}
359
360static const double UnitSphereVolume = sphere_volume(20);
361
362#else
363
364/* Precomputed volumes of the unit spheres for the first few dimensions */
365const double UnitSphereVolumes[] = {
366 0.000000, /* dimension 0 */
367 2.000000, /* dimension 1 */
368 3.141593, /* dimension 2 */
369 4.188790, /* dimension 3 */
370 4.934802, /* dimension 4 */
371 5.263789, /* dimension 5 */
372 5.167713, /* dimension 6 */
373 4.724766, /* dimension 7 */
374 4.058712, /* dimension 8 */
375 3.298509, /* dimension 9 */
376 2.550164, /* dimension 10 */
377 1.884104, /* dimension 11 */
378 1.335263, /* dimension 12 */
379 0.910629, /* dimension 13 */
380 0.599265, /* dimension 14 */
381 0.381443, /* dimension 15 */
382 0.235331, /* dimension 16 */
383 0.140981, /* dimension 17 */
384 0.082146, /* dimension 18 */
385 0.046622, /* dimension 19 */
386 0.025807, /* dimension 20 */
387};
388
389#if NUMDIMS > 20
390#error "not enough precomputed sphere volumes"
391#endif
392#define UnitSphereVolume UnitSphereVolumes[NUMDIMS]
393
394#endif
395
396/*
397 Calculate the n-dimensional volume of the bounding sphere of a rectangle
398 */
399
400#if 0
401/*
402 * A fast approximation to the volume of the bounding sphere for the
403 * given Rect. By Paul B.
404 */
406{
407 register struct RTree_Rect *r = R;
408 register int i;
409 RectReal maxsize = (RectReal) 0, c_size;
410
411 /* assert(r); */
412
413 if (Undefined(r, t))
414 return (RectReal) 0;
415
416 for (i = 0; i < t->ndims; i++) {
417 c_size = r->boundary[i + NUMDIMS] - r->boundary[i];
418 if (c_size > maxsize)
419 maxsize = c_size;
420 }
421 return (RectReal) (pow(maxsize / 2, NUMDIMS) *
422 UnitSphereVolumes[t->ndims]);
423}
424#endif
425
426/*
427 * The exact volume of the bounding sphere for the given Rect.
428 */
430{
431 int i;
432 double sum_of_squares = 0, extent;
433
434 /* assert(r); */
435
436 if (Undefined(r, t))
437 return (RectReal)0;
438
439 for (i = 0; i < t->ndims; i++) {
440 extent = (r->boundary[i + t->ndims_alloc] - r->boundary[i]);
441
442 /* extent should be half extent : /4 */
443 sum_of_squares += extent * extent / 4.;
444 }
445
446 return (RectReal)(pow(sqrt(sum_of_squares), t->ndims) *
447 UnitSphereVolumes[t->ndims]);
448}
449
450/*
451 Calculate the n-dimensional surface area of a rectangle
452 */
454{
455 int i, j;
456 RectReal face_area, sum = (RectReal)0;
457
458 /*assert(r); */
459
460 if (Undefined(r, t))
461 return (RectReal)0;
462
463 for (i = 0; i < t->ndims; i++) {
464 face_area = (RectReal)1;
465
466 for (j = 0; j < t->ndims; j++)
467 /* exclude i extent from product in this dimension */
468 if (i != j) {
469 face_area *= (r->boundary[j + t->ndims_alloc] - r->boundary[j]);
470 }
471 sum += face_area;
472 }
473 return 2 * sum;
474}
475
476/*
477 Calculate the n-dimensional margin of a rectangle
478 the margin is the sum of the lengths of the edges
479 */
481{
482 int i;
483 RectReal margin = 0.0;
484
485 /* assert(r); */
486
487 for (i = 0; i < t->ndims; i++) {
488 margin += r->boundary[i + t->ndims_alloc] - r->boundary[i];
489 }
490
491 return margin;
492}
493
494/*
495 Combine two rectangles, make one that includes both.
496 */
498 struct RTree_Rect *r3, struct RTree *t)
499{
500 int i, j;
501
502 /* assert(r1 && r2 && r3); */
503
504 if (Undefined(r1, t)) {
505 for (i = 0; i < t->nsides_alloc; i++)
506 r3->boundary[i] = r2->boundary[i];
507
508 return;
509 }
510
511 if (Undefined(r2, t)) {
512 for (i = 0; i < t->nsides_alloc; i++)
513 r3->boundary[i] = r1->boundary[i];
514
515 return;
516 }
517
518 for (i = 0; i < t->ndims; i++) {
519 r3->boundary[i] = MIN(r1->boundary[i], r2->boundary[i]);
520 j = i + t->ndims_alloc;
521 r3->boundary[j] = MAX(r1->boundary[j], r2->boundary[j]);
522 }
523 for (i = t->ndims; i < t->ndims_alloc; i++) {
524 r3->boundary[i] = 0;
525 j = i + t->ndims_alloc;
526 r3->boundary[j] = 0;
527 }
528}
529
530/*
531 Expand first rectangle to cover second rectangle.
532 */
534 struct RTree *t)
535{
536 int i, j, ret = 0;
537
538 /* assert(r1 && r2); */
539
540 if (Undefined(r2, t))
541 return ret;
542
543 for (i = 0; i < t->ndims; i++) {
544 if (r1->boundary[i] > r2->boundary[i]) {
545 r1->boundary[i] = r2->boundary[i];
546 ret = 1;
547 }
548 j = i + t->ndims_alloc;
549 if (r1->boundary[j] < r2->boundary[j]) {
550 r1->boundary[j] = r2->boundary[j];
551 ret = 1;
552 }
553 }
554
555 for (i = t->ndims; i < t->ndims_alloc; i++) {
556 r1->boundary[i] = 0;
557 j = i + t->ndims_alloc;
558 r1->boundary[j] = 0;
559 }
560
561 return ret;
562}
563
564/*
565 Decide whether two rectangles are identical.
566 */
568 struct RTree *t)
569{
570 register int i, j;
571
572 /* assert(r && s); */
573
574 for (i = 0; i < t->ndims; i++) {
575 j = i + t->ndims_alloc; /* index for high sides */
576 if (r->boundary[i] != s->boundary[i] ||
577 r->boundary[j] != s->boundary[j]) {
578 return 0;
579 }
580 }
581 return 1;
582}
583
584/*
585 Decide whether two rectangles overlap or touch.
586 */
587int RTreeOverlap(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
588{
589 register int i, j;
590
591 /* assert(r && s); */
592
593 for (i = 0; i < t->ndims; i++) {
594 j = i + t->ndims_alloc; /* index for high sides */
595 if (r->boundary[i] > s->boundary[j] ||
596 s->boundary[i] > r->boundary[j]) {
597 return FALSE;
598 }
599 }
600 return TRUE;
601}
602
603/*
604 Decide whether rectangle s is contained in rectangle r.
605 */
606int RTreeContained(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
607{
608 register int i, j;
609
610 /* assert(r && s); */
611
612 /* undefined rect is contained in any other */
613 if (Undefined(r, t))
614 return TRUE;
615
616 /* no rect (except an undefined one) is contained in an undef rect */
617 if (Undefined(s, t))
618 return FALSE;
619
620 for (i = 0; i < t->ndims; i++) {
621 j = i + t->ndims_alloc; /* index for high sides */
622 if (s->boundary[i] < r->boundary[i] || s->boundary[j] > r->boundary[j])
623 return FALSE;
624 }
625 return TRUE;
626}
627
628/*
629 Decide whether rectangle s fully contains rectangle r.
630 */
631int RTreeContains(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
632{
633 register int i, j;
634
635 /* assert(r && s); */
636
637 /* undefined rect is contained in any other */
638 if (Undefined(r, t))
639 return TRUE;
640
641 /* no rect (except an undefined one) is contained in an undef rect */
642 if (Undefined(s, t))
643 return FALSE;
644
645 for (i = 0; i < t->ndims; i++) {
646 j = i + t->ndims_alloc; /* index for high sides */
647 if (s->boundary[i] > r->boundary[i] || s->boundary[j] < r->boundary[j])
648 return FALSE;
649 }
650 return TRUE;
651}
#define NULL
Definition ccmath.h:32
double sphere_volume(double dimension)
Definition gammavol.c:24
#define MIN(a, b)
Definition gis.h:150
#define TRUE
Definition gis.h:75
#define FALSE
Definition gis.h:79
#define M_PI
Definition gis.h:154
#define MAX(a, b)
Definition gis.h:145
void RTreeTabIn(int)
Definition node.c:599
#define assert(condition)
Definition lz4.c:291
double t
Definition r_raster.c:37
double r
Definition r_raster.c:37
struct RTree_Rect * RTreeAllocRect(struct RTree *t)
Create a new rectangle for a given tree.
Definition rect.c:39
void RTreeFreeRect(struct RTree_Rect *r)
Delete a rectangle.
Definition rect.c:60
void RTreeNullRect(struct RTree_Rect *r, struct RTree *t)
Definition rect.c:222
const double UnitSphereVolumes[]
Definition rect.c:365
#define Undefined(x, t)
Definition rect.c:26
void RTreeCombineRect(struct RTree_Rect *r1, struct RTree_Rect *r2, struct RTree_Rect *r3, struct RTree *t)
Definition rect.c:497
#define BIG_NUM
Definition rect.c:24
RectReal RTreeRectVolume(struct RTree_Rect *R, struct RTree *t)
Definition rect.c:320
void RTreeFreeBoundary(struct RTree_Rect *r)
Delete the boundary of a rectangle.
Definition rect.c:95
void RTreeSetRect1D(struct RTree_Rect *r, struct RTree *t, double x_min, double x_max)
Set one dimensional coordinates of a rectangle for a given tree.
Definition rect.c:125
void RTreeSetRect2D(struct RTree_Rect *r, struct RTree *t, double x_min, double x_max, double y_min, double y_max)
Set two dimensional coordinates of a rectangle for a given tree.
Definition rect.c:146
void RTreeSetRect4D(struct RTree_Rect *r, struct RTree *t, double x_min, double x_max, double y_min, double y_max, double z_min, double z_max, double t_min, double t_max)
Set 4 dimensional coordinates of a rectangle for a given tree.
Definition rect.c:201
void RTreeInitRect(struct RTree_Rect *r, struct RTree *t)
Initialize a rectangle to have all 0 coordinates.
Definition rect.c:106
RectReal * RTreeAllocBoundary(struct RTree *t)
Allocate the boundary array of a rectangle for a given tree.
Definition rect.c:78
int RTreeContains(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
Definition rect.c:631
RectReal RTreeRectSurfaceArea(struct RTree_Rect *r, struct RTree *t)
Definition rect.c:453
int RTreeExpandRect(struct RTree_Rect *r1, struct RTree_Rect *r2, struct RTree *t)
Definition rect.c:533
RectReal RTreeRectMargin(struct RTree_Rect *r, struct RTree *t)
Definition rect.c:480
int RTreeOverlap(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
Definition rect.c:587
int RTreeContained(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
Definition rect.c:606
int RTreeCompareRect(struct RTree_Rect *r, struct RTree_Rect *s, struct RTree *t)
Definition rect.c:567
#define UnitSphereVolume
Definition rect.c:392
void RTreePrintRect(struct RTree_Rect *R, int depth, struct RTree *t)
Definition rect.c:301
RectReal RTreeRectSphericalVolume(struct RTree_Rect *r, struct RTree *t)
Definition rect.c:429
void RTreeSetRect3D(struct RTree_Rect *r, struct RTree *t, double x_min, double x_max, double y_min, double y_max, double z_min, double z_max)
Set three dimensional coordinates of a rectangle for a given tree.
Definition rect.c:171
double RectReal
Definition rtree.h:23
void * malloc(unsigned)
void free(void *)
RectReal * boundary
Definition rtree.h:52
Definition rtree.h:120