14 d kdarea b---kdbranch-
21 |------kdbranch---------
29 /* 0=right 1=down 2=left 3=up */
30 static int vx_and
[4] = {INT_MAX
, 0, INT_MAX
, 0};
31 static int vy_and
[4] = {0, INT_MAX
, 0, INT_MAX
};
32 static int vx
[4] = {1, 0, -1, 0};
33 static int vy
[4] = {0, 1, 0, -1};
34 static int vsign
[4] = {1,1,-1,-1};
35 static char* vname
[4] = {"right", "down", "left", "up"};
37 kdarea_t
* kdarea_new(void*data
)
40 area
->bbox
.xmin
= INT_MIN
;
41 area
->bbox
.ymin
= INT_MIN
;
42 area
->bbox
.xmax
= INT_MAX
;
43 area
->bbox
.ymax
= INT_MAX
;
48 kdtree_t
* kdtree_new()
51 tree
->root
= kdarea_new(0);
55 static inline int32_t max32(int32_t v1
, int32_t v2
) {return v1
>v2
?v1
:v2
;}
56 static inline int32_t min32(int32_t v1
, int32_t v2
) {return v1
<v2
?v1
:v2
;}
58 kdbranch_t
*kdbranch_new(int32_t xy
, kdtype_t type
)
66 kdarea_t
*kdbranch_follow(const kdbranch_t
*tree
, int32_t x
, int32_t y
)
72 follow = (x < tree->xy);
75 follow = (x > tree->xy);
78 follow = (y < tree->xy);
81 follow = (y > tree->xy);
84 return &tree->side[follow];
86 int32_t s
= x
*vx
[tree
->type
] + y
*vy
[tree
->type
];
87 int32_t v
= tree
->xy
*vsign
[tree
->type
];
89 return 0; //point is on the boundary
90 return tree
->side
[s
< v
];
93 static kdarea_list_t
* kdarea_list_new(kdarea_t
*area
)
97 b
->next
= b
->prev
= b
;
101 static kdarea_list_t
*kdarea_list_concatenate(kdarea_list_t
*l1
, kdarea_list_t
*l2
)
105 l2
->prev
->next
= l1
->next
;
106 l1
->next
->prev
= l2
->prev
;
112 static kdbbox_t
bbox_for_halfplane(int xy
, int dir
)
114 kdbbox_t b
= {INT_MIN
,INT_MIN
,INT_MAX
,INT_MAX
};
132 static kdbbox_t
intersect_bbox(const kdbbox_t
*box1
, const kdbbox_t
*box2
)
135 if(box2
->xmin
> b
.xmin
)
137 if(box2
->ymin
> b
.ymin
)
139 if(box2
->xmax
< b
.xmax
)
141 if(box2
->ymax
< b
.ymax
)
150 static void kdarea_split(kdarea_t
*area
, int xy
, int dir
,
151 int32_t x1
, int32_t y1
,
152 int32_t x2
, int32_t y2
)
155 kdbranch_t
*b
= area
->split
= kdbranch_new(xy
, dir
);
156 kdbbox_t b1
= bbox_for_halfplane(xy
, dir
);
157 kdbbox_t b2
= bbox_for_halfplane(xy
, dir
^2);
158 b
->side
[0] = kdarea_new(area
->data
);
159 b
->side
[1] = kdarea_new(area
->data
);
160 b
->side
[0]->bbox
= intersect_bbox(&area
->bbox
,&b1
);
161 b
->side
[1]->bbox
= intersect_bbox(&area
->bbox
,&b2
);
162 memcpy(b
->side
[0]->neighbors
, area
->neighbors
, sizeof(area
->neighbors
));
163 memcpy(b
->side
[1]->neighbors
, area
->neighbors
, sizeof(area
->neighbors
));
164 b
->side
[0]->neighbors
[dir
^2] = b
->side
[1];
165 b
->side
[1]->neighbors
[dir
] = b
->side
[0];
168 kdbranch_t
*split
= area
->split
;
169 kdarea_t
*first
= kdbranch_follow(split
, x1
,y1
);
170 kdarea_t
*second
= kdbranch_follow(split
, x2
,y2
);
174 /* line is on top of an already existing segment */
177 /* first point is directly on the split */
178 kdarea_split(second
, xy
, dir
, x1
,y1
, x2
,y2
);
183 /* second point is directly on the split */
184 kdarea_split(first
, xy
, dir
, x1
,y1
, x2
,y2
);
186 } else if(first
== second
) {
187 /* both points are to the same side of this split */
188 kdarea_split(first
, xy
, dir
, x1
,y1
, x2
,y2
);
191 kdarea_split(first
, xy
, dir
, x1
,y1
, x2
,y2
);
192 kdarea_split(second
, xy
, dir
, x1
,y1
, x2
,y2
);
199 static kdarea_list_t
* kdarea_filter(kdarea_t
*area
, int xy
, int dir
)
202 return kdarea_list_new(area
);
204 kdbranch_t
*branch
= area
->split
;
205 if((branch
->type
^dir
) == 0) {
206 /* both filter as well as branch point into the same direction */
207 if(xy
*vsign
[dir
] >= branch
->xy
*vsign
[dir
]) {
208 /* filter splits the primary node. We can skip the other one. */
209 return kdarea_filter(branch
->side
[0], xy
, dir
);
211 /* filter splits the secondary node. the primary node is left completely intact,
212 and returned as such */
213 kdarea_list_t
*l1
= kdarea_list_new(branch
->side
[0]);
214 kdarea_list_t
*l2
= kdarea_filter(branch
->side
[1], xy
, dir
);
215 return kdarea_list_concatenate(l1
,l2
);
217 } else if((branch
->type
^dir
) == 1) {
218 /* filter and branch point into opposite directions */
219 if(xy
*vsign
[dir
] <= branch
->xy
*vsign
[dir
]) {
220 // filter splits the secondary node. We can skip the primary node.
221 return kdarea_filter(branch
->side
[1], xy
, dir
);
223 /* filter splits the primary node. the secondary node is left completely intact,
224 and returned as such */
225 kdarea_list_t
*l1
= kdarea_filter(branch
->side
[0], xy
, dir
);
226 kdarea_list_t
*l2
= kdarea_list_new(branch
->side
[1]);
227 return kdarea_list_concatenate(l1
,l2
);
230 /* filter segment is perpendicular to the node */
231 kdarea_list_t
*l1
= kdarea_filter(branch
->side
[0], xy
, dir
);
232 kdarea_list_t
*l2
= kdarea_filter(branch
->side
[1], xy
, dir
);
233 return kdarea_list_concatenate(l1
,l2
);
238 static kdarea_t
* kdarea_find(kdarea_t
*node
, int x
, int y
)
243 node
= kdbranch_follow(node
->split
, x
,y
);
248 kdarea_t
*kdtree_find(kdtree_t
*tree
, int x
, int y
)
250 return kdarea_find(tree
->root
, x
,y
);
253 void kdarea_list_destroy(kdarea_list_t
*list
)
255 kdarea_list_t
*i
= list
;
257 kdarea_list_t
*next
= i
->next
;
263 static kdarea_list_t
* kdarea_list_add(kdarea_list_t
*l
, kdarea_t
*area
)
265 return kdarea_list_concatenate(l
,kdarea_list_new(area
));
268 static kdarea_list_t
* kdarea_all_children(kdarea_t
*area
, kdarea_list_t
*result
)
271 result
= kdarea_list_add(result
, area
);
273 result
= kdarea_all_children(area
->split
->side
[0], result
);
274 result
= kdarea_all_children(area
->split
->side
[1], result
);
279 /* return all areas that are contained in, or partly intersect, the given bounding box */
280 kdarea_list_t
* kdtree_filter(kdtree_t
*tree
, int32_t x1
, int32_t y1
, int32_t x2
, int32_t y2
, char leafs
)
282 kdarea_list_t
*result
= 0;
283 kdarea_list_t
*branches1
= kdarea_filter(tree
->root
, x2
, KD_LEFT
);
284 kdarea_list_t
*i
= branches1
;
286 kdarea_list_t
*branches2
= kdarea_filter(i
->area
, y2
, KD_UP
);
287 kdarea_list_t
*j
= branches2
;
289 kdarea_list_t
*branches3
= kdarea_filter(i
->area
, x1
, KD_RIGHT
);
290 kdarea_list_t
*k
= branches3
;
292 kdarea_list_t
*branches4
= kdarea_filter(i
->area
, y1
, KD_DOWN
);
293 kdarea_list_t
*l
= branches4
;
296 result
= kdarea_list_concatenate(result
, kdarea_all_children(l
->area
, 0));
298 } while(l
!=branches4
);
299 kdarea_list_destroy(branches4
);
301 result
= kdarea_list_concatenate(result
, l
);
304 } while(k
!=branches3
);
305 kdarea_list_destroy(branches3
);
307 } while(j
!=branches2
);
308 kdarea_list_destroy(branches2
);
310 } while(i
!=branches1
);
311 kdarea_list_destroy(branches1
);
315 static void kdtree_modify_box(kdtree_t
*tree
, int32_t x1
, int32_t y1
, int32_t x2
, int32_t y2
, void*(*f
)(void*user
,void*data
), void*user
)
317 kdarea_split(tree
->root
, x2
, KD_LEFT
, x2
,y1
, x2
,y2
);
318 kdarea_split(tree
->root
, y2
, KD_UP
, x1
,y2
, x2
,y2
);
319 kdarea_split(tree
->root
, x1
, KD_RIGHT
, x1
,y1
, x1
,y2
);
320 kdarea_split(tree
->root
, y1
, KD_DOWN
, x1
,y1
, x2
,y1
);
321 kdarea_list_t
*l
= kdtree_filter(tree
, x1
, y1
, x2
, y2
, 1);
324 l
->area
->data
= f(user
, l
->area
->data
);
327 kdarea_list_destroy(l
);
330 static void* overwrite(void*user
, void*data
)
335 void kdtree_add_box(kdtree_t
*tree
, int32_t x1
, int32_t y1
, int32_t x2
, int32_t y2
, void*data
)
337 kdtree_modify_box(tree
, x1
, y1
, x2
, y2
, overwrite
, data
);
340 kdarea_t
*kdarea_neighbor(kdarea_t
*area
, int dir
, int xy
)
361 kdarea_t
*n
= area
->neighbors
[dir
];
364 return kdarea_find(n
, x
, y
);
367 static void do_indent(int l
)
374 void kdarea_print(kdarea_t
*area
, int indent
);
375 void kdbranch_print(kdbranch_t
*branch
, int indent
)
377 do_indent(indent
);printf("[%p] branch (%s, %d)\n", branch
, vname
[branch
->type
], branch
->xy
);
378 kdbbox_t b
= bbox_for_halfplane(branch
->xy
, branch
->type
);
379 kdarea_print(branch
->side
[0], indent
+4);
380 kdarea_print(branch
->side
[1], indent
+4);
383 void kdarea_print(kdarea_t
*area
, int indent
)
387 do_indent(indent
);printf("[%p] leaf (%d,%d,%d,%d) %p (l:%p r:%p u:%p d:%p)\n", area
,
393 area
->neighbors
[KD_LEFT
],
394 area
->neighbors
[KD_RIGHT
],
395 area
->neighbors
[KD_UP
],
396 area
->neighbors
[KD_DOWN
]);
398 kdbranch_print(area
->split
, indent
+4);
402 void kdtree_print(kdtree_t
*tree
)
404 kdarea_print(tree
->root
, 0);
408 void kdbranch_destroy(kdbranch_t
*b
)
411 kdarea_destroy(b
->side
[0]);
415 kdarea_destroy(b
->side
[1]);
421 void kdarea_destroy(kdarea_t
*area
)
424 kdbranch_destroy(area
->split
);
429 void kdtree_destroy(kdtree_t
*tree
)
431 kdarea_destroy(tree
->root
);
439 assert((1^vx
[2]) < 0);
441 kdtree_t
*tree
= kdtree_new();
442 kdtree_add_box(tree
, 10,30,20,40, "hello world");
444 kdarea_t
*a
= kdtree_find(tree
, 15,35);
445 kdarea_t
*left
= kdarea_neighbor(a
, KD_LEFT
, /*y*/35);
446 kdarea_t
*right
= kdarea_neighbor(a
, KD_RIGHT
, /*y*/35);
447 kdarea_t
*up
= kdarea_neighbor(a
, KD_UP
, /*x*/15);
448 kdarea_t
*down
= kdarea_neighbor(a
, KD_DOWN
, /*x*/15);
449 kdtree_destroy(tree
);