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 +16/−5
- README.md +8/−4
- src/Cartesian/Core.hs +50/−0
- src/Cartesian/Internal/Core.hs +58/−88
- src/Cartesian/Internal/Instances.hs +44/−0
- src/Cartesian/Internal/Lenses.hs +106/−39
- src/Cartesian/Internal/Types.hs +112/−26
- src/Cartesian/Internal/Utils.hs +25/−10
- src/Cartesian/Lenses.hs +43/−0
- src/Cartesian/Plane.hs +0/−280
- src/Cartesian/Plane/Lenses.hs +0/−48
- src/Cartesian/Plane/Types.hs +0/−97
- src/Cartesian/Space.hs +0/−45
- src/Cartesian/Space/Lenses.hs +0/−44
- src/Cartesian/Space/Types.hs +0/−84
- src/Cartesian/Types.hs +21/−6
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