--------------------------------------------------------------------------------
-- |
-- Module      :  HGeometry.PolyLine.Class
-- Copyright   :  (C) Frank Staals
-- License     :  see the LICENSE file
-- Maintainer  :  Frank Staals
--
-- A Polyline class and some basic functions to interact with them.
--
--------------------------------------------------------------------------------
module HGeometry.PolyLine.Class
  ( PolyLine_
  , ConstructablePolyLine_(..)
  , _PolyLineLineSegment
  ) where

import           Control.Lens
import qualified Data.List.NonEmpty as NonEmpty
import           Data.Semigroup.Foldable
import           HGeometry.LineSegment.Class
import           HGeometry.Point.Class
import           HGeometry.Properties
import           Hiraffe.Graph

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

-- | A class representing PolyLines
class ( HasVertices polyLine polyLine
      , HasPoints' polyLine point
      , HasStart polyLine point
      , HasEnd polyLine point
      , Vertex polyLine ~ point
      , Point_ point (Dimension point) (NumType point)
      , NumType polyLine ~ NumType point
      , Dimension polyLine ~ Dimension point
      ) => PolyLine_ polyLine point | polyLine -> point where

-- | Class for constructable polylglines
class PolyLine_ polyLine point => ConstructablePolyLine_ polyLine point where

  -- | Constructs a polyline from a given sequence of points.
  --
  -- pre: there should be at least two distinct points
  polyLineFromPoints :: Foldable1 f => f point -> polyLine


-- maybe make these two functions into a prism instead

-- | Prism between a polyline and a line segment
_PolyLineLineSegment :: ( ConstructableLineSegment_ lineSegment point
                        , ConstructablePolyLine_ polyLine point
                        ) => Prism' polyLine lineSegment
_PolyLineLineSegment :: forall lineSegment point polyLine.
(ConstructableLineSegment_ lineSegment point,
 ConstructablePolyLine_ polyLine point) =>
Prism' polyLine lineSegment
_PolyLineLineSegment = (lineSegment -> polyLine)
-> (polyLine -> Maybe lineSegment)
-> Prism polyLine polyLine lineSegment lineSegment
forall b s a. (b -> s) -> (s -> Maybe a) -> Prism s s a b
prism' lineSegment -> polyLine
forall {b} {s}.
(NumType (Vertex b) ~ NumType b,
 Dimension (Vertex b) ~ Dimension b,
 ConstructablePolyLine_ b (Vertex b), HasStart s (Vertex b),
 HasEnd s (Vertex b),
 Point_ (Vertex b) (Dimension b) (NumType b)) =>
s -> b
lineSegmentToPolyLine polyLine -> Maybe lineSegment
forall {a} {s}.
(Dimension (IxValue (EndPointOf a)) ~ Dimension a,
 NumType (IxValue (EndPointOf a)) ~ NumType a, HasVertices s s,
 ConstructableLineSegment_ a (IxValue (EndPointOf a)),
 HasStart s (IxValue (EndPointOf a)),
 HasEnd s (IxValue (EndPointOf a))) =>
s -> Maybe a
polyLineToLineSegment
  where
    lineSegmentToPolyLine :: s -> b
lineSegmentToPolyLine s
s = NonEmpty (Vertex b) -> b
forall polyLine point (f :: * -> *).
(ConstructablePolyLine_ polyLine point, Foldable1 f) =>
f point -> polyLine
forall (f :: * -> *). Foldable1 f => f (Vertex b) -> b
polyLineFromPoints (NonEmpty (Vertex b) -> b)
-> ([Vertex b] -> NonEmpty (Vertex b)) -> [Vertex b] -> b
forall b c a. (b -> c) -> (a -> b) -> a -> c
. [Vertex b] -> NonEmpty (Vertex b)
forall a. HasCallStack => [a] -> NonEmpty a
NonEmpty.fromList ([Vertex b] -> b) -> [Vertex b] -> b
forall a b. (a -> b) -> a -> b
$ [s
ss -> Getting (Vertex b) s (Vertex b) -> Vertex b
forall s a. s -> Getting a s a -> a
^.Getting (Vertex b) s (Vertex b)
forall seg p. HasStart seg p => Lens' seg p
Lens' s (Vertex b)
start, s
ss -> Getting (Vertex b) s (Vertex b) -> Vertex b
forall s a. s -> Getting a s a -> a
^.Getting (Vertex b) s (Vertex b)
forall seg p. HasEnd seg p => Lens' seg p
Lens' s (Vertex b)
end]

    polyLineToLineSegment :: s -> Maybe a
polyLineToLineSegment s
pl
      | Getting (Endo (Endo Int)) s (Vertex s) -> s -> Int
forall s a. Getting (Endo (Endo Int)) s a -> s -> Int
lengthOf Getting (Endo (Endo Int)) s (Vertex s)
forall graph graph'.
HasVertices graph graph' =>
IndexedTraversal1
  (VertexIx graph) graph graph' (Vertex graph) (Vertex graph')
IndexedTraversal1 (VertexIx s) s s (Vertex s) (Vertex s)
vertices s
pl Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
== Int
2 = a -> Maybe a
forall a. a -> Maybe a
Just (a -> Maybe a) -> a -> Maybe a
forall a b. (a -> b) -> a -> b
$ IxValue (EndPointOf a) -> IxValue (EndPointOf a) -> a
forall lineSegment point.
ConstructableLineSegment_ lineSegment point =>
point -> point -> lineSegment
uncheckedLineSegment (s
pls
-> Getting (IxValue (EndPointOf a)) s (IxValue (EndPointOf a))
-> IxValue (EndPointOf a)
forall s a. s -> Getting a s a -> a
^.Getting (IxValue (EndPointOf a)) s (IxValue (EndPointOf a))
forall seg p. HasStart seg p => Lens' seg p
Lens' s (IxValue (EndPointOf a))
start) (s
pls
-> Getting (IxValue (EndPointOf a)) s (IxValue (EndPointOf a))
-> IxValue (EndPointOf a)
forall s a. s -> Getting a s a -> a
^.Getting (IxValue (EndPointOf a)) s (IxValue (EndPointOf a))
forall seg p. HasEnd seg p => Lens' seg p
Lens' s (IxValue (EndPointOf a))
end)
      | Bool
otherwise                 = Maybe a
forall a. Maybe a
Nothing