Files
loop/src/Geometry/Zone.hs
T
2021-08-16 20:56:49 +02:00

151 lines
4.4 KiB
Haskell

--{-# LANGUAGE TupleSections #-}
module Geometry.Zone
( ddaExt
)
where
import Geometry.Data
import Data.Foldable
import qualified Data.IntMap.Strict as IM
import qualified Data.IntSet as IS
--foldl2'
-- :: (b -> a -> a -> b)
-- -> b
-- -> [a]
-- -> b
--foldl2' f s (t:ts) = fst $ foldl' g (s, t) ts
-- where
-- g (r,x) y = (f r x y,y)
--foldl2' _ s _ = s
--sortArguments
-- :: Ord a
-- => (a -> a -> b)
-- -> a -> a -> b
--sortArguments f x y
-- | x < y = f x y
-- | otherwise = f y x
--sortArgumentsReverse
-- :: Ord a
-- => (a -> a -> [b])
-- -> a -> a -> [b]
--sortArgumentsReverse f x y
-- | x < y = f x y
-- | otherwise = reverse $ f y x
--
--intervalBounds
-- :: Float -- ^ interval threshold
-- -> Float -- ^ First endpoint
-- -> Float -- ^ Second endpoint
-- -> [Float]
--intervalBounds = sortArgumentsReverse . f
-- where
-- f r a b
-- | x > b = [a]
-- | otherwise = (a : [x,x+r..b])
-- where
-- x = floorTo r a + r
--floorTo :: Float -> Float -> Float
--floorTo r x = r * (fromIntegral ((floor $ x / r) :: Int))
--ceilingTo :: Float -> Float -> Float
--ceilingTo r x = r * (fromIntegral ((ceiling $ x / r) :: Int))
divTo :: Float -> Float -> Int
{-# INLINE divTo #-}
divTo s = floor . (/s)
--flipV :: Point2 -> Point2
--{-# INLINE flipV #-}
--flipV (V2 a b) = V2 b a
--applyInverted
-- :: (Point2 -> Point2 -> [Point2])
-- -> Point2 -> Point2 -> [Point2]
--applyInverted f sp@(V2 sx sy) ep@(V2 ex ey)
-- | abs (sx-ex) > abs (sy-ey) = f sp ep
-- | otherwise = map flipV $ f (flipV sp) (flipV ep)
sizeZoneOfPoint' :: Float -> Point2 -> V2 Int
{-# INLINE sizeZoneOfPoint' #-}
sizeZoneOfPoint' s = fmap (divTo s)
--increasingInterval :: Int -> Int -> [Int]
--increasingInterval x y
-- | y > x = [x .. y]
-- | otherwise = [y .. x]
-- | Determines which horizontal and vertical lines on a grid are crossed by a
-- line. For each adds the x-y index of the square to the right or above the
-- crossed grid line. Also adds the index of the square containing the start
-- point.
ddaExt :: Float -> V2 Float -> V2 Float -> IM.IntMap IS.IntSet
ddaExt s sp@(V2 sx sy) ep@(V2 ex ey)
| x1 <= x2 = addsp . addys . IM.fromDistinctAscList $ zip [x1 .. x2]
$ map (IS.singleton . divTo s) [x1y,x1y+ydx..]
| otherwise = addsp . addys . IM.fromDistinctAscList $ zip [x2-1 .. x1-1]
$ map (IS.singleton . divTo s) [x2y,x2y+ydx..]
where
addsp im = let V2 x y = sizeZoneOfPoint' s sp
in insertXY im (x,y)
x1 = divTo s sx
x2 = divTo s ex
x1y = fx' sp ep $ s * fromIntegral x1
x2y = fx' sp ep $ s * fromIntegral x2
ydx = s * ydx' sp ep
addys m = add2s m ypairs
y1 = divTo s sy
y2 = divTo s ey
y1x = fy' sp ep $ s * fromIntegral y1
y2x = fy' sp ep $ s * fromIntegral y2
xdy = s * xdy' sp ep
ypairs
| y1 <= y2 = zip (map (divTo s) [y1x,y1x+xdy..])
[y1 .. y2]
| otherwise = zip (map (divTo s) [y2x,y2x+xdy..])
[y2-1 .. y1-1]
ydx' :: Point2 -> Point2 -> Float
{-# INLINE ydx' #-}
ydx' (V2 sx sy) (V2 ex ey)
| sx == ex = 0
| otherwise = (ey - sy) / (ex - sx)
fx' :: Point2 -> Point2 -> Float -> Float
{-# INLINE fx' #-}
fx' sp@(V2 sx sy) ep@(V2 _ ey) x
| sy == ey = sy
| otherwise = sy + ydx' sp ep * (x - sx)
xdy' :: Point2 -> Point2 -> Float
{-# INLINE xdy' #-}
xdy' (V2 sx sy) (V2 ex ey)
| sy == ey = 0
| otherwise = (ex - sx) / (ey - sy)
fy' :: Point2 -> Point2 -> Float -> Float
{-# INLINE fy' #-}
fy' sp@(V2 sx sy) ep@(V2 ex _) y
| sx == ex = sx
| otherwise = sx + xdy' sp ep * (y - sy)
add2s :: IM.IntMap IS.IntSet -> [(Int,Int)] -> IM.IntMap IS.IntSet
{-# INLINE add2s #-}
add2s = foldl'
(\m (k,x) -> IM.insertWith (\_ old -> IS.insert x old) k (IS.singleton x) m)
insertXY :: IM.IntMap IS.IntSet -> (Int,Int) -> IM.IntMap IS.IntSet
{-# INLINE insertXY #-}
insertXY m (k,x) = IM.insertWith (\_ old -> IS.insert x old) k (IS.singleton x) m
--addV2s :: IM.IntMap IS.IntSet -> [V2 Int] -> IM.IntMap IS.IntSet
--{-# INLINE addV2s #-}
--addV2s imis = foldl'
-- (\m (V2 k x) -> IM.insertWith (\_ old -> IS.insert x old) k (IS.singleton x) m)
-- imis
--pairsToIntMapSet :: [V2 Int] -> IM.IntMap IS.IntSet
--pairsToIntMapSet = foldl'
-- (\m (V2 k x) -> IM.insertWith (\_ old -> IS.insert x old) k (IS.singleton x) m)
-- IM.empty