{-# LANGUAGE UndecidableInstances  #-}
--------------------------------------------------------------------------------
-- |
-- Module      :  Data.Geometry.PolyLine
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--------------------------------------------------------------------------------
module Data.Geometry.PolyLine where

import           Control.Lens
import           Data.Aeson
import           Data.Bifoldable
import           Data.Bifunctor
import           Data.Bitraversable
import           Data.Ext
import qualified Data.Foldable as F
import           Data.Geometry.Box
import           Data.Geometry.LineSegment
import           Data.Geometry.Point
import           Data.Geometry.Properties
import           Data.Geometry.Transformation
import           Data.Geometry.Vector
import           Data.LSeq (LSeq, pattern (:<|))
import qualified Data.LSeq as LSeq
import qualified Data.List.NonEmpty as NE
import           GHC.Generics (Generic)
import           GHC.TypeLits

--------------------------------------------------------------------------------

--------------------------------------------------------------------------------
-- $setup
-- >>> :{
-- let myPolyLine = fromPointsUnsafe $ map ext [origin, Point2 10.0 10.0, Point2 10.0 20.0]
-- :}

--------------------------------------------------------------------------------
-- * d-dimensional Polygonal Lines (PolyLines)

-- | A Poly line in R^d has at least 2 vertices
newtype PolyLine d p r = PolyLine { PolyLine d p r -> LSeq 2 (Point d r :+ p)
_points :: LSeq 2 (Point d r :+ p) } deriving ((forall x. PolyLine d p r -> Rep (PolyLine d p r) x)
-> (forall x. Rep (PolyLine d p r) x -> PolyLine d p r)
-> Generic (PolyLine d p r)
forall x. Rep (PolyLine d p r) x -> PolyLine d p r
forall x. PolyLine d p r -> Rep (PolyLine d p r) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall (d :: Nat) p r x. Rep (PolyLine d p r) x -> PolyLine d p r
forall (d :: Nat) p r x. PolyLine d p r -> Rep (PolyLine d p r) x
$cto :: forall (d :: Nat) p r x. Rep (PolyLine d p r) x -> PolyLine d p r
$cfrom :: forall (d :: Nat) p r x. PolyLine d p r -> Rep (PolyLine d p r) x
Generic)

-- | PolyLines are isomorphic to a sequence of points with at least 2 members.
points :: Iso (PolyLine d1 p1 r1) (PolyLine d2 p2 r2) (LSeq 2 (Point d1 r1 :+ p1)) (LSeq 2 (Point d2 r2 :+ p2))
points :: p (LSeq 2 (Point d1 r1 :+ p1)) (f (LSeq 2 (Point d2 r2 :+ p2)))
-> p (PolyLine d1 p1 r1) (f (PolyLine d2 p2 r2))
points = (PolyLine d1 p1 r1 -> LSeq 2 (Point d1 r1 :+ p1))
-> (LSeq 2 (Point d2 r2 :+ p2) -> PolyLine d2 p2 r2)
-> Iso
     (PolyLine d1 p1 r1)
     (PolyLine d2 p2 r2)
     (LSeq 2 (Point d1 r1 :+ p1))
     (LSeq 2 (Point d2 r2 :+ p2))
forall s a b t. (s -> a) -> (b -> t) -> Iso s t a b
iso (\(PolyLine LSeq 2 (Point d1 r1 :+ p1)
s) -> LSeq 2 (Point d1 r1 :+ p1)
s) LSeq 2 (Point d2 r2 :+ p2) -> PolyLine d2 p2 r2
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine

deriving instance (Show r, Show p, Arity d) => Show    (PolyLine d p r)
deriving instance (Eq r, Eq p, Arity d)     => Eq      (PolyLine d p r)
deriving instance (Ord r, Ord p, Arity d)   => Ord     (PolyLine d p r)

instance Arity d => Functor (PolyLine d p) where
  fmap :: (a -> b) -> PolyLine d p a -> PolyLine d p b
fmap a -> b
f (PolyLine LSeq 2 (Point d a :+ p)
ps) = LSeq 2 (Point d b :+ p) -> PolyLine d p b
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine (LSeq 2 (Point d b :+ p) -> PolyLine d p b)
-> LSeq 2 (Point d b :+ p) -> PolyLine d p b
forall a b. (a -> b) -> a -> b
$ ((Point d a :+ p) -> Point d b :+ p)
-> LSeq 2 (Point d a :+ p) -> LSeq 2 (Point d b :+ p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Point d a -> Point d b) -> (Point d a :+ p) -> Point d b :+ p
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first ((a -> b) -> Point d a -> Point d b
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap a -> b
f)) LSeq 2 (Point d a :+ p)
ps

