lulu 0.0.2 → 0.0.3
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 +8 -8
- data/.gitignore +1 -1
- data/ext/lulu/extconf.rb +3 -0
- data/ext/lulu/lulu.c +6 -6
- data/ext/lulu/marker.c +65 -65
- data/ext/lulu/marker.h +22 -22
- data/ext/lulu/merger.c +116 -154
- data/ext/lulu/merger.h +0 -2
- data/ext/lulu/pq.c +106 -179
- data/ext/lulu/pq.h +10 -13
- data/ext/lulu/qt.c +135 -191
- data/ext/lulu/qt.h +11 -10
- data/ext/lulu/test.c +221 -45
- data/ext/lulu/test.h +5 -0
- data/ext/lulu/utility.c +22 -26
- data/ext/lulu/utility.h +17 -14
- data/lib/lulu/version.rb +1 -1
- data/lulu.gemspec +10 -10
- metadata +6 -8
- data/ext/lulu/Makefile +0 -220
- data/lib/lulu/lulu.bundle +0 -0
data/ext/lulu/merger.h
CHANGED
data/ext/lulu/pq.c
CHANGED
@@ -17,228 +17,155 @@
|
|
17
17
|
|
18
18
|
// Move index at heap location j upward until its parent's value is no bigger.
|
19
19
|
static void pq_sift_up(PRIORITY_QUEUE *q, int j) {
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
20
|
+
int i = q->heap[j];
|
21
|
+
PRIORITY_QUEUE_VALUE val = q->values[i];
|
22
|
+
while (j > 0) {
|
23
|
+
int j_pnt = (j - 1) / 2;
|
24
|
+
if (q->values[q->heap[j_pnt]] <= val)
|
25
|
+
break;
|
26
|
+
int k = q->heap[j] = q->heap[j_pnt];
|
27
|
+
q->locs[k] = j;
|
28
|
+
j = j_pnt;
|
29
|
+
}
|
30
|
+
int k = q->heap[j] = i;
|
31
|
+
q->locs[k] = j;
|
32
32
|
}
|
33
33
|
|
34
34
|
// Move index at heap location j downward until its children's values are no smaller.
|
35
35
|
// Pay some attention to efficiency because this is bottleneck code.
|
36
36
|
static void pq_sift_down(PRIORITY_QUEUE *q, int j) {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
37
|
+
int i = q->heap[j];
|
38
|
+
PRIORITY_QUEUE_VALUE val = q->values[i];
|
39
|
+
for (;;) {
|
40
|
+
int j_rgt = 2 * j + 2;
|
41
|
+
if (j_rgt < q->size) {
|
42
|
+
// two children
|
43
|
+
int j_lft = j_rgt - 1;
|
44
|
+
PRIORITY_QUEUE_VALUE val_lft = q->values[q->heap[j_lft]];
|
45
|
+
PRIORITY_QUEUE_VALUE val_rgt = q->values[q->heap[j_rgt]];
|
46
|
+
if (val_lft < val_rgt) {
|
47
|
+
if (val <= val_lft)
|
48
|
+
break;
|
49
|
+
int k = q->heap[j] = q->heap[j_lft];
|
50
|
+
q->locs[k] = j;
|
51
|
+
j = j_lft;
|
52
|
+
} else {
|
53
|
+
if (val <= val_rgt)
|
54
|
+
break;
|
55
|
+
int k = q->heap[j] = q->heap[j_rgt];
|
56
|
+
q->locs[k] = j;
|
57
|
+
j = j_rgt;
|
58
|
+
}
|
59
|
+
} else if (j_rgt == q->size) {
|
60
|
+
// left child only
|
61
|
+
int j_lft = j_rgt - 1;
|
62
|
+
if (val <= q->values[q->heap[j_lft]])
|
63
|
+
break;
|
64
|
+
int k = q->heap[j] = q->heap[j_lft];
|
65
|
+
q->locs[k] = j;
|
66
|
+
j = j_lft;
|
67
|
+
break; // this node has no children
|
68
|
+
} else {
|
69
|
+
break; // no children at all
|
70
|
+
}
|
71
|
+
}
|
72
|
+
int k = q->heap[j] = i;
|
73
|
+
q->locs[k] = j;
|
74
74
|
}
|
75
75
|
|
76
76
|
// Initialize a newly allocated priority queue structure.
|
77
77
|
void pq_init(PRIORITY_QUEUE *q) {
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
78
|
+
q->max_size = q->size = 0;
|
79
|
+
q->heap = NULL;
|
80
|
+
q->locs = NULL;
|
81
|
+
q->values = NULL;
|
82
82
|
}
|
83
83
|
|
84
84
|
// Clear a previously initialized and possibly set up priority queue, returning
|
85
85
|
// it to the initialized state but with all resourced freed. Note the values
|
86
86
|
// are owned by the user and are not freed here.
|
87
87
|
void pq_clear(PRIORITY_QUEUE *q) {
|
88
|
-
|
89
|
-
|
90
|
-
|
88
|
+
Free(q->heap);
|
89
|
+
Free(q->locs);
|
90
|
+
pq_init(q);
|
91
91
|
}
|
92
92
|
|
93
93
|
// Build the queue with given pre-allocated and filled array of values.
|
94
94
|
void pq_set_up(PRIORITY_QUEUE *q, PRIORITY_QUEUE_VALUE *values, int size) {
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
95
|
+
q->max_size = q->size = size;
|
96
|
+
q->values = values;
|
97
|
+
NewArray(q->heap, size);
|
98
|
+
NewArray(q->locs, size);
|
99
|
+
for (int i = 0; i < size; i++)
|
100
|
+
q->heap[i] = q->locs[i] = i;
|
101
|
+
// heapify
|
102
|
+
for (int j = size / 2 - 1; j >= 0; j--)
|
103
|
+
pq_sift_down(q, j);
|
104
104
|
}
|
105
105
|
|
106
106
|
// Build the queue with given pre-allocated and filled array of values
|
107
107
|
// and given heap indices. Note the indices are owned by the heap
|
108
108
|
// after set up and will be freed with the heap.
|
109
109
|
void pq_set_up_heap(PRIORITY_QUEUE *q, int *heap, int size,
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
110
|
+
PRIORITY_QUEUE_VALUE *values, int max_size) {
|
111
|
+
q->max_size = max_size;
|
112
|
+
q->values = values;
|
113
|
+
q->size = size;
|
114
|
+
q->heap = heap;
|
115
|
+
NewArray(q->locs, max_size);
|
116
|
+
for (int i = 0; i < max_size; i++)
|
117
|
+
q->locs[i] = -1;
|
118
|
+
for (int j = 0; j < size; j++)
|
119
|
+
q->locs[heap[j]] = j;
|
120
|
+
for (int j = size / 2 - 1; j >= 0; j--)
|
121
|
+
pq_sift_down(q, j);
|
122
122
|
}
|
123
123
|
|
124
124
|
// Return the index of the minimum value on the queue.
|
125
125
|
int pq_peek_min(PRIORITY_QUEUE *q) {
|
126
|
-
|
126
|
+
return q->size <= 0 ? -1 : q->heap[0];
|
127
127
|
}
|
128
128
|
|
129
129
|
// Remove and return the index of the minimum value on the queue.
|
130
130
|
int pq_get_min(PRIORITY_QUEUE *q) {
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
131
|
+
if (q->size <= 0)
|
132
|
+
return -1;
|
133
|
+
int i = q->heap[0];
|
134
|
+
q->locs[i] = -1;
|
135
|
+
if (--q->size > 0) {
|
136
|
+
q->heap[0] = q->heap[q->size];
|
137
|
+
pq_sift_down(q, 0);
|
138
|
+
}
|
139
|
+
return i;
|
140
140
|
}
|
141
141
|
|
142
142
|
// Add a new value with index i into the queue.
|
143
143
|
void pq_add(PRIORITY_QUEUE *q, int i) {
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
144
|
+
if (q->size >= q->max_size)
|
145
|
+
return;
|
146
|
+
int j = q->size++;
|
147
|
+
q->heap[j] = i;
|
148
|
+
pq_sift_up(q, j);
|
149
149
|
}
|
150
150
|
|
151
151
|
// Restore the heap after the value at index i is changed.
|
152
152
|
void pq_update(PRIORITY_QUEUE *q, int i) {
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
153
|
+
int j = q->locs[i];
|
154
|
+
if (j >= 0) {
|
155
|
+
pq_sift_down(q, j);
|
156
|
+
pq_sift_up(q, j);
|
157
|
+
}
|
158
158
|
}
|
159
159
|
|
160
160
|
// Delete index i from the heap, making the corresponding key an orphan.
|
161
161
|
void pq_delete(PRIORITY_QUEUE *q, int i) {
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
162
|
+
int j = q->locs[i];
|
163
|
+
if (0 <= j) {
|
164
|
+
q->locs[i] = -1;
|
165
|
+
if (j < --q->size) {
|
166
|
+
q->heap[j] = q->heap[q->size];
|
167
|
+
pq_sift_down(q, j);
|
168
|
+
pq_sift_up(q, j);
|
169
|
+
}
|
170
|
+
}
|
171
171
|
}
|
172
|
-
|
173
|
-
#ifndef EXCLUDE_UNIT_TEST
|
174
|
-
|
175
|
-
/* Randomly permute the given distance array. */
|
176
|
-
void permute(PRIORITY_QUEUE_VALUE *a, int size) {
|
177
|
-
for (int i = size - 1; i > 0; i--) {
|
178
|
-
int j = rand() % (i + 1);
|
179
|
-
PRIORITY_QUEUE_VALUE tmp = a[i];
|
180
|
-
a[i] = a[j];
|
181
|
-
a[j] = tmp;
|
182
|
-
}
|
183
|
-
}
|
184
|
-
|
185
|
-
// Run a unit test on a priority queue of random data with given size.
|
186
|
-
int pq_test(int size) {
|
187
|
-
PRIORITY_QUEUE q[1];
|
188
|
-
pq_init(q);
|
189
|
-
|
190
|
-
fprintf(stderr, "test: heap_ops (n = %d):\n", size);
|
191
|
-
|
192
|
-
// Build linear pointer array of random keys.
|
193
|
-
PRIORITY_QUEUE_VALUE *dist;
|
194
|
-
NewArray(dist, size);
|
195
|
-
for (int i = 0; i < size; i++)
|
196
|
-
dist[i] = i;
|
197
|
-
permute(dist, size);
|
198
|
-
fprintf(stderr, " built random data\n");
|
199
|
-
|
200
|
-
pq_set_up(q, dist, size);
|
201
|
-
fprintf(stderr, " finished set up\n");
|
202
|
-
|
203
|
-
// Pull min repeatedly and verify vals are what they should be.
|
204
|
-
PRIORITY_QUEUE_VALUE should_be = 0;
|
205
|
-
for (int n = 0; n < size; n++) {
|
206
|
-
int i = pq_get_min(q);
|
207
|
-
if (dist[i] != should_be++) {
|
208
|
-
fprintf(stderr, "fail 1: %i -> %g\n", i, dist[i]);
|
209
|
-
return 42;
|
210
|
-
}
|
211
|
-
}
|
212
|
-
fprintf(stderr, " finished checking heapify\n");
|
213
|
-
|
214
|
-
// Now rebuild the heap by inserting one key at a time.
|
215
|
-
for (int n = 0; n < size; n++)
|
216
|
-
pq_add(q, n);
|
217
|
-
fprintf(stderr, " finished insertions\n");
|
218
|
-
|
219
|
-
// And verify values again.
|
220
|
-
should_be = 0;
|
221
|
-
for (int n = 0; n < size; n++) {
|
222
|
-
int i = pq_get_min(q);
|
223
|
-
if (dist[i] != should_be++) {
|
224
|
-
fprintf(stderr, " fail 2: %i -> %g\n", i, dist[i]);
|
225
|
-
return 4242;
|
226
|
-
}
|
227
|
-
}
|
228
|
-
fprintf(stderr, " finished checking insert\n");
|
229
|
-
|
230
|
-
// Now rebuild the heap by inserting one key at a time in reverse.
|
231
|
-
for (int n = size - 1; n >= 0; n--)
|
232
|
-
pq_add(q, n);
|
233
|
-
fprintf(stderr, " finished reverse insertions\n");
|
234
|
-
|
235
|
-
// Now delete one by one.
|
236
|
-
for (int n = 0; n < size; n++)
|
237
|
-
pq_delete(q, n);
|
238
|
-
fprintf(stderr, " finished reverse deletions\n");
|
239
|
-
|
240
|
-
pq_clear(q);
|
241
|
-
return 0;
|
242
|
-
}
|
243
|
-
|
244
|
-
#endif
|
data/ext/lulu/pq.h
CHANGED
@@ -11,11 +11,11 @@
|
|
11
11
|
typedef double PRIORITY_QUEUE_VALUE;
|
12
12
|
|
13
13
|
typedef struct priority_queue_s {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
int max_size; // max number of items in heap
|
15
|
+
int size; // current number of items in heap
|
16
|
+
int *heap; // heap of indices to values
|
17
|
+
int *locs; // map of value indices to heap locations
|
18
|
+
PRIORITY_QUEUE_VALUE *values; // values referred to by heap
|
19
19
|
} PRIORITY_QUEUE;
|
20
20
|
|
21
21
|
// Initialize a newly allocated priority queue structure.
|
@@ -34,8 +34,8 @@ void pq_set_up(PRIORITY_QUEUE *q, PRIORITY_QUEUE_VALUE *values, int size);
|
|
34
34
|
// and given heap indices. Note the indices are owned by the heap
|
35
35
|
// after set up and will be freed with the heap.
|
36
36
|
void pq_set_up_heap(PRIORITY_QUEUE *q,
|
37
|
-
|
38
|
-
|
37
|
+
int *heap, int size,
|
38
|
+
PRIORITY_QUEUE_VALUE *values, int max_size);
|
39
39
|
|
40
40
|
// Return the index of the minimum value on the queue.
|
41
41
|
int pq_peek_min(PRIORITY_QUEUE *q);
|
@@ -53,18 +53,15 @@ void pq_add(PRIORITY_QUEUE *q, int i);
|
|
53
53
|
void pq_delete(PRIORITY_QUEUE *q, int i);
|
54
54
|
|
55
55
|
// Return an array containing indices currently in the heap.
|
56
|
-
#define pq_index_set(Q)
|
56
|
+
#define pq_index_set(Q) ((Q)->heap)
|
57
57
|
|
58
58
|
// Return an array containing indices currently in the heap.
|
59
|
-
#define pq_index(Q, I)
|
59
|
+
#define pq_index(Q, I) ((Q)->heap[I])
|
60
60
|
|
61
61
|
// Return the size of the index array contained above.
|
62
|
-
#define pq_index_set_size(Q)
|
62
|
+
#define pq_index_set_size(Q) ((Q)->size)
|
63
63
|
|
64
64
|
// Return non-zero iff the queue is empty.
|
65
65
|
#define pq_empty_p(Q) ((Q)->size <= 0)
|
66
66
|
|
67
|
-
// Run the heap module through some unit tests.
|
68
|
-
int pq_test(int size);
|
69
|
-
|
70
67
|
#endif /* PRIORITY_QUEUE_H_ */
|
data/ext/lulu/qt.c
CHANGED
@@ -14,31 +14,31 @@
|
|
14
14
|
|
15
15
|
// Declare the given quadrant of a given bounding box.
|
16
16
|
#define QUADRANT_DECL(Q, QX, QY, QW, QH, X, Y, W, H) \
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
17
|
+
MARKER_DISTANCE QW = W * 0.5; \
|
18
|
+
MARKER_DISTANCE QH = H * 0.5; \
|
19
|
+
MARKER_COORD QX = (Q & 1) ? X + QW : X; \
|
20
|
+
MARKER_COORD QY = (Q & 2) ? Y + QH : Y
|
21
21
|
|
22
22
|
// Initialize a node to an empty leaf.
|
23
23
|
static void init_leaf(NODE *node) {
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
node->children = NULL;
|
25
|
+
node->markers = NULL;
|
26
|
+
node->marker_count = node->markers_size = 0;
|
27
27
|
}
|
28
28
|
|
29
29
|
// Clear contents of a leaf, returning it to the init_leaf state.
|
30
30
|
static void clear_leaf(NODE *node) {
|
31
|
-
|
32
|
-
|
31
|
+
Free(node->markers);
|
32
|
+
init_leaf(node);
|
33
33
|
}
|
34
34
|
|
35
35
|
// Make a leaf into an internal node with four empty leaves.
|
36
36
|
static void subdivide(NODE *node) {
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
37
|
+
if (leaf_p(node)) {
|
38
|
+
NewArray(node->children, 4);
|
39
|
+
for (int i = 0; i < 4; i++)
|
40
|
+
init_leaf(node->children + i);
|
41
|
+
}
|
42
42
|
}
|
43
43
|
|
44
44
|
static void clear_node(NODE *node);
|
@@ -46,254 +46,198 @@ static void clear_node(NODE *node);
|
|
46
46
|
// Recursively clear an internal node by removing all
|
47
47
|
// subtrees, returning this node to the init_leaf state.
|
48
48
|
static void clear_internal(NODE *node) {
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
for (int i = 0; i < 4; i++)
|
50
|
+
clear_node(node->children + i);
|
51
|
+
Free(node->children);
|
52
|
+
clear_leaf(node);
|
53
53
|
}
|
54
54
|
|
55
55
|
// Clear any node, returning it to the init_leaf state.
|
56
56
|
// Recursively removes all subtrees.
|
57
57
|
static void clear_node(NODE *node) {
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
if (internal_p(node))
|
59
|
+
clear_internal(node);
|
60
|
+
else
|
61
|
+
clear_leaf(node);
|
62
62
|
}
|
63
63
|
|
64
64
|
// Add a marker to the given node's marker list.
|
65
65
|
static void add_marker(NODE *node, MARKER *marker) {
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
66
|
+
if (node->marker_count == node->markers_size) {
|
67
|
+
node->markers_size = 2 + 2 * node->markers_size;
|
68
|
+
RenewArray(node->markers, node->markers_size);
|
69
|
+
}
|
70
|
+
node->markers[node->marker_count++] = marker;
|
71
71
|
}
|
72
72
|
|
73
73
|
// Find a marker in the given node's marker list.
|
74
74
|
static int find_marker(NODE *node, MARKER *marker) {
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
75
|
+
for (int i = 0; i < node->marker_count; i++)
|
76
|
+
if (node->markers[i] == marker)
|
77
|
+
return i;
|
78
|
+
return -1;
|
79
79
|
}
|
80
80
|
|
81
81
|
// Delete a marker from the given node's marker list.
|
82
82
|
static int delete_marker(NODE *node, MARKER *marker) {
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
int i = find_marker(node, marker);
|
84
|
+
if (i != -1 && --node->marker_count != 0)
|
85
|
+
node->markers[i] = node->markers[node->marker_count];
|
86
|
+
return i;
|
87
87
|
}
|
88
88
|
|
89
89
|
// Return non-zero iff the given bounding box lies inside the marker including its boundary.
|
90
|
-
static int bounds_inside_marker(
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
static int bounds_inside_marker(MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h, MARKER *marker) {
|
91
|
+
MARKER_COORD mx = mr_x(marker);
|
92
|
+
MARKER_COORD my = mr_y(marker);
|
93
|
+
MARKER_DISTANCE mr = mr_r(marker);
|
94
|
+
return mx - mr <= x && x + w <= mx + mr && my - mr <= y && y + h <= my + mr;
|
95
95
|
}
|
96
96
|
|
97
97
|
// Return an integer code with bits showing which quadrants of the given
|
98
98
|
// bounding box are overlapped by the given marker.
|
99
|
-
static int touch_code(
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
99
|
+
static int touch_code(MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h, MARKER *marker) {
|
100
|
+
MARKER_COORD xm = x + 0.5 * w;
|
101
|
+
MARKER_COORD ym = y + 0.5 * h;
|
102
|
+
int code = bit(SW) | bit(SE) | bit(NW) | bit(NE);
|
103
|
+
if (mr_e(marker) < xm) code &= ~(bit(NE) | bit(SE));
|
104
|
+
if (mr_w(marker) > xm) code &= ~(bit(NW) | bit(SW));
|
105
|
+
if (mr_n(marker) < ym) code &= ~(bit(NW) | bit(NE));
|
106
|
+
if (mr_s(marker) > ym) code &= ~(bit(SW) | bit(SE));
|
107
|
+
return code;
|
108
108
|
}
|
109
109
|
|
110
110
|
// Insert the given marker into the quadtree with given root and corresponding bounding box,
|
111
111
|
// subdividing no more than the given number of levels.
|
112
|
-
static void insert(NODE *node, int levels,
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
112
|
+
static void insert(NODE *node, int levels, MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h, MARKER *marker) {
|
113
|
+
if (bounds_inside_marker(x, y, w, h, marker) || levels == 0)
|
114
|
+
add_marker(node, marker);
|
115
|
+
else {
|
116
|
+
if (leaf_p(node))
|
117
|
+
subdivide(node);
|
118
|
+
int code = touch_code(x, y, w, h, marker);
|
119
|
+
for (int q = 0; q < 4; q++)
|
120
|
+
if (code & bit(q)) {
|
121
|
+
QUADRANT_DECL(q, qx, qy, qw, qh, x, y, w, h);
|
122
|
+
insert(node->children + q, levels - 1, qx, qy, qw, qh, marker);
|
123
|
+
}
|
124
|
+
}
|
125
125
|
}
|
126
126
|
|
127
127
|
// A helper function that returns true iff the given array of 4 child quadtrees are all empty leaves.
|
128
128
|
static int empty_leaves_p(NODE *children) {
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
129
|
+
for (int i = 0; i < 4; i++)
|
130
|
+
if (internal_p(children + i) || children[i].marker_count > 0)
|
131
|
+
return 0;
|
132
|
+
return 1;
|
133
133
|
}
|
134
134
|
|
135
135
|
// Delete the given marker from the quadtree with given root and corresponding bounding box,
|
136
136
|
// trimming any remaining empty leaves.
|
137
|
-
static void delete(NODE *node, int levels,
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
137
|
+
static void delete(NODE *node, int levels,
|
138
|
+
MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h,
|
139
|
+
MARKER *marker) {
|
140
|
+
if (bounds_inside_marker(x, y, w, h, marker) || levels == 0)
|
141
|
+
delete_marker(node, marker);
|
142
|
+
else if (internal_p(node)){
|
143
|
+
int code = touch_code(x, y, w, h, marker);
|
144
|
+
for (int q = 0; q < 4; q++)
|
145
|
+
if (code & bit(q)) {
|
146
|
+
QUADRANT_DECL(q, qx, qy, qw, qh, x, y, w, h);
|
147
|
+
delete(node->children + q, levels - 1, qx, qy, qw, qh, marker);
|
148
|
+
}
|
149
|
+
if (empty_leaves_p(node->children))
|
150
|
+
Free(node->children);
|
151
|
+
}
|
150
152
|
}
|
151
153
|
|
152
154
|
// Local struct to hold information about the nearest marker seen so far in a search.
|
153
155
|
struct nearest_info {
|
154
156
|
MARKER_INFO *info;
|
155
157
|
MARKER *target, *nearest;
|
156
|
-
|
158
|
+
MARKER_DISTANCE distance;
|
157
159
|
};
|
158
160
|
|
159
161
|
// Use the marker list of the given node to update nearest information with
|
160
162
|
// respect to the given marker.
|
161
163
|
static void update_nearest(NODE *node, struct nearest_info *nearest_info) {
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
164
|
+
for (int i = 0; i < node->marker_count; i++) {
|
165
|
+
// This < assumes the markers are in an array. It sustains the invariant.
|
166
|
+
if (node->markers[i] < nearest_info->target) {
|
167
|
+
MARKER_DISTANCE d = mr_distance(nearest_info->info, nearest_info->target, node->markers[i]);
|
168
|
+
if (d < nearest_info->distance) {
|
169
|
+
nearest_info->distance = d;
|
170
|
+
nearest_info->nearest = node->markers[i];
|
171
|
+
}
|
172
|
+
}
|
173
|
+
}
|
172
174
|
}
|
173
175
|
|
174
176
|
// Search out the nearest marker that overlaps the given one. This just visits every
|
175
177
|
// quad that overlaps the given marker and remembers the closest marker it sees. The
|
176
178
|
// circle distance function renders quite impossible the ruling out of quads as in
|
177
179
|
// nearest point neighbor search.
|
178
|
-
static void search_for_nearest(NODE *node,
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
}
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
180
|
+
static void search_for_nearest(NODE *node,
|
181
|
+
MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h,
|
182
|
+
struct nearest_info *nearest_info) {
|
183
|
+
update_nearest(node, nearest_info);
|
184
|
+
if (internal_p(node)) {
|
185
|
+
// Search the children that include some part of the marker.
|
186
|
+
int code = touch_code(x, y, w, h, nearest_info->target);
|
187
|
+
for (int q = 0; q < 4; q++)
|
188
|
+
if (code & bit(q)) {
|
189
|
+
QUADRANT_DECL(q, qx, qy, qw, qh, x, y, w, h);
|
190
|
+
search_for_nearest(node->children + q, qx, qy, qw, qh, nearest_info);
|
191
|
+
}
|
192
|
+
}
|
193
|
+
}
|
194
|
+
|
195
|
+
static MARKER *nearest(MARKER_INFO *info, NODE *node,
|
196
|
+
MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h,
|
197
|
+
MARKER *marker) {
|
198
|
+
struct nearest_info nearest_info[1] = {{ info, marker, NULL, 0 }};
|
199
|
+
search_for_nearest(node, x, y, w, h, nearest_info);
|
200
|
+
return nearest_info->nearest;
|
195
201
|
}
|
196
202
|
|
197
203
|
void qt_init(QUADTREE *qt) {
|
198
|
-
|
199
|
-
|
204
|
+
init_leaf(qt->root);
|
205
|
+
qt->x = qt->y = qt->w = qt->h = 0;
|
200
206
|
}
|
201
207
|
|
202
|
-
void qt_setup(QUADTREE *qt, int max_depth,
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
208
|
+
void qt_setup(QUADTREE *qt, int max_depth,
|
209
|
+
MARKER_COORD x, MARKER_COORD y, MARKER_DISTANCE w, MARKER_DISTANCE h,
|
210
|
+
MARKER_INFO *info) {
|
211
|
+
qt->x = x;
|
212
|
+
qt->y = y;
|
213
|
+
qt->w = w;
|
214
|
+
qt->h = h;
|
215
|
+
qt->max_depth = max_depth;
|
216
|
+
qt->info = info;
|
209
217
|
}
|
210
218
|
|
211
219
|
void qt_clear(QUADTREE *qt) {
|
212
|
-
|
213
|
-
|
220
|
+
clear_node(qt->root);
|
221
|
+
qt_init(qt);
|
214
222
|
}
|
215
223
|
|
216
224
|
void qt_insert(QUADTREE *qt, MARKER *marker) {
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
225
|
+
MARKER_COORD x = mr_x(marker);
|
226
|
+
MARKER_COORD y = mr_y(marker);
|
227
|
+
MARKER_DISTANCE r = mr_r(marker);
|
228
|
+
if (x + r >= qt->x && x - r <= qt->x + qt->w && y + r >= qt->y && y - r <= qt->y + qt->h)
|
229
|
+
insert(qt->root, qt->max_depth, qt->x, qt->y, qt->w, qt->h, marker);
|
222
230
|
}
|
223
231
|
|
224
232
|
void qt_delete(QUADTREE *qt, MARKER *marker) {
|
225
|
-
|
233
|
+
delete(qt->root, qt->max_depth, qt->x, qt->y, qt->w, qt->h, marker);
|
226
234
|
}
|
227
235
|
|
228
236
|
MARKER *qt_nearest(QUADTREE *qt, MARKER *marker) {
|
229
|
-
|
237
|
+
return nearest(qt->info, qt->root, qt->x, qt->y, qt->w, qt->h, marker);
|
230
238
|
}
|
231
239
|
|
232
240
|
int qt_nearest_wrt(MARKER *markers, QUADTREE *qt, int a) {
|
233
|
-
|
234
|
-
|
235
|
-
}
|
236
|
-
|
237
|
-
#ifndef EXCLUDE_UNIT_TEST
|
238
|
-
|
239
|
-
static void draw(FILE *f, NODE *node, double x, double y, double w, double h) {
|
240
|
-
emit_rectangle(f, x, y, w, h);
|
241
|
-
emit_marker_ptr_array(f, node->markers, node->marker_count);
|
242
|
-
if (internal_p(node)) {
|
243
|
-
for (int q = 0; q < 4; q++) {
|
244
|
-
QUADRANT_DECL(q, qx, qy, qw, qh, x, y, w, h);
|
245
|
-
draw(f, node->children + q, qx, qy, qw, qh);
|
246
|
-
}
|
247
|
-
}
|
248
|
-
}
|
249
|
-
|
250
|
-
static void draw_nearest(FILE *f, MARKER *markers, MARKER **nearest_markers, int n_markers) {
|
251
|
-
for (int i = 0; i < n_markers; i++) {
|
252
|
-
if (nearest_markers[i])
|
253
|
-
emit_segment(f, markers + i, nearest_markers[i]);
|
254
|
-
}
|
241
|
+
MARKER *nearest = qt_nearest(qt, markers + a);
|
242
|
+
return nearest ? (int)(nearest - markers) : -1;
|
255
243
|
}
|
256
|
-
|
257
|
-
int qt_draw(QUADTREE *qt, MARKER *markers, MARKER **nearest_markers, int n_markers, const char *name) {
|
258
|
-
char buf[1024];
|
259
|
-
sprintf(buf, "test/%s.js", name);
|
260
|
-
FILE *f = fopen(buf, "w");
|
261
|
-
if (!f)
|
262
|
-
return -1;
|
263
|
-
fprintf(f, "var %s = [\n", name);
|
264
|
-
draw(f, qt->root, qt->x, qt->y, qt->w, qt->h);
|
265
|
-
draw_nearest(f, markers, nearest_markers, n_markers);
|
266
|
-
fprintf(f, "];\n");
|
267
|
-
fclose(f);
|
268
|
-
return EXIT_SUCCESS;
|
269
|
-
}
|
270
|
-
|
271
|
-
int qt_test(int size) {
|
272
|
-
QUADTREE_DECL(qt);
|
273
|
-
MARKER_INFO_DECL(info);
|
274
|
-
MARKER *markers, **nearest_markers;
|
275
|
-
NewArray(markers, size);
|
276
|
-
NewArray(nearest_markers, size);
|
277
|
-
set_random_markers(info, markers, size);
|
278
|
-
qt_setup(qt, 5, 0, 0, 1024, 724, info);
|
279
|
-
fprintf(stderr, "inserting %d:\n", size);
|
280
|
-
for (int i = 0; i < size; i++) {
|
281
|
-
qt_insert(qt, markers + i);
|
282
|
-
}
|
283
|
-
fprintf(stderr, "inserted %d\n", size);
|
284
|
-
for (int i = 0; i < size; i++) {
|
285
|
-
nearest_markers[i] = qt_nearest(qt, markers + i);
|
286
|
-
}
|
287
|
-
fprintf(stderr, "looked up %d\n", size);
|
288
|
-
qt_draw(qt, markers, nearest_markers, size, "qt");
|
289
|
-
fprintf(stderr, "drew %d\n", size);
|
290
|
-
for (int i = 0; i < size; i++) {
|
291
|
-
qt_delete(qt, markers + i);
|
292
|
-
}
|
293
|
-
fprintf(stderr, "after delete all, root is %s\n",
|
294
|
-
leaf_p(qt->root) ? "leaf (ok)" : "internal (not ok)");
|
295
|
-
|
296
|
-
return EXIT_SUCCESS;
|
297
|
-
}
|
298
|
-
|
299
|
-
#endif
|