{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ViewPatterns #-}
{-# OPTIONS_GHC -fno-warn-orphans #-}
{-# OPTIONS_GHC -fno-warn-name-shadowing #-}
module Diagrams.Trail
(
Trail'(..)
, glueLine
, closeLine
, cutLoop
, Trail(..)
, _Line, _Loop
, _LocLine, _LocLoop
, wrapTrail, wrapLine, wrapLoop
, onTrail, onLine
, glueTrail, closeTrail, cutTrail
, emptyLine, emptyTrail
, lineFromVertices, trailFromVertices
, lineFromOffsets, trailFromOffsets
, lineFromSegments, trailFromSegments
, loopFromSegments
, withTrail', withTrail, withLine
, isLineEmpty, isTrailEmpty
, isLine, isLoop
, trailSegments, lineSegments, loopSegments
, onLineSegments
, trailOffsets, trailOffset
, lineOffsets, lineOffset, loopOffsets
, trailPoints, linePoints, loopPoints
, trailVertices', lineVertices', loopVertices'
, trailVertices, lineVertices, loopVertices
, trailLocSegments, fixTrail, unfixTrail
, reverseTrail, reverseLocTrail
, reverseLine, reverseLocLine
, reverseLoop, reverseLocLoop
, Line, Loop
, SegTree(..), trailMeasure, numSegs, offset
, GetSegment(..), getSegment, GetSegmentCodomain(..)
) where
import Control.Arrow ((***))
import Control.Lens hiding (at, transform, (<|), (|>))
import Data.FingerTree (FingerTree, ViewL (..), ViewR (..),
(<|), (|>))
import qualified Data.FingerTree as FT
import Data.Fixed
import qualified Data.Foldable as F
import Data.Monoid.MList
import Data.Semigroup
import qualified Numeric.Interval.Kaucher as I
import Diagrams.Core
import Diagrams.Located
import Diagrams.Parametric
import Diagrams.Segment
import Diagrams.Tangent
import Linear.Affine
import Linear.Metric
import Linear.Vector
import Data.Serialize (Serialize)
import qualified Data.Serialize as Serialize
type instance V (FingerTree m a) = V a
type instance N (FingerTree m a) = N a
instance (FT.Measured m a, Transformable a)
=> Transformable (FingerTree m a) where
transform = FT.fmap' . transform
instance (FT.Measured m a, FT.Measured n b)
=> Cons (FingerTree m a) (FingerTree n b) a b where
_Cons = prism (uncurry (FT.<|)) $ \aas -> case FT.viewl aas of
a FT.:< as -> Right (a, as)
EmptyL -> Left mempty
{-# INLINE _Cons #-}
instance (FT.Measured m a, FT.Measured n b)
=> Snoc (FingerTree m a) (FingerTree n b) a b where
_Snoc = prism (uncurry (FT.|>)) $ \aas -> case FT.viewr aas of
as FT.:> a -> Right (as, a)
EmptyR -> Left mempty
{-# INLINE _Snoc #-}
newtype SegTree v n = SegTree (FingerTree (SegMeasure v n) (Segment Closed v n))
deriving (Eq, Ord, Show, Monoid, Transformable, FT.Measured (SegMeasure v n))
#if MIN_VERSION_base(4,9,0)
deriving instance (Ord n, Floating n, Metric v) => Semigroup (SegTree v n)
#endif
instance Wrapped (SegTree v n) where
type Unwrapped (SegTree v n) = FingerTree (SegMeasure v n) (Segment Closed v n)
_Wrapped' = iso (\(SegTree x) -> x) SegTree
{-# INLINE _Wrapped' #-}
instance (Metric v, OrderedField n, Metric u, OrderedField n')
=> Cons (SegTree v n) (SegTree u n') (Segment Closed v n) (Segment Closed u n') where
_Cons = _Wrapped . _Cons . bimapping id _Unwrapped
{-# INLINE _Cons #-}
instance (Metric v, OrderedField n, Metric u, OrderedField n')
=> Snoc (SegTree v n) (SegTree u n') (Segment Closed v n) (Segment Closed u n') where
_Snoc = _Wrapped . _Snoc . bimapping _Unwrapped id
{-# INLINE _Snoc #-}
instance Rewrapped (SegTree v n) (SegTree v' n')
type instance V (SegTree v n) = v
type instance N (SegTree v n) = n
type instance Codomain (SegTree v n) = v
instance (Metric v, OrderedField n, Real n)
=> Parametric (SegTree v n) where
atParam t p = offset . fst $ splitAtParam t p
instance Num n => DomainBounds (SegTree v n)
instance (Metric v, OrderedField n, Real n)
=> EndValues (SegTree v n)
type SplitResult v n = ((SegTree v n, n -> n), (SegTree v n, n -> n))
splitAtParam' :: (Metric v, OrderedField n, Real n) => SegTree v n -> n -> SplitResult v n
splitAtParam' tree@(SegTree t) p
| p < 0 =
case FT.viewl t of
EmptyL -> emptySplit
seg FT.:< t' ->
case seg `splitAtParam` (p * tSegs) of
(seg1, seg2) ->
( (SegTree $ FT.singleton seg1, (*p))
, (SegTree $ seg2 <| t', \u -> 1 - (1 - u) * tSegs / (tSegs + 1))
)
| p >= 1 =
case FT.viewr t of
EmptyR -> emptySplit
t' FT.:> seg ->
case seg `splitAtParam` (1 - (1 - p)*tSegs) of
(seg1, seg2) ->
( (SegTree $ t' |> seg1, \u -> u * tSegs / (tSegs + 1))
, (SegTree $ FT.singleton seg2, \u -> (u - p) / (1 - p))
)
| otherwise =
case FT.viewl after of
EmptyL -> emptySplit
seg FT.:< after' ->
let (n, p') = propFrac $ p * tSegs
f p n u | u * tSegs < n = u * tSegs / (n + 1)
| otherwise = (n + (u * tSegs - n) / (p * tSegs - n)) / (n+1)
in case seg `splitAtParam` p' of
(seg1, seg2) ->
( ( SegTree $ before |> seg1 , f p n )
, ( SegTree $ seg2 <| after'
, \v -> 1 - f (1 - p) (tSegs - n - 1) (1 - v)
)
)
where
(before, after) = FT.split ((p * tSegs <) . numSegs) t
tSegs = numSegs t
emptySplit = let t' = (tree, id) in (t',t')
propFrac x = let m = signum x * mod1 x in (x - m, m)
instance (Metric v, OrderedField n, Real n) => Sectionable (SegTree v n) where
splitAtParam tree p = let ((a,_),(b,_)) = splitAtParam' tree p in (a,b)
reverseDomain (SegTree t) = SegTree $ FT.reverse t'
where t' = FT.fmap' reverseSegment t
section x t1 t2 = let ((a,fa),_) = splitAtParam' x t2
in snd $ splitAtParam a (fa t1)
instance (Metric v, OrderedField n, Real n)
=> HasArcLength (SegTree v n) where
arcLengthBounded eps t
| I.width i <= eps = i
| otherwise = fun (eps / numSegs t)
where
i = trailMeasure (I.singleton 0)
getArcLengthCached
t
fun = trailMeasure (const 0)
getArcLengthFun
t
arcLengthToParam eps st@(SegTree t) l
| l < 0 = case FT.viewl t of
EmptyL -> 0
seg FT.:< _ -> arcLengthToParam eps seg l / tSegs
| l >= totalAL = case FT.viewr t of
EmptyR -> 0
t' FT.:> seg ->
let p = arcLengthToParam (eps/2) seg
(l - arcLength (eps/2) (SegTree t'))
in (p - 1)/tSegs + 1
| otherwise = case FT.viewl after of
EmptyL -> 0
seg FT.:< _ ->
let p = arcLengthToParam (eps/2) seg
(l - arcLength (eps/2) (SegTree before))
in (numSegs before + p) / tSegs
where
totalAL = arcLength eps st
tSegs = numSegs t
before, after :: FingerTree (SegMeasure v n) (Segment Closed v n)
(before, after) =
FT.split ((>= l)
. trailMeasure
0
(I.midpoint . getArcLengthBounded eps))
t
trailMeasure :: ( SegMeasure v n :>: m, FT.Measured (SegMeasure v n) t )
=> a -> (m -> a) -> t -> a
trailMeasure d f = option d f . get . FT.measure
numSegs :: (Num c, FT.Measured (SegMeasure v n) a)
=> a -> c
numSegs = fromIntegral . trailMeasure 0 (getSum . op SegCount)
offset :: ( OrderedField n, Metric v,
FT.Measured (SegMeasure v n) t
)
=> t -> v n
offset = trailMeasure zero (op TotalOffset . view oeOffset)
data Line
data Loop
data Trail' l v n where
Line :: SegTree v n -> Trail' Line v n
Loop :: SegTree v n -> Segment Open v n -> Trail' Loop v n
withTrail' :: (Trail' Line v n -> r) -> (Trail' Loop v n -> r) -> Trail' l v n -> r
withTrail' line _ t@(Line{}) = line t
withTrail' _ loop t@(Loop{}) = loop t
deriving instance Eq (v n) => Eq (Trail' l v n)
deriving instance Ord (v n) => Ord (Trail' l v n)
instance Show (v n) => Show (Trail' l v n) where
showsPrec d (Line (SegTree ft)) = showParen (d > 10) $
showString "lineFromSegments " . showList (F.toList ft)
showsPrec d (Loop (SegTree ft) o) = showParen (d > 10) $
showString "loopFromSegments " . showList (F.toList ft) .
showChar ' ' . showsPrec 11 o
type instance V (Trail' l v n) = v
type instance N (Trail' l v n) = n
type instance Codomain (Trail' l v n) = v
instance (OrderedField n, Metric v) => Semigroup (Trail' Line v n) where
(Line t1) <> (Line t2) = Line (t1 `mappend` t2)
instance (Metric v, OrderedField n) => Monoid (Trail' Line v n) where
mempty = emptyLine
mappend = (<>)
instance (Metric v, OrderedField n) => AsEmpty (Trail' Line v n) where
_Empty = nearly emptyLine isLineEmpty
instance (HasLinearMap v, Metric v, OrderedField n)
=> Transformable (Trail' l v n) where
transform tr (Line t ) = Line (transform tr t)
transform tr (Loop t s) = Loop (transform tr t) (transform tr s)
instance (Metric v, OrderedField n) => Enveloped (Trail' l v n) where
getEnvelope = withTrail' ftEnv (ftEnv . cutLoop)
where
ftEnv :: Trail' Line v n -> Envelope v n
ftEnv (Line t) = trailMeasure mempty (view oeEnvelope) t
instance (HasLinearMap v, Metric v, OrderedField n)
=> Renderable (Trail' o v n) NullBackend where
render _ _ = mempty
instance (Metric v, OrderedField n, Real n)
=> Parametric (Trail' l v n) where
atParam t p = withTrail'
(\(Line segT) -> segT `atParam` p)
(\l -> cutLoop l `atParam` mod1 p)
t
instance (Parametric (GetSegment (Trail' c v n)), Additive v, Num n)
=> Parametric (Tangent (Trail' c v n)) where
Tangent tr `atParam` p =
case GetSegment tr `atParam` p of
GetSegmentCodomain Nothing -> zero
GetSegmentCodomain (Just (_, seg, reparam)) -> Tangent seg `atParam` (p ^. cloneIso reparam)
instance ( Parametric (GetSegment (Trail' c v n))
, EndValues (GetSegment (Trail' c v n))
, Additive v
, Num n
)
=> EndValues (Tangent (Trail' c v n)) where
atStart (Tangent tr) =
case atStart (GetSegment tr) of
GetSegmentCodomain Nothing -> zero
GetSegmentCodomain (Just (_, seg, _)) -> atStart (Tangent seg)
atEnd (Tangent tr) =
case atEnd (GetSegment tr) of
GetSegmentCodomain Nothing -> zero
GetSegmentCodomain (Just (_, seg, _)) -> atEnd (Tangent seg)
instance (Metric v , OrderedField n, Real n)
=> Parametric (Tangent (Trail v n)) where
Tangent tr `atParam` p
= withTrail
((`atParam` p) . Tangent)
((`atParam` p) . Tangent)
tr
instance (Metric v, OrderedField n, Real n)
=> EndValues (Tangent (Trail v n)) where
atStart (Tangent tr) = withTrail (atStart . Tangent) (atStart . Tangent) tr
atEnd (Tangent tr) = withTrail (atEnd . Tangent) (atEnd . Tangent) tr
mod1 :: Real a => a -> a
mod1 = (`mod'` 1)
instance Num n => DomainBounds (Trail' l v n)
instance (Metric v, OrderedField n, Real n)
=> EndValues (Trail' l v n)
instance (Metric v, OrderedField n, Real n)
=> Sectionable (Trail' Line v n) where
splitAtParam (Line t) p = (Line t1, Line t2)
where
(t1, t2) = splitAtParam t p
reverseDomain = reverseLine
instance (Metric v, OrderedField n, Real n)
=> HasArcLength (Trail' l v n) where
arcLengthBounded eps =
withTrail'
(\(Line t) -> arcLengthBounded eps t)
(arcLengthBounded eps . cutLoop)
arcLengthToParam eps tr l =
withTrail'
(\(Line t) -> arcLengthToParam eps t l)
(\lp -> arcLengthToParam eps (cutLoop lp) l)
tr
instance Rewrapped (Trail' Line v n) (Trail' Line v' n')
instance Wrapped (Trail' Line v n) where
type Unwrapped (Trail' Line v n) = SegTree v n
_Wrapped' = iso (\(Line x) -> x) Line
{-# INLINE _Wrapped' #-}
instance (Metric v, OrderedField n, Metric u, OrderedField n')
=> Cons (Trail' Line v n) (Trail' Line u n') (Segment Closed v n) (Segment Closed u n') where
_Cons = _Wrapped . _Cons . bimapping id _Unwrapped
{-# INLINE _Cons #-}
instance (Metric v, OrderedField n, Metric u, OrderedField n')
=> Snoc (Trail' Line v n) (Trail' Line u n') (Segment Closed v n) (Segment Closed u n') where
_Snoc = _Wrapped . _Snoc . bimapping _Unwrapped id
{-# INLINE _Snoc #-}
newtype GetSegment t = GetSegment t
newtype GetSegmentCodomain v n =
GetSegmentCodomain
(Maybe ( v n
, Segment Closed v n
, AnIso' n n
))
getSegment :: t -> GetSegment t
getSegment = GetSegment
type instance V (GetSegment t) = V t
type instance N (GetSegment t) = N t
type instance Codomain (GetSegment t) = GetSegmentCodomain (V t)
instance (Metric v, OrderedField n) => Parametric (GetSegment (Trail' Line v n)) where
atParam (GetSegment (Line (SegTree ft))) p
| p <= 0 = case FT.viewl ft of
EmptyL -> GetSegmentCodomain Nothing
seg FT.:< _ -> GetSegmentCodomain $ Just (zero, seg, reparam 0)
| p >= 1 = case FT.viewr ft of
EmptyR -> GetSegmentCodomain Nothing
ft' FT.:> seg -> GetSegmentCodomain $ Just (offset ft', seg, reparam (n-1))
| otherwise
= let (before, after) = FT.split ((p*n <) . numSegs) ft
in case FT.viewl after of
EmptyL -> GetSegmentCodomain Nothing
seg FT.:< _ -> GetSegmentCodomain $ Just (offset before, seg, reparam (numSegs before))
where
n = numSegs ft
reparam k = iso (subtract k . (*n))
((/n) . (+ k))
instance (Metric v, OrderedField n, Real n) => Parametric (GetSegment (Trail' Loop v n)) where
atParam (GetSegment l) p = atParam (GetSegment (cutLoop l)) (mod1 p)
instance (Metric v, OrderedField n, Real n)
=> Parametric (GetSegment (Trail v n)) where
atParam (GetSegment t) p
= withTrail
((`atParam` p) . GetSegment)
((`atParam` p) . GetSegment)
t
instance DomainBounds t => DomainBounds (GetSegment t) where
domainLower (GetSegment t) = domainLower t
domainUpper (GetSegment t) = domainUpper t
instance (Metric v, OrderedField n)
=> EndValues (GetSegment (Trail' Line v n)) where
atStart (GetSegment (Line (SegTree ft)))
= case FT.viewl ft of
EmptyL -> GetSegmentCodomain Nothing
seg FT.:< _ ->
let n = numSegs ft
in GetSegmentCodomain $ Just (zero, seg, iso (*n) (/n))
atEnd (GetSegment (Line (SegTree ft)))
= case FT.viewr ft of
EmptyR -> GetSegmentCodomain Nothing
ft' FT.:> seg ->
let n = numSegs ft
in GetSegmentCodomain $
Just (offset ft', seg, iso (subtract (n-1) . (*n))
((/n) . (+ (n-1)))
)
instance (Metric v, OrderedField n, Real n)
=> EndValues (GetSegment (Trail' Loop v n)) where
atStart (GetSegment l) = atStart (GetSegment (cutLoop l))
atEnd (GetSegment l) = atEnd (GetSegment (cutLoop l))
instance (Metric v, OrderedField n, Real n)
=> EndValues (GetSegment (Trail v n)) where
atStart (GetSegment t)
= withTrail
(atStart . GetSegment)
(atStart . GetSegment)
t
atEnd (GetSegment t)
= withTrail
(atEnd . GetSegment)
(atEnd . GetSegment)
t
data Trail v n where
Trail :: Trail' l v n -> Trail v n
deriving instance Show (v n) => Show (Trail v n)
instance Eq (v n) => Eq (Trail v n) where
t1 == t2 =
withTrail
(\ln1 -> withTrail (\ln2 -> ln1 == ln2) (const False) t2)
(\lp1 -> withTrail (const False) (\lp2 -> lp1 == lp2) t2)
t1
instance Ord (v n) => Ord (Trail v n) where
compare t1 t2 =
withTrail
(\ln1 -> withTrail (compare ln1) (const LT) t2)
(\lp1 -> withTrail (const GT) (compare lp1) t2)
t1
instance (OrderedField n, Metric v) => Semigroup (Trail v n) where
(Trail (Line (SegTree ft))) <> t2 | FT.null ft = t2
t1 <> (Trail (Line (SegTree ft))) | FT.null ft = t1
t1 <> t2 = flip withLine t1 $ \l1 ->
flip withLine t2 $ \l2 ->
wrapLine (l1 <> l2)
instance (Metric v, OrderedField n) => Monoid (Trail v n) where
mempty = wrapLine emptyLine
mappend = (<>)
instance (Metric v, OrderedField n) => AsEmpty (Trail v n) where
_Empty = nearly emptyTrail isTrailEmpty
type instance V (Trail v n) = v
type instance N (Trail v n) = n
type instance Codomain (Trail v n) = v
instance (HasLinearMap v, Metric v, OrderedField n)
=> Transformable (Trail v n) where
transform t = onTrail (transform t) (transform t)
instance (Metric v, OrderedField n) => Enveloped (Trail v n) where
getEnvelope = withTrail getEnvelope getEnvelope
instance (Metric v, OrderedField n, Real n)
=> Parametric (Trail v n) where
atParam t p = withTrail (`atParam` p) (`atParam` p) t
instance Num n => DomainBounds (Trail v n)
instance (Metric v, OrderedField n, Real n) => EndValues (Trail v n)
instance (Metric v, OrderedField n, Real n) => Sectionable (Trail v n) where
splitAtParam t p = withLine ((wrapLine *** wrapLine) . (`splitAtParam` p)) t
reverseDomain = reverseTrail
instance (Metric v, OrderedField n, Real n)
=> HasArcLength (Trail v n) where
arcLengthBounded = withLine . arcLengthBounded
arcLengthToParam eps tr al = withLine (\ln -> arcLengthToParam eps ln al) tr
_Line :: Prism' (Trail v n) (Trail' Line v n)
_Line = _Wrapped' . _Left
_Loop :: Prism' (Trail v n) (Trail' Loop v n)
_Loop = _Wrapped' . _Right
_LocLine :: Prism' (Located (Trail v n)) (Located (Trail' Line v n))
_LocLine = prism' (mapLoc Trail) $ located (preview _Line)
_LocLoop :: Prism' (Located (Trail v n)) (Located (Trail' Loop v n))
_LocLoop = prism' (mapLoc Trail) $ located (preview _Loop)
instance Rewrapped (Trail v n) (Trail v' n')
instance Wrapped (Trail v n) where
type Unwrapped (Trail v n) = Either (Trail' Line v n) (Trail' Loop v n)
_Wrapped' = iso getTrail (either Trail Trail)
where
getTrail :: Trail v n -> Either (Trail' Line v n) (Trail' Loop v n)
getTrail (Trail t@(Line {})) = Left t
getTrail (Trail t@(Loop {})) = Right t
withTrail :: (Trail' Line v n -> r) -> (Trail' Loop v n -> r) -> Trail v n -> r
withTrail line loop (Trail t) = withTrail' line loop t
onTrail :: (Trail' Line v n -> Trail' l1 v n) -> (Trail' Loop v n -> Trail' l2 v n)
-> Trail v n -> Trail v n
onTrail o c = withTrail (wrapTrail . o) (wrapTrail . c)
withLine :: (Metric v, OrderedField n)
=> (Trail' Line v n -> r) -> Trail v n -> r
withLine f = withTrail f (f . cutLoop)
onLine :: (Metric v, OrderedField n)
=> (Trail' Line v n -> Trail' Line v n) -> Trail v n -> Trail v n
onLine f = onTrail f (glueLine . f . cutLoop)
wrapTrail :: Trail' l v n -> Trail v n
wrapTrail = Trail
wrapLine :: Trail' Line v n -> Trail v n
wrapLine = wrapTrail
wrapLoop :: Trail' Loop v n -> Trail v n
wrapLoop = wrapTrail
emptyLine :: (Metric v, OrderedField n) => Trail' Line v n
emptyLine = Line mempty
emptyTrail :: (Metric v, OrderedField n) => Trail v n
emptyTrail = wrapLine emptyLine
lineFromSegments :: (Metric v, OrderedField n)
=> [Segment Closed v n] -> Trail' Line v n
lineFromSegments = Line . SegTree . FT.fromList
loopFromSegments :: (Metric v, OrderedField n)
=> [Segment Closed v n] -> Segment Open v n -> Trail' Loop v n
loopFromSegments segs = Loop (SegTree (FT.fromList segs))
trailFromSegments :: (Metric v, OrderedField n)
=> [Segment Closed v n] -> Trail v n
trailFromSegments = wrapTrail . lineFromSegments
lineFromOffsets :: (Metric v, OrderedField n) => [v n] -> Trail' Line v n
lineFromOffsets = lineFromSegments . map straight
trailFromOffsets :: (Metric v, OrderedField n) => [v n] -> Trail v n
trailFromOffsets = wrapTrail . lineFromOffsets
lineFromVertices :: (Metric v, OrderedField n)
=> [Point v n] -> Trail' Line v n
lineFromVertices [] = emptyLine
lineFromVertices [_] = emptyLine
lineFromVertices ps = lineFromSegments . map straight $ zipWith (.-.) (tail ps) ps
trailFromVertices :: (Metric v, OrderedField n)
=> [Point v n] -> Trail v n
trailFromVertices = wrapTrail . lineFromVertices
glueLine :: (Metric v, OrderedField n) => Trail' Line v n -> Trail' Loop v n
glueLine (Line (SegTree t)) =
case FT.viewr t of
FT.EmptyR -> Loop mempty (Linear OffsetOpen)
t' FT.:> Linear _ -> Loop (SegTree t') (Linear OffsetOpen)
t' FT.:> Cubic c1 c2 _ -> Loop (SegTree t') (Cubic c1 c2 OffsetOpen)
glueTrail :: (Metric v, OrderedField n) => Trail v n -> Trail v n
glueTrail = onTrail glueLine id
closeLine :: Trail' Line v n -> Trail' Loop v n
closeLine (Line t) = Loop t (Linear OffsetOpen)
closeTrail :: Trail v n -> Trail v n
closeTrail = onTrail closeLine id
cutLoop :: forall v n. (Metric v, OrderedField n)
=> Trail' Loop v n -> Trail' Line v n
cutLoop (Loop (SegTree t) c) =
case (FT.null t, c) of
(True, Linear OffsetOpen) -> emptyLine
(_ , Linear OffsetOpen) -> Line (SegTree (t |> Linear off))
(_ , Cubic c1 c2 OffsetOpen) -> Line (SegTree (t |> Cubic c1 c2 off))
where
offV :: v n
offV = negated . trailMeasure zero (op TotalOffset .view oeOffset) $ t
off = OffsetClosed offV
cutTrail :: (Metric v, OrderedField n)
=> Trail v n -> Trail v n
cutTrail = onTrail id cutLoop
isLineEmpty :: (Metric v, OrderedField n) => Trail' Line v n -> Bool
isLineEmpty (Line (SegTree t)) = FT.null t
isTrailEmpty :: (Metric v, OrderedField n) => Trail v n -> Bool
isTrailEmpty = withTrail isLineEmpty (const False)
isLine :: Trail v n -> Bool
isLine = not . isLoop
isLoop :: Trail v n -> Bool
isLoop = withTrail (const False) (const True)
lineSegments :: Trail' Line v n -> [Segment Closed v n]
lineSegments (Line (SegTree t)) = F.toList t
onLineSegments
:: (Metric v, OrderedField n)
=> ([Segment Closed v n] -> [Segment Closed v n])
-> Trail' Line v n -> Trail' Line v n
onLineSegments f = lineFromSegments . f . lineSegments
loopSegments :: Trail' Loop v n -> ([Segment Closed v n], Segment Open v n)
loopSegments (Loop (SegTree t) c) = (F.toList t, c)
trailSegments :: (Metric v, OrderedField n)
=> Trail v n -> [Segment Closed v n]
trailSegments = withLine lineSegments
trailOffsets :: (Metric v, OrderedField n) => Trail v n -> [v n]
trailOffsets = withLine lineOffsets
trailOffset :: (Metric v, OrderedField n) => Trail v n -> v n
trailOffset = withLine lineOffset
lineOffsets :: Trail' Line v n -> [v n]
lineOffsets = map segOffset . lineSegments
loopOffsets :: (Metric v, OrderedField n) => Trail' Loop v n -> [v n]
loopOffsets = lineOffsets . cutLoop
lineOffset :: (Metric v, OrderedField n) => Trail' Line v n -> v n
lineOffset (Line t) = trailMeasure zero (op TotalOffset . view oeOffset) t
trailPoints :: (Metric v, OrderedField n)
=> Located (Trail v n) -> [Point v n]
trailPoints (viewLoc -> (p,t))
= withTrail (linePoints . (`at` p)) (loopPoints . (`at` p)) t
linePoints :: (Metric v, OrderedField n)
=> Located (Trail' Line v n) -> [Point v n]
linePoints (viewLoc -> (p,t))
= segmentPoints p . lineSegments $ t
loopPoints :: (Metric v, OrderedField n)
=> Located (Trail' Loop v n) -> [Point v n]
loopPoints (viewLoc -> (p,t))
= segmentPoints p . fst . loopSegments $ t
segmentPoints :: (Additive v, Num n) => Point v n -> [Segment Closed v n] -> [Point v n]
segmentPoints p = scanl (.+^) p . map segOffset
tolerance :: OrderedField a => a
tolerance = 10e-16
trailVertices' :: (Metric v, OrderedField n)
=> n -> Located (Trail v n) -> [Point v n]
trailVertices' toler (viewLoc -> (p,t))
= withTrail (lineVertices' toler . (`at` p)) (loopVertices' toler . (`at` p)) t
trailVertices :: (Metric v, OrderedField n)
=> Located (Trail v n) -> [Point v n]
trailVertices = trailVertices' tolerance
lineVertices' :: (Metric v, OrderedField n)
=> n -> Located (Trail' Line v n) -> [Point v n]
lineVertices' toler (viewLoc -> (p,t))
= segmentVertices' toler p . lineSegments $ t
lineVertices :: (Metric v, OrderedField n)
=> Located (Trail' Line v n) -> [Point v n]
lineVertices = lineVertices' tolerance
loopVertices' :: (Metric v, OrderedField n)
=> n -> Located (Trail' Loop v n) -> [Point v n]
loopVertices' toler (viewLoc -> (p,t))
| length segs > 1 = if far > toler then init ps else init . drop 1 $ ps
| otherwise = ps
where
far = quadrance ((signorm . tangentAtStart . head $ segs) ^-^
(signorm . tangentAtEnd . last $ segs))
segs = lineSegments . cutLoop $ t
ps = segmentVertices' toler p segs
loopVertices :: (Metric v, OrderedField n)
=> Located (Trail' Loop v n) -> [Point v n]
loopVertices = loopVertices' tolerance
segmentVertices' :: (Metric v, OrderedField n)
=> n -> Point v n -> [Segment Closed v n] -> [Point v n]
segmentVertices' toler p ts =
case ps of
(x:_:_) -> x : select (drop 1 ps) ds ++ [last ps]
_ -> ps
where
ds = zipWith far tans (drop 1 tans)
tans = [(signorm . tangentAtStart $ s
,signorm . tangentAtEnd $ s) | s <- ts]
ps = scanl (.+^) p . map segOffset $ ts
far p2 q2 = quadrance (snd p2 ^-^ fst q2) > toler
select :: [a] -> [Bool] -> [a]
select xs bs = map fst $ filter snd (zip xs bs)
fixTrail :: (Metric v, OrderedField n)
=> Located (Trail v n) -> [FixedSegment v n]
fixTrail t = map mkFixedSeg (trailLocSegments t)
unfixTrail
:: (Metric v, Ord n, Floating n)
=> [FixedSegment v n] -> Located (Trail v n)
unfixTrail = mapLoc trailFromSegments . takeLoc . map fromFixedSeg
where
takeLoc [] = [] `at` origin
takeLoc xs@(x:_) = map unLoc xs `at` loc x
trailLocSegments :: (Metric v, OrderedField n)
=> Located (Trail v n) -> [Located (Segment Closed v n)]
trailLocSegments t = zipWith at (trailSegments (unLoc t)) (trailPoints t)
reverseTrail :: (Metric v, OrderedField n) => Trail v n -> Trail v n
reverseTrail = onTrail reverseLine reverseLoop
reverseLocTrail :: (Metric v, OrderedField n)
=> Located (Trail v n) -> Located (Trail v n)
reverseLocTrail (viewLoc -> (p, t)) = reverseTrail t `at` (p .+^ trailOffset t)
reverseLine :: (Metric v, OrderedField n)
=> Trail' Line v n -> Trail' Line v n
reverseLine = onLineSegments (reverse . map reverseSegment)
reverseLocLine :: (Metric v, OrderedField n)
=> Located (Trail' Line v n) -> Located (Trail' Line v n)
reverseLocLine (viewLoc -> (p,l)) = reverseLine l `at` (p .+^ lineOffset l)
reverseLoop :: (Metric v, OrderedField n)
=> Trail' Loop v n -> Trail' Loop v n
reverseLoop = glueLine . reverseLine . cutLoop
reverseLocLoop :: (Metric v, OrderedField n)
=> Located (Trail' Loop v n) -> Located (Trail' Loop v n)
reverseLocLoop = mapLoc reverseLoop
instance (Metric v, OrderedField n) => Reversing (Trail' l v n) where
reversing t@(Line _) = onLineSegments (reverse . map reversing) t
reversing t@(Loop _ _) = glueLine . reversing . cutLoop $ t
instance (Metric v, OrderedField n) => Reversing (Trail v n) where
reversing (Trail t) = Trail (reversing t)
instance (Metric v, OrderedField n) => Reversing (Located (Trail' l v n)) where
reversing l@(Loc _ Line {}) = reverseLocLine l
reversing l@(Loc _ Loop {}) = reverseLocLoop l
instance (Metric v, OrderedField n) => Reversing (Located (Trail v n)) where
reversing = reverseLocTrail
instance (Serialize (v n), OrderedField n, Metric v) => Serialize (Trail v n) where
{-# INLINE get #-}
get = do
isLine <- Serialize.get
case isLine of
True -> do
segTree <- Serialize.get
return (Trail (Line segTree))
False -> do
segTree <- Serialize.get
segment <- Serialize.get
return (Trail (Loop segTree segment))
{-# INLINE put #-}
put (Trail (Line segTree)) = do
Serialize.put True
Serialize.put segTree
put (Trail (Loop segTree segment)) = do
Serialize.put False
Serialize.put segTree
Serialize.put segment
instance (OrderedField n, Metric v, Serialize (v n)) => Serialize (SegTree v n) where
{-# INLINE put #-}
put (SegTree fingerTree) = Serialize.put (F.toList fingerTree)
{-# INLINE get #-}
get = do
fingerTree <- Serialize.get
return (SegTree (FT.fromList fingerTree))