packages feed

Cartesian 0.2.1.0 → 0.5.0.0

raw patch · 16 files changed

+483/−776 lines, 16 filesdep +linear

Dependencies added: linear

Files

Cartesian.cabal view
@@ -10,7 +10,7 @@ -- PVP summary:      +-+------- breaking API changes
 --                   | | +----- non-breaking API additions
 --                   | | | +--- code changes with no API change
-version:             0.2.1.0
+version:             0.5.0.0
 
 -- A short (one-line) description of the package.
 synopsis:            Coordinate systems
@@ -48,20 +48,31 @@ 
 library
   -- Modules exported by the library.
-  exposed-modules:     Cartesian.Plane,       Cartesian.Space, Cartesian.Types,
-                       Cartesian.Plane.Types, Cartesian.Plane.Lenses,
-                       Cartesian.Space.Types, Cartesian.Space.Lenses
+  exposed-modules:     Cartesian.Types, Cartesian.Core, Cartesian.Lenses
 
   -- Modules included in this library but not exported.
 
-  other-modules:       Cartesian.Internal.Types, Cartesian.Internal.Lenses, Cartesian.Internal.Core, Cartesian.Internal.Utils
+  other-modules:       Cartesian.Internal.Types, Cartesian.Internal.Instances, Cartesian.Internal.Lenses, Cartesian.Internal.Core, Cartesian.Internal.Utils
 
   -- LANGUAGE extensions used by modules in this package.
   other-extensions:    TemplateHaskell, RankNTypes, MultiParamTypeClasses, FlexibleInstances
 
+  --
+  ghc-options:         -fwarn-tabs
+                       -fwarn-unused-imports
+                       -fwarn-name-shadowing
+                       -fwarn-incomplete-uni-patterns
+                       -fwarn-incomplete-patterns
+                       -fwarn-overlapping-patterns
+                       -fwarn-incomplete-record-updates
+                       -fwarn-missing-signatures
+                       -fwarn-monomorphism-restriction
+                       -fwarn-orphans
+                       
   -- Other library packages from which modules are imported.
   build-depends:       base == 4.*,
                        lens <= 4.13.0.0,
+                       linear,
                        template-haskell
 
   -- Directories containing source files.
README.md view
@@ -2,7 +2,7 @@ =========
 Functions and types for working with three-dimensional coordinate systems.
 
-For now, all functions assume a coordinate system where right is +X, up is +Y and forwards is +Z.
+For now, all functions assume a coordinate system where right is +X, up is +Y and forwards is +Z, unless otherwise stated.
 
 Contributors
 ------------
@@ -11,6 +11,10 @@ 
 TODO
 ----
-- Use typeclass for Vectors (would save a lot of boilerplate)
-- Allow functions to operate on any Vector-like type (including eg. Complex)
-- Consistent naming scheme (eg. use Vector(2D|3D) or just Vector for both types)
+- [x] Use typeclass for Vectors (would save a lot of boilerplate)
+      -- [ ] Replace 'Vector' with more specific classes, depending on the use case
+      -- [ ] Perhaps 'Vector' could be an alias for types that support all vector ops
+- [x] Allow functions to operate on any Vector-like type (including eg. Complex) (cf. the `Vector`-typeclass)
+- [ ] Consistent naming scheme (eg. use Vector(2D|3D) or just Vector for both types)
+
+- [ ] Decide on a public API (right now, exports are a mess)
+ src/Cartesian/Core.hs view
@@ -0,0 +1,50 @@+-- |
+-- Module      : Cartesian.Core
+-- Description : Exports the core functionality of this package
+-- Copyright   : (c) Jonatan H Sundqvist, 2016
+-- License     : MIT
+-- Maintainer  : Jonatan H Sundqvist
+-- Stability   : experimental|stable
+-- Portability : POSIX (not sure)
+--
+
+-- Created September 24 2016
+
+-- TODO | -
+--        -
+
+-- SPEC | -
+--        -
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- GHC Pragmas
+------------------------------------------------------------------------------------------------------------------------------------------------------
+{-# LANGUAGE FlexibleInstances #-}
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- API
+------------------------------------------------------------------------------------------------------------------------------------------------------
+module Cartesian.Core (
+  -- ^ Types
+  module Cartesian.Types,
+  
+  -- ^ Lenses
+  module Cartesian.Lenses,
+
+  -- ^ Functions
+  overlap, fromCorners, fromAxes, fromExtents, intersect) where
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- We'll need these
+------------------------------------------------------------------------------------------------------------------------------------------------------
+import Cartesian.Internal.Core
+
+import Cartesian.Types
+import Cartesian.Lenses
+
src/Cartesian/Internal/Core.hs view
@@ -18,122 +18,78 @@ 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- 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.Lens ((^.))
+import Control.Applicative
 
 import Cartesian.Internal.Types
--- import Cartesian.Internal.Lenses
+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]
+  where
+    [a', b', c', d'] = sort [a, b, c, d] -- TODO: Silence the non-exhaustive warning
 
 -- Vectors ---------------------------------------------------------------------------------------------------------------------------------
 
