diff options
Diffstat (limited to 'Spear/Math/Octree.hs')
| -rw-r--r-- | Spear/Math/Octree.hs | 284 |
1 files changed, 0 insertions, 284 deletions
diff --git a/Spear/Math/Octree.hs b/Spear/Math/Octree.hs deleted file mode 100644 index 15f7dde..0000000 --- a/Spear/Math/Octree.hs +++ /dev/null | |||
| @@ -1,284 +0,0 @@ | |||
| 1 | module Spear.Math.Octree | ||
| 2 | ( | ||
| 3 | Octree | ||
| 4 | , makeOctree | ||
| 5 | , clone | ||
| 6 | , Spear.Math.Octree.insert | ||
| 7 | , insertl | ||
| 8 | , Spear.Math.Octree.map | ||
| 9 | , gmap | ||
| 10 | , population | ||
| 11 | ) | ||
| 12 | where | ||
| 13 | |||
| 14 | import Spear.Collision.Types | ||
| 15 | import Spear.Math.AABB | ||
| 16 | import Spear.Math.Vector3 | ||
| 17 | |||
| 18 | import Control.Applicative ((<*>)) | ||
| 19 | import Data.List | ||
| 20 | import Data.Functor | ||
| 21 | import Data.Monoid | ||
| 22 | import qualified Data.Foldable as F | ||
| 23 | |||
| 24 | |||
| 25 | -- | Represents an Octree. | ||
| 26 | data Octree e | ||
| 27 | = Octree | ||
| 28 | { | ||
| 29 | root :: !AABB, | ||
| 30 | ents :: ![e], | ||
| 31 | c1 :: !(Octree e), | ||
| 32 | c2 :: !(Octree e), | ||
| 33 | c3 :: !(Octree e), | ||
| 34 | c4 :: !(Octree e), | ||
| 35 | c5 :: !(Octree e), | ||
| 36 | c6 :: !(Octree e), | ||
| 37 | c7 :: !(Octree e), | ||
| 38 | c8 :: !(Octree e) | ||
| 39 | } | ||
| 40 | | | ||
| 41 | Leaf | ||
| 42 | { | ||
| 43 | root :: !AABB, | ||
| 44 | ents :: ![e] | ||
| 45 | } | ||
| 46 | |||
| 47 | |||
| 48 | -- | Builds an Octree using the specified AABB as the root and having the specified depth. | ||
| 49 | makeOctree :: Int -> AABB -> Octree e | ||
| 50 | makeOctree d root@(AABB min max) | ||
| 51 | | d == 0 = Leaf root [] | ||
| 52 | | otherwise = Octree root [] c1 c2 c3 c4 c5 c6 c7 c8 | ||
| 53 | where | ||
| 54 | boxes = subdivide root | ||
| 55 | c1 = makeOctree (d-1) $ boxes !! 0 | ||
| 56 | c2 = makeOctree (d-1) $ boxes !! 1 | ||
| 57 | c3 = makeOctree (d-1) $ boxes !! 2 | ||
| 58 | c4 = makeOctree (d-1) $ boxes !! 3 | ||
| 59 | c5 = makeOctree (d-1) $ boxes !! 4 | ||
| 60 | c6 = makeOctree (d-1) $ boxes !! 5 | ||
| 61 | c7 = makeOctree (d-1) $ boxes !! 6 | ||
| 62 | c8 = makeOctree (d-1) $ boxes !! 7 | ||
| 63 | |||
| 64 | |||
| 65 | subdivide :: AABB -> [AABB] | ||
| 66 | subdivide (AABB min max) = [a1, a2, a3, a4, a5, a6, a7, a8] | ||
| 67 | where | ||
| 68 | v = (max-min) / 2 | ||
| 69 | c = vec3 (x min + x v) (y min + y v) (z min + z v) | ||
| 70 | a1 = AABB min c | ||
| 71 | a2 = AABB ( vec3 (x min) (y min) (z c) ) ( vec3 (x c) (y c) (z max) ) | ||
| 72 | a3 = AABB ( vec3 (x min) (y c) (z min) ) ( vec3 (x c) (y max) (z c) ) | ||
| 73 | a4 = AABB ( vec3 (x min) (y c) (z c) ) ( vec3 (x c) (y max) (z max) ) | ||
| 74 | a5 = AABB ( vec3 (x c) (y min) (z min) ) ( vec3 (x max) (y c) (z c) ) | ||
| 75 | a6 = AABB ( vec3 (x c) (y min) (z c) ) ( vec3 (x max) (y c) (z max) ) | ||
| 76 | a7 = AABB ( vec3 (x c) (y c) (z min) ) ( vec3 (x max) (y max) (z c) ) | ||
| 77 | a8 = AABB c max | ||
| 78 | |||
| 79 | |||
| 80 | -- | Clones the structure of an octree. The new octree has no entities. | ||
| 81 | clone :: Octree e -> Octree e | ||
| 82 | clone (Leaf root ents) = Leaf root [] | ||
| 83 | clone (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = Octree root [] c1' c2' c3' c4' c5' c6' c7' c8' | ||
| 84 | where | ||
| 85 | c1' = clone c1 | ||
| 86 | c2' = clone c2 | ||
| 87 | c3' = clone c3 | ||
| 88 | c4' = clone c4 | ||
| 89 | c5' = clone c5 | ||
| 90 | c6' = clone c6 | ||
| 91 | c7' = clone c7 | ||
| 92 | c8' = clone c8 | ||
| 93 | |||
| 94 | |||
| 95 | keep :: (e -> AABB -> CollisionType) -> AABB -> e -> Bool | ||
| 96 | keep testAABB aabb e = test == FullyContainedBy | ||
| 97 | where test = e `testAABB` aabb | ||
| 98 | |||
| 99 | |||
| 100 | -- | Inserts an entity into the given octree. | ||
| 101 | insert :: (e -> AABB -> CollisionType) -> Octree e -> e -> Octree e | ||
| 102 | insert testAABB octree e = octree' where (octree', _) = insert' testAABB e octree | ||
| 103 | |||
| 104 | |||
| 105 | insert' :: (e -> AABB -> CollisionType) -> e -> Octree e -> (Octree e, Bool) | ||
| 106 | |||
| 107 | |||
| 108 | insert' testAABB e l@(Leaf root ents) | ||
| 109 | | test == True = (Leaf root (e:ents), True) | ||
| 110 | | otherwise = (l, False) | ||
| 111 | where | ||
| 112 | test = keep testAABB root e | ||
| 113 | |||
| 114 | |||
| 115 | insert' testAABB e o@(Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) | ||
| 116 | | test == False = (o, False) | ||
| 117 | | otherwise = | ||
| 118 | if isContainedInChild then (Octree root ents c1' c2' c3' c4' c5' c6' c7' c8', True) | ||
| 119 | else (Octree root (e:ents) c1 c2 c3 c4 c5 c6 c7 c8, True) | ||
| 120 | where | ||
| 121 | children = [c1,c2,c3,c4,c5,c6,c7,c8] | ||
| 122 | test = keep testAABB root e | ||
| 123 | descend = fmap (Spear.Math.Octree.insert' testAABB e) children | ||
| 124 | (children', results) = unzip descend | ||
| 125 | isContainedInChild = or results | ||
| 126 | c1' = children' !! 0 | ||
| 127 | c2' = children' !! 1 | ||
| 128 | c3' = children' !! 2 | ||
| 129 | c4' = children' !! 3 | ||
| 130 | c5' = children' !! 4 | ||
| 131 | c6' = children' !! 5 | ||
| 132 | c7' = children' !! 6 | ||
| 133 | c8' = children' !! 7 | ||
| 134 | |||
| 135 | |||
| 136 | -- | Inserts a list of entities into the given octree. | ||
| 137 | insertl :: (e -> AABB -> CollisionType) -> Octree e -> [e] -> Octree e | ||
| 138 | insertl testAABB octree es = octree' where (octree', _) = insertl' testAABB es octree | ||
| 139 | |||
| 140 | |||
| 141 | insertl' :: (e -> AABB -> CollisionType) -> [e] -> Octree e -> (Octree e, [e]) | ||
| 142 | |||
| 143 | insertl' testAABB es (Leaf root ents) = (Leaf root ents', outliers) | ||
| 144 | where | ||
| 145 | ents' = ents ++ ents_kept | ||
| 146 | ents_kept = filter (keep testAABB root) es | ||
| 147 | outliers = filter (not . keep testAABB root) es | ||
| 148 | |||
| 149 | insertl' testAABB es (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = | ||
| 150 | (Octree root ents' c1' c2' c3' c4' c5' c6' c7' c8', outliers) | ||
| 151 | where | ||
| 152 | ents' = ents ++ ents_kept | ||
| 153 | new_ents = es ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8 | ||
| 154 | ents_kept = filter (keep testAABB root) new_ents | ||
| 155 | outliers = filter (not . keep testAABB root) new_ents | ||
| 156 | (c1', ents1) = insertl' testAABB es c1 | ||
| 157 | (c2', ents2) = insertl' testAABB es c2 | ||
| 158 | (c3', ents3) = insertl' testAABB es c3 | ||
| 159 | (c4', ents4) = insertl' testAABB es c4 | ||
| 160 | (c5', ents5) = insertl' testAABB es c5 | ||
| 161 | (c6', ents6) = insertl' testAABB es c6 | ||
| 162 | (c7', ents7) = insertl' testAABB es c7 | ||
| 163 | (c8', ents8) = insertl' testAABB es c8 | ||
| 164 | |||
| 165 | |||
| 166 | -- | Extracts all entities from an octree. The resulting octree has no entities. | ||
| 167 | extract :: Octree e -> (Octree e, [e]) | ||
| 168 | extract (Leaf root ents) = (Leaf root [], ents) | ||
| 169 | extract (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = (Octree root [] c1' c2' c3' c4' c5' c6' c7' c8', ents') | ||
| 170 | where | ||
| 171 | (c1', ents1) = extract c1 | ||
| 172 | (c2', ents2) = extract c2 | ||
| 173 | (c3', ents3) = extract c3 | ||
| 174 | (c4', ents4) = extract c4 | ||
| 175 | (c5', ents5) = extract c5 | ||
| 176 | (c6', ents6) = extract c6 | ||
| 177 | (c7', ents7) = extract c7 | ||
| 178 | (c8', ents8) = extract c8 | ||
| 179 | ents' = ents ++ ents1 ++ ents2 ++ ents3 ++ ents4 ++ ents5 ++ ents6 ++ ents7 ++ ents8 | ||
| 180 | |||
| 181 | |||
| 182 | -- | Applies the given function to the entities in the octree. | ||
| 183 | -- Entities that break out of their cell are reallocated appropriately. | ||
| 184 | map :: (e -> AABB -> CollisionType) -> (e -> e) -> Octree e -> Octree e | ||
| 185 | map testAABB f o = let (o', outliers) = map' testAABB f o in insertl testAABB o' outliers | ||
| 186 | |||
| 187 | |||
| 188 | map' :: (e -> AABB -> CollisionType) -> (e -> e) -> Octree e -> (Octree e, [e]) | ||
| 189 | |||
| 190 | |||
| 191 | map' testAABB f (Leaf root ents) = (Leaf root ents_kept, outliers) | ||
| 192 | where | ||
| 193 | ents' = fmap f ents | ||
| 194 | ents_kept = filter (keep testAABB root) ents' | ||
| 195 | outliers = filter (not . keep testAABB root) ents' | ||
| 196 | |||
| 197 | |||
| 198 | map' testAABB f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = | ||
| 199 | (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers) | ||
| 200 | where | ||
| 201 | ents' = (fmap f ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8 | ||
| 202 | ents_kept = filter (keep testAABB root) ents' | ||
| 203 | outliers = filter (not . keep testAABB root) ents' | ||
| 204 | (c1', out1) = map' testAABB f c1 | ||
| 205 | (c2', out2) = map' testAABB f c2 | ||
| 206 | (c3', out3) = map' testAABB f c3 | ||
| 207 | (c4', out4) = map' testAABB f c4 | ||
| 208 | (c5', out5) = map' testAABB f c5 | ||
| 209 | (c6', out6) = map' testAABB f c6 | ||
| 210 | (c7', out7) = map' testAABB f c7 | ||
| 211 | (c8', out8) = map' testAABB f c8 | ||
| 212 | |||
| 213 | |||
| 214 | -- | Applies a function to the entity groups in the octree. | ||
| 215 | -- Entities that break out of their cell are reallocated appropriately. | ||
| 216 | gmap :: (e -> AABB -> CollisionType) -> (e -> e -> e) -> Octree e -> Octree e | ||
| 217 | gmap testAABB f o = let (o', outliers) = gmap' testAABB f o in insertl testAABB o' outliers | ||
| 218 | |||
| 219 | |||
| 220 | gmap' :: (e -> AABB -> CollisionType) -> (e -> e -> e) -> Octree e -> (Octree e, [e]) | ||
| 221 | |||
| 222 | gmap' testAABB f (Leaf root ents) = (Leaf root ents_kept, outliers) | ||
| 223 | where | ||
| 224 | ents' = f <$> ents <*> ents | ||
| 225 | ents_kept = filter (keep testAABB root) ents' | ||
| 226 | outliers = filter (not . keep testAABB root) ents' | ||
| 227 | |||
| 228 | gmap' testAABB f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = | ||
| 229 | (Octree root ents_kept c1' c2' c3' c4' c5' c6' c7' c8', outliers) | ||
| 230 | where | ||
| 231 | ents' = (f <$> ents <*> ents) ++ out1 ++ out2 ++ out3 ++ out4 ++ out5 ++ out6 ++ out7 ++ out8 | ||
| 232 | ents_kept = filter (keep testAABB root) ents' | ||
| 233 | outliers = filter (not . keep testAABB root) ents' | ||
| 234 | (c1', out1) = gmap' testAABB f c1 | ||
| 235 | (c2', out2) = gmap' testAABB f c2 | ||
| 236 | (c3', out3) = gmap' testAABB f c3 | ||
| 237 | (c4', out4) = gmap' testAABB f c4 | ||
| 238 | (c5', out5) = gmap' testAABB f c5 | ||
| 239 | (c6', out6) = gmap' testAABB f c6 | ||
| 240 | (c7', out7) = gmap' testAABB f c7 | ||
| 241 | (c8', out8) = gmap' testAABB f c8 | ||
| 242 | |||
| 243 | |||
| 244 | population :: Octree e -> Int | ||
| 245 | population = F.foldr (\_ acc -> acc+1) 0 | ||
| 246 | |||
| 247 | |||
| 248 | |||
| 249 | |||
| 250 | instance Functor Octree where | ||
| 251 | |||
| 252 | fmap f (Leaf root ents) = Leaf root $ fmap f ents | ||
| 253 | |||
| 254 | fmap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = | ||
| 255 | Octree root (fmap f ents) c1' c2' c3' c4' c5' c6' c7' c8' | ||
| 256 | where | ||
| 257 | c1' = fmap f c1 | ||
| 258 | c2' = fmap f c2 | ||
| 259 | c3' = fmap f c3 | ||
| 260 | c4' = fmap f c4 | ||
| 261 | c5' = fmap f c5 | ||
| 262 | c6' = fmap f c6 | ||
| 263 | c7' = fmap f c7 | ||
| 264 | c8' = fmap f c8 | ||
| 265 | |||
| 266 | |||
| 267 | |||
| 268 | instance F.Foldable Octree where | ||
| 269 | |||
| 270 | foldMap f (Leaf root ents) = mconcat . fmap f $ ents | ||
| 271 | |||
| 272 | foldMap f (Octree root ents c1 c2 c3 c4 c5 c6 c7 c8) = | ||
| 273 | mconcat (fmap f ents) `mappend` | ||
| 274 | c1' `mappend` c2' `mappend` c3' `mappend` c4' `mappend` | ||
| 275 | c5' `mappend` c6' `mappend` c7' `mappend` c8' | ||
| 276 | where | ||
| 277 | c1' = F.foldMap f c1 | ||
| 278 | c2' = F.foldMap f c2 | ||
| 279 | c3' = F.foldMap f c3 | ||
| 280 | c4' = F.foldMap f c4 | ||
| 281 | c5' = F.foldMap f c5 | ||
| 282 | c6' = F.foldMap f c6 | ||
| 283 | c7' = F.foldMap f c7 | ||
| 284 | c8' = F.foldMap f c8 | ||
