-- | -- Module : Cartesian.Internal.Core -- Description : Defines basic functionality that is shared between Plane and Space -- Copyright : (c) Jonatan H Sundqvist, 2015 -- License : MIT -- Maintainer : Jonatan H Sundqvist -- Stability : experimental|stable -- Portability : POSIX (not sure) -- -- Created October 31 2015 -- TODO | - -- - -- SPEC | - -- - ------------------------------------------------------------------------------------------------------------------------------------------------------ -- GHC Pragmas ------------------------------------------------------------------------------------------------------------------------------------------------------ {-# LANGUAGE FlexibleInstances #-} ------------------------------------------------------------------------------------------------------------------------------------------------------ -- API ------------------------------------------------------------------------------------------------------------------------------------------------------ module Cartesian.Internal.Core (module Cartesian.Internal.Core, module Cartesian.Internal.Types) where ------------------------------------------------------------------------------------------------------------------------------------------------------ -- We'll need these ------------------------------------------------------------------------------------------------------------------------------------------------------ import Data.List (sort) import Control.Lens ((^.)) import Control.Applicative import Cartesian.Internal.Types import Cartesian.Internal.Utils import Cartesian.Internal.Lenses ------------------------------------------------------------------------------------------------------------------------------------------------------ -- Functions ------------------------------------------------------------------------------------------------------------------------------------------------------ -- | Finds the overlap between two ranges (lower bound, upper bound). -- | Yields the overlap of two closed intervals (n ∈ R) -- TODO: Normalise intervals (eg. (12, 5) -> (5, 12)) -- TODO: Type for intervals (which would also encode the 'openness' of the lower and upper limits) overlap :: (Ord n) => (n, n) -> (n, n) -> Maybe (n, n) overlap (a, b) (c, d) | min (a, b) (c, d) /= (a', b') = Just (b', c') | otherwise = Nothing where [a', b', c', d'] = sort [a, b, c, d] -- TODO: Silence the non-exhaustive warning -- Vectors --------------------------------------------------------------------------------------------------------------------------------- -- | Cross product -- cross :: (Vector v, Num f) => v f -> v f -> v f -- cross a b = _ -- | Euclidean distance between two points -- euclidean :: (Vector v, Floating f) => v f -> v f -> f -- euclidean a b = sqrt $ dot a b -- -- | -- magnitude :: (Vector v, Floating f) => v f -> f -- magnitude v = euclidean v v -- -- | -- mag :: (Vector v, Floating f) => v f -> f -- mag = magnitude ------------------------------------------------------------------------------------------------------------------------------------------------------ -- | Vector -> (magnitude, argument) -- polar :: (Floating a, Eq a) => Vector a -> (a, a) -- polar v@(Vector x y) = (magnitude v, argument v) -- -- -- -- | Yields the overlap of two closed intervals (n ∈ R) -- -- TODO: Normalise intervals (eg. (12, 5) -> (5, 12)) -- overlap :: Real a => (a, a) -> (a, a) -> Maybe (a, a) -- overlap a b -- | leftmost /= (α, β) = Just $ (β, γ) -- -- | otherwise = Nothing -- -- where [α, β, γ, _] = sort [fst a, snd a, fst b, snd b] -- That's right. -- leftmost = minimumBy (comparing fst) [a, b] -- -- Convenience constructors ---------------------------------------------------------------------------------------------------------------- -- TODO: Generalise constructors, move to Internal.Core (✓) -- | Creates a bounding box from two opposite corners -- TODO: Better name (?) -- TODO: Don't make assumptions about WHICH corners they are (✓) -- TODO: Should we care about degenerate cases (such as 'a' and 'b' being identical) fromCorners :: (Applicative v, Num n, Ord n) => v n -> v n -> BoundingBox (v n) fromCorners a b = BoundingBox { cornerOf = min <$> a <*> b, sizeOf = abs <$> liftA2 (-) b a } -- | fromAxes :: (Applicative v) => Axes v n -> BoundingBox (v n) fromAxes axes' = let (begin', size') = unzipA axes' in BoundingBox { cornerOf = begin', sizeOf = size' } -- | Top Left Bottom Right fromExtents :: (Applicative v, Num n) => Axes v n -> BoundingBox (v n) fromExtents extents' = let (begin', end') = unzipA extents' in BoundingBox { cornerOf = begin', sizeOf = liftA2 (-) end' begin' } -- Booleans -------------------------------------------------------------------------------------------------------------------------------- -- | Finds the intersection (boolean AND) of two bounding boxes intersect :: (Applicative v, Traversable v, Ord n, Num n) => BoundingBox (v n) -> BoundingBox (v n) -> Maybe (BoundingBox (v n)) intersect a b = do overlaps' <- traverse (uncurry overlap) (zipA (a^.extents) (b^.extents)) return $ fromExtents overlaps'