Cartesian 0.1.0.1 → 0.2.0.0
raw patch · 16 files changed
+771/−485 lines, 16 filesdep +template-haskellPVP ok
version bump matches the API change (PVP)
Dependencies added: template-haskell
API changes (from Hackage documentation)
- Cartesian.Lenses: centre :: Lens' (BoundingBox f_a79V) (Complex f_a79V)
- Cartesian.Lenses: size :: Lens' (BoundingBox f_a79V) (Complex f_a79V)
- Cartesian.Plane.BoundingBox: fromCornerAndSize :: RealFloat f => Complex f -> Complex f -> BoundingBox f
- Cartesian.Plane.BoundingBox: fromCorners :: RealFloat f => Complex f -> Complex f -> BoundingBox f
- Cartesian.Plane.BoundingBox: fromSides :: RealFloat f => f -> f -> f -> f -> BoundingBox f
- Cartesian.Plane.BoundingBox: intersect :: (RealFloat f, Ord f) => BoundingBox f -> BoundingBox f -> Maybe (BoundingBox f)
- Cartesian.Plane.BoundingBox.Lenses: bottom :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: bottompad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: centre :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f)
- Cartesian.Plane.BoundingBox.Lenses: left :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: leftpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: makeBoundingBoxSideLens :: RealFloat f => (BoundingBox f -> f) -> (BoundingBox f -> f -> (f, f, f, f)) -> Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: right :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: rightpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: size :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f)
- Cartesian.Plane.BoundingBox.Lenses: top :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.BoundingBox.Lenses: toppad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
- Cartesian.Plane.Utilities: dotmap :: (a -> b) -> Complex a -> Complex b
- Cartesian.Plane.Utilities: dotwise :: (a -> a -> b) -> Complex a -> Complex a -> Complex b
- Cartesian.Plane.Utilities: flipx :: Complex Double -> Complex Double
- Cartesian.Plane.Utilities: flipy :: Complex Double -> Complex Double
- Cartesian.Plane.Utilities: imag :: Double -> Complex Double
- Cartesian.Plane.Utilities: real :: Double -> Complex Double
- Cartesian.Space: Line :: (Vector num) -> (Vector num) -> Line num
- Cartesian.Space: Vector :: num -> num -> num -> Vector num
- Cartesian.Space: coefficients :: (Fractional a, Eq a) => Line a -> Maybe (a, a)
- Cartesian.Space: data Line num
- Cartesian.Space: data Vector num
- Cartesian.Space: dot :: Floating a => Vector a -> Vector a -> a
- Cartesian.Space: dotwise :: (a -> b -> c) -> Vector a -> Vector b -> Vector c
- Cartesian.Space: euclidean :: Floating a => Vector a -> Vector a -> a
- Cartesian.Space: instance (GHC.Float.Floating a, GHC.Classes.Eq a) => GHC.Num.Num (Cartesian.Space.Vector a)
- Cartesian.Space: intersect :: Num a => Line a -> Line a -> Maybe (Vector a)
- Cartesian.Space: intersects :: Num a => Line a -> Line a -> Bool
- Cartesian.Space: mag :: (Floating a, Eq a) => Vector a -> a
- Cartesian.Space: magnitude :: (Floating a, Eq a) => Vector a -> a
- Cartesian.Space: overlap :: Real a => (a, a) -> (a, a) -> Maybe (a, a)
- Cartesian.Space: vector :: Num a => a -> a -> a -> Vector a
+ Cartesian.Plane.Lenses: bottom :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: bottompad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: centre :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f)
+ Cartesian.Plane.Lenses: left :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: leftpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: makeBoundingBoxSideLens :: RealFloat f => (BoundingBox f -> f) -> (BoundingBox f -> f -> (f, f, f, f)) -> Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: right :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: rightpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: size :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f)
+ Cartesian.Plane.Lenses: top :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Plane.Lenses: toppad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f
+ Cartesian.Space.Types: Line :: (Vector3D f) -> (Vector3D f) -> Line f
+ Cartesian.Space.Types: Vector3D :: f -> f -> f -> Vector3D f
+ Cartesian.Space.Types: data Line f
+ Cartesian.Space.Types: data Vector3D f
+ Cartesian.Space.Types: instance (GHC.Float.Floating v, GHC.Classes.Eq v) => GHC.Num.Num (Cartesian.Space.Types.Vector3D v)
+ Cartesian.Space.Types: instance Cartesian.Internal.Types.HasX (Cartesian.Space.Types.Vector3D f) f
+ Cartesian.Space.Types: instance Cartesian.Internal.Types.HasY (Cartesian.Space.Types.Vector3D f) f
+ Cartesian.Space.Types: instance Cartesian.Internal.Types.HasZ (Cartesian.Space.Types.Vector3D f) f
+ Cartesian.Space.Types: instance Cartesian.Internal.Types.Vector Cartesian.Space.Types.Vector3D
Files
- Cartesian.cabal +8/−5
- README.md +12/−1
- src/Cartesian/Internal/Core.hs +144/−0
- src/Cartesian/Internal/Lenses.hs +145/−0
- src/Cartesian/Internal/Types.hs +81/−0
- src/Cartesian/Internal/Utils.hs +51/−0
- src/Cartesian/Lenses.hs +0/−59
- src/Cartesian/Plane.hs +22/−22
- src/Cartesian/Plane/BoundingBox.hs +0/−85
- src/Cartesian/Plane/BoundingBox/Lenses.hs +0/−128
- src/Cartesian/Plane/Lenses.hs +127/−0
- src/Cartesian/Plane/Utilities.hs +0/−71
- src/Cartesian/Space.hs +2/−114
- src/Cartesian/Space/Lenses.hs +44/−0
- src/Cartesian/Space/Types.hs +91/−0
- src/Cartesian/Types.hs +44/−0
Cartesian.cabal view
@@ -10,7 +10,7 @@ -- PVP summary: +-+------- breaking API changes -- | | +----- non-breaking API additions -- | | | +--- code changes with no API change -version: 0.1.0.1 +version: 0.2.0.0 -- A short (one-line) description of the package. synopsis: Coordinate systems @@ -48,18 +48,21 @@ library -- Modules exported by the library. - exposed-modules: Cartesian.Lenses, Cartesian.Plane, Cartesian.Space, - Cartesian.Plane.Utilities, Cartesian.Plane.Types, Cartesian.Plane.BoundingBox, Cartesian.Plane.BoundingBox.Lenses + exposed-modules: Cartesian.Plane, Cartesian.Space, Cartesian.Types, + Cartesian.Plane.Types, Cartesian.Plane.Lenses, + Cartesian.Space.Types, Cartesian.Space.Lenses -- Modules included in this library but not exported. - -- other-modules: + other-modules: Cartesian.Internal.Types, Cartesian.Internal.Lenses, Cartesian.Internal.Core, Cartesian.Internal.Utils + -- LANGUAGE extensions used by modules in this package. other-extensions: TemplateHaskell, RankNTypes -- Other library packages from which modules are imported. build-depends: base <= 4.8.1.0, - lens <= 4.13.0.0 + lens <= 4.13.0.0, + template-haskell -- Directories containing source files. hs-source-dirs: src
README.md view
@@ -1,4 +1,15 @@ Cartesian ========= +Functions and types for working with three-dimensional coordinate systems. -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. + +Contributors +------------ +Jonatan H Sundqvist + + +TODO +---- +- Use typeclass for Vectors (would save a lot of boilerplate) +- Allow functions to operate on any Vector-like type (including eg. Complex)
+ src/Cartesian/Internal/Core.hs view
@@ -0,0 +1,144 @@+-- | +-- 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 +-------------------------------------------------------------------------------------------------------------------------------------------- + + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- 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 Cartesian.Internal.Types +import Cartesian.Internal.Lenses + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- Functions +-------------------------------------------------------------------------------------------------------------------------------------------- + +-- | Finds the overlap between two ranges (lower bound, upper bound). +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] + +-- Vectors --------------------------------------------------------------------------------------------------------------------------------- + +-- | Applies a function to each component in a vector +dotmap :: Vector v => (a -> b) -> v a -> v b +dotmap f v = vzip (const . f) v v + + +-- | Performs component-wise operations +dotwise :: Vector v => (a -> b -> c) -> v a -> v b -> v c +dotwise = vzip -- Hmmm. Dotwise isn't really a fold is it? + + +-- | Dot product of two vectors +dot :: (Vector v, Floating 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 (?) + + +-- | 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 + + +-- | 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 + + +-- 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) + + + +-- | 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) +-- 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). 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)
+ src/Cartesian/Internal/Lenses.hs view
@@ -0,0 +1,145 @@+-- | +-- Module : Cartesian.Internal.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 +-------------------------------------------------------------------------------------------------------------------------------------------- +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE RankNTypes #-} + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- API +-------------------------------------------------------------------------------------------------------------------------------------------- +module Cartesian.Internal.Lenses where + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- We'll need these +-------------------------------------------------------------------------------------------------------------------------------------------- +import Data.List (isSuffixOf) +import Control.Monad (mfilter) +import Control.Lens + +import Language.Haskell.TH + +import Cartesian.Internal.Types +import Cartesian.Internal.Utils + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- Lenses +-------------------------------------------------------------------------------------------------------------------------------------------- + +-- Vector ---------------------------------------------------------------------------------------------------------------------------------- + +-- | Focus on the X component +x :: HasX v f => Lens v v f f +x = lens getX setX + + +-- | Focus on the Y component +y :: HasY v f => Lens v v f f +y = lens getY setY + + +-- | Focus on the Z component +z :: HasZ v f => Lens v v f f +z = lens getZ setZ + +-- BoundingBox ----------------------------------------------------------------------------------------------------------------------------- + +-- TODO: Relative lenses (eg. padding) +-- TODO: Validate (eg. make sure that left < right) +-- TODO: Type-changing lenses (?) + + +-- | 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 :: f -> (Getter v f) -> f -> BoundingBox v +-- pad by axis direction = _ + + +-- | 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. +-- 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. + +-------------------------------------------------------------------------------------------------------------------------------------------- + +width :: (HasX v f) => Lens (BoundingBox v) (BoundingBox v) f f +width = size.x + + +height :: (HasY v f) => Lens (BoundingBox v) (BoundingBox v) f f +height = size.y + + +depth :: (HasZ v f) => Lens (BoundingBox v) (BoundingBox v) f f +depth = size.z + +-- So much boilerplate it makes me cry ----------------------------------------------------------------------------------------------------- + +-- type SideLens = (Fractional f, HasX v f) => Lens (BoundingBox v) (BoundingBox v) f f + +left :: (Fractional f, HasX v f) => Lens (BoundingBox v) (BoundingBox v) f f +left = side x (-) + + +right :: (Fractional f, HasX v f) => Lens (BoundingBox v) (BoundingBox v) f f +right = side x (+) + + +bottom :: (Fractional f, HasY v f) => Lens (BoundingBox v) (BoundingBox v) f f +bottom = side y (-) + + +top :: (Fractional f, HasY v f) => Lens (BoundingBox v) (BoundingBox v) f f +top = side y (+) + + +front :: (Fractional f, HasZ v f) => Lens (BoundingBox v) (BoundingBox v) f f +front = side z (-) + + +back :: (Fractional f, HasZ v f) => Lens (BoundingBox v) (BoundingBox v) f f +back = side z (+)
+ src/Cartesian/Internal/Types.hs view
@@ -0,0 +1,81 @@+-- | +-- Module : Cartesian.Internal.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 TemplateHaskell (?) +-- - Strictness + +-- SPEC | - +-- - + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- GHC Pragmas +-------------------------------------------------------------------------------------------------------------------------------------------- +{-# LANGUAGE TemplateHaskell #-} +{-# LANGUAGE MultiParamTypeClasses #-} +{-# LANGUAGE FunctionalDependencies #-} + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- API +-------------------------------------------------------------------------------------------------------------------------------------------- +module Cartesian.Internal.Types where + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- We'll need these +-------------------------------------------------------------------------------------------------------------------------------------------- + + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- Types +-------------------------------------------------------------------------------------------------------------------------------------------- + +-- 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 } + +-- Classes --------------------------------------------------------------------------------------------------------------------------------- + +-- | +-- TODO: Use GADT instead (?) +-- TODO: Reduce boilerplate, figure out deriving, choose interface carefully +class Vector v where + vfold :: (f' -> f -> f') -> f' -> v f -> f' + vzip :: (f -> f' -> f'') -> v f -> v f' -> v f'' + + +-- | +class HasX a f | a -> f where + getX :: a -> f + setX :: a -> f -> a + + +-- | +class HasY a f | a -> f where + getY :: a -> f + setY :: a -> f -> a + + +-- | +class HasZ a f | a -> f where + getZ :: a -> f + setZ :: a -> f -> a + +-- Instances -------------------------------------------------------------------------------------------------------------------------------
+ src/Cartesian/Internal/Utils.hs view
@@ -0,0 +1,51 @@+-- | +-- Module : Cartesian.Internal.Utils +-- Description : +-- Copyright : (c) Jonatan H Sundqvist, 2015 +-- License : MIT +-- Maintainer : Jonatan H Sundqvist +-- Stability : experimental|stable +-- Portability : POSIX (not sure) +-- + +-- Created November 2 2015 + +-- TODO | - +-- - + +-- SPEC | - +-- - + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- GHC Pragmas +-------------------------------------------------------------------------------------------------------------------------------------------- + + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- API +-------------------------------------------------------------------------------------------------------------------------------------------- +module Cartesian.Internal.Utils where + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- We'll need these +-------------------------------------------------------------------------------------------------------------------------------------------- +import Data.List (isSuffixOf) +import Control.Monad (mfilter) + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- 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)
− src/Cartesian/Lenses.hs
@@ -1,59 +0,0 @@--- | --- Module : Cartesian.Lenses --- Description : --- Copyright : (c) Jonatan H Sundqvist, 2015 --- License : MIT --- Maintainer : Jonatan H Sundqvist --- Stability : experimental|stable --- Portability : POSIX (not sure) --- - --- Created August 30 2015 - --- TODO | - --- - - --- SPEC | - --- - - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- GHC Pragmas --------------------------------------------------------------------------------------------------------------------------------------------- -{-# LANGUAGE TemplateHaskell #-} - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- API --------------------------------------------------------------------------------------------------------------------------------------------- -module Cartesian.Lenses where - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- We'll need these --------------------------------------------------------------------------------------------------------------------------------------------- -import qualified Control.Lens as L - -import qualified Cartesian.Plane.Types as Plane --- import qualified Cartesian.Space.Types as Space - --- import qualified Cartesian.Plane as Plane --- import qualified Cartesian.Space as Space - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Invoke the Templates! --------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------- -L.makeLenses ''Plane.BoundingBox - - - --------------------------------------------------------------------------------------------------------------------------------------------- - - ---------------------------------------------------------------------------------------------------------------------------------------------
src/Cartesian/Plane.hs view
@@ -71,9 +71,9 @@ -- TODO: How to treat points that lie on an edge inside :: Num n => Polygon n -> Vector n -> Bool inside (p:olygon) (Vector x y) = undefined - where - lines = (p:olygon)++[p] -- Close the loop - -- between (Line (Vector ax ay) (Vector bx by)) = _ + where + lines = (p:olygon)++[p] -- Close the loop + -- between (Line (Vector ax ay) (Vector bx by)) = _ @@ -82,14 +82,14 @@ -------------------------------------------------------------------------------------------------------------------------------------------- -- | abs v * signum v == v instance (Floating a, Eq a) => Num (Vector a) where - -- TODO: Helper method to reduce boilerplate for component-wise operations - (+) = dotwise (+) - (-) = dotwise (-) - (*) = dotwise (*) -- TODO: Is this really correct? - fromInteger n = Vector (fromInteger n) 0 - signum (Vector 0 0) = Vector 0 0 - signum v@(Vector x y) = Vector (x/mag v) (y/mag v) - abs a = Vector (euclidean a a) 0 + -- TODO: Helper method to reduce boilerplate for component-wise operations + (+) = dotwise (+) + (-) = dotwise (-) + (*) = dotwise (*) -- TODO: Is this really correct? + fromInteger n = Vector (fromInteger n) 0 + signum (Vector 0 0) = Vector 0 0 + signum v@(Vector x y) = Vector (x/mag v) (y/mag v) + abs a = Vector (euclidean a a) 0 @@ -171,18 +171,18 @@ -- | intersects :: RealFrac r => Line r -> Line r -> Bool intersects a b = case intersect a b of - Just _ -> True - Nothing -> False + 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] -- + | leftmost /= (α, β) = Just (β, γ) -- + | otherwise = Nothing -- + where [α, β, γ, _] = sort [fst a, snd a, fst b, snd b] -- That's right. + leftmost = minimumBy (comparing fst) [a, b] -- -- | @@ -198,9 +198,9 @@ -- 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) + | ax == bx = Nothing + | ay == ay = Nothing + | otherwise = let slope' = (by - ay)/(bx - ax) in Just (slope', ay - slope'*ax) -- Linear functions ------------------------------------------------------------------------------- @@ -208,5 +208,5 @@ -- 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) + | slope f == slope g = Nothing + | otherwise = Just $ (intercept f - intercept g)/(slope f - slope g)
− src/Cartesian/Plane/BoundingBox.hs
@@ -1,85 +0,0 @@--- | --- Module : Cartesian.Plane.BoundingBox --- Description : --- Copyright : (c) Jonatan H Sundqvist, 2015 --- License : MIT --- Maintainer : Jonatan H Sundqvist --- Stability : experimental|stable --- Portability : POSIX (not sure) --- - --- Created September 7 2015 - --- TODO | - Corner lenses --- - - --- SPEC | - --- - - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- GHC Pragmas --------------------------------------------------------------------------------------------------------------------------------------------- - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- API --------------------------------------------------------------------------------------------------------------------------------------------- -module Cartesian.Plane.BoundingBox (module Cartesian.Plane.Types, - module Cartesian.Plane.BoundingBox, - module Cartesian.Plane.BoundingBox.Lenses) where - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- We'll need these --------------------------------------------------------------------------------------------------------------------------------------------- -import Data.Complex -import Data.Functor ((<$>)) -import Data.List (sort) - -import Control.Lens - -import Cartesian.Plane.Types -import Cartesian.Plane.BoundingBox.Lenses -import Cartesian.Plane.Utilities - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Functions --------------------------------------------------------------------------------------------------------------------------------------------- - --- Convenience constructors ---------------------------------------------------------------------------------------------------------------- - --- | --- TODO: Better name (?) --- TODO: Don't make assumptions about WHICH corners they are (✓) -fromCorners :: RealFloat f => Complex f -> Complex f -> BoundingBox f -fromCorners nw@(n:+w) se@(s:+e) = let size = dotmap abs (se-nw) in BoundingBox { _centre=dotwise min nw se+size*(0.5:+0.0), _size=size } - - --- | Creates a bounding box from a topleft and size vector. -fromCornerAndSize :: RealFloat f => Complex f -> Complex f -> BoundingBox f -fromCornerAndSize nw size' = BoundingBox { _centre=nw+size'*0.5, _size=size' } - - --- | Top Left Bottom Right -fromSides :: RealFloat f => f -> f -> f -> f -> BoundingBox f -fromSides top left bottom right = fromCorners (left:+top) (right:+bottom) - --- Booleans -------------------------------------------------------------------------------------------------------------------------------- - --- | -intersect :: (RealFloat f, Ord f) => BoundingBox f -> BoundingBox f -> Maybe (BoundingBox f) -intersect a b = do - (left', right') <- overlap (a^.left, a^.right) (b^.left, b^.right) - (top', bottom') <- overlap (a^.top, a^.bottom) (b^.top, b^.bottom) - return $ fromSides top' left' bottom' right' - where - 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]
− src/Cartesian/Plane/BoundingBox/Lenses.hs
@@ -1,128 +0,0 @@--- | --- Module : Cartesian.BoundingBox.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.BoundingBox.Lenses where - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- We'll need these --------------------------------------------------------------------------------------------------------------------------------------------- -import Data.Complex (Complex ((:+))) -import Data.Functor ((<$>)) -import Control.Lens - -import Cartesian.Plane.Types - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Lenses --------------------------------------------------------------------------------------------------------------------------------------------- - - --- | --- TODO: Make sure invariants remain true (eg. left < right) --- TODO: Make coordinate-system independent (eg. direction of axes) -makeBoundingBoxSideLens :: RealFloat f => (BoundingBox f -> f) -> (BoundingBox f -> f -> (f, f, f, f)) -> Lens (BoundingBox f) (BoundingBox f) f f -makeBoundingBoxSideLens oldside newsides f s@(BoundingBox { _centre=(cx:+cy), _size=(dx:+dy) }) = assemble <$> f (oldside s) - where - assemble newside = let (nleft, nright, ntop, nbottom) = newsides s newside - newsize = (nright-nleft):+(nbottom-ntop) - in BoundingBox { _centre=(nleft:+ntop)+(newsize*(0.5:+0.0)), _size=newsize } - --- Core lenses ----------------------------------------------------------------------------------------------------------------------------- - --- | -centre :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f) -centre f s = let assemble new = s { _centre=new } in assemble <$> f (_centre s) - - --- | -size :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f) -size f s = let assemble new = s { _size=new } in assemble <$> f (_size s) - --- Side lenses (absolute) ------------------------------------------------------------------------------------------------------------------ - --- | -left :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -left = makeBoundingBoxSideLens - (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx - dx/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (newside, cx+dx/2, cy-dy/2, cy+dy/2)) - - --- | -right :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -right = makeBoundingBoxSideLens - (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx + dx/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, newside, cy-dy/2, cy+dy/2)) - - --- | -top :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -top = makeBoundingBoxSideLens - (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy - dy/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, newside, cy+dy/2)) - - --- | -bottom :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -bottom = makeBoundingBoxSideLens - (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy + dy/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2, newside)) - --- Side lenses (relative) ------------------------------------------------------------------------------------------------------------------ - --- | -leftpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -leftpad = makeBoundingBoxSideLens - (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx - dx/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2+newside, cx+dx/2, cy-dy/2, cy+dy/2)) - - --- | -rightpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -rightpad = makeBoundingBoxSideLens - (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx + dx/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2+newside, cy-dy/2, cy+dy/2)) - - --- | -toppad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -toppad = makeBoundingBoxSideLens - (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy - dy/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2+newside, cy+dy/2)) - - --- | -bottompad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f -bottompad = makeBoundingBoxSideLens - (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy + dy/2) - (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2, cy+dy/2+newside))
+ src/Cartesian/Plane/Lenses.hs view
@@ -0,0 +1,127 @@+-- | +-- 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 +-------------------------------------------------------------------------------------------------------------------------------------------- + +-- | +-- TODO: Make sure invariants remain true (eg. left < right) +-- TODO: Make coordinate-system independent (eg. direction of axes) +makeBoundingBoxSideLens :: RealFloat f => (BoundingBox f -> f) -> (BoundingBox f -> f -> (f, f, f, f)) -> Lens (BoundingBox f) (BoundingBox f) f f +makeBoundingBoxSideLens oldside newsides f s@(BoundingBox { _centre=(cx:+cy), _size=(dx:+dy) }) = assemble <$> f (oldside s) + where + assemble newside = let (nleft, nright, ntop, nbottom) = newsides s newside + newsize = (nright-nleft):+(nbottom-ntop) + in BoundingBox { _centre=(nleft:+ntop)+(newsize*(0.5:+0.0)), _size=newsize } + +-- Core lenses ----------------------------------------------------------------------------------------------------------------------------- + +-- | +centre :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f) +centre f s = let assemble new = s { _centre=new } in assemble <$> f (_centre s) + + +-- | +size :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) (Complex f) (Complex f) +size f s = let assemble new = s { _size=new } in assemble <$> f (_size s) + +-- Side lenses (absolute) ------------------------------------------------------------------------------------------------------------------ + +-- | +left :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +left = makeBoundingBoxSideLens + (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx - dx/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (newside, cx+dx/2, cy-dy/2, cy+dy/2)) + + +-- | +right :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +right = makeBoundingBoxSideLens + (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx + dx/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, newside, cy-dy/2, cy+dy/2)) + + +-- | +top :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +top = makeBoundingBoxSideLens + (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy - dy/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, newside, cy+dy/2)) + + +-- | +bottom :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +bottom = makeBoundingBoxSideLens + (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy + dy/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2, newside)) + +-- Side lenses (relative) ------------------------------------------------------------------------------------------------------------------ + +-- | +leftpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +leftpad = makeBoundingBoxSideLens + (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx - dx/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2+newside, cx+dx/2, cy-dy/2, cy+dy/2)) + + +-- | +rightpad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +rightpad = makeBoundingBoxSideLens + (\(BoundingBox { _centre=cx:+_, _size=dx:+_ }) -> cx + dx/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2+newside, cy-dy/2, cy+dy/2)) + + +-- | +toppad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +toppad = makeBoundingBoxSideLens + (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy - dy/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2+newside, cy+dy/2)) + + +-- | +bottompad :: RealFloat f => Lens (BoundingBox f) (BoundingBox f) f f +bottompad = makeBoundingBoxSideLens + (\(BoundingBox { _centre=_:+cy, _size=_:+dy }) -> cy + dy/2) + (\(BoundingBox { _centre=cx:+cy, _size=dx:+dy }) newside -> (cx-dx/2, cx+dx/2, cy-dy/2, cy+dy/2+newside))
− src/Cartesian/Plane/Utilities.hs
@@ -1,71 +0,0 @@--- | --- Module : Cartesian.Plane.Utilities --- Description : --- Copyright : (c) Jonatan H Sundqvist, 2015 --- License : MIT --- Maintainer : Jonatan H Sundqvist --- Stability : experimental|stable --- Portability : POSIX (not sure) --- - --- Created September 8 2015 - --- TODO | - Uses lenses for Complex type (?) --- - - --- SPEC | - --- - - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- GHC Pragmas --------------------------------------------------------------------------------------------------------------------------------------------- - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- API --------------------------------------------------------------------------------------------------------------------------------------------- -module Cartesian.Plane.Utilities where - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- We'll need these --------------------------------------------------------------------------------------------------------------------------------------------- -import Data.Complex - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Functions --------------------------------------------------------------------------------------------------------------------------------------------- --- | Applies a function to each component in a vector -dotmap :: (a -> b) -> Complex a -> Complex b -dotmap f (re:+im) = f re :+ f im - - --- | -dotwise :: (a -> a -> b) -> Complex a -> Complex a -> Complex b -dotwise f (re:+im) (re':+im') = f re re':+ f im im' - - --- | Negates the real component (X) -flipx :: Complex Double -> Complex Double -flipx (x:+y) = (-x):+y - - --- | Negates the imaginary component (Y) -flipy :: Complex Double -> Complex Double -flipy (x:+y) = x:+(-y) - - --- | Creates a number on the real line (where the imaginary part is 0) -real :: Double -> Complex Double -real = (:+ 0) - - --- | Creates a number on the imaginary line (where the real part is 0) -imag :: Double -> Complex Double -imag = (0 :+)
src/Cartesian/Space.hs view
@@ -19,6 +19,7 @@ -- 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 | - -- - @@ -35,123 +36,10 @@ import Data.List (sort, minimumBy) import Data.Ord (comparing) - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Types --------------------------------------------------------------------------------------------------------------------------------------------- - --- | -data Vector num = Vector num num num -- TODO: Constraints on argument types (cf. GADT) (?) - - --- | -data Line num = Line (Vector num) (Vector num) - - --- | Why the hell did I write this useless function? -vector :: Num a => a -> a -> a -> Vector a -vector = Vector -- SublimeHaskell prefers the eta-reduced version (point-free) - - - --------------------------------------------------------------------------------------------------------------------------------------------- --- Instances --------------------------------------------------------------------------------------------------------------------------------------------- - --- | -instance (Floating a, Eq a) => Num (Vector a) where - -- TODO: Helper method to reduce boilerplate for component-wise operations - (+) = dotwise (+) - (-) = dotwise (-) - (*) = dotwise (*) -- TODO: Is this really correct? - fromInteger n = Vector (fromInteger n) 0 0 - signum v@(Vector x y z) = Vector (x/mag v) (y/mag v) (z/mag v) -- TODO: Proper way of implementing this function for vectors - abs v = Vector (mag v) (0) (0) +import Cartesian.Space.Types -------------------------------------------------------------------------------------------------------------------------------------------- -- Functions -------------------------------------------------------------------------------------------------------------------------------------------- - --- Vector math ----------------------------------------------------------------------------------------------------------------------------- --- | Performs component-wise operations -dotwise :: (a -> b -> c) -> Vector a -> Vector b -> Vector c -dotwise f (Vector x y z) (Vector x' y' z') = Vector (f x x') (f y y') (f z z') - - --- | Dot product of two vectors -dot :: Floating a => Vector a -> Vector a -> a -dot (Vector x y z) (Vector x' y' z') = (x * x') + (y * y') + (z * z') -- TODO: Refactor with Num instance (?) - - --- | Euclidean distance between two points -euclidean :: Floating a => Vector a -> Vector a -> a -euclidean a b = sqrt $ dot a b - - --- | -magnitude :: (Floating a, Eq a) => Vector a -> a -magnitude v = euclidean v v - -mag :: (Floating a, Eq a) => Vector a -> a -mag = 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 - - --- 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) - --------------------------------------------------------------------------------------------------------------------------------------------- - --- | 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) -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). 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)
+ src/Cartesian/Space/Lenses.hs view
@@ -0,0 +1,44 @@+-- | +-- 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 view
@@ -0,0 +1,91 @@+-- | +-- 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) (?) + + +-- | +data Line f = Line (Vector3D f) (Vector3D f) + + +-- | +-- data BoundingBox f = BoundingBox { _centre :: Vector f, _size :: Vector f } + +-- Instances ------------------------------------------------------------------------------------------------------------------------------- + +-- | +-- TODO: Refactor. A lot. +instance Vector Vector3D where + 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 n = Vector3D (fromInteger n) 0 0 + signum v@(Vector3D x' y' z') = Vector3D (x'/(abs v^.x)) (y'/(abs v^.x)) (z'/(abs v^.x)) -- 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 + getX (Vector3D x' _ _) = x' + setX (Vector3D _ y' z') x' = Vector3D x' y' z' + +instance HasY (Vector3D f) f where + getY (Vector3D y' _ _) = y' + setY (Vector3D x' _ z') y' = Vector3D x' y' z' + +instance HasZ (Vector3D f) f where + getZ (Vector3D z' _ _) = z' + setZ (Vector3D x' y' _) z' = Vector3D x' y' z'
+ src/Cartesian/Types.hs view
@@ -0,0 +1,44 @@+-- | +-- Module : Cartesian.Types +-- Description : +-- Copyright : (c) Jonatan H Sundqvist, 2015 +-- License : MIT +-- Maintainer : Jonatan H Sundqvist +-- Stability : experimental|stable +-- Portability : POSIX (not sure) +-- + +-- Created _ _ 2015 + +-- TODO | - +-- - + +-- SPEC | - +-- - + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- GHC Pragmas +-------------------------------------------------------------------------------------------------------------------------------------------- + + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- API +-------------------------------------------------------------------------------------------------------------------------------------------- +module Cartesian.Types where + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- We'll need these +-------------------------------------------------------------------------------------------------------------------------------------------- + + + + +-------------------------------------------------------------------------------------------------------------------------------------------- +-- Functions +--------------------------------------------------------------------------------------------------------------------------------------------