----------------------------------------------------------------------------- -- | -- Copyright : (C) 2015 Dimitri Sabadie -- License : BSD3 -- -- Maintainer : Dimitri Sabadie -- Stability : experimental -- Portability : portable -- -- A @Spline s a@ represents a curve in which 'a' is very likely to be -- 'Additive' (see "linear") and 's' is the sampling type. -- -- The library exports two useful functions: 'spline' and 'smooth'. The former -- enables you to create splines while the latter enables you to sample from -- them using their control points. ---------------------------------------------------------------------------- module Data.Spline ( -- * Spline Spline , spline , unspline -- * Sampling values from splines , sample ) where import Data.List ( sortBy ) import Data.Ord ( comparing ) import Data.Spline.CP import Data.Spline.Polynomial ( Polynomial(..), bsearchLower ) import Data.Vector ( Vector, (!?), fromList, toList ) import qualified Data.Vector as V ( zip ) -- |A @Spline@ is a collection of control points with associated polynomials. -- Given two control points which indices are /i/ and /i+1/, interpolation on -- the resulting curve is performed using the polynomial of indice /i/. Thus, -- the latest control point is ignored and can be set to whatever the user wants -- to, even 'undefined' – you should use hold, though. Yeah, don’t go filthy. data Spline s a = Spline (Vector (CP s a)) (Vector (Polynomial s a)) -- |Create a spline using a list of control points and associated polynomials. -- Since 'spline' sorts the list before creating the 'Spline', you don’t have to -- ensure the list is sorted – even though you should, setting control points -- with no order might be… chaotic. spline :: (Ord a,Ord s) => [(CP s a,Polynomial s a)] -> Spline s a spline = uncurry spline_ . unzip . dupLast . sortBy (comparing fst) where spline_ cps polys = Spline (fromList cps) (fromList polys) -- |Deconstruct a 'Spline s a' to yield '[(CP s a,Polynomial s a)]'. unspline :: Spline s a -> [(CP s a,Polynomial s a)] unspline (Spline cps polys) = toList $ V.zip cps polys -- |Sample a point on a spline. sample :: (Ord s) => Spline s a -> s -> Maybe a sample (Spline cps polys) s = do i <- bsearchLower (\(CP s' _) -> compare s s') cps p <- polys !? i unPolynomial p s cps -- Duplicate the last element in a list. -- -- Warning: unsafe function. dupLast :: [a] -> [a] dupLast [] = [] dupLast [x] = [x,x] dupLast (x:xs) = x : dupLast xs