Releases: locationtech/geotrellis
v2.0.0
Additions
-
geotrellis.spark
- All focal operations now except an optional
partitioner
parameter. BufferTiles.apply
methods and thebufferTiles
methods now except an optionalpartitioner
parameter.CollectionLayerReader
now has an SPI interface.ZoomResample
can now be used onMultibandTileLayerRDD
.Partitioner
can be specified in thereproject
methods ofTileLayerRDD
.- Compression
level
of GeoTiffs can be specified in theDeflateCompression
constructor. resampleMethod
parameter has been added toCOGLayerWriter.Options
.- A new type called
LayerType
has been created to help identify the nature of a layer (either Avro or COG). LayerHeader
now have an additional parameter:layerType
.AttributeStore
now has four new methods:layerType
,isCOGLayer
,readCOGLayerAttributes
, andwriteCOGLayerAttributes
.- Kryo serialization of geometry now uses a binary format to reduce shuffle block size.
- Alter
geotrellis.spark.stitch.StitchRDDMethods
to allowRDD[(K, V)]
to be stitched when not all tiles are of the same dimension. - Introduce
Pyramid
class to provide a convenience wrapper for building raster pyramids. COGValueReader
andOverzoomingCOGValueReader
have thereadSubsetBands
method which allows reading bands subsets.COGLayerReader
now has thereadSubsetBands
andquerySubsetBands
methods which allow users to read in layers with the desired bands in the order they choose.KeyBounds
now has therekey
method that will rekey the bounds from a source layout to a target layout.
- All focal operations now except an optional
-
geotrellis.raster
- Kryo serialization of geometry now uses a binary format to reduce shuffle block size.
GeoTiffMultibandTile
now has anothercrop
method that takes aGridBounds
and anArray[Int]
that represents the band indices.GeoTiff[MultibandTile]
can be written withBandInterleave
, onlyPixelInterleave
previously supported. (#2767)MultibandTile
now has a new method,cropBands
that takes an Array of band indices and returns a croppedMultibandTile
with the chosen bands.
-
geotrellis.spark-etl
Input.partitionBytes
and it is set to134217728
by default to correspondHadoopGeoTiffRDD default behaviour
.Output.bufferSize
option to set up a custom buffer size for the buffered reprojection.
Changes
-
geotrellis.spark
- The length of the key (the space-filling curve index or address) used for layer reading and writing has been extended from a fixed length of 8 bytes to an arbitrary length. This change affects not only the
geotrellis.spark
package, but all backends (excludinggeotrellis.geowave
andgeotrellis.geomesa
). - Reprojection has improved performance due to one less shuffle stage and lower memory usage.
TileRDDReproject
loses dependency onTileReprojectMethods
in favor ofRasterRegionReproject
- The Ascii draw methods are now method extensions of
Tile
. - Replace
geotrellis.util.Functor
withcats.Functor
. - Specifying the
maxTileSize
for a COGLayer that's to be written is now done viaCOGLayerWriter.Options
which can be passed directly to thewrite
methods. - Specifying the
compression
for a COGLayer that's to be written is now done viaCOGLayerWriter.Options
which can be passed directly to thewrite
methods. - The attribute name for
COGLayerStorageMetadata
is nowmetadata
instead ofcog_metadata
. - Scalaz streams were replaced by fs2 streams.
- Refactored
HBaseInstance
, now accepts a plain HadoopConfiguration
object. - Refactored
CassandraInstance
, now accepts agetCluster
function. - Use pureconfig to handle all work with configuration files.
- Removed
LayerUpdater
with its functionality covered byLayerWriter
(#2663).
of the same dimension. - Change
TilerMethods.tileToLayout
functions that acceptTileLayerMetadata
as an argument to returnRDD[(K, V)] with Metadata[M]
instead ofRDD[(K, V)]
. - Expose
attributeStore
parameter to LayerReader interface. - Added exponential backoffs in
S3RDDReader
. - Changed SinglebandGeoTiff and MultibandGeoTiff crop function behaviour to work properly with cases when extent to crop by doesn't intersect tiff extent.
- All classes and objects in the
geowave
package now use the spelling:GeoWave
in their names. TileLayerMetadata.fromRdd
method has been renamed toTileLayerMetadata.fromRDD
.KeyBounds.fromRdd
method has been renamed toKeyBounds.fromRDD
.
- The length of the key (the space-filling curve index or address) used for layer reading and writing has been extended from a fixed length of 8 bytes to an arbitrary length. This change affects not only the
-
geotrellis.raster
- Removed implicit conversion from
Raster[T]
toT
(#2771). - Removed
decompress
option fromGeoTiffReader
functions. - Scalaz streams were replaced by fs2 streams.
- Removed implicit conversion from
-
geotrellis.spark-etl
- Package is deprecated since GeoTrellis 2.0.
Input.maxTileSize
is256
by default to correspondHadoopGeoTiffRDD default behaviour
.
-
geotrellis.slick
geotrellis.slick.Projected
has been moved togeotrellis.vector.Projected
Fixes
- StreamingHistogram.binCount now returns non-zero counts (#2590)
- HilbertSpatialKeyIndex index offset. Existing spatial layers using Hilbert index will need to be updated (#2586)
- Fixed
CastException
that sometimes occured when reading cached attributes. - Uncompressed
GeoTiffMultibandTiles
will now convert to the correctCellType
. - Calculating the Slope of a
Tile
whentargetCell
isData
will now produce the correct result. - Introduce new hooks into
AttributeStore
trait to allow for better performance in certain queries against catalogs with many layers. GeoTiffReader
can now read tiffs that are missing theNewSubfileType
tag.- Pyramiding code will once again respect resampling method and will now actually reduce shuffle volume by resampling
tiles on map side of pyramid operation. COGLayer
attributes can be accessed via the various read attribute methods in
AttributeStore
(iereadMetadata
,readHeader
, etc)- The regex used to match files for the
HadoopLayerAttributeStore
andFileLayerAttributeStore
has been
expanded to include more characters. HadoopAttributeStore.availableAttributes
has been fixed so that it'll now list all attribute files.- Allow for simple features to be generated with a specified or random id with geometry stored in the standard
field, "the_geom" - Update version of Amazon SDK API to remove deprecation warnings.
- Fixed a bug in incorrect metadata fetch by
COGLayerReader
that could lead to an incorrect data querying. - Cropping RDDs with
clamp=false
now produces correct result. - Fixed tiff reads in case
RowsPerStrip
tiff tag is not defined. - Change aspect result to azimuth, i.e. start from due north and be clockwise.
- COG overviews generated in the
COGLayer.fromLayerRDD
method will now use the passed inResampleMethod
. - Reading a GeoTiff with
streaming
will now work with files that are larger thanjava.lang.Integer.MAX_VALUE
. GeoTiffMultibandTile.crop
will now work with GeoTiffs that have tiled segments and band interleave.GeoTiffMultibandTile.crop
will now returnArrayMultibandTile
(s) with the correct number of bands.- Improved performance of
COGValueReader.readSubsetBands
when reading from S3.
1.2.1
1.2.0
API Changes
geotrellis.raster
- Deprecation:
GridBounds.size
in favor ofGridBounds.sizeLong
. - Deprecation:
GridBounds.coords
in favor ofGridBounds.coordsIter
. - New:
GridBounds.offset
andGridBounds.buffer
for creating a modifiedGridBounds
from an existing one. - New:
ColorRamps.greyscale: Int => ColorRamp
, which will generate a ramp when given some number of stops. - New:
ConstantTile.fromBytes
to create any type ofConstantTile
from anArray[Byte]
. - New:
Tile.rotate90: Int => Tile
,Tile.flipVertical: Tile
andTile.flipHorizontal: Tile
.
- Deprecation:
geotrellis.vector
- New:
Geometry.isEmpty: Boolean
. This incurs much less overhead than previous ways of determining emptiness. - New:
Line.head
andLine.last
for efficiently grabbing the first or lastPoint
in theLine
.
- New:
geotrellis.spark
- Deprecation: The
LayerUpdater
trait hierarchy. UseLayerWriter.update
orLayerWriter.overwrite
instead. - Deprecation: Every cache provided by
geotrellis.spark.util.cache
. These will be removed in favor of a pluggable cache in 2.0. - New:
SpatialKey.extent: LayoutDefinition => Extent
- New:
ValueReader.attributeStore: AttributeStore
- New:
TileLayerRDD.toSpatialReduce: ((V, V) => V) => TileLayerRDD[SpatialKey]
for smarter folding of 3D tile layers into 2D tile layers. - The often-used
apply
method overloads inMapKeyTransform
have been given more descriptive aliases.
- Deprecation: The
geotrellis.vectortile
(experimental)- New:
VectorTile.toGeoJson
andVectorTile.toIterable
. - Library simplified by assuming the codec backend will always be Protobuf.
- New:
New Features
Rasterizing Geometry
Layers
Finally, the full marriage of the vector
, raster
, and spark
packages! You can now transform an RDD[Geometry]
into a writable GeoTrellis layer of (SpatialKey, Tile)
!
val geoms: RDD[Geometry] = ...
val celltype: CellType = ...
val layout: LayoutDefinition = ...
val value: Double = ... /* Value to fill the intersecting pixels with */
val layer: RDD[(SpatialKey, Tile)] with Metadata[LayoutDefinition] =
geoms.rasterize(value, celltype, layout)
Clipping Geometry
Layers to a Grid
In a similar vein to the above, you can now transform an arbitrarily
large collection of Geometries into a proper GeoTrellis layer, where the
sections of each Geometry are clipped to fit inside their enclosing
Extents.
Here we can see a large Line
being clipped into nine sublines. It's
one method call:
import geotrellis.spark._
val layout: LayoutDefinition = ... /* The definition of your grid */
val geoms: RDD[Geometry] = ... /* Result of some previous work */
/* There are likely many clipped Geometries per SpatialKey... */
val layer: RDD[(SpatialKey, Geometry)] = geoms.clipToGrid(layout)
/* ... so we can group them! */
val grouped: RDD[(SpatialKey, Iterable[Geometry])] = layer.groupByKey
If clipping on the Extent boundaries is not what you want, there are ways to customize this. See the ClipToGrid entry in our Scaladocs.
Sparkified Viewshed
A Viewshed shows "visibility" from some set vantage point, given an Elevation raster. Prior to GeoTrellis 1.2 this was possible at the individual Tile
level but not the Layer (RDD
) level. Now it is.
First, we need to think about the Viewpoint
type:
import geotrellis.spark.viewshed._
val point: Viewpoint(
x = ..., // some coordinate.
y = ..., // some coordinate.
viewHeight = 4000, // 4 kilometres above the surface.
angle = Math.PI / 2, // direction that the "camera" faces (in radians). 0 == east.
fieldOfView = Math.PI / 2, // angular width of the "view port".
altitude = 0 // the height of points you're interested in seeing.
)
In other words:
- x, y, viewHeight: where are we?
- angle: what direction are we looking?
- fieldOfView: how wide are we looking?
- altitude: how high/low is the "target" of our viewing?
Given a Seq[Viewpoint]
(the algorithm supports multiple simultaneous
view points), we can do:
// Recall this common alias:
// type TileLayerRDD[K] = RDD[(K, Tile)] with Metadata[TileLayerMetadata[K]]
val layer: TileLayerRDD[SpatialKey] = ... /* Result of previous work */
val viewshed: TileLayerRDD[SpatialKey] = layer.viewshed(Seq(point))
Sparkified Euclidean Distance
We use Euclidean Distance to render a collection of points into a
heatmap of proximities of some area. Say, of two roads crossing:
Prior to GeoTrellis 1.2, this was possible at the individual Tile
level but not the Layer (RDD
) level. Now it is.
/* Result of previous work. Potentially millions of points per SpatialKey. */
val points: RDD[(SpatialKey, Array[Coordinate])] = ...
val layout: LayoutDefinition = ... /* The definition of your grid */
val layer: RDD[(SpatialKey, Tile)] = points.euclideanDistance(layout)
Polygonal Summaries over Time
The following was possible prior to GeoTrellis 1.2:
val layer: TileLayerRDD[SpatialKey] = ...
val polygon: Polgyon = ...
/* The maximum value within some Polygon overlaid on a Tile layer */
val summary: Double = layer.polygonalMaxDouble(polygon)
The above is also now possible for layers keyed by SpaceTimeKey
to
form a "time series":
val layer: TileLayerRDD[SpaceTimeKey] = ...
val polygon: MultiPolygon = ...
/* The maximum value within some Polygonal area at each time slice */
val summary: Map[ZonedDateTime, Double] = layer.maxSeries(polygon)
Overzooming ValueReader
A GeoTrellis ValueReader
connects to some layer catalog and lets you read individual values (usually Tiles):
import geotrellis.spark.io.s3._
val store: AttributeStore = ...
val reader: Reader[SpatialKey, Tile] = S3ValueReader(store).reader(LayerId("my-catalog", 10))
val tile: Tile = reader.read(SpatialKey(10, 10))
However .reader
is limited to zoom levels that actually exist for the given layer. Now you can use .overzoomingReader
to go as deep as you like:
import geotrellis.raster.resample._
val reader: Reader[SpatialKey, Tile] =
S3ValueReader(store).overzoomingReader(LayerId("my-catalog", 20), Average)
val tile: Tile = reader.read(SpatialKey(1000, 1000))
Regridding a Tile Layer
Have you ever wanted to "redraw" a grid over an established GeoTrellis layer? Say, this 16-tile Layer into a 4-tile one, both of 1024x1024 total pixels:
Prior to GeoTrellis 1.2, there was no official way to do this. Now you can use .regrid
:
/* The result of some previous work. Say each Tile is 256x256. */
val layer: TileLayerRDD[SpatialKey] = ...
/* "Recut" the tiles so that each one is now 512x512.
* No pixels are gained or lost, save some NODATA on the bottom
* and right edges that may appear for padding purposes.
*/
val regridded: TileLayerRDD[SpatialKey] = layer.regrid(512)
You can also regrid to non-rectangular sizes:
val regridded: TileLayerRDD[SpatialKey] = layer.regrid(tileCols = 100, tileRows = 300)
Robust Layer Querying
It's common to find a subset of Tiles in a layer that are touched by some given Polygon
:
val poly: Polygon = ???
val rdd: TileLayerRDD[SpatialKey] =
layerReader
.query[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](Layer("name", zoom))
.where(Intersects(poly))
.result
Now you can perform this same operation with Line
, MultiLine
, and even (Polygon, CRS)
to ensure that your Layer and Geometry always exist in the same projection.
Improved Tile
ASCII Art
Sometimes you just want to visualize a Tile
without going through the song-and-dance of rendering it to a .png
. The existing Tile.asciiDraw
method kind of does that, except its output is all in numbers.
The new Tile.renderAscii: Palette => String
method fulfills your heart's desire:
import geotrellis.raster._
import geotrellis.raster.io.geotiff._
import geotrellis.raster.render.ascii._
val tile: Tile = SinglebandGeoTiff("path/to/tiff.tiff").tile
// println(tile.renderAscii()) // the default
println(tile.renderAscii(AsciiArtEncoder.Palette.STIPLED))
▚▖
▚▚▜▚▚
▚▖▚▜▚▖▚▚
▜▚▚▚▜▚█▚▜▚█▚
█▚▜▖▜▖▚▚█▚▚▜▚█▖
▚▚█▚▜▚▚▚▚▚▚▚▜▚▚▚▚▚
▚▚▖▚▚▚▚▚█▜▚▚▜▚▚▖▚▖▚▖▚
▚▚▚▚█▚▚▚▚▚██▚▚▚▜▖▖██▚▚▜▚
▚▚█▚▚▚▚▚▚▚▜▚▚▚▚▚▚▜▚█▚▚▚▚▚▚▚
█▚▚▖▚█▚▜▚▚▚▚▖▚▚▚▚▚▚▚▚▚▚▜▚▚▚▚▚▚▖
█▚▚▚▜▚▖▚▚▚▚▚▚▚▚▚▚▚▚▚▚▚▚▚██▖▜▚█▚▚▚
█▚▚██▚▚▚▚▚▚▚▚▖▚▚▚▚▚▚▚▚█▚▚▚▚▚▚▖▖▖▚▚▚▚
█▜▚▚██▜▚▚▚▜▖▚▚▜▚█▜▚▚▚▜▚▖▚▜▚█▚▚▖▚▚▖▚▚▖▖▚▚
▚▚█▚▚▚█▚██▚▚▚▚▚▚▚▚▜▚▚█▜▚▖█▚▚▚▜▚▚▚▚▚▚▜▚█▚█
█▚▜▚▜▚█▚▜▚▚▜▚█▚▚▚▚▚▚▚▚▚▚▚▖▚▖▚▚▖▚█▚█▚▚▚▖█▚
████▚███▚▚▚▚██▚▚▚█▜▚▚▖▚▚▚▖▖▚▚▚▚▚▚▚▚█▚▜▖█
▖█▜▚█▚██▜▖▜▜█▜▜█▜▚▚▚▚▚█▖▚▚▚▚█▚▚▚▚▚▚▜▚▚█▖▜
▚▖██▚▜▚█▚▚▜▜█▜▜▜██▚▚▚▚█▚▚▚▜▖▚▚█▚▖▚▜▚▚▚▖▚█
█▚▚▚▚▜▚██▖██▜▚▚█▚▚▖▚▚▜▚▖▚▖▚▚▚▚▚▖▚▚▖▖▖▚▖▚
▚▚▚█▚▚▚▚▚█▜▚▚████▚█▚▚▚█▚▖▚▚▚▖▚▚█▚▚▖▚▚▚▖▖▖
▚▚▚█▚▚▚▖▖▚▜█▜██▜██▚▚▖██▜▚▜▚█▚▚▚▚▚▚▚▚▖▖▜██
▚▚▚▚▜█▚▚▚▚▚█████▚▜██▚██▚▚▚▚▜▚▖▚█▚▚▖▚▖▚▚█
▚▚▜▚▚▚▚▜▚▜▚▚▚▚▜▚█▚▜█▚██▚██▚▚▚▚▖▚▚▚▚▖▖▚▚▖█
▚▜▚▜▚▚▚▚▚▚█▚▚▚▚▚██▜▜▜███▖▚▚▜█▚▚▖▚█▚▚█▚▖▚
▚▜▚▚▚▚▚▚▚▚▚▚▜▜▜▚▚▖▚▖▚▚▜▜██▜▚██▚▚▚▚▚▚▖▜█▚
▚▚▖▚▚█▚█▚▚▚█▚▖▚▚▚█▚▚▚▚▚▜██▚█▜▚█▚▜▚▚███▜█▜
▚▚▚▜▚▚▚▚▚▚▚▚▚▚▚▖█▚█▚▚▜█▜█▜█▜▚▖▚▚▚██▜▜█▚▜
▚▚▚▚▜▚▚▚▚▚▚▜▚▚▚▚▚▚▖▚█▜▖▖█▚▖▜▖▚▖█▚▖█▚▚▜▚█
▚▚█▚▚█...