brillo-examples-2.0.0: picture/Styrene/QuadTree.hs
{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
{-# HLINT ignore "Eta reduce" #-}
module QuadTree (
QuadTree (..),
treeZero,
treeInsert,
treeElems,
)
where
import Brillo.Data.Point (Point)
data QuadTree a
= -- Nil cells take up space in the world, but don't contain any elements.
-- They can be at any depth in the tree.
QNil
!Point -- cell center point
!Float -- cell size
| -- Leaf cells are the only ones that contain elements.
-- They are always at the bottom of the tree.
QLeaf
!Point -- cell center point
!Float -- cell size
![a] -- elements in this cell
| -- Node cells contain more sub-trees
QNode
!Point -- cell center point
!Float -- cell size
!(QuadTree a)
!(QuadTree a) -- NW NE
!(QuadTree a)
!(QuadTree a) -- SW SE
deriving (Eq, Show)
-- Initial ---------------------------------------------------------------------
treeZero :: Float -> QuadTree a
treeZero size =
QNil (0, 0) size
-- Quadrant --------------------------------------------------------------------
-- | Insert an element with a bounding box into the tree
treeInsert ::
-- | maximum depth to place a leaf
Int ->
-- | current depth
Int ->
-- | bottom left of bounding box of new element
Point ->
-- | top right of bounding box of new element
Point ->
-- | element to insert into tree
a ->
-- | current tree
QuadTree a ->
QuadTree a
treeInsert depthMax depth p0@(x0, y0) p1@(x1, y1) a tree =
case tree of
QNode p@(x, y) size tNW tNE tSW tSE ->
let
tNW'
| y1 > y && x0 < x = treeInsert depthMax (depth + 1) p0 p1 a tNW
| otherwise = tNW
tNE'
| y1 > y && x1 > x = treeInsert depthMax (depth + 1) p0 p1 a tNE
| otherwise = tNE
tSW'
| y0 < y && x0 < x = treeInsert depthMax (depth + 1) p0 p1 a tSW
| otherwise = tSW
tSE'
| y0 < y && x1 > x = treeInsert depthMax (depth + 1) p0 p1 a tSE
| otherwise = tSE
in
QNode p size tNW' tNE' tSW' tSE'
QLeaf p size elems
| depth >= depthMax ->
QLeaf p size (a : elems)
QNil p@(x, y) size
| depth >= depthMax ->
QLeaf p size [a]
| otherwise ->
treeInsert
depthMax
depth
p0
p1
a
( let s2 = size / 2
in QNode
p
size
(QNil (x - s2, y + s2) s2)
(QNil (x + s2, y + s2) s2)
(QNil (x - s2, y - s2) s2)
(QNil (x + s2, y - s2) s2)
)
QLeaf (_, _) _ _ -> error "treeInsert: QLeaf"
-- flatten a quadtree into a list of its elements.
treeElems :: QuadTree a -> [[a]]
treeElems tree =
case tree of
QNode _ _ tNW tNE tSW tSE ->
treeElems tNW ++ treeElems tNE ++ treeElems tSW ++ treeElems tSE
QLeaf _ _ elems -> [elems]
QNil{} -> []