librtree 0.9.1 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +80 -0
  3. data/COPYING +21 -0
  4. data/README.md +87 -0
  5. data/ext/rtree/extconf.rb +37 -19
  6. data/ext/rtree/lib/README.md +9 -0
  7. data/ext/rtree/lib/bindex.c +157 -0
  8. data/ext/rtree/lib/bindex.h +31 -0
  9. data/ext/rtree/lib/bounds.h +21 -0
  10. data/ext/rtree/lib/branch.c +51 -0
  11. data/ext/rtree/lib/branches.c +17 -0
  12. data/ext/rtree/lib/bsrt.c +704 -0
  13. data/ext/rtree/lib/bsrt.h +16 -0
  14. data/ext/rtree/lib/constants.h +19 -0
  15. data/ext/rtree/lib/csv.c +81 -0
  16. data/ext/rtree/lib/csv.h +16 -0
  17. data/ext/rtree/lib/endianness.h +83 -0
  18. data/ext/rtree/lib/error.c +47 -0
  19. data/ext/rtree/lib/json.c +491 -0
  20. data/ext/rtree/lib/json.h +16 -0
  21. data/ext/rtree/lib/mk/Hdr.mk +3 -0
  22. data/ext/rtree/lib/mk/MakeDepend +25 -0
  23. data/ext/rtree/lib/mk/Obj.mk +3 -0
  24. data/ext/rtree/lib/node.c +736 -0
  25. data/ext/rtree/lib/package.c +11 -0
  26. data/ext/rtree/lib/page.c +47 -0
  27. data/ext/rtree/lib/page.h +13 -0
  28. data/ext/rtree/lib/postscript.c +543 -0
  29. data/ext/rtree/lib/rect.c +139 -0
  30. data/ext/rtree/lib/rectf.c +219 -0
  31. data/ext/rtree/lib/rtree/branch.h +105 -0
  32. data/ext/rtree/lib/rtree/branches.h +38 -0
  33. data/ext/rtree/lib/rtree/error.h +42 -0
  34. data/ext/rtree/lib/rtree/extent.h +20 -0
  35. data/ext/rtree/lib/rtree/node.h +96 -0
  36. data/ext/rtree/lib/rtree/package.h +14 -0
  37. data/ext/rtree/lib/rtree/postscript.h +66 -0
  38. data/ext/rtree/lib/rtree/rect.h +38 -0
  39. data/ext/rtree/lib/rtree/rectf.h +34 -0
  40. data/ext/rtree/lib/rtree/search.h +27 -0
  41. data/ext/rtree/lib/rtree/state.h +113 -0
  42. data/ext/rtree/lib/rtree/types.h +14 -0
  43. data/ext/rtree/lib/rtree-base.c +197 -0
  44. data/ext/rtree/lib/rtree.h +62 -0
  45. data/ext/rtree/lib/search.c +54 -0
  46. data/ext/rtree/lib/split.c +710 -0
  47. data/ext/rtree/lib/split.h +15 -0
  48. data/ext/rtree/lib/spvol.c +48 -0
  49. data/ext/rtree/lib/spvol.h +13 -0
  50. data/ext/rtree/lib/state.c +169 -0
  51. data/ext/rtree/rtree.c +11 -0
  52. data/lib/rtree.rb +4 -4
  53. metadata +65 -3
