diff --git a/geos.cabal b/geos.cabal
--- a/geos.cabal
+++ b/geos.cabal
@@ -1,6 +1,6 @@
 name:                geos
 
-version:             0.1.1.2
+version:             0.2.1
 
 synopsis:  Bindings for GEOS.
 
@@ -35,7 +35,7 @@
   c-sources:           cbits/noticehandlers.c
   include-dirs:        cbits
   build-depends:       
-      base <= 4.10.1.0
+      base <= 5
     , bytestring 
     , vector
     , transformers
@@ -44,11 +44,11 @@
   exposed-modules:
       Data.Geometry.Geos.Topology
     , Data.Geometry.Geos.Geometry
-    , Data.Geometry.Geos.Types
     , Data.Geometry.Geos.Serialize
     , Data.Geometry.Geos.Buffer
     , Data.Geometry.Geos.Prepared
     , Data.Geometry.Geos.STRTree
+    , Data.Geometry.Geos.Relatable
 
   other-modules:
       Data.Geometry.Geos.Raw.Base
@@ -90,7 +90,7 @@
   main-is: Main.hs
 
   build-depends:
-      base <= 4.10.1.0
+      base <= 5
     , bytestring
     , vector
     , mtl
@@ -113,9 +113,10 @@
     , Data.Geometry.Geos.Raw.Geometry
     , Data.Geometry.Geos.Raw.Serialize
     , Data.Geometry.Geos.Raw.Topology
+    , Data.Geometry.Geos.Raw.STRTree
     , Data.Geometry.Geos.Serialize
-    , Data.Geometry.Geos.Types
     , Data.Geometry.Geos.Topology
+    , Data.Geometry.Geos.STRTree
     , ParsingSpec
     , RawGeometrySpec
     , SpatialOperationsSpec
diff --git a/src/Data/Geometry/Geos/Buffer.hs b/src/Data/Geometry/Geos/Buffer.hs
--- a/src/Data/Geometry/Geos/Buffer.hs
+++ b/src/Data/Geometry/Geos/Buffer.hs
@@ -1,22 +1,38 @@
+{-|
+Module      : Data.Geometry.Geos.Raw.Buffer
+Maintainer  : pfrance@gmail.com
+
+Functions to compute the buffer of a geometry, for both positive and negative buffer distances.
+
+In GIS, the positive (or negative) buffer of a geometry is defined as the Minkowski sum (or difference) of the geometry with a circle with radius equal to the absolute value of the buffer distance. In the CAD/CAM world buffers are known as offset curves. In morphological analysis the operation of positive and negative buffering is referred to as erosion and dilation.
+
+The buffer operation always returns a polygonal result. The negative or zero-distance buffer of lines and points is always an empty Polygon.
+
+Since true buffer curves may contain circular arcs, computed buffer polygons can only be approximations to the true geometry. The user can control the accuracy of the curve approximation by specifying the number of linear segments with which to approximate a curve.
+
+
+-}
 {-# LANGUAGE ScopedTypeVariables #-}
 
+
 module Data.Geometry.Geos.Buffer (
     buffer
   , defaultBufferParams
-  , bufferWithParams
   , BufferParams (..)
   , BufferJoinStyle (..)
   , BufferCapStyle (..)
 ) where
 import qualified Data.Geometry.Geos.Raw.Buffer as R
 import Data.Geometry.Geos.Raw.Base
-import Data.Geometry.Geos.Types
 import Data.Geometry.Geos.Geometry
 import qualified Data.Geometry.Geos.Raw.Geometry as RG
 
 data BufferCapStyle = 
+  -- | the usual round end caps
     RoundCap
+  -- | end caps are truncated flat at the line ends
   | SquareCap
+  -- | end caps are squared off at the buffer distance beyond the line ends
   | FlatCap
 
 data BufferJoinStyle =
@@ -39,10 +55,37 @@
 data BufferParams = BufferParams {
     joinStyle :: BufferJoinStyle
   , capStyle :: BufferCapStyle 
+{-
+Sets the limit on the mitre ratio used for very sharp corners.
+
+The mitre ratio is the ratio of the distance from the corner to the end of the mitred offset corner. When two line segments meet at a sharp angle, a miter join will extend far beyond the original geometry. (and in the extreme case will be infinitely far.) To prevent unreasonable geometry, the mitre limit allows controlling the maximum length of the join corner. Corners with a ratio which exceed the limit will be beveled.
+-}
   , mitreLimit :: Double
-  -- | The default number of facets into which to divide a fillet of 90 degrees.
+{- | 
+Sets the number of line segments used to approximate an angle fillet.
+
+* If quadrantSegments >= 1, joins are round, and quadrantSegments indicates the number of segments to use to approximate a quarter-circle.
+* If quadrantSegments = 0, joins are bevelled (flat)
+* If quadrantSegments < 0, joins are mitred, and the value of qs indicates the mitre ration limit as: mitreLimit = |quadrantSegments|
+   
+For round joins, quadrantSegments determines the maximum error in the approximation to the true buffer curve.
+
+The default value of 8 gives less than 2% max error in the buffer distance.
+
+For a max error of < 1%, use QS = 12. For a max error of < 0.1%, use QS = 18. The error is always less than the buffer distance (in other words, the computed buffer curve is always inside the true curve).
+-}
   , quadrantSegments :: Int
-  -- | True for single-sided, False otherwise
+{- | 
+Sets whether the computed buffer should be single-sided. A single-sided buffer is constructed on only one side of each input line.
+
+The side used is determined by the sign of the buffer distance:
+
+* a positive distance indicates the left-hand side
+* a negative distance indicates the right-hand side
+The single-sided buffer of point geometries is the same as the regular buffer.
+
+The End Cap Style for single-sided buffers is always ignored, and forced to the equivalent of 'FlatCap'.
+-}
   , singleSided :: Bool
 }
 
@@ -55,16 +98,9 @@
   , singleSided = False
 }
 
