{-# LANGUAGE CPP #-}
{-# LANGUAGE OverloadedStrings #-}
module Graphics.Vega.VegaLite.Geometry
( geometry
, geoFeatureCollection
, geometryCollection
, Geometry(..)
, sphere
, graticule
, GraticuleProperty(..)
, projection
, ProjectionProperty(..)
, Projection(..)
, ClipRect(..)
, projectionProperty
) where
import qualified Data.Aeson as A
import qualified Data.Text as T
import Control.Arrow (second)
import Data.Aeson ((.=), object, toJSON)
#if !(MIN_VERSION_base(4, 12, 0))
import Data.Monoid ((<>))
#endif
import Graphics.Vega.VegaLite.Data
( DataValue
, dataValueSpec
)
import Graphics.Vega.VegaLite.Foundation (fromT)
import Graphics.Vega.VegaLite.Specification
( VLProperty(VLData, VLProjection)
, VLSpec
, LabelledSpec
, PropertySpec
)
import Graphics.Vega.VegaLite.Input
( Data
)
type_ :: T.Text -> LabelledSpec
type_ :: Text -> LabelledSpec
type_ Text
t = Text
"type" Text -> Text -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Text
t
geoFeatureCollection :: [VLSpec] -> VLSpec
geoFeatureCollection :: [VLSpec] -> VLSpec
geoFeatureCollection [VLSpec]
geoms =
[LabelledSpec] -> VLSpec
object [ Text -> LabelledSpec
type_ Text
"FeatureCollection"
, Text
"features" Text -> [VLSpec] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [VLSpec]
geoms
]
geometryCollection :: [VLSpec] -> VLSpec
geometryCollection :: [VLSpec] -> VLSpec
geometryCollection [VLSpec]
geoms =
[LabelledSpec] -> VLSpec
object [ Text -> LabelledSpec
type_ Text
"GeometryCollection"
, Text
"geometries" Text -> [VLSpec] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [VLSpec]
geoms
]
data Projection
= Albers
| AlbersUsa
| AzimuthalEqualArea
| AzimuthalEquidistant
| ConicConformal
| ConicEqualArea
| ConicEquidistant
| Custom T.Text
| EqualEarth
| Equirectangular
| Gnomonic
| Identity
| Mercator
| NaturalEarth1
| Orthographic
| Stereographic
| TransverseMercator
projectionLabel :: Projection -> T.Text
projectionLabel :: Projection -> Text
projectionLabel Projection
Albers = Text
"albers"
projectionLabel Projection
AlbersUsa = Text
"albersUsa"
projectionLabel Projection
AzimuthalEqualArea = Text
"azimuthalEqualArea"
projectionLabel Projection
AzimuthalEquidistant = Text
"azimuthalEquidistant"
projectionLabel Projection
ConicConformal = Text
"conicConformal"
projectionLabel Projection
ConicEqualArea = Text
"conicEqualarea"
projectionLabel Projection
ConicEquidistant = Text
"conicEquidistant"
projectionLabel (Custom Text
pName) = Text
pName
projectionLabel Projection
EqualEarth = Text
"equalEarth"
projectionLabel Projection
Equirectangular = Text
"equirectangular"
projectionLabel Projection
Gnomonic = Text
"gnomonic"
projectionLabel Projection
Identity = Text
"identity"
projectionLabel Projection
Mercator = Text
"mercator"
projectionLabel Projection
NaturalEarth1 = Text
"naturalEarth1"
projectionLabel Projection
Orthographic = Text
"orthographic"
projectionLabel Projection
Stereographic = Text
"stereographic"
projectionLabel Projection
TransverseMercator = Text
"transverseMercator"
data ClipRect
= NoClip
| LTRB Double Double Double Double
data ProjectionProperty
= PrType Projection
| PrClipAngle (Maybe Double)
| PrClipExtent ClipRect
| PrCenter Double Double
| PrScale Double
| PrTranslate Double Double
| PrRotate Double Double Double
| PrPrecision Double
| PrReflectX Bool
| PrReflectY Bool
| PrCoefficient Double
| PrDistance Double
| PrFraction Double
| PrLobes Int
| PrParallel Double
| PrRadius Double
| PrRatio Double
| PrSpacing Double
| PrTilt Double
projectionProperty :: ProjectionProperty -> LabelledSpec
projectionProperty :: ProjectionProperty -> LabelledSpec
projectionProperty (PrType Projection
proj) = Text
"type" Text -> Text -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Projection -> Text
projectionLabel Projection
proj
projectionProperty (PrClipAngle Maybe Double
numOrNull) = Text
"clipAngle" Text -> VLSpec -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= VLSpec -> (Double -> VLSpec) -> Maybe Double -> VLSpec
forall b a. b -> (a -> b) -> Maybe a -> b
maybe VLSpec
A.Null Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON Maybe Double
numOrNull
projectionProperty (PrClipExtent ClipRect
rClip) =
(Text
"clipExtent", case ClipRect
rClip of
ClipRect
NoClip -> VLSpec
A.Null
LTRB Double
l Double
t Double
r Double
b -> [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON ((Double -> VLSpec) -> [Double] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map Double -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Double
l, Double
t, Double
r, Double
b])
)
projectionProperty (PrCenter Double
lon Double
lat) = Text
"center" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lon, Double
lat]
projectionProperty (PrScale Double
sc) = Text
"scale" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
sc
projectionProperty (PrTranslate Double
tx Double
ty) = Text
"translate" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
tx, Double
ty]
projectionProperty (PrRotate Double
lambda Double
phi Double
gamma) = Text
"rotate" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lambda, Double
phi, Double
gamma]
projectionProperty (PrPrecision Double
pr) = Text
"precision" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
pr
projectionProperty (PrReflectX Bool
b) = Text
"reflectX" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
b
projectionProperty (PrReflectY Bool
b) = Text
"reflectY" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
b
projectionProperty (PrCoefficient Double
x) = Text
"coefficient" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrDistance Double
x) = Text
"distance" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrFraction Double
x) = Text
"fraction" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrLobes Int
n) = Text
"lobes" Text -> Int -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Int
n
projectionProperty (PrParallel Double
x) = Text
"parallel" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrRadius Double
x) = Text
"radius" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrRatio Double
x) = Text
"ratio" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrSpacing Double
x) = Text
"spacing" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projectionProperty (PrTilt Double
x) = Text
"tilt" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x
projection :: [ProjectionProperty] -> PropertySpec
projection :: [ProjectionProperty] -> PropertySpec
projection [ProjectionProperty]
pProps = (VLProperty
VLProjection, [LabelledSpec] -> VLSpec
object ((ProjectionProperty -> LabelledSpec)
-> [ProjectionProperty] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map ProjectionProperty -> LabelledSpec
projectionProperty [ProjectionProperty]
pProps))
data Geometry
= GeoPoint Double Double
| GeoPoints [(Double, Double)]
| GeoLine [(Double, Double)]
| GeoLines [[(Double, Double)]]
| GeoPolygon [[(Double, Double)]]
| GeoPolygons [[[(Double, Double)]]]
geometry :: Geometry -> [(T.Text, DataValue)] -> VLSpec
geometry :: Geometry -> [(Text, DataValue)] -> VLSpec
geometry Geometry
gType [(Text, DataValue)]
properties =
[LabelledSpec] -> VLSpec
object ([ (Text
"type", Text -> VLSpec
fromT Text
"Feature")
, (Text
"geometry", Geometry -> VLSpec
geometryTypeSpec Geometry
gType) ]
[LabelledSpec] -> [LabelledSpec] -> [LabelledSpec]
forall a. Semigroup a => a -> a -> a
<> if [(Text, DataValue)] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [(Text, DataValue)]
properties
then []
else [(Text
"properties",
[LabelledSpec] -> VLSpec
object (((Text, DataValue) -> LabelledSpec)
-> [(Text, DataValue)] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map ((DataValue -> VLSpec) -> (Text, DataValue) -> LabelledSpec
forall (a :: * -> * -> *) b c d.
Arrow a =>
a b c -> a (d, b) (d, c)
second DataValue -> VLSpec
dataValueSpec) [(Text, DataValue)]
properties))]
)
geometryTypeSpec :: Geometry -> VLSpec
geometryTypeSpec :: Geometry -> VLSpec
geometryTypeSpec Geometry
gType =
let toCoords :: [(Double, Double)] -> VLSpec
toCoords :: [(Double, Double)] -> VLSpec
toCoords = [(Double, Double)] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON
toCoordList :: [[(Double, Double)]] -> VLSpec
toCoordList :: [[(Double, Double)]] -> VLSpec
toCoordList = [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON ([VLSpec] -> VLSpec)
-> ([[(Double, Double)]] -> [VLSpec])
-> [[(Double, Double)]]
-> VLSpec
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ([(Double, Double)] -> VLSpec) -> [[(Double, Double)]] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map [(Double, Double)] -> VLSpec
toCoords
(VLSpec
ptype, VLSpec
cs) = case Geometry
gType of
GeoPoint Double
x Double
y -> (VLSpec
"Point", [Double] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON [Double
x, Double
y])
GeoPoints [(Double, Double)]
coords -> (VLSpec
"MultiPoint", [(Double, Double)] -> VLSpec
toCoords [(Double, Double)]
coords)
GeoLine [(Double, Double)]
coords -> (VLSpec
"LineString", [(Double, Double)] -> VLSpec
toCoords [(Double, Double)]
coords)
GeoLines [[(Double, Double)]]
coords -> (VLSpec
"MultiLineString", [[(Double, Double)]] -> VLSpec
toCoordList [[(Double, Double)]]
coords)
GeoPolygon [[(Double, Double)]]
coords -> (VLSpec
"Polygon", [[(Double, Double)]] -> VLSpec
toCoordList [[(Double, Double)]]
coords)
GeoPolygons [[[(Double, Double)]]]
ccoords -> (VLSpec
"MultiPolygon", [VLSpec] -> VLSpec
forall a. ToJSON a => a -> VLSpec
toJSON (([[(Double, Double)]] -> VLSpec)
-> [[[(Double, Double)]]] -> [VLSpec]
forall a b. (a -> b) -> [a] -> [b]
map [[(Double, Double)]] -> VLSpec
toCoordList [[[(Double, Double)]]]
ccoords))
in [LabelledSpec] -> VLSpec
object [(Text
"type", VLSpec
ptype), (Text
"coordinates", VLSpec
cs)]
sphere :: Data
sphere :: PropertySpec
sphere = (VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"sphere" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
True])
graticule ::
[GraticuleProperty]
-> Data
graticule :: [GraticuleProperty] -> PropertySpec
graticule [] = (VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"graticule" Text -> Bool -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Bool
True])
graticule [GraticuleProperty]
grProps =
(VLProperty
VLData, [LabelledSpec] -> VLSpec
object [Text
"graticule" Text -> VLSpec -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [LabelledSpec] -> VLSpec
object ((GraticuleProperty -> LabelledSpec)
-> [GraticuleProperty] -> [LabelledSpec]
forall a b. (a -> b) -> [a] -> [b]
map GraticuleProperty -> LabelledSpec
graticuleProperty [GraticuleProperty]
grProps)])
data GraticuleProperty
= GrExtent (Double, Double) (Double, Double)
| GrExtentMajor (Double, Double) (Double, Double)
| GrExtentMinor (Double, Double) (Double, Double)
| GrStep (Double, Double)
| GrStepMajor (Double, Double)
| GrStepMinor (Double, Double)
| GrPrecision Double
graticuleProperty :: GraticuleProperty -> LabelledSpec
graticuleProperty :: GraticuleProperty -> LabelledSpec
graticuleProperty (GrExtent (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
Text
"extent" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrExtentMajor (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
Text
"extentMajor" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrExtentMinor (Double
lng1, Double
lat1) (Double
lng2, Double
lat2)) =
Text
"extentMinor" Text -> [[Double]] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [[Double
lng1, Double
lat1], [Double
lng2, Double
lat2]]
graticuleProperty (GrStep (Double
lng, Double
lat)) = Text
"step" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrStepMajor (Double
lng, Double
lat)) = Text
"stepMajor" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrStepMinor (Double
lng, Double
lat)) = Text
"stepMinor" Text -> [Double] -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= [Double
lng, Double
lat]
graticuleProperty (GrPrecision Double
x) = Text
"precision" Text -> Double -> LabelledSpec
forall kv v. (KeyValue kv, ToJSON v) => Text -> v -> kv
.= Double
x