hgeos 0.1.1.0 → 0.1.2.0
raw patch · 11 files changed
+453/−160 lines, 11 filesdep +MissingHPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependencies added: MissingH
API changes (from Hackage documentation)
- Data.Geolocation.GEOS: withContext :: (Context -> IO a) -> IO a
- Data.Geolocation.GEOS.Imports: c_uninitializeGEOS :: GEOSContextHandle_t -> IO ()
+ Data.Geolocation.GEOS: GeometryCollection :: GeometryTypeId
+ Data.Geolocation.GEOS: LineString :: GeometryTypeId
+ Data.Geolocation.GEOS: LinearRing :: GeometryTypeId
+ Data.Geolocation.GEOS: MultiPoint :: GeometryTypeId
+ Data.Geolocation.GEOS: MultiPolygon :: GeometryTypeId
+ Data.Geolocation.GEOS: MultlLineString :: GeometryTypeId
+ Data.Geolocation.GEOS: Point :: GeometryTypeId
+ Data.Geolocation.GEOS: Polygon :: GeometryTypeId
+ Data.Geolocation.GEOS: area :: Geometry -> IO (Maybe Double)
+ Data.Geolocation.GEOS: data GeometryTypeId
+ Data.Geolocation.GEOS: geometryTypeId :: Geometry -> IO GeometryTypeId
+ Data.Geolocation.GEOS: getGeometry :: Geometry -> Int -> IO Geometry
+ Data.Geolocation.GEOS: getNumGeometries :: Geometry -> IO Int
+ Data.Geolocation.GEOS: getSize :: CoordinateSequence -> IO (Maybe Word)
+ Data.Geolocation.GEOS: getX :: CoordinateSequence -> Word -> IO (Maybe Double)
+ Data.Geolocation.GEOS: getY :: CoordinateSequence -> Word -> IO (Maybe Double)
+ Data.Geolocation.GEOS: getZ :: CoordinateSequence -> Word -> IO (Maybe Double)
+ Data.Geolocation.GEOS: instance GHC.Enum.Enum Data.Geolocation.GEOS.GeometryTypeId
+ Data.Geolocation.GEOS: instance GHC.Show.Show Data.Geolocation.GEOS.GeometryTypeId
+ Data.Geolocation.GEOS: isEmpty :: Geometry -> IO Bool
+ Data.Geolocation.GEOS: version :: IO String
+ Data.Geolocation.GEOS: withGEOS :: (Context -> IO a) -> IO a
+ Data.Geolocation.GEOS.Imports: c_GEOSArea_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> Ptr CDouble -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSCoordSeq_getSize_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> Ptr CUInt -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSCoordSeq_getX_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSCoordSeq_getY_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSCoordSeq_getZ_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSGeomTypeId_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSGetGeometryN_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> CInt -> IO GEOSGeometryPtr
+ Data.Geolocation.GEOS.Imports: c_GEOSGetNumGeometries_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CInt
+ Data.Geolocation.GEOS.Imports: c_GEOSisEmpty_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CChar
+ Data.Geolocation.GEOS.Imports: c_finishGEOS_r :: GEOSContextHandle_t -> IO ()
- Data.Geolocation.GEOS.Imports: c_GEOSversion :: CString
+ Data.Geolocation.GEOS.Imports: c_GEOSversion :: IO CString
Files
- hgeos.cabal +12/−8
- src/app/HighLevelAPI.hs +18/−0
- src/app/LowLevelAPI.hs +39/−0
- src/app/Main.hs +10/−77
- src/app/Sample.hs +150/−0
- src/lib/Data/Geolocation/GEOS.hs +113/−5
- src/lib/Data/Geolocation/GEOS/Imports.hs +61/−14
- src/lib/Data/Geolocation/GEOS/helpers.c +43/−0
- src/lib/Data/Geolocation/GEOS/helpers.h +7/−0
- src/lib/helpers.c +0/−48
- src/lib/helpers.h +0/−8
hgeos.cabal view
@@ -1,9 +1,10 @@ name: hgeos-version: 0.1.1.0+version: 0.1.2.0 synopsis: Simple Haskell bindings to GEOS C API description:- Simple Haskell bindings to the GEOS C API heavily inspired by- <https://github.com/django/django/tree/master/django/contrib/gis/geos Django GEOS bindings>+ Simple Haskell bindings to the <https://trac.osgeo.org/geos/ GEOS>+ <http://geos.osgeo.org/doxygen/geos__c_8h_source.html C API> heavily inspired+ by <https://github.com/django/django/tree/master/django/contrib/gis/geos Django GEOS bindings> homepage: https://github.com/rcook/hgeos#readme bug-reports: https://github.com/rcook/hgeos/issues license: MIT@@ -25,9 +26,8 @@ default-language: Haskell2010 build-depends: base >= 4.7 && < 5 extra-libraries: geos_c- c-sources: src/lib/helpers.c- , src/lib/helpers.h- includes: src/lib/helpers.h+ c-sources: src/lib/Data/Geolocation/GEOS/helpers.c+ , src/lib/Data/Geolocation/GEOS/helpers.h cc-options: -std=c99 -pthread exposed-modules: Data.Geolocation.GEOS , Data.Geolocation.GEOS.Imports@@ -40,6 +40,10 @@ hs-source-dirs: src/app main-is: Main.hs default-language: Haskell2010- build-depends: base >= 4.7 && < 5+ build-depends: MissingH+ , base >= 4.7 && < 5 , hgeos- other-modules: Main+ other-modules: HighLevelAPI+ , LowLevelAPI+ , Main+ , Sample
+ src/app/HighLevelAPI.hs view
@@ -0,0 +1,18 @@+module HighLevelAPI (demo) where++import Data.Geolocation.GEOS++-- Demonstrates use of high-level API+-- Lifetimes of GEOS objects are automatically managed by the context objects+-- which guarantees that they are released when the context goes out of scope+demo :: IO ()+demo = do+ withGEOS $ \ctx -> do+ reader <- mkReader ctx+ g0 <- readGeometry reader "POLYGON (( 10 10, 10 20, 20 20, 20 10, 10 10 ))"+ g1 <- readGeometry reader "POLYGON (( 11 11, 11 12, 12 12, 12 11, 11 11 ))"+ g2 <- intersection g0 g1+ writer <- mkWriter ctx+ str <- writeGeometry writer g2+ putStrLn str+ putStrLn "HighLevelAPI.demo done"
+ src/app/LowLevelAPI.hs view
@@ -0,0 +1,39 @@+module LowLevelAPI (demo) where++import Control.Exception+import Data.Geolocation.GEOS.Imports+import Foreign.C++-- Demonstrates direct use of imports+-- Lifetimes of various GEOS objects, including readers, writers and+-- geometries, must be managed explicitly by clients using explicit calls to+-- various destroy/free functions+demo :: IO ()+demo = do+ wkt0 <- newCString "POLYGON (( 10 10, 10 20, 20 20, 20 10, 10 10 ))"+ wkt1 <- newCString "POLYGON (( 11 11, 11 12, 12 12, 12 11, 11 11 ))"++ withGEOS $ \ctx -> do+ withWKTReader ctx $ \reader -> do+ withGeometry ctx reader wkt0 $ \g0 -> do+ withGeometry ctx reader wkt1 $ \g1 -> do+ bracket (c_GEOSIntersection_r ctx g0 g1) (c_GEOSGeom_destroy_r ctx) $ \g2 -> do+ withWKTWriter ctx $ \writer -> do+ str <- bracket+ (c_GEOSWKTWriter_write_r ctx writer g2)+ (c_GEOSFree_r_CString ctx)+ peekCString+ putStrLn str+ putStrLn "LowLevelAPI.demo done"+ where+ withGEOS :: (GEOSContextHandle_t -> IO a) -> IO a+ withGEOS = bracket c_initializeGEOSWithHandlers c_finishGEOS_r+ withWKTReader :: GEOSContextHandle_t -> (GEOSWKTReaderPtr -> IO a) -> IO a+ withWKTReader ctx = bracket (c_GEOSWKTReader_create_r ctx) (c_GEOSWKTReader_destroy_r ctx)+ withWKTWriter :: GEOSContextHandle_t -> (GEOSWKTWriterPtr -> IO a) -> IO a+ withWKTWriter ctx = bracket (c_GEOSWKTWriter_create_r ctx) (c_GEOSWKTWriter_destroy_r ctx)+ withGeometry :: GEOSContextHandle_t -> GEOSWKTReaderPtr -> CString -> (GEOSGeometryPtr -> IO a) -> IO a+ withGeometry ctx reader wkt =+ bracket+ (c_GEOSWKTReader_read_r ctx reader wkt)+ (c_GEOSGeom_destroy_r ctx)
src/app/Main.hs view
@@ -1,84 +1,17 @@+{-# LANGUAGE RecordWildCards #-}+ module Main (main) where -import Control.Exception import Data.Geolocation.GEOS-import Data.Geolocation.GEOS.Imports import Foreign.C-import Foreign.Ptr-import Paths_hgeos---- Demonstrates direct use of imports--- Lifetimes of various GEOS objects, including readers, writers and--- geometries, must be managed explicitly by clients using explicit calls to--- various destroy/free functions-lowLevelAPIDemo :: IO ()-lowLevelAPIDemo = do- wkt0 <- newCString "POLYGON (( 10 10, 10 20, 20 20, 20 10, 10 10 ))"- wkt1 <- newCString "POLYGON (( 11 11, 11 12, 12 12, 12 11, 11 11 ))"-- withGEOS $ \ctx -> do- withWKTReader ctx $ \reader -> do- withGeometry ctx reader wkt0 $ \g0 -> do- withGeometry ctx reader wkt1 $ \g1 -> do- bracket (c_GEOSIntersection_r ctx g0 g1) (c_GEOSGeom_destroy_r ctx) $ \g2 -> do- withWKTWriter ctx $ \writer -> do- str <- bracket- (c_GEOSWKTWriter_write_r ctx writer g2)- (c_GEOSFree_r_CString ctx)- peekCString- putStrLn str- putStrLn "lowLevelAPIDemo done"- where- withGEOS :: (GEOSContextHandle_t -> IO a) -> IO a- withGEOS = bracket c_initializeGEOSWithHandlers c_uninitializeGEOS- withWKTReader :: GEOSContextHandle_t -> (GEOSWKTReaderPtr -> IO a) -> IO a- withWKTReader ctx = bracket (c_GEOSWKTReader_create_r ctx) (c_GEOSWKTReader_destroy_r ctx)- withWKTWriter :: GEOSContextHandle_t -> (GEOSWKTWriterPtr -> IO a) -> IO a- withWKTWriter ctx = bracket (c_GEOSWKTWriter_create_r ctx) (c_GEOSWKTWriter_destroy_r ctx)- withGeometry :: GEOSContextHandle_t -> GEOSWKTReaderPtr -> CString -> (GEOSGeometryPtr -> IO a) -> IO a- withGeometry ctx reader wkt =- bracket- (c_GEOSWKTReader_read_r ctx reader wkt)- (c_GEOSGeom_destroy_r ctx)---- Demonstrates use of high-level API--- Lifetimes of GEOS objects are automatically managed by the context objects--- which guarantees that they are released when the context goes out of scope-highLevelAPIDemo :: IO ()-highLevelAPIDemo = do- withContext $ \ctx -> do- reader <- mkReader ctx- g0 <- readGeometry reader "POLYGON (( 10 10, 10 20, 20 20, 20 10, 10 10 ))"- g1 <- readGeometry reader "POLYGON (( 11 11, 11 12, 12 12, 12 11, 11 11 ))"- g2 <- intersection g0 g1- writer <- mkWriter ctx- str <- writeGeometry writer g2- putStrLn str- putStrLn "highLevelAPIDemo done"+import qualified HighLevelAPI+import qualified LowLevelAPI+import qualified Sample main :: IO () main = do- --s <- peekCString c_GEOSversion- --putStrLn s- --lowLevelAPIDemo- --highLevelAPIDemo- namibiaDemo--printGeometry :: Writer -> Geometry -> IO ()-printGeometry r g = writeGeometry r g >>= putStrLn--namibiaDemo :: IO ()-namibiaDemo = do- fileName <- getDataFileName "data/namibia.wkt"- wkt <- readFile fileName- withContext $ \ctx -> do- reader <- mkReader ctx- writer <- mkWriter ctx- let p = printGeometry writer-- country <- readGeometry reader wkt- env <- envelope country- shell <- exteriorRing env- coordSeq <- coordinateSequence shell- p shell- return ()+ v <- version+ putStrLn v+ LowLevelAPI.demo+ HighLevelAPI.demo+ Sample.demo
+ src/app/Sample.hs view
@@ -0,0 +1,150 @@+{-# LANGUAGE RecordWildCards #-}++module Sample (demo) where++import Control.Monad+import Data.Geolocation.GEOS+import Data.List+import Data.String.Utils+import Paths_hgeos+import Text.Printf++printGeometry :: Writer -> Geometry -> IO ()+printGeometry r g = writeGeometry r g >>= putStrLn++type Coordinate = (Double, Double, Double)++getXYZs :: CoordinateSequence -> IO (Maybe [Coordinate])+getXYZs coordSeq = do+ maybeSize <- getSize coordSeq+ case maybeSize of+ Nothing -> return Nothing+ Just size -> do+ xyzs <- forM [0..(size - 1)] $ \i -> do+ (Just x) <- getX coordSeq i+ (Just y) <- getY coordSeq i+ (Just z) <- getZ coordSeq i+ return (x, y, z)+ return $ Just xyzs++data Extent = Extent+ { minX :: Double+ , maxX :: Double+ , minY :: Double+ , maxY :: Double+ , minZ :: Double+ , maxZ :: Double+ } deriving Show++extent :: [Coordinate] -> Extent+extent ((x, y, z) : cs) =+ let (minX, maxX, minY, maxY, minZ, maxZ) =+ foldr (\(x', y', z') (minX, maxX, minY, maxY, minZ, maxZ) ->+ (if x' < minX then x' else minX,+ if x' > maxX then x' else maxX,+ if y' < minY then y' else minY,+ if y' > maxY then y' else maxY,+ if z' < minZ then z' else minZ,+ if z' > maxX then z' else maxZ)) (x, x, y, y, z, z) cs+ in Extent minX maxX minY maxY minZ maxZ++mfloor :: Double -> Double -> Double+mfloor m x = (fromInteger $ floor (x / m)) * m++frange :: Double -> Double -> Double -> [Double]+frange lower upper step =+ let count = (upper - lower) / step+ in [lower + (fromIntegral i) * step | i <- [0..(round count - 1)]]++type Longitude = Double+type Latitude = Double+type Resolution = Double++mkSquare :: Reader -> Longitude -> Latitude -> Resolution -> IO Geometry+mkSquare reader longitude latitude resolution =+ let points = [+ (longitude, latitude),+ (longitude + resolution, latitude),+ (longitude + resolution, latitude + resolution),+ (longitude, latitude + resolution),+ (longitude, latitude)+ ]+ wkt = printf "POLYGON ((%s))" (intercalate "," (map (\(a, b) -> printf "%f %f" a b) points))+ in readGeometry reader wkt++getGeometries :: Geometry -> IO [Geometry]+getGeometries geometry = do+ count <- getNumGeometries geometry+ forM [0..(count - 1)] (getGeometry geometry)++findBiggestPolygon :: Geometry -> IO Geometry+findBiggestPolygon geometry = do+ geometries@(g : gs) <- getGeometries geometry+ a : as <- sequence $ map area geometries+ let (g', _) = foldr (\p@(_, a') biggest@(_, aBiggest) -> if a' > aBiggest then p else biggest) (g, a) (zip gs as)+ return g'++resolution :: Double+resolution = 1.0++processPolygon :: String -> Resolution -> Longitude -> Latitude -> Geometry -> IO ()+processPolygon tableName resolution longitude latitude p = do+ let pId = polygonId resolution longitude latitude+ shell <- exteriorRing p+ coordSeq <- coordinateSequence shell+ (Just xyzs) <- getXYZs coordSeq+ forM_ (zip [0..] xyzs) $ \(pointId, (x, y, _)) -> do+ let s = printf+ "INSERT INTO %s (polygon_id, point_id, longitude, latitude) VALUES ('%s', %d, %f, %f);\n"+ tableName+ pId+ (pointId :: Int)+ x+ y+ putStr s++polygonId :: Resolution -> Longitude -> Latitude -> String+polygonId resolution longitude latitude = "id_" ++ formatValue longitude ++ "_" ++ formatValue latitude+ where+ formatValue :: Double -> String+ formatValue = replace "-" "m" . replace "." "_" . (printf "%.2f") . mfloor resolution++-- A more involved example of use of API+demo :: IO ()+demo = do+ fileName <- getDataFileName "data/namibia.wkt"+ wkt <- readFile fileName+ withGEOS $ \ctx -> do+ reader <- mkReader ctx+ writer <- mkWriter ctx+ let p = printGeometry writer++ country <- readGeometry reader wkt+ env <- envelope country+ shell <- exteriorRing env+ coordSeq <- coordinateSequence shell+ (Just xyzs) <- getXYZs coordSeq+ forM_ xyzs $ \(x, y, z) -> print (x, y, z)+ let Extent{..} = extent xyzs+ mfloorRes = mfloor resolution+ longitudeBegin = mfloorRes minX+ longitudeEnd = mfloorRes maxX + resolution+ latitudeBegin = mfloorRes minY+ latitudeEnd = mfloorRes maxY + resolution+ print longitudeBegin+ print longitudeEnd+ print latitudeBegin+ print latitudeEnd+ let longitudes = frange longitudeBegin longitudeEnd 1.0+ latitudes = frange latitudeBegin latitudeEnd 1.0+ forM_ [(i, j) | i <- longitudes, j <- latitudes] $ \(longitude, latitude) -> do+ square <- mkSquare reader longitude latitude resolution+ overlap <- intersection square country+ x <- isEmpty overlap+ unless x $ do+ id <- geometryTypeId overlap+ polygon <- case id of+ MultiPolygon -> findBiggestPolygon overlap+ Polygon -> return overlap+ processPolygon "foo" resolution longitude latitude polygon+ putStrLn "Sample.demo done"
src/lib/Data/Geolocation/GEOS.hs view
@@ -11,6 +11,10 @@ management of lifetimes of objects such as readers, writers and geometries. For the low-level FFI bindings, see "Data.Geolocation.GEOS.Imports".++<https://github.com/rcook/hgeos/blob/master/src/app/HighLevelAPI.hs View sample 1>++<https://github.com/rcook/hgeos/blob/master/src/app/Sample.hs View sample 2> -} {-# LANGUAGE RecordWildCards #-}@@ -19,23 +23,38 @@ ( Context () , CoordinateSequence () , Geometry ()+ , GeometryTypeId (..) , Reader () , Writer ()+ , area , coordinateSequence , envelope , exteriorRing+ , geometryTypeId+ , getGeometry+ , getNumGeometries+ , getSize+ , getX+ , getY+ , getZ , intersection+ , isEmpty , mkReader , mkWriter , readGeometry- , withContext+ , version+ , withGEOS , writeGeometry ) where import Control.Exception import Data.Geolocation.GEOS.Imports import Data.IORef+import Data.Word import Foreign.C+import Foreign.Marshal.Alloc+import Foreign.Ptr+import Foreign.Storable -- |Represents a <https://trac.osgeo.org/geos/ GEOS> context data Context = Context ContextStateRef@@ -53,6 +72,17 @@ -- |References a <https://trac.osgeo.org/geos/ GEOS> coordinate sequence data CoordinateSequence = CoordinateSequence ContextStateRef GEOSCoordSequencePtr +-- |Represents a <https://trac.osgeo.org/geos/ GEOS> geometry type ID+data GeometryTypeId =+ Point |+ LineString |+ LinearRing |+ Polygon |+ MultiPoint |+ MultlLineString |+ MultiPolygon |+ GeometryCollection deriving (Enum, Show)+ -- |References a <https://en.wikipedia.org/wiki/Well-known_text WKT> reader data Reader = Reader ContextStateRef GEOSWKTReaderPtr @@ -62,6 +92,18 @@ -- |References a <https://trac.osgeo.org/geos/ GEOS> geometry data Geometry = Geometry ContextStateRef GEOSGeometryPtr +-- |Returns area of a 'Geometry' instance+area :: Geometry -> IO (Maybe Double)+area (Geometry sr h) = do+ ContextState{..} <- readIORef sr+ alloca $ \valuePtr -> do+ status <- c_GEOSArea_r hCtx h valuePtr+ case status of+ 0 -> return Nothing+ _ -> do+ value <- peek valuePtr+ return $ Just (realToFrac value)+ -- |Returns a 'CoordinateSequence' from the supplied 'Geometry' coordinateSequence :: Geometry -> IO CoordinateSequence coordinateSequence (Geometry sr hGeometry) = do@@ -89,12 +131,74 @@ exteriorRing (Geometry sr h) = doNotTrack sr (\hCtx -> c_GEOSGetExteriorRing_r hCtx h) +-- |Returns type ID of a 'Geometry' instance+geometryTypeId :: Geometry -> IO GeometryTypeId+geometryTypeId (Geometry sr h) = do+ ContextState{..} <- readIORef sr+ value <- c_GEOSGeomTypeId_r hCtx h+ return $ toEnum (fromIntegral value)++-- |Returns child 'Geometry' at given index+getGeometry :: Geometry -> Int -> IO Geometry+getGeometry (Geometry sr h) index =+ doNotTrack sr (\hCtx -> c_GEOSGetGeometryN_r hCtx h (fromIntegral index))++-- |Gets the number of geometries in a 'Geometry' instance+getNumGeometries :: Geometry -> IO Int+getNumGeometries (Geometry sr h) = do+ ContextState{..} <- readIORef sr+ value <- c_GEOSGetNumGeometries_r hCtx h+ return $ fromIntegral value++getOrdinate :: (GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt) ->+ CoordinateSequence -> Word -> IO (Maybe Double)+getOrdinate f (CoordinateSequence sr h) index = do+ ContextState{..} <- readIORef sr+ alloca $ \valuePtr -> do+ status <- f hCtx h (fromIntegral index) valuePtr+ case status of+ 0 -> return Nothing+ _ -> do+ value <- peek valuePtr+ return $ Just (realToFrac value)++-- |Gets the size from a coordinate sequence+getSize :: CoordinateSequence -> IO (Maybe Word)+getSize (CoordinateSequence sr h) = do+ ContextState{..} <- readIORef sr+ alloca $ \sizePtr -> do+ status <- c_GEOSCoordSeq_getSize_r hCtx h sizePtr+ case status of+ 0 -> return Nothing+ _ -> do+ size <- peek sizePtr+ return $ Just (fromIntegral size)++-- |Gets an "x" ordinate value from a coordinate sequence+getX :: CoordinateSequence -> Word -> IO (Maybe Double)+getX = getOrdinate c_GEOSCoordSeq_getX_r++-- |Gets a "y" ordinate value from a coordinate sequence+getY :: CoordinateSequence -> Word -> IO (Maybe Double)+getY = getOrdinate c_GEOSCoordSeq_getY_r++-- |Gets a "z" ordinate value from a coordinate sequence+getZ :: CoordinateSequence -> Word -> IO (Maybe Double)+getZ = getOrdinate c_GEOSCoordSeq_getZ_r+ -- |Returns a 'Geometry' instance representing the intersection of the two -- supplied 'Geometry' instances: intersection :: Geometry -> Geometry -> IO Geometry intersection (Geometry sr0 h0) (Geometry sr1 h1) = track sr0 (\hCtx -> c_GEOSIntersection_r hCtx h0 h1) +-- |Returns value indicating if specified 'Geometry' instance is empty+isEmpty :: Geometry -> IO Bool+isEmpty (Geometry sr h) = do+ ContextState{..} <- readIORef sr+ value <- c_GEOSisEmpty_r hCtx h+ return $ value /= 0+ mkContext :: IO Context mkContext = do hCtx <- c_initializeGEOSWithHandlers@@ -132,7 +236,7 @@ mapM_ (c_GEOSGeom_destroy_r hCtx) hGeometries mapM_ (c_GEOSWKTWriter_destroy_r hCtx) hWriters mapM_ (c_GEOSWKTReader_destroy_r hCtx) hReaders- c_uninitializeGEOS hCtx+ c_finishGEOS_r hCtx track :: ContextStateRef -> (GEOSContextHandle_t -> IO GEOSGeometryPtr) -> IO Geometry track sr f = do@@ -141,19 +245,23 @@ modifyIORef' sr $ (\p@ContextState{..} -> p { hGeometries = h : hGeometries }) return $ Geometry sr h +-- |Reports version of GEOS API+version :: IO String+version = c_GEOSversion >>= peekCString+ -- |Creates a <https://trac.osgeo.org/geos/ GEOS> context, passes it to a block -- and releases the context and all associated objects such as readers, writers -- and geometries at the end: -- -- @--- withContext $ \ctx -> do+-- withGEOS $ \ctx -> do -- -- -- Use context -- -- return () -- @-withContext :: (Context -> IO a) -> IO a-withContext = bracket mkContext releaseContext+withGEOS :: (Context -> IO a) -> IO a+withGEOS = bracket mkContext releaseContext -- |Serializes a 'Geometry' instance to a 'String' using the supplied 'Writer': writeGeometry :: Writer -> Geometry -> IO String
src/lib/Data/Geolocation/GEOS/Imports.hs view
@@ -13,6 +13,8 @@ high-level wrappers do not yet exist. For the high-level API, see "Data.Geolocation.GEOS".++<https://github.com/rcook/hgeos/blob/master/src/app/LowLevelAPI.hs View sample> -} module Data.Geolocation.GEOS.Imports@@ -21,12 +23,20 @@ , GEOSGeometryPtr () , GEOSWKTReaderPtr () , GEOSWKTWriterPtr ()+ , c_GEOSArea_r+ , c_GEOSCoordSeq_destroy_r+ , c_GEOSCoordSeq_getSize_r+ , c_GEOSCoordSeq_getX_r+ , c_GEOSCoordSeq_getY_r+ , c_GEOSCoordSeq_getZ_r , c_GEOSEnvelope_r , c_GEOSFree_r_CString- , c_GEOSCoordSeq_destroy_r+ , c_GEOSGeomTypeId_r , c_GEOSGeom_destroy_r , c_GEOSGeom_getCoordSeq_r , c_GEOSGetExteriorRing_r+ , c_GEOSGetGeometryN_r+ , c_GEOSGetNumGeometries_r , c_GEOSIntersection_r , c_GEOSWKTReader_create_r , c_GEOSWKTReader_destroy_r@@ -34,9 +44,10 @@ , c_GEOSWKTWriter_create_r , c_GEOSWKTWriter_destroy_r , c_GEOSWKTWriter_write_r+ , c_GEOSisEmpty_r , c_GEOSversion+ , c_finishGEOS_r , c_initializeGEOSWithHandlers- , c_uninitializeGEOS ) where import Foreign.C@@ -57,10 +68,30 @@ -- |Wraps @GEOSWKTWriter*@ newtype GEOSWKTWriterPtr = GEOSWKTWriterPtr (Ptr GEOSWKTWriterPtr) +-- |Wraps @GEOSArea_r@+foreign import ccall "GEOSArea_r"+ c_GEOSArea_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> Ptr CDouble -> IO CInt+ -- |Wraps @GEOSCoordSeq_destroy_r@ foreign import ccall "GEOSCoordSeq_destroy_r" c_GEOSCoordSeq_destroy_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> IO () +-- |Wraps @GEOSCoordSeq_getSize_r@+foreign import ccall "GEOSCoordSeq_getSize_r"+ c_GEOSCoordSeq_getSize_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> Ptr CUInt -> IO CInt++-- |Wraps @GEOSCoordSeq_getX_r@+foreign import ccall "GEOSCoordSeq_getX_r"+ c_GEOSCoordSeq_getX_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt++-- |Wraps @GEOSCoordSeq_getY_r@+foreign import ccall "GEOSCoordSeq_getY_r"+ c_GEOSCoordSeq_getY_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt++-- |Wraps @GEOSCoordSeq_getZ_r@+foreign import ccall "GEOSCoordSeq_getZ_r"+ c_GEOSCoordSeq_getZ_r :: GEOSContextHandle_t -> GEOSCoordSequencePtr -> CUInt -> Ptr CDouble -> IO CInt+ -- |Wraps @GEOSEnvelope_r@ foreign import ccall "GEOSEnvelope_r" c_GEOSEnvelope_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO GEOSGeometryPtr@@ -69,13 +100,9 @@ foreign import ccall "GEOSFree_r" c_GEOSFree_r_CString :: GEOSContextHandle_t -> CString -> IO () --- |Wraps @GEOSGetExteriorRing_r@-foreign import ccall "GEOSGetExteriorRing_r"- c_GEOSGetExteriorRing_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO GEOSGeometryPtr---- |Wraps @GEOSIntersection_r@-foreign import ccall "GEOSIntersection_r"- c_GEOSIntersection_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> GEOSGeometryPtr -> IO GEOSGeometryPtr+-- |Wraps @GEOSGeomTypeId_r@+foreign import ccall "GEOSGeomTypeId_r"+ c_GEOSGeomTypeId_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CInt -- |Wraps @GEOSGeom_destroy_r@ foreign import ccall "GEOSGeom_destroy_r"@@ -85,6 +112,22 @@ foreign import ccall "GEOSGeom_getCoordSeq_r" c_GEOSGeom_getCoordSeq_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO GEOSCoordSequencePtr +-- |Wraps @GEOSGetExteriorRing_r@+foreign import ccall "GEOSGetExteriorRing_r"+ c_GEOSGetExteriorRing_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO GEOSGeometryPtr++-- |Wraps @GEOSGetGeometryN_r@+foreign import ccall "GEOSGetGeometryN_r"+ c_GEOSGetGeometryN_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> CInt -> IO GEOSGeometryPtr++-- |Wraps @GEOSGetNumGeometries_r@+foreign import ccall "GEOSGetNumGeometries_r"+ c_GEOSGetNumGeometries_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CInt++-- |Wraps @GEOSIntersection_r@+foreign import ccall "GEOSIntersection_r"+ c_GEOSIntersection_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> GEOSGeometryPtr -> IO GEOSGeometryPtr+ -- |Wraps @GEOSWKTReader_create_r@ foreign import ccall "GEOSWKTReader_create_r" c_GEOSWKTReader_create_r :: GEOSContextHandle_t -> IO GEOSWKTReaderPtr@@ -109,10 +152,18 @@ foreign import ccall "GEOSWKTWriter_write_r" c_GEOSWKTWriter_write_r :: GEOSContextHandle_t -> GEOSWKTWriterPtr -> GEOSGeometryPtr -> IO CString +-- |Wraps @GEOSisEmpty_r@+foreign import ccall "GEOSisEmpty_r"+ c_GEOSisEmpty_r :: GEOSContextHandle_t -> GEOSGeometryPtr -> IO CChar+ -- |Wraps @GEOSversion@ foreign import ccall "GEOSversion"- c_GEOSversion :: CString+ c_GEOSversion :: IO CString +-- |Wraps @finishGEOS_r@ helper function+foreign import ccall "finishGEOS_r"+ c_finishGEOS_r :: GEOSContextHandle_t -> IO ()+ -- |Wraps @getErrorMessage@ helper function foreign import ccall "helpers.h getErrorMessage" c_getErrorMessage :: IO CString@@ -124,7 +175,3 @@ -- |Wraps @initializeGEOSWithHandlers@ helper function foreign import ccall "helpers.h initializeGEOSWithHandlers" c_initializeGEOSWithHandlers :: IO GEOSContextHandle_t---- |Wraps @uninitializeGEOS@ helper function-foreign import ccall "helpers.h uninitializeGEOS"- c_uninitializeGEOS :: GEOSContextHandle_t -> IO ()
+ src/lib/Data/Geolocation/GEOS/helpers.c view
@@ -0,0 +1,43 @@+#include "helpers.h"+#include <geos_c.h>+#include <stdarg.h>+#include <stdio.h>++//#define TRACE(message) printf(message "\n")+#define TRACE(message) do {} while (0)++__thread char g_noticeMessage[256];+static const size_t s_noticeMessageLen = sizeof(g_noticeMessage) / sizeof(g_noticeMessage[0]);+__thread char g_errorMessage[256];+static const size_t s_errorMessageLen = sizeof(g_errorMessage) / sizeof(g_errorMessage[0]);++static void noticeHandler(const char* format, ...)+{+ va_list args;+ va_start(args, format);+ vsnprintf(g_noticeMessage, s_noticeMessageLen, format, args);+ va_end(args);+}++static void errorHandler(const char* format, ...)+{+ va_list args;+ va_start(args, format);+ vsnprintf(g_errorMessage, s_errorMessageLen, format, args);+ va_end(args);+}++GEOSContextHandle_t initializeGEOSWithHandlers()+{+ return initGEOS_r(noticeHandler, errorHandler);+}++const char* getNoticeMessage()+{+ return g_noticeMessage;+}++const char* getErrorMessage()+{+ return g_errorMessage;+}
+ src/lib/Data/Geolocation/GEOS/helpers.h view
@@ -0,0 +1,7 @@+#pragma once++#include "geos_c.h"++GEOSContextHandle_t initializeGEOSWithHandlers();+const char* getNoticeMessage();+const char* getErrorMessage();
− src/lib/helpers.c
@@ -1,48 +0,0 @@-#include "helpers.h"-#include <geos_c.h>-#include <stdarg.h>-#include <stdio.h>--//#define TRACE(message) printf(message "\n")-#define TRACE(message) do {} while (0)--__thread char g_noticeMessage[256];-static const size_t s_noticeMessageLen = sizeof(g_noticeMessage) / sizeof(g_noticeMessage[0]);-__thread char g_errorMessage[256];-static const size_t s_errorMessageLen = sizeof(g_errorMessage) / sizeof(g_errorMessage[0]);--static void noticeHandler(const char* format, ...)-{- va_list args;- va_start(args, format);- vsnprintf(g_noticeMessage, s_noticeMessageLen, format, args);- va_end(args);-}--static void errorHandler(const char* format, ...)-{- va_list args;- va_start(args, format);- vsnprintf(g_errorMessage, s_errorMessageLen, format, args);- va_end(args);-}--GEOSContextHandle_t initializeGEOSWithHandlers()-{- return initGEOS_r(noticeHandler, errorHandler);-}--void uninitializeGEOS(GEOSContextHandle_t handle)-{- finishGEOS_r(handle);-}--const char* getNoticeMessage()-{- return g_noticeMessage;-}--const char* getErrorMessage()-{- return g_errorMessage;-}
− src/lib/helpers.h
@@ -1,8 +0,0 @@-#pragma once--#include "geos_c.h"--GEOSContextHandle_t initializeGEOSWithHandlers();-void uninitializeGEOS(GEOSContextHandle_t handle);-const char* getNoticeMessage();-const char* getErrorMessage();