hgeometry-0.5.0.0: test/Algorithms/Geometry/SmallestEnclosingDisk/RISpec.hs
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE LambdaCase #-}
module Algorithms.Geometry.SmallestEnclosingDisk.RISpec where
import Util
import Control.Monad(when)
import System.Random(mkStdGen)
import Control.Lens
import Data.Ext
import Data.Maybe
import Data.Proxy
import Test.Hspec
import Data.Geometry
import Data.Geometry.Ball(fromDiameter, disk, Disk)
import Data.Geometry.Ipe
import Algorithms.Geometry.SmallestEnclosingBall.Types
import qualified Algorithms.Geometry.SmallestEnclosingBall.RandomizedIncrementalConstruction as RIC
import qualified Algorithms.Geometry.SmallestEnclosingBall.Naive as Naive
spec :: Spec
spec = testCases "test/Algorithms/Geometry/SmallestEnclosingDisk/manual.ipe"
testCases :: FilePath -> Spec
testCases fp = (runIO $ readInput fp) >>= \case
Left e -> it "reading Smallest enclosing disk file" $
expectationFailure $ "Failed to read ipe file " ++ show e
Right tcs -> mapM_ toSpec tcs
data TestCase r = TestCase { _pointSet :: [Point 2 r :+ ()]
, _solution :: Maybe (TwoOrThree (Point 2 r))
}
deriving (Show,Eq)
toSpec :: (Fractional r, Ord r, Show r) => TestCase r -> Spec
toSpec (TestCase pts sol) =
describe ("testing point set with solution " ++ show sol) $ do
it "comparing with naive solution" $
((RIC.smallestEnclosingDisk (mkStdGen 2123) pts)^.enclosingDisk)
`shouldBe`
((Naive.smallestEnclosingDisk pts)^.enclosingDisk)
when (isJust sol) $
it "manal solution" $
((RIC.smallestEnclosingDisk (mkStdGen 5) pts)^.enclosingDisk)
`shouldBe`
(diskOf $ fromJust sol)
diskOf :: (Fractional r, Eq r)
=> TwoOrThree (Point 2 r) -> Disk () r
diskOf (Two p q) = fromDiameter p q
diskOf (Three p q r) = fromMaybe (error "Wrong manual disk") $ disk p q r
-- | Point sets per color, Crosses form the solution
readInput :: FilePath -> IO (Either ConversionError [TestCase Rational])
readInput fp = fmap f <$> readSinglePageFile fp
where
f page = [ TestCase [p^.core.symbolPoint :+ () | p <- pSet] (solutionOf pSet)
| pSet <- byStrokeColour syms
]
where
syms = page^..content.traverse._IpeUse
-- | Crosses form a solution
isInSolution s = s^.core.symbolName == "mark/cross(sx)"
right = either (const Nothing) Just
solutionOf = right . fromList . map (^.core.symbolPoint) . filter isInSolution