module Data.Internal.Wkb.Line
( 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
getLine :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeospatialGeometry
getLine endianType coordType = do
gl <- getGeoLine endianType coordType
pure $ Geospatial.Line gl
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
getGeoLine :: Endian.EndianType -> Geometry.CoordinateType -> BinaryGet.Get Geospatial.GeoLine
getGeoLine endianType coordType = do
numberOfPoints <- Endian.getFourBytes endianType
if numberOfPoints >= 2 then do
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"
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