packages feed

vectortiles 1.0.0 → 1.1.0

raw patch · 8 files changed

+709/−698 lines, 8 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- Geography.VectorTile: B :: Bool -> Val
- Geography.VectorTile: Do :: Double -> Val
- Geography.VectorTile: Feature :: Int -> Map Text Val -> Vector g -> Feature g
- Geography.VectorTile: Fl :: Float -> Val
- Geography.VectorTile: I64 :: Int64 -> Val
- Geography.VectorTile: Layer :: Int -> Text -> Vector (Feature Point) -> Vector (Feature LineString) -> Vector (Feature Polygon) -> Int -> Layer
- Geography.VectorTile: S64 :: Int64 -> Val
- Geography.VectorTile: St :: Text -> Val
- Geography.VectorTile: VectorTile :: Vector Layer -> VectorTile
- Geography.VectorTile: W64 :: Word64 -> Val
- Geography.VectorTile: [_extent] :: Layer -> Int
- Geography.VectorTile: [_featureId] :: Feature g -> Int
- Geography.VectorTile: [_geometries] :: Feature g -> Vector g
- Geography.VectorTile: [_layers] :: VectorTile -> Vector Layer
- Geography.VectorTile: [_linestrings] :: Layer -> Vector (Feature LineString)
- Geography.VectorTile: [_metadata] :: Feature g -> Map Text Val
- Geography.VectorTile: [_name] :: Layer -> Text
- Geography.VectorTile: [_points] :: Layer -> Vector (Feature Point)
- Geography.VectorTile: [_polygons] :: Layer -> Vector (Feature Polygon)
- Geography.VectorTile: [_version] :: Layer -> Int
- Geography.VectorTile: data Feature g
- Geography.VectorTile: data Layer
- Geography.VectorTile: data Val
- Geography.VectorTile: extent :: Functor f => (Layer -> f Int) -> Layer -> f Layer
- Geography.VectorTile: featureId :: Functor f => (Feature g -> f Int) -> Feature g -> f (Feature g)
- Geography.VectorTile: features :: [Text] -> [RawVal] -> [RawFeature] -> Either Text (Vector (Feature Point), Vector (Feature LineString), Vector (Feature Polygon))
- Geography.VectorTile: geometries :: Functor f => (Feature g -> f (Vector g)) -> Feature g -> f (Feature g)
- Geography.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.Layer
- Geography.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.Val
- Geography.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.VectorTile
- Geography.VectorTile: instance Control.DeepSeq.NFData g => Control.DeepSeq.NFData (Geography.VectorTile.Feature g)
- Geography.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.Layer
- Geography.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.Val
- Geography.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.VectorTile
- Geography.VectorTile: instance GHC.Classes.Eq g => GHC.Classes.Eq (Geography.VectorTile.Feature g)
- Geography.VectorTile: instance GHC.Generics.Generic (Geography.VectorTile.Feature g)
- Geography.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.Layer
- Geography.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.Val
- Geography.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.VectorTile
- Geography.VectorTile: instance GHC.Show.Show Geography.VectorTile.Layer
- Geography.VectorTile: instance GHC.Show.Show Geography.VectorTile.Val
- Geography.VectorTile: instance GHC.Show.Show Geography.VectorTile.VectorTile
- Geography.VectorTile: instance GHC.Show.Show g => GHC.Show.Show (Geography.VectorTile.Feature g)
- Geography.VectorTile: layer :: RawLayer -> Either Text Layer
- Geography.VectorTile: layers :: Functor f => (Vector Layer -> f (Vector Layer)) -> VectorTile -> f VectorTile
- Geography.VectorTile: linestrings :: Functor f => (Layer -> f (Vector (Feature LineString))) -> Layer -> f Layer
- Geography.VectorTile: metadata :: Functor f => (Feature g -> f (Map Text Val)) -> Feature g -> f (Feature g)
- Geography.VectorTile: name :: Functor f => (Layer -> f Text) -> Layer -> f Layer
- Geography.VectorTile: newtype VectorTile
- Geography.VectorTile: points :: Functor f => (Layer -> f (Vector (Feature Point))) -> Layer -> f Layer
- Geography.VectorTile: polygons :: Functor f => (Layer -> f (Vector (Feature Polygon))) -> Layer -> f Layer
- Geography.VectorTile: unfeature :: Geom g => [Text] -> [Val] -> Feature g -> RawFeature
- Geography.VectorTile: unlayer :: Layer -> RawLayer
- Geography.VectorTile: unval :: Val -> RawVal
- Geography.VectorTile: value :: RawVal -> Either Text Val
- Geography.VectorTile: version :: Functor f => (Layer -> f Int) -> Layer -> f Layer
- Geography.VectorTile.Geometry: ClosePath :: Command
- Geography.VectorTile.Geometry: LineTo :: (Vector (Int, Int)) -> Command
- Geography.VectorTile.Geometry: MoveTo :: (Vector (Int, Int)) -> Command
- Geography.VectorTile.Geometry: class Geometry g
- Geography.VectorTile.Geometry: commands :: [Word32] -> Either Text [Command]
- Geography.VectorTile.Geometry: data Command
- Geography.VectorTile.Geometry: fromCommands :: Geometry g => [Command] -> Either Text (Vector g)
- Geography.VectorTile.Geometry: instance GHC.Classes.Eq Geography.VectorTile.Geometry.Command
- Geography.VectorTile.Geometry: instance GHC.Show.Show Geography.VectorTile.Geometry.Command
- Geography.VectorTile.Geometry: instance Geography.VectorTile.Geometry.Geometry Geography.VectorTile.Geometry.LineString
- Geography.VectorTile.Geometry: instance Geography.VectorTile.Geometry.Geometry Geography.VectorTile.Geometry.Point
- Geography.VectorTile.Geometry: instance Geography.VectorTile.Geometry.Geometry Geography.VectorTile.Geometry.Polygon
- Geography.VectorTile.Geometry: toCommands :: Geometry g => Vector g -> [Command]
- Geography.VectorTile.Geometry: uncommands :: [Command] -> [Word32]
- Geography.VectorTile.Geometry: unzig :: Word32 -> Int
- Geography.VectorTile.Geometry: zig :: Int -> Word32
- Geography.VectorTile.Raw: LineString :: GeomType
- Geography.VectorTile.Raw: Point :: GeomType
- Geography.VectorTile.Raw: Polygon :: GeomType
- Geography.VectorTile.Raw: RawFeature :: Optional 1 (Value Word64) -> Packed 2 (Value Word32) -> Optional 3 (Enumeration GeomType) -> Packed 4 (Value Word32) -> RawFeature
- Geography.VectorTile.Raw: RawLayer :: Required 15 (Value Word32) -> Required 1 (Value Text) -> Repeated 2 (Message RawFeature) -> Repeated 3 (Value Text) -> Repeated 4 (Message RawVal) -> Optional 5 (Value Word32) -> RawLayer
- Geography.VectorTile.Raw: RawVal :: Optional 1 (Value Text) -> Optional 2 (Value Float) -> Optional 3 (Value Double) -> Optional 4 (Value Int64) -> Optional 5 (Value Word64) -> Optional 6 (Value (Signed Int64)) -> Optional 7 (Value Bool) -> RawVal
- Geography.VectorTile.Raw: RawVectorTile :: Repeated 3 (Message RawLayer) -> RawVectorTile
- Geography.VectorTile.Raw: Unknown :: GeomType
- Geography.VectorTile.Raw: [bool] :: RawVal -> Optional 7 (Value Bool)
- Geography.VectorTile.Raw: [double] :: RawVal -> Optional 3 (Value Double)
- Geography.VectorTile.Raw: [extent] :: RawLayer -> Optional 5 (Value Word32)
- Geography.VectorTile.Raw: [featureId] :: RawFeature -> Optional 1 (Value Word64)
- Geography.VectorTile.Raw: [features] :: RawLayer -> Repeated 2 (Message RawFeature)
- Geography.VectorTile.Raw: [float] :: RawVal -> Optional 2 (Value Float)
- Geography.VectorTile.Raw: [geom] :: RawFeature -> Optional 3 (Enumeration GeomType)
- Geography.VectorTile.Raw: [geometries] :: RawFeature -> Packed 4 (Value Word32)
- Geography.VectorTile.Raw: [int64] :: RawVal -> Optional 4 (Value Int64)
- Geography.VectorTile.Raw: [keys] :: RawLayer -> Repeated 3 (Value Text)
- Geography.VectorTile.Raw: [layers] :: RawVectorTile -> Repeated 3 (Message RawLayer)
- Geography.VectorTile.Raw: [name] :: RawLayer -> Required 1 (Value Text)
- Geography.VectorTile.Raw: [sint] :: RawVal -> Optional 6 (Value (Signed Int64))
- Geography.VectorTile.Raw: [string] :: RawVal -> Optional 1 (Value Text)
- Geography.VectorTile.Raw: [tags] :: RawFeature -> Packed 2 (Value Word32)
- Geography.VectorTile.Raw: [uint64] :: RawVal -> Optional 5 (Value Word64)
- Geography.VectorTile.Raw: [values] :: RawLayer -> Repeated 4 (Message RawVal)
- Geography.VectorTile.Raw: [version] :: RawLayer -> Required 15 (Value Word32)
- Geography.VectorTile.Raw: class Geometry g => Geom g
- Geography.VectorTile.Raw: data GeomType
- Geography.VectorTile.Raw: data RawFeature
- Geography.VectorTile.Raw: data RawLayer
- Geography.VectorTile.Raw: data RawVal
- Geography.VectorTile.Raw: data RawVectorTile
- Geography.VectorTile.Raw: decode :: ByteString -> Either Text RawVectorTile
- Geography.VectorTile.Raw: decodeIO :: FilePath -> IO (Either Text RawVectorTile)
- Geography.VectorTile.Raw: encode :: RawVectorTile -> ByteString
- Geography.VectorTile.Raw: encodeIO :: RawVectorTile -> FilePath -> IO ()
- Geography.VectorTile.Raw: geomType :: Geom g => g -> GeomType
- Geography.VectorTile.Raw: instance Control.DeepSeq.NFData Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance Control.DeepSeq.NFData Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance Control.DeepSeq.NFData Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance Control.DeepSeq.NFData Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance Control.DeepSeq.NFData Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance GHC.Classes.Eq Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance GHC.Classes.Eq Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance GHC.Classes.Eq Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance GHC.Classes.Eq Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance GHC.Classes.Eq Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance GHC.Enum.Enum Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance GHC.Generics.Generic Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance GHC.Generics.Generic Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance GHC.Generics.Generic Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance GHC.Generics.Generic Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance GHC.Generics.Generic Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance GHC.Show.Show Geography.VectorTile.Raw.GeomType
- Geography.VectorTile.Raw: instance GHC.Show.Show Geography.VectorTile.Raw.RawFeature
- Geography.VectorTile.Raw: instance GHC.Show.Show Geography.VectorTile.Raw.RawLayer
- Geography.VectorTile.Raw: instance GHC.Show.Show Geography.VectorTile.Raw.RawVal
- Geography.VectorTile.Raw: instance GHC.Show.Show Geography.VectorTile.Raw.RawVectorTile
- Geography.VectorTile.Raw: instance Geography.VectorTile.Raw.Geom Geography.VectorTile.Geometry.LineString
- Geography.VectorTile.Raw: instance Geography.VectorTile.Raw.Geom Geography.VectorTile.Geometry.Point
- Geography.VectorTile.Raw: instance Geography.VectorTile.Raw.Geom Geography.VectorTile.Geometry.Polygon
+ Geography.VectorTile: decode :: ByteString -> Either Text RawVectorTile
+ Geography.VectorTile: encode :: RawVectorTile -> ByteString
+ Geography.VectorTile.Geometry: x :: (Int, Int) -> Int
+ Geography.VectorTile.Geometry: y :: (Int, Int) -> Int
+ Geography.VectorTile.Protobuf: ClosePath :: Command
+ Geography.VectorTile.Protobuf: LineString :: GeomType
+ Geography.VectorTile.Protobuf: LineTo :: (Vector (Int, Int)) -> Command
+ Geography.VectorTile.Protobuf: MoveTo :: (Vector (Int, Int)) -> Command
+ Geography.VectorTile.Protobuf: Point :: GeomType
+ Geography.VectorTile.Protobuf: Polygon :: GeomType
+ Geography.VectorTile.Protobuf: RawFeature :: Optional 1 (Value Word64) -> Packed 2 (Value Word32) -> Optional 3 (Enumeration GeomType) -> Packed 4 (Value Word32) -> RawFeature
+ Geography.VectorTile.Protobuf: RawLayer :: Required 15 (Value Word32) -> Required 1 (Value Text) -> Repeated 2 (Message RawFeature) -> Repeated 3 (Value Text) -> Repeated 4 (Message RawVal) -> Optional 5 (Value Word32) -> RawLayer
+ Geography.VectorTile.Protobuf: RawVal :: Optional 1 (Value Text) -> Optional 2 (Value Float) -> Optional 3 (Value Double) -> Optional 4 (Value Int64) -> Optional 5 (Value Word64) -> Optional 6 (Value (Signed Int64)) -> Optional 7 (Value Bool) -> RawVal
+ Geography.VectorTile.Protobuf: RawVectorTile :: Repeated 3 (Message RawLayer) -> RawVectorTile
+ Geography.VectorTile.Protobuf: Unknown :: GeomType
+ Geography.VectorTile.Protobuf: [_bool] :: RawVal -> Optional 7 (Value Bool)
+ Geography.VectorTile.Protobuf: [_double] :: RawVal -> Optional 3 (Value Double)
+ Geography.VectorTile.Protobuf: [_extent] :: RawLayer -> Optional 5 (Value Word32)
+ Geography.VectorTile.Protobuf: [_featureId] :: RawFeature -> Optional 1 (Value Word64)
+ Geography.VectorTile.Protobuf: [_features] :: RawLayer -> Repeated 2 (Message RawFeature)
+ Geography.VectorTile.Protobuf: [_float] :: RawVal -> Optional 2 (Value Float)
+ Geography.VectorTile.Protobuf: [_geom] :: RawFeature -> Optional 3 (Enumeration GeomType)
+ Geography.VectorTile.Protobuf: [_geometries] :: RawFeature -> Packed 4 (Value Word32)
+ Geography.VectorTile.Protobuf: [_int64] :: RawVal -> Optional 4 (Value Int64)
+ Geography.VectorTile.Protobuf: [_keys] :: RawLayer -> Repeated 3 (Value Text)
+ Geography.VectorTile.Protobuf: [_layers] :: RawVectorTile -> Repeated 3 (Message RawLayer)
+ Geography.VectorTile.Protobuf: [_name] :: RawLayer -> Required 1 (Value Text)
+ Geography.VectorTile.Protobuf: [_sint] :: RawVal -> Optional 6 (Value (Signed Int64))
+ Geography.VectorTile.Protobuf: [_string] :: RawVal -> Optional 1 (Value Text)
+ Geography.VectorTile.Protobuf: [_tags] :: RawFeature -> Packed 2 (Value Word32)
+ Geography.VectorTile.Protobuf: [_uint64] :: RawVal -> Optional 5 (Value Word64)
+ Geography.VectorTile.Protobuf: [_values] :: RawLayer -> Repeated 4 (Message RawVal)
+ Geography.VectorTile.Protobuf: [_version] :: RawLayer -> Required 15 (Value Word32)
+ Geography.VectorTile.Protobuf: class ProtobufGeom g
+ Geography.VectorTile.Protobuf: commands :: [Word32] -> Either Text [Command]
+ Geography.VectorTile.Protobuf: data Command
+ Geography.VectorTile.Protobuf: data GeomType
+ Geography.VectorTile.Protobuf: data RawFeature
+ Geography.VectorTile.Protobuf: data RawLayer
+ Geography.VectorTile.Protobuf: data RawVal
+ Geography.VectorTile.Protobuf: data RawVectorTile
+ Geography.VectorTile.Protobuf: decode :: ByteString -> Either Text RawVectorTile
+ Geography.VectorTile.Protobuf: decodeIO :: FilePath -> IO (Either Text RawVectorTile)
+ Geography.VectorTile.Protobuf: encode :: RawVectorTile -> ByteString
+ Geography.VectorTile.Protobuf: encodeIO :: RawVectorTile -> FilePath -> IO ()
+ Geography.VectorTile.Protobuf: features :: [Text] -> [RawVal] -> [RawFeature] -> Either Text (Vector (Feature Point), Vector (Feature LineString), Vector (Feature Polygon))
+ Geography.VectorTile.Protobuf: fromCommands :: ProtobufGeom g => [Command] -> Either Text (Vector g)
+ Geography.VectorTile.Protobuf: geomType :: ProtobufGeom g => g -> GeomType
+ Geography.VectorTile.Protobuf: instance Control.DeepSeq.NFData Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance Control.DeepSeq.NFData Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance Control.DeepSeq.NFData Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance Control.DeepSeq.NFData Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance Control.DeepSeq.NFData Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Decode.Decode Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance Data.ProtocolBuffers.Encode.Encode Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.Command
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance GHC.Classes.Eq Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance GHC.Enum.Enum Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance GHC.Generics.Generic Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance GHC.Generics.Generic Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance GHC.Generics.Generic Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance GHC.Generics.Generic Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance GHC.Generics.Generic Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.Command
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.GeomType
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.RawFeature
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.RawLayer
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.RawVal
+ Geography.VectorTile.Protobuf: instance GHC.Show.Show Geography.VectorTile.Protobuf.RawVectorTile
+ Geography.VectorTile.Protobuf: instance Geography.VectorTile.Protobuf.ProtobufGeom Geography.VectorTile.Geometry.LineString
+ Geography.VectorTile.Protobuf: instance Geography.VectorTile.Protobuf.ProtobufGeom Geography.VectorTile.Geometry.Point
+ Geography.VectorTile.Protobuf: instance Geography.VectorTile.Protobuf.ProtobufGeom Geography.VectorTile.Geometry.Polygon
+ Geography.VectorTile.Protobuf: layer :: RawLayer -> Either Text Layer
+ Geography.VectorTile.Protobuf: tile :: RawVectorTile -> Either Text VectorTile
+ Geography.VectorTile.Protobuf: toCommands :: ProtobufGeom g => Vector g -> [Command]
+ Geography.VectorTile.Protobuf: uncommands :: [Command] -> [Word32]
+ Geography.VectorTile.Protobuf: unfeature :: ProtobufGeom g => [Text] -> [Val] -> Feature g -> RawFeature
+ Geography.VectorTile.Protobuf: unlayer :: Layer -> RawLayer
+ Geography.VectorTile.Protobuf: untile :: VectorTile -> RawVectorTile
+ Geography.VectorTile.Protobuf: unval :: Val -> RawVal
+ Geography.VectorTile.Protobuf: unzig :: Word32 -> Int
+ Geography.VectorTile.Protobuf: value :: RawVal -> Either Text Val
+ Geography.VectorTile.Protobuf: zig :: Int -> Word32
+ Geography.VectorTile.VectorTile: B :: Bool -> Val
+ Geography.VectorTile.VectorTile: Do :: Double -> Val
+ Geography.VectorTile.VectorTile: Feature :: Int -> Map Text Val -> Vector g -> Feature g
+ Geography.VectorTile.VectorTile: Fl :: Float -> Val
+ Geography.VectorTile.VectorTile: I64 :: Int64 -> Val
+ Geography.VectorTile.VectorTile: Layer :: Int -> Text -> Vector (Feature Point) -> Vector (Feature LineString) -> Vector (Feature Polygon) -> Int -> Layer
+ Geography.VectorTile.VectorTile: S64 :: Int64 -> Val
+ Geography.VectorTile.VectorTile: St :: Text -> Val
+ Geography.VectorTile.VectorTile: VectorTile :: Vector Layer -> VectorTile
+ Geography.VectorTile.VectorTile: W64 :: Word64 -> Val
+ Geography.VectorTile.VectorTile: [_extent] :: Layer -> Int
+ Geography.VectorTile.VectorTile: [_featureId] :: Feature g -> Int
+ Geography.VectorTile.VectorTile: [_geometries] :: Feature g -> Vector g
+ Geography.VectorTile.VectorTile: [_layers] :: VectorTile -> Vector Layer
+ Geography.VectorTile.VectorTile: [_linestrings] :: Layer -> Vector (Feature LineString)
+ Geography.VectorTile.VectorTile: [_metadata] :: Feature g -> Map Text Val
+ Geography.VectorTile.VectorTile: [_name] :: Layer -> Text
+ Geography.VectorTile.VectorTile: [_points] :: Layer -> Vector (Feature Point)
+ Geography.VectorTile.VectorTile: [_polygons] :: Layer -> Vector (Feature Polygon)
+ Geography.VectorTile.VectorTile: [_version] :: Layer -> Int
+ Geography.VectorTile.VectorTile: data Feature g
+ Geography.VectorTile.VectorTile: data Layer
+ Geography.VectorTile.VectorTile: data Val
+ Geography.VectorTile.VectorTile: extent :: Functor f => (Int -> f Int) -> Layer -> f Layer
+ Geography.VectorTile.VectorTile: featureId :: Functor f => (Int -> f Int) -> Feature g -> f (Feature g)
+ Geography.VectorTile.VectorTile: geometries :: Functor f => (Vector g -> f (Vector g)) -> Feature g -> f (Feature g)
+ Geography.VectorTile.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.VectorTile.Layer
+ Geography.VectorTile.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.VectorTile.Val
+ Geography.VectorTile.VectorTile: instance Control.DeepSeq.NFData Geography.VectorTile.VectorTile.VectorTile
+ Geography.VectorTile.VectorTile: instance Control.DeepSeq.NFData g => Control.DeepSeq.NFData (Geography.VectorTile.VectorTile.Feature g)
+ Geography.VectorTile.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.VectorTile.Layer
+ Geography.VectorTile.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.VectorTile.Val
+ Geography.VectorTile.VectorTile: instance GHC.Classes.Eq Geography.VectorTile.VectorTile.VectorTile
+ Geography.VectorTile.VectorTile: instance GHC.Classes.Eq g => GHC.Classes.Eq (Geography.VectorTile.VectorTile.Feature g)
+ Geography.VectorTile.VectorTile: instance GHC.Generics.Generic (Geography.VectorTile.VectorTile.Feature g)
+ Geography.VectorTile.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.VectorTile.Layer
+ Geography.VectorTile.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.VectorTile.Val
+ Geography.VectorTile.VectorTile: instance GHC.Generics.Generic Geography.VectorTile.VectorTile.VectorTile
+ Geography.VectorTile.VectorTile: instance GHC.Show.Show Geography.VectorTile.VectorTile.Layer
+ Geography.VectorTile.VectorTile: instance GHC.Show.Show Geography.VectorTile.VectorTile.Val
+ Geography.VectorTile.VectorTile: instance GHC.Show.Show Geography.VectorTile.VectorTile.VectorTile
+ Geography.VectorTile.VectorTile: instance GHC.Show.Show g => GHC.Show.Show (Geography.VectorTile.VectorTile.Feature g)
+ Geography.VectorTile.VectorTile: layers :: Functor f => (Vector Layer -> f (Vector Layer)) -> VectorTile -> f VectorTile
+ Geography.VectorTile.VectorTile: linestrings :: Functor f => (Vector (Feature LineString) -> f (Vector (Feature LineString))) -> Layer -> f Layer
+ Geography.VectorTile.VectorTile: metadata :: Functor f => (Map Text Val -> f (Map Text Val)) -> Feature g -> f (Feature g)
+ Geography.VectorTile.VectorTile: name :: Functor f => (Text -> f Text) -> Layer -> f Layer
+ Geography.VectorTile.VectorTile: newtype VectorTile
+ Geography.VectorTile.VectorTile: points :: Functor f => (Vector (Feature Point) -> f (Vector (Feature Point))) -> Layer -> f Layer
+ Geography.VectorTile.VectorTile: polygons :: Functor f => (Vector (Feature Polygon) -> f (Vector (Feature Polygon))) -> Layer -> f Layer
+ Geography.VectorTile.VectorTile: version :: Functor f => (Int -> f Int) -> Layer -> f Layer

