librtree 0.9.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +72 -0
  3. data/COPYING +21 -0
  4. data/README.md +86 -0
  5. data/ext/rtree/extconf.rb +37 -19
  6. data/ext/rtree/lib/bindex.c +157 -0
  7. data/ext/rtree/lib/bindex.h +31 -0
  8. data/ext/rtree/lib/bounds.h +21 -0
  9. data/ext/rtree/lib/branch.c +51 -0
  10. data/ext/rtree/lib/branches.c +17 -0
  11. data/ext/rtree/lib/bsrt.c +704 -0
  12. data/ext/rtree/lib/bsrt.h +16 -0
  13. data/ext/rtree/lib/constants.h +19 -0
  14. data/ext/rtree/lib/csv.c +81 -0
  15. data/ext/rtree/lib/csv.h +16 -0
  16. data/ext/rtree/lib/endianness.h +83 -0
  17. data/ext/rtree/lib/error.c +47 -0
  18. data/ext/rtree/lib/json.c +491 -0
  19. data/ext/rtree/lib/json.h +16 -0
  20. data/ext/rtree/lib/mk/Hdr.mk +3 -0
  21. data/ext/rtree/lib/mk/MakeDepend +25 -0
  22. data/ext/rtree/lib/mk/Obj.mk +3 -0
  23. data/ext/rtree/lib/node.c +708 -0
  24. data/ext/rtree/lib/package.c +11 -0
  25. data/ext/rtree/lib/page.c +47 -0
  26. data/ext/rtree/lib/page.h +13 -0
  27. data/ext/rtree/lib/postscript.c +543 -0
  28. data/ext/rtree/lib/rect.c +139 -0
  29. data/ext/rtree/lib/rectf.c +219 -0
  30. data/ext/rtree/lib/rtree/branch.h +105 -0
  31. data/ext/rtree/lib/rtree/branches.h +38 -0
  32. data/ext/rtree/lib/rtree/error.h +42 -0
  33. data/ext/rtree/lib/rtree/extent.h +20 -0
  34. data/ext/rtree/lib/rtree/node.h +92 -0
  35. data/ext/rtree/lib/rtree/package.h +14 -0
  36. data/ext/rtree/lib/rtree/postscript.h +66 -0
  37. data/ext/rtree/lib/rtree/rect.h +38 -0
  38. data/ext/rtree/lib/rtree/rectf.h +34 -0
  39. data/ext/rtree/lib/rtree/search.h +27 -0
  40. data/ext/rtree/lib/rtree/state.h +113 -0
  41. data/ext/rtree/lib/rtree/types.h +14 -0
  42. data/ext/rtree/lib/rtree-base.c +190 -0
  43. data/ext/rtree/lib/rtree.h +61 -0
  44. data/ext/rtree/lib/search.c +54 -0
  45. data/ext/rtree/lib/split.c +710 -0
  46. data/ext/rtree/lib/split.h +15 -0
  47. data/ext/rtree/lib/spvol.c +48 -0
  48. data/ext/rtree/lib/spvol.h +13 -0
  49. data/ext/rtree/lib/state.c +169 -0
  50. metadata +50 -3
@@ -0,0 +1,708 @@
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
+ extern node_count_t node_count(const node_t*);
704
+ extern void node_count_increment(node_t*);
705
+ extern void node_count_decrement(node_t*);
706
+ extern node_level_t node_level(const node_t*);
707
+ extern void node_set_level(node_t*, node_level_t);
708
+ extern void* node_get_branches(node_t*);
@@ -0,0 +1,11 @@
1
+ /*
2
+ Generated from package.c.in, do not edit (but do not delete,
3
+ this file is checked into version control)
4
+ */
5
+
6
+ #include "rtree/package.h"
7
+
8
+ const char *rtree_package_version = "1.1.3";
9
+ const char *rtree_package_name = "librtree";
10
+ const char *rtree_package_url = "https://gitlab.com/jjg/librtree";
11
+ const char *rtree_package_bugreport = "j.j.green@gmx.co.uk";