--- | Applies a function to each component in a vector
-dotmap :: (Vector v, Num a) => (a -> b) -> v a -> v b
-dotmap f v = vzip (const . f) v v
-
-
--- | Performs component-wise operations
-dotwise :: (Vector v, Num a) => (a -> b -> c) -> v a -> v b -> v c
-dotwise = vzip
-
-
--- | Dot product of two vectors
-dot :: (Vector v, Num f) => v f -> v f -> f
-dot a b = vfold (+) 0 $ dotwise (*) a b
--- dot (Vector x y z) (Vector x' y' z') = (x * x') + (y * y') + (z * z') -- TODO: Refactor with Num instance (?)
+-- | 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
+-- euclidean :: (Vector v, Floating f) => v f -> v f -> f
+-- euclidean a b = sqrt $ dot a b
 
 
--- |
-mag :: (Vector v, Floating f) => v f -> f
-mag = magnitude
-
--- Instances -------------------------------------------------------------------------------------------------------------------------------
-
--- |
-instance (Vector v, Floating f) => Num (v f) where
-  -- TODO: Helper method to reduce boilerplate for component-wise operations
-  (+) = dotwise (+)       --
-  (-) = dotwise (-)       --
-  (*) a b     = undefined -- TODO: Is this really correct?
-  fromInteger = fromScalar . fromInteger             --
-  signum v    = dotmap (/mag v) v      -- TODO: Proper way of implementing this function for vectors
-  abs         = fromScalar . magnitude --
-
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- | Angle (in radians) between the positive X-axis and the vector
--- argument :: (Floating a, Eq a) => Vector a -> a
--- argument (Vector 0 0 0) = 0
--- argument (Vector x y z) = atan $ y/x
+-- -- |
+-- magnitude :: (Vector v, Floating f) => v f -> f
+-- magnitude v = euclidean v v
 
 
--- arg :: (Floating a, Eq a) => Vector a -> a
--- arg = argument
+-- -- |
+-- 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)
 
-
-
--- | Intersect
--- TODO: Math notes, MathJax or LaTex
--- TODO: Intersect for curves (functions) and single points (?)
--- TODO: Polymorphic, typeclass (lines, shapes, ranges, etc.) (?)
--- intersect :: Num a => Line a -> Line a -> Maybe (Vector a)
--- intersect _ _ = error "Not implemented" -- Nothing
 --
 --
--- -- |
--- intersects :: Num a => Line a -> Line a -> Bool
--- intersects a b = case intersect a b of
--- 	Just _  -> True
--- 	Nothing -> False
---
---
 -- -- | 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)
@@ -142,20 +98,34 @@ -- 	| otherwise                                  = Nothing --
 -- 	where [α, β, γ, _] = sort [fst a, snd a, fst b, snd b] -- That's right.
 -- 	      leftmost     = minimumBy (comparing fst) [a, b]  --
