imj-base-0.1.0.2: src/Imj/Graphics/Class/DiscreteInterpolation.hs
{-# OPTIONS_HADDOCK hide #-}
{-# LANGUAGE NoImplicitPrelude #-}
module Imj.Graphics.Class.DiscreteInterpolation
( DiscreteInterpolation(..)
-- * Reexport
, module Imj.Graphics.Class.DiscreteDistance
) where
import Imj.Prelude
import Data.List(length)
import Imj.Graphics.Class.DiscreteDistance
import Imj.Util
{- | Instances should statisfy the following constraints:
* An interpolation between A and B starts at A and ends at B:
\( \forall (\, from, to)\, \in v, \)
@
d = distance from to
interpolate from to 0 == from
interpolate from to d == to
@
* The interpolation path is composed of strictly distinct points:
@
length $ nubOrd $ map (interpolate from to) [0..pred d] == d
@
* Given any points A,B belonging the path generated by an interpolation,
the interpolation beween A and B will be the points of the path between A and B:
\( \forall med \in [\,0,d]\,, \forall low \in [\,0,med]\,, \forall high \in [\,med,d]\,, \)
@
distance from med + distance med to == 1 + distance from to
medVal = interpolate from to med
interpolate from to low == interpolate from medVal low
interpolate from to high == interpolate medVal to $ high-med
@
-}
class (DiscreteDistance v) => DiscreteInterpolation v where
-- | Implement this function if you want to interpolate /by value/, i.e the result of
-- the interpolation between two \(v\) is a \(v\).
interpolate :: v -- ^ first value
-> v -- ^ last value
-> Int -- ^ the current step
-> v -- ^ the interpolated value
interpolateSuccessive :: Successive v
-> Int
-> v
interpolateSuccessive (Successive []) _ = error "empty successive"
interpolateSuccessive (Successive [a]) _ = a
interpolateSuccessive (Successive l@(a:b:_)) i
| i <= 0 = a
| i >= lf = interpolateSuccessive (Successive $ tail l) $ i-lf
| otherwise = interpolate a b i
where lf = pred $ distance a b
-- | Naïve interpolation.
instance DiscreteInterpolation Int where
interpolate i i' progress =
i + signum (i'-i) * clamp progress 0 (abs (i-i'))
-- | Interpolate in parallel between 2 lists : each pair of same-index elements
-- is interpolated at the same time.
instance (DiscreteInterpolation a)
=> DiscreteInterpolation ([] a) where
interpolate l l' progress =
zipWith (\e e' -> interpolate e e' progress) l $ assert (length l == length l') l'