
-- | Basic definitions for stencil handling.
module Data.Array.Repa.Stencil.Base
	( Boundary	(..)
	, Stencil	(..)
	, makeStencil, makeStencil2)
where
import Data.Array.Repa.Index

-- | How to handle the case when the stencil lies partly outside the array.
data Boundary a
        -- | Use a fixed value for border regions.
        = BoundFixed !a

	-- | Treat points outside the array as having a constant value.
	| BoundConst !a

	-- | Clamp points outside to the same value as the edge pixel.
	| BoundClamp
	deriving (Show)


-- | Represents a convolution stencil that we can apply to array.
--   Only statically known stencils are supported right now.
data Stencil sh a

	-- | Static stencils are used when the coefficients are fixed,
	--   and known at compile time.
	= StencilStatic
	{ stencilExtent	:: !sh
	, stencilZero	:: !a
	, stencilAcc	:: !(sh -> a -> a -> a) }


-- | Make a stencil from a function yielding coefficients at each index.
makeStencil
	:: Num a
	=> sh			-- ^ Extent of stencil.
	-> (sh -> Maybe a) 	-- ^ Get the coefficient at this index.
	-> Stencil sh a

{-# INLINE makeStencil #-}
makeStencil ex getCoeff
 = StencilStatic ex 0
 $ \ix val acc
	-> case getCoeff ix of
		Nothing		-> acc
		Just coeff	-> acc + val * coeff


-- | Wrapper for `makeStencil` that requires a DIM2 stencil.
makeStencil2
	:: Num a
	=> Int -> Int		-- ^ extent of stencil
	-> (DIM2 -> Maybe a)	-- ^ Get the coefficient at this index.
	-> Stencil DIM2 a

{-# INLINE makeStencil2 #-}
makeStencil2 height width getCoeff
	= makeStencil (Z :. height :. width) getCoeff

