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