{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE UndecidableInstances #-} module Data.Geometry.Vector.VectorFixed where import Control.DeepSeq import Control.Lens hiding (element) import Data.Aeson import qualified Data.Foldable as F import Data.Proxy import qualified Data.Vector.Fixed as V import Data.Vector.Fixed (Arity) import Data.Vector.Fixed.Boxed import GHC.Generics (Generic) import GHC.TypeLits import Linear.Affine (Affine(..)) import Linear.Metric import qualified Linear.V2 as L2 import qualified Linear.V3 as L3 import Linear.Vector -------------------------------------------------------------------------------- -- | A proxy which can be used for the coordinates. data C (n :: Nat) = C deriving (Show,Read,Eq,Ord) -------------------------------------------------------------------------------- -- * d dimensional Vectors -- | Datatype representing d dimensional vectors. Our implementation wraps the -- implementation provided by fixed-vector. newtype Vector (d :: Nat) (r :: *) = Vector { _unV :: Vec d r } deriving (Generic) unV :: Lens' (Vector d r) (Vec d r) unV = lens _unV (const Vector) ---------------------------------------- -- | Lens into the i th element element :: forall proxy i d r. (Arity d, Arity i, (i + 1) <= d) => proxy i -> Lens' (Vector d r) r element _ = V.elementTy (Proxy :: Proxy i) -- | Similar to 'element' above. Except that we don't have a static guarantee -- that the index is in bounds. Hence, we can only return a Traversal element' :: forall d r. Arity d => Int -> Traversal' (Vector d r) r element' i f v | 0 <= i && i < fromInteger (natVal (C :: C d)) = f (v V.! i) <&> \a -> (v&V.element i .~ a) -- Implementation based on that of Ixed Vector in Control.Lens.At | otherwise = pure v vectorFromList :: Arity d => [a] -> Maybe (Vector d a) vectorFromList = fmap Vector . V.fromListM vectorFromListUnsafe :: Arity d => [a] -> Vector d a vectorFromListUnsafe = Vector . V.fromList instance (Show r, Arity d) => Show (Vector d r) where show (Vector v) = mconcat [ "Vector", show $ V.length v , " " , show $ F.toList v ] deriving instance (Eq r, Arity d) => Eq (Vector d r) deriving instance (Ord r, Arity d) => Ord (Vector d r) -- deriving instance Arity d => Functor (Vector d) -- for some weird reason, implemeting this myself yields is faster code instance Arity d => Functor (Vector d) where fmap f (Vector v) = Vector $ fmap f v deriving instance Arity d => Foldable (Vector d) deriving instance Arity d => Applicative (Vector d) instance Arity d => Traversable (Vector d) where traverse f (Vector v) = Vector <$> traverse f v deriving instance (Arity d, NFData r) => NFData (Vector d r) instance Arity d => Additive (Vector d) where zero = pure 0 (Vector u) ^+^ (Vector v) = Vector $ V.zipWith (+) u v instance Arity d => Affine (Vector d) where type Diff (Vector d) = Vector d u .-. v = u ^-^ v p .+^ v = p ^+^ v instance Arity d => Metric (Vector d) type instance V.Dim (Vector d) = d instance Arity d => V.Vector (Vector d) r where construct = Vector <$> V.construct inspect = V.inspect . _unV basicIndex = V.basicIndex . _unV instance (FromJSON r, Arity d, KnownNat d) => FromJSON (Vector d r) where parseJSON y = parseJSON y >>= \xs -> case vectorFromList xs of Nothing -> fail . mconcat $ [ "FromJSON (Vector d a), wrong number of elements. Expected " , show $ natVal (Proxy :: Proxy d) , " elements but found " , show $ length xs , "." ] Just v -> pure v instance (ToJSON r, Arity d) => ToJSON (Vector d r) where toJSON = toJSON . F.toList toEncoding = toEncoding . F.toList ------------------------------------------ -- | Get the head and tail of a vector destruct :: (Arity d, Arity (d + 1), 1 <= (d + 1)) => Vector (d + 1) r -> (r, Vector d r) destruct (Vector v) = (V.head v, Vector $ V.tail v) -- | Cross product of two three-dimensional vectors cross :: Num r => Vector 3 r -> Vector 3 r -> Vector 3 r u `cross` v = fromV3 $ (toV3 u) `L3.cross` (toV3 v) -------------------------------------------------------------------------------- -- | Vonversion to a Linear.V2 toV2 :: Vector 2 a -> L2.V2 a toV2 ~(Vector2 a b) = L2.V2 a b -- | Conversion to a Linear.V3 toV3 :: Vector 3 a -> L3.V3 a toV3 ~(Vector3 a b c) = L3.V3 a b c -- | Conversion from a Linear.V3 fromV3 :: L3.V3 a -> Vector 3 a fromV3 (L3.V3 a b c) = v3 a b c ---------------------------------------------------------------------------------- -- | Add an element at the back of the vector snoc :: (Arity (d + 1), Arity d) => Vector d r -> r -> Vector (d + 1) r snoc = flip V.snoc -- | Get a vector of the first d - 1 elements. init :: (Arity d, Arity (d + 1)) => Vector (d + 1) r -> Vector d r init = Vector . V.reverse . V.tail . V.reverse . _unV last :: forall d r. (Arity d, Arity (d + 1)) => Vector (d + 1) r -> r last = view $ element (Proxy :: Proxy d) -- | Get a prefix of i elements of a vector prefix :: forall i d r. (Arity d, Arity i, i <= d) => Vector d r -> Vector i r prefix = let i = fromInteger . natVal $ (Proxy :: Proxy i) in V.fromList . take i . V.toList -------------------------------------------------------------------------------- -- * Functions specific to two and three dimensional vectors. -- | Construct a 2 dimensional vector v2 :: r -> r -> Vector 2 r v2 a b = Vector $ V.mk2 a b -- | Construct a 3 dimensional vector v3 :: r -> r -> r -> Vector 3 r v3 a b c = Vector $ V.mk3 a b c -- | Destruct a 2 dim vector into a pair _unV2 :: Vector 2 r -> (r,r) _unV2 v = let [x,y] = V.toList v in (x,y) _unV3 :: Vector 3 r -> (r,r,r) _unV3 v = let [x,y,z] = V.toList v in (x,y,z) -- | Pattern synonym for two and three dim vectors pattern Vector2 :: r -> r -> Vector 2 r pattern Vector2 x y <- (_unV2 -> (x,y)) where Vector2 x y = v2 x y {-# COMPLETE Vector2 #-} pattern Vector3 :: r -> r -> r -> Vector 3 r pattern Vector3 x y z <- (_unV3 -> (x,y,z)) where Vector3 x y z = v3 x y z {-# COMPLETE Vector3 #-} pattern Vector4 :: r -> r -> r -> r -> Vector 4 r pattern Vector4 x y z a <- (V.toList -> [x,y,z,a]) where Vector4 x y z a = V.mk4 x y z a {-# COMPLETE Vector4 #-}