---
---
--- -- |
--- -- TODO: Intersect Rectangles
---
---
---
--- -- | Coefficients for the linear function of a Line (slope, intercept). The Z-component is ignored.
--- -- Fails for vertical and horizontal lines.
--- --
--- -- TODO: Use Maybe (?)
--- --
--- coefficients :: (Fractional a, Eq a) => Line a -> Maybe (a, a)
--- coefficients (Line (Vector ax ay _) (Vector bx by _))
--- 	| ax == bx  = Nothing
--- 	| ay == ay  = Nothing
--- 	| otherwise = let slope = (by - ay)/(bx - ax) in Just (slope, ay - slope*ax)
+
+-- 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'
+
+ src/Cartesian/Internal/Instances.hs view
@@ -0,0 +1,44 @@+-- |
+-- Module      : Cartesian.Internal.Instances
+-- Description :
+-- Copyright   : (c) Jonatan H Sundqvist, 2016
+-- License     : MIT
+-- Maintainer  : Jonatan H Sundqvist
+-- Stability   : experimental|stable
+-- Portability : POSIX (not sure)
+--
+
+-- Created September 1 2016
+
+-- TODO | - 
+--        - 
+
+-- SPEC | -
+--        -
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- GHC Directives
+------------------------------------------------------------------------------------------------------------------------------------------------------
+{-# LANGUAGE FlexibleInstances #-}
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- API
+------------------------------------------------------------------------------------------------------------------------------------------------------
+module Cartesian.Internal.Instances where
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- We'll need these
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- import Cartesian.Internal.Core
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+-- Instances
+------------------------------------------------------------------------------------------------------------------------------------------------------
src/Cartesian/Internal/Lenses.hs view
@@ -10,8 +10,8 @@ 
 -- Created October 31 2015
 
--- TODO | - QuickCheck, performance
---        -
+-- TODO | - QuickCheck, performance (inlining?)
+--        - Use classes for each lens (to avoid naming conflicts) (?)
 
 -- SPEC | -
 --        -
@@ -25,6 +25,9 @@ {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE TemplateHaskell        #-}
 {-# LANGUAGE RankNTypes             #-}
+{-# LANGUAGE ScopedTypeVariables    #-}
+{-# LANGUAGE FlexibleContexts       #-}
+{-# LANGUAGE TupleSections          #-}
 
 
 
@@ -38,14 +41,16 @@ --------------------------------------------------------------------------------------------------------------------------------------------
 -- We'll need these
 --------------------------------------------------------------------------------------------------------------------------------------------
-import Data.List     (isSuffixOf)
-import Control.Monad (mfilter)
-import Control.Lens
+import Control.Lens (makeLensesWith, lensRules, lensField, lens,
+                     Simple, Lens,
+                     (^.), (.~), (&),
+                     _1, _2,
+                     DefName(TopName))
 
 import Language.Haskell.TH
 
+-- import Cartesian.Internal.Core
 import Cartesian.Internal.Types
-import Cartesian.Internal.Core
 import Cartesian.Internal.Utils
 
 
@@ -66,32 +71,84 @@ -- | Ugh...
 makeLensesWith (lensRules & lensField .~ (\_ _ name -> [TopName (mkName $ dropSuffix "Of" (nameBase name))])) (''BoundingBox) -- TODO: 'Of'
 
+--------------------------------------------------------------------------------------------------------------------------------------------
 
+
 -- |
--- TODO: Rename (?)
-offset :: (Fractional f) => (Getter v f) -> (f -> f -> f) -> BoundingBox v -> f
-offset axis towards box = towards (box^.centre.axis) (0.5 * box^.size.axis)
+-- pad :: (Getter v f) -> f -> f -> BoundingBox v
+-- pad axis by direction = _
 
---------------------------------------------------------------------------------------------------------------------------------------------
 
--- |
--- pad :: f -> (Getter v f) -> f -> BoundingBox v
--- pad by axis direction = _
+-- | Like pinned, except it operates on a single axis and only focuses on the position (not size)
+--
+-- TODO: Change the type to make it play more nicely with 'pinned' (?)
+-- TODO: - What's the proper way of 'lifting' lenses (such as 'pinnedAxis'), so they work on multiple fields.
+--         This is not mucher better than it used to be when we didn't have the 'pinnedAxis' helper...
+pinnedAxis :: Num n => n -> Simple Lens (Axis n) (Axis n)
+pinnedAxis to = lens get set
+  where
+    get   (begin', len)   = (begin' + to*len, len)
+    set _ (begin', len) = (begin' - to*len, len)
 
 
--- | Moves one side of a BoundingBox along the given 'axis' so that its new position is at 'to'. The 'towards' parameter is expected to be
---   either (-) and (+), indicating which side along the axis we're dealing with.
+-- | Creates a lens where a pin is placed on a given point ('to'), so that
+--   the box can be placed or resized relative to the pin. It is also useful for 
+--   retrieving points within the box (such as the centre).
+--
+--   The pin is assumed to be normalised with respect to the corner and size of the box.
+--
+-- @
+-- let box = BoundingBox { cornerOf = V2 10 24, sizeOf = V2 6 18 }
+-- 
+-- box^.pinned (V2 0.5 0.5) -- Anchored to the centre
+-- > V2 (13.0,6.0) (33.0,18.0)
+-- @
+--
+pinned :: (Applicative v, Num n) => v n -> Simple Lens (BoundingBox (v n)) (Axes v n)
+pinned to f = axes (fmap undo . f . as) -- _.traverse._ to
+  where
+    toPinned   (pin, (begin', len)) = (begin' + pin*len, len)
+    fromPinned (pin, (begin', len)) = (begin' - pin*len, len)
+    
+    as   = fmap toPinned . zipA to
+    undo = fmap fromPinned . zipA to
+
+
+-- | Focuses on a single axis of the box
+axis :: (Applicative v, Num n) => Simple Lens (Axes v n) (Axis n) -> Simple Lens (BoundingBox (v n)) (Axis n)
+axis which = axes.which
+  -- where
+  --   get box = (box^.corner.which, box^.size.which)
+  --   set box new = box & corner.which .~ (new^._1)
+  --                     & size.which   .~ (new^._2)
+
+
+-- | 
+axes :: (Applicative v) => Lens (BoundingBox (v a)) (BoundingBox (v b)) (Axes v a) (Axes v b)
+axes f box = uncurry BoundingBox <$> newVecs
+  where
+    newAxes = f $ zipA (box^.corner) (box^.size)
+    newVecs = unzipA <$> newAxes
+
+
+-- | 
+extents :: (Applicative v, Num a, Num b) => Lens (BoundingBox (v a)) (BoundingBox (v b)) (Axes v a) (Axes v b)
+extents f = axes (fmap (fmap unbounds) . f . fmap bounds)
+  where
+    bounds   (from, len) = (from, from+len) -- From (begin, length) to (begin, end)
+    unbounds (from, to)  = (from, to-from) -- From (begin, length) to (begin, end)
+
+
+-- | 
 -- TODO: Turn this into a lens function (?)
 -- TODO: Polish description
--- TODO: Loosen constraint on f
-side :: (Fractional f) => Lens v v f f -> (f -> f -> f) -> Lens (BoundingBox v) (BoundingBox v) f f
-side axis towards = lens get set
-  where
-    get = offset axis towards
-    set box to = let newsize = abs (to - towards centre' (-(box^.size.axis)*0.5))
-                     centre' = box^.centre.axis --
-                 in BoundingBox { sizeOf=(box^.size) & axis .~ newsize, centreOf=(box^.centre) & axis .~ (to `towards` negate (newsize*0.5)) } -- TODO: Refactor. And then refactor some more.
+-- TODO: Loosen constraint on n (✓)
+-- axes which.pinned (V1 step).x._1 -- lens get set
+side :: (Applicative v, Num n) => Simple Lens (Axes v n) (Axis n) -> Simple Lens (Axis n) n -> Simple BoxLens v n
+side axis' endpoint' = extents.axis'.endpoint'
 
+-- TODO: sides, vertices
+
 -- Lines -----------------------------------------------------------------------------------------------------------------------------------
 
 -- TODO: Use type class (?)
@@ -99,43 +156,53 @@ begin :: Lens (Line v) (Line v) v v
 begin = lens (\(Line a _) -> a) (\(Line _ b) a -> Line a b)
 
+
 end :: Lens (Line v) (Line v) v v
 end = lens (\(Line _ b) -> b) (\(Line a _) b -> Line a b)
 
 --------------------------------------------------------------------------------------------------------------------------------------------
 
-width :: (HasX v f) => SideLens v f
+width :: (HasX (v f) f) => Simple Lens (BoundingBox (v f)) f
 width = size.x
 
 
-height :: (HasY v f) => SideLens v f
+height :: (HasY (v f) f) => Simple BoxLens v f
 height = size.y
 
 
-depth :: (HasZ v f) => SideLens v f
+depth :: (HasZ (v f) f) => Simple BoxLens v f
 depth = size.z
 
--- So much boilerplate it makes me cry -----------------------------------------------------------------------------------------------------
+-- Sides (so much boilerplate it makes me cry) ---------------------------------------------------------------------------------------------
 
-left :: (HasX v f, Fractional f) => SideLens v f
-left = side x (-)
+left :: (Applicative v, HasX (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+left = side x _1
 
 
-right :: (HasX v f, Fractional f) => SideLens v f
-right = side x (+)
+right :: (Applicative v, HasX (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+right = side x _2
 
 
-bottom :: (HasY v f, Fractional f) => SideLens v f
-bottom = side y (-)
+-- NOTE: Y-axis points upwards (cf. README.md)
+bottom :: (Applicative v, HasY (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+bottom = side y _1
 
 
-top :: (HasY v f, Fractional f) => SideLens v f
-top = side y (+)
+-- Note: Y-axis points upwards (cf. README.md)
+top :: (Applicative v, HasY (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+top = side y _2
 
 
-front :: (HasZ v f, Fractional f) => SideLens v f
-front = side z (-)
+-- NOTE: Z-axis points inwards (forwards) (cf. README.md)
+front :: (Applicative v, HasZ (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+front = side z _1
 
 
-back :: (HasZ v f, Fractional f) => SideLens v f
-back = side z (+)
+-- NOTE: Z-axis points inwards (forwards) (cf. README.md)
+back :: (Applicative v, HasZ (Axes v n) (Axis n), Num n) => Simple BoxLens v n
+back = side z _2
+
+--------------------------------------------------------------------------------------------------------------------------------------------
+
+centre :: (Applicative v, Fractional f) => Simple Lens (BoundingBox (v f)) (Axes v f)
+centre = pinned (pure $ 1/2)
src/Cartesian/Internal/Types.hs view
@@ -12,67 +12,153 @@ 
 -- TODO | - Use TemplateHaskell (?)
 --        - Strictness
+--        - Performance, inlining
 
 -- SPEC | -
 --        -
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- GHC Pragmas
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 {-# LANGUAGE TemplateHaskell        #-}
 {-# LANGUAGE MultiParamTypeClasses  #-}
 {-# LANGUAGE FunctionalDependencies #-}
 {-# LANGUAGE RankNTypes             #-}
+{-# LANGUAGE FlexibleInstances      #-}
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- API
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 module Cartesian.Internal.Types where
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Control.Lens (Lens)
+------------------------------------------------------------------------------------------------------------------------------------------------------
+import Control.Lens (Simple, Lens, lens)
 
+import Data.Complex (Complex(..))
 
---------------------------------------------------------------------------------------------------------------------------------------------
+import Linear.V1
+import Linear.V2
+import Linear.V3
+import Linear.V4
+
+
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- Types
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 
--- Synonyms --------------------------------------------------------------------------------------------------------------------------------
+-- Synonyms ------------------------------------------------------------------------------------------------------------------------------------------
 
+-- TODO: Add some aliased lenses for these aliased types (?)
+
+-- | A lens focusing on a single [vector-]component in a BoundingBox
+type BoxLens v v' f f' = Lens (BoundingBox (v f)) (BoundingBox (v' f')) f f'
+
+
+-- | An axis represented as (begin, length)
+type Axis a = (a, a)
+
+
+-- | A vector where each component represents a single axis (cf. 'Axis')
+type Axes v a = v (Axis a)
+
+
 -- |
--- type SideLens = (Fractional f, HasX v f) => Lens (BoundingBox v) (BoundingBox v) f f
-type SideLens v f = Lens (BoundingBox v) (BoundingBox v) f f
+-- type Domain
 
--- Types -----------------------------------------------------------------------------------------------------------------------------------
 
 -- |
+-- TODO: Rename (eg. 'Shape') (?)
+type Polygon m v f = m (v f)
+
+
+-- | Coordinate system wrappers
+newtype Normalised v = Normalised { absolute   :: v } -- 
+newtype Absolute   v = Absoloute  { normalised :: v } -- 
+
+-- Types ---------------------------------------------------------------------------------------------------------------------------------------------
+
+-- |
 -- TODO: Anchors (eg. C, N, S, E W and combinations thereof, perhaps represented as relative Vectors)
-data BoundingBox v = BoundingBox { centreOf :: v, sizeOf :: v }
+-- TODO: Define some standard instances (eg. Functor, Applicative)
+data BoundingBox v = BoundingBox { cornerOf :: v, sizeOf :: v } deriving (Show, Eq)
 
 
 -- |
 -- TODO: Use record (eg. from, to) (?)
-data Line v = Line v v
+data Line v = Line v v deriving (Show, Eq)
 
--- Classes ---------------------------------------------------------------------------------------------------------------------------------
 
 -- |
--- TODO: Use GADT instead (?)
--- TODO: Reduce boilerplate, figure out deriving, choose interface carefully
--- TODO: Figure out how to deal with parameter (fromScalar requires a Num constraint on f, maybe use 'subclass')
-class Vector v where
-  fromScalar :: Num f => f -> v f
-  vfold :: Num f => (f' -> f  -> f')  -> f'  -> v f  -> f'     -- TODO: What's with the Num constraint (not sure what I was thinking)
-  vzip  :: Num f => (f  -> f' -> f'') -> v f -> v f' -> v f''  -- TODO: What's with the Num constraint (not sure what I was thinking)
+data Linear f = Linear { interceptOf :: f, slopeOf :: f } deriving (Show, Eq)
 
 
-class HasX a f | a -> f where { x :: Lens a a f f }
-class HasY a f | a -> f where { y :: Lens a a f f }
-class HasZ a f | a -> f where { z :: Lens a a f f }
+-- |
+data Inclusivity r = Inclusive r | Exclusive r -- TODO: Rename (?)
+data Interval r    = Interval (Inclusivity r) (Inclusivity r)
+
+
+-- |
+-- TODO: Use existing type instead (?)
+-- data Side = SideLeft | SideRight | SideTop | SideBottom
+
+-- Classes -------------------------------------------------------------------------------------------------------------------------------------------
+
+-- TODO: How do you generate lenses for non-record types (?)
+class HasX a f | a -> f where { x :: Simple Lens a f }
+class HasY a f | a -> f where { y :: Simple Lens a f }
+class HasZ a f | a -> f where { z :: Simple Lens a f }
+
+-- Instances -----------------------------------------------------------------------------------------------------------------------------------------
+
+
+instance HasX (V1 f) f where
+  x = lens (\(V1 x') -> x') (\_ x' -> V1 x')
+
+
+instance HasX (V2 f) f where
+  x = lens (\(V2 x' _) -> x') (\(V2 _ y') x' -> V2 x' y')
+
+
+instance HasY (V2 f) f where
+  y = lens (\(V2 _ y') -> y') (\(V2 x' _) y' -> V2 x' y')
+
+
+instance HasX (V3 f) f where
+  x = lens (\(V3 x' _ _) -> x') (\(V3 _ y' z') x' -> V3 x' y' z')
+
+
+instance HasY (V3 f) f where
+  y = lens (\(V3 _ y' _) -> y') (\(V3 x' _ z') y' -> V3 x' y' z')
+
+
+instance HasZ (V3 f) f where
+  z = lens (\(V3 _ _ z') -> z') (\(V3 x' y' _) z' -> V3 x' y' z')
+
+
+instance HasX (V4 f) f where
+  x = lens (\(V4 x' _ _ _) -> x') (\(V4 _ y' z' w') x' -> V4 x' y' z' w')
+
+
+instance HasY (V4 f) f where
+  y = lens (\(V4 _ y' _ _) -> y') (\(V4 x' _ z' w') y' -> V4 x' y' z' w')
+
+
+instance HasZ (V4 f) f where
+  z = lens (\(V4 _ _ z' _) -> z') (\(V4 x' y' _ w') z' -> V4 x' y' z' w')
+
+
+instance HasX (Complex f) f where
+  x = lens (\(x':+_) -> x') (\(_:+y') x' -> x':+y')
+
+
+instance HasY (Complex f) f where
+  y = lens (\(_':+y') -> y') (\(x':+_) y' -> x':+y')
+
src/Cartesian/Internal/Utils.hs view
@@ -18,34 +18,49 @@ 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- GHC Pragmas
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- API
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 module Cartesian.Internal.Utils where
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Data.List     (isSuffixOf)
-import Control.Monad (mfilter)
+------------------------------------------------------------------------------------------------------------------------------------------------------
+import Data.List           (isSuffixOf)
+import Control.Monad       (mfilter)
+import Control.Applicative (liftA2)
 
 
 
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 -- Functions
---------------------------------------------------------------------------------------------------------------------------------------------
+------------------------------------------------------------------------------------------------------------------------------------------------------
 
 -- | Removes the given suffix if it exists, does nothing otherwise
 -- TODO: Move to utils module or use existing implementation
 -- TODO: Refactor
 dropSuffix :: (Eq a) => [a] -> [a] -> [a]
 dropSuffix su xs = maybe xs (take (length xs - length su)) $ mfilter (su `isSuffixOf`) (Just xs)
+
+
+-- |
+-- TODO: Type for distinguishing inclusive and exclusive values
+between :: Ord a => a -> a -> a -> Bool
+between mini maxi a = mini <= a && a <= maxi
+
+------------------------------------------------------------------------------------------------------------------------------------------------------
+
+zipA :: (Applicative f) => f a -> f b -> f (a, b)
+zipA = liftA2 (,)
+
+unzipA :: (Applicative f) => f (a, b) -> (f a, f b)
+unzipA v = (fst <$> v, snd <$> v)
+ src/Cartesian/Lenses.hs view
@@ -0,0 +1,43 @@+-- |
+-- Module      : Cartesian.Lenses
+-- Description : Exports public lenses
+-- Copyright   : (c) Jonatan H Sundqvist, 2015
+-- License     : MIT
+-- Maintainer  : Jonatan H Sundqvist
+-- Stability   : experimental|stable
+-- Portability : POSIX (not sure)
+--
+
+-- Created September 24 2016
+
+-- TODO | - 
+--        - 
+
+-- SPEC | -
+--        -
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------
+-- GHC Pragmas
+--------------------------------------------------------------------------------------------------------------------------------------------
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------
+-- API
+--------------------------------------------------------------------------------------------------------------------------------------------
+module Cartesian.Lenses (
+  pinnedAxis, pinned,
+  axis, axes, extents, side,
+  begin, end,
+  width, height, depth, 
+  left, right, bottom, top, front, back,
+  centre) where
+
+
+
+--------------------------------------------------------------------------------------------------------------------------------------------
+-- We'll need these
+--------------------------------------------------------------------------------------------------------------------------------------------
+import Cartesian.Internal.Lenses
− src/Cartesian/Plane.hs
@@ -1,280 +0,0 @@--- |
--- Module      : Cartesian.Plane
--- Description :
--- Copyright   : (c) Jonatan H Sundqvist, year
--- License     : MIT
--- Maintainer  : Jonatan H Sundqvist
--- Stability   : experimental|stable
--- Portability : POSIX (not sure)
---
-
--- Created date year
-
--- TODO | - Which constraints are appropriate (Num is probably too generic, should be Real, maybe RealFrac)
---        - Strictness, performance
-
--- SPEC | -
---        -
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- API
---------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Plane (module Cartesian.Plane,
-                        module Cartesian.Plane.Types,
-                        magnitude) where -- TODO: Why do I need to export 'intersect' specifically when I'm already exporting this entire module
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Data.List (sort, minimumBy)
-import Data.Ord  (comparing)
-import Data.Complex hiding (magnitude)
-
-import           Control.Monad (when)
-import           Control.Applicative
-
-import           Control.Lens ((^.))
-import qualified Control.Lens as L
-
--- import Southpaw.Utilities.Utilities (pairwise)
-
-import Cartesian.Internal.Types
-import Cartesian.Internal.Lenses
-import Cartesian.Internal.Core
-
-import Cartesian.Space.Types
-import Cartesian.Plane.Types
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Functions
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- | Determines if a point lies within a polygon using the odd-even method.
---
--- TODO: Use epsilon (?)
--- TODO: How to treat points that lie on an edge
-inside :: Num n => Polygon n -> Vector2D n -> Bool
-inside polygon (Vector2D x y) = undefined
-  where
-    lines   = polygon ++ [head polygon] -- Close the loop
-    -- between (Line (Vector ax ay) (Vector bx by)) = _
-
-
--- |
--- instance Convertible (Vector2D f, Vector3D f) where
-  -- _
-
-
--- |
-to3D :: Num f => Vector2D f -> Vector3D f
-to3D (Vector2D x' y') = Vector3D x' y' 0
-
-
--- |
-from3D :: Num f => Vector3D f -> Vector2D f
-from3D (Vector3D x' y' _) = Vector2D x' y'
-
-
--- | Perform some unary operation on a 2D vector as a 3D vector, converting the result back to 2D by discarding the z component.
--- TODO: Rename (?)
--- TODO: Loosen Num restriction (eg. to anything with a 'zero' value) (?)
-in3D :: (Num f, Num f') => (Vector3D f -> Vector3D f') -> Vector2D f -> Vector2D f'
-in3D f = from3D . f . to3D
-
-
--- | Same as in3D, but for binary operations.
--- _ :: _
--- _
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Functions
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- Vector math -----------------------------------------------------------------------------------------------------------------------------
-
--- | Angle (in radians) between the positive X-axis and the vector
--- argument :: (Floating a, Eq a) => Vector a -> a
--- argument (Vector 0 0) = 0
--- argument (Vector x y) = atan $ y/x
---
---
--- arg :: (Floating a, Eq a) => Vector a -> a
--- arg = argument
---
---
--- -- | Vector -> (magnitude, argument)
--- polar :: (Floating a, Eq a) => Vector a -> (a, a)
--- polar v@(Vector x y) = (magnitude v, argument v)
-
--- Geometry --------------------------------------------------------------------------------------------------------------------------------
-
--- | Yields the intersection point of two finite lines. The lines are defined inclusively by
---   their endpoints. The result is wrapped in a Maybe value to account for non-intersecting
---   lines.
---
--- TODO: Move equation solving to separate function (two linear functions)
--- TODO: Simplify logic by considering f(x) = y for vertical lines (?)
--- TODO: Return Either instead of Maybe (eg. Left "parallel") (?)
---
--- TODO: Math notes, MathJax or LaTex
--- TODO: Intersect for curves (functions) and single points (?)
--- TODO: Polymorphic, typeclass (lines, shapes, ranges, etc.) (?)
---
--- TODO: I'm pretty sure I've finished this function and then misplaced it...
--- intersect :: RealFrac n => Line n -> Line n -> Maybe (Vector2D n)
--- intersect a b = do
---   when ((fst $ deltas a) == 0) $ Just (error "Not implemented")
---   when ((fst $ deltas b) == 0) $ Just (error "Not implemented")
---   when (slope a == slope b)    $ Nothing
---   let Just $ Vector2D () ()
---   where
---     deltas   (Line (Vector2D ax ay) (Vector2D bx by)) = (bx - ax, by - ay) -- TODO: Rename (eg. deltas) (?)
---     vertical (Line (Vector2D ax _) (Vector2D bx _))   =  ax == bx
---     slope line     = let (dx, dy) = deltas line in dy/dx
---     intercept line@(Line (Vector x y) _)
---       | vertical line = Nothing
---       | otherwise     = Just $ y - slope line * x
-
--- Linear functions ------------------------------------------------------------------------------------------------------------------------
-
--- |
--- TODO: Refactor
--- TODO: Invariants, check corner cases
--- TODO: Deal with vertical lines
--- TODO: Factor out infinite-line logic
--- TODO: Decide how to deal with identical lines
--- TODO: Factor out domain logic (eg. write restrict or domain function)
--- TODO: Visual debugging functions
-intersect :: RealFloat f => Line (Vector2D f) -> Line (Vector2D f) -> Maybe (Vector2D f)
-intersect f' g' = do
-  p <- mp
-  indomain f' p
-  indomain g' p
-  where
-    -- indomain :: RealFloat f => Line (Vector2D f) -> Vector2D f -> Maybe (Vector2D f)
-    indomain h' = restrict (h'^.begin) (h'^.end)
-
-    -- mp :: Maybe (Vector2D f)
-    mp = case [linear f', linear g'] of
-      [Just f, Nothing] -> let x' = g'^.begin.x in Just $ Vector2D (x') (plotpoint f x')
-      [Nothing, Just g] -> let x' = f'^.begin.x in Just $ Vector2D (x') (plotpoint g x')
-      [Just f,  Just g] -> linearIntersect f g
-      _                 -> Nothing
-
-
--- | Gives the linear function overlapping the given segment
-linear :: RealFloat f => Line (Vector2D f) -> Maybe (Linear f)
-linear line = Linear <$> intercept line <*> slope line
-
-
--- | Applies a linear function to the given value
--- TODO: Rename (?)
-plotpoint :: RealFloat f => Linear f -> f -> f
-plotpoint f x = slopeOf f*x + interceptOf f
-
-
--- | Finds the intersection (if any) of two linear functions
-linearIntersect :: RealFloat f => Linear f -> Linear f -> Maybe (Vector2D f)
-linearIntersect f g
-  | slopeOf f == slopeOf g  = Nothing
-  | otherwise = let x = (a-α)/(β-b) in Just $ Vector2D x (a*x + b)
-  where
-    [a, α] = map interceptOf [f, g]
-    [b, β] = map slopeOf [f, g]
-
-
--- |
-slope :: RealFloat f => Line (Vector2D f) -> Maybe f
-slope (Line fr to)
-  | dx == 0   = Nothing
-  | otherwise = Just $ dy/dx
-  where
-    (Vector2D dx dy) = to - fr
-
-
--- |
-intercept :: RealFloat f => Line (Vector2D f) -> Maybe f
-intercept line = do
-  slope' <- slope line
-  return $ y' - slope'*x'
-  where
-    (x', y') = (line^.begin.x, line^.begin.y)
-
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- |
-between :: Ord a => a -> a -> a -> Bool
-between mini maxi a = mini <= a && a <= maxi
-
-
--- | Ensures that a given point lies within the domain and codomain
--- TODO: Let this function work on scalars, write another function for domain and codomain (?)
--- restrict domain codomain p = _
-restrict :: (Num f, Ord f) => Vector2D f -> Vector2D f -> Vector2D f -> Maybe (Vector2D f)
-restrict a b p@(Vector2D x y)
-  | indomain && incodomain = Just p
-  | otherwise              = Nothing
-  where
-    (Vector2D lowx lowy)   = dotwise min a b
-    (Vector2D highx highy) = dotwise max a b
-    indomain   = between lowx highx x
-    incodomain = between lowy highy y
-
--- Geometry --------------------------------------------------------------------------------------------------------------------------------
-
--- |
--- inside :: (Num n, Ord n) => Triangle n -> Point n -> Bool
--- inside _ _ = False
-
-
--- |
--- intersects :: RealFrac r => Line r -> Line r -> Bool
--- intersects a b = case intersect a b of
---   Just _  -> True
---   Nothing -> False
-
-
--- -- | 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]  --
-
-
--- |
--- TODO: Intersect Rectangles
-
-
-
--- | Coefficients for the linear function of a Line (slope, intercept).
--- Fails for vertical and horizontal lines.
---
--- TODO: Use Maybe (?)
--- TODO: Rename (eg. toLinear, function) (?)
---
--- coefficients :: (Fractional a, Eq a) => Line a -> Maybe (a, a)
--- coefficients (Line (Vector ax ay) (Vector bx by)) = do
--- 	when (ax == bx) Nothing
--- 	when (ay == ay) Nothing
--- 	let slope' = (by - ay)/(bx - ax) in Just (slope', ay - slope'*ax)
-
--- Linear functions ------------------------------------------------------------------------------------------------------------------------
-
--- | Solves a linear equation for x (f(x) = g(x))
--- TODO: Use Epsilon (?)
--- solve :: (Fractional n, Eq n) => Linear n -> Linear n -> Maybe n
--- solve f g
---   | slope f == slope g = Nothing
---   | otherwise          = Just $ (intercept f - intercept g)/(slope f - slope g)
− src/Cartesian/Plane/Lenses.hs
@@ -1,48 +0,0 @@--- |
--- Module      : Cartesian.Plane.Lenses
--- Description :
--- Copyright   : (c) Jonatan H Sundqvist, 2015
--- License     : MIT
--- Maintainer  : Jonatan H Sundqvist
--- Stability   : experimental|stable
--- Portability : POSIX (not sure)
---
-
--- Created October 21 2015
-
--- TODO | -
---        -
-
--- SPEC | -
---        -
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- GHC Pragmas
---------------------------------------------------------------------------------------------------------------------------------------------
-{-# LANGUAGE RankNTypes #-}
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- API
---------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Plane.Lenses where
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Data.Complex
-import Data.Functor ((<$>))
-import Control.Lens
-
-import Cartesian.Plane.Types
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Lenses
---------------------------------------------------------------------------------------------------------------------------------------------
− src/Cartesian/Plane/Types.hs
@@ -1,97 +0,0 @@--- |
--- Module      : Cartesian.Plane.Types
--- Description :
--- Copyright   : (c) Jonatan H Sundqvist, 2015
--- License     : MIT
--- Maintainer  : Jonatan H Sundqvist
--- Stability   : experimental|stable
--- Portability : POSIX (not sure)
---
-
--- Created September 6 2015
-
--- TODO | - Rename or move out function definitions
---        - Move BoundingBox functions to separate module (so that you could write BBox.makeFrom...)
-
--- SPEC | -
---        -
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- GHC Directives
---------------------------------------------------------------------------------------------------------------------------------------------
-{-# LANGUAGE TemplateHaskell       #-}
-{-# LANGUAGE RankNTypes            #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances     #-}
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- API
---------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Plane.Types (module Cartesian.Plane.Types,
-                              module Cartesian.Internal.Types) where
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Data.Complex
-import Control.Lens
-
-import Cartesian.Internal.Types
-import Cartesian.Space.Types
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Types
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- |
--- type Domain
-
-
--- |
--- TODO: Rename (?)
-data Vector2D f = Vector2D f f deriving (Eq, Show) -- TODO: Constraints on argument types (cf. GADT) (?)
-
-
--- |
--- TODO: Rename (eg. 'Shape') (?)
-type Polygon f = [Vector2D f]
-
-
--- |
-data Linear f = Linear { interceptOf :: f, slopeOf :: f }
-
-
--- |
--- TODO: Use existing type instead (?)
--- data Side = SideLeft | SideRight | SideTop | SideBottom
-
--- Instances -------------------------------------------------------------------------------------------------------------------------------
-
--- |
--- TODO: Refactor. A lot.
-instance Vector Vector2D where
-  fromScalar s = Vector2D s 0
-  vfold f a (Vector2D x' y')                    = f (f a x') y'
-  vzip  f   (Vector2D x' y') (Vector2D x'' y'') = Vector2D (f x' x'') (f y' y'')
-
-
-instance HasX (Vector2D f) f where
-  x = lens
-        (\(Vector2D x' _)     -> x')
-        (\(Vector2D _  y') x' -> Vector2D x' y')
-
-instance HasY (Vector2D f) f where
-  y = lens
-        (\(Vector2D _  y')   -> y')
-        (\(Vector2D x' _) y' -> Vector2D x' y')
-
--- instance HasZ (Vector2D f) f where
-  -- z = lens (const 0) const
− src/Cartesian/Space.hs
@@ -1,45 +0,0 @@--- |
--- Module      :  Cartesian.Space
--- Copyright   :  (C) 2015 Jonatan H Sundqvist
--- License     :  MIT-style (see the file LICENSE)
--- Maintainer  :  Jonatan H Sundqvist <jonatanhsundqvist@gmail.com>
--- Stability   :  provisional
--- Portability :  Portable
---
--- Vector and coordinate system utilities.
-
---
--- Cartesian.hs
--- This module exports the API for the Cartesian project
---
--- Jonatan H Sundqvist
--- January 27 2015
---
-
--- TODO | - Haddock header, sections, full coverage
---        - Separate 2D and 3D modules (✓)
---        - Factor out common functionality for Space.hs and Plane.hs
---        - Use existing vector type (eg. Linear.V3)
-
--- SPEC | -
---        -
-
-
-
-module Cartesian.Space where
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Data.List (sort, minimumBy)
-import Data.Ord  (comparing)
-
-import Cartesian.Space.Types
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Functions
---------------------------------------------------------------------------------------------------------------------------------------------
− src/Cartesian/Space/Lenses.hs
@@ -1,44 +0,0 @@--- |
--- Module      : Cartesian.Space.Lenses
--- Description :
--- 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
---------------------------------------------------------------------------------------------------------------------------------------------
-
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- API
---------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Space.Lenses where
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Cartesian.Space.Types
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Lenses
---------------------------------------------------------------------------------------------------------------------------------------------
− src/Cartesian/Space/Types.hs
@@ -1,84 +0,0 @@--- |
--- Module      : Cartesian.Space.Types
--- Description :
--- Copyright   : (c) Jonatan H Sundqvist, 2015
--- License     : MIT
--- Maintainer  : Jonatan H Sundqvist
--- Stability   : experimental|stable
--- Portability : POSIX (not sure)
---
-
--- Created October 31 2015
-
--- TODO | - Use Linear.V3 instead of defining my own vector type (?)
---        -
-
--- SPEC | -
---        -
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- GHC Pragmas
---------------------------------------------------------------------------------------------------------------------------------------------
-{-# LANGUAGE MultiParamTypeClasses #-}
-{-# LANGUAGE FlexibleInstances     #-}
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- API
---------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Space.Types where
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
-import Control.Lens
-
-import Cartesian.Internal.Types
-import Cartesian.Internal.Lenses
-import Cartesian.Internal.Core
-
-
-
---------------------------------------------------------------------------------------------------------------------------------------------
--- Types
---------------------------------------------------------------------------------------------------------------------------------------------
-
---------------------------------------------------------------------------------------------------------------------------------------------
-
--- |
-data Vector3D f = Vector3D f f f -- TODO: Constraints on argument types (cf. GADT) (?)
-
--- Instances -------------------------------------------------------------------------------------------------------------------------------
-
--- |
--- TODO: Refactor. A lot.
-instance Vector Vector3D where
-  fromScalar s = Vector3D s 0 0
-  vfold f a (Vector3D x' y' z')                        = f (f (f a x') y') z'
-  vzip  f   (Vector3D x' y' z') (Vector3D x'' y'' z'') = Vector3D (f x' x'') (f y' y'') (f z' z'')
-
-
--- |
--- instance (Floating v, Eq v) => Num (Vector3D v) where
---   -- TODO: Helper method to reduce boilerplate for component-wise operations
---   (+) = dotwise (+)
---   (-) = dotwise (-)
---   (*) (Vector3D x y z) (Vector3D x' y' z') = undefined -- TODO: Is this really correct?
---   fromInteger x = Vector3D (fromInteger x) 0 0
---   signum v = dotmap (/mag v) v -- TODO: Proper way of implementing this function for vectors
---   abs    (Vector3D x' y' z') = Vector3D (sqrt $ (x'**2) + (y'**2) + (z'**2)) (0) (0)
-
-
-instance HasX (Vector3D f) f where
-  x = lens (\(Vector3D x' _ _) -> x') (\(Vector3D _ y' z') x' -> Vector3D x' y' z')
-
-instance HasY (Vector3D f) f where
-  y = lens (\(Vector3D _ y' _) -> y') (\(Vector3D x' _ z') y' -> Vector3D x' y' z')
-
-instance HasZ (Vector3D f) f where
-  z = lens (\(Vector3D _ _ z') -> z') (\(Vector3D x' y' _) z' -> Vector3D x' y' z')
src/Cartesian/Types.hs view
@@ -28,17 +28,32 @@ --------------------------------------------------------------------------------------------------------------------------------------------
 -- API
 --------------------------------------------------------------------------------------------------------------------------------------------
-module Cartesian.Types where
-
+module Cartesian.Types (
+  -- ^ Third party types
+  V1(..), V2(..), V3(..), V4(..), Complex(..),
+  
+  -- ^ Synonyms
+  BoxLens, Axis, Axes, Polygon,
 
+  -- ^ Coordinate types
+  Normalised, Absolute,
 
---------------------------------------------------------------------------------------------------------------------------------------------
--- We'll need these
---------------------------------------------------------------------------------------------------------------------------------------------
+  -- ^ Types defined in this library
+  BoundingBox(..), Line, Linear,
 
+  -- ^ Classes
+  HasX, HasY, HasZ) where
 
 
 
 --------------------------------------------------------------------------------------------------------------------------------------------
--- Functions
+-- We'll need these
 --------------------------------------------------------------------------------------------------------------------------------------------
+import Linear.V1
+import Linear.V2
+import Linear.V3
+import Linear.V4
+
+import Data.Complex (Complex(..))
+
+import Cartesian.Internal.Types