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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +80 -0
- data/COPYING +21 -0
- data/README.md +87 -0
- data/ext/rtree/extconf.rb +37 -19
- data/ext/rtree/lib/README.md +9 -0
- data/ext/rtree/lib/bindex.c +157 -0
- data/ext/rtree/lib/bindex.h +31 -0
- data/ext/rtree/lib/bounds.h +21 -0
- data/ext/rtree/lib/branch.c +51 -0
- data/ext/rtree/lib/branches.c +17 -0
- data/ext/rtree/lib/bsrt.c +704 -0
- data/ext/rtree/lib/bsrt.h +16 -0
- data/ext/rtree/lib/constants.h +19 -0
- data/ext/rtree/lib/csv.c +81 -0
- data/ext/rtree/lib/csv.h +16 -0
- data/ext/rtree/lib/endianness.h +83 -0
- data/ext/rtree/lib/error.c +47 -0
- data/ext/rtree/lib/json.c +491 -0
- data/ext/rtree/lib/json.h +16 -0
- data/ext/rtree/lib/mk/Hdr.mk +3 -0
- data/ext/rtree/lib/mk/MakeDepend +25 -0
- data/ext/rtree/lib/mk/Obj.mk +3 -0
- data/ext/rtree/lib/node.c +736 -0
- data/ext/rtree/lib/package.c +11 -0
- data/ext/rtree/lib/page.c +47 -0
- data/ext/rtree/lib/page.h +13 -0
- data/ext/rtree/lib/postscript.c +543 -0
- data/ext/rtree/lib/rect.c +139 -0
- data/ext/rtree/lib/rectf.c +219 -0
- data/ext/rtree/lib/rtree/branch.h +105 -0
- data/ext/rtree/lib/rtree/branches.h +38 -0
- data/ext/rtree/lib/rtree/error.h +42 -0
- data/ext/rtree/lib/rtree/extent.h +20 -0
- data/ext/rtree/lib/rtree/node.h +96 -0
- data/ext/rtree/lib/rtree/package.h +14 -0
- data/ext/rtree/lib/rtree/postscript.h +66 -0
- data/ext/rtree/lib/rtree/rect.h +38 -0
- data/ext/rtree/lib/rtree/rectf.h +34 -0
- data/ext/rtree/lib/rtree/search.h +27 -0
- data/ext/rtree/lib/rtree/state.h +113 -0
- data/ext/rtree/lib/rtree/types.h +14 -0
- data/ext/rtree/lib/rtree-base.c +197 -0
- data/ext/rtree/lib/rtree.h +62 -0
- data/ext/rtree/lib/search.c +54 -0
- data/ext/rtree/lib/split.c +710 -0
- data/ext/rtree/lib/split.h +15 -0
- data/ext/rtree/lib/spvol.c +48 -0
- data/ext/rtree/lib/spvol.h +13 -0
- data/ext/rtree/lib/state.c +169 -0
- data/ext/rtree/rtree.c +11 -0
- data/lib/rtree.rb +4 -4
- 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
|
+
}
|