aboutsummaryrefslogtreecommitdiff
path: root/Spear/Math/Octree.hs
diff options
context:
space:
mode:
Diffstat (limited to 'Spear/Math/Octree.hs')
-rw-r--r--Spear/Math/Octree.hs456
1 files changed, 228 insertions, 228 deletions
diff --git a/Spear/Math/Octree.hs b/Spear/Math/Octree.hs
index f5538b4..6c22468 100644
--- a/Spear/Math/Octree.hs
+++ b/Spear/Math/Octree.hs
@@ -1,228 +1,228 @@
1module Spear.Math.Octree 1module Spear.Math.Octree
2( 2(
3 Octree 3 Octree
4, makeOctree 4, makeOctree
5, clone 5, clone
6, Spear.Math.Octree.insert 6, Spear.Math.Octree.insert
7, Spear.Math.Octree.map 7, Spear.Math.Octree.map
8, gmap 8, gmap
9) 9)
10where 10where
11 11
12import Spear.Math.AABB 12import Spear.Math.AABB
13import Spear.Math.Collision 13import Spear.Math.Collision
14import Spear.Math.Vector 14import Spear.Math.Vector
15 15
16import Control.Applicative ((<*>)) 16import Control.Applicative ((<*>))
17import Data.List 17import Data.List
18import Data.Functor 18import Data.Functor
19import Data.Monoid 19import Data.Monoid
20import qualified Data.Foldable as F 20import qualified Data.Foldable as F
21 21
22-- | An octree. 22-- | An octree.
23data Octree e 23data Octree e
24 = Octree 24 = Octree
25 { root :: !AABB2 25 { root :: !AABB2
26 , ents :: ![e] 26 , ents :: ![e]
27 , c1 :: !(Octree e) 27 , c1 :: !(Octree e)
28 , c2 :: !(Octree e) 28 , c2 :: !(Octree e)
29 , c3 :: !(Octree e) 29 , c3 :: !(Octree e)
30 , c4 :: !(Octree e) 30 , c4 :: !(Octree e)
31 , c5 :: !(Octree e) 31 , c5 :: !(Octree e)
32 , c6 :: !(Octree e) 32 , c6 :: !(Octree e)
33 , c7 :: !(Octree e) 33 , c7 :: !(Octree e)
34 , c8 :: !(Octree e) 34 , c8 :: !(Octree e)
35 } 35 }
36 | 36 |
37 Leaf 37 Leaf
38 { root :: !AABB2 38 { root :: !AABB2
39 , ents :: ![e] 39 , ents :: ![e]
40 } 40 }
41 41
42-- | Construct an octree using the specified AABB as the root and having the specified depth. 42-- | Construct an octree using the specified AABB as the root and having the specified depth.
43makeOctree :: Int -> AABB2 -> Octree e 43makeOctree :: Int -> AABB2 -> Octree e
44makeOctree d root@(AABB2 min max) 44makeOctree d root@(AABB2 min max)
45 | d == 0 = Leaf root [] 45 | d == 0 = Leaf root []
46 | otherwise = Octree root [] c1 c2 c3 c4 c5 c6 c7 c8 46 | otherwise = Octree root [] c1 c2 c3 c4 c5 c6 c7 c8
47 where 47 where
48 boxes = subdivide root 48 boxes = subdivide root
49 c1 = makeOctree (d-1) $ boxes !! 0 49 c1 = makeOctree (d-1) $ boxes !! 0
50 c2 = makeOctree (d-1) $ boxes !! 1 50 c2 = makeOctree (d-1) $ boxes !! 1
51 c3 = makeOctree (d-1) $ boxes !! 2 51 c3 = makeOctree (d-1) $ boxes !! 2
52 c4 = makeOctree (d-1) $ boxes !! 3 52 c4 = makeOctree (d-1) $ boxes !! 3
53 c5 = makeOctree (d-1) $ boxes !! 4 53 c5 = makeOctree (d-1) $ boxes !! 4
54 c6 = makeOctree (d-1) $ boxes !! 5 54 c6 = makeOctree (d-1) $ boxes !! 5
55 c7 = makeOctree (d-1) $ boxes !! 6 55 c7 = makeOctree (d-1) $ boxes !! 6
56 c8 = makeOctree (d-1) $ boxes !! 7 56 c8 = makeOctree (d-1) $ boxes !! 7
57 57
58subdivide :: AABB2 -> [AABB2] 58subdivide :: AABB2 -> [AABB2]
59subdivide (AABB2 min max) = [a1, a2, a3, a4, a5, a6, a7, a8] 59subdivide (AABB2 min max) = [a1, a2, a3, a4, a5, a6, a7, a8]
60 where 60 where
61 v = (max-min) / 2 61 v = (max-min) / 2
62 c = vec2 (x min + x v) (y min + y v) 62 c = vec2 (x min + x v) (y min + y v)
63 a1 = AABB2 min c 63 a1 = AABB2 min c
64 a2 = AABB2 ( vec2 (x min) (y min)) ( vec2 (x c) (y c) ) 64 a2 = AABB2 ( vec2 (x min) (y min)) ( vec2 (x c) (y c) )
65 a3 = AABB2 ( vec2 (x min) (y c) ) ( vec2 (x c) (y max)) 65 a3 = AABB2 ( vec2 (x min) (y c) ) ( vec2 (x c) (y max))
66 a4 = AABB2 ( vec2 (x min) (y c) ) ( vec2 (x c) (y max)) 66 a4 = AABB2 ( vec2 (x min) (y c) ) ( vec2 (x c) (y max))
67 a5 = AABB2 ( vec2 (x c) (y min)) ( vec2 (x max) (y c) ) 67 a5 = AABB2 ( vec2 (x c) (y min)) ( vec2 (x max) (y c) )
68 a6 = AABB2 ( vec2 (x c) (y min)) ( vec2 (x max) (y c) ) 68 a6 = AABB2 ( vec2 (x c) (y min)) ( vec2 (x max) (y c) )
69 a7 = AABB2 ( vec2 (x c) (y c) ) ( vec2 (x max) (y max)) 69 a7 = AABB2 ( vec2 (x c) (y c) ) ( vec2 (x max) (y max))
70 a8 = AABB2 c max 70 a8 = AABB2 c max
71 71
72-- | Clone the structure of the octree. The new octree has no entities. 72-- | Clone the structure of the octree. The new octree has no entities.
73clone :: Octree e -> Octree e 73clone :: Octree e -> Octree e
74clone (Leaf root ents) = Leaf root [] 74clone (Leaf root ents) = Leaf root []
75clone (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = Octree root [] c1' c2' c3' c4' c5' c6' c7' c8' 75clone (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = Octree root [] c1' c2' c3' c4' c5' c6' c7' c8'
76 where 76 where
77 c1' = clone c1 77 c1' = clone c1
78 c2' = clone c2 78 c2' = clone c2
79 c3' = clone c3 79 c3' = clone c3
80 c4' = clone c4 80 c4' = clone c4
81 c5' = clone c5 81 c5' = clone c5
82 c6' = clone c6 82 c6' = clone c6
83 c7' = clone c7 83 c7' = clone c7
84 c8' = clone c8 84 c8' = clone c8
85 85
86keep :: (e -> AABB2 -> CollisionType) -> AABB2 -> e -> Bool 86keep :: (e -> AABB2 -> CollisionType) -> AABB2 -> e -> Bool
87keep testAABB2 aabb e = test == FullyContainedBy 87keep testAABB2 aabb e = test == FullyContainedBy
88 where test = e `testAABB2` aabb 88 where test = e `testAABB2` aabb
89 89
90-- | Insert a list of entities into the octree. 90-- | Insert a list of entities into the octree.
91insert :: (e -> AABB2 -> CollisionType) -> Octree e -> [e] -> Octree e 91insert :: (e -> AABB2 -> CollisionType) -> Octree e -> [e] -> Octree e
92insert testAABB2 octree es = octree' where (octree', _) = insert' testAABB2 es octree 92insert testAABB2 octree es = octree' where (octree', _) = insert' testAABB2 es octree
93 93
94insert' :: (e -> AABB2 -> CollisionType) -> [e] -> Octree e -> (Octree e, [e]) 94insert' :: (e -> AABB2 -> CollisionType) -> [e] -> Octree e -> (Octree e, [e])
95 95
96insert' testAABB2 es (Leaf root ents) = (Leaf root ents', outliers) 96insert' testAABB2 es (Leaf root ents) = (Leaf root ents', outliers)
97 where 97 where
98 ents' = ents ++ ents_kept 98 ents' = ents ++ ents_kept
99 ents_kept = filter (keep testAABB2 root) es 99 ents_kept = filter (keep testAABB2 root) es
100 outliers = filter (not . keep testAABB2 root) es 100 outliers = filter (not . keep testAABB2 root) es
101 101
102insert' testAABB2 es (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = 102insert' testAABB2 es (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) =
103 (Octree root ents' c1' c2' c3' c4' c5' c6' c7' c8', outliers) 103 (Octree root ents' c1' c2' c3' c4' c5' c6' c7' c8', outliers)
104 where 104 where
105 ents' = ents ++ ents_kept 105 ents' = ents ++ ents_kept
106 new_ents = es ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8 106 new_ents = es ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8
107 ents_kept = filter (keep testAABB2 root) new_ents 107 ents_kept = filter (keep testAABB2 root) new_ents
108 outliers = filter (not . keep testAABB2 root) new_ents 108 outliers = filter (not . keep testAABB2 root) new_ents
109 (c1', ents1) = insert' testAABB2 es c1 109 (c1', ents1) = insert' testAABB2 es c1
110 (c2', ents2) = insert' testAABB2 es c2 110 (c2', ents2) = insert' testAABB2 es c2
111 (c3', ents3) = insert' testAABB2 es c3 111 (c3', ents3) = insert' testAABB2 es c3
112 (c4', ents4) = insert' testAABB2 es c4 112 (c4', ents4) = insert' testAABB2 es c4
113 (c5', ents5) = insert' testAABB2 es c5 113 (c5', ents5) = insert' testAABB2 es c5
114 (c6', ents6) = insert' testAABB2 es c6 114 (c6', ents6) = insert' testAABB2 es c6
115 (c7', ents7) = insert' testAABB2 es c7 115 (c7', ents7) = insert' testAABB2 es c7
116 (c8', ents8) = insert' testAABB2 es c8 116 (c8', ents8) = insert' testAABB2 es c8
117 117
118-- | Extract all entities from the octree. The resulting octree has no entities. 118-- | Extract all entities from the octree. The resulting octree has no entities.
119extract :: Octree e -> (Octree e, [e]) 119extract :: Octree e -> (Octree e, [e])
120extract (Leaf root ents) = (Leaf root [], ents) 120extract (Leaf root ents) = (Leaf root [], ents)
121extract (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = (Octree root [] c1' c2' c3' c4' c5' c6' c7' c8', ents') 121extract (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = (Octree root [] c1' c2' c3' c4' c5' c6' c7' c8', ents')
122 where 122 where
123 (c1', ents1) = extract c1 123 (c1', ents1) = extract c1
124 (c2', ents2) = extract c2 124 (c2', ents2) = extract c2
125 (c3', ents3) = extract c3 125 (c3', ents3) = extract c3
126 (c4', ents4) = extract c4 126 (c4', ents4) = extract c4
127 (c5', ents5) = extract c5 127 (c5', ents5) = extract c5
128 (c6', ents6) = extract c6 128 (c6', ents6) = extract c6
129 (c7', ents7) = extract c7 129 (c7', ents7) = extract c7
130 (c8', ents8) = extract c8 130 (c8', ents8) = extract c8
131 ents' = ents ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8 131 ents' = ents ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8
132 132
133-- | Apply the given function to the entities in the octree. 133-- | Apply the given function to the entities in the octree.
134-- 134--
135-- Entities that break out of their cell are reallocated appropriately. 135-- Entities that break out of their cell are reallocated appropriately.
136map :: (e -> AABB2 -> CollisionType) -> (e -> e) -> Octree e -> Octree e 136map :: (e -> AABB2 -> CollisionType) -> (e -> e) -> Octree e -> Octree e
137map testAABB2 f o = 137map testAABB2 f o =
138 let (o', outliers) = map' testAABB2 f o 138 let (o', outliers) = map' testAABB2 f o
139 in Spear.Math.Octree.insert testAABB2 o' outliers 139 in Spear.Math.Octree.insert testAABB2 o' outliers
140 140
141map' :: (e -> AABB2 -> CollisionType) -> (e -> e) -> Octree e -> (Octree e, [e]) 141map' :: (e -> AABB2 -> CollisionType) -> (e -> e) -> Octree e -> (Octree e, [e])
142 142
143map' testAABB2 f (Leaf root ents) = (Leaf root ents_kept, outliers) 143map' testAABB2 f (Leaf root ents) = (Leaf root ents_kept, outliers)
144 where 144 where
145 ents' = fmap f ents 145 ents' = fmap f ents
146 ents_kept = filter (keep testAABB2 root) ents' 146 ents_kept = filter (keep testAABB2 root) ents'
147 outliers = filter (not . keep testAABB2 root) ents' 147 outliers = filter (not . keep testAABB2 root) ents'
148 148
149map' testAABB2 f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = 149map' testAABB2 f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) =
150 (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers) 150 (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers)
151 where 151 where
152 ents' = (fmap f ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8 152 ents' = (fmap f ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8
153 ents_kept = filter (keep testAABB2 root) ents' 153 ents_kept = filter (keep testAABB2 root) ents'
154 outliers = filter (not . keep testAABB2 root) ents' 154 outliers = filter (not . keep testAABB2 root) ents'
155 (c1', out1) = map' testAABB2 f c1 155 (c1', out1) = map' testAABB2 f c1
156 (c2', out2) = map' testAABB2 f c2 156 (c2', out2) = map' testAABB2 f c2
157 (c3', out3) = map' testAABB2 f c3 157 (c3', out3) = map' testAABB2 f c3
158 (c4', out4) = map' testAABB2 f c4 158 (c4', out4) = map' testAABB2 f c4
159 (c5', out5) = map' testAABB2 f c5 159 (c5', out5) = map' testAABB2 f c5
160 (c6', out6) = map' testAABB2 f c6 160 (c6', out6) = map' testAABB2 f c6
161 (c7', out7) = map' testAABB2 f c7 161 (c7', out7) = map' testAABB2 f c7
162 (c8', out8) = map' testAABB2 f c8 162 (c8', out8) = map' testAABB2 f c8
163 163
164 164
165-- | Apply a function to the entity groups in the octree. 165-- | Apply a function to the entity groups in the octree.
166-- 166--
167-- Entities that break out of their cell are reallocated appropriately. 167-- Entities that break out of their cell are reallocated appropriately.
168gmap :: (e -> AABB2 -> CollisionType) -> (e -> e -> e) -> Octree e -> Octree e 168gmap :: (e -> AABB2 -> CollisionType) -> (e -> e -> e) -> Octree e -> Octree e
169gmap testAABB2 f o = 169gmap testAABB2 f o =
170 let (o', outliers) = gmap' testAABB2 f o 170 let (o', outliers) = gmap' testAABB2 f o
171 in Spear.Math.Octree.insert testAABB2 o' outliers 171 in Spear.Math.Octree.insert testAABB2 o' outliers
172 172
173gmap' :: (e -> AABB2 -> CollisionType) -> (e -> e -> e) -> Octree e -> (Octree e, [e]) 173gmap' :: (e -> AABB2 -> CollisionType) -> (e -> e -> e) -> Octree e -> (Octree e, [e])
174 174
175gmap' testAABB2 f (Leaf root ents) = (Leaf root ents_kept, outliers) 175gmap' testAABB2 f (Leaf root ents) = (Leaf root ents_kept, outliers)
176 where 176 where
177 ents' = f <$> ents <*> ents 177 ents' = f <$> ents <*> ents
178 ents_kept = filter (keep testAABB2 root) ents' 178 ents_kept = filter (keep testAABB2 root) ents'
179 outliers = filter (not . keep testAABB2 root) ents' 179 outliers = filter (not . keep testAABB2 root) ents'
180 180
181gmap' testAABB2 f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = 181gmap' testAABB2 f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) =
182 (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers) 182 (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers)
183 where 183 where
184 ents'= (f <$> ents <*> ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8 184 ents'= (f <$> ents <*> ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8
185 ents_kept = filter (keep testAABB2 root) ents' 185 ents_kept = filter (keep testAABB2 root) ents'
186 outliers = filter (not . keep testAABB2 root) ents' 186 outliers = filter (not . keep testAABB2 root) ents'
187 (c1', out1) = gmap' testAABB2 f c1 187 (c1', out1) = gmap' testAABB2 f c1
188 (c2', out2) = gmap' testAABB2 f c2 188 (c2', out2) = gmap' testAABB2 f c2
189 (c3', out3) = gmap' testAABB2 f c3 189 (c3', out3) = gmap' testAABB2 f c3
190 (c4', out4) = gmap' testAABB2 f c4 190 (c4', out4) = gmap' testAABB2 f c4
191 (c5', out5) = gmap' testAABB2 f c5 191 (c5', out5) = gmap' testAABB2 f c5
192 (c6', out6) = gmap' testAABB2 f c6 192 (c6', out6) = gmap' testAABB2 f c6
193 (c7', out7) = gmap' testAABB2 f c7 193 (c7', out7) = gmap' testAABB2 f c7
194 (c8', out8) = gmap' testAABB2 f c8 194 (c8', out8) = gmap' testAABB2 f c8
195 195
196instance Functor Octree where 196instance Functor Octree where
197 197
198 fmap f (Leaf root ents) = Leaf root $ fmap f ents 198 fmap f (Leaf root ents) = Leaf root $ fmap f ents
199 199
200 fmap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = 200 fmap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) =
201 Octree root (fmap f ents) c1' c2' c3' c4' c5' c6' c7' c8' 201 Octree root (fmap f ents) c1' c2' c3' c4' c5' c6' c7' c8'
202 where 202 where
203 c1' = fmap f c1 203 c1' = fmap f c1
204 c2' = fmap f c2 204 c2' = fmap f c2
205 c3' = fmap f c3 205 c3' = fmap f c3
206 c4' = fmap f c4 206 c4' = fmap f c4
207 c5' = fmap f c5 207 c5' = fmap f c5
208 c6' = fmap f c6 208 c6' = fmap f c6
209 c7' = fmap f c7 209 c7' = fmap f c7
210 c8' = fmap f c8 210 c8' = fmap f c8
211 211
212instance F.Foldable Octree where 212instance F.Foldable Octree where
213 213
214 foldMap f (Leaf root ents) = mconcat . fmap f $ ents 214 foldMap f (Leaf root ents) = mconcat . fmap f $ ents
215 215
216 foldMap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = 216 foldMap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) =
217 mconcat (fmap f ents) `mappend` 217 mconcat (fmap f ents) `mappend`
218 c1' `mappend` c2' `mappend` c3' `mappend` c4' `mappend` 218 c1' `mappend` c2' `mappend` c3' `mappend` c4' `mappend`
219 c5' `mappend` c6' `mappend` c7' `mappend` c8' 219 c5' `mappend` c6' `mappend` c7' `mappend` c8'
220 where 220 where
221 c1' = F.foldMap f c1 221 c1' = F.foldMap f c1
222 c2' = F.foldMap f c2 222 c2' = F.foldMap f c2
223 c3' = F.foldMap f c3 223 c3' = F.foldMap f c3
224 c4' = F.foldMap f c4 224 c4' = F.foldMap f c4
225 c5' = F.foldMap f c5 225 c5' = F.foldMap f c5
226 c6' = F.foldMap f c6 226 c6' = F.foldMap f c6
227 c7' = F.foldMap f c7 227 c7' = F.foldMap f c7
228 c8' = F.foldMap f c8 228 c8' = F.foldMap f c8