Files

Geography/VectorTile.hs view
@@ -1,7 +1,3 @@-{-# LANGUAGE StrictData #-}-{-# LANGUAGE OverloadedStrings #-}-{-# LANGUAGE DeriveGeneric #-}- -- | -- Module    : Geography.VectorTile -- Copyright : (c) Azavea, 2016@@ -18,336 +14,43 @@ -- -- The order in which to explore the modules of this library is as follows: ----- 1. "Geography.VectorTile" (here)+-- 1. "Geography.VectorTile.VectorTile" -- 2. "Geography.VectorTile.Geometry"--- 3. "Geography.VectorTile.Raw"+-- 3. "Geography.VectorTile.Protobuf" -- -- == Usage ----- This library reads and writes strict `ByteString`s. Given some legal+-- This library reads and writes strict `ByteString`s. By importing this module,+-- you use the default protobuf backend. Given some legal -- VectorTile file called @roads.mvt@: -- -- > import qualified Data.ByteString as BS -- > import           Data.Text (Text) -- > import           Geography.VectorTile--- > import qualified Geography.VectorTile.Raw as R -- > -- > -- | Read in raw protobuf data and decode it into a high-level type. -- > roads :: IO (Either Text VectorTile) -- > roads = do -- >   mvt <- BS.readFile "roads.mvt"--- >   pure $ R.decode mvt >>= tile+-- >   pure $ decode mvt >>= tile -- -- Or encode a `VectorTile` back into a `ByteString`: -- -- > roadsBytes :: VectorTile -> BS.ByteString--- > roadsBytes = R.encode . untile+-- > roadsBytes = encode . untile + module Geography.VectorTile-  ( -- * Types-    VectorTile(..)-  , Layer(..)-  , Feature(..)-  , Val(..)-    -- * Protobuf Conversions-    -- ** From Protobuf-    -- | Generally the `tile` function is the only one needed here. Usage:-    ---    -- > import qualified Geography.VectorTile.Raw as R-    -- >-    -- > R.decode someBytes >>= tile-    ---    -- Note that since the "Data.ProtocolBuffers" library does not handle default-    -- values, we handle those specifically defined in /vector_tile.proto/-    -- explicitely here. See:-    ---    -- https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto-  , tile-  , layer-  , features-  , value-    -- ** To Protobuf-    -- | To convert from high-level data back into a form that can be encoded-    -- into raw protobuf bytes, use:-    ---    -- > import qualified Geography.VectorTile.Raw as R-    -- >-    -- > R.encode $ untile someTile-    ---    -- This is a pure process and will succeed every time.-  , untile-  , unlayer-  , unfeature-  , unval-    -- * Lenses-    -- | This section can be safely ignored if one isn't concerned with lenses.-    -- Otherwise, see the following for a good primer on Haskell lenses:-    -- http://hackage.haskell.org/package/lens-tutorial-1.0.1/docs/Control-Lens-Tutorial.html-    ---    -- These lenses are written in a generic way to avoid taking a dependency-    -- on one of the lens libraries.-  , layers-  , version-  , name-  , points-  , linestrings-  , polygons-  , extent-  , featureId-  , metadata-  , geometries+  ( -- * High-level Types+    module Geography.VectorTile.VectorTile+  , -- * Protobuf Backend+    -- ** Conversions+    PB.tile+  , PB.untile+  -- ** ByteString Encoding / Decoding+  , PB.decode+  , PB.encode   ) where -import           Control.Applicative ((<|>))-import           Control.DeepSeq (NFData)-import           Data.Foldable (foldrM)-import           Data.Int-import           Data.List (nub, elemIndex)-import qualified Data.Map.Lazy as M-import           Data.Maybe (fromJust)-import           Data.Monoid-import           Data.ProtocolBuffers-import qualified Data.Set as S-import           Data.Text (Text,pack)-import qualified Data.Vector as V-import           Data.Word-import           GHC.Generics (Generic)-import           Geography.VectorTile.Geometry-import qualified Geography.VectorTile.Raw as R-import           Geography.VectorTile.Util-------{- Types -}---- | A high-level representation of a Vector Tile. At its simplest, a tile--- is just a list of `Layer`s.------ There is potential to implement `_layers` as a `M.Map`, with its String-based--- `name` as a key.-newtype VectorTile = VectorTile { _layers :: V.Vector Layer } deriving (Eq,Show,Generic)---- | > Lens' VectorTile (Vector Layer)-layers :: Functor f => (V.Vector Layer -> f (V.Vector Layer)) -> VectorTile -> f VectorTile-layers f v = VectorTile <$> f (_layers v)-{-# INLINE layers #-}--instance NFData VectorTile---- | A layer, which could contain any number of `Feature`s of any `Geometry` type.--- This codec only respects the canonical three `Geometry` types, and we split--- them here explicitely to allow for more fine-grained access to each type.-data Layer = Layer { _version :: Int  -- ^ The version of the spec we follow. Should always be 2.-                   , _name :: Text-                   , _points :: V.Vector (Feature Point)-                   , _linestrings :: V.Vector (Feature LineString)-                   , _polygons :: V.Vector (Feature Polygon)-                   , _extent :: Int  -- ^ Default: 4096-                   } deriving (Eq,Show,Generic)---- | > Lens' Layer Int-version :: Functor f => (Layer -> f Int) -> Layer -> f Layer-version f l = fmap (\v -> l { _version = v }) $ f l-{-# INLINE version #-}---- | > Lens' Layer Text-name :: Functor f => (Layer -> f Text) -> Layer -> f Layer-name f l = fmap (\v -> l { _name = v }) $ f l-{-# INLINE name #-}---- | > Lens' Layer (Vector (Feature Point))-points :: Functor f => (Layer -> f (V.Vector (Feature Point))) -> Layer -> f Layer-points f l = fmap (\v -> l { _points = v }) $ f l-{-# INLINE points #-}---- | > Lens' Layer (Vector (Feature LineString)))-linestrings :: Functor f => (Layer -> f (V.Vector (Feature LineString))) -> Layer -> f Layer-linestrings f l = fmap (\v -> l { _linestrings = v }) $ f l-{-# INLINE linestrings #-}---- | > Lens' Layer (Vector (Feature Polygon)))-polygons :: Functor f => (Layer -> f (V.Vector (Feature Polygon))) -> Layer -> f Layer-polygons f l = fmap (\v -> l { _polygons = v }) $ f l-{-# INLINE polygons #-}---- | > Lens' Layer Int-extent :: Functor f => (Layer -> f Int) -> Layer -> f Layer-extent f l = fmap (\v -> l { _extent = v }) $ f l-{-# INLINE extent #-}--instance NFData Layer---- | A geographic feature. Features are a set of geometries that share--- some common theme:------ * Points: schools, gas station locations, etc.--- * LineStrings: Roads, power lines, rivers, etc.--- * Polygons: Buildings, water bodies, etc.------ Where, for instance, all school locations may be stored as a single--- `Feature`, and no `Point` within that `Feature` would represent anything--- else.------ Note: Each `Geometry` type and their /Multi*/ counterpart are considered--- the same thing, as a `V.Vector` of that `Geometry`.-data Feature g = Feature { _featureId :: Int  -- ^ Default: 0-                         , _metadata :: M.Map Text Val-                         , _geometries :: V.Vector g } deriving (Eq,Show,Generic)---- | > Lens' (Feature g) Int-featureId :: Functor f => (Feature g -> f Int) -> Feature g -> f (Feature g)-featureId f l = fmap (\v -> l { _featureId = v }) $ f l-{-# INLINE featureId #-}---- | > Lens' (Feature g) (Map Text Val)-metadata :: Functor f => (Feature g -> f (M.Map Text Val)) -> Feature g -> f (Feature g)-metadata f l = fmap (\v -> l { _metadata = v }) $ f l-{-# INLINE metadata #-}---- | > Lens' (Feature g) (Vector g)-geometries :: Functor f => (Feature g -> f (V.Vector g)) -> Feature g -> f (Feature g)-geometries f l = fmap (\v -> l { _geometries = v }) $ f l-{-# INLINE geometries #-}--instance NFData g => NFData (Feature g)---- | Legal Metadata /Value/ types. Note that `S64` are Z-encoded automatically--- by the underlying "Data.ProtocolBuffers" library.-data Val = St Text | Fl Float | Do Double | I64 Int64 | W64 Word64 | S64 Int64 | B Bool-         deriving (Eq,Show,Generic)--instance NFData Val--{- FROM PROTOBUF -}---- | Convert a `R.RawVectorTile` of parsed protobuf data into a useable--- `VectorTile`.-tile :: R.RawVectorTile -> Either Text VectorTile-tile = fmap (VectorTile . V.fromList) . mapM layer . getField . R.layers---- | Convert a single `R.RawLayer` of parsed protobuf data into a useable--- `Layer`.-layer :: R.RawLayer -> Either Text Layer-layer l = do-  (ps,ls,polys) <- features keys vals . getField $ R.features l-  pure Layer { _version = fromIntegral . getField $ R.version l-             , _name = getField $ R.name l-             , _points = ps-             , _linestrings = ls-             , _polygons = polys-             , _extent = maybe 4096 fromIntegral (getField $ R.extent l) }-  where keys = getField $ R.keys l-        vals = getField $ R.values l---- | Convert a list of `R.RawFeature`s of parsed protobuf data into `V.Vector`s--- of each of the three legal `Geometry` types.------ The long type signature is due to two things:------ 1. `Feature`s are polymorphic at the high level, but not at the parsed--- protobuf mid-level. In a @[RawFeature]@, there are features of points,--- linestrings, and polygons all mixed together.------ 2. `R.RawLayer`s and `R.RawFeature`s--- are strongly coupled at the protobuf level. In order to achieve higher--- compression ratios, `R.RawLayer`s contain all metadata in key/value lists--- to be shared across their `R.RawFeature`s, while those `R.RawFeature`s store only--- indices into those lists. As a result, this function needs to be passed--- those key/value lists from the parent `R.RawLayer`, and a more isomorphic:------ > feature :: Geometry g => RawFeature -> Either Text (Feature g)------ is not possible.-features :: [Text] -> [R.RawVal] -> [R.RawFeature]-  -> Either Text (V.Vector (Feature Point), V.Vector (Feature LineString), V.Vector (Feature Polygon))-features _ _ [] = Left "VectorTile.features: `[R.RawFeature]` empty"-features keys vals fs = (,,) <$> ps <*> ls <*> polys-  where -- (_:ps':ls':polys':_) = groupBy sameGeom $ sortOn geomBias fs  -- ok ok ok-        ps = foldrM f V.empty $ filter (\fe -> getField (R.geom fe) == Just R.Point) fs-        ls = foldrM f V.empty $ filter (\fe -> getField (R.geom fe) == Just R.LineString) fs-        polys = foldrM f V.empty $ filter (\fe -> getField (R.geom fe) == Just R.Polygon) fs--        f :: Geometry g => R.RawFeature -> V.Vector (Feature g) -> Either Text (V.Vector (Feature g))-        f x acc = do-          geos <- commands (getField $ R.geometries x) >>= fromCommands-          meta <- getMeta keys vals . getField $ R.tags x-          pure $ Feature { _featureId = maybe 0 fromIntegral . getField $ R.featureId x-                         , _metadata = meta-                         , _geometries = geos-                         } `V.cons` acc---- | Convert a `R.RawVal` parsed from protobuf data into a useable--- `Val`. The higher-level `Val` type better expresses the mutual exclusivity--- of the /Value/ types.-value :: R.RawVal -> Either Text Val-value v = mtoe "Value decode: No legal Value type offered" $ fmap St (getField $ R.string v)-  <|> fmap Fl  (getField $ R.float v)-  <|> fmap Do  (getField $ R.double v)-  <|> fmap I64 (getField $ R.int64 v)-  <|> fmap W64 (getField $ R.uint64 v)-  <|> fmap (\(Signed n) -> S64 n) (getField $ R.sint v)-  <|> fmap B   (getField $ R.bool v)--getMeta :: [Text] -> [R.RawVal] -> [Word32] -> Either Text (M.Map Text Val)-getMeta keys vals tags = do-  kv <- map (both fromIntegral) <$> pairs tags-  foldrM (\(k,v) acc -> (\v' -> M.insert (keys !! k) v' acc) <$> (value $ vals !! v)) M.empty kv--{- TO PROTOBUF -}---- | Encode a high-level `VectorTile` back into its mid-level--- `R.RawVectorTile` form.-untile :: VectorTile -> R.RawVectorTile-untile vt = R.RawVectorTile { R.layers = putField . V.toList . V.map unlayer $ _layers vt }---- Has to get back all its metadata from its features--- | Encode a high-level `Layer` back into its mid-level `R.RawLayer` form.-unlayer :: Layer -> R.RawLayer-unlayer l = R.RawLayer { R.version = putField . fromIntegral $ _version l-                       , R.name = putField $ _name l-                       , R.features = putField fs-                       , R.keys = putField ks-                       , R.values = putField $ map unval vs-                       , R.extent = putField . Just . fromIntegral $ _extent l }-  where (ks,vs) = totalMeta (_points l) (_linestrings l) (_polygons l)-        fs = V.toList $ V.concat [ V.map (unfeature ks vs) (_points l)-                                 , V.map (unfeature ks vs) (_linestrings l)-                                 , V.map (unfeature ks vs) (_polygons l) ]--totalMeta :: V.Vector (Feature Point) -> V.Vector (Feature LineString) -> V.Vector (Feature Polygon) -> ([Text], [Val])-totalMeta ps ls polys = (keys, vals)-  where keys = S.toList . S.unions $ f ps <> f ls <> f polys-        vals = nub . concat $ g ps <> g ls <> g polys  -- `nub` is O(n^2)-        f = V.foldr (\x acc -> M.keysSet (_metadata x) : acc) []-        g = V.foldr (\x acc -> M.elems (_metadata x) : acc) []---- | Encode a high-level `Feature` back into its mid-level `R.RawFeature` form.-unfeature :: R.Geom g => [Text] -> [Val] -> Feature g -> R.RawFeature-unfeature keys vals fe = R.RawFeature-                         { R.featureId = putField . Just . fromIntegral $ _featureId fe-                         , R.tags = putField $ tags fe-                         , R.geom = putField . Just . R.geomType . V.head $ _geometries fe-                         , R.geometries = putField . uncommands . toCommands $ _geometries fe-                         }-  where tags = unpairs . map f . M.toList . _metadata-        f (k,v) = both (fromIntegral . fromJust) (k `elemIndex` keys, v `elemIndex` vals)---- | Encode a high-level `Val` back into its mid-level `R.RawVal` form.-unval :: Val -> R.RawVal-unval (St v)  = def { R.string = putField $ Just v }-unval (Fl v)  = def { R.float = putField $ Just v }-unval (Do v)  = def { R.double = putField $ Just v }-unval (I64 v) = def { R.int64 = putField $ Just v }-unval (W64 v) = def { R.uint64 = putField $ Just v }-unval (S64 v) = def { R.sint = putField . Just $ Signed v }-unval (B v)   = def { R.bool = putField $ Just v }---- | A `R.RawVal` with every entry set to `Nothing`.-def :: R.RawVal-def = R.RawVal { R.string = putField Nothing-               , R.float  = putField Nothing-               , R.double = putField Nothing-               , R.int64  = putField Nothing-               , R.uint64 = putField Nothing-               , R.sint   = putField Nothing-               , R.bool   = putField Nothing }+import Geography.VectorTile.VectorTile+import qualified Geography.VectorTile.Protobuf as PB
Geography/VectorTile/Geometry.hs view
@@ -17,37 +17,19 @@ module Geography.VectorTile.Geometry   ( -- * Geometries     -- ** Types-    Geometry(..)-  , Point(..)+    Point, x, y   , LineString(..)   , Polygon(..)   -- ** Operations   , area   , surveyor   , distance-  -- * Commands-  , Command(..)-  , commands-  , uncommands-   -- * Z-Encoding-  , zig-  , unzig   ) where  import           Control.DeepSeq (NFData)-import           Control.Monad.Trans.State.Lazy-import           Data.Bits-import           Data.Foldable (foldlM)-import           Data.Int-import           Data.Monoid-import           Data.Text (Text)-import qualified Data.Text as T import qualified Data.Vector as V import qualified Data.Vector.Unboxed as U-import           Data.Word import           GHC.Generics (Generic)-import           Geography.VectorTile.Util-import           Text.Printf.TH  --- @@ -102,154 +84,3 @@ distance p1 p2 = sqrt . fromIntegral $ dx ^ 2 + dy ^ 2   where dx = x p1 - x p2         dy = y p1 - y p2---- | Any classical type considered a GIS "geometry". These must be able--- to convert between an encodable list of `Command`s.-class Geometry g where-  fromCommands :: [Command] -> Either Text (V.Vector g)-  toCommands :: V.Vector g -> [Command]---- | A valid `R.Feature` of points must contain a single `MoveTo` command--- with a count greater than 0.-instance Geometry Point where-  fromCommands (MoveTo ps : []) = Right . U.convert $ evalState (U.mapM expand ps) (0,0)-  fromCommands (c:_) = Left $ [st|Invalid command found in Point feature: %s|] (show c)-  fromCommands [] = Left "No points given!"--  -- | A multipoint geometry must reduce to a single `MoveTo` command.-  toCommands ps = [MoveTo $ evalState (U.mapM collapse $ U.convert ps) (0,0)]---- | A valid `R.Feature` of linestrings must contain pairs of:------ A `MoveTo` with a count of 1, followed by one `LineTo` command with--- a count greater than 0.-instance Geometry LineString where-  fromCommands cs = evalState (f cs) (0,0)-    where f (MoveTo p : LineTo ps : rs) = fmap . V.cons <$> ls <*> f rs-            where ls = LineString <$> U.mapM expand (p <> ps)-          f [] = pure $ Right V.empty-          f _  = pure $ Left "LineString decode: Invalid command sequence given."--  toCommands ls = concat $ evalState (mapM f ls) (0,0)-    where f (LineString ps) = do-            curr <- get-            let (h,t) = (U.head ps, U.tail ps)-            put h-            l <- U.mapM collapse t-            pure [MoveTo $ U.singleton (x h - x curr, y h - y curr), LineTo l]---- | A valid `R.Feature` of polygons must contain at least one sequence of:------ An Exterior Ring, followed by 0 or more Interior Rings.------ Any Ring must have a `MoveTo` with a count of 1, a single `LineTo`--- with a count of at least 2, and a single `ClosePath` command.------ Performs no sanity checks for malformed Interior Rings.-instance Geometry Polygon where-  fromCommands cs = do-    ps <- evalState (f cs) (0,0)-    let (h,t) = (V.head ps, V.tail ps)-        (ps',p') = runState (foldlM g V.empty t) h-    pure $ V.snoc ps' p'  -- Include the last Exterior Ring worked on.-    where f (MoveTo p : LineTo ps : ClosePath : rs) = do-            curr <- get-            let h = U.head p-                here = (x h + x curr, y h + y curr)-            po <- flip U.snoc here <$> U.mapM expand (U.cons h ps)-            fmap (V.cons (Polygon po V.empty)) <$> f rs-          f [] = pure $ Right V.empty-          f _  = pure . Left $ [st|Polygon decode: Invalid command sequence given: %s|] (show cs)-          g acc p | area p > 0 = do  -- New external rings.-                      curr <- get-                      put p-                      pure $ V.snoc acc curr-                  | otherwise = do  -- Next internal ring.-                      modify (\s -> s { inner = V.snoc (inner s) p })-                      pure acc--  toCommands ps = concat $ evalState (mapM f ps) (0,0)-    where f (Polygon p i) = do-            curr <- get-            let (h,t) = (U.head p, U.tail $ U.init p)  -- Exclude the final point.-            put h-            l <- U.mapM collapse t-            let cs = [MoveTo $ U.singleton (x h - x curr, y h - y curr), LineTo l, ClosePath]-            concat . V.cons cs <$> mapM f i---- | The possible commands, and the values they hold.-data Command = MoveTo (U.Vector (Int,Int))-             | LineTo (U.Vector (Int,Int))-             | ClosePath deriving (Eq,Show)---- | Z-encode a 64-bit Int.-zig :: Int -> Word32-zig n = fromIntegral $ shift n 1 `xor` shift n (-63)---- | Decode a Z-encoded Word32 into a 64-bit Int.-unzig :: Word32 -> Int-unzig n = fromIntegral (fromIntegral unzigged :: Int32)-  where unzigged = shift n (-1) `xor` negate (n .&. 1)---- | Divide a "Command Integer" into its @(Command,Count)@.-parseCmd :: Word32 -> Either T.Text (Int,Int)-parseCmd n = case (cmd,count) of-  (1,m) -> Right $ both fromIntegral (1,m)-  (2,m) -> Right $ both fromIntegral (2,m)-  (7,1) -> Right (7,1)-  (7,m) -> Left $ "ClosePath was given a parameter count: " <> T.pack (show m)-  (m,_) -> Left $ [st|Invalid command integer %d found in: %X|] m n-  where cmd = n .&. 7-        count = shift n (-3)---- | Recombine a Command ID and parameter count into a Command Integer.-unparseCmd :: (Int,Int) -> Word32-unparseCmd (cmd,count) = fromIntegral $ (cmd .&. 7) .|. shift count 3---- | Attempt to parse a list of Command/Parameter integers, as defined here:------ https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding-commands :: [Word32] -> Either T.Text [Command]-commands [] = Right []-commands (n:ns) = parseCmd n >>= f-  where f (1,count) = do-          mts <- MoveTo . U.fromList . map (both unzig) <$> pairs (take (count * 2) ns)-          (mts :) <$> commands (drop (count * 2) ns)-        f (2,count) = do-          mts <- LineTo . U.fromList . map (both unzig) <$> pairs (take (count * 2) ns)-          (mts :) <$> commands (drop (count * 2) ns)-        f (7,_) = (ClosePath :) <$> commands ns-        f _ = Left "Sentinel: You should never see this."---- | Convert a list of parsed `Command`s back into their original Command--- and Z-encoded Parameter integer forms.-uncommands :: [Command] -> [Word32]-uncommands = U.toList . U.concat . map f-  where f (MoveTo ps) = (U.cons $ unparseCmd (1, U.length ps)) $ params ps-        f (LineTo ls) = (U.cons $ unparseCmd (2, U.length ls)) $ params ls-        f ClosePath = U.singleton $ unparseCmd (7,1)  -- ClosePath, Count 1.--{- UTIL -}---- | Transform a `V.Vector` of `Point`s into one of Z-encoded Parameter ints.-params :: U.Vector (Int,Int) -> U.Vector Word32-params = U.foldr (\(a,b) acc -> U.cons (zig a) $ U.cons (zig b) acc) U.empty---- | Expand a pair of diffs from some reference point into that--- of a `Point` value. The reference point is moved to our new `Point`.-expand :: (Int,Int) -> State (Int,Int) Point-expand p = do-  curr <- get-  let here = (x p + x curr, y p + y curr)-  put here-  pure here---- | Collapse a given `Point` into a pair of diffs, relative to--- the previous point in the sequence. The reference point is moved--- to the `Point` given.-collapse :: Point -> State (Int,Int) (Int,Int)-collapse p = do-  curr <- get-  let diff = (x p - x curr, y p - y curr)-  put p-  pure diff
+ Geography/VectorTile/Protobuf.hs view
@@ -0,0 +1,473 @@+{-# LANGUAGE StrictData #-}+{-# LANGUAGE DataKinds #-}+{-# LANGUAGE DeriveGeneric #-}+{-# LANGUAGE TypeSynonymInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE QuasiQuotes #-}+{-# LANGUAGE OverloadedStrings #-}++-- |+-- Module    : Geography.VectorTile.Raw+-- Copyright : (c) Azavea, 2016+-- License   : Apache 2+-- Maintainer: Colin Woodbury <cwoodbury@azavea.com>+--+-- Raw Vector Tile data is stored as binary protobuf data.+-- This module reads and writes raw protobuf ByteStrings between a data type+-- which closely matches the current Mapbox vector tile spec defined here:+-- https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto+--+-- As this raw version of the data is hard to work with, in practice we convert+-- to a more canonical Haskell type for further processing.+-- See `Geography.VectorTile` for the user-friendly version.+--+-- Please import this module @qualified@ to avoid namespace clashes:+--+-- > import qualified Geography.VectorTile.Protobuf as PB++module Geography.VectorTile.Protobuf+  ( -- * Types+    RawVectorTile(..)+  , RawLayer(..)+  , RawVal(..)+  , RawFeature(..)+  , GeomType(..)+  , ProtobufGeom(..)+    -- * Commands+  , Command(..)+  , commands+  , uncommands+   -- * Z-Encoding+  , zig+  , unzig+    -- * Protobuf Conversions+    -- ** From Protobuf+    -- | Generally the `tile` function is the only one needed here. Usage:+    --+    -- > import qualified Geography.VectorTile.Protobuf as PB+    -- >+    -- > PB.decode someBytes >>= PB.tile+    --+    -- Note that since the "Data.ProtocolBuffers" library does not handle default+    -- values, we handle those specifically defined in /vector_tile.proto/+    -- explicitely here. See:+    --+    -- https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto+  , tile+  , layer+  , features+  , value+    -- ** To Protobuf+    -- | To convert from high-level data back into a form that can be encoded+    -- into raw protobuf bytes, use:+    --+    -- > import qualified Geography.VectorTile.Protobuf as PB+    -- >+    -- > PB.encode $ PB.untile someTile+    --+    -- This is a pure process and will succeed every time.+  , untile+  , unlayer+  , unfeature+  , unval+    -- * ByteString Encoding / Decoding+  , decode+  , encode+  , decodeIO+  , encodeIO+  ) where++import           Control.Applicative ((<|>))+import           Control.DeepSeq (NFData)+import           Control.Monad.Trans.State.Lazy+import           Data.Bits+import qualified Data.ByteString as BS+import           Data.Foldable (foldrM, foldlM)+import           Data.Int+import           Data.List (nub, elemIndex)+import qualified Data.Map.Lazy as M+import           Data.Maybe (fromJust)+import           Data.Monoid+import           Data.ProtocolBuffers hiding (decode, encode)+import           Data.Serialize.Get+import           Data.Serialize.Put+import qualified Data.Set as S+import           Data.Text (Text, pack)+import qualified Data.Vector as V+import qualified Data.Vector.Unboxed as U+import           Data.Word+import           GHC.Generics (Generic)+import qualified Geography.VectorTile.VectorTile as VT+import qualified Geography.VectorTile.Geometry as G+import           Geography.VectorTile.Util+import           Text.Printf.TH++---++-- | A list of `RawLayer`s.+data RawVectorTile = RawVectorTile { _layers :: Repeated 3 (Message RawLayer) }+                   deriving (Generic,Show,Eq)++instance Encode RawVectorTile+instance Decode RawVectorTile+instance NFData RawVectorTile++-- | Contains a pseudo-map of metadata, to be shared across all `RawFeature`s+-- of this `RawLayer`.+data RawLayer = RawLayer { _version :: Required 15 (Value Word32)+                         , _name :: Required 1 (Value Text)+                         , _features :: Repeated 2 (Message RawFeature)+                         , _keys :: Repeated 3 (Value Text)+                         , _values :: Repeated 4 (Message RawVal)+                         , _extent :: Optional 5 (Value Word32)+                         } deriving (Generic,Show,Eq)++instance Encode RawLayer+instance Decode RawLayer+instance NFData RawLayer++-- | The /Value/ types of metadata fields.+data RawVal = RawVal { _string :: Optional 1 (Value Text)+                     , _float :: Optional 2 (Value Float)+                     , _double :: Optional 3 (Value Double)+                     , _int64 :: Optional 4 (Value Int64)+                     , _uint64 :: Optional 5 (Value Word64)+                     , _sint :: Optional 6 (Value (Signed Int64))  -- ^ Z-encoded.+                     , _bool :: Optional 7 (Value Bool)+                     } deriving (Generic,Show,Eq)++instance Encode RawVal+instance Decode RawVal+instance NFData RawVal++-- | A set of geometries unified by some theme.+data RawFeature = RawFeature { _featureId :: Optional 1 (Value Word64)+                             , _tags :: Packed 2 (Value Word32)+                             , _geom :: Optional 3 (Enumeration GeomType)+                             , _geometries :: Packed 4 (Value Word32)+                             } deriving (Generic,Show,Eq)++instance Encode RawFeature+instance Decode RawFeature+instance NFData RawFeature++-- | The four potential Geometry types. The spec allows for encoders to set+-- `Unknown` as the type, but our decoder ignores these.+data GeomType = Unknown | Point | LineString | Polygon+              deriving (Generic,Enum,Show,Eq)++instance Encode GeomType+instance Decode GeomType+instance NFData GeomType++-- | Any classical type considered a GIS "geometry". These must be able+-- to convert between an encodable list of `Command`s.+class ProtobufGeom g where+  fromCommands :: [Command] -> Either Text (V.Vector g)+  toCommands :: V.Vector g -> [Command]+  geomType :: g -> GeomType++-- | A valid `RawFeature` of points must contain a single `MoveTo` command+-- with a count greater than 0.+instance ProtobufGeom G.Point where+  fromCommands (MoveTo ps : []) = Right . U.convert $ evalState (U.mapM expand ps) (0,0)+  fromCommands (c:_) = Left $ [st|Invalid command found in Point feature: %s|] (show c)+  fromCommands [] = Left "No points given!"++  -- | A multipoint geometry must reduce to a single `MoveTo` command.+  toCommands ps = [MoveTo $ evalState (U.mapM collapse $ U.convert ps) (0,0)]++  geomType _ = Point++-- | A valid `RawFeature` of linestrings must contain pairs of:+--+-- A `MoveTo` with a count of 1, followed by one `LineTo` command with+-- a count greater than 0.+instance ProtobufGeom G.LineString where+  fromCommands cs = evalState (f cs) (0,0)+    where f (MoveTo p : LineTo ps : rs) = fmap . V.cons <$> ls <*> f rs+            where ls = G.LineString <$> U.mapM expand (p <> ps)+          f [] = pure $ Right V.empty+          f _  = pure $ Left "LineString decode: Invalid command sequence given."++  toCommands ls = concat $ evalState (mapM f ls) (0,0)+    where f (G.LineString ps) = do+            curr <- get+            let (h,t) = (U.head ps, U.tail ps)+            put h+            l <- U.mapM collapse t+            pure [MoveTo $ U.singleton (G.x h - G.x curr, G.y h - G.y curr), LineTo l]++  geomType _ = LineString++-- | A valid `RawFeature` of polygons must contain at least one sequence of:+--+-- An Exterior Ring, followed by 0 or more Interior Rings.+--+-- Any Ring must have a `MoveTo` with a count of 1, a single `LineTo`+-- with a count of at least 2, and a single `ClosePath` command.+--+-- Performs no sanity checks for malformed Interior Rings.+instance ProtobufGeom G.Polygon where+  fromCommands cs = do+    ps <- evalState (f cs) (0,0)+    let (h,t) = (V.head ps, V.tail ps)+        (ps',p') = runState (foldlM g V.empty t) h+    pure $ V.snoc ps' p'  -- Include the last Exterior Ring worked on.+    where f (MoveTo p : LineTo ps : ClosePath : rs) = do+            curr <- get+            let h = U.head p+                here = (G.x h + G.x curr, G.y h + G.y curr)+            po <- flip U.snoc here <$> U.mapM expand (U.cons h ps)+            fmap (V.cons (G.Polygon po V.empty)) <$> f rs+          f [] = pure $ Right V.empty+          f _  = pure . Left $ [st|Polygon decode: Invalid command sequence given: %s|] (show cs)+          g acc p | G.area p > 0 = do  -- New external rings.+                      curr <- get+                      put p+                      pure $ V.snoc acc curr+                  | otherwise = do  -- Next internal ring.+                      modify (\s -> s { G.inner = V.snoc (G.inner s) p })+                      pure acc++  toCommands ps = concat $ evalState (mapM f ps) (0,0)+    where f (G.Polygon p i) = do+            curr <- get+            let (h,t) = (U.head p, U.tail $ U.init p)  -- Exclude the final point.+            put h+            l <- U.mapM collapse t+            let cs = [MoveTo $ U.singleton (G.x h - G.x curr, G.y h - G.y curr), LineTo l, ClosePath]+            concat . V.cons cs <$> mapM f i++  geomType _ = Polygon++-- | The possible commands, and the values they hold.+data Command = MoveTo (U.Vector (Int,Int))+             | LineTo (U.Vector (Int,Int))+             | ClosePath deriving (Eq,Show)++-- | Z-encode a 64-bit Int.+zig :: Int -> Word32+zig n = fromIntegral $ shift n 1 `xor` shift n (-63)++-- | Decode a Z-encoded Word32 into a 64-bit Int.+unzig :: Word32 -> Int+unzig n = fromIntegral (fromIntegral unzigged :: Int32)+  where unzigged = shift n (-1) `xor` negate (n .&. 1)++-- | Divide a "Command Integer" into its @(Command,Count)@.+parseCmd :: Word32 -> Either Text (Int,Int)+parseCmd n = case (cmd,count) of+  (1,m) -> Right $ both fromIntegral (1,m)+  (2,m) -> Right $ both fromIntegral (2,m)+  (7,1) -> Right (7,1)+  (7,m) -> Left $ "ClosePath was given a parameter count: " <> pack (show m)+  (m,_) -> Left $ [st|Invalid command integer %d found in: %X|] m n+  where cmd = n .&. 7+        count = shift n (-3)++-- | Recombine a Command ID and parameter count into a Command Integer.+unparseCmd :: (Int,Int) -> Word32+unparseCmd (cmd,count) = fromIntegral $ (cmd .&. 7) .|. shift count 3++-- | Attempt to parse a list of Command/Parameter integers, as defined here:+--+-- https://github.com/mapbox/vector-tile-spec/tree/master/2.1#43-geometry-encoding+commands :: [Word32] -> Either Text [Command]+commands [] = Right []+commands (n:ns) = parseCmd n >>= f+  where f (1,count) = do+          mts <- MoveTo . U.fromList . map (both unzig) <$> pairs (take (count * 2) ns)+          (mts :) <$> commands (drop (count * 2) ns)+        f (2,count) = do+          mts <- LineTo . U.fromList . map (both unzig) <$> pairs (take (count * 2) ns)+          (mts :) <$> commands (drop (count * 2) ns)+        f (7,_) = (ClosePath :) <$> commands ns+        f _ = Left "Sentinel: You should never see this."++-- | Convert a list of parsed `Command`s back into their original Command+-- and Z-encoded Parameter integer forms.+uncommands :: [Command] -> [Word32]+uncommands = U.toList . U.concat . map f+  where f (MoveTo ps) = (U.cons $ unparseCmd (1, U.length ps)) $ params ps+        f (LineTo ls) = (U.cons $ unparseCmd (2, U.length ls)) $ params ls+        f ClosePath = U.singleton $ unparseCmd (7,1)  -- ClosePath, Count 1.++-- | Attempt to decode a `BS.ByteString` of raw protobuf data into a mid-level+-- representation of a `RawVectorTile`.+decode :: BS.ByteString -> Either Text RawVectorTile+decode bs = case runGet decodeMessage bs of+  Left e -> Left $ pack e+  Right vt -> Right vt++-- | Encode a mid-level representation of a `RawVectorTile` into raw protobuf data.+encode :: RawVectorTile -> BS.ByteString+encode = runPut . encodeMessage++-- | Given a filename, attempt to decode bytes read from that file.+decodeIO :: FilePath -> IO (Either Text RawVectorTile)+decodeIO = fmap decode . BS.readFile++-- | Write a mid-level representation of a `RawVectorTile` to a file as raw+-- protobuf data.+encodeIO :: RawVectorTile -> FilePath -> IO ()+encodeIO vt fp = BS.writeFile fp $ encode vt++{- FROM PROTOBUF -}++-- | Convert a `RawVectorTile` of parsed protobuf data into a useable+-- `VectorTile`.+tile :: RawVectorTile -> Either Text VT.VectorTile+tile = fmap (VT.VectorTile . V.fromList) . mapM layer . getField . _layers++-- | Convert a single `RawLayer` of parsed protobuf data into a useable+-- `Layer`.+layer :: RawLayer -> Either Text VT.Layer+layer l = do+  (ps,ls,polys) <- features keys vals . getField $ _features l+  pure VT.Layer { VT._version = fromIntegral . getField $ _version l+                , VT._name = getField $ _name l+                , VT._points = ps+                , VT._linestrings = ls+                , VT._polygons = polys+                , VT._extent = maybe 4096 fromIntegral (getField $ _extent l) }+  where keys = getField $ _keys l+        vals = getField $ _values l++-- | Convert a list of `RawFeature`s of parsed protobuf data into `V.Vector`s+-- of each of the three legal `ProtobufGeom` types.+--+-- The long type signature is due to two things:+--+-- 1. `Feature`s are polymorphic at the high level, but not at the parsed+-- protobuf mid-level. In a @[RawFeature]@, there are features of points,+-- linestrings, and polygons all mixed together.+--+-- 2. `RawLayer`s and `RawFeature`s+-- are strongly coupled at the protobuf level. In order to achieve higher+-- compression ratios, `RawLayer`s contain all metadata in key/value lists+-- to be shared across their `RawFeature`s, while those `RawFeature`s store only+-- indices into those lists. As a result, this function needs to be passed+-- those key/value lists from the parent `RawLayer`, and a more isomorphic:+--+-- > feature :: ProtobufGeom g => RawFeature -> Either Text (Feature g)+--+-- is not possible.+features :: [Text] -> [RawVal] -> [RawFeature]+  -> Either Text (V.Vector (VT.Feature G.Point), V.Vector (VT.Feature G.LineString), V.Vector (VT.Feature G.Polygon))+features _ _ [] = Left "VectorTile.features: `[RawFeature]` empty"+features keys vals fs = (,,) <$> ps <*> ls <*> polys+  where -- (_:ps':ls':polys':_) = groupBy sameGeom $ sortOn geomBias fs  -- ok ok ok+        ps = foldrM f V.empty $ filter (\fe -> getField (_geom fe) == Just Point) fs+        ls = foldrM f V.empty $ filter (\fe -> getField (_geom fe) == Just LineString) fs+        polys = foldrM f V.empty $ filter (\fe -> getField (_geom fe) == Just Polygon) fs++        f :: ProtobufGeom g => RawFeature -> V.Vector (VT.Feature g) -> Either Text (V.Vector (VT.Feature g))+        f x acc = do+          geos <- commands (getField $ _geometries x) >>= fromCommands+          meta <- getMeta keys vals . getField $ _tags x+          pure $ VT.Feature { VT._featureId = maybe 0 fromIntegral . getField $ _featureId x+                            , VT._metadata = meta+                            , VT._geometries = geos+                            } `V.cons` acc++-- | Convert a `RawVal` parsed from protobuf data into a useable+-- `Val`. The higher-level `Val` type better expresses the mutual exclusivity+-- of the /Value/ types.+value :: RawVal -> Either Text VT.Val+value v = mtoe "Value decode: No legal Value type offered" $ fmap VT.St (getField $ _string v)+  <|> fmap VT.Fl  (getField $ _float v)+  <|> fmap VT.Do  (getField $ _double v)+  <|> fmap VT.I64 (getField $ _int64 v)+  <|> fmap VT.W64 (getField $ _uint64 v)+  <|> fmap (\(Signed n) -> VT.S64 n) (getField $ _sint v)+  <|> fmap VT.B   (getField $ _bool v)++getMeta :: [Text] -> [RawVal] -> [Word32] -> Either Text (M.Map Text VT.Val)+getMeta keys vals tags = do+  kv <- map (both fromIntegral) <$> pairs tags+  foldrM (\(k,v) acc -> (\v' -> M.insert (keys !! k) v' acc) <$> (value $ vals !! v)) M.empty kv++{- TO PROTOBUF -}++-- | Encode a high-level `VectorTile` back into its mid-level+-- `RawVectorTile` form.+untile :: VT.VectorTile -> RawVectorTile+untile vt = RawVectorTile { _layers = putField . V.toList . V.map unlayer $ VT._layers vt }++-- Has to get back all its metadata from its features+-- | Encode a high-level `Layer` back into its mid-level `RawLayer` form.+unlayer :: VT.Layer -> RawLayer+unlayer l = RawLayer { _version = putField . fromIntegral $ VT._version l+                     , _name = putField $ VT._name l+                     , _features = putField fs+                     , _keys = putField ks+                     , _values = putField $ map unval vs+                     , _extent = putField . Just . fromIntegral $ VT._extent l }+  where (ks,vs) = totalMeta (VT._points l) (VT._linestrings l) (VT._polygons l)+        fs = V.toList $ V.concat [ V.map (unfeature ks vs) (VT._points l)+                                 , V.map (unfeature ks vs) (VT._linestrings l)+                                 , V.map (unfeature ks vs) (VT._polygons l) ]++totalMeta :: V.Vector (VT.Feature G.Point) -> V.Vector (VT.Feature G.LineString) -> V.Vector (VT.Feature G.Polygon) -> ([Text], [VT.Val])+totalMeta ps ls polys = (keys, vals)+  where keys = S.toList . S.unions $ f ps <> f ls <> f polys+        vals = nub . concat $ g ps <> g ls <> g polys  -- `nub` is O(n^2)+        f = V.foldr (\x acc -> M.keysSet (VT._metadata x) : acc) []+        g = V.foldr (\x acc -> M.elems (VT._metadata x) : acc) []++-- | Encode a high-level `Feature` back into its mid-level `RawFeature` form.+unfeature :: ProtobufGeom g => [Text] -> [VT.Val] -> VT.Feature g -> RawFeature+unfeature keys vals fe = RawFeature+                         { _featureId = putField . Just . fromIntegral $ VT._featureId fe+                         , _tags = putField $ tags fe+                         , _geom = putField . Just . geomType . V.head $ VT._geometries fe+                         , _geometries = putField . uncommands . toCommands $ VT._geometries fe+                         }+  where tags = unpairs . map f . M.toList . VT._metadata+        f (k,v) = both (fromIntegral . fromJust) (k `elemIndex` keys, v `elemIndex` vals)++-- | Encode a high-level `Val` back into its mid-level `RawVal` form.+unval :: VT.Val -> RawVal+unval (VT.St v)  = def { _string = putField $ Just v }+unval (VT.Fl v)  = def { _float = putField $ Just v }+unval (VT.Do v)  = def { _double = putField $ Just v }+unval (VT.I64 v) = def { _int64 = putField $ Just v }+unval (VT.W64 v) = def { _uint64 = putField $ Just v }+unval (VT.S64 v) = def { _sint = putField . Just $ Signed v }+unval (VT.B v)   = def { _bool = putField $ Just v }++{- UTIL -}++-- | A `RawVal` with every entry set to `Nothing`.+def :: RawVal+def = RawVal { _string = putField Nothing+             , _float  = putField Nothing+             , _double = putField Nothing+             , _int64  = putField Nothing+             , _uint64 = putField Nothing+             , _sint   = putField Nothing+             , _bool   = putField Nothing }++-- | Transform a `V.Vector` of `Point`s into one of Z-encoded Parameter ints.+params :: U.Vector (Int,Int) -> U.Vector Word32+params = U.foldr (\(a,b) acc -> U.cons (zig a) $ U.cons (zig b) acc) U.empty++-- | Expand a pair of diffs from some reference point into that+-- of a `Point` value. The reference point is moved to our new `Point`.+expand :: (Int,Int) -> State (Int,Int) G.Point+expand p = do+  curr <- get+  let here = (G.x p + G.x curr, G.y p + G.y curr)+  put here+  pure here++-- | Collapse a given `Point` into a pair of diffs, relative to+-- the previous point in the sequence. The reference point is moved+-- to the `Point` given.+collapse :: G.Point -> State (Int,Int) (Int,Int)+collapse p = do+  curr <- get+  let diff = (G.x p - G.x curr, G.y p - G.y curr)+  put p+  pure diff
− Geography/VectorTile/Raw.hs
@@ -1,142 +0,0 @@-{-# LANGUAGE StrictData #-}-{-# LANGUAGE DataKinds #-}-{-# LANGUAGE DeriveGeneric #-}-{-# LANGUAGE TypeSynonymInstances #-}-{-# LANGUAGE FlexibleInstances #-}---- |--- Module    : Geography.VectorTile.Raw--- Copyright : (c) Azavea, 2016--- License   : Apache 2--- Maintainer: Colin Woodbury <cwoodbury@azavea.com>------ Raw Vector Tile data is stored as binary protobuf data.--- This module reads and writes raw protobuf ByteStrings between a data type--- which closely matches the current Mapbox vector tile spec defined here:--- https://github.com/mapbox/vector-tile-spec/blob/master/2.1/vector_tile.proto------ As this raw version of the data is hard to work with, in practice we convert--- to a more canonical Haskell type for further processing.--- See `Geography.VectorTile` for the user-friendly version.------ Please import this module @qualified@ to avoid namespace clashes:------ > import qualified Geography.VectorTile.Raw as R--module Geography.VectorTile.Raw-  ( -- * Types-    RawVectorTile(..)-  , RawLayer(..)-  , RawVal(..)-  , RawFeature(..)-  , GeomType(..)-  , Geom(..)-    -- * Encoding / Decoding-  , decode-  , encode-  , decodeIO-  , encodeIO-  ) where--import           Control.DeepSeq (NFData)-import qualified Data.ByteString as BS-import           Data.Int-import           Data.ProtocolBuffers hiding (decode, encode)-import           Data.Serialize.Get-import           Data.Serialize.Put-import           Data.Text (Text, pack)-import           Data.Word-import           GHC.Generics (Generic)-import qualified Geography.VectorTile.Geometry as G--------- | A list of `RawLayer`s.-data RawVectorTile = RawVectorTile { layers :: Repeated 3 (Message RawLayer) }-                   deriving (Generic,Show,Eq)--instance Encode RawVectorTile-instance Decode RawVectorTile-instance NFData RawVectorTile---- | Contains a pseudo-map of metadata, to be shared across all `RawFeature`s--- of this `RawLayer`.-data RawLayer = RawLayer { version :: Required 15 (Value Word32)-                         , name :: Required 1 (Value Text)-                         , features :: Repeated 2 (Message RawFeature)-                         , keys :: Repeated 3 (Value Text)-                         , values :: Repeated 4 (Message RawVal)-                         , extent :: Optional 5 (Value Word32)-                         } deriving (Generic,Show,Eq)--instance Encode RawLayer-instance Decode RawLayer-instance NFData RawLayer---- | The /Value/ types of metadata fields.-data RawVal = RawVal { string :: Optional 1 (Value Text)-                     , float :: Optional 2 (Value Float)-                     , double :: Optional 3 (Value Double)-                     , int64 :: Optional 4 (Value Int64)-                     , uint64 :: Optional 5 (Value Word64)-                     , sint :: Optional 6 (Value (Signed Int64))  -- ^ Z-encoded.-                     , bool :: Optional 7 (Value Bool)-                     } deriving (Generic,Show,Eq)--instance Encode RawVal-instance Decode RawVal-instance NFData RawVal---- | A set of geometries unified by some theme.-data RawFeature = RawFeature { featureId :: Optional 1 (Value Word64)-                             , tags :: Packed 2 (Value Word32)-                             , geom :: Optional 3 (Enumeration GeomType)-                             , geometries :: Packed 4 (Value Word32)-                             } deriving (Generic,Show,Eq)--instance Encode RawFeature-instance Decode RawFeature-instance NFData RawFeature---- | The four potential Geometry types. The spec allows for encoders to set--- `Unknown` as the type, but our decoder ignores these.-data GeomType = Unknown | Point | LineString | Polygon-              deriving (Generic,Enum,Show,Eq)--instance Encode GeomType-instance Decode GeomType-instance NFData GeomType---- | A `Geom` can recover its `GeomType` from its `G.Geometry` instance.-class G.Geometry g => Geom g where-  -- | The @g@ here is a proxy argument to discern the type.-  geomType :: g -> GeomType--instance Geom G.Point where-  geomType _ = Point--instance Geom G.LineString where-  geomType _ = LineString--instance Geom G.Polygon where-  geomType _ = Polygon---- | Attempt to decode a `BS.ByteString` of raw protobuf data into a mid-level--- representation of a `RawVectorTile`.-decode :: BS.ByteString -> Either Text RawVectorTile-decode bs = case runGet decodeMessage bs of-  Left e -> Left $ pack e-  Right vt -> Right vt---- | Encode a mid-level representation of a `RawVectorTile` into raw protobuf data.-encode :: RawVectorTile -> BS.ByteString-encode = runPut . encodeMessage---- | Given a filename, attempt to decode bytes read from that file.-decodeIO :: FilePath -> IO (Either Text RawVectorTile)-decodeIO = fmap decode . BS.readFile---- | Write a mid-level representation of a `RawVectorTile` to a file as raw--- protobuf data.-encodeIO :: RawVectorTile -> FilePath -> IO ()-encodeIO vt fp = BS.writeFile fp $ encode vt
+ Geography/VectorTile/VectorTile.hs view
@@ -0,0 +1,145 @@+{-# LANGUAGE StrictData #-}+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE DeriveGeneric #-}++-- |+-- Module    : Geography.VectorTile.VectorTile+-- Copyright : (c) Azavea, 2016+-- License   : Apache 2+-- Maintainer: Colin Woodbury <cwoodbury@azavea.com>+--+-- High-level types for representing Vector Tiles.++module Geography.VectorTile.VectorTile+  ( -- * Types+    VectorTile(..)+  , Layer(..)+  , Feature(..)+  , Val(..)+    -- * Lenses+    -- | This section can be safely ignored if one isn't concerned with lenses.+    -- Otherwise, see the following for a good primer on Haskell lenses:+    -- http://hackage.haskell.org/package/lens-tutorial-1.0.1/docs/Control-Lens-Tutorial.html+    --+    -- These lenses are written in a generic way to avoid taking a dependency+    -- on one of the lens libraries.+  , layers+  , version+  , name+  , points+  , linestrings+  , polygons+  , extent+  , featureId+  , metadata+  , geometries+  ) where++import           Control.DeepSeq (NFData)+import           Data.Int+import qualified Data.Map.Lazy as M+import           Data.Text (Text)+import qualified Data.Vector as V+import           Data.Word+import           GHC.Generics (Generic)+import           Geography.VectorTile.Geometry++---++-- | A high-level representation of a Vector Tile. At its simplest, a tile+-- is just a list of `Layer`s.+--+-- There is potential to implement `_layers` as a `M.Map`, with its String-based+-- `name` as a key.+newtype VectorTile = VectorTile { _layers :: V.Vector Layer } deriving (Eq,Show,Generic)++-- | > Lens' VectorTile (Vector Layer)+layers :: Functor f => (V.Vector Layer -> f (V.Vector Layer)) -> VectorTile -> f VectorTile+layers f v = VectorTile <$> f (_layers v)+{-# INLINE layers #-}++instance NFData VectorTile++-- | A layer, which could contain any number of `Feature`s of any `Geometry` type.+-- This codec only respects the canonical three `Geometry` types, and we split+-- them here explicitely to allow for more fine-grained access to each type.+data Layer = Layer { _version :: Int  -- ^ The version of the spec we follow. Should always be 2.+                   , _name :: Text+                   , _points :: V.Vector (Feature Point)+                   , _linestrings :: V.Vector (Feature LineString)+                   , _polygons :: V.Vector (Feature Polygon)+                   , _extent :: Int  -- ^ Default: 4096+                   } deriving (Eq,Show,Generic)++-- | > Lens' Layer Int+version :: Functor f => (Int -> f Int) -> Layer -> f Layer+version f l = fmap (\v -> l { _version = v }) $ f (_version l)+{-# INLINE version #-}++-- | > Lens' Layer Text+name :: Functor f => (Text -> f Text) -> Layer -> f Layer+name f l = fmap (\v -> l { _name = v }) $ f (_name l)+{-# INLINE name #-}++-- | > Lens' Layer (Vector (Feature Point))+points :: Functor f => (V.Vector (Feature Point) -> f (V.Vector (Feature Point))) -> Layer -> f Layer+points f l = fmap (\v -> l { _points = v }) $ f (_points l)+{-# INLINE points #-}++-- | > Lens' Layer (Vector (Feature LineString)))+linestrings :: Functor f => (V.Vector (Feature LineString) -> f (V.Vector (Feature LineString))) -> Layer -> f Layer+linestrings f l = fmap (\v -> l { _linestrings = v }) $ f (_linestrings l)+{-# INLINE linestrings #-}++-- | > Lens' Layer (Vector (Feature Polygon)))+polygons :: Functor f => (V.Vector (Feature Polygon) -> f (V.Vector (Feature Polygon))) -> Layer -> f Layer+polygons f l = fmap (\v -> l { _polygons = v }) $ f (_polygons l)+{-# INLINE polygons #-}++-- | > Lens' Layer Int+extent :: Functor f => (Int -> f Int) -> Layer -> f Layer+extent f l = fmap (\v -> l { _extent = v }) $ f (_extent l)+{-# INLINE extent #-}++instance NFData Layer++-- | A geographic feature. Features are a set of geometries that share+-- some common theme:+--+-- * Points: schools, gas station locations, etc.+-- * LineStrings: Roads, power lines, rivers, etc.+-- * Polygons: Buildings, water bodies, etc.+--+-- Where, for instance, all school locations may be stored as a single+-- `Feature`, and no `Point` within that `Feature` would represent anything+-- else.+--+-- Note: Each `Geometry` type and their /Multi*/ counterpart are considered+-- the same thing, as a `V.Vector` of that `Geometry`.+data Feature g = Feature { _featureId :: Int  -- ^ Default: 0+                         , _metadata :: M.Map Text Val+                         , _geometries :: V.Vector g } deriving (Eq,Show,Generic)++-- | > Lens' (Feature g) Int+featureId :: Functor f => (Int -> f Int) -> Feature g -> f (Feature g)+featureId f l = fmap (\v -> l { _featureId = v }) $ f (_featureId l)+{-# INLINE featureId #-}++-- | > Lens' (Feature g) (Map Text Val)+metadata :: Functor f => (M.Map Text Val -> f (M.Map Text Val)) -> Feature g -> f (Feature g)+metadata f l = fmap (\v -> l { _metadata = v }) $ f (_metadata l)+{-# INLINE metadata #-}++-- | > Lens' (Feature g) (Vector g)+geometries :: Functor f => (V.Vector g -> f (V.Vector g)) -> Feature g -> f (Feature g)+geometries f l = fmap (\v -> l { _geometries = v }) $ f (_geometries l)+{-# INLINE geometries #-}++instance NFData g => NFData (Feature g)++-- | Legal Metadata /Value/ types. Note that `S64` are Z-encoded automatically+-- by the underlying "Data.ProtocolBuffers" library.+data Val = St Text | Fl Float | Do Double | I64 Int64 | W64 Word64 | S64 Int64 | B Bool+         deriving (Eq,Show,Generic)++instance NFData Val
bench/Bench.hs view
@@ -4,7 +4,7 @@ import           Criterion.Main import qualified Data.ByteString as BS import           Geography.VectorTile-import qualified Geography.VectorTile.Raw as R+import qualified Geography.VectorTile.Protobuf as R  --- @@ -13,9 +13,9 @@   op <- BS.readFile "test/onepoint.mvt"   ls <- BS.readFile "test/linestring.mvt"   rd <- BS.readFile "test/roads.mvt"-  let op' = fromRight $ R.decode op >>= tile-      ls' = fromRight $ R.decode ls >>= tile-      rd' = fromRight $ R.decode rd >>= tile+  let op' = fromRight $ R.decode op >>= R.tile+      ls' = fromRight $ R.decode ls >>= R.tile+      rd' = fromRight $ R.decode rd >>= R.tile   defaultMain [ bgroup "Decoding"                 [ bgroup "onepoint.mvt" $ decodes op                 , bgroup "linestring.mvt" $ decodes ls@@ -30,12 +30,12 @@  decodes :: BS.ByteString -> [Benchmark] decodes bs = [ bench "Raw.VectorTile" $ nf R.decode bs-             , bench "VectorTile" $ nf (R.decode >=> tile) bs+             , bench "VectorTile" $ nf (R.decode >=> R.tile) bs              ]  encodes :: VectorTile -> [Benchmark]-encodes vt = [ bench "Raw.VectorTile" $ nf untile vt-             , bench "ByteString" $ nf (R.encode . untile) vt+encodes vt = [ bench "Raw.VectorTile" $ nf R.untile vt+             , bench "ByteString" $ nf (R.encode . R.untile) vt              ]  fromRight :: Either a b -> b
test/Test.hs view
@@ -9,7 +9,7 @@ import           Data.ProtocolBuffers import           Data.Serialize.Get import           Data.Serialize.Put-import qualified Geography.VectorTile.Raw as R+import qualified Geography.VectorTile.Protobuf as R import           Test.Tasty import           Test.Tasty.HUnit import           Geography.VectorTile@@ -90,7 +90,7 @@ tileDecode :: BS.ByteString -> Assertion tileDecode bs = case decodeIt bs of   Left e -> assertFailure e-  Right t -> assert . isRight $ tile t+  Right t -> assert . isRight $ R.tile t  fromRaw :: BS.ByteString -> Assertion fromRaw vt = case decodeIt vt of@@ -124,116 +124,116 @@ rawTest = decodeIt <$> BS.readFile "onepoint.mvt"  encodeIso :: R.RawVectorTile -> Assertion-encodeIso vt = assert . isRight . fmap untile $ tile vt+encodeIso vt = assert . isRight . fmap R.untile $ R.tile vt  testTile :: R.RawVectorTile testTile = R.RawVectorTile $ putField [l]-  where l = R.RawLayer { R.version = putField 2-                       , R.name = putField "testlayer"-                       , R.features = putField [f]-                       , R.keys = putField ["somekey"]-                       , R.values = putField [v]-                       , R.extent = putField $ Just 4096+  where l = R.RawLayer { R._version = putField 2+                       , R._name = putField "testlayer"+                       , R._features = putField [f]+                       , R._keys = putField ["somekey"]+                       , R._values = putField [v]+                       , R._extent = putField $ Just 4096                        }-        f = R.RawFeature { R.featureId = putField $ Just 0-                         , R.tags = putField [0,0]-                         , R.geom = putField $ Just R.Point-                         , R.geometries = putField [9, 50, 34]  -- MoveTo(+25,+17)+        f = R.RawFeature { R._featureId = putField $ Just 0+                         , R._tags = putField [0,0]+                         , R._geom = putField $ Just R.Point+                         , R._geometries = putField [9, 50, 34]  -- MoveTo(+25,+17)                          }-        v = R.RawVal { R.string = putField $ Just "Some Value"-                     , R.float = putField Nothing-                     , R.double = putField Nothing-                     , R.int64 = putField Nothing-                     , R.uint64 = putField Nothing-                     , R.sint = putField Nothing-                     , R.bool = putField Nothing+        v = R.RawVal { R._string = putField $ Just "Some Value"+                     , R._float = putField Nothing+                     , R._double = putField Nothing+                     , R._int64 = putField Nothing+                     , R._uint64 = putField Nothing+                     , R._sint = putField Nothing+                     , R._bool = putField Nothing                      }  -- | Correct decoding of `onepoint.mvt` onePoint :: R.RawVectorTile onePoint = R.RawVectorTile $ putField [l]-  where l = R.RawLayer { R.version = putField 1-                       , R.name = putField "OnePoint"-                       , R.features = putField [f]-                       , R.keys = putField []-                       , R.values = putField []-                       , R.extent = putField $ Just 4096+  where l = R.RawLayer { R._version = putField 1+                       , R._name = putField "OnePoint"+                       , R._features = putField [f]+                       , R._keys = putField []+                       , R._values = putField []+                       , R._extent = putField $ Just 4096                        }-        f = R.RawFeature { R.featureId = putField Nothing-                         , R.tags = putField []-                         , R.geom = putField $ Just R.Point-                         , R.geometries = putField [9, 10, 10]  -- MoveTo(+5,+5)+        f = R.RawFeature { R._featureId = putField Nothing+                         , R._tags = putField []+                         , R._geom = putField $ Just R.Point+                         , R._geometries = putField [9, 10, 10]  -- MoveTo(+5,+5)                          }  -- | Correct decoding of `linestring.mvt` oneLineString :: R.RawVectorTile oneLineString = R.RawVectorTile $ putField [l]-  where l = R.RawLayer { R.version = putField 1-                       , R.name = putField "OneLineString"-                       , R.features = putField [f]-                       , R.keys = putField []-                       , R.values = putField []-                       , R.extent = putField $ Just 4096+  where l = R.RawLayer { R._version = putField 1+                       , R._name = putField "OneLineString"+                       , R._features = putField [f]+                       , R._keys = putField []+                       , R._values = putField []+                       , R._extent = putField $ Just 4096                        }-        f = R.RawFeature { R.featureId = putField Nothing-                         , R.tags = putField []-                         , R.geom = putField $ Just R.LineString+        f = R.RawFeature { R._featureId = putField Nothing+                         , R._tags = putField []+                         , R._geom = putField $ Just R.LineString                          -- MoveTo(+5,+5), LineTo(+1195,+1195)-                         , R.geometries = putField [9, 10, 10, 10, 2390, 2390]+                         , R._geometries = putField [9, 10, 10, 10, 2390, 2390]                          }  -- | Correct decoding of `polygon.mvt` onePolygon :: R.RawVectorTile onePolygon = R.RawVectorTile $ putField [l]-  where l = R.RawLayer { R.version = putField 1-                       , R.name = putField "OnePolygon"-                       , R.features = putField [f]-                       , R.keys = putField []-                       , R.values = putField []-                       , R.extent = putField $ Just 4096+  where l = R.RawLayer { R._version = putField 1+                       , R._name = putField "OnePolygon"+                       , R._features = putField [f]+                       , R._keys = putField []+                       , R._values = putField []+                       , R._extent = putField $ Just 4096                        }-        f = R.RawFeature { R.featureId = putField Nothing-                         , R.tags = putField []-                         , R.geom = putField $ Just R.Polygon+        f = R.RawFeature { R._featureId = putField Nothing+                         , R._tags = putField []+                         , R._geom = putField $ Just R.Polygon                          -- MoveTo(+2,+2), LineTo(+3,+2), LineTo(-3,+2), ClosePath-                         , R.geometries = putField [9, 4, 4, 18, 6, 4, 5, 4, 15]+                         , R._geometries = putField [9, 4, 4, 18, 6, 4, 5, 4, 15]                          }  zencoding :: Assertion-zencoding = assert $ map (unzig . zig) vs @?= vs+zencoding = assert $ map (R.unzig . R.zig) vs @?= vs   where vs = [0,(-1),1,(-2),2,(-3),3]  commandTest :: Assertion-commandTest = assert $ commands [9,4,4,18,6,4,5,4,15] @?= Right-  [ MoveTo $ U.singleton (2,2)-  , LineTo $ U.fromList [(3,2),(-3,2)]-  , ClosePath ]+commandTest = assert $ R.commands [9,4,4,18,6,4,5,4,15] @?= Right+  [ R.MoveTo $ U.singleton (2,2)+  , R.LineTo $ U.fromList [(3,2),(-3,2)]+  , R.ClosePath ]  commandIso :: Assertion-commandIso = assert $ (uncommands . fromRight $ commands cs) @?= cs+commandIso = assert $ (R.uncommands . fromRight $ R.commands cs) @?= cs   where cs = [9,4,4,18,6,4,5,4,15]  pointIso :: Assertion pointIso = cs' @?= cs   where cs = [17,4,4,6,6]-        cs' = fromRight $ uncommands . toCommands <$> (commands cs >>= fromCommands @Point)+        cs' = fromRight $ R.uncommands . R.toCommands <$> (R.commands cs >>= R.fromCommands @Point)  linestringIso :: Assertion linestringIso = cs' @?= cs   where cs = [9,4,4,18,6,4,5,4,9,4,4,18,6,4,5,4]-        cs' = fromRight $ uncommands . toCommands <$> (commands cs >>= fromCommands @LineString)+        cs' = fromRight $ R.uncommands . R.toCommands <$> (R.commands cs >>= R.fromCommands @LineString)  -- | Two external rings polygonIso :: Assertion polygonIso = cs' @?= cs   where cs = [9,4,4,18,6,4,5,4,15,9,4,4,18,6,4,5,4,15]-        cs' = fromRight $ uncommands . toCommands <$> (commands cs >>= fromCommands @Polygon)+        cs' = fromRight $ R.uncommands . R.toCommands <$> (R.commands cs >>= R.fromCommands @Polygon)  -- | One external, one internal polygonIso2 :: Assertion polygonIso2 = cs' @?= cs   where cs = [9,4,4,26,6,0,0,6,5,0,15,9,2,3,26,0,2,2,0,0,1,15]-        cs' = fromRight $ uncommands . toCommands <$> (commands cs >>= fromCommands @Polygon)+        cs' = fromRight $ R.uncommands . R.toCommands <$> (R.commands cs >>= R.fromCommands @Polygon)  {-} foo :: FilePath -> IO (Either Text VectorTile)
vectortiles.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/  name:                vectortiles-version:             1.0.0+version:             1.1.0 synopsis:            GIS Vector Tiles, as defined by Mapbox. description:         GIS Vector Tiles, as defined by Mapbox.                      .@@ -14,9 +14,9 @@                      .                      The order in which to explore the modules of this library is as follows:                      .-                     1. "Geography.VectorTile" (high-level types and conversion functions)+                     1. "Geography.VectorTile.VectorTile" (high-level types)                      2. "Geography.VectorTile.Geometry" (typical GIS geometry types)-                     3. "Geography.VectorTile.Raw" (mid-level representation of parsed protobuf data)+                     3. "Geography.VectorTile.Protobuf" (mid-level representation of parsed protobuf data with conversion functions)  homepage:            https://github.com/fosskers/vectortiles license:             Apache-2.0@@ -36,7 +36,8 @@  library   exposed-modules:     Geography.VectorTile-                     , Geography.VectorTile.Raw+                     , Geography.VectorTile.VectorTile+                     , Geography.VectorTile.Protobuf                      , Geography.VectorTile.Geometry                      , Geography.VectorTile.Util