packages feed

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 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();