type instance Dimension (PolyLine d p r) = d
type instance NumType   (PolyLine d p r) = r

instance Semigroup (PolyLine d p r) where
  (PolyLine LSeq 2 (Point d r :+ p)
pts) <> :: PolyLine d p r -> PolyLine d p r -> PolyLine d p r
<> (PolyLine LSeq 2 (Point d r :+ p)
pts') = LSeq 2 (Point d r :+ p) -> PolyLine d p r
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine (LSeq 2 (Point d r :+ p) -> PolyLine d p r)
-> LSeq 2 (Point d r :+ p) -> PolyLine d p r
forall a b. (a -> b) -> a -> b
$ LSeq 2 (Point d r :+ p)
pts LSeq 2 (Point d r :+ p)
-> LSeq 2 (Point d r :+ p) -> LSeq 2 (Point d r :+ p)
forall a. Semigroup a => a -> a -> a
<> LSeq 2 (Point d r :+ p)
pts'

instance Arity d => IsBoxable (PolyLine d p r) where
  boundingBox :: PolyLine d p r
-> Box (Dimension (PolyLine d p r)) () (NumType (PolyLine d p r))
boundingBox = NonEmpty (Point d r) -> Box d () r
forall g (c :: * -> *).
(IsBoxable g, Foldable1 c, Ord (NumType g), Arity (Dimension g)) =>
c g -> Box (Dimension g) () (NumType g)
boundingBoxList (NonEmpty (Point d r) -> Box d () r)
-> (PolyLine d p r -> NonEmpty (Point d r))
-> PolyLine d p r
-> Box d () r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Point d r] -> NonEmpty (Point d r)
forall a. [a] -> NonEmpty a
NE.fromList ([Point d r] -> NonEmpty (Point d r))
-> (PolyLine d p r -> [Point d r])
-> PolyLine d p r
-> NonEmpty (Point d r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Getting (Endo [Point d r]) (PolyLine d p r) (Point d r)
-> PolyLine d p r -> [Point d r]
forall a s. Getting (Endo [a]) s a -> s -> [a]
toListOf ((LSeq 2 (Point d r :+ p)
 -> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p)))
-> PolyLine d p r -> Const (Endo [Point d r]) (PolyLine d p r)
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points((LSeq 2 (Point d r :+ p)
  -> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p)))
 -> PolyLine d p r -> Const (Endo [Point d r]) (PolyLine d p r))
-> ((Point d r -> Const (Endo [Point d r]) (Point d r))
    -> LSeq 2 (Point d r :+ p)
    -> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p)))
-> Getting (Endo [Point d r]) (PolyLine d p r) (Point d r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.((Point d r :+ p) -> Const (Endo [Point d r]) (Point d r :+ p))
-> LSeq 2 (Point d r :+ p)
-> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse(((Point d r :+ p) -> Const (Endo [Point d r]) (Point d r :+ p))
 -> LSeq 2 (Point d r :+ p)
 -> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p)))
-> ((Point d r -> Const (Endo [Point d r]) (Point d r))
    -> (Point d r :+ p) -> Const (Endo [Point d r]) (Point d r :+ p))
-> (Point d r -> Const (Endo [Point d r]) (Point d r))
-> LSeq 2 (Point d r :+ p)
-> Const (Endo [Point d r]) (LSeq 2 (Point d r :+ p))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Point d r -> Const (Endo [Point d r]) (Point d r))
-> (Point d r :+ p) -> Const (Endo [Point d r]) (Point d r :+ p)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core)

instance (Fractional r, Arity d, Arity (d + 1)) => IsTransformable (PolyLine d p r) where
  transformBy :: Transformation
  (Dimension (PolyLine d p r)) (NumType (PolyLine d p r))
-> PolyLine d p r -> PolyLine d p r
transformBy = Transformation
  (Dimension (PolyLine d p r)) (NumType (PolyLine d p r))
-> PolyLine d p r -> PolyLine d p r
forall (g :: * -> *) r (d :: Nat).
(PointFunctor g, Fractional r, d ~ Dimension (g r), Arity d,
 Arity (d + 1)) =>
Transformation d r -> g r -> g r
transformPointFunctor

