]> gitweb.factorcode.org Git - factor.git/blob - extra/quadtrees/quadtrees.factor
fill some holes in quadtree docs, rename quadtrees:prune to prune-quadtree to avoid...
[factor.git] / extra / quadtrees / quadtrees.factor
1 ! (c) 2009 Joe Groff, see BSD license
2 USING: assocs kernel math.geometry.rect combinators accessors
3 math.vectors vectors sequences math math.points math.geometry
4 combinators.short-circuit arrays fry locals ;
5 IN: quadtrees
6
7 TUPLE: quadtree { bounds rect } point value ll lr ul ur leaf? ;
8
9 : <quadtree> ( bounds -- quadtree )
10     quadtree new
11         swap >>bounds
12         t >>leaf? ;
13
14 : rect-ll ( rect -- point ) loc>> ;
15 : rect-lr ( rect -- point ) [ loc>> ] [ width  ] bi v+x ;
16 : rect-ul ( rect -- point ) [ loc>> ] [ height ] bi v+y ;
17 : rect-ur ( rect -- point ) [ loc>> ] [ dim>>  ] bi v+  ;
18
19 : rect-center ( rect -- point ) [ loc>> ] [ dim>> 0.5 v*n ] bi v+ ; inline
20
21 : (quadrant) ( pt node -- quadrant )
22     swap [ first 0.0 < ] [ second 0.0 < ] bi
23     [ [ ll>> ] [ lr>> ] if ]
24     [ [ ul>> ] [ ur>> ] if ] if ;
25
26 : quadrant ( pt node -- quadrant )
27     [ bounds>> rect-center v- ] keep (quadrant) ;
28
29 : descend ( pt node -- pt subnode )
30     [ drop ] [ quadrant ] 2bi ; inline
31
32 :: each-quadrant ( node quot -- )
33     node ll>> quot call
34     node lr>> quot call
35     node ul>> quot call
36     node ur>> quot call ; inline
37 : map-quadrant ( node quot: ( child-node -- x ) -- array )
38     each-quadrant 4array ; inline
39
40 <PRIVATE
41
42 DEFER: (prune)
43 DEFER: insert
44 DEFER: erase
45 DEFER: at-point
46 DEFER: quadtree>alist
47 DEFER: quadtree-size
48 DEFER: node-insert
49 DEFER: in-rect*
50
51 : child-dim ( rect -- dim/2 ) dim>> 0.5 v*n ; inline
52 : ll-bounds ( rect -- rect' )
53     [   loc>>                                  ] [ child-dim ] bi <rect> ;
54 : lr-bounds ( rect -- rect' )
55     [ [ loc>> ] [ dim>> { 0.5 0.0 } v* ] bi v+ ] [ child-dim ] bi <rect> ;
56 : ul-bounds ( rect -- rect' )
57     [ [ loc>> ] [ dim>> { 0.0 0.5 } v* ] bi v+ ] [ child-dim ] bi <rect> ;
58 : ur-bounds ( rect -- rect' )
59     [ [ loc>> ] [ dim>> { 0.5 0.5 } v* ] bi v+ ] [ child-dim ] bi <rect> ;
60
61 : {quadrants} ( node -- quadrants )
62     { [ ll>> ] [ lr>> ] [ ul>> ] [ ur>> ] } cleave 4array ;
63
64 : add-subnodes ( node -- node )
65     dup bounds>> {
66         [ ll-bounds <quadtree> >>ll ]
67         [ lr-bounds <quadtree> >>lr ]
68         [ ul-bounds <quadtree> >>ul ]
69         [ ur-bounds <quadtree> >>ur ]
70     } cleave
71     f >>leaf? ;
72
73 : split-leaf ( value point leaf -- )
74     add-subnodes
75     [ value>> ] [ point>> ] [ ] tri
76     [ node-insert ] [ node-insert ] bi ;
77
78 : leaf-replaceable? ( pt leaf -- ? ) point>> { [ nip not ] [ = ] } 2|| ;
79 : leaf-insert ( value point leaf -- )
80     2dup leaf-replaceable?
81     [ [ (>>point) ] [ (>>value) ] bi ]
82     [ split-leaf ] if ;
83
84 : node-insert ( value point node -- )
85     descend insert ;
86
87 : insert ( value point tree -- )
88     dup leaf?>> [ leaf-insert ] [ node-insert ] if ;
89
90 : leaf-at-point ( point leaf -- value/f ? )
91     tuck point>> = [ value>> t ] [ drop f f ] if ;
92
93 : node-at-point ( point node -- value/f ? )
94     descend at-point ;
95
96 : at-point ( point tree -- value/f ? )
97     dup leaf?>> [ leaf-at-point ] [ node-at-point ] if ;
98
99 : (node-in-rect*) ( values rect node -- values )
100     2dup bounds>> intersects? [ in-rect* ] [ 2drop ] if ;
101 : node-in-rect* ( values rect node -- values )
102     [ (node-in-rect*) ] with each-quadrant ;
103
104 : leaf-in-rect* ( values rect leaf -- values ) 
105     tuck { [ nip point>> ] [ point>> swap intersects? ] } 2&&
106     [ value>> over push ] [ drop ] if ;
107
108 : in-rect* ( values rect tree -- values )
109     dup leaf?>> [ leaf-in-rect* ] [ node-in-rect* ] if ;
110
111 : leaf-erase ( point leaf -- )
112     tuck point>> = [ f >>point f >>value ] when drop ;
113
114 : node-erase ( point node -- )
115     descend erase ;
116
117 : erase ( point tree -- )
118     dup leaf?>> [ leaf-erase ] [ node-erase ] if ;
119
120 : (?leaf) ( quadrant -- {point,value}/f )
121     dup point>> [ swap value>> 2array ] [ drop f ] if* ;
122 : ?leaf ( quadrants -- {point,value}/f )
123     [ (?leaf) ] map sift dup length {
124         { 1 [ first ] }
125         { 0 [ drop { f f } ] }
126         [ 2drop f ]
127     } case ;
128
129 : collapseable? ( node -- {point,value}/f )
130     {quadrants} { [ [ leaf?>> ] all? ] [ ?leaf ] } 1&& ;
131
132 : remove-subnodes ( node -- leaf ) f >>ll f >>lr f >>ul f >>ur t >>leaf? ;
133
134 : collapse ( node {point,value} -- )
135     first2 [ >>point ] [ >>value ] bi* remove-subnodes drop ;
136
137 : node-prune ( node -- )
138     [ [ (prune) ] each-quadrant ] [ ] [ collapseable? ] tri
139     [ collapse ] [ drop ] if* ;
140
141 : (prune) ( tree -- )
142     dup leaf?>> [ drop ] [ node-prune ] if ;
143
144 : leaf>alist ( leaf -- alist )
145     dup point>> [ [ point>> ] [ value>> ] bi 2array 1array ] [ drop { } ] if ;
146
147 : node>alist ( node -- alist ) [ quadtree>alist ] map-quadrant concat ;
148
149 : quadtree>alist ( tree -- assoc )
150     dup leaf?>> [ leaf>alist ] [ node>alist ] if ;
151
152 : leaf-size ( leaf -- count )
153     point>> [ 1 ] [ 0 ] if ;
154 : node-size ( node -- count )
155     0 swap [ quadtree-size + ] each-quadrant ; 
156     
157 : quadtree-size ( tree -- count )
158     dup leaf?>> [ leaf-size ] [ node-size ] if ;
159
160 : leaf= ( a b -- ? ) [ [ point>> ] [ value>> ] bi 2array ] bi@ = ;
161
162 : node= ( a b -- ? ) [ {quadrants} ] bi@ = ;
163
164 : (tree=) ( a b -- ? ) dup leaf?>> [ leaf= ] [ node= ] if ;
165
166 : tree= ( a b -- ? )
167     2dup [ leaf?>> ] bi@ = [ (tree=) ] [ 2drop f ] if ;
168
169 PRIVATE>
170
171 : prune-quadtree ( tree -- tree ) [ (prune) ] keep ;
172
173 : in-rect ( tree rect -- values )
174     [ 16 <vector> ] 2dip in-rect* ;
175
176 M: quadtree equal? ( a b -- ? )
177     over quadtree? [ tree= ] [ 2drop f ] if ;
178
179 INSTANCE: quadtree assoc
180
181 M: quadtree at* ( key assoc -- value/f ? ) at-point ;
182 M: quadtree assoc-size ( assoc -- n ) quadtree-size ;
183 M: quadtree >alist ( assoc -- alist ) quadtree>alist ;
184 M: quadtree set-at ( value key assoc -- ) insert ;
185 M: quadtree delete-at ( key assoc -- ) erase ;
186 M: quadtree clear-assoc ( assoc -- )
187     t >>leaf?
188     f >>point
189     f >>value
190     drop ;
191