module Geometry.Trajectory.PathSimplifier.Radial (
    module Geometry.Trajectory.PathSimplifier.Radial
) where



import           Data.Sequential
import qualified Data.Vector     as V

import Geometry.Core



-- | Simplify a path by dropping points too close to their neighbours. The larger
-- the cutoff parameter, the simpler the result will be.
--
-- <<docs/interpolation/3_simplify_path_radial.svg>>
simplifyTrajectoryRadial
    :: Sequential vector
    => Double      -- ^ Cutoff parameter: minimum distance to the next neighbour. Higher values yield fewer points.
    -> vector Vec2 -- ^ Trajectory
    -> [Vec2]      -- ^ Simplified trajectory
simplifyTrajectoryRadial :: forall (vector :: * -> *).
Sequential vector =>
Double -> vector Vec2 -> [Vec2]
simplifyTrajectoryRadial Double
minimumNeighbourDistance = Double -> (Vec2 -> Vec2) -> Vector Vec2 -> [Vec2]
forall (vector :: * -> *) a.
Sequential vector =>
Double -> (a -> Vec2) -> vector a -> [a]
simplifyTrajectoryRadialBy Double
minimumNeighbourDistance Vec2 -> Vec2
forall a. a -> a
id (Vector Vec2 -> [Vec2])
-> (vector Vec2 -> Vector Vec2) -> vector Vec2 -> [Vec2]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. vector Vec2 -> Vector Vec2
forall a. vector a -> Vector a
forall (f :: * -> *) a. Sequential f => f a -> Vector a
toVector

-- | 'simplifyTrajectoryRadial', but allows specifying a function for how to extract the points
-- to base simplifying on from the input.
simplifyTrajectoryRadialBy
    :: Sequential vector
    => Double      -- ^ Cutoff parameter: minimum distance to the next neighbour. Higher values yield fewer points.
    -> (a -> Vec2) -- ^ Extract the relevant 'Vec2' to simplify on
    -> vector a    -- ^ Trajectory
    -> [a]         -- ^ Simplified trajectory
simplifyTrajectoryRadialBy :: forall (vector :: * -> *) a.
Sequential vector =>
Double -> (a -> Vec2) -> vector a -> [a]
simplifyTrajectoryRadialBy Double
minimumNeighbourDistance a -> Vec2
vec2in = Vector a -> [a]
go (Vector a -> [a]) -> (vector a -> Vector a) -> vector a -> [a]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. vector a -> Vector a
forall a. vector a -> Vector a
forall (f :: * -> *) a. Sequential f => f a -> Vector a
toVector
  where
    tooClose :: a -> a -> Bool
tooClose a
pivot a
candidate = Vec2 -> Double
normSquare (a -> Vec2
vec2in a
pivot Vec2 -> Vec2 -> Vec2
forall v. VectorSpace v => v -> v -> v
-. a -> Vec2
vec2in a
candidate) Double -> Double -> Bool
forall a. Ord a => a -> a -> Bool
<= Double
minimumNeighbourDistanceDouble -> Integer -> Double
forall a b. (Num a, Integral b) => a -> b -> a
^Integer
2
    go :: Vector a -> [a]
go Vector a
trajectory = case Vector a -> Maybe (a, Vector a)
forall a. Vector a -> Maybe (a, Vector a)
V.uncons Vector a
trajectory of
        Maybe (a, Vector a)
Nothing -> []
        Just (a
pivot,Vector a
xs)
            | Vector a -> Bool
forall a. Vector a -> Bool
V.null Vector a
rest Bool -> Bool -> Bool
&& Vector a -> Bool
forall a. Vector a -> Bool
V.null Vector a
toDrop -> [a
pivot]
            | Vector a -> Bool
forall a. Vector a -> Bool
V.null Vector a
rest -> [a
pivot, Vector a -> a
forall a. Vector a -> a
V.last Vector a
toDrop]
            | Bool
otherwise -> a
pivot a -> [a] -> [a]
forall a. a -> [a] -> [a]
: Vector a -> [a]
go Vector a
rest
            where (Vector a
toDrop, Vector a
rest) = (a -> Bool) -> Vector a -> (Vector a, Vector a)
forall a. (a -> Bool) -> Vector a -> (Vector a, Vector a)
V.span (a -> a -> Bool
tooClose a
pivot) Vector a
xs