instance PointFunctor (PolyLine d p) where
  pmap :: (Point (Dimension (PolyLine d p r)) r
 -> Point (Dimension (PolyLine d p s)) s)
-> PolyLine d p r -> PolyLine d p s
pmap Point (Dimension (PolyLine d p r)) r
-> Point (Dimension (PolyLine d p s)) s
f = ASetter
  (PolyLine d p r)
  (PolyLine d p s)
  (LSeq 2 (Point d r :+ p))
  (LSeq 2 (Point d s :+ p))
-> (LSeq 2 (Point d r :+ p) -> LSeq 2 (Point d s :+ p))
-> PolyLine d p r
-> PolyLine d p s
forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
over ASetter
  (PolyLine d p r)
  (PolyLine d p s)
  (LSeq 2 (Point d r :+ p))
  (LSeq 2 (Point d s :+ p))
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points (((Point d r :+ p) -> Point d s :+ p)
-> LSeq 2 (Point d r :+ p) -> LSeq 2 (Point d s :+ p)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ((Point d r -> Point d s) -> (Point d r :+ p) -> Point d s :+ p
forall (p :: * -> * -> *) a b c.
Bifunctor p =>
(a -> b) -> p a c -> p b c
first Point d r -> Point d s
Point (Dimension (PolyLine d p r)) r
-> Point (Dimension (PolyLine d p s)) s
f))

instance Arity d => Bifunctor (PolyLine d) where
  bimap :: (a -> b) -> (c -> d) -> PolyLine d a c -> PolyLine d b d
bimap = (a -> b) -> (c -> d) -> PolyLine d a c -> PolyLine d b d
forall (t :: * -> * -> *) a b c d.
Bitraversable t =>
(a -> b) -> (c -> d) -> t a c -> t b d
bimapDefault
instance Arity d => Bifoldable (PolyLine d) where
  bifoldMap :: (a -> m) -> (b -> m) -> PolyLine d a b -> m
bifoldMap = (a -> m) -> (b -> m) -> PolyLine d a b -> m
forall (t :: * -> * -> *) m a b.
(Bitraversable t, Monoid m) =>
(a -> m) -> (b -> m) -> t a b -> m
bifoldMapDefault
instance Arity d => Bitraversable (PolyLine d) where
  bitraverse :: (a -> f c) -> (b -> f d) -> PolyLine d a b -> f (PolyLine d c d)
bitraverse a -> f c
f b -> f d
g (PolyLine LSeq 2 (Point d b :+ a)
pts) = LSeq 2 (Point d d :+ c) -> PolyLine d c d
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine (LSeq 2 (Point d d :+ c) -> PolyLine d c d)
-> f (LSeq 2 (Point d d :+ c)) -> f (PolyLine d c d)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> ((Point d b :+ a) -> f (Point d d :+ c))
-> LSeq 2 (Point d b :+ a) -> f (LSeq 2 (Point d d :+ c))
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse ((Point d b -> f (Point d d))
-> (a -> f c) -> (Point d b :+ a) -> f (Point d d :+ c)
forall (t :: * -> * -> *) (f :: * -> *) a c b d.
(Bitraversable t, Applicative f) =>
(a -> f c) -> (b -> f d) -> t a b -> f (t c d)
bitraverse ((b -> f d) -> Point d b -> f (Point d d)
forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
traverse b -> f d
g) a -> f c
f) LSeq 2 (Point d b :+ a)
pts

instance (ToJSON p, ToJSON r, Arity d) => ToJSON (PolyLine d p r) where
    toEncoding :: PolyLine d p r -> Encoding
