module Diagrams.Tangent
( tangentAtParam
, tangentAtStart
, tangentAtEnd
, normalAtParam
, normalAtStart
, normalAtEnd
, Tangent(..)
)
where
import Control.Lens (cloneIso, (^.))
import Data.VectorSpace
import Diagrams.Core
import Diagrams.Located
import Diagrams.Parametric
import Diagrams.Segment
import Diagrams.Trail
import Diagrams.TwoD.Types (R2)
import Diagrams.TwoD.Vector (perp)
newtype Tangent t = Tangent t
type instance V (Tangent t) = V t
instance DomainBounds t => DomainBounds (Tangent t) where
domainLower (Tangent t) = domainLower t
domainUpper (Tangent t) = domainUpper t
type instance Codomain (Tangent (Located t)) = Codomain (Tangent t)
instance Parametric (Tangent t) => Parametric (Tangent (Located t)) where
Tangent l `atParam` p = Tangent (unLoc l) `atParam` p
instance (DomainBounds t, EndValues (Tangent t))
=> EndValues (Tangent (Located t)) where
atStart (Tangent l) = atStart (Tangent (unLoc l))
atEnd (Tangent l) = atEnd (Tangent (unLoc l))
tangentAtParam :: Parametric (Tangent t) => t -> Scalar (V t) -> Codomain (Tangent t)
tangentAtParam t p = Tangent t `atParam` p
tangentAtStart :: EndValues (Tangent t) => t -> Codomain (Tangent t)
tangentAtStart = atStart . Tangent
tangentAtEnd :: EndValues (Tangent t) => t -> Codomain (Tangent t)
tangentAtEnd = atEnd . Tangent
type instance Codomain (Tangent (Segment Closed v)) = Codomain (Segment Closed v)
instance (VectorSpace v, Num (Scalar v))
=> Parametric (Tangent (Segment Closed v)) where
Tangent (Linear (OffsetClosed v)) `atParam` _ = v
Tangent (Cubic c1 c2 (OffsetClosed x2)) `atParam` p
= (3*(3*p*p4*p+1))*^c1 ^+^ (3*(23*p)*p)*^c2 ^+^ (3*p*p)*^x2
instance (VectorSpace v, Num (Scalar v))
=> EndValues (Tangent (Segment Closed v)) where
atStart (Tangent (Linear (OffsetClosed v))) = v
atStart (Tangent (Cubic c1 _ _)) = c1
atEnd (Tangent (Linear (OffsetClosed v))) = v
atEnd (Tangent (Cubic _ c2 (OffsetClosed x2))) = x2 ^-^ c2
type instance Codomain (Tangent (Trail' c v)) = Codomain (Trail' c v)
instance ( Parametric (GetSegment (Trail' c v))
, VectorSpace v
, Num (Scalar v)
)
=> Parametric (Tangent (Trail' c v)) where
Tangent tr `atParam` p =
case GetSegment tr `atParam` p of
Nothing -> zeroV
Just (_, seg, reparam) -> Tangent seg `atParam` (p ^. cloneIso reparam)
instance ( Parametric (GetSegment (Trail' c v))
, EndValues (GetSegment (Trail' c v))
, VectorSpace v
, Num (Scalar v)
)
=> EndValues (Tangent (Trail' c v)) where
atStart (Tangent tr) =
case atStart (GetSegment tr) of
Nothing -> zeroV
Just (_, seg, _) -> atStart (Tangent seg)
atEnd (Tangent tr) =
case atEnd (GetSegment tr) of
Nothing -> zeroV
Just (_, seg, _) -> atEnd (Tangent seg)
type instance Codomain (Tangent (Trail v)) = Codomain (Trail v)
instance ( InnerSpace v
, OrderedField (Scalar v)
, RealFrac (Scalar v)
)
=> Parametric (Tangent (Trail v)) where
Tangent tr `atParam` p
= withTrail
((`atParam` p) . Tangent)
((`atParam` p) . Tangent)
tr
instance ( InnerSpace v
, OrderedField (Scalar v)
, RealFrac (Scalar v)
)
=> EndValues (Tangent (Trail v)) where
atStart (Tangent tr) = withTrail (atStart . Tangent) (atStart . Tangent) tr
atEnd (Tangent tr) = withTrail (atEnd . Tangent) (atEnd . Tangent) tr
normalAtParam
:: (Codomain (Tangent t) ~ R2, Parametric (Tangent t))
=> t -> Scalar (V t) -> R2
normalAtParam t p = normize (t `tangentAtParam` p)
normalAtStart
:: (Codomain (Tangent t) ~ R2, EndValues (Tangent t))
=> t -> R2
normalAtStart = normize . tangentAtStart
normalAtEnd
:: (Codomain (Tangent t) ~ R2, EndValues (Tangent t))
=> t -> R2
normalAtEnd = normize . tangentAtEnd
normize :: R2 -> R2
normize = negateV . perp . normalized