librtree 0.9.1 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
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