{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE UndecidableInstances #-}
module Data.Geometry.Point.Internal
( Point(..)
, origin, vector
, pointFromList
, coord , unsafeCoord
, projectPoint
, pattern Point1
, pattern Point2
, pattern Point3
, PointFunctor(..)
, cmpByDistanceTo
, squaredEuclideanDist, euclideanDist
) where
import Control.DeepSeq
import Control.Lens
import Data.Aeson
import Data.Ext
import qualified Data.Foldable as F
import Data.Geometry.Properties
import Data.Geometry.Vector
import qualified Data.Geometry.Vector as Vec
import Data.Hashable
import Data.Ord (comparing)
import Data.Proxy
import GHC.Generics (Generic)
import GHC.TypeLits
import System.Random (Random(..))
import Test.QuickCheck (Arbitrary)
import Text.ParserCombinators.ReadP (ReadP, string,pfail)
import Text.ParserCombinators.ReadPrec (lift)
import Text.Read (Read(..),readListPrecDefault, readPrec_to_P,minPrec)
newtype Point d r = Point { toVec :: Vector d r } deriving (Generic)
instance (Show r, Arity d) => Show (Point d r) where
show (Point v) = mconcat [ "Point", show $ F.length v , " "
, show $ F.toList v
]
instance (Read r, Arity d) => Read (Point d r) where
readPrec = lift readPt
readListPrec = readListPrecDefault
readPt :: forall d r. (Arity d, Read r) => ReadP (Point d r)
readPt = do let d = natVal (Proxy :: Proxy d)
_ <- string $ "Point" <> show d <> " "
rs <- readPrec_to_P readPrec minPrec
case pointFromList rs of
Just p -> pure p
_ -> pfail
deriving instance (Eq r, Arity d) => Eq (Point d r)
deriving instance (Ord r, Arity d) => Ord (Point d r)
deriving instance Arity d => Functor (Point d)
deriving instance Arity d => Foldable (Point d)
deriving instance Arity d => Traversable (Point d)
deriving instance (Arity d, NFData r) => NFData (Point d r)
deriving instance (Arity d, Arbitrary r) => Arbitrary (Point d r)
deriving instance (Arity d, Hashable r) => Hashable (Point d r)
deriving instance (Arity d, Random r) => Random (Point d r)
type instance NumType (Point d r) = r
type instance Dimension (Point d r) = d
instance Arity d => Affine (Point d) where
type Diff (Point d) = Vector d
p .-. q = toVec p ^-^ toVec q
p .+^ v = Point $ toVec p ^+^ v
instance (FromJSON r, Arity d, KnownNat d) => FromJSON (Point d r) where
parseJSON = fmap Point . parseJSON
instance (ToJSON r, Arity d) => ToJSON (Point d r) where
toJSON = toJSON . toVec
toEncoding = toEncoding . toVec
origin :: (Arity d, Num r) => Point d r
origin = Point $ pure 0
vector :: Lens' (Point d r) (Vector d r)
vector = lens toVec (const Point)
{-# INLINABLE vector #-}
unsafeCoord :: Arity d => Int -> Lens' (Point d r) r
unsafeCoord i = vector . singular (ix (i-1))
{-# INLINABLE unsafeCoord #-}
coord :: forall proxy i d r. (1 <= i, i <= d, Arity d, KnownNat i)
=> proxy i -> Lens' (Point d r) r
coord _ = unsafeCoord $ fromIntegral (natVal $ C @i)
{-# INLINABLE coord #-}
pointFromList :: Arity d => [r] -> Maybe (Point d r)
pointFromList = fmap Point . Vec.vectorFromList
projectPoint :: (Arity i, Arity d, i <= d) => Point d r -> Point i r
projectPoint = Point . prefix . toVec
pattern Point1 :: r -> Point 1 r
pattern Point1 x = Point (Vector1 x)
{-# COMPLETE Point1 #-}
pattern Point2 :: r -> r -> Point 2 r
pattern Point2 x y = Point (Vector2 x y)
{-# COMPLETE Point2 #-}
pattern Point3 :: r -> r -> r -> Point 3 r
pattern Point3 x y z = (Point (Vector3 x y z))
{-# COMPLETE Point3 #-}
class PointFunctor g where
pmap :: (Point (Dimension (g r)) r -> Point (Dimension (g s)) s) -> g r -> g s
instance PointFunctor (Point d) where
pmap f = f
cmpByDistanceTo :: (Ord r, Num r, Arity d)
=> Point d r :+ c -> Point d r :+ p -> Point d r :+ q -> Ordering
cmpByDistanceTo (c :+ _) p q = comparing (squaredEuclideanDist c) (p^.core) (q^.core)
squaredEuclideanDist :: (Num r, Arity d) => Point d r -> Point d r -> r
squaredEuclideanDist = qdA
euclideanDist :: (Floating r, Arity d) => Point d r -> Point d r -> r
euclideanDist = distanceA