packages feed

colour-space 0.1.5.1 → 0.2.0.0

raw patch · 4 files changed

+346/−27 lines, 4 filesdep +QuickCheckdep +colour-spacedep +manifolds-coredep ~basedep ~colourdep ~manifoldsPVP ok

version bump matches the API change (PVP)

Dependencies added: QuickCheck, colour-space, manifolds-core, random, tasty, tasty-quickcheck

Dependency ranges changed: base, colour, manifolds

API changes (from Hackage documentation)

- Data.Colour.Manifold: instance Data.AdditiveGroup.AdditiveGroup Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Data.AffineSpace.AffineSpace Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Data.Manifold.Atlas.Atlas Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Data.Manifold.Riemannian.Geodesic Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Data.VectorSpace.VectorSpace Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance GHC.Classes.Eq Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance GHC.Show.Show Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.LinearMap.Category.Class.LinearSpace Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.LinearMap.Category.Class.TensorSpace Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.PseudoAffine (Data.Colour.Internal.Colour Math.Manifold.Core.Types.Internal.ℝ)
- Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.PseudoAffine Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.Semimanifold (Data.Colour.Internal.Colour Math.Manifold.Core.Types.Internal.ℝ)
- Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.Semimanifold Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.VectorSpace.Docile.FiniteDimensional Data.Colour.Manifold.ColourNeedle
- Data.Colour.Manifold: instance Math.VectorSpace.Docile.SemiInner Data.Colour.Manifold.ColourNeedle
+ Data.Colour.Manifold: instance Data.AdditiveGroup.AdditiveGroup Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.AffineSpace.AffineSpace Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Foldable.Foldable Data.Colour.RGB.RGB
+ Data.Colour.Manifold: instance Data.Manifold.Atlas.Atlas Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Manifold.Riemannian.Geodesic Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.ProjectableBoundary Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.PseudoAffineWithBoundary (Data.Colour.Internal.Colour Math.Manifold.Core.Types.Internal.ℝ)
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.PseudoAffineWithBoundary Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.SemimanifoldWithBoundary (Data.Colour.Internal.Colour Math.Manifold.Core.Types.Internal.ℝ)
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.SemimanifoldWithBoundary Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold: instance Data.Manifold.WithBoundary.Class.SemimanifoldWithBoundary Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Data.Monoid.Additive.AdditiveMonoid Data.Colour.Manifold.Internal.ColourHalfNeedle
+ Data.Colour.Manifold: instance Data.Monoid.Additive.HalfSpace Data.Colour.Manifold.Internal.ColourHalfNeedle
+ Data.Colour.Manifold: instance Data.VectorSpace.VectorSpace Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.LinearMap.Category.Class.LinearSpace Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.LinearMap.Category.Class.TensorSpace Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.PseudoAffine Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.Manifold.Core.PseudoAffine.Semimanifold Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.VectorSpace.Docile.FiniteDimensional Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Math.VectorSpace.Docile.SemiInner Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold: instance Test.QuickCheck.Arbitrary.Arbitrary Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold: instance Test.QuickCheck.Arbitrary.Arbitrary Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold.Internal: ColourBoundarySphere :: S² -> ColourBoundary
+ Data.Colour.Manifold.Internal: ColourHalfNeedle :: !ℝay -> !Needle ColourBoundary -> ColourHalfNeedle
+ Data.Colour.Manifold.Internal: ColourNeedle :: RGB ℝ -> ColourNeedle
+ Data.Colour.Manifold.Internal: [colourBoundaryDistance] :: ColourHalfNeedle -> !ℝay
+ Data.Colour.Manifold.Internal: [colourBoundaryTangent] :: ColourHalfNeedle -> !Needle ColourBoundary
+ Data.Colour.Manifold.Internal: [getColourBounarySphere] :: ColourBoundary -> S²
+ Data.Colour.Manifold.Internal: [getRGBNeedle] :: ColourNeedle -> RGB ℝ
+ Data.Colour.Manifold.Internal: asV3Needle :: ColourNeedle -+> V3 ℝ
+ Data.Colour.Manifold.Internal: data ColourHalfNeedle
+ Data.Colour.Manifold.Internal: fromV3Needle :: V3 ℝ -+> ColourNeedle
+ Data.Colour.Manifold.Internal: instance GHC.Classes.Eq Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold.Internal: instance GHC.Classes.Eq Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold.Internal: instance GHC.Generics.Generic Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold.Internal: instance GHC.Generics.Generic Data.Colour.Manifold.Internal.ColourHalfNeedle
+ Data.Colour.Manifold.Internal: instance GHC.Show.Show Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold.Internal: instance GHC.Show.Show Data.Colour.Manifold.Internal.ColourNeedle
+ Data.Colour.Manifold.Internal: instance Math.Manifold.Core.PseudoAffine.PseudoAffine Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold.Internal: instance Math.Manifold.Core.PseudoAffine.Semimanifold Data.Colour.Manifold.Internal.ColourBoundary
+ Data.Colour.Manifold.Internal: newtype ColourBoundary
+ Data.Colour.Manifold.Internal: newtype ColourNeedle