toEncoding = Options -> PolyLine d p r -> Encoding
forall a.
(Generic a, GToJSON' Encoding Zero (Rep a)) =>
Options -> a -> Encoding
genericToEncoding Options
defaultOptions
instance (FromJSON p, FromJSON r, Arity d, KnownNat d) => FromJSON (PolyLine d p r)

instance HasStart (PolyLine d p r) where
  type StartCore (PolyLine d p r)  = Point d r
  type StartExtra (PolyLine d p r) = p
  start :: ((StartCore (PolyLine d p r) :+ StartExtra (PolyLine d p r))
 -> f (StartCore (PolyLine d p r) :+ StartExtra (PolyLine d p r)))
-> PolyLine d p r -> f (PolyLine d p r)
start = (LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
-> PolyLine d p r -> f (PolyLine d p r)
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points((LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
 -> PolyLine d p r -> f (PolyLine d p r))
-> (((Point d r :+ p) -> f (Point d r :+ p))
    -> LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
-> ((Point d r :+ p) -> f (Point d r :+ p))
-> PolyLine d p r
-> f (PolyLine d p r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.((Point d r :+ p) -> f (Point d r :+ p))
-> LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p))
forall (t :: * -> *) a. Traversable1 t => Lens' (t a) a
head1

instance HasEnd (PolyLine d p r) where
  type EndCore (PolyLine d p r)  = Point d r
  type EndExtra (PolyLine d p r) = p
  end :: ((EndCore (PolyLine d p r) :+ EndExtra (PolyLine d p r))
 -> f (EndCore (PolyLine d p r) :+ EndExtra (PolyLine d p r)))
-> PolyLine d p r -> f (PolyLine d p r)
end = (LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
-> PolyLine d p r -> f (PolyLine d p r)
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points((LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
 -> PolyLine d p r -> f (PolyLine d p r))
-> (((Point d r :+ p) -> f (Point d r :+ p))
    -> LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p)))
-> ((Point d r :+ p) -> f (Point d r :+ p))
-> PolyLine d p r
-> f (PolyLine d p r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.((Point d r :+ p) -> f (Point d r :+ p))
-> LSeq 2 (Point d r :+ p) -> f (LSeq 2 (Point d r :+ p))
forall (t :: * -> *) a. Traversable1 t => Lens' (t a) a
last1

-- | Builds a Polyline from a list of points, if there are sufficiently many points
fromPoints :: [Point d r :+ p] -> Maybe (PolyLine d p r)
fromPoints :: [Point d r :+ p] -> Maybe (PolyLine d p r)
fromPoints = (LSeq 2 (Point d r :+ p) -> PolyLine d p r)
-> Maybe (LSeq 2 (Point d r :+ p)) -> Maybe (PolyLine d p r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap LSeq 2 (Point d r :+ p) -> PolyLine d p r
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine (Maybe (LSeq 2 (Point d r :+ p)) -> Maybe (PolyLine d p r))
-> ([Point d r :+ p] -> Maybe (LSeq 2 (Point d r :+ p)))
-> [Point d r :+ p]
-> Maybe (PolyLine d p r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: Nat) a. KnownNat 2 => LSeq m a -> Maybe (LSeq 2 a)
forall (n :: Nat) (m :: Nat) a.
KnownNat n =>
LSeq m a -> Maybe (LSeq n a)
LSeq.eval @2 (LSeq 0 (Point d r :+ p) -> Maybe (LSeq 2 (Point d r :+ p)))
-> ([Point d r :+ p] -> LSeq 0 (Point d r :+ p))
-> [Point d r :+ p]
-> Maybe (LSeq 2 (Point d r :+ p))
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Point d r :+ p] -> LSeq 0 (Point d r :+ p)
forall (f :: * -> *) a. Foldable f => f a -> LSeq 0 a
LSeq.fromList

-- | pre: The input list contains at least two points
fromPointsUnsafe :: [Point d r :+ p] -> PolyLine d p r
fromPointsUnsafe :: [Point d r :+ p] -> PolyLine d p r
fromPointsUnsafe = LSeq 2 (Point d r :+ p) -> PolyLine d p r
forall (d :: Nat) p r. LSeq 2 (Point d r :+ p) -> PolyLine d p r
PolyLine (LSeq 2 (Point d r :+ p) -> PolyLine d p r)
-> ([Point d r :+ p] -> LSeq 2 (Point d r :+ p))
-> [Point d r :+ p]
-> PolyLine d p r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. C 2 -> LSeq 0 (Point d r :+ p) -> LSeq 2 (Point d r :+ p)
forall (n :: Nat) (proxy :: Nat -> *) (m :: Nat) a.
KnownNat n =>
proxy n -> LSeq m a -> LSeq n a
LSeq.forceLSeq (C 2
forall (n :: Nat). C n
C @ 2) (LSeq 0 (Point d r :+ p) -> LSeq 2 (Point d r :+ p))
-> ([Point d r :+ p] -> LSeq 0 (Point d r :+ p))
-> [Point d r :+ p]
-> LSeq 2 (Point d r :+ p)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Point d r :+ p] -> LSeq 0 (Point d r :+ p)
forall (f :: * -> *) a. Foldable f => f a -> LSeq 0 a
LSeq.fromList

-- | pre: The input list contains at least two points. All extra vields are
-- initialized with mempty.
fromPointsUnsafe' :: (Monoid p) => [Point d r] -> PolyLine d p r
fromPointsUnsafe' :: [Point d r] -> PolyLine d p r
fromPointsUnsafe' = [Point d r :+ p] -> PolyLine d p r
forall (d :: Nat) r p. [Point d r :+ p] -> PolyLine d p r
fromPointsUnsafe ([Point d r :+ p] -> PolyLine d p r)
-> ([Point d r] -> [Point d r :+ p])
-> [Point d r]
-> PolyLine d p r
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Point d r -> Point d r :+ p) -> [Point d r] -> [Point d r :+ p]
forall a b. (a -> b) -> [a] -> [b]
map (Point d r -> p -> Point d r :+ p
forall core extra. core -> extra -> core :+ extra
:+ p
forall a. Monoid a => a
mempty)


-- | We consider the line-segment as closed.
fromLineSegment                     :: LineSegment d p r -> PolyLine d p r
fromLineSegment :: LineSegment d p r -> PolyLine d p r
fromLineSegment ~(LineSegment' Point d r :+ p
p Point d r :+ p
q) = [Point d r :+ p] -> PolyLine d p r
forall (d :: Nat) r p. [Point d r :+ p] -> PolyLine d p r
fromPointsUnsafe [Point d r :+ p
p,Point d r :+ p
q]

-- | Convert to a closed line segment by taking the first two points.
asLineSegment                            :: PolyLine d p r -> LineSegment d p r
asLineSegment :: PolyLine d p r -> LineSegment d p r
asLineSegment (PolyLine (p :<| q :<| _)) = (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
forall (d :: Nat) r p.
(Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
ClosedLineSegment Point d r :+ p
p Point d r :+ p
q

-- | Stricter version of asLineSegment that fails if the Polyline contains more
-- than two points.
asLineSegment'                :: PolyLine d p r -> Maybe (LineSegment d p r)
asLineSegment' :: PolyLine d p r -> Maybe (LineSegment d p r)
asLineSegment' (PolyLine LSeq 2 (Point d r :+ p)
pts) = case LSeq 2 (Point d r :+ p) -> [Point d r :+ p]
forall (t :: * -> *) a. Foldable t => t a -> [a]
F.toList LSeq 2 (Point d r :+ p)
pts of
                                  [Point d r :+ p
p,Point d r :+ p
q] -> LineSegment d p r -> Maybe (LineSegment d p r)
forall a. a -> Maybe a
Just (LineSegment d p r -> Maybe (LineSegment d p r))
-> LineSegment d p r -> Maybe (LineSegment d p r)
forall a b. (a -> b) -> a -> b
$ (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
forall (d :: Nat) r p.
(Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
ClosedLineSegment Point d r :+ p
p Point d r :+ p
q
                                  [Point d r :+ p]
_     -> Maybe (LineSegment d p r)
forall a. Maybe a
Nothing

-- | Computes the edges, as linesegments, of an LSeq
edgeSegments    :: Arity d => PolyLine d p r -> LSeq 1 (LineSegment d p r)
edgeSegments :: PolyLine d p r -> LSeq 1 (LineSegment d p r)
edgeSegments PolyLine d p r
pl = let vs :: LSeq 2 (Point d r :+ p)
vs = PolyLine d p r
plPolyLine d p r
-> Getting
     (LSeq 2 (Point d r :+ p))
     (PolyLine d p r)
     (LSeq 2 (Point d r :+ p))
-> LSeq 2 (Point d r :+ p)
forall s a. s -> Getting a s a -> a
^.Getting
  (LSeq 2 (Point d r :+ p))
  (PolyLine d p r)
  (LSeq 2 (Point d r :+ p))
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points
                  in ((Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r)
-> LSeq 1 (Point d r :+ p)
-> LSeq 1 (Point d r :+ p)
-> LSeq 1 (LineSegment d p r)
forall a b c (n :: Nat).
(a -> b -> c) -> LSeq n a -> LSeq n b -> LSeq n c
LSeq.zipWith (Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
forall (d :: Nat) r p.
(Point d r :+ p) -> (Point d r :+ p) -> LineSegment d p r
ClosedLineSegment (LSeq (1 + 1) (Point d r :+ p) -> LSeq 1 (Point d r :+ p)
forall (n :: Nat) a. LSeq (1 + n) a -> LSeq n a
LSeq.init LSeq 2 (Point d r :+ p)
LSeq (1 + 1) (Point d r :+ p)
vs) (LSeq (1 + 1) (Point d r :+ p) -> LSeq 1 (Point d r :+ p)
forall (n :: Nat) a. LSeq (1 + n) a -> LSeq n a
LSeq.tail LSeq 2 (Point d r :+ p)
LSeq (1 + 1) (Point d r :+ p)
vs)


-- | Linearly interpolate the polyline with a value in the range
-- \([0,n-1]\), where \(n\) is the number of vertices of the polyline.
--
-- running time: \(O(\log n)\)
--
-- >>> interpolatePoly 0.5 myPolyLine
-- Point2 5.0 5.0
-- >>> interpolatePoly 1.5 myPolyLine
-- Point2 10.0 15.0
interpolatePoly      :: (RealFrac r, Arity d) => r -> PolyLine d p r -> Point d r
interpolatePoly :: r -> PolyLine d p r -> Point d r
interpolatePoly r
t PolyLine d p r
pl = let i :: Int
i = r -> Int
forall a b. (RealFrac a, Integral b) => a -> b
floor r
t in case PolyLine d p r -> LSeq 1 (LineSegment d p r)
forall (d :: Nat) p r.
Arity d =>
PolyLine d p r -> LSeq 1 (LineSegment d p r)
edgeSegments PolyLine d p r
plLSeq 1 (LineSegment d p r)
-> Getting
     (First (LineSegment d p r))
     (LSeq 1 (LineSegment d p r))
     (LineSegment d p r)
-> Maybe (LineSegment d p r)
forall s a. s -> Getting (First a) s a -> Maybe a
^?Index (LSeq 1 (LineSegment d p r))
-> Traversal'
     (LSeq 1 (LineSegment d p r)) (IxValue (LSeq 1 (LineSegment d p r)))
forall m. Ixed m => Index m -> Traversal' m (IxValue m)
ix Int
Index (LSeq 1 (LineSegment d p r))
i of
                         Maybe (LineSegment d p r)
Nothing -> PolyLine d p r
plPolyLine d p r
-> Getting (Point d r) (PolyLine d p r) (Point d r) -> Point d r
forall s a. s -> Getting a s a -> a
^.(LSeq 2 (Point d r :+ p)
 -> Const (Point d r) (LSeq 2 (Point d r :+ p)))
-> PolyLine d p r -> Const (Point d r) (PolyLine d p r)
forall (d1 :: Nat) p1 r1 (d2 :: Nat) p2 r2.
Iso
  (PolyLine d1 p1 r1)
  (PolyLine d2 p2 r2)
  (LSeq 2 (Point d1 r1 :+ p1))
  (LSeq 2 (Point d2 r2 :+ p2))
points((LSeq 2 (Point d r :+ p)
  -> Const (Point d r) (LSeq 2 (Point d r :+ p)))
 -> PolyLine d p r -> Const (Point d r) (PolyLine d p r))
-> ((Point d r -> Const (Point d r) (Point d r))
    -> LSeq 2 (Point d r :+ p)
    -> Const (Point d r) (LSeq 2 (Point d r :+ p)))
-> Getting (Point d r) (PolyLine d p r) (Point d r)
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(LSeq 2 (Point d r :+ p) -> Point d r :+ p)
-> Optic'
     (->) (Const (Point d r)) (LSeq 2 (Point d r :+ p)) (Point d r :+ p)
forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to LSeq 2 (Point d r :+ p) -> Point d r :+ p
forall (n :: Nat) a. LSeq (1 + n) a -> a
LSeq.lastOptic'
  (->) (Const (Point d r)) (LSeq 2 (Point d r :+ p)) (Point d r :+ p)
-> ((Point d r -> Const (Point d r) (Point d r))
    -> (Point d r :+ p) -> Const (Point d r) (Point d r :+ p))
-> (Point d r -> Const (Point d r) (Point d r))
-> LSeq 2 (Point d r :+ p)
-> Const (Point d r) (LSeq 2 (Point d r :+ p))
forall b c a. (b -> c) -> (a -> b) -> a -> c
.(Point d r -> Const (Point d r) (Point d r))
-> (Point d r :+ p) -> Const (Point d r) (Point d r :+ p)
forall core extra core'.
Lens (core :+ extra) (core' :+ extra) core core'
core
                         Just LineSegment d p r
e  -> r -> LineSegment d p r -> Point d r
forall r (d :: Nat) p.
(Fractional r, Arity d) =>
r -> LineSegment d p r -> Point d r
interpolate (r
tr -> r -> r
forall a. Num a => a -> a -> a
-Int -> r
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
i) LineSegment d p r
e