{-# LANGUAGE NoImplicitPrelude #-}
module Imj.Geo.Discrete
( module Imj.Geo.Discrete.Types
, mkSegmentByExtendingWhile
, changeSegmentLength
, extremities
, segmentContains
, zeroCoords
, coordsForDirection
, diffCoords
, diffPosToSpeed
, sumCoords
, sumPosSpeed
, move
, translate
, translate'
, translateInDir
, module Imj.Geo.Discrete.Bresenham
, module Imj.Geo.Discrete.Bresenham3
, module Imj.Geo.Discrete.Resample
) where
import Imj.Prelude
import Imj.Geo.Discrete.Types
import Imj.Geo.Discrete.Bresenham
import Imj.Geo.Discrete.Bresenham3
import Imj.Geo.Discrete.Resample
zeroCoords :: Coords a
zeroCoords = Coords 0 0
diffCoords :: Coords a
-> Coords a
-> Coords a
diffCoords (Coords r1 c1) (Coords r2 c2) =
Coords (r1 - r2) (c1 - c2)
sumCoords :: Coords a
-> Coords a
-> Coords a
sumCoords (Coords r1 c1) (Coords r2 c2) =
Coords (r1 + r2) (c1 + c2)
sumPosSpeed :: Coords Pos
-> Coords Vel
-> Coords Pos
sumPosSpeed (Coords r1 c1) (Coords r2 c2) =
Coords (r1 + r2) (c1 + c2)
{-# INLINE diffPosToSpeed #-}
diffPosToSpeed :: Coords Pos
-> Coords Pos
-> Coords Vel
diffPosToSpeed (Coords r1 c1) (Coords r2 c2) =
Coords (r1 - r2) (c1 - c2)
coordsForDirection :: Direction -> Coords a
coordsForDirection Down = Coords 1 0
coordsForDirection Up = Coords (-1) 0
coordsForDirection LEFT = Coords 0 (-1)
coordsForDirection RIGHT = Coords 0 1
multiply :: Int -> Coords a -> Coords a
multiply n (Coords r c) = Coords (r * fromIntegral n) (c * fromIntegral n)
translateInDir :: Direction -> Coords a -> Coords a
translateInDir dir = translate $ coordsForDirection dir
changeSegmentLength :: Int -> Segment -> Segment
changeSegmentLength i (Horizontal row c1 _) = Horizontal row c1 $ c1 + fromIntegral i
changeSegmentLength i (Vertical col r1 _) = Vertical col r1 $ r1 + fromIntegral i
changeSegmentLength _ _ = error "changeSegmentLength cannot operate on oblique segments"
segmentContains :: Coords Pos
-> Segment
-> Maybe Int
segmentContains (Coords row' c) (Horizontal row c1 c2) =
if row' == row
then
fromIntegral <$> rangeContains c1 c2 c
else
Nothing
segmentContains (Coords r col') (Vertical col r1 r2) =
if col' == col
then
fromIntegral <$> rangeContains r1 r2 r
else
Nothing
segmentContains _ _ =
error "segmentContains cannot operate on oblique segments"
extremities :: Segment -> (Coords Pos, Coords Pos)
extremities (Horizontal row c1 c2) = (Coords row c1, Coords row c2)
extremities (Vertical col r1 r2) = (Coords r1 col, Coords r2 col)
extremities (Oblique c1 c2) = (c1, c2)
{-# INLINABLE rangeContains #-}
rangeContains :: (Num a, Eq a) => a -> a -> a -> Maybe a
rangeContains r1 r2 i =
if abs (r2-i) + abs (i-r1) == abs (r2-r1)
then
Just (i - r1)
else
Nothing
translate :: Coords a -> Coords a -> Coords a
translate = sumCoords
translate' :: Length Height
-> Length Width
-> Coords Pos
-> Coords Pos
translate' h w c =
sumCoords c $ toCoords h w
move :: Int
-> Direction
-> Coords a
-> Coords a
move t dir c = sumCoords c $ multiply t $ coordsForDirection dir
mkSegmentByExtendingWhile :: Coords Pos
-> Direction
-> (Coords Pos -> Bool)
-> Segment
mkSegmentByExtendingWhile start dir f =
let end = extend' start dir f
in mkSegment start end
extend' :: Coords Pos -> Direction -> (Coords Pos -> Bool) -> Coords Pos
extend' coords dir continue =
let loc = translateInDir dir coords
in if continue loc
then
extend' loc dir continue
else
coords