Files

colour-space.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                colour-space-version:             0.1.5.1+version:             0.2.0.0 synopsis:            Instances of the manifold-classes for colour types -- description:          homepage:            https://github.com/leftaroundabout/colour-space@@ -18,10 +18,12 @@  library   exposed-modules:     Data.Colour.Manifold+                       Data.Colour.Manifold.Internal   -- other-modules:          -- other-extensions:       build-depends:       base >=4.7 && <5-                     , manifolds >=0.4.5 && <0.6+                     , manifolds >=0.4.5 && <0.7+                     , manifolds-core                      , constrained-categories                      , linearmap-category >=0.3.5                      , linear@@ -29,7 +31,25 @@                      , semigroups                      , lens                      , call-stack+                     , QuickCheck                      , colour > 2 && < 3                      , JuicyPixels >= 3.1 && < 3.4   hs-source-dirs:      src   default-language:    Haskell2010++test-suite tasty+  main-is:         test.hs+  type:            exitcode-stdio-1.0+  hs-source-dirs:  test/tasty+  build-depends:   base, colour-space+                   , QuickCheck+                   , manifolds-core+                   , manifolds+                   , random+                   , colour+                   , vector-space+                   , constrained-categories+                   , tasty, tasty-quickcheck+  ghc-options: -threaded "-with-rtsopts -N4 -M2G"+  default-language:    Haskell2010+
src/Data/Colour/Manifold.hs view
@@ -1,11 +1,17 @@-{-# LANGUAGE TypeFamilies        #-}-{-# LANGUAGE FlexibleInstances   #-}-{-# LANGUAGE FlexibleContexts    #-}-{-# LANGUAGE TypeOperators       #-}-{-# LANGUAGE UnicodeSyntax       #-}-{-# LANGUAGE ScopedTypeVariables #-}-{-# LANGUAGE TemplateHaskell     #-}-{-# LANGUAGE Rank2Types          #-}+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE TypeApplications     #-}+{-# LANGUAGE UnicodeSyntax        #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TemplateHaskell      #-}+{-# LANGUAGE Rank2Types           #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE DeriveAnyClass       #-}+{-# LANGUAGE EmptyCase            #-}+{-# LANGUAGE CPP                  #-}  module Data.Colour.Manifold (          -- * Full colour space@@ -19,6 +25,8 @@          , SimpleColourMap, blackBlueYellowRed, brightVsRed, redVsBlue          ) where +import Data.Colour.Manifold.Internal+ import Data.Functor (($>)) import Control.Applicative (empty) import Control.Applicative.Constrained@@ -26,16 +34,23 @@ import Data.Semigroup  import Data.Manifold.PseudoAffine+import Math.Manifold.Core.PseudoAffine (GenericNeedle(..)) import Data.Manifold.Types import Data.Manifold.Atlas import Data.Manifold.Riemannian import Data.VectorSpace+import Data.Basis import Data.AffineSpace import Data.AdditiveGroup-import Data.Manifold.Shade (Shade(..), Shade'(..), rangeWithinVertices)-+import Data.Manifold.Shade (Shade(..), Shade'(..)+                           , rangeWithinVertices+                           )+#if MIN_VERSION_manifolds(0,6,0)+import Data.Manifold.WithBoundary+#endif import Data.Colour.SRGB (toSRGB, toSRGB24) import Data.Colour.SRGB.Linear+import Data.Colour.RGBSpace.HSL (hslView, hsl) import Data.Colour hiding (AffineSpace) import Data.Colour.Names @@ -48,21 +63,20 @@  import Codec.Picture.Types +import qualified Test.QuickCheck as QC+ import Data.Coerce import Data.Type.Coercion import Data.CallStack  import Control.Lens+import GHC.Generics +instance QC.Arbitrary ColourNeedle where+  arbitrary = ColourNeedle <$> (+                   RGB <$> QC.arbitrary <*> QC.arbitrary <*> QC.arbitrary ) -newtype ColourNeedle = ColourNeedle { getRGBNeedle :: RGB ℝ } deriving (Eq, Show) -asV3Needle :: ColourNeedle -+> V3 ℝ-asV3Needle = LinearFunction $ \(ColourNeedle (RGB r g b)) -> V3 r g b--fromV3Needle :: V3 ℝ -+> ColourNeedle-fromV3Needle = LinearFunction $ \(V3 r g b) -> ColourNeedle $ RGB r g b- asV3Tensor :: (ColourNeedle⊗w) -+> (V3 ℝ⊗w) asV3Tensor = LinearFunction $ \(Tensor (RGB r g b)) -> Tensor $ V3 r g b @@ -86,7 +100,10 @@ instance TensorSpace ColourNeedle where   type TensorProduct ColourNeedle w = RGB w   scalarSpaceWitness = ScalarSpaceWitness-  linearManifoldWitness = LinearManifoldWitness BoundarylessWitness+  linearManifoldWitness = LinearManifoldWitness+#if !MIN_VERSION_manifolds(0,6,0)+        BoundarylessWitness+#endif   zeroTensor = Tensor (RGB zeroV zeroV zeroV)   toFlatTensor = LinearFunction $ \(ColourNeedle (RGB r g b)) -> Tensor (RGB r g b)   fromFlatTensor = LinearFunction $ \(Tensor (RGB r g b)) -> ColourNeedle (RGB r g b)@@ -152,6 +169,7 @@   composeLinear = bilinearFunction $ \f (LinearMap (RGB r' g' b'))             -> LinearMap $ RGB (f +$ r') (f +$ g') (f +$ b')    where f+$x = getLinearFunction (getLinearFunction applyLinear f) x+  useTupleLinearSpaceComponents _ = undefined  instance SemiInner ColourNeedle where   dualBasisCandidates = cartesianDualBasisCandidates@@ -184,6 +202,7 @@   recomposeContraLinMap f l = LinearMap $ RGB (f $ fmap (channelRed . getRGBNeedle) l)                                               (f $ fmap (channelGreen . getRGBNeedle) l)                                               (f $ fmap (channelBlue . getRGBNeedle) l)+  tensorEquality (Tensor t) (Tensor τ) = t == τ   recomposeContraLinMapTensor = rclmt dualSpaceWitness    where rclmt :: ∀ u w f . ( Hask.Functor f                             , FiniteDimensional u, LinearSpace w@@ -213,17 +232,46 @@  instance Semimanifold ColourNeedle where   type Needle ColourNeedle = ColourNeedle+#if MIN_VERSION_manifolds(0,6,0)+  (.+~^) = (^+^)+#else   fromInterior = id; toInterior = pure   translateP = pure (^+^)+#endif  instance PseudoAffine ColourNeedle where-  ColourNeedle q .-~. ColourNeedle s = pure . ColourNeedle $ liftA2 (-) q s+  ColourNeedle q .-~! ColourNeedle s = ColourNeedle $ liftA2 (-) q s+  q .-~. s = pure (q.-~!s)  instance Atlas ColourNeedle where   type ChartIndex ColourNeedle = ()+#if !MIN_VERSION_manifolds(0,6,0)   interiorChartReferencePoint _ () = zeroV+#else+  chartReferencePoint () = zeroV+#endif   lookupAtlas _ = () +#if MIN_VERSION_manifolds(0,6,0)+instance SemimanifoldWithBoundary ColourNeedle where+  type Interior ColourNeedle = ColourNeedle+  type Boundary ColourNeedle = EmptyMfd ℝ⁰+  type HalfNeedle ColourNeedle = ℝay+  smfdWBoundWitness = OpenManifoldWitness+  (|+^) b = case b of {}+  _ .+^| b = case b of {}+  fromBoundary b = case b of {}+  fromInterior = id++instance PseudoAffineWithBoundary ColourNeedle where+  _ !-| b = case b of {}+  (.--!) = (.-~!)++instance ProjectableBoundary ColourNeedle where+  projectToBoundary _ b = case b of {}+  marginFromBoundary b _ = case b of {}+#endif+ instance AffineSpace ColourNeedle where   type Diff ColourNeedle = ColourNeedle   (.-.) = (.-~!)@@ -252,22 +300,95 @@ --   = (y - 1 +! sqrt( 1 + y² ) ) / (2*y)  -- unstable for y ≈ 0 --   = 1/2 - (1 - sqrt( 1 + y² ) ) / (2*y) -bijectFromLtd :: CD¹ ℝ⁰ -> Maybe ℝ+bijectFromLtd :: CD¹ ℝ⁰ -> Either S⁰ ℝ bijectFromLtd (CD¹ x Origin)-    | x>0 && x<1  = return $ (x - 0.5) / (x*(1 - x))-    | otherwise   = empty+    | x<=1e-9     = Left NegativeHalfSphere+    | x>=1-1e-9   = Left PositiveHalfSphere+    | otherwise   = return $ (x - 0.5) / (x*(1 - x)) +++#if MIN_VERSION_manifolds(0,6,0)+instance AdditiveMonoid ColourHalfNeedle+instance HalfSpace ColourHalfNeedle+#endif++#if MIN_VERSION_manifolds(0,6,0)+instance QC.Arbitrary ColourBoundary where+  arbitrary = ColourBoundarySphere <$> QC.arbitrary++instance SemimanifoldWithBoundary ColourBoundary where+  type Boundary ColourBoundary = EmptyMfd ℝ⁰+  type Interior ColourBoundary = ColourBoundary+  type HalfNeedle ColourBoundary = ℝay+  smfdWBoundWitness = OpenManifoldWitness+  needleIsOpenMfd q = q+  b|+^_ = case b of {}+  _.+^|b = case b of {}+  fromInterior = id+  fromBoundary b = case b of {}+#endif++instance Hask.Foldable RGB where+  foldMap f (RGB r g b) = f r `mappend` f g `mappend` f b++projectRGBToColourBoundary :: RGB ℝ -> ColourBoundary+projectRGBToColourBoundary c = ColourBoundarySphere $ S²Polar ϑ φ+ where (h,_,l) = hslView c+       φ = h*2*pi/360 - pi+       ϑ = l * pi++#if MIN_VERSION_manifolds(0,6,0)+instance SemimanifoldWithBoundary (Colour ℝ) where+  type Boundary (Colour ℝ) = ColourBoundary+  type HalfNeedle (Colour ℝ) = ColourHalfNeedle+  smfdWBoundWitness = undefined -- SmfdWBoundWitness+  needleIsOpenMfd q = q+  fromBoundary (ColourBoundarySphere (S²Polar ϑ φ))+        = fromRGB $ hsl ((φ+pi)*360/(2*pi)) 1 (ϑ/pi)+  b |+^ ColourHalfNeedle (Cℝay d Origin) δb+        = fromRGB $ hsl ((φ+pi)*360/(2*pi)) (1/(d+1)) (0.5 + (ϑ/pi-0.5)/(d+1))+   where ColourBoundarySphere (S²Polar ϑ φ) = b.+~^δb+  c .+^| ColourNeedle dc+    | η>1        = Left (projectRGBToColourBoundary $ (+).(/η) <$> dc <*> rgb, η - 1)+    | otherwise  = case separateInterior . fromRGB $ (+)<$>dc<*>rgb of+                     Right c' -> Right c'+                     Left c'b -> error $ show (η, (+)<$>dc<*>rgb)+   where rgb = toRGB c+         η = maximum $ (\m d -> if d>0 then if m<1 then d/(1-m) else huge+                                 else if d<0 then -d/m+                                 else 0)+                      <$> rgb <*> dc+         huge = 1e12+  separateInterior c = case toin $ toLtdRGB c of+           Left _ -> Left . projectRGBToColourBoundary $ toRGB c+           Right ci -> Right $ ColourNeedle ci+   where rgb = toRGB c+         toin (RGB r g b) = liftA3 RGB (bijectFromLtd r) (bijectFromLtd g) (bijectFromLtd b)+#else instance Semimanifold (Colour ℝ) where-  type Interior (Colour ℝ) = ColourNeedle   type Needle (Colour ℝ) = ColourNeedle+#endif+  type Interior (Colour ℝ) = ColourNeedle   fromInterior (ColourNeedle q) = fromLtdRGB $ fmap bijectToLtd q-  toInterior = fmap ColourNeedle . toin . toLtdRGB+  toInterior = fmap ColourNeedle . eitherToMaybe . toin . toLtdRGB    where toin (RGB r g b) = liftA3 RGB (bijectFromLtd r) (bijectFromLtd g) (bijectFromLtd b)+#if !MIN_VERSION_manifolds(0,6,0)   translateP = pure (^+^)+#endif +#if MIN_VERSION_manifolds(0,6,0)+instance PseudoAffineWithBoundary (Colour ℝ) where+  c .--! d = ColourNeedle $ (-) <$> toRGB c <*> toRGB d+#else instance PseudoAffine (Colour ℝ) where   c .-~. ζ = liftA2 (^-^) (toInterior c) (toInterior ζ)+#endif +eitherToMaybe :: Either a b -> Maybe b+eitherToMaybe (Left _) = Nothing+eitherToMaybe (Right x) = Just x+ instance Geodesic (Colour ℝ) where   geodesicBetween a b = return $ \(D¹ q) -> blend ((q+1)/2) b a @@ -281,8 +402,10 @@ instance Atlas (Colour ℝ) where   type ChartIndex (Colour ℝ) = ()   chartReferencePoint () = grey+#if !MIN_VERSION_manifolds(0,6,0)   interiorChartReferencePoint = \_ () -> intGrey    where Just intGrey = toInterior (grey :: Colour ℝ)+#endif   lookupAtlas _ = ()  class QuantisedColour c where@@ -315,6 +438,9 @@ colourMapPlane :: Traversal' (ColourMap x) ColourPlane colourMapPlane = lens _cmPlane (\cm pl' -> cm{_cmPlane = pl'}) +fromRGB :: Fractional a => RGB a -> Colour a+fromRGB (RGB r g b) = rgb r g b+ data ColourPlane = ColourPlane {         _cpCold :: Colour ℝ       , _cpNeutral :: Interior (Colour ℝ)@@ -350,7 +476,7 @@                             (spanNorm [(256,0), (0,256)])                                      :: Shade (ℝ,ℝ)    where Just shFn = rangeWithinVertices ((0,0), neutralC)-                                        [((1,0), coldC), ((0,1), hotC)]+                                        [((1,0) :: (ℝ,ℝ), coldC), ((0,1), hotC)]  instance ColourMappable (ℝ,ℝ) where   type ColourMapped (ℝ,ℝ) = Colour ℝ
+ src/Data/Colour/Manifold/Internal.hs view
@@ -0,0 +1,42 @@+{-# LANGUAGE TypeFamilies         #-}+{-# LANGUAGE FlexibleInstances    #-}+{-# LANGUAGE UndecidableInstances #-}+{-# LANGUAGE FlexibleContexts     #-}+{-# LANGUAGE TypeOperators        #-}+{-# LANGUAGE TypeApplications     #-}+{-# LANGUAGE UnicodeSyntax        #-}+{-# LANGUAGE ScopedTypeVariables  #-}+{-# LANGUAGE TemplateHaskell      #-}+{-# LANGUAGE Rank2Types           #-}+{-# LANGUAGE DeriveGeneric        #-}+{-# LANGUAGE DeriveAnyClass       #-}+{-# LANGUAGE EmptyCase            #-}+{-# LANGUAGE CPP                  #-}++module Data.Colour.Manifold.Internal where++import Data.Colour.SRGB.Linear+import Data.Manifold.Types+import Math.LinearMap.Category+import Linear.V3+import GHC.Generics++newtype ColourNeedle = ColourNeedle { getRGBNeedle :: RGB ℝ } deriving (Eq, Show)++asV3Needle :: ColourNeedle -+> V3 ℝ+asV3Needle = LinearFunction $ \(ColourNeedle (RGB r g b)) -> V3 r g b++fromV3Needle :: V3 ℝ -+> ColourNeedle+fromV3Needle = LinearFunction $ \(V3 r g b) -> ColourNeedle $ RGB r g b+++newtype ColourBoundary = ColourBoundarySphere {+   getColourBounarySphere :: S² -- ^ Corresponds to an inflated version of the HSL bicone+  }+ deriving (Generic, Semimanifold, PseudoAffine, Eq, Show)++data ColourHalfNeedle = ColourHalfNeedle {+         colourBoundaryDistance :: !ℝay+       , colourBoundaryTangent :: !(Needle ColourBoundary)+       }+   deriving (Generic)
+ test/tasty/test.hs view
@@ -0,0 +1,131 @@+-- |+-- Module      : test+-- Copyright   : (c) Justus Sagemüller 2022+-- License     : GPL v3+-- +-- Maintainer  : (@) jsag $ hvl.no+-- Stability   : experimental+-- Portability : portable+-- ++{-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE TypeOperators       #-}+{-# LANGUAGE FlexibleContexts    #-}+{-# LANGUAGE FlexibleInstances   #-}+{-# LANGUAGE UnicodeSyntax       #-}+{-# LANGUAGE AllowAmbiguousTypes #-}+{-# LANGUAGE TypeApplications    #-}+{-# LANGUAGE DeriveGeneric       #-}+{-# LANGUAGE DeriveAnyClass      #-}+{-# LANGUAGE DerivingStrategies  #-}+{-# LANGUAGE DataKinds           #-}+{-# LANGUAGE TypeFamilies        #-}+{-# LANGUAGE TupleSections       #-}+{-# LANGUAGE CPP                 #-}++import Math.Manifold.Core.PseudoAffine+import Data.Manifold.Types+import Data.Manifold.WithBoundary+import Data.VectorSpace+import Data.Semigroup++import Data.Colour.Manifold+import Data.Colour.Manifold.Internal+import Data.Colour+import Data.Colour.SRGB.Linear++import Test.Tasty+import Test.Tasty.QuickCheck+import qualified Test.QuickCheck as QC+import System.Random (Random)+import Text.Printf++main :: IO ()+main = do+  putStrLn "here"+  defaultMain $ testGroup "Tests"+   [ testGroup "Sanity checks"+    [ testProperty "Self equality"+     $ \(c :: Colour ℝ) -> c ≈≈≈ c+    , testProperty "Equality nontriviality"+     . QC.expectFailure $ \(c :: Colour ℝ) d -> c ≈≈≈ d+    ]+   , testGroup "Manifold laws"+    [ testProperty "Zero displacement"+     $ \(c :: Colour ℝ) -> case toInterior c of+          Nothing -> undefined+          Just ci -> case c .+^| zeroV of+            Right c' -> c'≈≈≈ci+    , testProperty "Boundary retrieval"+     $ \ce -> separateInterior (fromBoundary ce :: Colour ℝ) ≈≈≈ Left ce+    , testProperty "Interior retrieval"+     $ \ci -> separateInterior (fromInterior ci :: Colour ℝ) ≈≈≈ Right ci+    , testProperty "Difference re-addition"+     $ \(c :: Colour ℝ) d+         -> let Just v = c.--.d+            in QC.counterexample (printf "v = %s\n" (show v)) $ case d .+^| v of+                   Left (cb, η) -> QC.property (abs η < 1e-6) .&&. fromBoundary cb ≈≈≈ c+                   Right ci     -> fromInterior ci ≈≈≈ c+    , testProperty "Displacement re-subtraction"+     $ \(c :: Colour ℝ) v+         -> case c .+^| v of+              Left (db, η) -> let w = fromBoundary db.--!c+                                  μ = v<.>w+                                  λ = v<.>v+                              in QC.property (μ>=0 && μ<=λ)+                                     .&&. v^*(μ/λ) ≈≈≈ w+                                     .&&. w^*(1+η) ≈≈≈ v+              Right di     -> fromInterior di.--!c ≈≈≈ v+    ]+   ]+++infix 4 ≈≈, ≈≈≈++class NearEq a where+  (≈≈) :: a -> a -> Bool++instance NearEq ℝ where+  n ≈≈ m+   | abs n<=1, m<=1  = abs (n-m) < 1e-9+   | otherwise       = abs (n-m) < 1e-9 * (abs n + abs n)+instance (NearEq a, NearEq b) => NearEq (a,b) where+  (x,y) ≈≈ (ξ,υ) = x≈≈ξ && y≈≈υ+instance (NearEq a, NearEq b, NearEq c) => NearEq (a,b,c) where+  (x,y,z) ≈≈ (ξ,υ,ζ) = x≈≈ξ && y≈≈υ && z≈≈ζ+instance NearEq a => NearEq (RGB a) where+  RGB r g b ≈≈ RGB ρ γ β = r≈≈ρ && g≈≈γ && b≈≈β+instance NearEq a => NearEq (Maybe a) where+  Just p ≈≈ Just q = p≈≈q+  Nothing ≈≈ Nothing = True+  _ ≈≈ _ = False+instance (NearEq a, NearEq b) => NearEq (Either a b) where+  Left p ≈≈ Left q = p≈≈q+  Right p ≈≈ Right q = p≈≈q+  _ ≈≈ _ = False+instance NearEq D¹ where+  D¹ p ≈≈ D¹ q = abs (p-q) < 1e-9+instance NearEq S² where+  p ≈≈ q = magnitude (p.-~.q) < 1e-9++instance (NearEq a, Fractional a) => NearEq (Colour a) where+  c ≈≈ ζ = toRGB c ≈≈ toRGB ζ+instance NearEq ColourNeedle where+  ColourNeedle v ≈≈ ColourNeedle w = v ≈≈ w+instance (Fractional a, Random a) => QC.Arbitrary (Colour a) where+  arbitrary = rgb <$> QC.choose (0,1) <*> QC.choose (0,1) <*> QC.choose (0,1)+instance NearEq ColourBoundary where+  ColourBoundarySphere v ≈≈ ColourBoundarySphere w = v ≈≈ w++(≈≈≈) :: (NearEq a, Eq a, Show a)+      => a -> a -> QC.Property+p≈≈≈q+ | p≈≈q       = QC.property True+ | otherwise  = p===q+++++instance InnerSpace ColourNeedle where+  ColourNeedle c <.> ColourNeedle d = pr+pg+pb+   where RGB pr pg pb = (*)<$>c<*>d