--- | Returns a Geometry that represents all points whose distance from this geometry is less than or equal to the given width. The quadsegs argument sets the number of segments used to approximate a quarter circle.
-
-buffer :: Geometry a -> Double -> Int -> Some Geometry 
-buffer g width quadsegs = runGeos $  do
-    rg :: RG.Geom <- convertGeometryToRaw g
-    rg' <- R.buffer rg width quadsegs
-    convertGeometryFromRaw rg'
-
-bufferWithParams :: Geometry a -> Double -> BufferParams -> Some Geometry
-bufferWithParams g width bp = runGeos $ do
+-- | Returns a Geometry that represents all points whose distance from this geometry is less than or equal to the given width.
+buffer :: Geometry a -> Double -> BufferParams -> Some Geometry
+buffer g width bp = runGeos $ do
   rg :: RG.Geom <- convertGeometryToRaw g
   rbp <- R.createBufferParams 
   R.setEndCapStyle rbp (convertCapStyle $ capStyle bp) 
@@ -72,5 +108,5 @@
   R.setMitreLimit rbp (mitreLimit bp)
   R.setQuadrantSegments rbp (quadrantSegments bp)
   R.setSingleSided rbp (singleSided bp)
-  rg' <- R.bufferWithParams rg rbp width  
+  rg' <- R.buffer rg rbp width  
   convertGeometryFromRaw rg'
