{-# LANGUAGE TemplateHaskell #-}
--------------------------------------------------------------------------------
-- |
-- Module      :  Data.Geometry.QuadTree.Split
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--------------------------------------------------------------------------------
module Data.Geometry.QuadTree.Split where

import Control.Lens (makePrisms,(^.))
import Data.Geometry.QuadTree.Cell
import Data.Geometry.QuadTree.Quadrants

--------------------------------------------------------------------------------

-- | Data Type to Decide if we should continue splitting the current cell
data Split i v p = No !p | Yes !v (Quadrants i) deriving (Int -> Split i v p -> ShowS
[Split i v p] -> ShowS
Split i v p -> String
(Int -> Split i v p -> ShowS)
-> (Split i v p -> String)
-> ([Split i v p] -> ShowS)
-> Show (Split i v p)
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
forall i v p.
(Show p, Show v, Show i) =>
Int -> Split i v p -> ShowS
forall i v p. (Show p, Show v, Show i) => [Split i v p] -> ShowS
forall i v p. (Show p, Show v, Show i) => Split i v p -> String
showList :: [Split i v p] -> ShowS
$cshowList :: forall i v p. (Show p, Show v, Show i) => [Split i v p] -> ShowS
show :: Split i v p -> String
$cshow :: forall i v p. (Show p, Show v, Show i) => Split i v p -> String
showsPrec :: Int -> Split i v p -> ShowS
$cshowsPrec :: forall i v p.
(Show p, Show v, Show i) =>
Int -> Split i v p -> ShowS
Show,Split i v p -> Split i v p -> Bool
(Split i v p -> Split i v p -> Bool)
-> (Split i v p -> Split i v p -> Bool) -> Eq (Split i v p)
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
forall i v p.
(Eq p, Eq v, Eq i) =>
Split i v p -> Split i v p -> Bool
/= :: Split i v p -> Split i v p -> Bool
$c/= :: forall i v p.
(Eq p, Eq v, Eq i) =>
Split i v p -> Split i v p -> Bool
== :: Split i v p -> Split i v p -> Bool
$c== :: forall i v p.
(Eq p, Eq v, Eq i) =>
Split i v p -> Split i v p -> Bool
Eq,Eq (Split i v p)
Eq (Split i v p)
-> (Split i v p -> Split i v p -> Ordering)
-> (Split i v p -> Split i v p -> Bool)
-> (Split i v p -> Split i v p -> Bool)
-> (Split i v p -> Split i v p -> Bool)
-> (Split i v p -> Split i v p -> Bool)
-> (Split i v p -> Split i v p -> Split i v p)
-> (Split i v p -> Split i v p -> Split i v p)
-> Ord (Split i v p)
Split i v p -> Split i v p -> Bool
Split i v p -> Split i v p -> Ordering
Split i v p -> Split i v p -> Split i v p
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall i v p. (Ord p, Ord v, Ord i) => Eq (Split i v p)
forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Bool
forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Ordering
forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Split i v p
min :: Split i v p -> Split i v p -> Split i v p
$cmin :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Split i v p
max :: Split i v p -> Split i v p -> Split i v p
$cmax :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Split i v p
>= :: Split i v p -> Split i v p -> Bool
$c>= :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Bool
> :: Split i v p -> Split i v p -> Bool
$c> :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Bool
<= :: Split i v p -> Split i v p -> Bool
$c<= :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Bool
< :: Split i v p -> Split i v p -> Bool
$c< :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Bool
compare :: Split i v p -> Split i v p -> Ordering
$ccompare :: forall i v p.
(Ord p, Ord v, Ord i) =>
Split i v p -> Split i v p -> Ordering
$cp1Ord :: forall i v p. (Ord p, Ord v, Ord i) => Eq (Split i v p)
Ord)
makePrisms ''Split

-- | A splitter is a function that determines weather or not we should the given cell
-- corresponding to the given input (i).
type Splitter r i v p = Cell r -> i -> Split i v p

-- | Transformer that limits the depth of a splitter
type Limiter r i v p = Splitter r i v p
                    -> Splitter r i v (Either i p)

-- | Split only when the Cell-width is at least wMin
limitWidthTo        :: WidthIndex -- ^ smallest allowed width of a cell (i.e. width of a leaf)
                    -> Limiter r i v p
limitWidthTo :: Int -> Limiter r i v p
limitWidthTo Int
wMin Splitter r i v p
f Cell r
c i
pts =
    case Splitter r i v p
f Cell r
c i
pts of
      No p
p                                -> Either i p -> Split i v (Either i p)
forall i v p. p -> Split i v p
No (p -> Either i p
forall a b. b -> Either a b
Right p
p)
      Yes v
v Quadrants i
qs | Int
wMin Int -> Int -> Bool
forall a. Ord a => a -> a -> Bool
< Cell r
cCell r -> Getting Int (Cell r) Int -> Int
forall s a. s -> Getting a s a -> a
^.Getting Int (Cell r) Int
forall r. Lens' (Cell r) Int
cellWidthIndex -> v -> Quadrants i -> Split i v (Either i p)
forall i v p. v -> Quadrants i -> Split i v p
Yes v
v Quadrants i
qs
               | Bool
otherwise                -> Either i p -> Split i v (Either i p)
forall i v p. p -> Split i v p
No (i -> Either i p
forall a b. a -> Either a b
Left i
pts)
  -- note that it is important that we still evaluate the function so
  -- that we can distinguish at the last level i.e. between a regular
  -- " we are done splitting (No (Right p))" and a "we are no longer
  -- allowed to split further (No (Left p))"