{-# LANGUAGE GADTs #-} -- for ghc < 7.8, TypeFamilies covers GADT patten mathcing in > 7.8 {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} ----------------------------------------------------------------------------- -- | -- Module : Diagrams.Tangent -- Copyright : (c) 2013 diagrams-lib team (see LICENSE) -- License : BSD-style (see LICENSE) -- Maintainer : diagrams-discuss@googlegroups.com -- -- Computing tangent and normal vectors for segments and trails. -- ----------------------------------------------------------------------------- module Diagrams.Tangent ( -- ** Tangents tangentAtParam , tangentAtStart , tangentAtEnd -- ** Normals , normalAtParam , normalAtStart , normalAtEnd -- ** Tangent newtype , Tangent(..) ) where import Diagrams.Core import Diagrams.Located import Diagrams.Parametric import Diagrams.Segment import Linear.Vector import Linear.Metric import Linear.V2 ------------------------------------------------------------ -- Tangent ------------------------------------------------------------ -- | A newtype wrapper used to give different instances of -- 'Parametric' and 'EndValues' that compute tangent vectors. newtype Tangent t = Tangent t type instance V (Tangent t) = V t type instance N (Tangent t) = N t type instance Codomain (Tangent t) = V t instance DomainBounds t => DomainBounds (Tangent t) where domainLower (Tangent t) = domainLower t domainUpper (Tangent t) = domainUpper 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)) -- | Compute the tangent vector to a segment or trail at a particular -- parameter. -- -- Examples of more specific types this function can have include -- -- * @Segment Closed V2 -> Double -> V2 Double@ -- -- * @Trail' Line V2 -> Double -> V2 Double@ -- -- * @Located (Trail V2) -> Double -> V2 Double@ -- -- See the instances listed for the 'Tangent' newtype for more. tangentAtParam :: Parametric (Tangent t) => t -> N t -> Vn t tangentAtParam t p = Tangent t `atParam` p -- | Compute the tangent vector at the start of a segment or trail. tangentAtStart :: EndValues (Tangent t) => t -> Vn t tangentAtStart = atStart . Tangent -- | Compute the tangent vector at the end of a segment or trail. tangentAtEnd :: EndValues (Tangent t) => t -> Vn t tangentAtEnd = atEnd . Tangent -------------------------------------------------- -- Segment instance (Additive v, Num n) => Parametric (Tangent (Segment Closed v n)) where Tangent (Linear (OffsetClosed v)) `atParam` _ = v Tangent (Cubic c1 c2 (OffsetClosed x2)) `atParam` p = (3*(3*p*p-4*p+1))*^c1 ^+^ (3*(2-3*p)*p)*^c2 ^+^ (3*p*p)*^x2 instance (Additive v, Num n) => EndValues (Tangent (Segment Closed v n)) 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 instance (Additive v, Num n) => Parametric (Tangent (FixedSegment v n)) where atParam (Tangent fSeg) = atParam $ Tangent (fromFixedSeg fSeg) instance (Additive v, Num n) => EndValues (Tangent (FixedSegment v n)) where atStart (Tangent fSeg) = atStart $ Tangent (fromFixedSeg fSeg) atEnd (Tangent fSeg) = atEnd $ Tangent (fromFixedSeg fSeg) ------------------------------------------------------------ -- Normal ------------------------------------------------------------ -- | Compute the (unit) normal vector to a segment or trail at a -- particular parameter. -- -- Examples of more specific types this function can have include -- -- * @Segment Closed V2 Double -> Double -> V2 Double@ -- -- * @Trail' Line V2 Double -> Double -> V2 Double@ -- -- * @Located (Trail V2 Double) -> Double -> V2 Double@ -- -- See the instances listed for the 'Tangent' newtype for more. normalAtParam :: (InSpace V2 n t, Parametric (Tangent t), Floating n) => t -> n -> V2 n normalAtParam t p = normize (t `tangentAtParam` p) -- | Compute the normal vector at the start of a segment or trail. normalAtStart :: (InSpace V2 n t, EndValues (Tangent t), Floating n) => t -> V2 n normalAtStart = normize . tangentAtStart -- | Compute the normal vector at the end of a segment or trail. normalAtEnd :: (InSpace V2 n t, EndValues (Tangent t), Floating n) => t -> V2 n normalAtEnd = normize . tangentAtEnd -- | Construct a normal vector from a tangent. normize :: Floating n => V2 n -> V2 n normize = negated . perp . signorm