{-# LANGUAGE FlexibleInstances #-} module Data.Geometry.Geos.Raw.CoordSeq ( CoordinateSequence(..) , CoordSeqConst(CoordSeqConst) , CoordSeq(CoordSeq) , getCoordinateSequenceX , getCoordinateSequenceY , getCoordinateSequenceZ , getCoordinateSequenceSize , getCoordinateSequenceDimensions , setCoordinateSequenceX , setCoordinateSequenceY , setCoordinateSequenceZ , setCoordinateSequenceOrd ) where import qualified Data.Geometry.Geos.Raw.Internal as I import Data.Geometry.Geos.Raw.Base import Foreign hiding ( throwIfNull , void ) import Foreign.C.Types import Control.Monad class CoordinateSequence a where withCoordinateSequence :: a -> (Ptr I.GEOSCoordSequence -> IO b) -> IO b createEmptyCoordinateSequence :: Int -> Int -> Geos a createCoordinateSequence :: Ptr I.GEOSCoordSequence -> Geos a newtype CoordSeq = CoordSeq { _unCoordSeq :: ForeignPtr I.GEOSCoordSequence } newtype CoordSeqConst = CoordSeqConst { _unCoordSeqConst :: Ptr I.GEOSCoordSequence } instance Eq CoordSeq where (==) = coordSeqEq instance Eq CoordSeqConst where (==) = coordSeqEq coordSeqEq :: CoordinateSequence a => a -> a -> Bool coordSeqEq a b = runGeos $ do sa <- getCoordinateSequenceSize a sb <- getCoordinateSequenceSize b da <- getCoordinateSequenceDimensions a db <- getCoordinateSequenceDimensions b if (sa == sb) && (da == db) then foldM (comp (da == 3)) True [0 .. (sa - 1)] else return False where comp zdim acc i = do xa <- getCoordinateSequenceX a i ya <- getCoordinateSequenceY a i xb <- getCoordinateSequenceX b i yb <- getCoordinateSequenceY b i zd <- if zdim then do za <- getCoordinateSequenceZ a i zb <- getCoordinateSequenceZ b i return $ za == zb else return True return $ (xa == xb) && (ya == yb) && acc && zd instance Show CoordSeq where show = coordSeqShow instance Show CoordSeqConst where show = coordSeqShow coordSeqShow :: CoordinateSequence a => a -> String coordSeqShow a = runGeos $ do sa <- getCoordinateSequenceSize a unlines `fmap` mapM show' [0 .. (sa - 1)] where show' i = do xa <- getCoordinateSequenceX a i ya <- getCoordinateSequenceY a i return . show $ (xa, ya) instance CoordinateSequence CoordSeq where withCoordinateSequence (CoordSeq fp) = withForeignPtr fp createEmptyCoordinateSequence size dim = do ptr <- throwIfNull "createEmptyCoordinateSequence" $ withGeos $ \h -> I.geos_CoordSeqCreate h (fromIntegral size) (fromIntegral dim) createCoordinateSequence ptr createCoordinateSequence ptr = withGeos $ \h -> do fptr <- newForeignPtrEnv I.geos_CoordSeqDestroy h ptr return $ CoordSeq fptr instance CoordinateSequence CoordSeqConst where withCoordinateSequence (CoordSeqConst p) f = f p createEmptyCoordinateSequence size dim = do ptr <- throwIfNull "createEmptyCoordinateSequence" $ withGeos $ \h -> I.geos_CoordSeqCreate h (fromIntegral size) (fromIntegral dim) createCoordinateSequence ptr createCoordinateSequence ptr = return $ CoordSeqConst ptr getCoordinateSequenceD_ :: CoordinateSequence a => ( I.GEOSContextHandle_t -> Ptr I.GEOSCoordSequence -> CUInt -> Ptr CDouble -> IO CInt ) -> a -> Int -> Geos Double getCoordinateSequenceD_ f cs idx = withGeos' $ \h -> alloca $ \dptr -> do eitherRet <- throwIfZero' (mkErrorMessage "getCoordiniateSequenceN") $ withCoordinateSequence cs $ \pcs -> f h pcs (fromIntegral idx) dptr traverse (\_ -> marshallDouble dptr) eitherRet getCoordinateSequenceX :: CoordinateSequence a => a -> Int -> Geos Double getCoordinateSequenceX = getCoordinateSequenceD_ I.geos_CoordSeqGetX getCoordinateSequenceY :: CoordinateSequence a => a -> Int -> Geos Double getCoordinateSequenceY = getCoordinateSequenceD_ I.geos_CoordSeqGetY getCoordinateSequenceZ :: CoordinateSequence a => a -> Int -> Geos Double getCoordinateSequenceZ = getCoordinateSequenceD_ I.geos_CoordSeqGetZ getCoordinateSequenceSize :: CoordinateSequence a => a -> Geos Int getCoordinateSequenceSize c = withGeos' $ \h -> alloca $ \ptr -> do eitherRet <- throwIfZero' (mkErrorMessage "getCoordinateSequenceSize") $ withCoordinateSequence c $ \pc -> I.geos_CoordSeqGetSize h pc ptr traverse (\_ -> marshallInt ptr) eitherRet getCoordinateSequenceDimensions :: CoordinateSequence a => a -> Geos Int getCoordinateSequenceDimensions c = withGeos' $ \h -> alloca $ \ptr -> do eitherRet <- throwIfZero' (mkErrorMessage "getCoordinateSeqenceDimensions") $ withCoordinateSequence c $ \pc -> I.geos_CoordSeqGetDimensions h pc ptr traverse (\_ -> marshallInt ptr) eitherRet --- setCoordinateSequence_ :: CoordinateSequence a => ( I.GEOSContextHandle_t -> Ptr I.GEOSCoordSequence -> CUInt -> CDouble -> IO CInt ) -> a -> Int -> Double -> Geos () setCoordinateSequence_ f cs idx val = void $ throwIfZero (mkErrorMessage "setCoordinateSEquenceN") $ withGeos $ \h -> withCoordinateSequence cs $ \pcs -> f h pcs (fromIntegral idx) (realToFrac val) setCoordinateSequenceX :: CoordinateSequence a => a -> Int -> Double -> Geos () setCoordinateSequenceX = setCoordinateSequence_ I.geos_CoordSeqSetX setCoordinateSequenceY :: CoordinateSequence a => a -> Int -> Double -> Geos () setCoordinateSequenceY = setCoordinateSequence_ I.geos_CoordSeqSetY setCoordinateSequenceZ :: CoordinateSequence a => a -> Int -> Double -> Geos () setCoordinateSequenceZ = setCoordinateSequence_ I.geos_CoordSeqSetZ setCoordinateSequenceOrd :: CoordinateSequence a => a -> Int -> Int -> Double -> Geos () setCoordinateSequenceOrd cs idx dim v = void $ throwIfZero (mkErrorMessage "setCoordinateSequenceN") $ withGeos $ \h -> withCoordinateSequence cs $ \pcs -> I.geos_CoordSeqSetOrdinate h pcs (fromIntegral idx) (fromIntegral dim) (realToFrac v)