packages feed

keid-geometry-0.1.1.2: src/Geometry/Tile/Microblob.hs

module Geometry.Tile.Microblob
  ( Microblob(..)
  , indices
  , names
  , quad

  , genSets
  ) where

import RIO

import Data.Bits
import Geometry.Quad (Quad(..))
import Geometry.Tile.Neighbors (Neighbors(..))
import Resource.Collection (Generic1, Generically1(..), enumerate)
import RIO.Map qualified as Map
import RIO.Set qualified as Set

data Microblob a = Microblob
  { brCornerInner    :: a
  , blCornerInner    :: a
  , trCornerInner    :: a
  , tlCornerInner    :: a
  , tlCornerOuter    :: a
  , ttEdgeHorizontal :: a
  , trCornerOuter    :: a
  , llEdgeVertical   :: a
  , full             :: a
  , rrEdgeVertical   :: a
  , blCornerOuter    :: a
  , bbEdgeHorizontal :: a
  , brCornerOuter    :: a
  }
  deriving stock (Eq, Ord, Show, Functor, Foldable, Traversable, Generic1)
  deriving Applicative via Generically1 Microblob

indices :: Microblob Int
indices = fmap fst . enumerate $ pure ()

names :: Microblob Text
names = Microblob
  { brCornerInner    = "brCornerInner"
  , blCornerInner    = "blCornerInner"
  , trCornerInner    = "trCornerInner"
  , tlCornerInner    = "tlCornerInner"
  , tlCornerOuter    = "tlCornerOuter"
  , ttEdgeHorizontal = "ttEdgeHorizontal"
  , trCornerOuter    = "trCornerOuter"
  , llEdgeVertical   = "llEdgeVertical"
  , full             = "full"
  , rrEdgeVertical   = "rrEdgeVertical"
  , blCornerOuter    = "blCornerOuter"
  , bbEdgeHorizontal = "bbEdgeHorizontal"
  , brCornerOuter    = "brCornerOuter"
  }

quad :: Neighbors Int -> Microblob a -> Int -> Quad a
quad Neighbors{..} Microblob{..} index = Quad
  { quadLT =
      if iNorth && iWest then
        if testBit index northWest then
          full
        else
          tlCornerInner
      else
        if iNorth then
          llEdgeVertical
        else
          if iWest then
            ttEdgeHorizontal
          else
            tlCornerOuter

  , quadRT =
      if iNorth && iEast then
        if testBit index northEast then
          full
        else
          trCornerInner
      else
        if iNorth then
          rrEdgeVertical
        else
          if iEast then
            ttEdgeHorizontal
          else
            trCornerOuter

  , quadLB =
      if iSouth && iWest then
        if testBit index southWest then
          full
        else
          blCornerInner
      else
        if iSouth then
          llEdgeVertical
        else
          if iWest then
            bbEdgeHorizontal
          else
            blCornerOuter

  , quadRB =
      if iSouth && iEast then
        if testBit index southEast then
          full
        else
          brCornerInner
      else
        if iSouth then
          rrEdgeVertical
        else
          if iEast then
            bbEdgeHorizontal
          else
            brCornerOuter
  }
  where
    iNorth = testBit index north
    iWest  = testBit index west
    iEast  = testBit index east
    iSouth = testBit index south

genSets :: Neighbors Int -> (Set Int, Map Int Int)
genSets bits = foldl' @[] f (Set.empty, Map.empty) [0..255]
  where
    Neighbors{..} = bits

    f (uniq, dups) i =
      ( Set.insert index uniq
      , Map.insert i index dups
      )
      where
        index = i
          & bool (clearBit northWest) id (iNorth && iWest)
          & bool (clearBit northEast) id (iNorth && iEast)
          & bool (clearBit southWest) id (iSouth && iWest)
          & bool (clearBit southEast) id (iSouth && iEast)

        iNorth = testBit i north
        iWest  = testBit i west
        iEast  = testBit i east
        iSouth = testBit i south