diff --git a/src/Data/Geometry/Geos/Geometry.hs b/src/Data/Geometry/Geos/Geometry.hs
--- a/src/Data/Geometry/Geos/Geometry.hs
+++ b/src/Data/Geometry/Geos/Geometry.hs
@@ -1,10 +1,23 @@
 {-# LANGUAGE LambdaCase, ScopedTypeVariables #-}
 {-# LANGUAGE ExistentialQuantification #-}
 {-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# LANGUAGE StandaloneDeriving #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
 module Data.Geometry.Geos.Geometry (
-    convertGeometryFromRaw
+    Geometry(..)
+  , Point(..)
+  , LinearRing(..)
+  , LineString(..)
+  , Polygon(..)
+  , MultiPoint(..)
+  , MultiLineString(..)
+  , MultiPolygon(..)
+  , Some(..)
+  , SRID
+  , binaryPredicate
+  , convertGeometryFromRaw
   , convertGeometryToRaw
   , convertMultiPolygonFromRaw
   , ensurePoint
@@ -18,31 +31,105 @@
   , interpolateNormalized
   , project
   , projectNormalized
-  , covers
-  , coveredBy
   , equalsExact
   , equals
-  , overlaps
-  , contains
-  , within
-  , crosses
-  , touches
-  , disjoint
   , area
   , geometryLength
   , distance
   , hausdorffDistance
   , nearestPoints
+  , withSomeGeometry
 
 ) where
 
-import Data.Geometry.Geos.Types
+import Data.Data
+import Data.Semigroup as Sem
 import qualified Data.Vector as V
 import qualified Data.Geometry.Geos.Raw.Geometry as R
 import qualified Data.Geometry.Geos.Raw.CoordSeq as RC
 import Data.Geometry.Geos.Raw.Base
 import Control.Monad
+import Control.Applicative ((<*>))
 
+type SRID = Maybe Int
+
+data Some :: (* -> *) -> * where
+  Some :: f a -> Some f
+
+withSomeGeometry :: Some Geometry -> (forall a . Geometry a -> b) -> b
+withSomeGeometry (Some p) f = f p
+
+
+instance Show (Some Geometry) where
+  show (Some a) = "Some (" <> show a <> ")"
+
+data Geometry a where
+  PointGeometry :: Point -> SRID -> Geometry Point
+  LineStringGeometry :: LineString -> SRID -> Geometry LineString
+  LinearRingGeometry :: LinearRing -> SRID -> Geometry LinearRing
+  PolygonGeometry :: Polygon -> SRID -> Geometry Polygon
+  MultiPointGeometry :: MultiPoint -> SRID -> Geometry MultiPoint
+  MultiLineStringGeometry :: MultiLineString -> SRID -> Geometry MultiLineString
+  MultiPolygonGeometry :: MultiPolygon -> SRID -> Geometry MultiPolygon
+  {-CollectionGeometry :: GeometryCollection -> Geometry GeometryCollection-}
+
+deriving instance Eq (Geometry a)
+deriving instance Show (Geometry a)
+
+data Coordinate =
+    Coordinate2 {-# UNPACK #-} !Double {-# UNPACK #-} !Double
+  | Coordinate3 {-# UNPACK #-} !Double {-# UNPACK #-} !Double {-# UNPACK #-} !Double  deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+
+dimensionsCoordinate :: Coordinate -> Int
+dimensionsCoordinate = length . gmapQ (const ())
+
+type CoordinateSequence = V.Vector Coordinate
+
+dimensionsCoordinateSequence :: CoordinateSequence -> Int
+dimensionsCoordinateSequence = dimensionsCoordinate . V.head
+
+newtype Point = Point Coordinate
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+-- A LinearRing is a LineString that is closed
+newtype LinearRing = LinearRing CoordinateSequence
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+instance Sem.Semigroup LinearRing where
+  (<>) (LinearRing a) (LinearRing b) =  LinearRing (a <> b)
+
+instance Monoid LinearRing where
+  mempty  = LinearRing V.empty
+
+newtype LineString = LineString CoordinateSequence
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+instance Sem.Semigroup LineString where
+  (<>) (LineString a) (LineString b) =  LineString (a <> b)
+
+instance Monoid LineString where
+  mempty  = LineString V.empty
+
+-- | In a polygon, the fist LinearRing is the shell, and any following are holes.
+newtype Polygon = Polygon (V.Vector LinearRing)
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+newtype MultiPoint = MultiPoint (V.Vector Point)
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+instance Sem.Semigroup MultiPoint where
+  (<>) (MultiPoint a) (MultiPoint b) =  MultiPoint (a <> b)
+
+instance Monoid MultiPoint where
+  mempty  = MultiPoint V.empty
+
+newtype MultiLineString = MultiLineString (V.Vector LineString)
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
+newtype MultiPolygon = MultiPolygon (V.Vector Polygon)
+ deriving (Read, Ord, Show, Eq, Data, Typeable)
+
 -- | Returns the distance from the origin of LineString to the point projected on the geometry (that is to a point of the line the closest to the given point).
 project :: Geometry LineString -> Geometry Point -> Double
 project g1 g2 = runGeos $ do
@@ -74,30 +161,18 @@
   p <- convertPointFromRaw =<<  (R.interpolateNormalized g' $ realToFrac d)
   return $ PointGeometry p s
 
-binaryPredicate_ :: (R.GeomConst -> R.GeomConst -> Geos Bool)
+binaryPredicate :: (R.GeomConst -> R.GeomConst -> Geos Bool)
                   -> Geometry a
                   -> Geometry b
                   -> Bool
-binaryPredicate_ f g1 g2 = runGeos . join $ (f <$> convertGeometryToRaw g1 <*> convertGeometryToRaw g2)
-
-instance Relatable (Geometry a) where
-  disjoint = binaryPredicate_ R.disjoint
-  touches = binaryPredicate_ R.touches
-  intersects = binaryPredicate_ R.intersects
-  contains = binaryPredicate_ R.contains
-  within = binaryPredicate_ R.within
-  crosses = binaryPredicate_ R.crosses
-  overlaps = binaryPredicate_ R.overlaps
-  covers = binaryPredicate_ R.covers
-  coveredBy = binaryPredicate_ R.coveredBy
+binaryPredicate f g1 g2 = runGeos . join $ (f <$> convertGeometryToRaw g1 <*> convertGeometryToRaw g2)
 
--- | Returns True if the DE-9IM intersection matrix for the two geometries is T*F**FFF*.
 equals :: Geometry a -> Geometry a -> Bool
-equals = binaryPredicate_ R.equals
+equals = binaryPredicate R.equals
 
 -- | Returns True if the two geometries are exactly equal, up to a specified tolerance. The tolerance value should be a floating point number representing the error tolerance in the comparison, e.g., @equalsExact g1 g2 0.001 @  will compare equality to within one thousandth of a unit.
 equalsExact :: Geometry a -> Geometry a -> Double -> Bool
-equalsExact g1 g2 d = binaryPredicate_ (\g1' g2' -> R.equalsExact g1' g2' d) g1 g2
+equalsExact g1 g2 d = binaryPredicate (\g1' g2' -> R.equalsExact g1' g2' d) g1 g2
 
 convertGeometryToRaw :: (R.Geometry a, R.CoordSeqInput a ~ cb, RC.CoordinateSequence cb) => Geometry b -> Geos a
 convertGeometryToRaw = \case
@@ -305,7 +380,7 @@
   l <- R.geometryLength r
   return l
 
--- | NOTE: Data.Geometry.Geos distance calculations are linear – in other words, Data.Geometry.Geos does not perform a spherical calculation even if the SRID specifies a geographic coordinate system.
+-- | NOTE: @distance@ calculations are linear – in other words, @distance@ does not perform a spherical calculation even if the SRID specifies a geographic coordinate system.
 distance :: Geometry a -> Geometry a -> Double
 distance p g = runGeos $ do
   p' :: R.Geom <- convertGeometryToRaw p
@@ -327,3 +402,5 @@
   p1 <- getPosition cs 0
   p2 <- getPosition cs 1
   return (p1, p2)
+
+
diff --git a/src/Data/Geometry/Geos/Prepared.hs b/src/Data/Geometry/Geos/Prepared.hs
--- a/src/Data/Geometry/Geos/Prepared.hs
+++ b/src/Data/Geometry/Geos/Prepared.hs
@@ -26,12 +26,12 @@
 import qualified Data.Geometry.Geos.Raw.Prepared as RP
 import qualified Data.Geometry.Geos.Raw.Geometry as RG
 import Data.Geometry.Geos.Raw.Base
-import qualified Data.Geometry.Geos.Geometry as G
-import Data.Geometry.Geos.Types
+import Data.Geometry.Geos.Geometry (Geometry(..), convertGeometryToRaw)
+import Data.Geometry.Geos.Relatable
 
 prepare :: Geometry a -> RP.PreparedGeometry
 prepare g = runGeos $ do
-  r :: RG.Geom <- G.convertGeometryToRaw g
+  r :: RG.Geom <- convertGeometryToRaw g
   RP.prepare r
 
 
@@ -39,7 +39,7 @@
               -> RP.PreparedGeometry
               -> Geometry b
               -> Bool 
-queryPrepared f pg g = runGeos $ G.convertGeometryToRaw g >>= (f pg)
+queryPrepared f pg g = runGeos $ convertGeometryToRaw g >>= (f pg)
 
 instance Relatable (RP.PreparedGeometry) where
   contains = queryPrepared RP.contains
@@ -52,14 +52,16 @@
   touches = queryPrepared RP.touches 
   within = queryPrepared RP.within 
 
--- | The containsProperly predicate has the following equivalent definitions:
+{-|
+The containsProperly predicate has the following equivalent definitions:
 
--- | Every point of the other geometry is a point of this geometry's interior. In other words, if the test geometry has any interaction with the boundary of the target geometry the result of containsProperly is false. This is different semantics to the @contains@ predicate, in which test geometries can intersect the target's boundary and still be contained.
+Every point of the other geometry is a point of this geometry's interior. In other words, if the test geometry has any interaction with the boundary of the target geometry the result of containsProperly is false. This is different semantics to the @contains@ predicate, in which test geometries can intersect the target's boundary and still be contained.
 
--- | The advantage of using this predicate is that it can be computed efficiently, since it avoids the need to compute the full topological relationship of the input boundaries in cases where they intersect.
+The advantage of using this predicate is that it can be computed efficiently, since it avoids the need to compute the full topological relationship of the input boundaries in cases where they intersect.
 
--- | An example use case is computing the intersections of a set of geometries with a large polygonal geometry. Since intersection is a fairly slow operation, it can be more efficient to use containsProperly to filter out test geometries which lie wholly inside the area. In these cases the intersection is known a priori to be exactly the original test geometry.
+An example use case is computing the intersections of a set of geometries with a large polygonal geometry. Since intersection is a fairly slow operation, it can be more efficient to use containsProperly to filter out test geometries which lie wholly inside the area. In these cases the intersection is known a priori to be exactly the original test geometry.
 
+-}
 
 containsProperly :: RP.PreparedGeometry
                   -> Geometry a
diff --git a/src/Data/Geometry/Geos/Raw/Base.hs b/src/Data/Geometry/Geos/Raw/Base.hs
--- a/src/Data/Geometry/Geos/Raw/Base.hs
+++ b/src/Data/Geometry/Geos/Raw/Base.hs
@@ -17,7 +17,6 @@
 
 newtype GEOSHandle = GEOSHandle (MV.MVar (ForeignPtr I.GEOSContextHandle_HS))
 
--- idea: stores list of (Handle -> IO) actions
 newtype Geos a = Geos { unGeos :: ReaderT GEOSHandle IO a }
   deriving (MonadReader GEOSHandle, Monad, Functor, Applicative)
 -- don't derive MonadIO to restrict user from performing arbitrary IO
@@ -30,8 +29,7 @@
   ptrC <- I.geos_init
   fptr <- newForeignPtr I.geos_finish ptrC
   mv <- MV.newMVar fptr
-  v <- runReaderT (unGeos g) $ GEOSHandle mv
-  return v
+  runReaderT (unGeos g) $ GEOSHandle mv
   
 
 throwIfZero :: (Eq a, Num a) => (a -> String) -> IO a -> IO a
@@ -39,5 +37,3 @@
 
 mkErrorMessage :: Show a => String -> (a -> String) 
 mkErrorMessage s = \n -> s  <> " has thrown an error:  " <> show n
-
-
diff --git a/src/Data/Geometry/Geos/Raw/Buffer.hs b/src/Data/Geometry/Geos/Raw/Buffer.hs
--- a/src/Data/Geometry/Geos/Raw/Buffer.hs
+++ b/src/Data/Geometry/Geos/Raw/Buffer.hs
@@ -11,7 +11,6 @@
   , setQuadrantSegments
   , setSingleSided
   , bufferWithStyle
-  , bufferWithParams
   , offsetCurve
   , capRound
   , capFlat
@@ -32,15 +31,6 @@
 withBufferParams (BufferParams g) f = withForeignPtr g f
 
 
--- | Create a buffer around a geometry, where quadsegs is the number of line segments to use to approximate a quarter of a circle.
-buffer :: RG.Geometry a => a -> Double -> Int -> Geos a
-buffer geo width quadsegs = do 
-  withGeos $ \h -> 
-        RG.withGeometry geo $ \gp -> do
-          g' <- geos_Buffer h gp (realToFrac width) $ fromIntegral quadsegs
-          RG.constructGeometry h g'
-
-
 createBufferParams :: Geos BufferParams 
 createBufferParams = withGeos $ \h -> do
   bp <- geos_BufferParamsCreate h
@@ -79,8 +69,8 @@
     geos_BufferParamsSetSingleSided h bpp $ fromBool b
   return ()
 
-bufferWithParams :: RG.Geometry a => a -> BufferParams -> Double -> Geos a
-bufferWithParams g b width = 
+buffer :: RG.Geometry a => a -> BufferParams -> Double -> Geos a
+buffer g b width = 
   withGeos $ \h -> do
     RG.withGeometry g $ \gp ->
       withBufferParams b $ \bp ->  do
diff --git a/src/Data/Geometry/Geos/Raw/Geometry.hs b/src/Data/Geometry/Geos/Raw/Geometry.hs
--- a/src/Data/Geometry/Geos/Raw/Geometry.hs
+++ b/src/Data/Geometry/Geos/Raw/Geometry.hs
@@ -1,8 +1,6 @@
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 {-# LANGUAGE TypeFamilies #-}
 {-# LANGUAGE FlexibleInstances #-}
-
-
 {-|
 Module      : Data.Geometry.Geos.Raw.Geometery
 
diff --git a/src/Data/Geometry/Geos/Raw/STRTree.hs b/src/Data/Geometry/Geos/Raw/STRTree.hs
--- a/src/Data/Geometry/Geos/Raw/STRTree.hs
+++ b/src/Data/Geometry/Geos/Raw/STRTree.hs
@@ -16,9 +16,6 @@
 import Data.IORef
 import qualified Data.Vector as V
 
---A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. For two-dimensional spatial data.
-
---The STR packed R-tree is simple to implement and maximizes space utilization; that is, as many leaves as possible are filled to capacity. Overlap between nodes is far less than in a basic R-tree. However, once the tree has been built (explicitly or on the first call to query), items may not be added or removed.
 
 class STRTreeLike t where
     withSTRTree :: t a -> (Ptr I.GEOSSTRTree -> IO b ) -> IO b
diff --git a/src/Data/Geometry/Geos/Relatable.hs b/src/Data/Geometry/Geos/Relatable.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Geometry/Geos/Relatable.hs
@@ -0,0 +1,29 @@
+module Data.Geometry.Geos.Relatable where
+
+import Data.Geometry.Geos.Geometry 
+import qualified Data.Geometry.Geos.Raw.Geometry as R
+
+class Relatable a where
+  contains ::  a -> Geometry b -> Bool
+  coveredBy :: a -> Geometry b -> Bool
+  covers :: a -> Geometry b -> Bool
+  crosses :: a -> Geometry b -> Bool
+  disjoint ::  a -> Geometry b -> Bool
+  intersects :: a -> Geometry b -> Bool
+  overlaps :: a -> Geometry b -> Bool
+  touches ::  a -> Geometry b -> Bool
+  within ::  a -> Geometry b -> Bool
+
+
+instance Relatable (Geometry a) where
+  disjoint = binaryPredicate R.disjoint
+  touches = binaryPredicate R.touches
+  intersects = binaryPredicate R.intersects
+  contains = binaryPredicate R.contains
+  within = binaryPredicate R.within
+  crosses = binaryPredicate R.crosses
+  overlaps = binaryPredicate R.overlaps
+  covers = binaryPredicate R.covers
+  coveredBy = binaryPredicate R.coveredBy
+
+
diff --git a/src/Data/Geometry/Geos/STRTree.hs b/src/Data/Geometry/Geos/STRTree.hs
--- a/src/Data/Geometry/Geos/STRTree.hs
+++ b/src/Data/Geometry/Geos/STRTree.hs
@@ -1,19 +1,42 @@
 {-# LANGUAGE ScopedTypeVariables #-}
+{-|
+Module      : Data.Geometry.Geos.STRTree
+Maintainer  : pfrance@gmail.com
 
+A query-only R-tree created using the Sort-Tile-Recursive (STR) algorithm. For two-dimensional spatial data.
 
-module Data.Geometry.Geos.STRTree where
+The STR packed R-tree is simple to implement and maximizes space utilization; that is, as many leaves as possible are filled to capacity. Overlap between nodes is far less than in a basic R-tree. However, once the tree has been built (explicitly or on the first call to query), items may not be added or removed.
 
-import Prelude hiding (foldr)
+Described in: P. Rigaux, Michel Scholl and Agnes Voisard. Spatial Databases With Application To GIS. Morgan Kaufmann, San Francisco, 2002.
+
+-}
+
+
+module Data.Geometry.Geos.STRTree ( 
+  foldr, 
+  toList,
+  toVector,
+  fromList,
+  empty,
+  build,
+  insert,
+  fromFoldable,
+  fromFoldable_,
+  lookup,
+  RT.STRTree,
+  RT.STRTreeBuilder
+) where
+
+import Prelude hiding (foldr, lookup)
 import qualified Data.Geometry.Geos.Raw.STRTree as RT
 import qualified Data.Geometry.Geos.Raw.Geometry as RG
-import Data.Geometry.Geos.Types
 import Data.Geometry.Geos.Geometry
 import Data.Geometry.Geos.Raw.Base
 import Foreign
 import qualified Data.Vector as V
 
 -- can't make instance of Foldable because of Storable constraint
-foldr :: (RT.STRTreeLike t, Storable a) => (a -> b -> b) -> b -> t a -> b
+foldr :: (Storable a) => (a -> b -> b) -> b -> RT.STRTree a -> b
 foldr f a = runGeos . RT.foldr f a
 
 
@@ -24,8 +47,6 @@
 toVector :: Storable a => RT.STRTree a -> V.Vector a
 toVector = foldr V.cons V.empty
 
--- would like to expose 'empty' as is common for haskell collections, but when initializing an STRTree we have to know the node size before hand
-
 fromList :: Storable b => [(Geometry a, b)] -> RT.STRTree b
 fromList = fromFoldable
 
@@ -57,6 +78,10 @@
           RT.insert tree' rg b
 
 
+{-| 
+Queries the index for all items whose extents intersect the given search Envelope.
+Note that some kinds of indexes may also return objects which do not in fact intersect the query envelope.
+-}
 lookup :: Storable b => Geometry a -> RT.STRTree b -> V.Vector b
 lookup g tree = runGeos $ do
   rg :: RG.GeomConst <- convertGeometryToRaw g
diff --git a/src/Data/Geometry/Geos/Serialize.hs b/src/Data/Geometry/Geos/Serialize.hs
--- a/src/Data/Geometry/Geos/Serialize.hs
+++ b/src/Data/Geometry/Geos/Serialize.hs
@@ -1,3 +1,13 @@
+{-|
+Module      : Data.Geometry.Geos.Serialize
+Maintainer  : pfrance@gmail.com
+
+Functions to read and write geometries in WKB and WKT formats.
+
+The WKB format is specified in the OGC Simple Features for SQL specification. This implementation supports the extended WKB standard for representing 3-dimensional coordinates. The presence of 3D coordinates is signified by setting the high bit of the wkbType word.
+Empty Points cannot be represented in WKB; an IllegalArgumentException will be thrown if one is written. The WKB specification does not support representing 'LinearRing', they will be written as 'LineString'
+-}
+
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE ScopedTypeVariables #-}
 
@@ -13,7 +23,6 @@
 import Data.Geometry.Geos.Geometry
 import qualified Data.Geometry.Geos.Raw.Serialize as S
 import qualified Data.Geometry.Geos.Raw.Geometry as R
-import Data.Geometry.Geos.Types
 import qualified Data.ByteString.Char8 as BC
 import Data.Maybe (catMaybes)
 
@@ -37,6 +46,7 @@
   r :: R.Geom <- convertGeometryToRaw g
   S.writeHex w r
 
+-- Read a string of WKT, optionally adding an SRID to the resulting geometry.
 readWkt :: Maybe Int -> BC.ByteString -> Maybe (Some Geometry)
 readWkt srid bs = runGeos $ do
   r <- S.createWktReader
diff --git a/src/Data/Geometry/Geos/Topology.hs b/src/Data/Geometry/Geos/Topology.hs
--- a/src/Data/Geometry/Geos/Topology.hs
+++ b/src/Data/Geometry/Geos/Topology.hs
@@ -14,7 +14,6 @@
   , node
   , delaunayTriangulation
 ) where
-import Data.Geometry.Geos.Types
 import Data.Geometry.Geos.Raw.Base
 import Data.Geometry.Geos.Geometry
 import qualified Data.Geometry.Geos.Raw.Topology as R
diff --git a/src/Data/Geometry/Geos/Types.hs b/src/Data/Geometry/Geos/Types.hs
deleted file mode 100644
--- a/src/Data/Geometry/Geos/Types.hs
+++ /dev/null
@@ -1,96 +0,0 @@
-{-# LANGUAGE RankNTypes, KindSignatures, GADTs, DeriveDataTypeable, StandaloneDeriving, FlexibleInstances #-}
-
-module Data.Geometry.Geos.Types where
-import qualified Data.Vector as V
-import Data.Monoid
-import Data.Data
-
-class Relatable a where
-  contains ::  a -> Geometry b -> Bool
-  coveredBy :: a -> Geometry b -> Bool
-  covers :: a -> Geometry b -> Bool
-  -- | Returns @True@ if the DE-9IM intersection matrix for the two Geometries is T*T****** (for a point and a curve,a point and an area or a line and an area) 0******** (for two curves).
-  crosses :: a -> Geometry b -> Bool
-  -- | Returns @True@ if the DE-9IM intersection matrix for the two geometries is FF*FF****.
-  disjoint ::  a -> Geometry b -> Bool
-  -- | Returns @True@ if @disjoint@ is False.
-  intersects :: a -> Geometry b -> Bool
-  -- | Returns true if the DE-9IM intersection matrix for the two geometries is T*T***T** (for two points or two surfaces) 1*T***T** (for two curves).
-  overlaps :: a -> Geometry b -> Bool
-  -- | Returns True if the DE-9IM intersection matrix for the two geometries is FT*******, F**T***** or F***T****.
-  touches ::  a -> Geometry b -> Bool
-  -- | Returns True if the DE-9IM intersection matrix for the two geometries is T*F**F***.
-  within ::  a -> Geometry b -> Bool
-
-
-type SRID = Maybe Int
-
-data Some :: (* -> *) -> * where
-  Some :: f a -> Some f
-
-withSomeGeometry :: Some Geometry -> (forall a . Geometry a -> b) -> b
-withSomeGeometry (Some p) f = f p
-
-instance Show (Some Geometry) where
-  show (Some a) = "Some (" <> show a <> ")"
-
-data Geometry a where
-  PointGeometry :: Point -> SRID -> Geometry Point
-  LineStringGeometry :: LineString -> SRID -> Geometry LineString
-  LinearRingGeometry :: LinearRing -> SRID -> Geometry LinearRing
-  PolygonGeometry :: Polygon -> SRID -> Geometry Polygon
-  MultiPointGeometry :: MultiPoint -> SRID -> Geometry MultiPoint
-  MultiLineStringGeometry :: MultiLineString -> SRID -> Geometry MultiLineString
-  MultiPolygonGeometry :: MultiPolygon -> SRID -> Geometry MultiPolygon
-  {-CollectionGeometry :: GeometryCollection -> Geometry GeometryCollection-}
-
-deriving instance Eq (Geometry a)
-deriving instance Show (Geometry a)
-
-data Coordinate =
-    Coordinate2 {-# UNPACK #-} !Double {-# UNPACK #-} !Double
-  | Coordinate3 {-# UNPACK #-} !Double {-# UNPACK #-} !Double {-# UNPACK #-} !Double  deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-
-dimensionsCoordinate :: Coordinate -> Int
-dimensionsCoordinate = length . gmapQ (const ())
-
-type CoordinateSequence = V.Vector Coordinate
-
-dimensionsCoordinateSequence :: CoordinateSequence -> Int
-dimensionsCoordinateSequence = dimensionsCoordinate . V.head
-
-newtype Point = Point Coordinate
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
--- A LinearRing is a LineString that is closed
-newtype LinearRing = LinearRing CoordinateSequence
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-instance Monoid LinearRing where
-  mempty  = LinearRing V.empty
-  mappend (LinearRing a) (LinearRing b) =  LinearRing (a <> b)
-
-newtype LineString = LineString CoordinateSequence
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-instance Monoid LineString where
-  mempty  = LineString V.empty
-  mappend (LineString a) (LineString b) =  LineString (a <> b)
-
--- | In a polygon, the fist LinearRing is the shell, and any following are holes.
-newtype Polygon = Polygon (V.Vector LinearRing)
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-newtype MultiPoint = MultiPoint (V.Vector Point)
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-instance Monoid MultiPoint where
-  mempty  = MultiPoint V.empty
-  mappend (MultiPoint a) (MultiPoint b) =  MultiPoint (a <> b)
-
-newtype MultiLineString = MultiLineString (V.Vector LineString)
- deriving (Read, Ord, Show, Eq, Data, Typeable)
-
-newtype MultiPolygon = MultiPolygon (V.Vector Polygon)
- deriving (Read, Ord, Show, Eq, Data, Typeable)