@@ -0,0 +1,736 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include "config.h"
3
+ #endif
4
+
5
+ #include "rtree/node.h"
6
+ #include "rtree/branches.h"
7
+ #include "rtree/rect.h"
8
+ #include "rtree/error.h"
9
+
10
+ #include "split.h"
11
+
12
+ #include <stdbool.h>
13
+ #include <stddef.h>
14
+ #include <string.h>
15
+ #include <stdlib.h>
16
+ #include <assert.h>
17
+ #include <errno.h>
18
+
19
+ #ifdef HAVE_TGMATH_H
20
+ #include <tgmath.h>
21
+ #else
22
+ #include <math.h>
23
+ #endif
24
+
25
+ /*
26
+ how many branches can we fit at the end of a node of the specified
27
+ size, typically this will be a fraction of a page size. This does
28
+ not take a state_t* as argument since it is used to initialise it.
29
+ */
30
+
31
+ size_t node_num_branch(size_t node_size, size_t branch_size)
32
+ {
33
+ return (node_size - offsetof(node_t, branches)) / branch_size;
34
+ }
35
+
36
+ static branch_t* node_get_branch(const state_t *state,
37
+ const node_t *node, size_t i)
38
+ {
39
+ return branches_get(state, (void*)node->branches, i);
40
+ }
41
+
42
+ int node_init(const state_t *state, node_t *node)
43
+ {
44
+ node->count = 0;
45
+ node->level = 0;
46
+
47
+ const size_t n = state_branching_factor(state);
48
+
49
+ for (size_t i = 0 ; i < n ; i++)
50
+ {
51
+ int err = branch_init(state, node_get_branch(state, node, i));
52
+ if (err != RTREE_OK)
53
+ return err;
54
+ }
55
+
56
+ return RTREE_OK;
57
+ }
58
+
59
+ node_t* node_new(const state_t *state)
60
+ {
61
+ node_t *node;
62
+
63
+ if ((node = malloc(state_node_size(state))) == NULL)
64
+ errno = ENOMEM;
65
+ else
66
+ {
67
+ if (node_init(state, node) == 0)
68
+ return node;
69
+
70
+ free(node);
71
+ }
72
+
73
+ return NULL;
74
+ }
75
+
76
+ /*
77
+ Rather than iterate over the branches, we here recurse: this is so
78
+ that we can do all of the work that we need to do but leave the
79
+ allocation in node_clone() until last, and only then call ourself.
80
+ In case of failure we back out with node_destroy() return error and
81
+ our recursive parents do the same, so cleaning up after ourselves.
82
+ */
83
+
84
+ static int node_clone_children(const state_t *state,
85
+ const node_t *src, node_t *dest,
86
+ size_t i)
87
+ {
88
+ if (i >= node_count(src)) return RTREE_OK;
89
+
90
+ const branch_t *src_branch;
91
+ if ((src_branch = node_get_branch(state, src, i)) == NULL)
92
+ return RTREE_ERR_GETBRANCH;
93
+
94
+ branch_t *dest_branch;
95
+ if ((dest_branch = node_get_branch(state, dest, i)) == NULL)
96
+ return RTREE_ERR_GETBRANCH;
97
+
98
+ const node_t *src_child;
99
+ if ((src_child = branch_get_child(src_branch)) == NULL)
100
+ return RTREE_ERR_GETCHILD;
101
+
102
+ node_t *dest_child;
103
+ if ((dest_child = node_clone(state, src_child)) == NULL)
104
+ return RTREE_ERR_NODECLONE;
105
+
106
+ int err = node_clone_children(state, src, dest, i + 1);
107
+ if (err != RTREE_OK)
108
+ {
109
+ node_destroy(state, dest_child);
110
+ return err;
111
+ }
112
+
113
+ branch_set_child(dest_branch, dest_child);
114
+
115
+ return RTREE_OK;
116
+ }
117
+
118
+ /*
119
+ To clone a leaf node (and its branches), we just need to copy,
120
+ but for internal nodes we need to replace the branches' pointers
121
+ to node by the pointer to its clone; so recursion.
122
+ */
123
+
124
+ node_t* node_clone(const state_t *state, const node_t *src)
125
+ {
126
+ const size_t node_size = state_node_size(state);
127
+ node_t *dest;
128
+
129
+ if ((dest = malloc(node_size)) == NULL)
130
+ {
131
+ errno = ENOMEM;
132
+ return NULL;
133
+ }
134
+
135
+ memcpy(dest, src, node_size);
136
+ if (node_level(src) > 0)
137
+ {
138
+ if (node_clone_children(state, src, dest, 0) != 0)
139
+ {
140
+ free(dest);
141
+ return NULL;
142
+ }
143
+ }
144
+
145
+ return dest;
146
+ }
147
+
148
+ /*
149
+ For the destroy, we go a bit overboard checking that everything
150
+ is non-NULL, this since we expect it to be used backing out on
151
+ failure, and that failure might be a bad alloc.
152
+ */
153
+
154
+ void node_destroy(const state_t *state, node_t *node)
155
+ {
156
+ if (node != NULL)
157
+ {
158
+ if (node_level(node) > 0)
159
+ {
160
+ for (size_t i = 0 ; i < node_count(node) ; i++)
161
+ {
162
+ branch_t *branch;
163
+ if ((branch = node_get_branch(state, node, i)) != NULL)
164
+ {
165
+ node_t *child;
166
+ if ((child = branch_get_child_mutable(branch)) != NULL)
167
+ node_destroy(state, child);
168
+ }
169
+ }
170
+ }
171
+ free(node);
172
+ }
173
+ }
174
+
175
+ /*
176
+ Apply the function f to each branch of the specified node, even if
177
+ that branch is empty (i.e., has no child). The function f should
178
+ return zero to indicate success, if a non-zero value is returned
179
+ then the iteration is aborted and that value returned.
180
+ */
181
+
182
+ int node_branch_each(const state_t *state, const node_t *node,
183
+ nbe_cb_t *f, void *arg)
184
+ {
185
+ for (size_t i = 0 ; i < node_count(node) ; i++)
186
+ {
187
+ int err;
188
+ if ((err = f(state, node_get_branch(state, node, i), arg)) != 0)
189
+ return err;
190
+ }
191
+ return RTREE_OK;
192
+ }
193
+
194
+ /*
195
+ a bit like node_branch each, but applied to all nodes at the specified
196
+ level; a breadth-first iterate if you will
197
+ */
198
+
199
+ int node_branch_each_level(const state_t *state, const node_t *node,
200
+ node_level_t level, nbe_cb_t *f, void *arg)
201
+ {
202
+ const node_level_t this_level = node_level(node);
203
+
204
+ if (this_level > level)
205
+ {
206
+ for (size_t i = 0 ; i < node_count(node) ; i++)
207
+ {
208
+ branch_t *branch = node_get_branch(state, node, i);
209
+ const node_t *child = branch_get_child(branch);
210
+ int err = node_branch_each_level(state, child, level, f, arg);
211
+ if (err != 0) return err;
212
+ }
213
+ }
214
+ else if (this_level == level)
215
+ {
216
+ for (size_t i = 0 ; i < node_count(node) ; i++)
217
+ {
218
+ branch_t *branch = node_get_branch(state, node, i);
219
+ int err = f(state, branch, arg);
220
+ if (err != 0) return err;
221
+ }
222
+ }
223
+ return RTREE_OK;
224
+ }
225
+
226
+ size_t node_bytes(const state_t *state, const node_t *node)
227
+ {
228
+ if (node == NULL)
229
+ return 0;
230
+
231
+ if (node_level(node) == 0)
232
+ return state_node_size(state);
233
+
234
+ size_t bytes = state_node_size(state);
235
+
236
+ for (size_t i = 0 ; i < node_count(node) ; i++)
237
+ {
238
+ branch_t *branch = node_get_branch(state, node, i);
239
+ const node_t *child = branch_get_child(branch);
240
+ bytes += node_bytes(state, child);
241
+ }
242
+
243
+ return bytes;
244
+ }
245
+
246
+ /*
247
+ remove branch i from node, to maintain contiguousness, we copy the
248
+ final branch to i (we don't need to do that if it is the final branch
249
+ of course, indeed, since we use memcpy we shouldn't do that). Note
250
+ that this handles the case when there is only one branch.
251
+ */
252
+
253
+ int node_detach_branch(const state_t *state, node_t *node, size_t i)
254
+ {
255
+ branch_t *branch;
256
+
257
+ if ((i >= node_count(node)) ||
258
+ ((branch = node_get_branch(state, node, i)) == NULL))
259
+ return RTREE_ERR_GETBRANCH;
260
+
261
+ if (i + 1 != node_count(node))
262
+ {
263
+ branch_t *branch_end = node_get_branch(state, node, node_count(node) - 1);
264
+
265
+ if (branch_end == NULL)
266
+ return RTREE_ERR_GETBRANCH;
267
+
268
+ if (branch_copy(state, branch_end, branch) == NULL)
269
+ return RTREE_ERR_NOMEM;
270
+ }
271
+
272
+ node_count_decrement(node);
273
+
274
+ return RTREE_OK;
275
+ }
276
+
277
+ static node_t* node_split(const state_t *state, node_t *node, branch_t *branch)
278
+ {
279
+ return split_node(state, node, branch);
280
+ }
281
+
282
+ /*
283
+ add branch to node, which may split the node: if so the new node
284
+ argumemnt is returned, so comparing the node argument and return
285
+ value is the way to detect that splitting has occured.
286
+ */
287
+
288
+ node_t* node_add_branch(const state_t *state, node_t *node, branch_t *branch)
289
+ {
290
+ if (node_count(node) < state_branching_factor(state))
291
+ {
292
+ branch_t *b;
293
+
294
+ if ((b = node_get_branch(state, node, node_count(node))) == NULL)
295
+ return NULL;
296
+
297
+ branch_copy(state, branch, b);
298
+ node_count_increment(node);
299
+
300
+ return node;
301
+ }
302
+
303
+ return node_split(state, node, branch);
304
+ }
305
+
306
+ /*
307
+ Pick a branch. Pick the one that will need the smallest increase
308
+ in volume to accomodate the new (hyper-)rectangle. This will result
309
+ in the least total volume for the covering rectangles in the current
310
+ node. In case of a tie, pick the one which was smaller before, to
311
+ get the best resolution when searching.
312
+ */
313
+
314
+ static int node_pick_branch(const state_t *state,
315
+ node_t *node, const rtree_coord_t *rect,
316
+ size_t *index)
317
+ {
318
+ const size_t
319
+ dims = state_dims(state);
320
+ size_t
321
+ index_min = SIZE_MAX;
322
+ rtree_coord_t
323
+ dvol_min = INFINITY,
324
+ vol_min = INFINITY;
325
+
326
+ for (size_t i = 0 ; i < node_count(node) ; i++)
327
+ {
328
+ branch_t *branch;
329
+
330
+ if ((branch = node_get_branch(state, node, i)) == NULL)
331
+ return RTREE_ERR_GETBRANCH;
332
+
333
+ const rtree_coord_t *rect1 = branch_get_rect(branch);
334
+ rtree_coord_t rect2[2 * dims];
335
+ rect_combine(state, rect, rect1, rect2);
336
+
337
+ rtree_coord_t
338
+ vol1 = rect_spherical_volume(state, rect1),
339
+ vol2 = rect_spherical_volume(state, rect2),
340
+ dvol = vol2 - vol1;
341
+
342
+ if ((dvol < dvol_min) || ((dvol == dvol_min) && (vol1 < vol_min)))
343
+ {
344
+ index_min = i;
345
+ vol_min = vol1;
346
+ dvol_min = dvol;
347
+ }
348
+ }
349
+
350
+ /*
351
+ This can only happen if no branches are assigned in the above
352
+ block, on the first call of it, dvol_min == DBL_MAX, so either
353
+ the first case is called, or dvol == DBL_MAX, but dvol is equal
354
+ to vol2 - vol1, and vol1, vol2 are non-negative, so vol2 must
355
+ be DBL_MAX and vol1 zero, in particular vol1 < vol_min (DBL_MAX),
356
+ so the second condition is met.
357
+ */
358
+
359
+ if (index_min == SIZE_MAX)
360
+ return RTREE_ERR_PICKBRANCH;
361
+
362
+ *index = index_min;
363
+
364
+ return RTREE_OK;
365
+ }
366
+
367
+ int node_envelope(const state_t *state, const node_t *node,
368
+ rtree_coord_t *rect)
369
+ {
370
+ size_t n = node_count(node);
371
+
372
+ if (n > 0)
373
+ {
374
+ const branch_t *branch;
375
+
376
+ if ((branch = node_get_branch(state, node, 0)) == NULL)
377
+ return RTREE_ERR_GETBRANCH;
378
+ rect_copy(state, branch_get_rect(branch), rect);
379
+
380
+ for (size_t i = 1 ; i < n ; i++)
381
+ {
382
+ if ((branch = node_get_branch(state, node, i)) == NULL)
383
+ return RTREE_ERR_GETBRANCH;
384
+ rect_merge(state, branch_get_rect(branch), rect);
385
+ }
386
+ }
387
+
388
+ return RTREE_OK;
389
+ }
390
+
391
+ static node_t* node_add_rect2(const state_t *state,
392
+ rtree_id_t id, const rtree_coord_t *rect, node_t *node,
393
+ node_level_t level)
394
+ {
395
+ const size_t rect_size = state_rect_size(state);
396
+
397
+ if (node_level(node) > level)
398
+ {
399
+ /* internal node */
400
+
401
+ size_t i;
402
+
403
+ if (node_pick_branch(state, node, rect, &i) != 0)
404
+ return NULL;
405
+
406
+ branch_t *picked;
407
+
408
+ if ((picked = node_get_branch(state, node, i)) == NULL)
409
+ return NULL;
410
+
411
+ node_t
412
+ *child = branch_get_child_mutable(picked),
413
+ *node2 = node_add_rect2(state, id, rect, child, level);
414
+
415
+ if (node2 == child)
416
+ {
417
+ /* child not split */
418
+
419
+ rtree_coord_t rect_comb[rect_size];
420
+ rect_combine(state, rect, branch_get_rect(picked), rect_comb);
421
+ branch_set_rect(state, picked, rect_comb);
422
+
423
+ return node;
424
+ }
425
+ else
426
+ {
427
+ /* child split */
428
+
429
+ rtree_coord_t rect_comb[rect_size];
430
+ if (node_envelope(state, child, rect_comb) != 0)
431
+ return NULL;
432
+ branch_set_rect(state, picked, rect_comb);
433
+
434
+ char branch_bytes[state_branch_size(state)];
435
+ branch_t *branch = (branch_t*)branch_bytes;
436
+ branch_init(state, branch);
437
+
438
+ branch_set_child(branch, node2);
439
+
440
+ if (node_envelope(state, node2, rect_comb) != 0)
441
+ return NULL;
442
+ branch_set_rect(state, branch, rect_comb);
443
+
444
+ node_t *new_node = node_add_branch(state, node, branch);
445
+
446
+ return new_node;
447
+ }
448
+ }
449
+ else if (node_level(node) == level)
450
+ {
451
+ /* leaf node */
452
+
453
+ char branch_bytes[state_branch_size(state)];
454
+ branch_t *branch = (branch_t*)branch_bytes;
455
+ branch_init(state, branch);
456
+
457
+ branch_set_id(branch, id);
458
+ branch_set_rect(state, branch, rect);
459
+
460
+ node_t *new_node = node_add_branch(state, node, branch);
461
+
462
+ return new_node;
463
+ }
464
+
465
+ return NULL;
466
+ }
467
+
468
+ /*
469
+ Insert the rect (array) into the node root, the root may be split
470
+ and the sibling is returned from the function on success. On failure
471
+ NULL is returned and the root is not modified (so can be reallocated)
472
+ */
473
+
474
+ node_t* node_add_rect(const state_t *state,
475
+ rtree_id_t id, rtree_coord_t *rect, node_t *root,
476
+ node_level_t level)
477
+ {
478
+ const size_t dims = state_dims(state);
479
+
480
+ /*
481
+ dims is never zero as that would not make sense at the application
482
+ level, and that is enforced in state_new(), but scan-build does
483
+ not look that deep and thinks that it might be so errors on a length
484
+ zero VLA below; this assert fixes that, removing it leads to spurious
485
+ CI failures.
486
+ */
487
+
488
+ assert(dims > 0);
489
+
490
+ for (size_t i = 0 ; i < dims ; i++)
491
+ {
492
+ if (rect[i] > rect[dims + i])
493
+ {
494
+ errno = EINVAL;
495
+ return NULL;
496
+ }
497
+ }
498
+
499
+ node_t *sibling;
500
+
501
+ if ((sibling = node_add_rect2(state, id, rect, root, level)) == NULL)
502
+ return NULL;
503
+
504
+ if (sibling == root)
505
+ return root;
506
+
507
+ node_t *new_root;
508
+
509
+ if ((new_root = node_new(state)) != NULL)
510
+ {
511
+ node_set_level(new_root, node_level(root) + 1);
512
+
513
+ char branch_bytes[state_branch_size(state)];
514
+ branch_t *branch = (branch_t*)branch_bytes;
515
+ branch_init(state, branch);
516
+
517
+ rtree_coord_t envelope[2 * dims];
518
+
519
+ if (node_envelope(state, root, envelope) == 0)
520
+ {
521
+ branch_set_child(branch, root);
522
+ branch_set_rect(state, branch, envelope);
523
+
524
+ /*
525
+ node_add_branch() may return a node different to the input
526
+ node if the node splits -- that shouldn't happen, since we
527
+ have just created this node, so if it does then we error
528
+ out (making a half-hearted effort to clean up).
529
+ */
530
+
531
+ node_t *n = node_add_branch(state, new_root, branch);
532
+
533
+ if (n != new_root)
534
+ node_destroy(state, n);
535
+ else
536
+ {
537
+ if (node_envelope(state, sibling, envelope) == 0)
538
+ {
539
+ branch_set_child(branch, sibling);
540
+ branch_set_rect(state, branch, envelope);
541
+ node_add_branch(state, new_root, branch);
542
+
543
+ return new_root;
544
+ }
545
+ }
546
+ }
547
+
548
+ node_destroy(state, new_root);
549
+ }
550
+
551
+ node_destroy(state, sibling);
552
+
553
+ return NULL;
554
+ }
555
+
556
+ int node_update(const state_t *state, const node_t *node,
557
+ rtree_update_t *f, void *context)
558
+ {
559
+ node_level_t level = node_level(node);
560
+
561
+ if (level > 0)
562
+ {
563
+ const size_t dims = state_dims(state);
564
+
565
+ for (size_t i = 0 ; i < node_count(node) ; i++)
566
+ {
567
+ branch_t *branch = node_get_branch(state, node, i);
568
+ if (branch == NULL) return RTREE_ERR_GETBRANCH;
569
+
570
+ const node_t *child = branch_get_child(branch);
571
+ if (child == NULL) return RTREE_ERR_GETCHILD;
572
+
573
+ /*
574
+ Note, in the case that node_update returns RTREE_ERR_USER,
575
+ we could calculate and assign the envelope, and then the
576
+ search index should be correct. but it seems unlikely that
577
+ this would ever be useful, since you're then be indexing a
578
+ half-updated set of rectangles. So we leave that until the
579
+ need arises.
580
+ */
581
+
582
+ int err;
583
+
584
+ err = node_update(state, child, f, context);
585
+ if (err != RTREE_OK) return err;
586
+
587
+ rtree_coord_t envelope[2 * dims];
588
+ err = node_envelope(state, child, envelope);
589
+ if (err != RTREE_OK) return err;
590
+
591
+ branch_set_rect(state, branch, envelope);
592
+ }
593
+ }
594
+ else
595
+ {
596
+ for (size_t i = 0 ; i < node_count(node) ; i++)
597
+ {
598
+ branch_t *branch = node_get_branch(state, node, i);
599
+ if (branch == NULL) return RTREE_ERR_GETBRANCH;
600
+
601
+ rtree_coord_t *rect = branch_get_rect_mutable(branch);
602
+ rtree_id_t id = branch_get_id(branch);
603
+
604
+ if (f(id, rect, context) != 0) return RTREE_ERR_USER;
605
+ }
606
+ }
607
+
608
+ return RTREE_OK;
609
+ }
610
+
611
+ /*
612
+ Height is the maximal number of branches from the root to a leaf,
613
+ or zero if the tree is empty. If there have been no branch
614
+ deletions, then this is the same as the level of the root plus one,
615
+ but if there have been deletions then this is not the case. This
616
+ function iterates over all internal nodes to calculate the height,
617
+ this could probably be done more efficiently by holding some state
618
+ on branch deletions, but we don't expect this to be called that
619
+ often (and it's still pretty quick).
620
+ */
621
+
622
+ node_level_t node_height(const state_t *state, const node_t *node)
623
+ {
624
+ node_count_t count;
625
+
626
+ if ((count = node_count(node)) == 0)
627
+ return 0;
628
+
629
+ if (node_level(node) == 0)
630
+ return 1;
631
+
632
+ node_level_t child_max_height = 0;
633
+
634
+ for (size_t i = 0 ; i < count ; i++)
635
+ {
636
+ const branch_t *branch = node_get_branch(state, node, i);
637
+ const node_t *child = branch_get_child(branch);
638
+ node_level_t child_height = node_height(state, child);
639
+
640
+ if (child_height > child_max_height)
641
+ child_max_height = child_height;
642
+ }
643
+
644
+ if (child_max_height == 0)
645
+ return 0;
646
+ else
647
+ return child_max_height + 1;
648
+ }
649
+
650
+ /*
651
+ it is assumed that the state is identical for a and b, i.e., that
652
+ state_identical() is true (so we don't need to pass the state for
653
+ both nodes).
654
+ */
655
+
656
+ bool node_identical(const state_t *state, const node_t *a, const node_t *b)
657
+ {
658
+ if (a && b)
659
+ {
660
+ if ((node_level(a) != node_level(b)) || (node_count(a) != node_count(b)))
661
+ return false;
662
+
663
+ node_level_t level = node_level(a);
664
+ node_count_t count = node_count(a);
665
+
666
+ for (size_t i = 0 ; i < count ; i++)
667
+ {
668
+ const branch_t
669
+ *branch_a = node_get_branch(state, a, i),
670
+ *branch_b = node_get_branch(state, b, i);
671
+ const rtree_coord_t
672
+ *rect_a = branch_get_rect(branch_a),
673
+ *rect_b = branch_get_rect(branch_b);
674
+
675
+ if (! rect_identical(state, rect_a, rect_b))
676
+ return false;
677
+
678
+ if (level > 0)
679
+ {
680
+ const node_t
681
+ *child_a = branch_get_child(branch_a),
682
+ *child_b = branch_get_child(branch_b);
683
+
684
+ if (! node_identical(state, child_a, child_b))
685
+ return false;
686
+ }
687
+ else
688
+ {
689
+ rtree_id_t
690
+ id_a = branch_get_id(branch_a),
691
+ id_b = branch_get_id(branch_b);
692
+
693
+ if (id_a != id_b)
694
+ return false;
695
+ }
696
+ }
697
+ return true;
698
+ }
699
+
700
+ return ! (a || b);
701
+ }
702
+
703
+ /*
704
+ find whether the node or its descendants have a leaf, so we're
705
+ looking for a level-zero node with a non-zero count, of course
706
+ we short circuit as soon as we find one.
707
+ */
708
+
709
+ bool node_nonempty(const state_t *state, const node_t *node)
710
+ {
711
+ node_count_t count;
712
+
713
+ if ((count = node_count(node)) == 0)
714
+ return false;
715
+
716
+ if (node_level(node) == 0)
717
+ return true;
718
+
719
+ for (size_t i = 0 ; i < count ; i++)
720
+ {
721
+ const branch_t *branch = node_get_branch(state, node, i);
722
+ const node_t *child = branch_get_child(branch);
723
+
724
+ if (node_nonempty(state, child))
725
+ return true;
726
+ }
727
+
728
+ return false;
729
+ }
730
+
731
+ extern node_count_t node_count(const node_t*);
732
+ extern void node_count_increment(node_t*);
733
+ extern void node_count_decrement(node_t*);
734
+ extern node_level_t node_level(const node_t*);
735
+ extern void node_set_level(node_t*, node_level_t);
736
+ extern void* node_get_branches(node_t*);