spatial-graph 0.0.1__py3-none-any.whl
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.
- spatial_graph/__init__.py +15 -0
- spatial_graph/dtypes.py +130 -0
- spatial_graph/graph/__init__.py +3 -0
- spatial_graph/graph/graph.py +226 -0
- spatial_graph/graph/src/LICENSE.txt +7 -0
- spatial_graph/graph/src/graph_lite.h +1357 -0
- spatial_graph/graph/wrapper_template.pyx +654 -0
- spatial_graph/rtree/__init__.py +5 -0
- spatial_graph/rtree/line_rtree.py +156 -0
- spatial_graph/rtree/point_rtree.py +6 -0
- spatial_graph/rtree/rtree.py +125 -0
- spatial_graph/rtree/src/ARCHITECTURE.md +162 -0
- spatial_graph/rtree/src/LICENSE +20 -0
- spatial_graph/rtree/src/config.h +13 -0
- spatial_graph/rtree/src/rtree.c +1021 -0
- spatial_graph/rtree/src/rtree.h +97 -0
- spatial_graph/rtree/wrapper_template.pyx +356 -0
- spatial_graph/spatial_graph.py +95 -0
- spatial_graph-0.0.1.dist-info/METADATA +130 -0
- spatial_graph-0.0.1.dist-info/RECORD +22 -0
- spatial_graph-0.0.1.dist-info/WHEEL +4 -0
- spatial_graph-0.0.1.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,1021 @@
|
|
|
1
|
+
// Copyright 2023 Joshua J Baker. All rights reserved.
|
|
2
|
+
// Use of this source code is governed by an MIT-style
|
|
3
|
+
// license that can be found in the LICENSE file.
|
|
4
|
+
|
|
5
|
+
#include <string.h>
|
|
6
|
+
#include <math.h>
|
|
7
|
+
#include "config.h"
|
|
8
|
+
#include "rtree.h"
|
|
9
|
+
|
|
10
|
+
// used for splits
|
|
11
|
+
#define MINITEMS_PERCENTAGE 10
|
|
12
|
+
#define MINITEMS ((MAXITEMS) * (MINITEMS_PERCENTAGE) / 100 + 1)
|
|
13
|
+
|
|
14
|
+
#ifndef RTREE_NOPATHHINT
|
|
15
|
+
#define USE_PATHHINT
|
|
16
|
+
#endif
|
|
17
|
+
|
|
18
|
+
#ifdef RTREE_MAXITEMS
|
|
19
|
+
#undef MAXITEMS
|
|
20
|
+
#define MAXITEMS RTREE_MAXITEMS
|
|
21
|
+
#endif
|
|
22
|
+
|
|
23
|
+
#ifdef RTREE_NOATOMICS
|
|
24
|
+
typedef int rc_t;
|
|
25
|
+
static int rc_load(rc_t *ptr, bool relaxed) {
|
|
26
|
+
(void)relaxed; // nothing to do
|
|
27
|
+
return *ptr;
|
|
28
|
+
}
|
|
29
|
+
static int rc_fetch_sub(rc_t *ptr, int val) {
|
|
30
|
+
int rc = *ptr;
|
|
31
|
+
*ptr -= val;
|
|
32
|
+
return rc;
|
|
33
|
+
}
|
|
34
|
+
static int rc_fetch_add(rc_t *ptr, int val) {
|
|
35
|
+
int rc = *ptr;
|
|
36
|
+
*ptr += val;
|
|
37
|
+
return rc;
|
|
38
|
+
}
|
|
39
|
+
#else
|
|
40
|
+
#include <stdatomic.h>
|
|
41
|
+
typedef atomic_int rc_t;
|
|
42
|
+
static int rc_load(rc_t *ptr, bool relaxed) {
|
|
43
|
+
if (relaxed) {
|
|
44
|
+
return atomic_load_explicit(ptr, memory_order_relaxed);
|
|
45
|
+
} else {
|
|
46
|
+
return atomic_load(ptr);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
static int rc_fetch_sub(rc_t *ptr, int delta) {
|
|
50
|
+
return atomic_fetch_sub(ptr, delta);
|
|
51
|
+
}
|
|
52
|
+
static int rc_fetch_add(rc_t *ptr, int delta) {
|
|
53
|
+
return atomic_fetch_add(ptr, delta);
|
|
54
|
+
}
|
|
55
|
+
#endif
|
|
56
|
+
|
|
57
|
+
#define abs(x) ((x) >= 0 ? (x) : -(x))
|
|
58
|
+
|
|
59
|
+
enum kind {
|
|
60
|
+
LEAF = 1,
|
|
61
|
+
BRANCH = 2,
|
|
62
|
+
ITEM_BY_BB = 3, // for priority queue, item enqueued by bb distance
|
|
63
|
+
ITEM = 4 // for priority queue, item enqueued with exact distance
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
struct rect {
|
|
67
|
+
coord_t min[DIMS];
|
|
68
|
+
coord_t max[DIMS];
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
struct node {
|
|
72
|
+
rc_t rc; // reference counter for copy-on-write
|
|
73
|
+
enum kind kind; // LEAF or BRANCH
|
|
74
|
+
int count; // number of rects
|
|
75
|
+
struct rect rects[MAXITEMS];
|
|
76
|
+
union {
|
|
77
|
+
struct node *nodes[MAXITEMS];
|
|
78
|
+
item_t items[MAXITEMS];
|
|
79
|
+
};
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
// priority queue
|
|
83
|
+
struct element {
|
|
84
|
+
coord_t distance;
|
|
85
|
+
enum kind kind;
|
|
86
|
+
union {
|
|
87
|
+
struct node* node; // if kind == LEAF or BRANCH
|
|
88
|
+
struct { // if kind == ITEM_BY_BB or ITEM
|
|
89
|
+
item_t item;
|
|
90
|
+
struct rect *rect;
|
|
91
|
+
};
|
|
92
|
+
};
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
struct priority_queue {
|
|
96
|
+
size_t size;
|
|
97
|
+
size_t capacity;
|
|
98
|
+
struct element *elements;
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
struct priority_queue* priority_queue_new() {
|
|
102
|
+
struct priority_queue *queue = (struct priority_queue*)malloc(sizeof(struct priority_queue));
|
|
103
|
+
if (!queue)
|
|
104
|
+
return NULL;
|
|
105
|
+
queue->size = 0;
|
|
106
|
+
queue->capacity = INITIAL_QUEUE_SIZE;
|
|
107
|
+
queue->elements = (struct element*)malloc(sizeof(struct element) * queue->capacity);
|
|
108
|
+
if (!queue->elements) {
|
|
109
|
+
free(queue);
|
|
110
|
+
return NULL;
|
|
111
|
+
}
|
|
112
|
+
return queue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
void priority_queue_free(struct priority_queue* queue) {
|
|
116
|
+
if (queue->elements)
|
|
117
|
+
free(queue->elements);
|
|
118
|
+
free(queue);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
void swap(struct element* a, struct element* b) {
|
|
122
|
+
struct element tmp = *a;
|
|
123
|
+
*a = *b;
|
|
124
|
+
*b = tmp;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
void heapify_up(struct priority_queue* queue, size_t index) {
|
|
128
|
+
if (index == 0) return;
|
|
129
|
+
size_t midpoint = (index - 1)/2;
|
|
130
|
+
if (queue->elements[midpoint].distance > queue->elements[index].distance) {
|
|
131
|
+
swap(&queue->elements[midpoint], &queue->elements[index]);
|
|
132
|
+
heapify_up(queue, midpoint);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
void heapify_down(struct priority_queue* queue, size_t index) {
|
|
137
|
+
size_t smallest = index;
|
|
138
|
+
size_t left = 2*index + 1;
|
|
139
|
+
size_t right = 2*index + 2;
|
|
140
|
+
|
|
141
|
+
if (left < queue->size) {
|
|
142
|
+
if (queue->elements[left].distance < queue->elements[smallest].distance) {
|
|
143
|
+
smallest = left;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
if (right < queue->size) {
|
|
147
|
+
if (queue->elements[right].distance < queue->elements[smallest].distance) {
|
|
148
|
+
smallest = right;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
if (smallest != index) {
|
|
152
|
+
swap(&queue->elements[index], &queue->elements[smallest]);
|
|
153
|
+
heapify_down(queue, smallest);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
bool enqueue(struct priority_queue* queue, struct element element) {
|
|
158
|
+
if (queue->size == queue->capacity) {
|
|
159
|
+
queue->capacity *= 2;
|
|
160
|
+
queue->elements = realloc(queue->elements, sizeof(struct element) * queue->capacity);
|
|
161
|
+
if (!queue->elements)
|
|
162
|
+
return false;
|
|
163
|
+
}
|
|
164
|
+
queue->elements[queue->size] = element;
|
|
165
|
+
queue->size++;
|
|
166
|
+
heapify_up(queue, queue->size - 1);
|
|
167
|
+
return true;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
struct element dequeue(struct priority_queue* queue) {
|
|
171
|
+
|
|
172
|
+
struct element top = queue->elements[0];
|
|
173
|
+
queue->elements[0] = queue->elements[--queue->size];
|
|
174
|
+
heapify_down(queue, 0);
|
|
175
|
+
// reclaim some memory when the queue is shrinking
|
|
176
|
+
if (queue->size < queue->capacity/4) {
|
|
177
|
+
queue->capacity /= 2;
|
|
178
|
+
struct element *elements = realloc(queue->elements, sizeof(struct element) * queue->capacity);
|
|
179
|
+
if (!elements) {
|
|
180
|
+
queue->capacity *= 2;
|
|
181
|
+
} else {
|
|
182
|
+
queue->elements = elements;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return top;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
struct element peek(struct priority_queue* queue) {
|
|
189
|
+
return queue->elements[0];
|
|
190
|
+
}
|
|
191
|
+
// end priority queue
|
|
192
|
+
|
|
193
|
+
struct rtree {
|
|
194
|
+
struct rect rect;
|
|
195
|
+
struct node *root;
|
|
196
|
+
struct priority_queue *queue;
|
|
197
|
+
size_t count;
|
|
198
|
+
size_t height;
|
|
199
|
+
#ifdef USE_PATHHINT
|
|
200
|
+
int path_hint[16];
|
|
201
|
+
#endif
|
|
202
|
+
bool relaxed;
|
|
203
|
+
void *(*malloc)(size_t);
|
|
204
|
+
void (*free)(void *);
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
static inline coord_t min0(coord_t x, coord_t y) {
|
|
208
|
+
return x < y ? x : y;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
static inline coord_t max0(coord_t x, coord_t y) {
|
|
212
|
+
return x > y ? x : y;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
static bool feq(coord_t a, coord_t b) {
|
|
216
|
+
return !(a < b || a > b);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
#ifdef KNN_USE_EXACT_DISTANCE
|
|
220
|
+
inline coord_t distance(const coord_t point[], const struct rect *rect, const struct item_t item);
|
|
221
|
+
#endif
|
|
222
|
+
|
|
223
|
+
static struct node *node_new(struct rtree *tr, enum kind kind) {
|
|
224
|
+
struct node *node = (struct node *)tr->malloc(sizeof(struct node));
|
|
225
|
+
if (!node) return NULL;
|
|
226
|
+
memset(node, 0, sizeof(struct node));
|
|
227
|
+
node->kind = kind;
|
|
228
|
+
return node;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
static struct node *node_copy(struct rtree *tr, struct node *node) {
|
|
232
|
+
struct node *node2 = (struct node *)tr->malloc(sizeof(struct node));
|
|
233
|
+
if (!node2) return NULL;
|
|
234
|
+
memcpy(node2, node, sizeof(struct node));
|
|
235
|
+
node2->rc = 0;
|
|
236
|
+
if (node2->kind == BRANCH) {
|
|
237
|
+
for (int i = 0; i < node2->count; i++) {
|
|
238
|
+
rc_fetch_add(&node2->nodes[i]->rc, 1);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
return node2;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
static void node_free(struct rtree *tr, struct node *node) {
|
|
245
|
+
if (rc_fetch_sub(&node->rc, 1) > 0) return;
|
|
246
|
+
if (node->kind == BRANCH) {
|
|
247
|
+
for (int i = 0; i < node->count; i++) {
|
|
248
|
+
node_free(tr, node->nodes[i]);
|
|
249
|
+
}
|
|
250
|
+
} else {
|
|
251
|
+
}
|
|
252
|
+
tr->free(node);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
#define cow_node_or(rnode, code) { \
|
|
256
|
+
if (rc_load(&(rnode)->rc, tr->relaxed) > 0) { \
|
|
257
|
+
struct node *node2 = node_copy(tr, (rnode)); \
|
|
258
|
+
if (!node2) { code; } \
|
|
259
|
+
rc_fetch_sub(&(rnode)->rc, 1); \
|
|
260
|
+
(rnode) = node2; \
|
|
261
|
+
} \
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
static void rect_expand(struct rect *rect, const struct rect *other) {
|
|
265
|
+
for (int i = 0; i < DIMS; i++) {
|
|
266
|
+
rect->min[i] = min0(rect->min[i], other->min[i]);
|
|
267
|
+
rect->max[i] = max0(rect->max[i], other->max[i]);
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
static coord_t rect_area(const struct rect *rect) {
|
|
272
|
+
coord_t result = 1;
|
|
273
|
+
for (int i = 0; i < DIMS; i++) {
|
|
274
|
+
result *= (rect->max[i] - rect->min[i]);
|
|
275
|
+
}
|
|
276
|
+
return result;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
// return the area of two rects expanded
|
|
280
|
+
static coord_t rect_unioned_area(const struct rect *rect,
|
|
281
|
+
const struct rect *other)
|
|
282
|
+
{
|
|
283
|
+
coord_t result = 1;
|
|
284
|
+
for (int i = 0; i < DIMS; i++) {
|
|
285
|
+
result *= (max0(rect->max[i], other->max[i]) -
|
|
286
|
+
min0(rect->min[i], other->min[i]));
|
|
287
|
+
}
|
|
288
|
+
return result;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
static bool rect_contains(const struct rect *rect, const struct rect *other) {
|
|
292
|
+
int bits = 0;
|
|
293
|
+
for (int i = 0; i < DIMS; i++) {
|
|
294
|
+
bits |= other->min[i] < rect->min[i];
|
|
295
|
+
bits |= other->max[i] > rect->max[i];
|
|
296
|
+
}
|
|
297
|
+
return bits == 0;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
static bool rect_contains_point(const struct rect *rect, const coord_t point[]) {
|
|
301
|
+
int bits = 0;
|
|
302
|
+
for (int i = 0; i < DIMS; i++) {
|
|
303
|
+
bits |= point[i] < rect->min[i];
|
|
304
|
+
bits |= point[i] > rect->max[i];
|
|
305
|
+
}
|
|
306
|
+
return bits == 0;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
static bool rect_intersects(const struct rect *rect, const struct rect *other) {
|
|
310
|
+
int bits = 0;
|
|
311
|
+
for (int i = 0; i < DIMS; i++) {
|
|
312
|
+
bits |= other->min[i] > rect->max[i];
|
|
313
|
+
bits |= other->max[i] < rect->min[i];
|
|
314
|
+
}
|
|
315
|
+
return bits == 0;
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
static bool rect_onedge(const struct rect *rect, const struct rect *other) {
|
|
319
|
+
for (int i = 0; i < DIMS; i++) {
|
|
320
|
+
if (feq(rect->min[i], other->min[i]) ||
|
|
321
|
+
feq(rect->max[i], other->max[i]))
|
|
322
|
+
{
|
|
323
|
+
return true;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
return false;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
static bool rect_equals(const struct rect *rect, const struct rect *other) {
|
|
330
|
+
for (int i = 0; i < DIMS; i++) {
|
|
331
|
+
if (!feq(rect->min[i], other->min[i]) ||
|
|
332
|
+
!feq(rect->max[i], other->max[i]))
|
|
333
|
+
{
|
|
334
|
+
return false;
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
static bool rect_equals_bin(const struct rect *rect, const struct rect *other) {
|
|
341
|
+
for (int i = 0; i < DIMS; i++) {
|
|
342
|
+
if (rect->min[i] != other->min[i] ||
|
|
343
|
+
rect->max[i] != other->max[i])
|
|
344
|
+
{
|
|
345
|
+
return false;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
return true;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
static int rect_largest_axis(const struct rect *rect) {
|
|
352
|
+
int axis = 0;
|
|
353
|
+
coord_t nlength = rect->max[0] - rect->min[0];
|
|
354
|
+
for (int i = 1; i < DIMS; i++) {
|
|
355
|
+
coord_t length = rect->max[i] - rect->min[i];
|
|
356
|
+
if (length > nlength) {
|
|
357
|
+
nlength = length;
|
|
358
|
+
axis = i;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
return axis;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
// swap two rectangles
|
|
365
|
+
static void node_swap(struct node *node, int i, int j) {
|
|
366
|
+
struct rect tmp = node->rects[i];
|
|
367
|
+
node->rects[i] = node->rects[j];
|
|
368
|
+
node->rects[j] = tmp;
|
|
369
|
+
if (node->kind == LEAF) {
|
|
370
|
+
item_t tmp = node->items[i];
|
|
371
|
+
node->items[i] = node->items[j];
|
|
372
|
+
node->items[j] = tmp;
|
|
373
|
+
} else {
|
|
374
|
+
struct node *tmp = node->nodes[i];
|
|
375
|
+
node->nodes[i] = node->nodes[j];
|
|
376
|
+
node->nodes[j] = tmp;
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
struct rect4 {
|
|
381
|
+
coord_t all[DIMS*2];
|
|
382
|
+
};
|
|
383
|
+
|
|
384
|
+
static void node_qsort(struct node *node, int s, int e, int index, bool rev) {
|
|
385
|
+
int nrects = e - s;
|
|
386
|
+
if (nrects < 2) {
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
int left = 0;
|
|
390
|
+
int right = nrects-1;
|
|
391
|
+
int pivot = nrects / 2;
|
|
392
|
+
node_swap(node, s+pivot, s+right);
|
|
393
|
+
struct rect4 *rects = (struct rect4 *)&node->rects[s];
|
|
394
|
+
if (!rev) {
|
|
395
|
+
for (int i = 0; i < nrects; i++) {
|
|
396
|
+
if (rects[i].all[index] < rects[right].all[index]) {
|
|
397
|
+
node_swap(node, s+i, s+left);
|
|
398
|
+
left++;
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
} else {
|
|
402
|
+
for (int i = 0; i < nrects; i++) {
|
|
403
|
+
if (rects[right].all[index] < rects[i].all[index]) {
|
|
404
|
+
node_swap(node, s+i, s+left);
|
|
405
|
+
left++;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
node_swap(node, s+left, s+right);
|
|
410
|
+
node_qsort(node, s, s+left, index, rev);
|
|
411
|
+
node_qsort(node, s+left+1, e, index, rev);
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
// sort the node rectangles by the axis. used during splits
|
|
415
|
+
static void node_sort_by_axis(struct node *node, int axis, bool rev, bool max) {
|
|
416
|
+
int by_index = max ? DIMS+axis : axis;
|
|
417
|
+
node_qsort(node, 0, node->count, by_index, rev);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
static void node_move_rect_at_index_into(struct node *from, int index,
|
|
421
|
+
struct node *into)
|
|
422
|
+
{
|
|
423
|
+
into->rects[into->count] = from->rects[index];
|
|
424
|
+
from->rects[index] = from->rects[from->count-1];
|
|
425
|
+
if (from->kind == LEAF) {
|
|
426
|
+
into->items[into->count] = from->items[index];
|
|
427
|
+
from->items[index] = from->items[from->count-1];
|
|
428
|
+
} else {
|
|
429
|
+
into->nodes[into->count] = from->nodes[index];
|
|
430
|
+
from->nodes[index] = from->nodes[from->count-1];
|
|
431
|
+
}
|
|
432
|
+
from->count--;
|
|
433
|
+
into->count++;
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
static bool node_split_largest_axis_edge_snap(struct rtree *tr,
|
|
437
|
+
struct rect *rect, struct node *node, struct node **right_out)
|
|
438
|
+
{
|
|
439
|
+
int axis = rect_largest_axis(rect);
|
|
440
|
+
struct node *right = node_new(tr, node->kind);
|
|
441
|
+
if (!right) {
|
|
442
|
+
return false;
|
|
443
|
+
}
|
|
444
|
+
for (int i = 0; i < node->count; i++) {
|
|
445
|
+
coord_t min_dist = node->rects[i].min[axis] - rect->min[axis];
|
|
446
|
+
coord_t max_dist = rect->max[axis] - node->rects[i].max[axis];
|
|
447
|
+
if (max_dist < min_dist) {
|
|
448
|
+
// move to right
|
|
449
|
+
node_move_rect_at_index_into(node, i, right);
|
|
450
|
+
i--;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
// Make sure that both left and right nodes have at least
|
|
454
|
+
// MINITEMS by moving items into underflowed nodes.
|
|
455
|
+
if (node->count < MINITEMS) {
|
|
456
|
+
// reverse sort by min axis
|
|
457
|
+
node_sort_by_axis(right, axis, true, false);
|
|
458
|
+
do {
|
|
459
|
+
node_move_rect_at_index_into(right, right->count-1, node);
|
|
460
|
+
} while (node->count < MINITEMS);
|
|
461
|
+
} else if (right->count < MINITEMS) {
|
|
462
|
+
// reverse sort by max axis
|
|
463
|
+
node_sort_by_axis(node, axis, true, true);
|
|
464
|
+
do {
|
|
465
|
+
node_move_rect_at_index_into(node, node->count-1, right);
|
|
466
|
+
} while (right->count < MINITEMS);
|
|
467
|
+
}
|
|
468
|
+
*right_out = right;
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
static bool node_split(struct rtree *tr, struct rect *rect, struct node *node,
|
|
473
|
+
struct node **right)
|
|
474
|
+
{
|
|
475
|
+
return node_split_largest_axis_edge_snap(tr, rect, node, right);
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
static int node_choose_least_enlargement(const struct node *node,
|
|
479
|
+
const struct rect *ir)
|
|
480
|
+
{
|
|
481
|
+
int j = 0;
|
|
482
|
+
coord_t jenlarge = INFINITY;
|
|
483
|
+
for (int i = 0; i < node->count; i++) {
|
|
484
|
+
// calculate the enlarged area
|
|
485
|
+
coord_t uarea = rect_unioned_area(&node->rects[i], ir);
|
|
486
|
+
coord_t area = rect_area(&node->rects[i]);
|
|
487
|
+
coord_t enlarge = uarea - area;
|
|
488
|
+
if (enlarge < jenlarge) {
|
|
489
|
+
j = i;
|
|
490
|
+
jenlarge = enlarge;
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
return j;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
static int node_choose(struct rtree *tr, const struct node *node,
|
|
497
|
+
const struct rect *rect, int depth)
|
|
498
|
+
{
|
|
499
|
+
#ifdef USE_PATHHINT
|
|
500
|
+
int h = tr->path_hint[depth];
|
|
501
|
+
if (h < node->count) {
|
|
502
|
+
if (rect_contains(&node->rects[h], rect)) {
|
|
503
|
+
return h;
|
|
504
|
+
}
|
|
505
|
+
}
|
|
506
|
+
#endif
|
|
507
|
+
// Take a quick look for the first node that contain the rect.
|
|
508
|
+
for (int i = 0; i < node->count; i++) {
|
|
509
|
+
if (rect_contains(&node->rects[i], rect)) {
|
|
510
|
+
#ifdef USE_PATHHINT
|
|
511
|
+
tr->path_hint[depth] = i;
|
|
512
|
+
#endif
|
|
513
|
+
return i;
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
// Fallback to using che "choose least enlargment" algorithm.
|
|
517
|
+
int i = node_choose_least_enlargement(node, rect);
|
|
518
|
+
#ifdef USE_PATHHINT
|
|
519
|
+
tr->path_hint[depth] = i;
|
|
520
|
+
#endif
|
|
521
|
+
return i;
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
static struct rect node_rect_calc(const struct node *node) {
|
|
525
|
+
struct rect rect = node->rects[0];
|
|
526
|
+
for (int i = 1; i < node->count; i++) {
|
|
527
|
+
rect_expand(&rect, &node->rects[i]);
|
|
528
|
+
}
|
|
529
|
+
return rect;
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
// node_insert returns false if out of memory
|
|
533
|
+
static bool node_insert(struct rtree *tr, struct rect *nr, struct node *node,
|
|
534
|
+
struct rect *ir, item_t item, int depth, bool *split)
|
|
535
|
+
{
|
|
536
|
+
if (node->kind == LEAF) {
|
|
537
|
+
if (node->count == MAXITEMS) {
|
|
538
|
+
*split = true;
|
|
539
|
+
return true;
|
|
540
|
+
}
|
|
541
|
+
int index = node->count;
|
|
542
|
+
node->rects[index] = *ir;
|
|
543
|
+
node->items[index] = item;
|
|
544
|
+
node->count++;
|
|
545
|
+
*split = false;
|
|
546
|
+
return true;
|
|
547
|
+
}
|
|
548
|
+
// Choose a subtree for inserting the rectangle.
|
|
549
|
+
int i = node_choose(tr, node, ir, depth);
|
|
550
|
+
cow_node_or(node->nodes[i], return false);
|
|
551
|
+
if (!node_insert(tr, &node->rects[i], node->nodes[i], ir, item, depth+1,
|
|
552
|
+
split))
|
|
553
|
+
{
|
|
554
|
+
return false;
|
|
555
|
+
}
|
|
556
|
+
if (!*split) {
|
|
557
|
+
rect_expand(&node->rects[i], ir);
|
|
558
|
+
*split = false;
|
|
559
|
+
return true;
|
|
560
|
+
}
|
|
561
|
+
// split the child node
|
|
562
|
+
if (node->count == MAXITEMS) {
|
|
563
|
+
*split = true;
|
|
564
|
+
return true;
|
|
565
|
+
}
|
|
566
|
+
struct node *right;
|
|
567
|
+
if (!node_split(tr, &node->rects[i], node->nodes[i], &right)) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
node->rects[i] = node_rect_calc(node->nodes[i]);
|
|
571
|
+
node->rects[node->count] = node_rect_calc(right);
|
|
572
|
+
node->nodes[node->count] = right;
|
|
573
|
+
node->count++;
|
|
574
|
+
return node_insert(tr, nr, node, ir, item, depth, split);
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
struct rtree *rtree_new_with_allocator(void *(*_malloc)(size_t),
|
|
578
|
+
void (*_free)(void*)
|
|
579
|
+
) {
|
|
580
|
+
_malloc = _malloc ? _malloc : malloc;
|
|
581
|
+
_free = _free ? _free : free;
|
|
582
|
+
struct rtree *tr = (struct rtree *)_malloc(sizeof(struct rtree));
|
|
583
|
+
if (!tr) return NULL;
|
|
584
|
+
memset(tr, 0, sizeof(struct rtree));
|
|
585
|
+
tr->malloc = _malloc;
|
|
586
|
+
tr->free = _free;
|
|
587
|
+
return tr;
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
struct rtree *rtree_new(void) {
|
|
591
|
+
return rtree_new_with_allocator(NULL, NULL);
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
bool rtree_insert(struct rtree *tr, const coord_t *min,
|
|
595
|
+
const coord_t *max, const item_t item)
|
|
596
|
+
{
|
|
597
|
+
// copy input rect
|
|
598
|
+
struct rect rect;
|
|
599
|
+
memcpy(&rect.min[0], min, sizeof(coord_t)*DIMS);
|
|
600
|
+
memcpy(&rect.max[0], max?max:min, sizeof(coord_t)*DIMS);
|
|
601
|
+
|
|
602
|
+
while (1) {
|
|
603
|
+
if (!tr->root) {
|
|
604
|
+
struct node *new_root = node_new(tr, LEAF);
|
|
605
|
+
if (!new_root) {
|
|
606
|
+
break;
|
|
607
|
+
}
|
|
608
|
+
tr->root = new_root;
|
|
609
|
+
tr->rect = rect;
|
|
610
|
+
tr->height = 1;
|
|
611
|
+
}
|
|
612
|
+
bool split = false;
|
|
613
|
+
cow_node_or(tr->root, break);
|
|
614
|
+
if (!node_insert(tr, &tr->rect, tr->root, &rect, item, 0, &split)) {
|
|
615
|
+
break;
|
|
616
|
+
}
|
|
617
|
+
if (!split) {
|
|
618
|
+
rect_expand(&tr->rect, &rect);
|
|
619
|
+
tr->count++;
|
|
620
|
+
return true;
|
|
621
|
+
}
|
|
622
|
+
struct node *new_root = node_new(tr, BRANCH);
|
|
623
|
+
if (!new_root) {
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
struct node *right;
|
|
627
|
+
if (!node_split(tr, &tr->rect, tr->root, &right)) {
|
|
628
|
+
tr->free(new_root);
|
|
629
|
+
break;
|
|
630
|
+
}
|
|
631
|
+
new_root->rects[0] = node_rect_calc(tr->root);
|
|
632
|
+
new_root->rects[1] = node_rect_calc(right);
|
|
633
|
+
new_root->nodes[0] = tr->root;
|
|
634
|
+
new_root->nodes[1] = right;
|
|
635
|
+
tr->root = new_root;
|
|
636
|
+
tr->root->count = 2;
|
|
637
|
+
tr->height++;
|
|
638
|
+
}
|
|
639
|
+
// out of memory
|
|
640
|
+
return false;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
void rtree_free(struct rtree *tr) {
|
|
644
|
+
if (tr->root) {
|
|
645
|
+
node_free(tr, tr->root);
|
|
646
|
+
}
|
|
647
|
+
if (tr->queue) {
|
|
648
|
+
priority_queue_free(tr->queue);
|
|
649
|
+
}
|
|
650
|
+
tr->free(tr);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
static bool node_search(struct node *node, struct rect *rect,
|
|
654
|
+
bool (*iter)(const coord_t *min, const coord_t *max, const item_t item,
|
|
655
|
+
void *udata),
|
|
656
|
+
void *udata)
|
|
657
|
+
{
|
|
658
|
+
if (node->kind == LEAF) {
|
|
659
|
+
for (int i = 0; i < node->count; i++) {
|
|
660
|
+
if (rect_intersects(&node->rects[i], rect)) {
|
|
661
|
+
if (!iter(node->rects[i].min, node->rects[i].max,
|
|
662
|
+
node->items[i], udata))
|
|
663
|
+
{
|
|
664
|
+
return false;
|
|
665
|
+
}
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
for (int i = 0; i < node->count; i++) {
|
|
671
|
+
if (rect_intersects(&node->rects[i], rect)) {
|
|
672
|
+
if (!node_search(node->nodes[i], rect, iter, udata)) {
|
|
673
|
+
return false;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
}
|
|
677
|
+
return true;
|
|
678
|
+
}
|
|
679
|
+
|
|
680
|
+
void rtree_search(const struct rtree *tr, const coord_t min[],
|
|
681
|
+
const coord_t max[],
|
|
682
|
+
bool (*iter)(const coord_t min[], const coord_t max[], const item_t item,
|
|
683
|
+
void *udata),
|
|
684
|
+
void *udata)
|
|
685
|
+
{
|
|
686
|
+
// copy input rect
|
|
687
|
+
struct rect rect;
|
|
688
|
+
memcpy(&rect.min[0], min, sizeof(coord_t)*DIMS);
|
|
689
|
+
memcpy(&rect.max[0], max?max:min, sizeof(coord_t)*DIMS);
|
|
690
|
+
|
|
691
|
+
if (tr->root) {
|
|
692
|
+
node_search(tr->root, &rect, iter, udata);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
coord_t distance_bb(const coord_t point[], struct rect *rect) {
|
|
697
|
+
|
|
698
|
+
coord_t dist2 = 0;
|
|
699
|
+
|
|
700
|
+
for (int i = 0; i < DIMS; i++) {
|
|
701
|
+
if (point[i] < rect->min[i]) {
|
|
702
|
+
dist2 += pow(rect->min[i] - point[i], 2);
|
|
703
|
+
} else if (point[i] > rect->max[i]) {
|
|
704
|
+
dist2 += pow(point[i] - rect->max[i], 2);
|
|
705
|
+
}
|
|
706
|
+
// else: coordinate is within min and max, does not contribute to
|
|
707
|
+
// distance
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
return dist2;
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
bool rtree_nearest(struct rtree *tr, const coord_t point[],
|
|
714
|
+
bool (*iter)(const item_t item, coord_t distance, void *udata),
|
|
715
|
+
void *udata) {
|
|
716
|
+
|
|
717
|
+
if (!tr->root)
|
|
718
|
+
return true;
|
|
719
|
+
|
|
720
|
+
if (!tr->queue)
|
|
721
|
+
tr->queue = priority_queue_new();
|
|
722
|
+
else
|
|
723
|
+
tr->queue->size = 0;
|
|
724
|
+
|
|
725
|
+
struct element root = { .distance = 0.0, .kind = tr->root->kind, .node = tr->root };
|
|
726
|
+
if (!enqueue(tr->queue, root)) {
|
|
727
|
+
return false;
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
while (tr->queue->size > 0) {
|
|
731
|
+
|
|
732
|
+
struct element next_element = dequeue(tr->queue);
|
|
733
|
+
|
|
734
|
+
if (next_element.kind == ITEM) {
|
|
735
|
+
// We found an ITEM with an exact distance that is the next closest
|
|
736
|
+
// to the query point.
|
|
737
|
+
|
|
738
|
+
// Report the item and stop searching if the user function returns
|
|
739
|
+
// false:
|
|
740
|
+
bool keep_going = iter(next_element.item, next_element.distance, udata);
|
|
741
|
+
if (!keep_going) {
|
|
742
|
+
return true;
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
} else if (next_element.kind == ITEM_BY_BB) {
|
|
746
|
+
// We found an ITEM_BY_BB in the queue, whose bounding box is next
|
|
747
|
+
// closest to the query point.
|
|
748
|
+
|
|
749
|
+
// Here, we can calculate a more accurate distance than the one
|
|
750
|
+
// used in the queue (e.g., distance to a line is poorly
|
|
751
|
+
// approximated by distance to bounding box of line). If that
|
|
752
|
+
// distance is larger than the next element on the queue, enqueue
|
|
753
|
+
// the item again with kind ITEM and continue the while-loop.
|
|
754
|
+
|
|
755
|
+
#ifdef KNN_USE_EXACT_DISTANCE
|
|
756
|
+
next_element.distance = distance(point, next_element.rect, next_element.item);
|
|
757
|
+
if (next_element.distance > peek(tr->queue).distance) {
|
|
758
|
+
next_element.kind = ITEM;
|
|
759
|
+
if (!enqueue(tr->queue, next_element)) {
|
|
760
|
+
return false;
|
|
761
|
+
}
|
|
762
|
+
continue;
|
|
763
|
+
}
|
|
764
|
+
#endif
|
|
765
|
+
|
|
766
|
+
// Report the item and stop searching if the user function returns
|
|
767
|
+
// false:
|
|
768
|
+
bool keep_going = iter(next_element.item, next_element.distance, udata);
|
|
769
|
+
if (!keep_going) {
|
|
770
|
+
return true;
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
} else if (next_element.kind == LEAF) {
|
|
774
|
+
// We found a LEAF node in the queue, whose bounding box is next
|
|
775
|
+
// closest to the query point. Add each item contained in that leaf
|
|
776
|
+
// to the queue.
|
|
777
|
+
|
|
778
|
+
struct node *leaf = next_element.node;
|
|
779
|
+
for (int i = 0; i < leaf->count; i++) {
|
|
780
|
+
|
|
781
|
+
struct element item_element = {
|
|
782
|
+
.distance = distance_bb(point, &leaf->rects[i]),
|
|
783
|
+
.kind = ITEM_BY_BB,
|
|
784
|
+
.item = leaf->items[i],
|
|
785
|
+
.rect = &leaf->rects[i]
|
|
786
|
+
};
|
|
787
|
+
if (!enqueue(tr->queue, item_element)) {
|
|
788
|
+
return false;
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
} else { // next_element.kind == BRANCH
|
|
793
|
+
// We found a BRANCH node in the queue, whose bounding box is next
|
|
794
|
+
// closest to the query point. Add each child node (BRANCH or LEAF)
|
|
795
|
+
// to the queue.
|
|
796
|
+
|
|
797
|
+
struct node *branch = next_element.node;
|
|
798
|
+
for (int i = 0; i < branch->count; i++) {
|
|
799
|
+
|
|
800
|
+
struct element node_element = {
|
|
801
|
+
.distance = distance_bb(point, &branch->rects[i]),
|
|
802
|
+
.kind = branch->nodes[i]->kind, // BRANCH or LEAF
|
|
803
|
+
.node = branch->nodes[i]
|
|
804
|
+
};
|
|
805
|
+
if (!enqueue(tr->queue, node_element)) {
|
|
806
|
+
return false;
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
}
|
|
810
|
+
}
|
|
811
|
+
return true;
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
static bool node_scan(struct node *node,
|
|
815
|
+
bool (*iter)(const coord_t *min, const coord_t *max, const item_t item,
|
|
816
|
+
void *udata),
|
|
817
|
+
void *udata)
|
|
818
|
+
{
|
|
819
|
+
if (node->kind == LEAF) {
|
|
820
|
+
for (int i = 0; i < node->count; i++) {
|
|
821
|
+
if (!iter(node->rects[i].min, node->rects[i].max,
|
|
822
|
+
node->items[i], udata))
|
|
823
|
+
{
|
|
824
|
+
return false;
|
|
825
|
+
}
|
|
826
|
+
}
|
|
827
|
+
return true;
|
|
828
|
+
}
|
|
829
|
+
for (int i = 0; i < node->count; i++) {
|
|
830
|
+
if (!node_scan(node->nodes[i], iter, udata)) {
|
|
831
|
+
return false;
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
return true;
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
void rtree_scan(const struct rtree *tr,
|
|
838
|
+
bool (*iter)(const coord_t *min, const coord_t *max, const item_t item,
|
|
839
|
+
void *udata),
|
|
840
|
+
void *udata)
|
|
841
|
+
{
|
|
842
|
+
if (tr->root) {
|
|
843
|
+
node_scan(tr->root, iter, udata);
|
|
844
|
+
}
|
|
845
|
+
}
|
|
846
|
+
|
|
847
|
+
size_t rtree_count(const struct rtree *tr) {
|
|
848
|
+
return tr->count;
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
void rtree_bb(const struct rtree *tr, coord_t* min, coord_t* max) {
|
|
852
|
+
memcpy(min, tr->rect.min, sizeof(coord_t)*DIMS);
|
|
853
|
+
memcpy(max, tr->rect.max, sizeof(coord_t)*DIMS);
|
|
854
|
+
}
|
|
855
|
+
|
|
856
|
+
static bool node_delete(struct rtree *tr, struct rect *nr, struct node *node,
|
|
857
|
+
struct rect *ir, item_t item, int depth, bool *removed, bool *shrunk,
|
|
858
|
+
int (*compare)(const item_t a, const item_t b, void *udata),
|
|
859
|
+
void *udata)
|
|
860
|
+
{
|
|
861
|
+
*removed = false;
|
|
862
|
+
*shrunk = false;
|
|
863
|
+
if (node->kind == LEAF) {
|
|
864
|
+
for (int i = 0; i < node->count; i++) {
|
|
865
|
+
if (!rect_equals_bin(ir, &node->rects[i])) {
|
|
866
|
+
// different bounding box, keep going
|
|
867
|
+
continue;
|
|
868
|
+
}
|
|
869
|
+
if (!equal(node->items[i], item)) {
|
|
870
|
+
// different content, keep going
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
// Found the target item to delete.
|
|
874
|
+
node->rects[i] = node->rects[node->count-1];
|
|
875
|
+
node->items[i] = node->items[node->count-1];
|
|
876
|
+
node->count--;
|
|
877
|
+
if (rect_onedge(ir, nr)) {
|
|
878
|
+
// The item rect was on the edge of the node rect.
|
|
879
|
+
// We need to recalculate the node rect.
|
|
880
|
+
*nr = node_rect_calc(node);
|
|
881
|
+
// Notify the caller that we shrunk the rect.
|
|
882
|
+
*shrunk = true;
|
|
883
|
+
}
|
|
884
|
+
*removed = true;
|
|
885
|
+
return true;
|
|
886
|
+
}
|
|
887
|
+
return true;
|
|
888
|
+
}
|
|
889
|
+
int h = 0;
|
|
890
|
+
#ifdef USE_PATHHINT
|
|
891
|
+
h = tr->path_hint[depth];
|
|
892
|
+
if (h < node->count) {
|
|
893
|
+
if (rect_contains(&node->rects[h], ir)) {
|
|
894
|
+
cow_node_or(node->nodes[h], return false);
|
|
895
|
+
if (!node_delete(tr, &node->rects[h], node->nodes[h], ir, item,
|
|
896
|
+
depth+1,removed, shrunk, compare, udata))
|
|
897
|
+
{
|
|
898
|
+
return false;
|
|
899
|
+
}
|
|
900
|
+
if (*removed) {
|
|
901
|
+
goto removed;
|
|
902
|
+
}
|
|
903
|
+
}
|
|
904
|
+
}
|
|
905
|
+
h = 0;
|
|
906
|
+
#endif
|
|
907
|
+
for (; h < node->count; h++) {
|
|
908
|
+
if (!rect_contains(&node->rects[h], ir)) {
|
|
909
|
+
continue;
|
|
910
|
+
}
|
|
911
|
+
struct rect crect = node->rects[h];
|
|
912
|
+
cow_node_or(node->nodes[h], return false);
|
|
913
|
+
if (!node_delete(tr, &node->rects[h], node->nodes[h], ir, item, depth+1,
|
|
914
|
+
removed, shrunk, compare, udata))
|
|
915
|
+
{
|
|
916
|
+
return false;
|
|
917
|
+
}
|
|
918
|
+
if (!*removed) {
|
|
919
|
+
continue;
|
|
920
|
+
}
|
|
921
|
+
removed:
|
|
922
|
+
if (node->nodes[h]->count == 0) {
|
|
923
|
+
// underflow
|
|
924
|
+
node_free(tr, node->nodes[h]);
|
|
925
|
+
node->rects[h] = node->rects[node->count-1];
|
|
926
|
+
node->nodes[h] = node->nodes[node->count-1];
|
|
927
|
+
node->count--;
|
|
928
|
+
*nr = node_rect_calc(node);
|
|
929
|
+
*shrunk = true;
|
|
930
|
+
return true;
|
|
931
|
+
}
|
|
932
|
+
#ifdef USE_PATHHINT
|
|
933
|
+
tr->path_hint[depth] = h;
|
|
934
|
+
#endif
|
|
935
|
+
if (*shrunk) {
|
|
936
|
+
*shrunk = !rect_equals(&node->rects[h], &crect);
|
|
937
|
+
if (*shrunk) {
|
|
938
|
+
*nr = node_rect_calc(node);
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
return true;
|
|
942
|
+
}
|
|
943
|
+
return true;
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
// returns false if out of memory
|
|
947
|
+
static int rtree_delete0(struct rtree *tr, const coord_t *min,
|
|
948
|
+
const coord_t *max, const item_t item,
|
|
949
|
+
int (*compare)(const item_t a, const item_t b, void *udata),
|
|
950
|
+
void *udata)
|
|
951
|
+
{
|
|
952
|
+
// copy input rect
|
|
953
|
+
struct rect rect;
|
|
954
|
+
memcpy(&rect.min[0], min, sizeof(coord_t)*DIMS);
|
|
955
|
+
memcpy(&rect.max[0], max?max:min, sizeof(coord_t)*DIMS);
|
|
956
|
+
|
|
957
|
+
if (!tr->root) {
|
|
958
|
+
return 0;
|
|
959
|
+
}
|
|
960
|
+
bool removed = false;
|
|
961
|
+
bool shrunk = false;
|
|
962
|
+
cow_node_or(tr->root, return false);
|
|
963
|
+
if (!node_delete(tr, &tr->rect, tr->root, &rect, item, 0, &removed, &shrunk,
|
|
964
|
+
compare, udata))
|
|
965
|
+
{
|
|
966
|
+
return -1; // OOM
|
|
967
|
+
}
|
|
968
|
+
if (!removed) {
|
|
969
|
+
return 0;
|
|
970
|
+
}
|
|
971
|
+
tr->count--;
|
|
972
|
+
if (tr->count == 0) {
|
|
973
|
+
node_free(tr, tr->root);
|
|
974
|
+
tr->root = NULL;
|
|
975
|
+
memset(&tr->rect, 0, sizeof(struct rect));
|
|
976
|
+
tr->height = 0;
|
|
977
|
+
} else {
|
|
978
|
+
while (tr->root->kind == BRANCH && tr->root->count == 1) {
|
|
979
|
+
struct node *prev = tr->root;
|
|
980
|
+
tr->root = tr->root->nodes[0];
|
|
981
|
+
prev->count = 0;
|
|
982
|
+
node_free(tr, prev);
|
|
983
|
+
tr->height--;
|
|
984
|
+
}
|
|
985
|
+
if (shrunk) {
|
|
986
|
+
tr->rect = node_rect_calc(tr->root);
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
return 1;
|
|
990
|
+
}
|
|
991
|
+
|
|
992
|
+
int rtree_delete(struct rtree *tr, const coord_t *min, const coord_t *max,
|
|
993
|
+
const item_t item)
|
|
994
|
+
{
|
|
995
|
+
return rtree_delete0(tr, min, max, item, NULL, NULL);
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
int rtree_delete_with_comparator(struct rtree *tr, const coord_t *min,
|
|
999
|
+
const coord_t *max, const item_t item,
|
|
1000
|
+
int (*compare)(const item_t a, const item_t b, void *udata),
|
|
1001
|
+
void *udata)
|
|
1002
|
+
{
|
|
1003
|
+
return rtree_delete0(tr, min, max, item, compare, udata);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
struct rtree *rtree_clone(struct rtree *tr) {
|
|
1007
|
+
if (!tr) return NULL;
|
|
1008
|
+
struct rtree *tr2 = tr->malloc(sizeof(struct rtree));
|
|
1009
|
+
if (!tr2) return NULL;
|
|
1010
|
+
memcpy(tr2, tr, sizeof(struct rtree));
|
|
1011
|
+
if (tr2->root) rc_fetch_add(&tr2->root->rc, 1);
|
|
1012
|
+
return tr2;
|
|
1013
|
+
}
|
|
1014
|
+
|
|
1015
|
+
void rtree_opt_relaxed_atomics(struct rtree *tr) {
|
|
1016
|
+
tr->relaxed = true;
|
|
1017
|
+
}
|
|
1018
|
+
|
|
1019
|
+
#ifdef TEST_PRIVATE_FUNCTIONS
|
|
1020
|
+
#include "tests/priv_funcs.h"
|
|
1021
|
+
#endif
|