GRASS 8 Programmer's Manual 8.6.0dev(2026)-4bb960b182
Loading...
Searching...
No Matches
vector/rtree/index.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/rtree/index.c
3
4 \brief R-Tree library - Multidimensional index
5
6 Higher level functions for managing R*-Trees.
7
8 SPDX-FileCopyrightText: 2010-2012 GRASS Development Team
9 SPDX-License-Identifier: GPL-2.0-or-later
10
11 \author Antonin Guttman - original code
12 \author Daniel Green (green@superliminal.com) - major clean-up
13 and implementation of bounding spheres
14 \author Markus Metz - file-based and memory-based R*-tree
15 */
16
17/* Read these articles first before attempting to modify the code
18 *
19 * R-Tree reference:
20 * Guttman, A. (1984). "R-Trees: A Dynamic Index Structure for Spatial
21 * Searching". Proceedings of the 1984 ACM SIGMOD international
22 * conference on Management of data - SIGMOD '84. pp. 47.
23 * DOI:10.1145/602259.602266
24 * ISBN 0897911288
25 *
26 * R*-Tree reference:
27 * Beckmann, N.; Kriegel, H. P.; Schneider, R.; Seeger, B. (1990).
28 * "The R*-tree: an efficient and robust access method for points and
29 * rectangles". Proceedings of the 1990 ACM SIGMOD international
30 * conference on Management of data - SIGMOD '90. pp. 322.
31 * DOI:10.1145/93597.98741
32 * ISBN 0897913655
33 */
34
35#include <stdlib.h>
36#include <sys/types.h>
37#include <unistd.h>
38#include <assert.h>
39#include <string.h>
40#include <errno.h>
41
42#include <grass/gis.h>
43#include <grass/glocale.h>
44
45#include "index.h"
46
47/*!
48 \brief Create new empty R*-Tree
49
50 This method creates a new RTree, either in memory (fd < 0) or in file.
51 If the file descriptor is positive, the corresponding file must have
52 been opened for reading and writing.
53 This method must also be called if an existing tree previously saved
54 to file is going to be accessed.
55
56 \param fd file descriptor to hold data, negative toggles memory mode
57 \param rootpos offset in file to root node (past any header info)
58 \param ndims number of dimensions for the new tree: min 2, max 20
59
60 \return pointer to new RTree structure
61 */
63{
64 struct RTree *new_rtree;
65 struct RTree_Node *n;
66 int i, j, k;
67
68 new_rtree = (struct RTree *)malloc(sizeof(struct RTree));
69
70 new_rtree->fd = fd;
71 new_rtree->rootpos = rootpos;
72 new_rtree->ndims = ndims;
73 new_rtree->nsides = 2 * ndims;
74 /* hack to keep compatibility */
75 if (ndims < 3)
76 new_rtree->ndims_alloc = 3;
77 else
78 new_rtree->ndims_alloc = ndims;
79
80 new_rtree->nsides_alloc = 2 * new_rtree->ndims_alloc;
81
82 /* init free node positions */
83 new_rtree->free_nodes.avail = 0;
84 new_rtree->free_nodes.alloc = 0;
85 new_rtree->free_nodes.pos = NULL;
86
87 new_rtree->rectsize = new_rtree->nsides_alloc * sizeof(RectReal);
88 new_rtree->branchsize = sizeof(struct RTree_Branch) -
89 sizeof(struct RTree_Rect) + new_rtree->rectsize;
90 new_rtree->nodesize = sizeof(struct RTree_Node) -
92 MAXCARD * new_rtree->branchsize;
93
94 /* create empty root node */
96 new_rtree->rootlevel = n->level = 0; /* leaf */
97
98 /* use overflow by default */
99 new_rtree->overflow = 1;
100
101 if (fd > -1) { /* file based */
102 /* nodecard and leafcard can be adjusted, must NOT be larger than
103 * MAXCARD */
104 new_rtree->nodecard = MAXCARD;
105 new_rtree->leafcard = MAXCARD;
106
107 /* initialize node buffer */
108 new_rtree->nb = calloc(MAXLEVEL, sizeof(struct NodeBuffer *));
109 new_rtree->nb[0] =
110 calloc(MAXLEVEL * NODE_BUFFER_SIZE, sizeof(struct NodeBuffer));
111 for (i = 1; i < MAXLEVEL; i++) {
112 new_rtree->nb[i] = new_rtree->nb[i - 1] + NODE_BUFFER_SIZE;
113 }
114
115 new_rtree->used = malloc(MAXLEVEL * sizeof(int *));
116 new_rtree->used[0] = malloc(MAXLEVEL * NODE_BUFFER_SIZE * sizeof(int));
117 for (i = 0; i < MAXLEVEL; i++) {
118 if (i)
119 new_rtree->used[i] = new_rtree->used[i - 1] + NODE_BUFFER_SIZE;
120 for (j = 0; j < NODE_BUFFER_SIZE; j++) {
121 new_rtree->nb[i][j].dirty = 0;
122 new_rtree->nb[i][j].pos = -1;
123 /* usage order */
124 new_rtree->used[i][j] = j;
125
126 new_rtree->nb[i][j].n.branch =
127 malloc(MAXCARD * sizeof(struct RTree_Branch));
128
129 /* alloc memory for rectangles */
130 for (k = 0; k < MAXCARD; k++) {
131 new_rtree->nb[i][j].n.branch[k].rect.boundary =
133 }
134 }
135 }
136
137 /* write empty root node */
138 if (lseek(new_rtree->fd, rootpos, SEEK_SET) == -1) {
139 int err = errno;
140 G_fatal_error(_("File read/write operation failed: %s (%d)"),
141 strerror(err), err);
142 }
144 RTreeFreeNode(n);
145 new_rtree->root = NULL;
146
147 new_rtree->insert_rect = RTreeInsertRectF;
148 new_rtree->delete_rect = RTreeDeleteRectF;
149 new_rtree->search_rect = RTreeSearchF;
150 new_rtree->valid_child = RTreeValidChildF;
151 }
152 else { /* memory based */
153 new_rtree->nodecard = MAXCARD;
154 new_rtree->leafcard = MAXCARD;
155
156 new_rtree->insert_rect = RTreeInsertRectM;
157 new_rtree->delete_rect = RTreeDeleteRectM;
158 new_rtree->search_rect = RTreeSearchM;
159 new_rtree->valid_child = RTreeValidChildM;
160
161 new_rtree->root = n;
162 }
163
164 /* minimum number of remaining children for RTreeDeleteRect */
165 /* NOTE: min fill can be changed if needed, must be < nodecard and leafcard.
166 */
167 new_rtree->min_node_fill = (new_rtree->nodecard - 2) / 2;
168 new_rtree->min_leaf_fill = (new_rtree->leafcard - 2) / 2;
169
170 /* balance criteria for node splitting */
171 new_rtree->minfill_node_split = (new_rtree->nodecard - 1) / 2;
172 new_rtree->minfill_leaf_split = (new_rtree->leafcard - 1) / 2;
173
174 new_rtree->n_nodes = 1;
175 new_rtree->n_leafs = 0;
176
177 /* initialize temp variables */
178 new_rtree->ns = malloc(MAXLEVEL * sizeof(struct nstack));
179
180 new_rtree->p.cover[0].boundary = RTreeAllocBoundary(new_rtree);
181 new_rtree->p.cover[1].boundary = RTreeAllocBoundary(new_rtree);
182
183 new_rtree->tmpb1.rect.boundary = RTreeAllocBoundary(new_rtree);
184 new_rtree->tmpb2.rect.boundary = RTreeAllocBoundary(new_rtree);
185 new_rtree->c.rect.boundary = RTreeAllocBoundary(new_rtree);
186
187 new_rtree->BranchBuf = malloc((MAXCARD + 1) * sizeof(struct RTree_Branch));
188 for (i = 0; i <= MAXCARD; i++) {
189 new_rtree->BranchBuf[i].rect.boundary = RTreeAllocBoundary(new_rtree);
190 }
191 new_rtree->rect_0.boundary = RTreeAllocBoundary(new_rtree);
192 new_rtree->rect_1.boundary = RTreeAllocBoundary(new_rtree);
193 new_rtree->upperrect.boundary = RTreeAllocBoundary(new_rtree);
194 new_rtree->orect.boundary = RTreeAllocBoundary(new_rtree);
195 new_rtree->center_n =
196 (RectReal *)malloc(new_rtree->ndims_alloc * sizeof(RectReal));
197
198 return new_rtree;
199}
200
201/*!
202 \brief Enable/disable R*-tree forced reinsertion (overflow)
203
204 For dynamic R*-trees with runtime insertion and deletion,
205 forced reinsertion results in a more compact tree, searches are a bit
206 faster. For static R*-trees (no insertion/deletion after creation)
207 forced reinsertion can be disabled at the cost of slower searches.
208
209 \param t pointer to RTree structure
210 \param overflow binary flag
211
212 \return nothing
213 */
214void RTreeSetOverflow(struct RTree *t, char overflow)
215{
216 t->overflow = overflow != 0;
217}
218
219/*!
220 \brief Destroy an R*-Tree
221
222 This method releases all memory allocated to a RTree. It deletes all
223 rectangles and all memory allocated for internal support data.
224 Note that for a file-based RTree, the file is not deleted and not
225 closed. The file can thus be used to permanently store an RTree.
226
227 \param t pointer to RTree structure
228
229 \return nothing
230 */
232{
233 int i;
234
235 assert(t);
236
237 if (t->fd > -1) {
238 int j, k;
239
240 for (i = 0; i < MAXLEVEL; i++) {
241 for (j = 0; j < NODE_BUFFER_SIZE; j++) {
242 for (k = 0; k < MAXCARD; k++) {
243 RTreeFreeBoundary(&t->nb[i][j].n.branch[k].rect);
244 }
245 free(t->nb[i][j].n.branch);
246 }
247 }
248
249 if (t->free_nodes.alloc)
250 free(t->free_nodes.pos);
251 free(t->nb[0]);
252 free(t->nb);
253 free(t->used[0]);
254 free(t->used);
255 }
256 else if (t->root)
257 RTreeDestroyNode(t->root, t->root->level ? t->nodecard : t->leafcard);
258
259 /* free temp variables */
260 free(t->ns);
261
262 RTreeFreeBoundary(&(t->p.cover[0]));
263 RTreeFreeBoundary(&(t->p.cover[1]));
264
265 RTreeFreeBoundary(&(t->tmpb1.rect));
266 RTreeFreeBoundary(&(t->tmpb2.rect));
267 RTreeFreeBoundary(&(t->c.rect));
268 for (i = 0; i <= MAXCARD; i++) {
269 RTreeFreeBoundary(&(t->BranchBuf[i].rect));
270 }
271 free(t->BranchBuf);
272 RTreeFreeBoundary(&(t->rect_0));
273 RTreeFreeBoundary(&(t->rect_1));
274 RTreeFreeBoundary(&(t->upperrect));
275 RTreeFreeBoundary(&(t->orect));
276 free(t->center_n);
277
278 free(t);
279
280 return;
281}
282
283/*!
284 \brief Search an R*-Tree
285
286 Search in an RTree for all data rectangles that overlap or touch the
287 argument rectangle.
288 Return the number of qualifying data rectangles.
289 The search stops if the SearchHitCallBack function returns 0 (zero)
290 or if there are no more qualifying data rectangles.
291
292 \param t pointer to RTree structure
293 \param r pointer to rectangle to use for searching
294 \param shcb Search Hit CallBack function
295 \param cbarg custom pointer used as argument for the shcb fn
296
297 \return number of qualifying data rectangles
298 */
299/*
300 *
301 * add option to select operator to select rectangles ?
302 * current: overlap
303 * possible alternatives:
304 * - select all rectangles that are fully contained in r
305 * - select all rectangles that fully contain r
306 */
308 void *cbarg)
309{
310 assert(r && t);
311
312 return t->search_rect(t, r, shcb, cbarg);
313}
314
315/*!
316 \brief Insert an item into a R*-Tree
317
318 \param r pointer to rectangle to use for searching
319 \param tid data id stored with rectangle, must be > 0
320 \param t pointer to RTree structure
321
322 \return number of qualifying data rectangles
323 */
324int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
325{
326 union RTree_Child newchild;
327
328 assert(r && t && tid > 0);
329
330 t->n_leafs++;
331 newchild.id = tid;
332
333 return t->insert_rect(r, newchild, 0, t);
334}
335
336/*!
337 \brief Delete an item from a R*-Tree
338
339 This method deletes an item from the RTree. The rectangle passed to
340 this method does not need to be the exact rectangle, the only
341 requirement is that this rectangle overlaps with the rectangle to
342 be deleted. The rectangle to be deleted is identified by its id.
343
344 \param r pointer to rectangle to use for searching
345 \param tid id of the data to be deleted, must be > 0
346 \param t pointer to RTree structure
347
348 \return 0 on success
349 \return 1 if data item not found
350 */
351int RTreeDeleteRect(struct RTree_Rect *r, int tid, struct RTree *t)
352{
353 union RTree_Child child;
354
355 assert(r && t && tid > 0);
356
357 child.id = tid;
358
359 return t->delete_rect(r, child, t);
360}
361
362/***********************************
363 * internally used functions *
364 ***********************************/
365
366/*
367 * Allocate space for a node in the list used in DeleteRect to
368 * store Nodes that are too empty.
369 */
371{
372 return (struct RTree_ListNode *)malloc(sizeof(struct RTree_ListNode));
373}
374
376{
377 free(p);
378}
379
380/*
381 * Add a node to the reinsertion list. All its branches will later
382 * be reinserted into the index structure.
383 */
385{
387
388 l->node = n;
389 l->next = *ee;
390 *ee = l;
391}
392
393/*
394 * Free ListBranch, used by R*-type forced reinsertion
395 */
397{
398 RTreeFreeBoundary(&(p->b.rect));
399 free(p);
400}
#define NULL
Definition ccmath.h:32
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
#define _(str)
Definition glocale.h:10
int RTreeSearchM(struct RTree *, struct RTree_Rect *, SearchHitCallback *, void *)
Definition indexm.c:30
int RTreeInsertRectF(struct RTree_Rect *, union RTree_Child, int, struct RTree *)
Definition indexf.c:210
int RTreeDeleteRectM(struct RTree_Rect *, union RTree_Child, struct RTree *)
Definition indexm.c:349
int RTreeSearchF(struct RTree *, struct RTree_Rect *, SearchHitCallback *, void *)
Definition indexf.c:33
int RTreeInsertRectM(struct RTree_Rect *, union RTree_Child, int, struct RTree *)
Definition indexm.c:182
int RTreeDeleteRectF(struct RTree_Rect *, union RTree_Child, struct RTree *)
Definition indexf.c:405
int RTreeValidChildM(union RTree_Child *child)
Definition indexm.c:20
int RTreeValidChildF(union RTree_Child *)
Definition indexf.c:23
size_t RTreeWriteNode(struct RTree_Node *n, struct RTree *t)
Definition io.c:174
#define assert(condition)
Definition lz4.c:291
void RTreeFreeNode(struct RTree_Node *n)
Definition node.c:92
void RTreeDestroyNode(struct RTree_Node *n, int nodes)
Definition node.c:287
struct RTree_Node * RTreeAllocNode(struct RTree *t, int level)
Definition node.c:71
double l
Definition r_raster.c:37
double t
Definition r_raster.c:37
double r
Definition r_raster.c:37
void RTreeFreeBoundary(struct RTree_Rect *r)
Delete the boundary of a rectangle.
Definition rect.c:95
RectReal * RTreeAllocBoundary(struct RTree *t)
Allocate the boundary array of a rectangle for a given tree.
Definition rect.c:78
#define MAXCARD
Definition rtree.h:41
int SearchHitCallback(int id, const struct RTree_Rect *rect, void *arg)
Definition rtree.h:83
#define NODE_BUFFER_SIZE
Definition rtree.h:49
double RectReal
Definition rtree.h:23
void * malloc(unsigned)
void free(void *)
struct RTree_Branch b
Definition index.h:42
int level
Definition rtree.h:72
Definition rtree.h:120
off_t rootpos
Definition rtree.h:184
int fd
Definition rtree.h:122
unsigned char ndims
Definition rtree.h:123
Definition rtree.h:97
SYMBOL * err(FILE *fp, SYMBOL *s, char *msg)
int id
Definition rtree.h:58
int RTreeDeleteRect(struct RTree_Rect *r, int tid, struct RTree *t)
Delete an item from a R*-Tree.
void RTreeSetOverflow(struct RTree *t, char overflow)
Enable/disable R*-tree forced reinsertion (overflow)
void RTreeFreeListNode(struct RTree_ListNode *p)
void RTreeReInsertNode(struct RTree_Node *n, struct RTree_ListNode **ee)
struct RTree * RTreeCreateTree(int fd, off_t rootpos, int ndims)
Create new empty R*-Tree.
struct RTree_ListNode * RTreeNewListNode(void)
int RTreeInsertRect(struct RTree_Rect *r, int tid, struct RTree *t)
Insert an item into a R*-Tree.
void RTreeDestroyTree(struct RTree *t)
Destroy an R*-Tree.
int RTreeSearch(struct RTree *t, struct RTree_Rect *r, SearchHitCallback *shcb, void *cbarg)
Search an R*-Tree.
void RTreeFreeListBranch(struct RTree_ListBranch *p)
#define MAXLEVEL
Maximum verbosity level.
Definition verbose.c:28