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,710 @@
1
+ #ifdef HAVE_CONFIG_H
2
+ #include "config.h"
3
+ #endif
4
+
5
+ #include <float.h>
6
+ #include <errno.h>
7
+
8
+ #ifdef HAVE_TGMATH_H
9
+ #include <tgmath.h>
10
+ #else
11
+ #include <math.h>
12
+ #endif
13
+
14
+ #include "rtree/error.h"
15
+ #include "rtree/branches.h"
16
+
17
+ #include "split.h"
18
+ #include "bindex.h"
19
+
20
+ typedef struct
21
+ {
22
+ bindex_t *choice, *taken;
23
+ size_t total, minfill, count[2];
24
+ rtree_coord_t area[2], *cover[2];
25
+ } partition_t;
26
+
27
+ typedef struct
28
+ {
29
+ size_t n;
30
+ void *branches;
31
+ rtree_coord_t *rect;
32
+ partition_t partition;
33
+ } split_t;
34
+
35
+ /*
36
+ Assign branch i to a partition group, updating the covering
37
+ rectangles, areas, counts
38
+ */
39
+
40
+ static int split_classify(size_t i, size_t group,
41
+ const state_t *state, split_t *split)
42
+ {
43
+ partition_t *part = &(split->partition);
44
+ branch_t *branch = branches_get(state, split->branches, i);
45
+ const rtree_coord_t *rect = branch_get_rect(branch);
46
+
47
+ int err;
48
+
49
+ if (((err = bindex_set(part->choice, i, group)) != RTREE_OK) ||
50
+ ((err = bindex_set(part->taken, i, 1)) != RTREE_OK))
51
+ return err;
52
+
53
+ if (part->count[group] == 0)
54
+ rect_copy(state, rect, part->cover[group]);
55
+ else
56
+ rect_merge(state, rect, part->cover[group]);
57
+
58
+ part->area[group] = rect_spherical_volume(state, part->cover[group]);
59
+ part->count[group]++;
60
+
61
+ return RTREE_OK;
62
+ }
63
+
64
+ /*
65
+ Picks two rectangles to be the first (seed) elements of the
66
+ partition groups. We try to get two which are most-separated
67
+ along any dimension, or overlap least. In degenerate case we
68
+ may not find such a pair, but this is not fatal.
69
+ */
70
+
71
+ static int split_seed_linear(const state_t *state, split_t *split)
72
+ {
73
+ const size_t
74
+ dims = state_dims(state),
75
+ nbuf = state_branching_factor(state);
76
+ size_t
77
+ greatest_lower[dims],
78
+ least_upper[dims];
79
+ rtree_coord_t width[dims];
80
+
81
+ for (size_t dim = 0 ; dim < dims ; dim++)
82
+ {
83
+ greatest_lower[dim] = least_upper[dim] = 0;
84
+
85
+ for (size_t i = 1 ; i < nbuf ; i++)
86
+ {
87
+ branch_t
88
+ *b0 = branches_get(state, split->branches, greatest_lower[dim]),
89
+ *b1 = branches_get(state, split->branches, i),
90
+ *b2 = branches_get(state, split->branches, least_upper[dim]);
91
+ const rtree_coord_t
92
+ *r0 = branch_get_rect(b0),
93
+ *r1 = branch_get_rect(b1),
94
+ *r2 = branch_get_rect(b2);
95
+
96
+ if (r1[dim] > r0[dim])
97
+ greatest_lower[dim] = i;
98
+
99
+ if (r1[dim + dims] < r2[dim + dims])
100
+ least_upper[dim] = i;
101
+ }
102
+
103
+ width[dim] = split->rect[dim + dims] - split->rect[dim];
104
+ }
105
+
106
+ rtree_coord_t sep_max = -1.0;
107
+ size_t seed0 = 0, seed1 = 0;
108
+
109
+ for (size_t dim = 0 ; dim < dims ; dim++)
110
+ {
111
+ branch_t
112
+ *bl = branches_get(state, split->branches, least_upper[dim]),
113
+ *bh = branches_get(state, split->branches, greatest_lower[dim]);
114
+ const rtree_coord_t
115
+ *rl = branch_get_rect(bl),
116
+ *rh = branch_get_rect(bh),
117
+ w = (width[dim] ? width[dim] : 1.0),
118
+ sep = (rh[dim] - rl[dim + dims]) / w;
119
+
120
+ if (sep > sep_max)
121
+ {
122
+ seed0 = least_upper[dim];
123
+ seed1 = greatest_lower[dim];
124
+ sep_max = sep;
125
+ }
126
+ }
127
+
128
+ if (seed0 != seed1)
129
+ {
130
+ int err;
131
+
132
+ if (((err = split_classify(seed0, 0, state, split)) != RTREE_OK) ||
133
+ ((err = split_classify(seed1, 1, state, split)) != RTREE_OK))
134
+ return err;
135
+ }
136
+
137
+ return RTREE_OK;
138
+ }
139
+
140
+ /*
141
+ Picks two rectangles to be the first (seed) elements of the
142
+ partition groups. They are the two that waste the most area
143
+ if convered by a single rectangle.
144
+
145
+ Note that this is as implemented in the Guttman-Green version
146
+ quadratic splitting, but is quadratic only in the page-size,
147
+ so I'm not sure if it is rather a "better seeding method"
148
+ developed during the work on quadratic splitting and then not
149
+ back-ported to the linear case.
150
+ */
151
+
152
+ static int split_seed_quadratic(const state_t *state, split_t *split)
153
+ {
154
+ size_t
155
+ dims = state_dims(state),
156
+ total = split->partition.total;
157
+ rtree_coord_t area[total];
158
+
159
+ for (size_t i = 0 ; i < total ; i++)
160
+ {
161
+ branch_t *branch = branches_get(state, split->branches, i);
162
+ const rtree_coord_t *rect = branch_get_rect(branch);
163
+ area[i] = rect_spherical_volume(state, rect);
164
+ }
165
+
166
+ rtree_coord_t worst = -INFINITY;
167
+ size_t seed0 = 0, seed1 = 0;
168
+ int err;
169
+
170
+ for (size_t i = 0 ; i < total - 1 ; i++)
171
+ {
172
+ branch_t *bi = branches_get(state, split->branches, i);
173
+ const rtree_coord_t *ri = branch_get_rect(bi);
174
+
175
+ for (size_t j = i + 1 ; j < total ; j++)
176
+ {
177
+ branch_t *bj = branches_get(state, split->branches, j);
178
+ const rtree_coord_t *rj = branch_get_rect(bj);
179
+ rtree_coord_t rect[2 * dims];
180
+
181
+ rect_combine(state, ri, rj, rect);
182
+
183
+ rtree_coord_t waste =
184
+ rect_spherical_volume(state, rect) - area[i] - area[j];
185
+
186
+ if (waste > worst)
187
+ {
188
+ worst = waste;
189
+ seed0 = i;
190
+ seed1 = j;
191
+ }
192
+ }
193
+ }
194
+
195
+ if (((err = split_classify(seed0, 1, state, split)) != RTREE_OK) ||
196
+ ((err = split_classify(seed1, 0, state, split)) != RTREE_OK))
197
+ return err;
198
+
199
+ return RTREE_OK;
200
+ }
201
+
202
+ /*
203
+ Assign unseeded branches to partition groups, using a cascade of
204
+ conditions (on tie, drop to the next one).
205
+ */
206
+
207
+ static int split_linear(const state_t *state, split_t *split)
208
+ {
209
+ int err;
210
+
211
+ if ((err = split_seed_linear(state, split)) != RTREE_OK)
212
+ return err;
213
+
214
+ const size_t n = split->n;
215
+ partition_t *part = &(split->partition);
216
+ rtree_coord_t *cover[2], area[2], increase[2];
217
+
218
+ if ((err = rects_alloc(state, 2, cover)) != RTREE_OK)
219
+ return err;
220
+
221
+ for (size_t i = bindex_first_unset(part->taken) ;
222
+ i <= n ;
223
+ i = bindex_next_unset(part->taken, i + 1))
224
+ {
225
+ if (part->count[0] >= part->total - part->minfill)
226
+ {
227
+ if ((err = split_classify(i, 1, state, split)) != RTREE_OK)
228
+ return err;
229
+ continue;
230
+ }
231
+ else if (part->count[1] >= part->total - part->minfill)
232
+ {
233
+ if ((err = split_classify(i, 0, state, split)) != RTREE_OK)
234
+ return err;
235
+ continue;
236
+ }
237
+
238
+ branch_t *branch = branches_get(state, split->branches, i);
239
+ const rtree_coord_t *rect = branch_get_rect(branch);
240
+
241
+ for (size_t group = 0 ; group < 2 ; group++)
242
+ {
243
+ if (part->count[group] == 0)
244
+ rect_copy(state, rect, cover[group]);
245
+ else
246
+ rect_combine(state, rect, part->cover[group], cover[group]);
247
+
248
+ area[group] = rect_spherical_volume(state, cover[group]);
249
+ increase[group] = area[group] - part->area[group];
250
+ }
251
+
252
+ if (increase[0] < increase[1])
253
+ {
254
+ if ((err = split_classify(i, 0, state, split)) != RTREE_OK)
255
+ return err;
256
+ }
257
+ else if (increase[0] > increase[1])
258
+ {
259
+ if ((err = split_classify(i, 1, state, split)) != RTREE_OK)
260
+ return err;
261
+ }
262
+ else if (part->area[0] < part->area[1])
263
+ {
264
+ if ((err = split_classify(i, 0, state, split)) != RTREE_OK)
265
+ return err;
266
+ }
267
+ else if (part->area[0] > part->area[1])
268
+ {
269
+ if ((err = split_classify(i, 1, state, split)) != RTREE_OK)
270
+ return err;
271
+ }
272
+ else if (part->count[0] < part->count[1])
273
+ {
274
+ if ((err = split_classify(i, 0, state, split)) != RTREE_OK)
275
+ return err;
276
+ }
277
+ else
278
+ {
279
+ if ((err = split_classify(i, 1, state, split)) != RTREE_OK)
280
+ return err;
281
+ }
282
+ }
283
+
284
+ rects_free(2, cover);
285
+
286
+ return RTREE_OK;
287
+ }
288
+
289
+ /*
290
+ Assign non-seeded branches according to the greatest difference in
291
+ area expansion - the rectangle most strongly attracted to one group
292
+ and repelled from the other.
293
+
294
+ If one group gets too full (more would force other group to violate
295
+ minimum-fill requirement) then other group gets the rest. These last
296
+ are the ones that can go in either group most easily.
297
+ */
298
+
299
+ static int split_quadratic(const state_t *state, split_t *split)
300
+ {
301
+ int err;
302
+
303
+ if ((err = split_seed_quadratic(state, split)) != RTREE_OK)
304
+ return err;
305
+
306
+ partition_t *part = &(split->partition);
307
+ const size_t
308
+ dims = state_dims(state),
309
+ total = part->total,
310
+ minfill = part->minfill,
311
+ *count = part->count;
312
+ rtree_coord_t
313
+ **cover = part->cover,
314
+ *area = part->area;
315
+
316
+ while ( (count[0] + count[1] < total) &&
317
+ (count[0] + minfill < total) &&
318
+ (count[1] + minfill < total) )
319
+ {
320
+ rtree_coord_t dg_max = -1;
321
+ size_t group = 0, chosen = 0;
322
+
323
+ for (size_t i = bindex_first_unset(part->taken) ;
324
+ i < total ;
325
+ i = bindex_next_unset(part->taken, i + 1))
326
+ {
327
+ branch_t *branch = branches_get(state, split->branches, i);
328
+ const rtree_coord_t *rect = branch_get_rect(branch);
329
+ rtree_coord_t r0[2 * dims], r1[2 * dims];
330
+
331
+ rect_combine(state, rect, cover[0], r0);
332
+ rect_combine(state, rect, cover[1], r1);
333
+
334
+ const rtree_coord_t
335
+ g0 = rect_spherical_volume(state, r0) - area[0],
336
+ g1 = rect_spherical_volume(state, r1) - area[1];
337
+ rtree_coord_t dg = g1 - g0;
338
+
339
+ size_t putative;
340
+ if (dg >= 0)
341
+ putative = 0;
342
+ else
343
+ {
344
+ putative = 1;
345
+ dg *= -1;
346
+ }
347
+
348
+ if (dg > dg_max)
349
+ {
350
+ dg_max = dg;
351
+ group = putative;
352
+ chosen = i;
353
+ }
354
+ }
355
+
356
+ if ((err = split_classify(chosen, group, state, split)) != RTREE_OK)
357
+ return err;
358
+ }
359
+
360
+ if (count[0] + count[1] < total)
361
+ {
362
+ const size_t group = (count[0] + minfill < total) ? 0 : 1;
363
+
364
+ for (size_t i = bindex_first_unset(part->taken) ;
365
+ i < total ;
366
+ i = bindex_next_unset(part->taken, i + 1))
367
+ {
368
+ if ((err = split_classify(i, group, state, split)) != RTREE_OK)
369
+ return err;
370
+ }
371
+ }
372
+
373
+ return RTREE_OK;
374
+ }
375
+
376
+ /*
377
+ The splitting method described by D. Green in "An Implementation and
378
+ Performance Analysis of Spatial Data Access Methods", 1989
379
+ */
380
+
381
+ /*
382
+ for the sort pair, id will be much smaller that UINT16_MAX, but we
383
+ choose it to be the same size as rtree_coord_t for alignment
384
+ */
385
+
386
+ typedef struct
387
+ {
388
+ #if SIZEOF_RTREE_COORD_T == 2
389
+ uint16_t id;
390
+ #elif SIZEOF_RTREE_COORD_T == 4
391
+ uint32_t id;
392
+ #elif SIZEOF_RTREE_COORD_T == 8
393
+ uint64_t id;
394
+ #else
395
+ #error rtree_id_t size not handled
396
+ #endif
397
+ rtree_coord_t min;
398
+ } pair_t;
399
+
400
+ static int pair_compare(const void *va, const void *vb)
401
+ {
402
+ const pair_t *a = va, *b = vb;
403
+ rtree_coord_t ma = a->min, mb = b->min;
404
+
405
+ if (ma > mb)
406
+ return 1;
407
+ else if (ma < mb)
408
+ return -1;
409
+ else
410
+ return 0;
411
+ }
412
+
413
+ static int split_greene(const state_t *state, split_t *split)
414
+ {
415
+ int err;
416
+
417
+ /* dimension on which to split */
418
+
419
+ const size_t dims = state_dims(state);
420
+ size_t axis = dims;
421
+
422
+ /* quadratic seeds */
423
+
424
+ {
425
+ if ((err = split_seed_quadratic(state, split)) != RTREE_OK)
426
+ return err;
427
+
428
+ branch_t
429
+ *b0 = branches_get(state, split->branches, 0),
430
+ *b1 = branches_get(state, split->branches, 1);
431
+ const rtree_coord_t
432
+ *r0 = branch_get_rect(b0),
433
+ *r1 = branch_get_rect(b1);
434
+
435
+ rtree_coord_t sep_best = -INFINITY;
436
+
437
+ for (size_t dim = 0 ; dim < dims ; dim++)
438
+ {
439
+ rtree_coord_t
440
+ s0 = r0[dim] - r1[dim + dims],
441
+ s1 = r1[dim] - r0[dim + dims],
442
+ s2 = fmax(s0, s1),
443
+ n0 = fmin(r0[dim], r1[dim]),
444
+ n1 = fmax(r0[dim + dims], r1[dim + dims]),
445
+ n2 = n1 - n0,
446
+ sep = s2 / n2;
447
+
448
+ if (sep > sep_best)
449
+ {
450
+ sep_best = sep;
451
+ axis = dim;
452
+ }
453
+ }
454
+ }
455
+
456
+ if (axis == dims)
457
+ return RTREE_ERR_SPLIT;
458
+
459
+ /* order by lower boumd in this dimension */
460
+
461
+ partition_t *part = &(split->partition);
462
+ const size_t total = part->total;
463
+ pair_t pairs[total];
464
+
465
+ for (size_t i = 0 ; i < total ; i++)
466
+ {
467
+ branch_t *b = branches_get(state, split->branches, i);
468
+ const rtree_coord_t *r = branch_get_rect(b);
469
+ pairs[i].id = i;
470
+ pairs[i].min = r[axis];
471
+ }
472
+
473
+ qsort(pairs, total, sizeof(pair_t), pair_compare);
474
+
475
+ /* lower part to group 0 */
476
+
477
+ size_t half = (total + 1) >> 1;
478
+
479
+ for (size_t i = 0 ; i < half ; i++)
480
+ if ((err = split_classify(pairs[i].id, 0, state, split)) != RTREE_OK)
481
+ return err;
482
+
483
+ if (total & 1)
484
+ {
485
+ /* tiebreak in the odd case */
486
+
487
+ const branch_t *b = branches_get(state, split->branches, pairs[0].id);
488
+ rtree_coord_t r0[2 * dims], r1[2 * dims];
489
+
490
+ rect_copy(state, branch_get_rect(b), r0);
491
+
492
+ for (size_t i = 1 ; i < half ; i++)
493
+ {
494
+ b = branches_get(state, split->branches, pairs[i].id);
495
+ rect_merge(state, branch_get_rect(b), r0);
496
+ }
497
+
498
+ b = branches_get(state, split->branches, pairs[half + 1].id);
499
+ rect_copy(state, branch_get_rect(b), r1);
500
+
501
+ for (size_t i = half + 2 ; i < total ; i++)
502
+ {
503
+ b = branches_get(state, split->branches, pairs[i].id);
504
+ rect_merge(state, branch_get_rect(b), r1);
505
+ }
506
+
507
+ rtree_coord_t
508
+ v0 = rect_volume(state, r0),
509
+ v1 = rect_volume(state, r1);
510
+
511
+ b = branches_get(state, split->branches, pairs[half].id);
512
+ const rtree_coord_t *rh = branch_get_rect(b);
513
+
514
+ rect_merge(state, rh, r0);
515
+ rect_merge(state, rh, r1);
516
+
517
+ rtree_coord_t
518
+ v0p = rect_volume(state, r0),
519
+ v1p = rect_volume(state, r1);
520
+
521
+ size_t group = (v0p - v0 < v1p - v1) ? 0 : 1;
522
+
523
+ if ((err = split_classify(pairs[half].id, group, state, split)) != RTREE_OK)
524
+ return err;
525
+
526
+ for (size_t i = half + 1 ; i < total ; i++)
527
+ if ((err = split_classify(pairs[i].id, 1, state, split)) != RTREE_OK)
528
+ return err;
529
+ }
530
+ else
531
+ {
532
+ /* total is even, no tiebreaker needed */
533
+
534
+ for (size_t i = half ; i < total ; i++)
535
+ if ((err = split_classify(pairs[i].id, 1, state, split)) != RTREE_OK)
536
+ return err;
537
+ }
538
+
539
+ return RTREE_OK;
540
+ }
541
+
542
+
543
+ static int split_assign(const state_t *state, split_t *split)
544
+ {
545
+ switch (state_split(state))
546
+ {
547
+ case RTREE_SPLIT_LINEAR:
548
+ return split_linear(state, split);
549
+ case RTREE_SPLIT_QUADRATIC:
550
+ return split_quadratic(state, split);
551
+ case RTREE_SPLIT_GREENE:
552
+ return split_greene(state, split);
553
+ default:
554
+ return RTREE_ERR_NOSUCHSPLIT;
555
+ }
556
+ }
557
+
558
+ /*
559
+ This actually performs the split, the input node is reset, a new
560
+ node is created, and the branches in the split struct are distributed
561
+ between these nodes. So the input node is half-emptied and the new
562
+ node is half-filled.
563
+ */
564
+
565
+ static node_t* split_load(const state_t *state, node_t *node, split_t *split)
566
+ {
567
+ const node_level_t level = node_level(node);
568
+
569
+ if (node_init(state, node) != RTREE_OK)
570
+ return NULL;
571
+
572
+ node_t *new_node;
573
+
574
+ if ((new_node = node_new(state)) == NULL)
575
+ return NULL;
576
+
577
+ node_set_level(node, level);
578
+ node_set_level(new_node, level);
579
+
580
+ const partition_t *part = &(split->partition);
581
+ const size_t n = split->n;
582
+
583
+ for (size_t i = 0 ; i <= n ; i++)
584
+ {
585
+ branch_t *branch = branches_get(state, split->branches, i);
586
+ size_t group = bindex_get(part->choice, i);
587
+ node_t *result;
588
+
589
+ switch (group)
590
+ {
591
+ case 0:
592
+ result = node_add_branch(state, node, branch);
593
+ if (result != node)
594
+ goto cleanup_load;
595
+ break;
596
+ case 1:
597
+ result = node_add_branch(state, new_node, branch);
598
+ if (result != new_node)
599
+ goto cleanup_load;
600
+ break;
601
+ default:
602
+ goto cleanup_load;
603
+ }
604
+ }
605
+
606
+ return new_node;
607
+
608
+ cleanup_load:
609
+
610
+ node_destroy(state, new_node);
611
+
612
+ return NULL;
613
+ }
614
+
615
+ static node_t* split_part(const state_t *state, node_t *node, split_t *split)
616
+ {
617
+ partition_t *part = &(split->partition);
618
+ const size_t n = split->n;
619
+ node_t *new_node = NULL;
620
+
621
+ part->count[0] = part->count[1] = 0;
622
+ part->total = n + 1;
623
+ part->minfill = n / 2;
624
+
625
+ if (rects_alloc(state, 2, part->cover) == RTREE_OK)
626
+ {
627
+ if ((part->choice = bindex_new(n + 1)) != NULL)
628
+ {
629
+ if ((part->taken = bindex_new(n + 1)) != NULL)
630
+ {
631
+ if (split_assign(state, split) == RTREE_OK)
632
+ {
633
+ new_node = split_load(state, node, split);
634
+ }
635
+ bindex_destroy(part->taken);
636
+ }
637
+ bindex_destroy(part->choice);
638
+ }
639
+ rects_free(2, part->cover);
640
+ }
641
+
642
+ return new_node;
643
+ }
644
+
645
+ /* Get the covering rectangle */
646
+
647
+ static node_t* split_cover(const state_t *state, node_t *node, split_t *split)
648
+ {
649
+ node_t *new_node = NULL;
650
+ rtree_coord_t split_rect[2 * state_dims(state)];
651
+
652
+ split->rect = split_rect;
653
+
654
+ branch_t *b = branches_get(state, split->branches, 0);
655
+ const rtree_coord_t *r;
656
+
657
+ if ((r = branch_get_rect(b)) != NULL)
658
+ {
659
+ rect_copy(state, r, split->rect);
660
+
661
+ int err = 0;
662
+
663
+ for (size_t i = 0 ; i <= split->n ; i++)
664
+ {
665
+ b = branches_get(state, split->branches, 1);
666
+ if ((r = branch_get_rect(b)) == NULL)
667
+ err++;
668
+ rect_merge(state, r, split->rect);
669
+ }
670
+
671
+ if (err == 0)
672
+ new_node = split_part(state, node, split);
673
+ }
674
+
675
+ split->rect = NULL;
676
+
677
+ return new_node;
678
+ }
679
+
680
+ node_t* split_node(const state_t *state, node_t *node, branch_t *branch)
681
+ {
682
+ void *branches;
683
+ node_t *new_node = NULL;
684
+
685
+ if ((branches = node_get_branches(node)) != NULL)
686
+ {
687
+ split_t split;
688
+ const size_t
689
+ n = split.n = state_branching_factor(state),
690
+ branch_size = state_branch_size(state);
691
+ char split_branches[(n + 1) * branch_size];
692
+
693
+ split.branches = split_branches;
694
+
695
+ for (size_t i = 0 ; i < n ; i++)
696
+ {
697
+ branch_t *b = branches_get(state, branches, i);
698
+ branches_set(state, split.branches, i, b);
699
+ }
700
+
701
+ branches_set(state, split.branches, n, branch);
702
+
703
+ if (branch_init(state, branch) == RTREE_OK)
704
+ new_node = split_cover(state, node, &split);
705
+
706
+ split.branches = NULL;
707
+ }
708
+
709
+ return new_node;
710
+ }
@@ -0,0 +1,15 @@
1
+ /*
2
+ split.h
3
+ Copyright (c) J.J. Green 2020
4
+ */
5
+
6
+ #ifndef SPLIT_H
7
+ #define SPLIT_H
8
+
9
+ #include <rtree/state.h>
10
+ #include <rtree/branch.h>
11
+ #include <rtree/node.h>
12
+
13
+ node_t* split_node(const state_t*, node_t*, branch_t*);
14
+
15
+ #endif