wkt-geom 0.0.4 → 0.0.5
raw patch · 39 files changed
+1436/−857 lines, 39 filesdep +base16-bytestringdep +hedgehogdep +hlintdep ~base
Dependencies added: base16-bytestring, hedgehog, hlint, hw-hspec-hedgehog
Dependency ranges changed: base
Files
- CHANGELOG.md +9/−0
- README.md +8/−4
- hlint/Main.hs +12/−0
- src/Data/Ewkb.hs +18/−1
- src/Data/Hex.hs +25/−0
- src/Data/Internal/Ewkb/Geometry.hs +90/−21
- src/Data/Internal/Wkb/Endian.hs +38/−14
- src/Data/Internal/Wkb/Geometry.hs +69/−4
- src/Data/Internal/Wkb/GeometryCollection.hs +31/−8
- src/Data/Internal/Wkb/Geospatial.hs +37/−11
- src/Data/Internal/Wkb/Line.hs +42/−15
- src/Data/Internal/Wkb/Point.hs +78/−37
- src/Data/Internal/Wkb/Polygon.hs +48/−14
- src/Data/Internal/Wkt/Line.hs +26/−14
- src/Data/Internal/Wkt/Point.hs +62/−21
- src/Data/Internal/Wkt/Polygon.hs +28/−16
- src/Data/Wkb.hs +17/−1
- test/Data/Internal/Ewkb/GeometrySpec.hs +75/−90
- test/Data/Internal/Wkb/EndianSpec.hs +7/−8
- test/Data/Internal/Wkb/GeometryCollectionSpec.hs +14/−0
- test/Data/Internal/Wkb/GeometrySpec.hs +43/−49
- test/Data/Internal/Wkb/HexParsingSpec.hs +31/−0
- test/Data/Internal/Wkb/LineSpec.hs +28/−0
- test/Data/Internal/Wkb/PointSpec.hs +56/−0
- test/Data/Internal/Wkb/PolygonSpec.hs +55/−0
- test/Data/Internal/Wkt/GeometryCollectionSpec.hs +34/−0
- test/Data/Internal/Wkt/LineSpec.hs +86/−0
- test/Data/Internal/Wkt/PointSpec.hs +80/−0
- test/Data/Internal/Wkt/PolygonSpec.hs +92/−0
- test/Data/SpecHelper.hs +139/−4
- test/Data/WkbGeometryCollectionSpec.hs +0/−54
- test/Data/WkbLineSpec.hs +0/−63
- test/Data/WkbPointSpec.hs +0/−55
- test/Data/WkbPolygonSpec.hs +0/−100
- test/Data/WktGeometryCollectionSpec.hs +0/−34
- test/Data/WktLineSpec.hs +0/−55
- test/Data/WktPointSpec.hs +0/−60
- test/Data/WktPolygonSpec.hs +0/−63
- wkt-geom.cabal +58/−41
+ CHANGELOG.md view
@@ -0,0 +1,9 @@+# Changelog+All notable changes to this project will be documented in this file.++## [0.0.5] - 2019-01-07+### Added+- Add serializers back into ByteString [https://github.com/indicatrix/wkt-geom/issues/7].+- New API for WKB which takes hex (base 16) encoded ByteString [https://github.com/indicatrix/wkt-geom/issues/6].+- Improvements in testing (added Hedgehog).+- Support for WKT encodings for 3D (XYZ) and 4D (XYZM) points, lines and polygons.
README.md view
@@ -1,6 +1,10 @@-# wkt-geom+# wkt-geom [](https://travis-ci.org/indicatrix/wkt-geom) [Hackage](https://hackage.haskell.org/package/wkt-geom) -+A parser for Well Known Text (WKT), Well Known Binary (WKB) and the PostgreSQL extension Extended Well Know Binary (eWKB). -http://www.opengeospatial.org/standards/sfa (Section 7)-http://edndoc.esri.com/arcsde/9.0/general_topics/wkt_representation.htm+See:+- http://www.opengeospatial.org/standards/sfa (Section 7)+- http://edndoc.esri.com/arcsde/9.0/general_topics/wkt_representation.htm++### Other Projects+- [Terroformer Wkt Parser](http://terraformer.io/wkt-parser/)
+ hlint/Main.hs view
@@ -0,0 +1,12 @@+module Main where++import Control.Monad (unless)+import Language.Haskell.HLint (hlint)+import System.Environment (getArgs)+import System.Exit (exitFailure)++main :: IO ()+main = do+ args <- getArgs+ hlints <- hlint $ ["src/", "test/", "hlint/", "--cpp-define=HLINT", "--cpp-ansi"] ++ args+ unless (null hlints) exitFailure
src/Data/Ewkb.hs view
@@ -5,19 +5,36 @@ ------------------------------------------------------------------- module Data.Ewkb ( parseByteString+ , parseHexByteString+ , toByteString ) where import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder import qualified Data.ByteString.Lazy as LazyByteString import qualified Data.Geospatial as Geospatial+import qualified Data.Hex as Hex import qualified Data.Internal.Ewkb.Geometry as EwkbGeometry+import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geospatial as WkbGeospatial +-- |+-- Representation of EWKB as Binary parseByteString :: LazyByteString.ByteString -> Either String Geospatial.GeospatialGeometry parseByteString byteString = case BinaryGet.runGetOrFail- (WkbGeospatial.geospatialGeometry EwkbGeometry.wkbGeometryType)+ (WkbGeospatial.getGeospatialGeometry EwkbGeometry.getWkbGeom) byteString of Left (_, _, err) -> Left $ "Could not parse ewkb: " ++ err Right (_, _, geoSpatialGeometry) -> Right geoSpatialGeometry++-- |+-- Representation of EWKB as a String in Base16/Hex form i.e. "0101000000000000000000f03f0000000000000040" is POINT 1.0 2.0+parseHexByteString :: Hex.Hex -> Either String Geospatial.GeospatialGeometry+parseHexByteString = Hex.safeConvert parseByteString++toByteString :: Endian.EndianType -> Geospatial.GeospatialGeometry -> LazyByteString.ByteString+toByteString endianType =+ ByteStringBuilder.toLazyByteString . WkbGeospatial.builderGeospatialGeometry+ EwkbGeometry.builderWkbGeom endianType
+ src/Data/Hex.hs view
@@ -0,0 +1,25 @@+module Data.Hex+ ( safeConvert+ , Hex(..)+ ) where++import qualified Data.ByteString as ByteString+import qualified Data.ByteString.Base16 as ByteStringBase16+import qualified Data.ByteString.Char8 as ByteStringChar8+import qualified Data.ByteString.Lazy as LazyByteString+import qualified Data.Geospatial as Geospatial+import Data.Monoid ((<>))++newtype Hex = Hex ByteString.ByteString++safeConvert :: (LazyByteString.ByteString -> Either String Geospatial.GeospatialGeometry) -> Hex -> Either String Geospatial.GeospatialGeometry+safeConvert f (Hex byteString) =+ let+ (decoded, rest) = ByteStringBase16.decode byteString+ in+ if ByteString.null rest then+ f $ LazyByteString.fromStrict decoded+ else+ Left ("Invalid hex representation: " <> ByteStringChar8.unpack byteString)++
src/Data/Internal/Ewkb/Geometry.hs view
@@ -1,35 +1,77 @@ module Data.Internal.Ewkb.Geometry ( EwkbGeometryType (..) , SridType (..)- , ewkbGeometryType- , wkbGeometryType+ , getEwkbGeom+ , getWkbGeom+ , builderWkbGeom+ , builderEwkbGeom ) where import qualified Control.Monad as Monad import qualified Data.Binary.Get as BinaryGet-import Data.Bits ((.&.))+import Data.Bits ((.&.), (.|.))+import qualified Data.ByteString.Builder as ByteStringBuilder+import Data.Monoid ((<>)) import qualified Data.Word as Word import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geometry as Geometry +-- Types+ data SridType = Srid Word.Word32 | NoSrid deriving (Show, Eq) data EwkbGeometryType = EwkbGeom Geometry.WkbGeometryType SridType deriving (Show, Eq) -ewkbGeometryType :: Endian.EndianType -> BinaryGet.Get EwkbGeometryType-ewkbGeometryType endianType = do- rawGeometryType <- Endian.fourBytes endianType++-- Binary parsers++getEwkbGeom :: Endian.EndianType -> BinaryGet.Get EwkbGeometryType+getEwkbGeom endianType = do+ rawGeometryType <- Endian.getFourBytes endianType ewkbSrid <- getEwkbSrid endianType rawGeometryType geomType <- rawtoWkbGeometryType rawGeometryType pure $ EwkbGeom geomType ewkbSrid -wkbGeometryType :: Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType-wkbGeometryType endianType = do- rawGeometryType <- Endian.fourBytes endianType+getWkbGeom :: Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType+getWkbGeom endianType = do+ rawGeometryType <- Endian.getFourBytes endianType _ <- getEwkbSrid endianType rawGeometryType rawtoWkbGeometryType rawGeometryType +getEwkbSrid :: Endian.EndianType -> Word.Word32 -> BinaryGet.Get SridType+getEwkbSrid endianType int =+ if int .&. sridMask /= 0 then do+ srid <- Endian.getFourBytes endianType+ if srid == supportedSrid then+ pure $ Srid srid+ else+ Monad.fail $ "Invalid SRID only " <> show supportedSrid <> " supported: " ++ show srid+ else+ pure NoSrid+++-- Binary builders++builderEwkbGeom :: Endian.EndianType -> EwkbGeometryType -> ByteStringBuilder.Builder+builderEwkbGeom endianType (EwkbGeom wkbGeometryType NoSrid) =+ builderWkbGeom endianType wkbGeometryType+builderEwkbGeom endianType (EwkbGeom wkbGeometryType (Srid srid)) = do+ let int = wkbGeometryTypeToInt wkbGeometryType .|. sridMask+ Endian.builderFourBytes endianType int+ <> Endian.builderFourBytes endianType srid++builderWkbGeom :: Endian.EndianType -> Geometry.WkbGeometryType -> ByteStringBuilder.Builder+builderWkbGeom endianType wkbGeometryType =+ Endian.builderFourBytes endianType $ wkbGeometryTypeToInt wkbGeometryType+++-- Helpers++wkbGeometryTypeToInt :: Geometry.WkbGeometryType -> Word.Word32+wkbGeometryTypeToInt (Geometry.WkbGeom geometryType coordinateType) =+ coordinateTypeToInt coordinateType .|. geometryTypeToInt geometryType+ rawtoWkbGeometryType :: Word.Word32 -> BinaryGet.Get Geometry.WkbGeometryType rawtoWkbGeometryType rawGeometryType = do let geomType = intToGeometryType rawGeometryType@@ -38,20 +80,10 @@ Just g -> pure $ Geometry.WkbGeom g coordType _ -> Monad.fail $ "Invalid EwkbGeometry: " ++ show rawGeometryType -getEwkbSrid :: Endian.EndianType -> Word.Word32 -> BinaryGet.Get SridType-getEwkbSrid endianType int =- if int .&. 0x20000000 /= 0 then do- srid <- Endian.fourBytes endianType- if srid == 4326 then- pure $ Srid srid- else- Monad.fail $ "Invalid SRID only 4326 supported: " ++ show srid- else- pure NoSrid intToGeometryType :: Word.Word32 -> Maybe Geometry.GeometryType intToGeometryType int =- case int .&. 0x0fffffff of+ case int .&. geometryMask of 0 -> Just Geometry.Geometry 1 -> Just Geometry.Point 2 -> Just Geometry.LineString@@ -62,6 +94,18 @@ 7 -> Just Geometry.GeometryCollection _ -> Nothing +geometryTypeToInt :: Geometry.GeometryType -> Word.Word32+geometryTypeToInt geometryType =+ case geometryType of+ Geometry.Geometry -> 0+ Geometry.Point -> 1+ Geometry.LineString -> 2+ Geometry.Polygon -> 3+ Geometry.MultiPoint -> 4+ Geometry.MultiLineString -> 5+ Geometry.MultiPolygon -> 6+ Geometry.GeometryCollection -> 7+ intToCoordinateType :: Word.Word32 -> Geometry.CoordinateType intToCoordinateType int = case (hasZ int, hasM int) of@@ -70,11 +114,36 @@ (True, False) -> Geometry.Z (True, True) -> Geometry.ZM +coordinateTypeToInt :: Geometry.CoordinateType -> Word.Word32+coordinateTypeToInt coordinateType =+ case coordinateType of+ Geometry.TwoD -> 0+ Geometry.Z -> zMask+ Geometry.M -> mMask+ Geometry.ZM -> zMask .|. mMask+ hasZ :: Word.Word32 -> Bool hasZ int =- int .&. 0x80000000 /= 0+ int .&. zMask /= 0 hasM :: Word.Word32 -> Bool hasM int = int .&. 0x40000000 /= 0 ++-- Constants++zMask :: Word.Word32+zMask = 0x80000000++mMask :: Word.Word32+mMask = 0x40000000++sridMask :: Word.Word32+sridMask = 0x20000000++geometryMask :: Word.Word32+geometryMask = 0x0fffffff++supportedSrid :: Word.Word32+supportedSrid = 4326
src/Data/Internal/Wkb/Endian.hs view
@@ -1,18 +1,22 @@ module Data.Internal.Wkb.Endian ( EndianType (..)- , endianType- , fourBytes- , doubleBytes+ , getEndianType+ , getFourBytes+ , getDouble+ , builderEndianType+ , builderFourBytes+ , builderDouble ) where -import qualified Control.Monad as Monad-import qualified Data.Binary.Get as BinaryGet-import qualified Data.Word as Word+import qualified Control.Monad as Monad+import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Word as Word data EndianType = LittleEndian | BigEndian deriving (Show, Eq) -endianType :: BinaryGet.Get EndianType-endianType = do+getEndianType :: BinaryGet.Get EndianType+getEndianType = do byte <- BinaryGet.getWord8 case byte of 0 ->@@ -22,18 +26,38 @@ _ -> Monad.fail "Invalid EndianType" -fourBytes :: EndianType -> BinaryGet.Get Word.Word32-fourBytes et =- case et of+getFourBytes :: EndianType -> BinaryGet.Get Word.Word32+getFourBytes endianType =+ case endianType of LittleEndian -> BinaryGet.getWord32le BigEndian -> BinaryGet.getWord32be -doubleBytes :: EndianType -> BinaryGet.Get Double-doubleBytes et =- case et of+getDouble :: EndianType -> BinaryGet.Get Double+getDouble endianType =+ case endianType of LittleEndian -> BinaryGet.getDoublele BigEndian -> BinaryGet.getDoublebe++builderEndianType :: EndianType -> ByteStringBuilder.Builder+builderEndianType BigEndian = ByteStringBuilder.word8 0+builderEndianType LittleEndian = ByteStringBuilder.word8 1++builderFourBytes :: EndianType -> Word.Word32 -> ByteStringBuilder.Builder+builderFourBytes endianType =+ case endianType of+ LittleEndian ->+ ByteStringBuilder.word32LE+ BigEndian ->+ ByteStringBuilder.word32BE++builderDouble :: EndianType -> Double -> ByteStringBuilder.Builder+builderDouble endianType =+ case endianType of+ LittleEndian ->+ ByteStringBuilder.doubleLE+ BigEndian ->+ ByteStringBuilder.doubleBE
src/Data/Internal/Wkb/Geometry.hs view
@@ -2,15 +2,27 @@ ( GeometryType (..) , CoordinateType (..) , WkbGeometryType (..)- , geometryTypeWithCoords+ , BuilderWkbGeometryType+ , getWkbGeom+ , builderWkbGeom+ , geoPositionWithoutCRSToCoordinateType+ , coordTypeOfSequence+ , coordTypeOfLinearRings ) where import qualified Control.Monad as Monad import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Geospatial as Geospatial+import qualified Data.LinearRing as LinearRing+import qualified Data.Maybe as Maybe+import qualified Data.Sequence as Sequence import qualified Data.Word as Word import qualified Data.Internal.Wkb.Endian as Endian +-- Types+ data GeometryType = Geometry | Point@@ -25,9 +37,12 @@ data WkbGeometryType = WkbGeom GeometryType CoordinateType deriving (Show, Eq) -geometryTypeWithCoords :: Endian.EndianType -> BinaryGet.Get WkbGeometryType-geometryTypeWithCoords endianType = do- fullGeometryType <- Endian.fourBytes endianType++-- Binary parsers++getWkbGeom :: Endian.EndianType -> BinaryGet.Get WkbGeometryType+getWkbGeom endianType = do+ fullGeometryType <- Endian.getFourBytes endianType let geomType = intToGeometryType $ fullGeometryType `rem` 1000 coordType = intToCoordinateType $ fullGeometryType `div` 1000 case (geomType, coordType) of@@ -35,6 +50,36 @@ _ -> Monad.fail $ "Invalid WkbGeometryType: " ++ show fullGeometryType ++-- Binary builders++type BuilderWkbGeometryType = Endian.EndianType -> WkbGeometryType -> ByteStringBuilder.Builder++builderWkbGeom :: Endian.EndianType -> WkbGeometryType -> ByteStringBuilder.Builder+builderWkbGeom endianType (WkbGeom geometryType coordinateType) = do+ let int = coordinateTypeToInt coordinateType * 1000 + geometryTypeToInt geometryType+ Endian.builderFourBytes endianType int+++-- Helpers++geoPositionWithoutCRSToCoordinateType :: Geospatial.GeoPositionWithoutCRS -> Maybe CoordinateType+geoPositionWithoutCRSToCoordinateType geoPosition =+ case geoPosition of+ Geospatial.GeoEmpty -> Nothing+ Geospatial.GeoPointXY _ -> Just TwoD+ Geospatial.GeoPointXYZ _ -> Just Z+ Geospatial.GeoPointXYZM _ -> Just ZM++coordTypeOfSequence :: Sequence.Seq Geospatial.GeoPositionWithoutCRS -> CoordinateType+coordTypeOfSequence (first Sequence.:<| _) =+ Maybe.fromMaybe TwoD (geoPositionWithoutCRSToCoordinateType first)+coordTypeOfSequence _ = TwoD++coordTypeOfLinearRings :: Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS) -> CoordinateType+coordTypeOfLinearRings (first Sequence.:<| _) = coordTypeOfSequence $ LinearRing.toSeq first+coordTypeOfLinearRings _ = TwoD+ intToGeometryType :: Word.Word32 -> Maybe GeometryType intToGeometryType int = case int of@@ -48,6 +93,18 @@ 7 -> Just GeometryCollection _ -> Nothing +geometryTypeToInt :: GeometryType -> Word.Word32+geometryTypeToInt geometryType =+ case geometryType of+ Geometry -> 0+ Point -> 1+ LineString -> 2+ Polygon -> 3+ MultiPoint -> 4+ MultiLineString -> 5+ MultiPolygon -> 6+ GeometryCollection -> 7+ intToCoordinateType :: Word.Word32 -> Maybe CoordinateType intToCoordinateType int = case int of@@ -56,3 +113,11 @@ 2 -> Just M 3 -> Just ZM _ -> Nothing++coordinateTypeToInt :: CoordinateType -> Word.Word32+coordinateTypeToInt coordinateType =+ case coordinateType of+ TwoD -> 0+ Z -> 1+ M -> 2+ ZM -> 3
src/Data/Internal/Wkb/GeometryCollection.hs view
@@ -1,34 +1,57 @@ module Data.Internal.Wkb.GeometryCollection- ( geometryCollection- , enclosedFeature+ ( getGeometryCollection+ , getEnclosedFeature+ , builderGeometryCollection ) where import qualified Control.Monad as Monad import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Foldable as Foldable import qualified Data.Geospatial as Geospatial+import Data.Monoid ((<>)) import qualified Data.Sequence as Sequence import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geometry as Geometry -geometryCollection :: BinaryGet.Get Geospatial.GeospatialGeometry++-- Binary parsers++getGeometryCollection :: BinaryGet.Get Geospatial.GeospatialGeometry -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-geometryCollection getGeospatialGeometry endianType _ = do- numberOfGeometries <- Endian.fourBytes endianType+getGeometryCollection getGeospatialGeometry endianType _ = do+ numberOfGeometries <- Endian.getFourBytes endianType geoSpatialGeometries <- Sequence.replicateM (fromIntegral numberOfGeometries) getGeospatialGeometry pure $ Geospatial.Collection geoSpatialGeometries -enclosedFeature :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType)+getEnclosedFeature :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Geometry.GeometryType -> (Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get feature) -> BinaryGet.Get feature-enclosedFeature getWkbGeom expectedGeometryType getFeature = do- endianType <- Endian.endianType+getEnclosedFeature getWkbGeom expectedGeometryType getFeature = do+ endianType <- Endian.getEndianType geometryTypeWithCoords <- getWkbGeom endianType let (Geometry.WkbGeom geoType coordType) = geometryTypeWithCoords if geoType == expectedGeometryType then getFeature endianType coordType else Monad.fail "Wrong geometry type of enclosed feature"+++-- Binary builders++type BuilderGeospatialFeature = Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeospatialGeometry -> ByteStringBuilder.Builder++builderGeometryCollection :: BuilderGeospatialFeature+ -> Geometry.BuilderWkbGeometryType+ -> Endian.EndianType+ -> Sequence.Seq Geospatial.GeospatialGeometry+ -> ByteStringBuilder.Builder+builderGeometryCollection builderGeospatialFeature builderWkbGeom endianType geometryCollection =+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.GeometryCollection Geometry.TwoD)+ <> Endian.builderFourBytes endianType (fromIntegral $ length geometryCollection)+ <> Foldable.foldMap (builderGeospatialFeature builderWkbGeom endianType) geometryCollection
src/Data/Internal/Wkb/Geospatial.hs view
@@ -1,9 +1,12 @@ module Data.Internal.Wkb.Geospatial- ( geospatialGeometry+ ( getGeospatialGeometry+ , builderGeospatialGeometry ) where import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder import qualified Data.Geospatial as Geospatial+import qualified Data.Monoid as Monoid import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geometry as Geometry@@ -12,10 +15,13 @@ import qualified Data.Internal.Wkb.Point as Point import qualified Data.Internal.Wkb.Polygon as Polygon -geospatialGeometry :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType)++-- Binary parsers++getGeospatialGeometry :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> BinaryGet.Get Geospatial.GeospatialGeometry-geospatialGeometry getWkbGeom = do- endianType <- Endian.endianType+getGeospatialGeometry getWkbGeom = do+ endianType <- Endian.getEndianType geometryTypeWithCoords <- getWkbGeom endianType let (Geometry.WkbGeom geomType coordType) = geometryTypeWithCoords getFeature geomType getWkbGeom endianType coordType@@ -28,15 +34,35 @@ getFeature geomType getWkbGeom = case geomType of Geometry.Geometry -> getNoGeometry- Geometry.Point -> Point.point- Geometry.LineString -> Line.line- Geometry.Polygon -> Polygon.polygon- Geometry.MultiPoint -> Point.multiPoint getWkbGeom- Geometry.MultiLineString -> Line.multiLine getWkbGeom- Geometry.MultiPolygon -> Polygon.multiPolygon getWkbGeom- Geometry.GeometryCollection -> GeometryCollection.geometryCollection (geospatialGeometry getWkbGeom)+ Geometry.Point -> Point.getPoint+ Geometry.LineString -> Line.getLine+ Geometry.Polygon -> Polygon.getPolygon+ Geometry.MultiPoint -> Point.getMultiPoint getWkbGeom+ Geometry.MultiLineString -> Line.getMultiLine getWkbGeom+ Geometry.MultiPolygon -> Polygon.getMultiPolygon getWkbGeom+ Geometry.GeometryCollection -> GeometryCollection.getGeometryCollection (getGeospatialGeometry getWkbGeom) getNoGeometry :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry getNoGeometry _ _ = pure Geospatial.NoGeometry ++-- Binary builders++builderGeospatialGeometry :: Geometry.BuilderWkbGeometryType+ -> Endian.EndianType+ -> Geospatial.GeospatialGeometry+ -> ByteStringBuilder.Builder+builderGeospatialGeometry builderWkbGeom endianType geospatialGeometry =+ case geospatialGeometry of+ Geospatial.NoGeometry -> Monoid.mempty+ Geospatial.Point geoPoint -> build Point.builderPoint geoPoint+ Geospatial.Line geoLine -> build Line.builderLine geoLine+ Geospatial.Polygon geoPolygon -> build Polygon.builderPolygon geoPolygon+ Geospatial.MultiPoint geoMultiPoint -> build Point.builderMultiPoint geoMultiPoint+ Geospatial.MultiLine geoMultiLine -> build Line.builderMultiLine geoMultiLine+ Geospatial.MultiPolygon geoMultiPolygon -> build Polygon.builderMultiPolygon geoMultiPolygon+ Geospatial.Collection geoCollection -> builderGeometryCollection endianType geoCollection+ where builderGeometryCollection =+ GeometryCollection.builderGeometryCollection builderGeospatialGeometry builderWkbGeom+ build builder = builder builderWkbGeom endianType
src/Data/Internal/Wkb/Line.hs view
@@ -1,37 +1,64 @@ module Data.Internal.Wkb.Line- ( Data.Internal.Wkb.Line.line- , multiLine+ ( Data.Internal.Wkb.Line.getLine+ , getMultiLine+ , builderLine+ , builderMultiLine ) where import qualified Control.Monad as Monad import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Foldable as Foldable import qualified Data.Geospatial as Geospatial import qualified Data.LineString as LineString+import Data.Monoid ((<>)) import qualified Data.Sequence as Sequence + import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geometry as Geometry import qualified Data.Internal.Wkb.GeometryCollection as GeometryCollection import qualified Data.Internal.Wkb.Point as Point -line :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-line endianType coordType = do- gl <- geoLine endianType coordType+-- Binary parsers++getLine :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getLine endianType coordType = do+ gl <- getGeoLine endianType coordType pure $ Geospatial.Line gl -multiLine :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-multiLine getWkbGeom endianType _ = do- numberOfLines <- Endian.fourBytes endianType- geoLines <- Sequence.replicateM (fromIntegral numberOfLines) (GeometryCollection.enclosedFeature getWkbGeom Geometry.LineString geoLine)+getMultiLine :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getMultiLine getWkbGeom endianType _ = do+ numberOfLines <- Endian.getFourBytes endianType+ geoLines <- Sequence.replicateM (fromIntegral numberOfLines) (GeometryCollection.getEnclosedFeature getWkbGeom Geometry.LineString getGeoLine) pure $ Geospatial.MultiLine $ Geospatial.mergeGeoLines geoLines -geoLine :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoLine-geoLine endianType coordType = do- numberOfPoints <- Endian.fourBytes endianType+getGeoLine :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoLine+getGeoLine endianType coordType = do+ numberOfPoints <- Endian.getFourBytes endianType if numberOfPoints >= 2 then do- p1 <- Point.coordPoint endianType coordType- p2 <- Point.coordPoint endianType coordType- pts <- Point.coordPoints endianType coordType (numberOfPoints - 2)+ p1 <- Point.getCoordPoint endianType coordType+ p2 <- Point.getCoordPoint endianType coordType+ pts <- Point.getCoordPoints endianType coordType (numberOfPoints - 2) pure $ Geospatial.GeoLine $ LineString.makeLineString p1 p2 pts else Monad.fail "Must have at least two points for a line"+++-- Binary builders++builderLine :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoLine -> ByteStringBuilder.Builder+builderLine builderWkbGeom endianType (Geospatial.GeoLine lineString) = do+ let coordPoints = LineString.toSeq lineString+ coordType = Geometry.coordTypeOfSequence coordPoints+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.LineString coordType)+ <> Endian.builderFourBytes endianType (fromIntegral $ length coordPoints)+ <> Foldable.foldMap (Point.builderCoordPoint endianType) coordPoints++builderMultiLine :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoMultiLine -> ByteStringBuilder.Builder+builderMultiLine builderWkbGeom endianType (Geospatial.GeoMultiLine lineStrings) =+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.MultiLineString Geometry.TwoD)+ <> Endian.builderFourBytes endianType (fromIntegral $ length lineStrings)+ <> Foldable.foldMap (builderLine builderWkbGeom endianType . Geospatial.GeoLine) lineStrings
src/Data/Internal/Wkb/Point.hs view
@@ -1,12 +1,21 @@ module Data.Internal.Wkb.Point- ( point- , multiPoint- , coordPoint- , coordPoints+ ( getPoint+ , getMultiPoint+ , getGeoPoint+ , getCoordPoint+ , getCoordPoints+ , builderPoint+ , builderMultiPoint+ , builderCoordPoint+ , builderCoordPoints ) where import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Foldable as Foldable import qualified Data.Geospatial as Geospatial+import Data.Monoid ((<>))+import qualified Data.Monoid as Monoid import qualified Data.Sequence as Sequence import qualified Data.Word as Word @@ -14,46 +23,78 @@ import qualified Data.Internal.Wkb.Geometry as Geometry import qualified Data.Internal.Wkb.GeometryCollection as GeometryCollection -point :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-point endianType coordType = do- gp <- geoPoint endianType coordType- pure $ Geospatial.Point gp+-- Binary parsers -multiPoint :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-multiPoint getWkbGeom endianType _ = do- numberOfPoints <- Endian.fourBytes endianType- geoPoints <- Sequence.replicateM (fromIntegral numberOfPoints) (GeometryCollection.enclosedFeature getWkbGeom Geometry.Point geoPoint)+getPoint :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getPoint endianType coordType = do+ geoPoint <- getGeoPoint endianType coordType+ pure $ Geospatial.Point geoPoint++getMultiPoint :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getMultiPoint getWkbGeom endianType _ = do+ numberOfPoints <- Endian.getFourBytes endianType+ geoPoints <- Sequence.replicateM (fromIntegral numberOfPoints) (GeometryCollection.getEnclosedFeature getWkbGeom Geometry.Point getGeoPoint) pure $ Geospatial.MultiPoint $ Geospatial.mergeGeoPoints geoPoints -geoPoint :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoPoint-geoPoint endianType coordType = do- p <- coordPoint endianType coordType+getGeoPoint :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoPoint+getGeoPoint endianType coordType = do+ p <- getCoordPoint endianType coordType pure $ Geospatial.GeoPoint p -coordPoints :: Endian.EndianType -> Geometry.CoordinateType -> Word.Word32 -> BinaryGet.Get (Sequence.Seq Geospatial.GeoPositionWithoutCRS)-coordPoints endianType coordType numberOfPoints =- Sequence.replicateM (fromIntegral numberOfPoints) (coordPoint endianType coordType)--coordPoint :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoPositionWithoutCRS-coordPoint endianType coordType =+getCoordPoint :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoPositionWithoutCRS+getCoordPoint endianType coordType = case coordType of Geometry.TwoD -> do- x <- Endian.doubleBytes endianType- y <- Endian.doubleBytes endianType- pure $ Geospatial.GeoPointXY (Geospatial.PointXY x y)+ point <- Geospatial.PointXY <$> getDouble <*> getDouble+ return $ Geospatial.GeoPointXY point Geometry.Z -> do- x <- Endian.doubleBytes endianType- y <- Endian.doubleBytes endianType- z <- Endian.doubleBytes endianType- pure $ Geospatial.GeoPointXYZ (Geospatial.PointXYZ x y z)+ point <- Geospatial.PointXYZ <$> getDouble <*> getDouble <*> getDouble+ return $ Geospatial.GeoPointXYZ point Geometry.M -> do- x <- Endian.doubleBytes endianType- y <- Endian.doubleBytes endianType- m <- Endian.doubleBytes endianType- pure $ Geospatial.GeoPointXYZ (Geospatial.PointXYZ x y m)+ point <- Geospatial.PointXYZ <$> getDouble <*> getDouble <*> getDouble+ return $ Geospatial.GeoPointXYZ point Geometry.ZM -> do- x <- Endian.doubleBytes endianType- y <- Endian.doubleBytes endianType- z <- Endian.doubleBytes endianType- m <- Endian.doubleBytes endianType- pure $ Geospatial.GeoPointXYZM (Geospatial.PointXYZM x y z m)+ point <- Geospatial.PointXYZM <$> getDouble <*> getDouble <*> getDouble <*> getDouble+ return $ Geospatial.GeoPointXYZM point+ where getDouble = Endian.getDouble endianType++getCoordPoints :: Endian.EndianType -> Geometry.CoordinateType -> Word.Word32 -> BinaryGet.Get (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+getCoordPoints endianType coordType numberOfPoints =+ Sequence.replicateM (fromIntegral numberOfPoints) (getCoordPoint endianType coordType)+++-- Binary builders++builderPoint :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoPoint -> ByteStringBuilder.Builder+builderPoint builderWkbGeom endianType (Geospatial.GeoPoint coordPoint) =+ case Geometry.geoPositionWithoutCRSToCoordinateType coordPoint of+ Just coordinateType ->+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.Point coordinateType)+ <> builderCoordPoint endianType coordPoint+ Nothing ->+ Monoid.mempty++builderMultiPoint :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoMultiPoint -> ByteStringBuilder.Builder+builderMultiPoint builderWkbGeom endianType (Geospatial.GeoMultiPoint coordPoints) =+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.MultiPoint coordType)+ <> Endian.builderFourBytes endianType (fromIntegral $ length coordPoints)+ <> Foldable.foldMap (builderPoint builderWkbGeom endianType . Geospatial.GeoPoint) coordPoints+ where coordType = Geometry.coordTypeOfSequence coordPoints++builderCoordPoint :: Endian.EndianType -> Geospatial.GeoPositionWithoutCRS -> ByteStringBuilder.Builder+builderCoordPoint endianType coordPoint =+ case coordPoint of+ Geospatial.GeoEmpty -> Monoid.mempty+ Geospatial.GeoPointXY (Geospatial.PointXY x y) ->+ Foldable.foldMap builderDouble [x, y]+ Geospatial.GeoPointXYZ (Geospatial.PointXYZ x y z) ->+ Foldable.foldMap builderDouble [x, y, z]+ Geospatial.GeoPointXYZM (Geospatial.PointXYZM x y z m) ->+ Foldable.foldMap builderDouble [x, y, z, m]+ where builderDouble = Endian.builderDouble endianType++builderCoordPoints :: Endian.EndianType -> Sequence.Seq Geospatial.GeoPositionWithoutCRS -> ByteStringBuilder.Builder+builderCoordPoints endianType =+ Foldable.foldMap (builderCoordPoint endianType)
src/Data/Internal/Wkb/Polygon.hs view
@@ -1,12 +1,17 @@ module Data.Internal.Wkb.Polygon- ( polygon- , multiPolygon+ ( getPolygon+ , getMultiPolygon+ , builderPolygon+ , builderMultiPolygon ) where import qualified Control.Monad as Monad import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Foldable as Foldable import qualified Data.Geospatial as Geospatial import qualified Data.LinearRing as LinearRing+import Data.Monoid ((<>)) import qualified Data.Sequence as Sequence import qualified Data.Internal.Wkb.Endian as Endian@@ -15,15 +20,17 @@ import qualified Data.Internal.Wkb.Point as Point import qualified Data.SeqHelper as SeqHelper -polygon :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-polygon endianType coordType = do+-- Binary parsers++getPolygon :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getPolygon endianType coordType = do geoPolygon <- getGeoPolygon endianType coordType pure $ Geospatial.Polygon geoPolygon -multiPolygon :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry-multiPolygon getWkbGeom endianType _ = do- numberOfPolygons <- Endian.fourBytes endianType- geoPolygons <- Sequence.replicateM (fromIntegral numberOfPolygons) (GeometryCollection.enclosedFeature getWkbGeom Geometry.Polygon getGeoPolygon)+getMultiPolygon :: (Endian.EndianType -> BinaryGet.Get Geometry.WkbGeometryType) -> Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry+getMultiPolygon getWkbGeom endianType _ = do+ numberOfPolygons <- Endian.getFourBytes endianType+ geoPolygons <- Sequence.replicateM (fromIntegral numberOfPolygons) (GeometryCollection.getEnclosedFeature getWkbGeom Geometry.Polygon getGeoPolygon) pure $ Geospatial.MultiPolygon $ Geospatial.mergeGeoPolygons geoPolygons getGeoPolygon :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoPolygon@@ -33,17 +40,17 @@ getLinearRings :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)) getLinearRings endianType coordType = do- numberOfRings <- Endian.fourBytes endianType+ numberOfRings <- Endian.getFourBytes endianType Sequence.replicateM (fromIntegral numberOfRings) (getLinearRing endianType coordType) getLinearRing :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS) getLinearRing endianType coordType = do- numberOfPoints <- Endian.fourBytes endianType+ numberOfPoints <- Endian.getFourBytes endianType if numberOfPoints >= 4 then do- p1 <- Point.coordPoint endianType coordType- p2 <- Point.coordPoint endianType coordType- p3 <- Point.coordPoint endianType coordType- pts@(_ Sequence.:|> lastS) <- Point.coordPoints endianType coordType (numberOfPoints - 3)+ p1 <- Point.getCoordPoint endianType coordType+ p2 <- Point.getCoordPoint endianType coordType+ p3 <- Point.getCoordPoint endianType coordType+ pts@(_ Sequence.:|> lastS) <- Point.getCoordPoints endianType coordType (numberOfPoints - 3) if lastS == p1 then pure $ LinearRing.makeLinearRing p1 p2 p3 (SeqHelper.sequenceHead pts) else@@ -54,3 +61,30 @@ Monad.fail $ "Must have at least four points for a linear ring: " ++ show numberOfPoints+++-- Binary builders++builderPolygon :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoPolygon -> ByteStringBuilder.Builder+builderPolygon builderWkbGeom endianType (Geospatial.GeoPolygon linearRings) = do+ let coordType = Geometry.coordTypeOfLinearRings linearRings+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.Polygon coordType)+ <> Endian.builderFourBytes endianType (fromIntegral $ length linearRings)+ <> Foldable.foldMap (builderLinearRing endianType) linearRings++builderMultiPolygon :: Geometry.BuilderWkbGeometryType -> Endian.EndianType -> Geospatial.GeoMultiPolygon -> ByteStringBuilder.Builder+builderMultiPolygon builderWkbGeom endianType (Geospatial.GeoMultiPolygon polygons) =+ Endian.builderEndianType endianType+ <> builderWkbGeom endianType (Geometry.WkbGeom Geometry.MultiPolygon Geometry.TwoD)+ <> Endian.builderFourBytes endianType (fromIntegral $ length polygons)+ <> Foldable.foldMap (builderPolygon builderWkbGeom endianType . Geospatial.GeoPolygon) polygons++builderLinearRing :: Endian.EndianType -> LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS -> ByteStringBuilder.Builder+builderLinearRing endianType linearRing = do+ let coordPoints = LinearRing.toSeq linearRing+ lastCoordPoint = LinearRing.ringHead linearRing+ lengthOfRing = fromIntegral $ length coordPoints + 1+ Endian.builderFourBytes endianType lengthOfRing+ <> Foldable.foldMap (Point.builderCoordPoint endianType) coordPoints+ <> Point.builderCoordPoint endianType lastCoordPoint
src/Data/Internal/Wkt/Line.hs view
@@ -20,37 +20,49 @@ lineString = do _ <- Trifecta.string "linestring" _ <- Trifecta.spaces- (Trifecta.string "empty" >> pure emptyLine) <|> Geospatial.GeoLine <$> line+ (Trifecta.string "empty" >> pure emptyLine) <|> nonEmptyLines +nonEmptyLines :: Trifecta.Parser Geospatial.GeoLine+nonEmptyLines =+ (Trifecta.string "zm" >> Geospatial.GeoLine <$> line Point.justPointsXYZM)+ <|> (Trifecta.string "z" >> Geospatial.GeoLine <$> line Point.justPointsXYZ)+ <|> Geospatial.GeoLine <$> line Point.justPointsXY+ multiLineString :: Trifecta.Parser Geospatial.GeoMultiLine multiLineString = do _ <- Trifecta.string "multilinestring" _ <- Trifecta.spaces- x <- Wkt.emptySet <|> manyLines+ x <- Wkt.emptySet <|> nonEmptyMultiLines pure $ Geospatial.GeoMultiLine x -manyLines :: Trifecta.Parser (Sequence.Seq (LineString.LineString Geospatial.GeoPositionWithoutCRS))-manyLines = do+nonEmptyMultiLines :: Trifecta.Parser (Sequence.Seq (LineString.LineString Geospatial.GeoPositionWithoutCRS))+nonEmptyMultiLines =+ (Trifecta.string "zm" >> manyLines Point.justPointsXYZM)+ <|> (Trifecta.string "z" >> manyLines Point.justPointsXYZ)+ <|> manyLines Point.justPointsXY++manyLines :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq (LineString.LineString Geospatial.GeoPositionWithoutCRS))+manyLines pointParser = do _ <- Trifecta.spaces >> Trifecta.char '('- x <- line- xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> line)+ x <- line pointParser+ xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> line pointParser) _ <- Trifecta.char ')' >> Trifecta.spaces pure $ x Sequence.:<| Sequence.fromList xs -line :: Trifecta.Parser (LineString.LineString Geospatial.GeoPositionWithoutCRS)-line = do+line :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (LineString.LineString Geospatial.GeoPositionWithoutCRS)+line pointParser = do _ <- Trifecta.spaces >> Trifecta.char '(' >> Trifecta.spaces- first <- Point.justPoints- second <- commandPoint- rest <- Trifecta.many commandPoint+ first <- pointParser+ second <- commandPoint pointParser+ rest <- Trifecta.many (commandPoint pointParser) _ <- Trifecta.char ')' >> Trifecta.spaces pure $ LineString.makeLineString first second (Sequence.fromList rest) -commandPoint :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS-commandPoint = do+commandPoint :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser Geospatial.GeoPositionWithoutCRS+commandPoint pointParser = do _ <- Trifecta.char ',' _ <- Trifecta.spaces- Point.justPoints+ pointParser emptyLine :: Geospatial.GeoLine emptyLine = Geospatial.GeoLine $ LineString.makeLineString Geospatial.GeoEmpty Geospatial.GeoEmpty Sequence.empty
src/Data/Internal/Wkt/Point.hs view
@@ -1,7 +1,9 @@ module Data.Internal.Wkt.Point ( point , multiPoint- , justPoints+ , justPointsXY+ , justPointsXYZ+ , justPointsXYZM , emptyPoint , emptyMultiPoint ) where@@ -17,47 +19,86 @@ point = do _ <- Trifecta.string "point" _ <- Trifecta.spaces- (Trifecta.string "empty" >> pure emptyPoint) <|> fmap Geospatial.GeoPoint bracketedPoint+ (Trifecta.string "empty" >> pure emptyPoint) <|> nonEmptyPoints +nonEmptyPoints :: Trifecta.Parser Geospatial.GeoPoint+nonEmptyPoints =+ (Trifecta.string "zm" >> fmap Geospatial.GeoPoint (bracketedPoint justPointsXYZM))+ <|> (Trifecta.string "z" >> fmap Geospatial.GeoPoint (bracketedPoint justPointsXYZ))+ <|> fmap Geospatial.GeoPoint (bracketedPoint justPointsXY)+ multiPoint :: Trifecta.Parser Geospatial.GeoMultiPoint multiPoint = do _ <- Trifecta.string "multipoint" _ <- Trifecta.spaces- xl <- Wkt.emptySet <|> manyPoints+ xl <- Wkt.emptySet <|> nonEmptyMultipoints pure $ Geospatial.GeoMultiPoint xl -manyPoints :: Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)-manyPoints = do- _ <- Trifecta.char '(' >> Trifecta.spaces- xl <- unbracketedPoints <|> bracketedPoints+nonEmptyMultipoints :: Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+nonEmptyMultipoints =+ (Trifecta.string "zm" >> manyPoints justPointsXYZM)+ <|> (Trifecta.string "z" >> manyPoints justPointsXYZ)+ <|> manyPoints justPointsXY++manyPoints :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+manyPoints pointParser = do+ _ <- Trifecta.spaces >> Trifecta.char '(' >> Trifecta.spaces+ xl <- unbracketedPoints pointParser <|> bracketedPoints pointParser _ <- Trifecta.spaces >> Trifecta.char ')' >> Trifecta.spaces pure xl -unbracketedPoints :: Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)-unbracketedPoints = do- x <- justPoints- xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> justPoints)+unbracketedPoints :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+unbracketedPoints pointParser = do+ x <- pointParser+ xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> pointParser ) pure $ x Sequence.<| Sequence.fromList xs -bracketedPoints :: Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)-bracketedPoints = do- x <- bracketedPoint- xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> bracketedPoint)+bracketedPoints :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+bracketedPoints pointParser = do+ x <- bracketedPoint pointParser+ xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> bracketedPoint pointParser) pure $ x Sequence.<| Sequence.fromList xs -bracketedPoint :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS-bracketedPoint = do+bracketedPoint :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser Geospatial.GeoPositionWithoutCRS+bracketedPoint pointParser = do _ <- Trifecta.spaces >> Trifecta.char '(' >> Trifecta.spaces- x <- justPoints+ x <- pointParser _ <- Trifecta.spaces >> Trifecta.char ')' >> Trifecta.spaces pure x -justPoints :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS-justPoints = do+firstXy :: Trifecta.Parser (Scientific.Scientific, Scientific.Scientific)+firstXy = do x <- Wkt.number _ <- Trifecta.spaces y <- Wkt.number- pure $ Geospatial.GeoPointXY (Geospatial.PointXY (Scientific.toRealFloat x) (Scientific.toRealFloat y))+ pure (x, y)++firstXyz :: Trifecta.Parser (Scientific.Scientific, Scientific.Scientific, Scientific.Scientific)+firstXyz = do+ (x, y) <- firstXy+ _ <- Trifecta.spaces+ z <- Wkt.number+ pure (x, y, z)++justPointsXY :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS+justPointsXY = do+ (x,y) <- firstXy+ let xy = Geospatial.PointXY (Scientific.toRealFloat x) (Scientific.toRealFloat y)+ pure $ Geospatial.GeoPointXY xy++justPointsXYZ :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS+justPointsXYZ = do+ (x,y,z) <- firstXyz+ let xyz = Geospatial.PointXYZ (Scientific.toRealFloat x) (Scientific.toRealFloat y) (Scientific.toRealFloat z)+ pure $ Geospatial.GeoPointXYZ xyz++justPointsXYZM :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS+justPointsXYZM = do+ (x,y,z) <- firstXyz+ _ <- Trifecta.spaces+ m <- Wkt.number+ let xyzm = Geospatial.PointXYZM (Scientific.toRealFloat x) (Scientific.toRealFloat y) (Scientific.toRealFloat z) (Scientific.toRealFloat m)+ pure $ Geospatial.GeoPointXYZM xyzm emptyPoint :: Geospatial.GeoPoint emptyPoint = Geospatial.GeoPoint Geospatial.GeoEmpty
src/Data/Internal/Wkt/Polygon.hs view
@@ -20,39 +20,51 @@ polygon = do _ <- Trifecta.string "polygon" _ <- Trifecta.spaces- x <- Wkt.emptySet <|> polygon'+ x <- Wkt.emptySet <|> nonEmptyPolygon pure $ Geospatial.GeoPolygon x +nonEmptyPolygon :: Trifecta.Parser (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS))+nonEmptyPolygon =+ (Trifecta.string "zm" >> polygon' Point.justPointsXYZM)+ <|> (Trifecta.string "z" >> polygon' Point.justPointsXYZ)+ <|> polygon' Point.justPointsXY+ multiPolygon :: Trifecta.Parser Geospatial.GeoMultiPolygon multiPolygon = do _ <- Trifecta.string "multipolygon" _ <- Trifecta.spaces- xs <- Wkt.emptySet <|> multiPolygon'+ xs <- Wkt.emptySet <|> nonEmptyMultiPolygon pure $ Geospatial.GeoMultiPolygon xs -polygon' :: Trifecta.Parser (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS))-polygon' = do+nonEmptyMultiPolygon :: Trifecta.Parser (Sequence.Seq (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)))+nonEmptyMultiPolygon =+ (Trifecta.string "zm" >> multiPolygon' Point.justPointsXYZM)+ <|> (Trifecta.string "z" >> multiPolygon' Point.justPointsXYZ)+ <|> multiPolygon' Point.justPointsXY++polygon' :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS))+polygon' pointParser = do _ <- Trifecta.spaces >> Trifecta.char '('- x <- linearRing- xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> linearRing)+ x <- linearRing pointParser+ xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> linearRing pointParser) _ <- Trifecta.char ')' >> Trifecta.spaces pure $ x Sequence.:<| Sequence.fromList xs -multiPolygon' :: Trifecta.Parser (Sequence.Seq (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)))-multiPolygon' = do+multiPolygon' :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (Sequence.Seq (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)))+multiPolygon' pointParser = do _ <- Trifecta.spaces >> Trifecta.char '('- x <- polygon'- xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> polygon')+ x <- polygon' pointParser+ xs <- Trifecta.many (Trifecta.char ',' >> Trifecta.spaces >> polygon' pointParser) _ <- Trifecta.char ')' >> Trifecta.spaces pure $ x Sequence.:<| Sequence.fromList xs -linearRing :: Trifecta.Parser (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)-linearRing = do+linearRing :: Trifecta.Parser Geospatial.GeoPositionWithoutCRS -> Trifecta.Parser (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)+linearRing pointParser = do _ <- Trifecta.spaces >> Trifecta.char '(' >> Trifecta.spaces- first <- Point.justPoints- second <- Line.commandPoint- third <- Line.commandPoint- rest <- Trifecta.many Line.commandPoint+ first <- pointParser+ second <- Line.commandPoint pointParser+ third <- Line.commandPoint pointParser+ rest <- Trifecta.many (Line.commandPoint pointParser) _ <- Trifecta.char ')' >> Trifecta.spaces pure $ LinearRing.makeLinearRing first second third (SeqHelper.sequenceHead $ Sequence.fromList rest)
src/Data/Wkb.hs view
@@ -5,19 +5,35 @@ ------------------------------------------------------------------- module Data.Wkb ( parseByteString+ , parseHexByteString+ , toByteString ) where import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder import qualified Data.ByteString.Lazy as LazyByteString import qualified Data.Geospatial as Geospatial+import qualified Data.Hex as Hex +import qualified Data.Internal.Wkb.Endian as Endian import qualified Data.Internal.Wkb.Geometry as Geometry import qualified Data.Internal.Wkb.Geospatial as WkbGeospatial +-- |+-- Representation of WKB as Binary parseByteString :: LazyByteString.ByteString -> Either String Geospatial.GeospatialGeometry parseByteString byteString = case BinaryGet.runGetOrFail- (WkbGeospatial.geospatialGeometry Geometry.geometryTypeWithCoords)+ (WkbGeospatial.getGeospatialGeometry Geometry.getWkbGeom) byteString of Left (_, _, err) -> Left $ "Could not parse wkb: " ++ err Right (_, _, geoSpatialGeometry) -> Right geoSpatialGeometry++-- |+-- Representation of WKB as a String in Base16/Hex form i.e. "0101000000000000000000f03f0000000000000040" is POINT 1.0 2.0+parseHexByteString :: Hex.Hex -> Either String Geospatial.GeospatialGeometry+parseHexByteString = Hex.safeConvert parseByteString++toByteString :: Endian.EndianType -> Geospatial.GeospatialGeometry -> LazyByteString.ByteString+toByteString endianType =+ ByteStringBuilder.toLazyByteString . WkbGeospatial.builderGeospatialGeometry Geometry.builderWkbGeom endianType
test/Data/Internal/Ewkb/GeometrySpec.hs view
@@ -4,8 +4,6 @@ import qualified Data.Binary.Get as BinaryGet import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import Data.Monoid ((<>)) import qualified Data.Word as Word import Test.Hspec (Spec, describe, it, shouldBe) @@ -20,98 +18,85 @@ testValidGetEwkbGeometryType :: Spec testValidGetEwkbGeometryType = describe "get extended wkb geometry type for valid data" $- mapM_ testGetEwkbGeometryType expectations+ mapM_ testGetEwkbGeometryType testValues -testGetEwkbGeometryType :: (Word.Word32, Maybe Word.Word32, Ewkb.EwkbGeometryType) -> Spec-testGetEwkbGeometryType (rawGeomType, maybeSrid, expected) =- it ("Parse " ++ show expected) $+testGetEwkbGeometryType :: Ewkb.EwkbGeometryType -> Spec+testGetEwkbGeometryType geometryType =+ it ("Parse " ++ show geometryType) $ mapM_ test [Endian.BigEndian, Endian.LittleEndian]- where test endianType =- BinaryGet.runGet (Ewkb.ewkbGeometryType endianType) (getByteString endianType rawGeomType maybeSrid) `shouldBe` expected+ where test endianType = roundTrip endianType geometryType `shouldBe` geometryType -getByteString :: Endian.EndianType -> Word.Word32 -> Maybe Word.Word32 -> LazyByteString.ByteString-getByteString endianType rawGeomType maybeSrid =- ByteStringBuilder.toLazyByteString $- case maybeSrid of- Just srid' ->- case endianType of- Endian.LittleEndian ->- ByteStringBuilder.word32LE rawGeomType <> ByteStringBuilder.word32LE srid'- Endian.BigEndian ->- ByteStringBuilder.word32BE rawGeomType <> ByteStringBuilder.word32BE srid'- Nothing ->- case endianType of- Endian.LittleEndian ->- ByteStringBuilder.word32LE rawGeomType- Endian.BigEndian ->- ByteStringBuilder.word32BE rawGeomType+roundTrip :: Endian.EndianType -> Ewkb.EwkbGeometryType -> Ewkb.EwkbGeometryType+roundTrip endianType geometryType =+ BinaryGet.runGet (Ewkb.getEwkbGeom endianType) encodedGeometryType+ where encodedGeometryType = ByteStringBuilder.toLazyByteString $ Ewkb.builderEwkbGeom endianType geometryType -expectations :: [(Word.Word32, Maybe Word.Word32, Ewkb.EwkbGeometryType)]-expectations =- [ (0x00000000, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.TwoD) Ewkb.NoSrid)- , (0x00000001, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.TwoD) Ewkb.NoSrid)- , (0x00000002, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.TwoD) Ewkb.NoSrid)- , (0x00000003, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.TwoD) Ewkb.NoSrid)- , (0x00000004, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.TwoD) Ewkb.NoSrid)- , (0x00000005, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.TwoD) Ewkb.NoSrid)- , (0x00000006, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.TwoD) Ewkb.NoSrid)- , (0x00000007, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.TwoD) Ewkb.NoSrid)- , (0x80000000, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.Z) Ewkb.NoSrid)- , (0x80000001, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.Z) Ewkb.NoSrid)- , (0x80000002, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.Z) Ewkb.NoSrid)- , (0x80000003, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.Z) Ewkb.NoSrid)- , (0x80000004, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.Z) Ewkb.NoSrid)- , (0x80000005, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.Z) Ewkb.NoSrid)- , (0x80000006, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.Z) Ewkb.NoSrid)- , (0x80000007, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.Z) Ewkb.NoSrid)- , (0x40000000, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.M) Ewkb.NoSrid)- , (0x40000001, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.M) Ewkb.NoSrid)- , (0x40000002, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.M) Ewkb.NoSrid)- , (0x40000003, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.M) Ewkb.NoSrid)- , (0x40000004, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.M) Ewkb.NoSrid)- , (0x40000005, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.M) Ewkb.NoSrid)- , (0x40000006, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.M) Ewkb.NoSrid)- , (0x40000007, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.M) Ewkb.NoSrid)- , (0xC0000000, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.ZM) Ewkb.NoSrid)- , (0xC0000001, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.ZM) Ewkb.NoSrid)- , (0xC0000002, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.ZM) Ewkb.NoSrid)- , (0xC0000003, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.ZM) Ewkb.NoSrid)- , (0xC0000004, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.ZM) Ewkb.NoSrid)- , (0xC0000005, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.ZM) Ewkb.NoSrid)- , (0xC0000006, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.ZM) Ewkb.NoSrid)- , (0xC0000007, Nothing, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.ZM) Ewkb.NoSrid)- , (0x20000000, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000001, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000002, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000003, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000004, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000005, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000006, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.TwoD) (Ewkb.Srid srid))- , (0x20000007, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.TwoD) (Ewkb.Srid srid))- , (0xA0000000, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.Z) (Ewkb.Srid srid))- , (0xA0000001, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.Z) (Ewkb.Srid srid))- , (0xA0000002, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.Z) (Ewkb.Srid srid))- , (0xA0000003, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.Z) (Ewkb.Srid srid))- , (0xA0000004, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.Z) (Ewkb.Srid srid))- , (0xA0000005, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.Z) (Ewkb.Srid srid))- , (0xA0000006, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.Z) (Ewkb.Srid srid))- , (0xA0000007, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.Z) (Ewkb.Srid srid))- , (0x60000000, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.M) (Ewkb.Srid srid))- , (0x60000001, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.M) (Ewkb.Srid srid))- , (0x60000002, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.M) (Ewkb.Srid srid))- , (0x60000003, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.M) (Ewkb.Srid srid))- , (0x60000004, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.M) (Ewkb.Srid srid))- , (0x60000005, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.M) (Ewkb.Srid srid))- , (0x60000006, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.M) (Ewkb.Srid srid))- , (0x60000007, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.M) (Ewkb.Srid srid))- , (0xE0000000, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000001, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000002, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000003, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000004, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000005, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000006, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.ZM) (Ewkb.Srid srid))- , (0xE0000007, Just srid, Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.ZM) (Ewkb.Srid srid))+testValues :: [Ewkb.EwkbGeometryType]+testValues =+ [ Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.TwoD) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.Z) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.M) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.ZM) Ewkb.NoSrid+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.TwoD) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.Z) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.M) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Geometry Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Point Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.LineString Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.Polygon Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPoint Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiLineString Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.MultiPolygon Wkb.ZM) (Ewkb.Srid srid)+ , Ewkb.EwkbGeom (Wkb.WkbGeom Wkb.GeometryCollection Wkb.ZM) (Ewkb.Srid srid) ] srid :: Word.Word32
test/Data/Internal/Wkb/EndianSpec.hs view
@@ -4,8 +4,6 @@ import qualified Data.Binary.Get as BinaryGet import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified GHC.Word as Word import Test.Hspec (Spec, describe, it, shouldBe) import qualified Data.Internal.Wkb.Endian as Endian@@ -18,12 +16,13 @@ testGetEndian = describe "get endian" $ do it "Returns BigEndian for 0" $- BinaryGet.runGet Endian.endianType (getByteString 0) `shouldBe` Endian.BigEndian+ roundTrip Endian.BigEndian `shouldBe` Endian.BigEndian it "Returns LittleEndian for 1" $- BinaryGet.runGet Endian.endianType (getByteString 1) `shouldBe` Endian.LittleEndian+ roundTrip Endian.LittleEndian `shouldBe` Endian.LittleEndian it "Returns fail for other" $- BinaryGet.runGetOrFail Endian.endianType (getByteString 5) `shouldBe` Left ("", 1, "Invalid EndianType")+ BinaryGet.runGetOrFail Endian.getEndianType (ByteStringBuilder.toLazyByteString $ ByteStringBuilder.word8 5) `shouldBe` Left ("", 1, "Invalid EndianType") -getByteString :: Word.Word8 -> LazyByteString.ByteString-getByteString int =- ByteStringBuilder.toLazyByteString $ ByteStringBuilder.word8 int+roundTrip :: Endian.EndianType -> Endian.EndianType+roundTrip endianType =+ BinaryGet.runGet Endian.getEndianType encodedEndianType+ where encodedEndianType = ByteStringBuilder.toLazyByteString $ Endian.builderEndianType endianType
+ test/Data/Internal/Wkb/GeometryCollectionSpec.hs view
@@ -0,0 +1,14 @@++{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkb.GeometryCollectionSpec where++import Test.Hspec (Spec, describe)++import qualified Data.SpecHelper as SpecHelper++spec :: Spec+spec =+ describe "Test wkb geometry collection parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "geometry collection" SpecHelper.genGeometryCollection+
test/Data/Internal/Wkb/GeometrySpec.hs view
@@ -4,8 +4,6 @@ import qualified Data.Binary.Get as BinaryGet import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified Data.Word as Word import Test.Hspec (Spec, describe, it, shouldBe) import qualified Data.Internal.Wkb.Endian as Endian@@ -18,56 +16,52 @@ testValidGetGeometryTypeWithCoords :: Spec testValidGetGeometryTypeWithCoords = describe "get geometry type with coords type for valid data" $- mapM_ testGetGeometryTypeWithCoords expectations+ mapM_ testGetGeometryTypeWithCoords geometryTypes -testGetGeometryTypeWithCoords :: (Word.Word32, Geometry.WkbGeometryType) -> Spec-testGetGeometryTypeWithCoords (int, expected) =- it ("Parse " ++ show expected) $+testGetGeometryTypeWithCoords :: Geometry.WkbGeometryType -> Spec+testGetGeometryTypeWithCoords geometryType =+ it ("Parse " ++ show geometryType) $ mapM_ test [Endian.BigEndian, Endian.LittleEndian] where test endianType =- BinaryGet.runGet (Geometry.geometryTypeWithCoords endianType) (getByteString endianType int) `shouldBe` expected+ roundTrip endianType geometryType `shouldBe` geometryType -getByteString :: Endian.EndianType -> Word.Word32 -> LazyByteString.ByteString-getByteString endianType int =- ByteStringBuilder.toLazyByteString $- case endianType of- Endian.LittleEndian ->- ByteStringBuilder.word32LE int- Endian.BigEndian ->- ByteStringBuilder.word32BE int+roundTrip :: Endian.EndianType -> Geometry.WkbGeometryType -> Geometry.WkbGeometryType+roundTrip endianType geometryType =+ BinaryGet.runGet (Geometry.getWkbGeom endianType) encodedGeometryType+ where encodedGeometryType = ByteStringBuilder.toLazyByteString $ Geometry.builderWkbGeom endianType geometryType -expectations :: [(Word.Word32, Geometry.WkbGeometryType)]-expectations =- [ (0000, Geometry.WkbGeom Geometry.Geometry Geometry.TwoD)- , (0001, Geometry.WkbGeom Geometry.Point Geometry.TwoD)- , (0002, Geometry.WkbGeom Geometry.LineString Geometry.TwoD)- , (0003, Geometry.WkbGeom Geometry.Polygon Geometry.TwoD)- , (0004, Geometry.WkbGeom Geometry.MultiPoint Geometry.TwoD)- , (0005, Geometry.WkbGeom Geometry.MultiLineString Geometry.TwoD)- , (0006, Geometry.WkbGeom Geometry.MultiPolygon Geometry.TwoD)- , (0007, Geometry.WkbGeom Geometry.GeometryCollection Geometry.TwoD)- , (1000, Geometry.WkbGeom Geometry.Geometry Geometry.Z)- , (1001, Geometry.WkbGeom Geometry.Point Geometry.Z)- , (1002, Geometry.WkbGeom Geometry.LineString Geometry.Z)- , (1003, Geometry.WkbGeom Geometry.Polygon Geometry.Z)- , (1004, Geometry.WkbGeom Geometry.MultiPoint Geometry.Z)- , (1005, Geometry.WkbGeom Geometry.MultiLineString Geometry.Z)- , (1006, Geometry.WkbGeom Geometry.MultiPolygon Geometry.Z)- , (1007, Geometry.WkbGeom Geometry.GeometryCollection Geometry.Z)- , (2000, Geometry.WkbGeom Geometry.Geometry Geometry.M)- , (2001, Geometry.WkbGeom Geometry.Point Geometry.M)- , (2002, Geometry.WkbGeom Geometry.LineString Geometry.M)- , (2003, Geometry.WkbGeom Geometry.Polygon Geometry.M)- , (2004, Geometry.WkbGeom Geometry.MultiPoint Geometry.M)- , (2005, Geometry.WkbGeom Geometry.MultiLineString Geometry.M)- , (2006, Geometry.WkbGeom Geometry.MultiPolygon Geometry.M)- , (2007, Geometry.WkbGeom Geometry.GeometryCollection Geometry.M)- , (3000, Geometry.WkbGeom Geometry.Geometry Geometry.ZM)- , (3001, Geometry.WkbGeom Geometry.Point Geometry.ZM)- , (3002, Geometry.WkbGeom Geometry.LineString Geometry.ZM)- , (3003, Geometry.WkbGeom Geometry.Polygon Geometry.ZM)- , (3004, Geometry.WkbGeom Geometry.MultiPoint Geometry.ZM)- , (3005, Geometry.WkbGeom Geometry.MultiLineString Geometry.ZM)- , (3006, Geometry.WkbGeom Geometry.MultiPolygon Geometry.ZM)- , (3007, Geometry.WkbGeom Geometry.GeometryCollection Geometry.ZM)+geometryTypes :: [Geometry.WkbGeometryType]+geometryTypes =+ [ Geometry.WkbGeom Geometry.Geometry Geometry.TwoD+ , Geometry.WkbGeom Geometry.Point Geometry.TwoD+ , Geometry.WkbGeom Geometry.LineString Geometry.TwoD+ , Geometry.WkbGeom Geometry.Polygon Geometry.TwoD+ , Geometry.WkbGeom Geometry.MultiPoint Geometry.TwoD+ , Geometry.WkbGeom Geometry.MultiLineString Geometry.TwoD+ , Geometry.WkbGeom Geometry.MultiPolygon Geometry.TwoD+ , Geometry.WkbGeom Geometry.GeometryCollection Geometry.TwoD+ , Geometry.WkbGeom Geometry.Geometry Geometry.Z+ , Geometry.WkbGeom Geometry.Point Geometry.Z+ , Geometry.WkbGeom Geometry.LineString Geometry.Z+ , Geometry.WkbGeom Geometry.Polygon Geometry.Z+ , Geometry.WkbGeom Geometry.MultiPoint Geometry.Z+ , Geometry.WkbGeom Geometry.MultiLineString Geometry.Z+ , Geometry.WkbGeom Geometry.MultiPolygon Geometry.Z+ , Geometry.WkbGeom Geometry.GeometryCollection Geometry.Z+ , Geometry.WkbGeom Geometry.Geometry Geometry.M+ , Geometry.WkbGeom Geometry.Point Geometry.M+ , Geometry.WkbGeom Geometry.LineString Geometry.M+ , Geometry.WkbGeom Geometry.Polygon Geometry.M+ , Geometry.WkbGeom Geometry.MultiPoint Geometry.M+ , Geometry.WkbGeom Geometry.MultiLineString Geometry.M+ , Geometry.WkbGeom Geometry.MultiPolygon Geometry.M+ , Geometry.WkbGeom Geometry.GeometryCollection Geometry.M+ , Geometry.WkbGeom Geometry.Geometry Geometry.ZM+ , Geometry.WkbGeom Geometry.Point Geometry.ZM+ , Geometry.WkbGeom Geometry.LineString Geometry.ZM+ , Geometry.WkbGeom Geometry.Polygon Geometry.ZM+ , Geometry.WkbGeom Geometry.MultiPoint Geometry.ZM+ , Geometry.WkbGeom Geometry.MultiLineString Geometry.ZM+ , Geometry.WkbGeom Geometry.MultiPolygon Geometry.ZM+ , Geometry.WkbGeom Geometry.GeometryCollection Geometry.ZM ]
+ test/Data/Internal/Wkb/HexParsingSpec.hs view
@@ -0,0 +1,31 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkb.HexParsingSpec where++import qualified Data.Geospatial as Geospatial+import Test.Hspec (Spec, describe, it, shouldBe)++import qualified Data.Hex as Hex+import qualified Data.Wkb as Wkb++spec :: Spec+spec =+ testWkbHexParsing++testWkbHexParsing :: Spec+testWkbHexParsing =+ describe "Test hex encoded wkb point" $ do+ it "Parse valid hex wkb" $+ Wkb.parseHexByteString exampleHexPoint `shouldBe` Right expectedPoint+ it "Not parse valid hex but invalid wkb" $+ Wkb.parseHexByteString (Hex.Hex "deadbeef") `shouldBe` Left "Could not parse wkb: Invalid EndianType"+ it "Some valid, some invalid hex" $+ Wkb.parseHexByteString (Hex.Hex "deadfish") `shouldBe` Left "Invalid hex representation: deadfish"+ it "All bad" $+ Wkb.parseHexByteString (Hex.Hex "cowboyx") `shouldBe` Left "Invalid hex representation: cowboyx"++exampleHexPoint :: Hex.Hex+exampleHexPoint = Hex.Hex "0101000000000000000000f03f0000000000000040"++expectedPoint :: Geospatial.GeospatialGeometry+expectedPoint = Geospatial.Point (Geospatial.GeoPoint (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0)))
+ test/Data/Internal/Wkb/LineSpec.hs view
@@ -0,0 +1,28 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkb.LineSpec where++import Test.Hspec (Spec, describe)++import qualified Data.SpecHelper as SpecHelper++spec :: Spec+spec = do+ testWkbLineParsing+ testWkbMultiLineParsing+++-- Test Wkb Line Parsing++testWkbLineParsing :: Spec+testWkbLineParsing =+ describe "Test wkb line parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "line" SpecHelper.genLine+++-- Test Wkb MultiLine Parsing++testWkbMultiLineParsing :: Spec+testWkbMultiLineParsing =+ describe "Test wkb multiline parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "multiLine" SpecHelper.genMultiLine
+ test/Data/Internal/Wkb/PointSpec.hs view
@@ -0,0 +1,56 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkb.PointSpec where++import qualified Data.Binary.Get as BinaryGet+import qualified Data.ByteString.Builder as ByteStringBuilder+import qualified Data.Geospatial as Geospatial+import qualified HaskellWorks.Hspec.Hedgehog as HedgehogHspec+import Hedgehog+import Test.Hspec (Spec, describe, it)++import qualified Data.Internal.Wkb.Geometry as Geometry+import qualified Data.Internal.Wkb.Point as Point+import qualified Data.SpecHelper as SpecHelper++spec :: Spec+spec = do+ testCoordPointParsing+ testWkbPointParsing+ testWkbMultiPointParsing+++-- Test Coord Point Parsing++testCoordPointParsing :: Spec+testCoordPointParsing =+ describe "Test coord point parsing" $+ mapM_ testCoordPointParsing' SpecHelper.coordPointGenerators++testCoordPointParsing' :: (Geometry.CoordinateType, Gen Geospatial.GeoPositionWithoutCRS) -> Spec+testCoordPointParsing' (coordType, genCoordPoint) =+ it ("round trips coord point: " ++ show coordType) $ HedgehogHspec.require $ property $ do+ coordPoint <- forAll genCoordPoint+ endianType <- forAll SpecHelper.genEndianType+ roundTrip endianType coordPoint === coordPoint+ where+ roundTrip endianType coordPoint =+ BinaryGet.runGet (Point.getCoordPoint endianType coordType) (encodedCoordPoint endianType coordPoint)+ encodedCoordPoint endianType coordPoint =+ ByteStringBuilder.toLazyByteString $ Point.builderCoordPoint endianType coordPoint+++-- Test Wkb Point Parsing++testWkbPointParsing :: Spec+testWkbPointParsing =+ describe "Test wkb point parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "point" SpecHelper.genPoint+++-- Test Wkb MultiPoint Parsing++testWkbMultiPointParsing :: Spec+testWkbMultiPointParsing =+ describe "Test wkb multipoint parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "multipoint" SpecHelper.genMultiPoint
+ test/Data/Internal/Wkb/PolygonSpec.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkb.PolygonSpec where++import qualified Data.ByteString.Builder as ByteStringBuilder+import Data.Monoid ((<>))+import Test.Hspec (Spec, describe, it, shouldBe)++import qualified Data.SpecHelper as SpecHelper+import qualified Data.Wkb as Wkb++spec :: Spec+spec = do+ testWkbPolygonParsing+ testWkbMultiPolygonParsing+++-- Test Wkb Polygon Parsing++testWkbPolygonParsing :: Spec+testWkbPolygonParsing =+ describe "Test wkb polygon" $ do+ testValidWkbPolyonParsing+ testInvalidWkbPolyonParsing++testValidWkbPolyonParsing :: Spec+testValidWkbPolyonParsing =+ SpecHelper.testRoundTripWkbGeometryParsing "polygon" SpecHelper.genPolygon++testInvalidWkbPolyonParsing :: Spec+testInvalidWkbPolyonParsing =+ it "does not parse bad wkb polygon" $+ Wkb.parseByteString exampleBadWkbPolygon `shouldBe` Left "Could not parse wkb: First and last points of linear ring are different: first=GeoPointXY (PointXY {_xyX = 1.0, _xyY = 2.0}) last=GeoPointXY (PointXY {_xyX = 7.0, _xyY = 8.0})"+ where exampleBadWkbPolygon =+ ByteStringBuilder.toLazyByteString $+ ByteStringBuilder.word8 0+ <> ByteStringBuilder.int32BE 3+ <> ByteStringBuilder.int32BE 1+ <> ByteStringBuilder.int32BE 4+ <> ByteStringBuilder.doubleBE 1.0+ <> ByteStringBuilder.doubleBE 2.0+ <> ByteStringBuilder.doubleBE 3.0+ <> ByteStringBuilder.doubleBE 4.0+ <> ByteStringBuilder.doubleBE 5.0+ <> ByteStringBuilder.doubleBE 6.0+ <> ByteStringBuilder.doubleBE 7.0+ <> ByteStringBuilder.doubleBE 8.0+++-- Test Wkb MultiPolygon Parsing++testWkbMultiPolygonParsing :: Spec+testWkbMultiPolygonParsing =+ describe "Test wkb multipolygon parsing" $+ SpecHelper.testRoundTripWkbGeometryParsing "multipolygon" SpecHelper.genMultiPolygon
+ test/Data/Internal/Wkt/GeometryCollectionSpec.hs view
@@ -0,0 +1,34 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkt.GeometryCollectionSpec where++import Control.Lens ((^?!))+import qualified Data.Geospatial as Geospatial+import qualified Data.Sequence as Sequence+import Test.Hspec (Spec, describe, it, shouldBe)+import qualified Text.Trifecta as Trifecta++import qualified Data.Wkt as Wkt++import qualified Data.SpecHelper as SpecHelper++spec :: Spec+spec = testGeometryCollection++testGeometryCollection :: Spec+testGeometryCollection =+ describe "simple geometry collections" $ do+ it "Parse empty" $+ Wkt.parseString Wkt.geometryCollection "geometrycollection empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyGeometryCollection+ it "Parse something" $+ Wkt.parseString Wkt.geometryCollection "GeometryCollection(POINT (1 2),POINT (3 4),LINESTRING (15 15, 20 20, 25 25))" ^?! Trifecta._Success `shouldBe` exampleGeometryCollection+ it "Parse something with spaces" $+ Wkt.parseString Wkt.geometryCollection "GeometryCollection ( POINT ( 1 2) , POINT (3 4) , LINESTRING (15 15 , 20 20, 25 25 ) ) " ^?! Trifecta._Success `shouldBe` exampleGeometryCollection++exampleGeometryCollection :: Sequence.Seq Geospatial.GeospatialGeometry+exampleGeometryCollection =+ Sequence.fromList+ [ Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point1+ , Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point2+ , Geospatial.Line $ Geospatial.GeoLine SpecHelper.lineString4+ ]
+ test/Data/Internal/Wkt/LineSpec.hs view
@@ -0,0 +1,86 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkt.LineSpec where++import Control.Lens ((^?), (^?!))+import qualified Data.Geospatial as Geospatial+import qualified Data.LineString as LineString+import qualified Data.Maybe as Maybe+import qualified Data.Sequence as Sequence+import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)+import qualified Text.Trifecta as Trifecta++import qualified Data.Wkt as Wkt++spec :: Spec+spec = do+ testLines+ testMultiLines++testLines :: Spec+testLines =+ describe "simple lines" $ do+ it "Parse incomplete" $+ Wkt.parseString Wkt.lineString "linestring" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse empty" $+ Wkt.parseString Wkt.lineString "linestring empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyLine+ it "Parse not points" $+ Wkt.parseString Wkt.lineString "linestring (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse something" $+ Wkt.parseString Wkt.lineString "linestring (1.0 2.0, 1.0 2.5, 1.0 3.0)" ^?! Trifecta._Success `shouldBe` exampleLine+ it "Parse spaces" $+ Wkt.parseString Wkt.lineString "linestring ( 1.0 2.0,1.0 2.5, 1.0 3.0)" ^?! Trifecta._Success `shouldBe` exampleLine+ it "Parse z lines" $+ Wkt.parseString Wkt.lineString "linestring z (1.0 2.0 3.0,1.0 2.5 4.0,1.0 3.0 5.0)" ^?! Trifecta._Success `shouldBe` example3DLine+ it "Parse z lines" $+ Wkt.parseString Wkt.lineString "linestring z(1.0 2.0 3.0,1.0 2.5 4.0,1.0 3.0 5.0)" ^?! Trifecta._Success `shouldBe` example3DLine+ it "Parse z lines" $+ Wkt.parseString Wkt.lineString "linestringz(1.0 2.0 3.0,1.0 2.5 4.0,1.0 3.0 5.0)" ^?! Trifecta._Success `shouldBe` example3DLine+ it "Parse zm lines" $+ Wkt.parseString Wkt.lineString "linestring zm (1.0 2.0 3.0 4.0,1.0 2.5 4.0 5.5, 1.0 3.0 5.0 7.0)" ^?! Trifecta._Success `shouldBe` example4DLine+++testMultiLines :: Spec+testMultiLines =+ describe "simple multilines" $ do+ it "Parse incomplete" $+ Wkt.parseString Wkt.multiLineString "multilinestring" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse empty" $+ Wkt.parseString Wkt.multiLineString "multilinestring empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiLine+ it "Parse not points" $+ Wkt.parseString Wkt.multiLineString "multilinestring (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse something" $+ Wkt.parseString Wkt.multiLineString "multilinestring ((1.0 2.0, 1.0 2.5, 1.0 3.0))" ^?! Trifecta._Success `shouldBe` exampleMultiLine+ it "Parse spaces" $+ Wkt.parseString Wkt.multiLineString "multilinestring ( ( 1.0 2.0,1.0 2.5, 1.0 3.0) )" ^?! Trifecta._Success `shouldBe` exampleMultiLine+ it "Parse z lines" $+ Wkt.parseString Wkt.multiLineString "multilinestring z ((1.0 2.0 3.0,1.0 2.5 4.0,1.0 3.0 5.0))" ^?! Trifecta._Success `shouldBe` example3DMultiLine+ it "Parse zm lines" $+ Wkt.parseString Wkt.multiLineString "multilinestring zm ((1.0 2.0 3.0 4.0,1.0 2.5 4.0 5.5, 1.0 3.0 5.0 7.0))" ^?! Trifecta._Success `shouldBe` example4DMultiLine++exampleLine :: Geospatial.GeoLine+exampleLine = Geospatial.GeoLine exampleLineString++example3DLine :: Geospatial.GeoLine+example3DLine = Geospatial.GeoLine exampleLine3DString++example4DLine :: Geospatial.GeoLine+example4DLine = Geospatial.GeoLine exampleLine4DString++exampleMultiLine :: Geospatial.GeoMultiLine+exampleMultiLine = Geospatial.GeoMultiLine (Sequence.singleton exampleLineString)++example3DMultiLine :: Geospatial.GeoMultiLine+example3DMultiLine = Geospatial.GeoMultiLine (Sequence.singleton exampleLine3DString)++example4DMultiLine :: Geospatial.GeoMultiLine+example4DMultiLine = Geospatial.GeoMultiLine (Sequence.singleton exampleLine4DString)++exampleLineString :: LineString.LineString Geospatial.GeoPositionWithoutCRS+exampleLineString = LineString.makeLineString (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.5)) (Sequence.singleton (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 3.0)))++exampleLine3DString :: LineString.LineString Geospatial.GeoPositionWithoutCRS+exampleLine3DString = LineString.makeLineString (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 1.0 2.0 3.0)) (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 1.0 2.5 4.0)) (Sequence.singleton (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 1.0 3.0 5.0)))++exampleLine4DString :: LineString.LineString Geospatial.GeoPositionWithoutCRS+exampleLine4DString = LineString.makeLineString (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 1.0 2.0 3.0 4.0)) (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 1.0 2.5 4.0 5.5)) (Sequence.singleton (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 1.0 3.0 5.0 7.0)))
+ test/Data/Internal/Wkt/PointSpec.hs view
@@ -0,0 +1,80 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkt.PointSpec where++import Control.Lens ((^?), (^?!))+import qualified Data.Geospatial as Geospatial+import qualified Data.Maybe as Maybe+import qualified Data.Sequence as Sequence+import Test.Hspec (Spec, describe, expectationFailure, it,+ shouldBe, shouldSatisfy)+import qualified Text.Trifecta as Trifecta++import qualified Data.Wkt as Wkt++spec :: Spec+spec = do+ testPoints+ testMultiPoints++testPoints :: Spec+testPoints =+ describe "simple points" $ do+ it "Parse incomplete" $+ Wkt.parseString Wkt.point "point" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse empty" $+ Wkt.parseString Wkt.point "point empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyPoint+ it "Parse not points" $+ Wkt.parseString Wkt.point "point (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse something" $ do+ --Wkt.parseString Wkt.point "point (1.0 2.0)" ^?! Trifecta._Success `shouldBe` examplePoint+ let x = Wkt.parseString Wkt.point "point (1.0 2.0)"+ case x of+ Trifecta.Success a -> a `shouldBe` examplePoint+ Trifecta.Failure f -> expectationFailure (show f)+ it "Parse spaces" $+ Wkt.parseString Wkt.point "point( 1.0 2.0 )" ^?! Trifecta._Success `shouldBe` examplePoint+ it "Parse z points" $+ Wkt.parseString Wkt.point "point z (1.0 2.0 3.0)" ^?! Trifecta._Success `shouldBe` example3DPoint+ it "Parse zm points" $+ Wkt.parseString Wkt.point "point zm (1.0 2.0 3.0 4.0)" ^?! Trifecta._Success `shouldBe` example4DPoint++testMultiPoints :: Spec+testMultiPoints =+ describe "simple multipoints" $ do+ it "Parse incomplete" $+ Wkt.parseString Wkt.multiPoint "multipoint" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse empty" $+ Wkt.parseString Wkt.multiPoint "multipoint empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiPoint+ it "Parse not points" $+ Wkt.parseString Wkt.multiPoint "multipoint (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)+ it "Parse unbracketed" $+ Wkt.parseString Wkt.multiPoint "multipoint (1.0 2.0, 2.0 2.0)" ^?! Trifecta._Success `shouldBe` exampleMultiPoint+ it "Parse unbracketed spaces" $+ Wkt.parseString Wkt.multiPoint "multipoint( 1.0 2.0,2.0 2.0 )" ^?! Trifecta._Success `shouldBe` exampleMultiPoint+ it "Parse bracketed" $+ Wkt.parseString Wkt.multiPoint "multipoint ((1.0 2.0), (2.0 2.0))" ^?! Trifecta._Success `shouldBe` exampleMultiPoint+ it "Parse bracketed spaces" $+ Wkt.parseString Wkt.multiPoint "multipoint( ( 1.0 2.0) ,( 2.0 2.0) )" ^?! Trifecta._Success `shouldBe` exampleMultiPoint+ it "Parse z points" $+ Wkt.parseString Wkt.multiPoint "multipoint z ((1.0 2.0 3.0),(2.0 2.0 2.0))" ^?! Trifecta._Success `shouldBe` exampleMulti3DPoint+ it "Parse zm points" $+ Wkt.parseString Wkt.multiPoint "multipoint zm ((1.0 2.0 3.0 4.0),(2.0 2.0 2.0 2.0))" ^?! Trifecta._Success `shouldBe` exampleMulti4DPoint++examplePoint :: Geospatial.GeoPoint+examplePoint = Geospatial.GeoPoint (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0))++example3DPoint :: Geospatial.GeoPoint+example3DPoint = Geospatial.GeoPoint (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 1.0 2.0 3.0))++example4DPoint :: Geospatial.GeoPoint+example4DPoint = Geospatial.GeoPoint (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 1.0 2.0 3.0 4.0))++exampleMultiPoint :: Geospatial.GeoMultiPoint+exampleMultiPoint = Geospatial.GeoMultiPoint (Sequence.fromList [Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0), Geospatial.GeoPointXY (Geospatial.PointXY 2.0 2.0)])++exampleMulti3DPoint :: Geospatial.GeoMultiPoint+exampleMulti3DPoint = Geospatial.GeoMultiPoint (Sequence.fromList [Geospatial.GeoPointXYZ (Geospatial.PointXYZ 1.0 2.0 3.0), Geospatial.GeoPointXYZ (Geospatial.PointXYZ 2.0 2.0 2.0)])++exampleMulti4DPoint :: Geospatial.GeoMultiPoint+exampleMulti4DPoint = Geospatial.GeoMultiPoint (Sequence.fromList [Geospatial.GeoPointXYZM (Geospatial.PointXYZM 1.0 2.0 3.0 4.0), Geospatial.GeoPointXYZM (Geospatial.PointXYZM 2.0 2.0 2.0 2.0)])
+ test/Data/Internal/Wkt/PolygonSpec.hs view
@@ -0,0 +1,92 @@+{-# LANGUAGE OverloadedStrings #-}++module Data.Internal.Wkt.PolygonSpec where++import Control.Lens ((^?!))+import qualified Data.Geospatial as Geospatial+import qualified Data.LinearRing as LinearRing+import qualified Data.Sequence as Sequence+import Test.Hspec (Spec, describe, it, shouldBe)+import qualified Text.Trifecta as Trifecta++import qualified Data.Wkt as Wkt++spec :: Spec+spec = do+ testPolygons+ testMultiPolygons++testPolygons :: Spec+testPolygons =+ describe "simple polygons" $ do+ it "Parse empty" $+ Wkt.parseString Wkt.polygon "polygon empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyPolygon+ it "Parse something" $+ Wkt.parseString Wkt.polygon "polygon ((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygon+ it "Parse spaces" $+ Wkt.parseString Wkt.polygon "polygon ( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygon+ it "Parse something with hole" $+ Wkt.parseString Wkt.polygon "polygon ((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0),(2.0 0.0, 0.0 2.0, -2.0 0.0, 0.0 -2.0, 2.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygonWithHole+ it "Parse something with hole spaces" $+ Wkt.parseString Wkt.polygon "polygon ( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0),( 2.0 0.0, 0.0 2.0 , -2.0 0.0, 0.0 -2.0, 2.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygonWithHole+ it "Parse something with z" $+ Wkt.parseString Wkt.polygon "polygon z ((4.0 0.0 1.0, 0.0 4.0 1.0, -4.0 0.0 1.0, 0.0 -4.0 1.0, 4.0 0.0 1.0))" ^?! Trifecta._Success `shouldBe` examplePolygon3D+ it "Parse something with zm" $+ Wkt.parseString Wkt.polygon "polygon zm ((4.0 0.0 1.0 0.5, 0.0 4.0 1.0 0.5, -4.0 0.0 1.0 0.5, 0.0 -4.0 1.0 0.5, 4.0 0.0 1.0 0.5))" ^?! Trifecta._Success `shouldBe` examplePolygon4D+++testMultiPolygons :: Spec+testMultiPolygons =+ describe "simple multipolygons" $ do+ it "Parse empty" $+ Wkt.parseString Wkt.multiPolygon "multipolygon empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiPolygon+ it "Parse something" $+ Wkt.parseString Wkt.multiPolygon "multipolygon (((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygon+ it "Parse something with hole" $+ Wkt.parseString Wkt.multiPolygon "multipolygon (( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0),( 2.0 0.0, 0.0 2.0 , -2.0 0.0, 0.0 -2.0, 2.0 0.0)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygonWithHole+ it "Parse something with z" $+ Wkt.parseString Wkt.multiPolygon "multipolygon z (((4.0 0.0 1.0, 0.0 4.0 1.0, -4.0 0.0 1.0, 0.0 -4.0 1.0, 4.0 0.0 1.0)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygon3D+ it "Parse something with zm" $+ Wkt.parseString Wkt.multiPolygon "multipolygon zm (((4.0 0.0 1.0 0.5, 0.0 4.0 1.0 0.5, -4.0 0.0 1.0 0.5, 0.0 -4.0 1.0 0.5, 4.0 0.0 1.0 0.5)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygon4D++examplePolygon :: Geospatial.GeoPolygon+examplePolygon =+ Geospatial.GeoPolygon (Sequence.singleton linearRingSingle)++examplePolygon3D :: Geospatial.GeoPolygon+examplePolygon3D =+ Geospatial.GeoPolygon (Sequence.singleton linearRingSingle3D)++examplePolygon4D :: Geospatial.GeoPolygon+examplePolygon4D =+ Geospatial.GeoPolygon (Sequence.singleton linearRingSingle4D)++examplePolygonWithHole :: Geospatial.GeoPolygon+examplePolygonWithHole = Geospatial.GeoPolygon linearRingDouble++linearRingSingle :: LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS+linearRingSingle = LinearRing.makeLinearRing (Geospatial.GeoPointXY (Geospatial.PointXY 4.0 0.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 0.0 4.0)) (Geospatial.GeoPointXY (Geospatial.PointXY (-4.0) 0.0)) (Sequence.fromList [Geospatial.GeoPointXY (Geospatial.PointXY 0.0 (-4.0))])++linearRingSingle3D :: LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS+linearRingSingle3D = LinearRing.makeLinearRing (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 4.0 0.0 1.0)) (Geospatial.GeoPointXYZ (Geospatial.PointXYZ 0.0 4.0 1.0)) (Geospatial.GeoPointXYZ (Geospatial.PointXYZ (-4.0) 0.0 1.0)) (Sequence.fromList [Geospatial.GeoPointXYZ (Geospatial.PointXYZ 0.0 (-4.0) 1.0)])++linearRingSingle4D :: LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS+linearRingSingle4D = LinearRing.makeLinearRing (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 4.0 0.0 1.0 0.5)) (Geospatial.GeoPointXYZM (Geospatial.PointXYZM 0.0 4.0 1.0 0.5)) (Geospatial.GeoPointXYZM (Geospatial.PointXYZM (-4.0) 0.0 1.0 0.5)) (Sequence.fromList [Geospatial.GeoPointXYZM (Geospatial.PointXYZM 0.0 (-4.0) 1.0 0.5)])++linearRingDouble :: Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)+linearRingDouble = Sequence.fromList+ [ linearRingSingle+ , LinearRing.makeLinearRing (Geospatial.GeoPointXY (Geospatial.PointXY 2.0 0.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 0.0 2.0)) (Geospatial.GeoPointXY (Geospatial.PointXY (-2.0) 0.0)) (Sequence.fromList [ Geospatial.GeoPointXY (Geospatial.PointXY 0.0 (-2.0))])+ ]++exampleMultiPolygon :: Geospatial.GeoMultiPolygon+exampleMultiPolygon = Geospatial.GeoMultiPolygon (Sequence.singleton (Sequence.singleton linearRingSingle))++exampleMultiPolygon3D :: Geospatial.GeoMultiPolygon+exampleMultiPolygon3D = Geospatial.GeoMultiPolygon (Sequence.singleton (Sequence.singleton linearRingSingle3D))++exampleMultiPolygon4D :: Geospatial.GeoMultiPolygon+exampleMultiPolygon4D = Geospatial.GeoMultiPolygon (Sequence.singleton (Sequence.singleton linearRingSingle4D))++exampleMultiPolygonWithHole :: Geospatial.GeoMultiPolygon+exampleMultiPolygonWithHole = Geospatial.GeoMultiPolygon (Sequence.singleton linearRingDouble)
test/Data/SpecHelper.hs view
@@ -1,9 +1,144 @@ module Data.SpecHelper where -import qualified Data.Geospatial as Geospatial-import qualified Data.LinearRing as LinearRing-import qualified Data.LineString as LineString-import qualified Data.Sequence as Sequence+import qualified Data.Geospatial as Geospatial+import qualified Data.LinearRing as LinearRing+import qualified Data.LineString as LineString+import qualified Data.Sequence as Sequence+import qualified HaskellWorks.Hspec.Hedgehog as HedgehogHspec+import Hedgehog+import qualified Hedgehog.Gen as Gen+import qualified Hedgehog.Range as Range+import Test.Hspec (Spec, it)++import qualified Data.Internal.Wkb.Endian as Endian+import qualified Data.Internal.Wkb.Geometry as Geometry+import qualified Data.Wkb as Wkb++-- Helpers++type GeometryGenerator = Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry++roundTripWkb :: Endian.EndianType -> Geospatial.GeospatialGeometry -> Either String Geospatial.GeospatialGeometry+roundTripWkb endianType = Wkb.parseByteString . Wkb.toByteString endianType++testRoundTripWkbGeometryParsing :: String -> GeometryGenerator -> Spec+testRoundTripWkbGeometryParsing name generator =+ mapM_ (testRoundTripWkbGeometryParsing' name generator) coordPointGenerators++testRoundTripWkbGeometryParsing' :: String -> GeometryGenerator -> (Geometry.CoordinateType, Gen Geospatial.GeoPositionWithoutCRS) -> Spec+testRoundTripWkbGeometryParsing' name generator (coordType, genCoordPoint) =+ it ("round trips wkb " ++ name ++ ": " ++ show coordType) $+ HedgehogHspec.require $ property $ do+ geometry <- forAll $ generator genCoordPoint+ endianType <- forAll genEndianType+ roundTripWkb endianType geometry === Right geometry+++-- Generators++upperBoundOfMultiGeometries :: Int+upperBoundOfMultiGeometries = 10++upperBoundOfPoints :: Int+upperBoundOfPoints = 100++coordPointGenerators :: [(Geometry.CoordinateType, Gen Geospatial.GeoPositionWithoutCRS)]+coordPointGenerators =+ [ (Geometry.TwoD, genCoordPointXY)+ , (Geometry.Z, genCoordPointXYZ)+-- We can't roundtrip or express M in the current geometry (hs-geojson)+-- , (Geometry.M, genCoordPointXYZ)+ , (Geometry.ZM, genCoordPointXYZM)+ ]++genGeometryCollection :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genGeometryCollection genCoordPoint = do+ geoCollection <- Gen.seq (Range.linear 0 upperBoundOfMultiGeometries) (genGeospatialGeometry genCoordPoint)+ return $ Geospatial.Collection geoCollection++genGeospatialGeometry :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genGeospatialGeometry genCoordPoint = Gen.recursive Gen.choice+ [ genPoint genCoordPoint+ , genLine genCoordPoint+ , genPolygon genCoordPoint+ , genMultiPoint genCoordPoint+ , genMultiLine genCoordPoint+ , genMultiPolygon genCoordPoint+ ]+ [ genGeometryCollection genCoordPoint ]++genMultiPolygon :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genMultiPolygon genCoordPoint = do+ geoMultiPolygon <- Geospatial.GeoMultiPolygon <$> Gen.seq (Range.linear 0 upperBoundOfMultiGeometries) (genLinearRings genCoordPoint)+ return $ Geospatial.MultiPolygon geoMultiPolygon++genPolygon :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genPolygon genCoordPoint = do+ geoPolygon <- Geospatial.GeoPolygon <$> genLinearRings genCoordPoint+ return $ Geospatial.Polygon geoPolygon++genMultiLine :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genMultiLine genCoordPoint = do+ geoMultiLine <- Geospatial.GeoMultiLine <$> Gen.seq (Range.linear 0 upperBoundOfMultiGeometries) (genLineString genCoordPoint)+ return $ Geospatial.MultiLine geoMultiLine++genLine :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genLine genCoordPoint = do+ geoLine <- Geospatial.GeoLine <$> genLineString genCoordPoint+ return $ Geospatial.Line geoLine++genMultiPoint :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genMultiPoint genCoordPoint = do+ geoMultiPoint <- Geospatial.GeoMultiPoint <$> genCoordPoints genCoordPoint+ return $ Geospatial.MultiPoint geoMultiPoint++genPoint :: Gen Geospatial.GeoPositionWithoutCRS -> Gen Geospatial.GeospatialGeometry+genPoint genCoordPoint = do+ geoPoint <- Geospatial.GeoPoint <$> genCoordPoint+ return $ Geospatial.Point geoPoint++genLinearRings :: Gen Geospatial.GeoPositionWithoutCRS -> Gen (Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS))+genLinearRings genCoordPoint =+ Gen.seq (Range.linear 0 upperBoundOfMultiGeometries) (genLinearRing genCoordPoint)++genLinearRing :: Gen Geospatial.GeoPositionWithoutCRS -> Gen (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)+genLinearRing genCoordPoint =+ LinearRing.makeLinearRing <$> genCoordPoint <*> genCoordPoint <*> genCoordPoint <*> genCoordPoints genCoordPoint++genLineString :: Gen Geospatial.GeoPositionWithoutCRS -> Gen (LineString.LineString Geospatial.GeoPositionWithoutCRS)+genLineString genCoordPoint =+ LineString.makeLineString <$> genCoordPoint <*> genCoordPoint <*> genCoordPoints genCoordPoint++genCoordPoints :: Gen Geospatial.GeoPositionWithoutCRS -> Gen (Sequence.Seq Geospatial.GeoPositionWithoutCRS)+genCoordPoints =+ Gen.seq (Range.linear 0 upperBoundOfPoints)++genCoordPointXY :: Gen Geospatial.GeoPositionWithoutCRS+genCoordPointXY = do+ point <- Geospatial.PointXY <$> genDouble <*> genDouble+ return $ Geospatial.GeoPointXY point++genCoordPointXYZ :: Gen Geospatial.GeoPositionWithoutCRS+genCoordPointXYZ = do+ point <- Geospatial.PointXYZ <$> genDouble <*> genDouble <*> genDouble+ return $ Geospatial.GeoPointXYZ point++genCoordPointXYZM :: Gen Geospatial.GeoPositionWithoutCRS+genCoordPointXYZM = do+ point <- Geospatial.PointXYZM <$> genDouble <*> genDouble <*> genDouble <*> genDouble+ return $ Geospatial.GeoPointXYZM point++genDouble :: Gen Double+genDouble = Gen.double $ Range.linearFrac (-10e6) 10e6++genEndianType :: Gen Endian.EndianType+genEndianType = Gen.choice+ [ Gen.constant Endian.BigEndian+ , Gen.constant Endian.LittleEndian+ ]+++-- Example point1 :: Geospatial.GeoPositionWithoutCRS point1 = Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0)
− test/Data/WkbGeometryCollectionSpec.hs
@@ -1,54 +0,0 @@--{-# LANGUAGE OverloadedStrings #-}--module Data.WkbGeometryCollectionSpec where--import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified Data.Geospatial as Geospatial-import Data.Monoid ((<>))-import qualified Data.Sequence as Sequence-import qualified Data.Wkb as Wkb-import Test.Hspec (Spec, describe, it, shouldBe)--import qualified Data.SpecHelper as SpecHelper--spec :: Spec-spec =- testWkbGeometryCollectionParsing--testWkbGeometryCollectionParsing :: Spec-testWkbGeometryCollectionParsing =- describe "Test wkb geometry collection" $- it "Parse valid wkb geometry collection" $- Wkb.parseByteString exampleWkbGeometryCollection `shouldBe` (Right . Geospatial.Collection $- Sequence.fromList- [ Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point1- , Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point2- , Geospatial.Line $ Geospatial.GeoLine SpecHelper.lineString3- ]- )--exampleWkbGeometryCollection :: LazyByteString.ByteString-exampleWkbGeometryCollection =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 7- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.doubleBE 1- <> ByteStringBuilder.doubleBE 2- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.doubleBE 3- <> ByteStringBuilder.doubleBE 4- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.doubleBE 15- <> ByteStringBuilder.doubleBE 15- <> ByteStringBuilder.doubleBE 20- <> ByteStringBuilder.doubleBE 20- <> ByteStringBuilder.doubleBE 20- <> ByteStringBuilder.doubleBE 20
− test/Data/WkbLineSpec.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WkbLineSpec where--import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified Data.Geospatial as Geospatial-import Data.Monoid ((<>))-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe)--import qualified Data.Wkb as Wkb--import qualified Data.SpecHelper as SpecHelper--spec :: Spec-spec = do- testWkbLineParsing- testWkbMultiLineParsing--testWkbLineParsing :: Spec-testWkbLineParsing =- describe "Test wkb line" $- it "Parse valid wkb line" $- Wkb.parseByteString exampleWkbLine `shouldBe` (Right $ Geospatial.Line $ Geospatial.GeoLine SpecHelper.lineString1)--exampleWkbLine :: LazyByteString.ByteString-exampleWkbLine =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0--testWkbMultiLineParsing :: Spec-testWkbMultiLineParsing =- describe "Test wkb multi line" $- it "Parse valid wkb multi line" $- Wkb.parseByteString exampleWkbMultiLine `shouldBe` (Right $ Geospatial.MultiLine $ Geospatial.GeoMultiLine (Sequence.fromList [SpecHelper.lineString1, SpecHelper.lineString2]))--exampleWkbMultiLine :: LazyByteString.ByteString-exampleWkbMultiLine =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 5- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.doubleBE 1.5- <> ByteStringBuilder.doubleBE 2.5- <> ByteStringBuilder.doubleBE 3.5- <> ByteStringBuilder.doubleBE 4.5
− test/Data/WkbPointSpec.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WkbPointSpec where--import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified Data.Geospatial as Geospatial-import Data.Monoid ((<>))-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe)--import qualified Data.Wkb as Wkb--import qualified Data.SpecHelper as SpecHelper--spec :: Spec-spec = do- testWkbPointParsing- testWkbMultiPointParsing--testWkbPointParsing :: Spec-testWkbPointParsing =- describe "Test wkb point" $- it "Parse valid wkb point" $- Wkb.parseByteString exampleWkbPoint `shouldBe` (Right . Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point1)--exampleWkbPoint :: LazyByteString.ByteString-exampleWkbPoint =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0--testWkbMultiPointParsing :: Spec-testWkbMultiPointParsing =- describe "Test wkb multi point" $- it "Parse valid wkb multi point" $- Wkb.parseByteString exampleWkbMultiPoint `shouldBe` (Right $ Geospatial.MultiPoint (Geospatial.GeoMultiPoint (Sequence.fromList [SpecHelper.point1, SpecHelper.point2])))--exampleWkbMultiPoint :: LazyByteString.ByteString-exampleWkbMultiPoint =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 4- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0-
− test/Data/WkbPolygonSpec.hs
@@ -1,100 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WkbPolygonSpec where--import qualified Data.ByteString.Builder as ByteStringBuilder-import qualified Data.ByteString.Lazy as LazyByteString-import qualified Data.Geospatial as Geospatial-import Data.Monoid ((<>))-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe)--import qualified Data.Wkb as Wkb--import qualified Data.SpecHelper as SpecHelper--spec :: Spec-spec = do- testWkbPolygonParsing- testWkbMultiPolygonParsing--testWkbPolygonParsing :: Spec-testWkbPolygonParsing =- describe "Test wkb polygon" $ do- it "Parse valid wkb polygon" $- Wkb.parseByteString exampleWkbPolygon `shouldBe` (Right $ Geospatial.Polygon $ Geospatial.GeoPolygon (Sequence.singleton SpecHelper.linearRing1))- it "Not parse bad wkb polygon" $- Wkb.parseByteString exampleBadWkbPolygon `shouldBe` Left "Could not parse wkb: First and last points of linear ring are different: first=GeoPointXY (PointXY {_xyX = 1.0, _xyY = 2.0}) last=GeoPointXY (PointXY {_xyX = 7.0, _xyY = 8.0})"--exampleWkbPolygon :: LazyByteString.ByteString-exampleWkbPolygon =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.int32BE 4- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0- <> ByteStringBuilder.doubleBE 5.0- <> ByteStringBuilder.doubleBE 6.0- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0--exampleBadWkbPolygon :: LazyByteString.ByteString-exampleBadWkbPolygon =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.int32BE 4- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0- <> ByteStringBuilder.doubleBE 5.0- <> ByteStringBuilder.doubleBE 6.0- <> ByteStringBuilder.doubleBE 7.0- <> ByteStringBuilder.doubleBE 8.0--testWkbMultiPolygonParsing :: Spec-testWkbMultiPolygonParsing =- describe "Test wkb multi polygon" $- it "Parse valid wkb multi polygon" $- Wkb.parseByteString exampleWkbMultiPolygon `shouldBe` (Right $ Geospatial.MultiPolygon $ Geospatial.GeoMultiPolygon- (Sequence.fromList- [ Sequence.singleton SpecHelper.linearRing1- , Sequence.singleton SpecHelper.linearRing2- ]))--exampleWkbMultiPolygon :: LazyByteString.ByteString-exampleWkbMultiPolygon =- ByteStringBuilder.toLazyByteString $- ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 6- <> ByteStringBuilder.int32BE 2- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.int32BE 4- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.doubleBE 3.0- <> ByteStringBuilder.doubleBE 4.0- <> ByteStringBuilder.doubleBE 5.0- <> ByteStringBuilder.doubleBE 6.0- <> ByteStringBuilder.doubleBE 1.0- <> ByteStringBuilder.doubleBE 2.0- <> ByteStringBuilder.word8 0- <> ByteStringBuilder.int32BE 3- <> ByteStringBuilder.int32BE 1- <> ByteStringBuilder.int32BE 4- <> ByteStringBuilder.doubleBE 1.5- <> ByteStringBuilder.doubleBE 2.5- <> ByteStringBuilder.doubleBE 3.5- <> ByteStringBuilder.doubleBE 4.5- <> ByteStringBuilder.doubleBE 5.5- <> ByteStringBuilder.doubleBE 6.5- <> ByteStringBuilder.doubleBE 1.5- <> ByteStringBuilder.doubleBE 2.5
− test/Data/WktGeometryCollectionSpec.hs
@@ -1,34 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WktGeometryCollectionSpec where--import Control.Lens ((^?!))-import qualified Data.Geospatial as Geospatial-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe)-import qualified Text.Trifecta as Trifecta--import qualified Data.Wkt as Wkt--import qualified Data.SpecHelper as SpecHelper--spec :: Spec-spec = testGeometryCollection--testGeometryCollection :: Spec-testGeometryCollection =- describe "simple geometry collections" $ do- it "Parse empty" $- Wkt.parseString Wkt.geometryCollection "geometrycollection empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyGeometryCollection- it "Parse something" $- Wkt.parseString Wkt.geometryCollection "GeometryCollection(POINT (1 2),POINT (3 4),LINESTRING (15 15, 20 20, 25 25))" ^?! Trifecta._Success `shouldBe` exampleGeometryCollection- it "Parse something with spaces" $- Wkt.parseString Wkt.geometryCollection "GeometryCollection ( POINT ( 1 2) , POINT (3 4) , LINESTRING (15 15 , 20 20, 25 25 ) ) " ^?! Trifecta._Success `shouldBe` exampleGeometryCollection--exampleGeometryCollection :: Sequence.Seq Geospatial.GeospatialGeometry-exampleGeometryCollection =- Sequence.fromList- [ Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point1- , Geospatial.Point $ Geospatial.GeoPoint SpecHelper.point2- , Geospatial.Line $ Geospatial.GeoLine SpecHelper.lineString4- ]
− test/Data/WktLineSpec.hs
@@ -1,55 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WktLineSpec where--import Control.Lens ((^?), (^?!))-import qualified Data.Geospatial as Geospatial-import qualified Data.LineString as LineString-import qualified Data.Maybe as Maybe-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe, shouldSatisfy)-import qualified Text.Trifecta as Trifecta--import qualified Data.Wkt as Wkt--spec :: Spec-spec = do- testLines- testMultiLines--testLines :: Spec-testLines =- describe "simple lines" $ do- it "Parse incomplete" $- Wkt.parseString Wkt.lineString "linestring" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse empty" $- Wkt.parseString Wkt.lineString "linestring empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyLine- it "Parse not points" $- Wkt.parseString Wkt.lineString "linestring (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse something" $- Wkt.parseString Wkt.lineString "linestring (1.0 2.0, 1.0 2.5, 1.0 3.0)" ^?! Trifecta._Success `shouldBe` exampleLine- it "Parse spaces" $- Wkt.parseString Wkt.lineString "linestring ( 1.0 2.0,1.0 2.5, 1.0 3.0)" ^?! Trifecta._Success `shouldBe` exampleLine--testMultiLines :: Spec-testMultiLines =- describe "simple multilines" $ do- it "Parse incomplete" $- Wkt.parseString Wkt.multiLineString "multilinestring" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse empty" $- Wkt.parseString Wkt.multiLineString "multilinestring empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiLine- it "Parse not points" $- Wkt.parseString Wkt.multiLineString "multilinestring (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse something" $- Wkt.parseString Wkt.multiLineString "multilinestring ((1.0 2.0, 1.0 2.5, 1.0 3.0))" ^?! Trifecta._Success `shouldBe` exampleMultiLine- it "Parse spaces" $- Wkt.parseString Wkt.multiLineString "multilinestring ( ( 1.0 2.0,1.0 2.5, 1.0 3.0) )" ^?! Trifecta._Success `shouldBe` exampleMultiLine--exampleLine :: Geospatial.GeoLine-exampleLine = Geospatial.GeoLine exampleLineString--exampleMultiLine :: Geospatial.GeoMultiLine-exampleMultiLine = Geospatial.GeoMultiLine (Sequence.singleton exampleLineString)--exampleLineString :: LineString.LineString Geospatial.GeoPositionWithoutCRS-exampleLineString = LineString.makeLineString (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.5)) (Sequence.singleton (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 3.0)))
− test/Data/WktPointSpec.hs
@@ -1,60 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WktPointSpec where--import Control.Lens ((^?), (^?!))-import qualified Data.Geospatial as Geospatial-import qualified Data.Maybe as Maybe-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, expectationFailure, it,- shouldBe, shouldSatisfy)-import qualified Text.Trifecta as Trifecta--import qualified Data.Wkt as Wkt--spec :: Spec-spec = do- testPoints- testMultiPoints--testPoints :: Spec-testPoints =- describe "simple points" $ do- it "Parse incomplete" $- Wkt.parseString Wkt.point "point" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse empty" $- Wkt.parseString Wkt.point "point empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyPoint- it "Parse not points" $- Wkt.parseString Wkt.point "point (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse something" $ do- --Wkt.parseString Wkt.point "point (1.0 2.0)" ^?! Trifecta._Success `shouldBe` examplePoint- let x = Wkt.parseString Wkt.point "point (1.0 2.0)"- case x of- Trifecta.Success a -> a `shouldBe` examplePoint- Trifecta.Failure f -> expectationFailure (show f)- it "Parse spaces" $- Wkt.parseString Wkt.point "point( 1.0 2.0 )" ^?! Trifecta._Success `shouldBe` examplePoint--testMultiPoints :: Spec-testMultiPoints =- describe "simple multipoints" $ do- it "Parse incomplete" $- Wkt.parseString Wkt.multiPoint "multipoint" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse empty" $- Wkt.parseString Wkt.multiPoint "multipoint empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiPoint- it "Parse not points" $- Wkt.parseString Wkt.multiPoint "multipoint (abc)" `shouldSatisfy` (Maybe.isJust . flip (^?) Trifecta._Failure)- it "Parse unbracketed" $- Wkt.parseString Wkt.multiPoint "multipoint (1.0 2.0, 2.0 2.0)" ^?! Trifecta._Success `shouldBe` exampleMultiPoint- it "Parse unbracketed spaces" $- Wkt.parseString Wkt.multiPoint "multipoint( 1.0 2.0,2.0 2.0 )" ^?! Trifecta._Success `shouldBe` exampleMultiPoint- it "Parse bracketed" $- Wkt.parseString Wkt.multiPoint "multipoint ((1.0 2.0), (2.0 2.0))" ^?! Trifecta._Success `shouldBe` exampleMultiPoint- it "Parse bracketed spaces" $- Wkt.parseString Wkt.multiPoint "multipoint( ( 1.0 2.0) ,( 2.0 2.0) )" ^?! Trifecta._Success `shouldBe` exampleMultiPoint--examplePoint :: Geospatial.GeoPoint-examplePoint = Geospatial.GeoPoint (Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0))--exampleMultiPoint :: Geospatial.GeoMultiPoint-exampleMultiPoint = Geospatial.GeoMultiPoint (Sequence.fromList [Geospatial.GeoPointXY (Geospatial.PointXY 1.0 2.0), Geospatial.GeoPointXY (Geospatial.PointXY 2.0 2.0)])
− test/Data/WktPolygonSpec.hs
@@ -1,63 +0,0 @@-{-# LANGUAGE OverloadedStrings #-}--module Data.WktPolygonSpec where--import Control.Lens ((^?!))-import qualified Data.Geospatial as Geospatial-import qualified Data.LinearRing as LinearRing-import qualified Data.Sequence as Sequence-import Test.Hspec (Spec, describe, it, shouldBe)-import qualified Text.Trifecta as Trifecta--import qualified Data.Wkt as Wkt--spec :: Spec-spec = do- testPolygons- testMultiPolygons--testPolygons :: Spec-testPolygons =- describe "simple polygons" $ do- it "Parse empty" $- Wkt.parseString Wkt.polygon "polygon empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyPolygon- it "Parse something" $- Wkt.parseString Wkt.polygon "polygon ((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygon- it "Parse spaces" $- Wkt.parseString Wkt.polygon "polygon ( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygon- it "Parse something with hole" $- Wkt.parseString Wkt.polygon "polygon ((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0),(2.0 0.0, 0.0 2.0, -2.0 0.0, 0.0 -2.0, 2.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygonWithHole- it "Parse something with hole spaces" $- Wkt.parseString Wkt.polygon "polygon ( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0),( 2.0 0.0, 0.0 2.0 , -2.0 0.0, 0.0 -2.0, 2.0 0.0))" ^?! Trifecta._Success `shouldBe` examplePolygonWithHole--testMultiPolygons :: Spec-testMultiPolygons =- describe "simple multipolygons" $ do- it "Parse empty" $- Wkt.parseString Wkt.multiPolygon "multipolygon empty" ^?! Trifecta._Success `shouldBe` Wkt.emptyMultiPolygon- it "Parse something" $- Wkt.parseString Wkt.multiPolygon "multipolygon (((4.0 0.0, 0.0 4.0, -4.0 0.0, 0.0 -4.0, 4.0 0.0)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygon- it "Parse something with hole" $- Wkt.parseString Wkt.multiPolygon "multipolygon (( (4.0 0.0, 0.0 4.0, -4.0 0.0 , 0.0 -4.0 , 4.0 0.0),( 2.0 0.0, 0.0 2.0 , -2.0 0.0, 0.0 -2.0, 2.0 0.0)))" ^?! Trifecta._Success `shouldBe` exampleMultiPolygonWithHole--examplePolygon :: Geospatial.GeoPolygon-examplePolygon =- Geospatial.GeoPolygon (Sequence.singleton linearRingSingle)--examplePolygonWithHole :: Geospatial.GeoPolygon-examplePolygonWithHole = Geospatial.GeoPolygon linearRingDouble--linearRingSingle :: LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS-linearRingSingle = LinearRing.makeLinearRing (Geospatial.GeoPointXY (Geospatial.PointXY 4.0 0.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 0.0 4.0)) (Geospatial.GeoPointXY (Geospatial.PointXY (-4.0) 0.0)) (Sequence.fromList [Geospatial.GeoPointXY (Geospatial.PointXY 0.0 (-4.0))])--linearRingDouble :: Sequence.Seq (LinearRing.LinearRing Geospatial.GeoPositionWithoutCRS)-linearRingDouble = Sequence.fromList- [ linearRingSingle- , LinearRing.makeLinearRing (Geospatial.GeoPointXY (Geospatial.PointXY 2.0 0.0)) (Geospatial.GeoPointXY (Geospatial.PointXY 0.0 2.0)) (Geospatial.GeoPointXY (Geospatial.PointXY (-2.0) 0.0)) (Sequence.fromList [ Geospatial.GeoPointXY (Geospatial.PointXY 0.0 (-2.0))])- ]--exampleMultiPolygon :: Geospatial.GeoMultiPolygon-exampleMultiPolygon = Geospatial.GeoMultiPolygon (Sequence.singleton (Sequence.singleton linearRingSingle))--exampleMultiPolygonWithHole :: Geospatial.GeoMultiPolygon-exampleMultiPolygonWithHole = Geospatial.GeoMultiPolygon (Sequence.singleton linearRingDouble)
wkt-geom.cabal view
@@ -1,24 +1,26 @@-name: wkt-geom-version: 0.0.4-synopsis: A parser of WKT, WKB and eWKB.-description: Well Known Text (WKT), Well Known Binary and the Postgresql extension Extended Well Know Binary (eWKB) are vector geometry representations.+name: wkt-geom+version: 0.0.5+synopsis: A parser of WKT, WKB and eWKB.+description: Well Known Text (WKT), Well Known Binary (WKB) and the PostgreSQL extension Extended Well Know Binary (eWKB) are vector geometry representations. .- The text or binary representations are parsed and turned into their GeoJSON representations. The binary representations use vectors throughout- whereas the text representation still uses a list and then is converted to a vector representation.-homepage: https://github.com/indicatrix/wkt-geom#readme-license: Apache-2.0-license-file: LICENSE-author: Andrew Newmnan, Dominic Endrei-maintainer: andrewfnewman@gmail.com-copyright: 2017-2018 Wkt-Geom Project-category: Data-build-type: Simple-extra-source-files: README.md-cabal-version: >=1.10+ The text or binary representations are parsed and turned into their GeoJSON representations. The binary representations use vectors throughout+ whereas the text representation still uses a list and then is converted to a vector representation.+homepage: https://github.com/indicatrix/wkt-geom#readme+license: Apache-2.0+license-file: LICENSE+author: Andrew Newmnan, Dominic Endrei+maintainer: andrewfnewman@gmail.com+copyright: 2017-2019 Wkt-Geom Project+category: Data+build-type: Simple+extra-source-files: README.md+ , CHANGELOG.md+cabal-version: >=1.10 library hs-source-dirs: src exposed-modules: Data.Ewkb+ , Data.Hex , Data.Wkb , Data.Wkt , Data.Internal.Ewkb.Geometry @@ -36,15 +38,16 @@ , Data.Internal.Wkt.GeometryCollection - build-depends: base < 5 && >= 4.8 - , binary >= 0.8- , bytestring >= 0.10- , containers >= 0.5.10.1- , geojson >= 3.0.3- , scientific >= 0.3.6- , trifecta >= 1.7- , utf8-string >= 1- , vector >= 0.10+ build-depends: base < 5 && >= 4.8 + , base16-bytestring >= 0.1.1.6+ , binary >= 0.8+ , bytestring >= 0.10+ , containers >= 0.5.10.1+ , geojson >= 3.0.3+ , scientific >= 0.3.6+ , trifecta >= 1.7+ , utf8-string >= 1+ , vector >= 0.10 ghc-options: -Wall default-language: Haskell2010@@ -54,32 +57,46 @@ hs-source-dirs: test other-modules: Data.Internal.Ewkb.GeometrySpec , Data.Internal.Wkb.EndianSpec+ , Data.Internal.Wkb.GeometryCollectionSpec , Data.Internal.Wkb.GeometrySpec- , Data.WkbGeometryCollectionSpec- , Data.WkbLineSpec- , Data.WkbPointSpec- , Data.WkbPolygonSpec- , Data.WktGeometryCollectionSpec- , Data.WktLineSpec- , Data.WktPointSpec- , Data.WktPolygonSpec + , Data.Internal.Wkb.HexParsingSpec+ , Data.Internal.Wkb.LineSpec+ , Data.Internal.Wkb.PointSpec+ , Data.Internal.Wkb.PolygonSpec+ , Data.Internal.Wkt.GeometryCollectionSpec+ , Data.Internal.Wkt.LineSpec+ , Data.Internal.Wkt.PointSpec+ , Data.Internal.Wkt.PolygonSpec , Data.SpecHelper main-is: Spec.hs build-depends: base- , binary >= 0.8- , ansi-wl-pprint >= 0.6- , bytestring >= 0.10- , containers >= 0.5.10.1- , geojson >= 3.0.3+ , base16-bytestring >= 0.1.1.6+ , binary >= 0.8+ , ansi-wl-pprint >= 0.6+ , bytestring >= 0.10+ , containers >= 0.5.10.1+ , geojson >= 3.0.3+ , hedgehog , hspec+ , hw-hspec-hedgehog , lens , QuickCheck- , scientific >= 0.3.6- , trifecta >= 1.7- , vector >= 0.10 + , scientific >= 0.3.6+ , trifecta >= 1.7+ , vector >= 0.10 , wkt-geom ghc-options: -Wall default-language: Haskell2010++test-suite wkt-geom-hlint+ hs-source-dirs: hlint+ main-is: Main.hs+ type: exitcode-stdio-1.0+ build-depends: base+ , hlint+ default-language: Haskell2010+ ghc-options: -Wall+ -threaded source-repository head type: git