{-# LANGUAGE BangPatterns #-} -- | Functions specialised for arrays of dimension 2. module Data.Array.Repa.Specialised.Dim2 ( isInside2 , isOutside2 , clampToBorder2 , makeBordered2) where import Data.Array.Repa.Index import Data.Array.Repa.Base import Data.Array.Repa.Repr.Partitioned import Data.Array.Repa.Repr.Undefined -- | Check if an index lies inside the given extent. -- As opposed to `inRange` from "Data.Array.Repa.Index", -- this is a short-circuited test that checks that lowest dimension first. isInside2 :: DIM2 -- ^ Extent of array. -> DIM2 -- ^ Index to check. -> Bool {-# INLINE isInside2 #-} isInside2 ex = not . isOutside2 ex -- | Check if an index lies outside the given extent. -- As opposed to `inRange` from "Data.Array.Repa.Index", -- this is a short-circuited test that checks the lowest dimension first. isOutside2 :: DIM2 -- ^ Extent of array. -> DIM2 -- ^ Index to check. -> Bool {-# INLINE isOutside2 #-} isOutside2 (_ :. yLen :. xLen) (_ :. yy :. xx) | xx < 0 = True | xx >= xLen = True | yy < 0 = True | yy >= yLen = True | otherwise = False -- | Given the extent of an array, clamp the components of an index so they -- lie within the given array. Outlying indices are clamped to the index -- of the nearest border element. clampToBorder2 :: DIM2 -- ^ Extent of array. -> DIM2 -- ^ Index to clamp. -> DIM2 {-# INLINE clampToBorder2 #-} clampToBorder2 (_ :. yLen :. xLen) (sh :. j :. i) = clampX j i where {-# INLINE clampX #-} clampX !y !x | x < 0 = clampY y 0 | x >= xLen = clampY y (xLen - 1) | otherwise = clampY y x {-# INLINE clampY #-} clampY !y !x | y < 0 = sh :. 0 :. x | y >= yLen = sh :. (yLen - 1) :. x | otherwise = sh :. y :. x -- | Make a 2D partitioned array from two others, one to produce the elements -- in the internal region, and one to produce elements in the border region. -- The two arrays must have the same extent. -- The border must be the same width on all sides. -- makeBordered2 :: (Source r1 a, Source r2 a) => DIM2 -- ^ Extent of array. -> Int -- ^ Width of border. -> Array r1 DIM2 a -- ^ Array for internal elements. -> Array r2 DIM2 a -- ^ Array for border elements. -> Array (P r1 (P r2 (P r2 (P r2 (P r2 X))))) DIM2 a {-# INLINE makeBordered2 #-} makeBordered2 sh@(_ :. aHeight :. aWidth) bWidth arrInternal arrBorder = checkDims `seq` let -- minimum and maximum indicies of values in the inner part of the image. !inX = bWidth !inY = bWidth !inW = aWidth - 2 * bWidth !inH = aHeight - 2 * bWidth inInternal (Z :. y :. x) = x >= inX && x < (inX + inW) && y >= inY && y < (inY + inH) {-# INLINE inInternal #-} inBorder = not . inInternal {-# INLINE inBorder #-} in -- internal region APart sh (Range (Z :. inY :. inX) (Z :. inH :. inW ) inInternal) arrInternal -- border regions $ APart sh (Range (Z :. 0 :. 0) (Z :. bWidth :. aWidth) inBorder) arrBorder $ APart sh (Range (Z :. inY + inH :. 0) (Z :. bWidth :. aWidth) inBorder) arrBorder $ APart sh (Range (Z :. inY :. 0) (Z :. inH :. bWidth) inBorder) arrBorder $ APart sh (Range (Z :. inY :. inX + inW) (Z :. inH :. bWidth) inBorder) arrBorder $ AUndefined sh where checkDims = if (extent arrInternal) == (extent arrBorder) then () else error "makeBordered2: internal and border arrays have different extents" {-# NOINLINE checkDims #-} -- NOINLINE because we don't want the branch in the core code.