Minimalist Layer-level metadata.
Minimalist Layer-level metadata. Necessary for writing layers of VectorTiles.
Clipping Strategies.
"Collator" or "Schema" functions which form
VectorTile
s from collections of GeoTrellis
Feature
s.
"Collator" or "Schema" functions which form
VectorTile
s from collections of GeoTrellis
Feature
s. Any function can be considered a valid "collator" if it
satisfies the type:
collate: (Extent, Iterable[Feature[G,D]]) => VectorTile
Create a VectorTile from some collection of GeoTrellis Geometries:
val tileExtent: Extent = ... // Extent of _this_ Tile val geoms: Iterable[Feature[Geometry, Map[String, String]]] = ... // Some collection of Geometries val tile: VectorTile = Collate.withStringMetadata(tileExtent, geoms)
Create a VectorTile via some custom collation scheme:
def partition(f: Feature[G,D]): String = ... def metadata(d: D): Map[String, Value] = ... val tileExtent: Extent = ... // Extent of _this_ Tile val geoms: Iterable[Feature[G, D]] = ... // Some collection of Geometries val tile: VectorTile = Collate.generically(tileExtent, geoms, partition, metadata)
We provide a few defaults here, but any collation scheme is possible.
Collation just refers to the process of organizing some Iterable
collection of Geometries into various VectorTile Layer
s. Creating your own
collator is done easiest with generically. It expects a partition
function to guide Geometries into separate Layers, and a metadata
transformation function.
A valid partition function must be of the type:
partition: Feature[G,D] => String
The output String is the name of the Layer
you'd like a given
Feature
to be relegated to. Notice that the entire Feature
is available
(i.e. both its Geometry and metadata), so that your partitioner can make
fine-grained choices.
One of these takes your D
type and transforms it into what VectorTile
s expect:
metadata: D => Map[String, Value]
You're encouraged to review the Value
sum-type in
geotrellis.vectortile
VectorTiles require that Polygon exteriors have clockwise winding order,
and that interior holes have counter-clockwise winding order. These assume
that the origin (0,0)
is in the top-left corner.
Any custom collator which does not call generically
must correct
for Polygon winding order manually. This can be done via the vectorpipe.winding
function.
But why correct for winding order at all? Well, OSM data makes no guarantee
about what winding order its derived Polygons will have. We could correct
winding order when our first RDD[OSMFeature]
is created, except that its
unlikely that the clipping process afterward would maintain our winding for
all Polygons.
Given a particular Layout (tile grid), split a collection of Features into a grid of them indexed by SpatialKey.
Given a particular Layout (tile grid), split a collection of Features into a grid of them indexed by SpatialKey.
A clipping strategy defines how Geometries which stretch outside their associated bounding box should be reduced to better fit it. This is benefical, as it saves on storage for large, complex Geometries who only partially intersect some bounding box. The excess points will be cut out, but the "how" is a matter of weighing PROs and CONs in the context of the user's use-case. Several strategies come to mind:
These clipping strategies are defined in vectorpipe.geom.Clip, where you can find further explanation.
A function which represents a "clipping strategy".
An IO function that will log any clipping failures.
The LayoutDefinition defining the area to gridify.
Skip over some failure.
Log an error as an ERROR through Spark's default log4j.
Log an error to STDOUT.
Types and functions unique to working with OpenStreetMap data.
Encode a VectorTile via Avro.
Encode a VectorTile via Avro. This is the glue for Layer IO.
Given a collection of GeoTrellis Feature
s which have been associated
with some SpatialKey
and a "collation" function, form those Feature
s
into a VectorTile
.
Given a collection of GeoTrellis Feature
s which have been associated
with some SpatialKey
and a "collation" function, form those Feature
s
into a VectorTile
.
Ensure a geotrellis.vector.Polygon has the correct winding order to be used in a VectorTile.
Functions to transform RDD
s of Features along the pipeline.
Useful defaults for functions like vectorpipe.grid, where we wish to log small failures and skip them, instead of crashing the entire Spark job.
VectorPipe is a library for mass conversion of Vector data into Mapbox VectorTiles. It is powered by GeoTrellis and Apache Spark.
Outline
GeoTrellis and Spark do most of our work for us. Writing a
main
function that uses VectorPipe need not contain much more than:Writing Portable Tiles
This method outputs VectorTiles to a directory structure appropriate for serving by a Tile Map Server. The VTs themselves are saved in the usual
.mvt
format, and so can be read by any other tool. The example that follows writestiles
from above to an S3 bucket:Writing a GeoTrellis Layer of VectorTiles
The disadvantage of the "Portable Tiles" approach is that there is no way to read the tiles back into a
RDD[(SpatialKey, VectorTile)]
and do Spark-based manipulation operations. To do that, the tiles have to be written as a "GeoTrellis Layer" from the get-go. The output of such a write are split and compressed files that aren't readable by other tools. This method compresses VectorTiles to about half the size of a normal.mvt
.