Skip to content

Commit d699a76

Browse files
committed
Added rf_agg_reprojected_extent.
1 parent eb7183a commit d699a76

File tree

10 files changed

+57
-16
lines changed

10 files changed

+57
-16
lines changed

core/src/main/scala/org/locationtech/rasterframes/functions/AggregateFunctions.scala

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
*/
2121

2222
package org.locationtech.rasterframes.functions
23-
import geotrellis.proj4.WebMercator
23+
import geotrellis.proj4.{CRS, WebMercator}
2424
import geotrellis.raster.resample.ResampleMethod
2525
import geotrellis.raster.{IntConstantNoDataCellType, Tile}
2626
import geotrellis.vector.Extent
@@ -29,6 +29,7 @@ import org.locationtech.rasterframes.expressions.accessors.{ExtractTile, GetCRS,
2929
import org.locationtech.rasterframes.expressions.aggregates.TileRasterizerAggregate.ProjectedRasterDefinition
3030
import org.locationtech.rasterframes.expressions.aggregates._
3131
import org.locationtech.rasterframes.stats._
32+
import org.locationtech.rasterframes._
3233

3334
/** Functions associated with computing columnar aggregates over tile and geometry columns. */
3435
trait AggregateFunctions {
@@ -87,17 +88,23 @@ trait AggregateFunctions {
8788
TileRasterizerAggregate(params, tileCRS, tileExtent, tile)
8889
}
8990

91+
import org.apache.spark.sql.functions._
92+
import org.locationtech.rasterframes.encoders.StandardEncoders.extentEncoder
93+
import org.locationtech.rasterframes.util.NamedColumn
9094

91-
/** Compute the aggregate extent over a column. */
95+
/** Compute the aggregate extent over a column. Assumes CRS homogeneity. */
9296
def rf_agg_extent(extent: Column): TypedColumn[Any, Extent] = {
93-
import org.apache.spark.sql.functions._
94-
import org.locationtech.rasterframes.encoders.StandardEncoders.extentEncoder
95-
import org.locationtech.rasterframes.util.NamedColumn
9697
struct(
9798
min(extent.getField("xmin")) as "xmin",
9899
min(extent.getField("ymin")) as "ymin",
99100
max(extent.getField("xmax")) as "xmax",
100101
max(extent.getField("ymax")) as "ymax"
101102
).as(s"rf_agg_extent(${extent.columnName})").as[Extent]
102103
}
104+
105+
/** Compute the aggregate extent over a column after reprojecting from the rows source CRS into the given destination CRS . */
106+
def rf_agg_reprojected_extent(extent: Column, srcCRS: Column, destCRS: CRS): TypedColumn[Any, Extent] =
107+
rf_agg_extent(st_extent(st_reproject(st_geometry(extent), srcCRS, destCRS)))
108+
.as(s"rf_agg_reprojected_extent(${extent.columnName}, ${srcCRS.columnName}, $destCRS)")
109+
.as[Extent]
103110
}

core/src/test/scala/org/locationtech/rasterframes/functions/AggregateFunctionsSpec.scala

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,12 +202,24 @@ class AggregateFunctionsSpec extends TestEnvironment with RasterMatchers {
202202
}
203203

204204
describe("geometric aggregates") {
205+
// SQL docs not available until we re-implement as an expression
206+
ignore("should have docs") {
207+
checkDocs("rf_agg_extent")
208+
checkDocs("rf_agg_reprojected_extent")
209+
}
210+
205211
it("should compute an aggregate extent") {
206212
val src = TestData.l8Sample(1)
207213
val df = src.toDF(TileDimensions(10, 10))
208-
df.show(false)
209214
val result = df.select(rf_agg_extent($"extent")).first()
210215
result should be(src.extent)
211216
}
217+
218+
it("should compute a reprojected aggregate extent") {
219+
val src = TestData.l8Sample(1)
220+
val df = src.toDF(TileDimensions(10, 10))
221+
val result = df.select(rf_agg_reprojected_extent($"extent", $"crs", WebMercator)).first()
222+
result should be(src.extent.reproject(src.crs, WebMercator))
223+
}
212224
}
213225
}

docs/src/main/paradox/release-notes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
* Added `withSpatialIndex` to RasterSourceDataSource to pre-partition tiles based on tile extents mapped to a Z2 space-filling curve
1010
* Add `rf_mask_by_bit`, `rf_mask_by_bits` and `rf_local_extract_bits` to deal with bit packed quality masks. Updated the masking documentation to demonstrate the use of these functions.
1111
* Added `toDF` extension method to `MultibandGeoTiff`
12-
* Added `rf_agg_extent` to compute the aggregate extent of a column
12+
* Added `rf_agg_extent` and `rf_agg_reprojected_extent` to compute the aggregate extent of a column
1313
* Added `rf_proj_raster` for constructing a `proj_raster` structure from individual CRS, Extent, and Tile columns.
1414

1515
### 0.8.4

project/RFDependenciesPlugin.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ object RFDependenciesPlugin extends AutoPlugin {
5555
"locationtech-releases" at "https://repo.locationtech.org/content/groups/releases",
5656
"Azavea Public Builds" at "https://dl.bintray.com/azavea/geotrellis",
5757
"boundless-releases" at "https://repo.boundlessgeo.com/main/",
58-
"Open Source Geospatial Foundation Repository" at "http://download.osgeo.org/webdav/geotools/"
58+
"Open Source Geospatial Foundation Repository" at "https://download.osgeo.org/webdav/geotools/"
5959
),
6060

6161
// NB: Make sure to update the Spark version in pyrasterframes/python/setup.py

project/build.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
sbt.version=1.2.8
1+
sbt.version=1.3.4

project/plugins.sbt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
logLevel := sbt.Level.Error
22

3-
addSbtCoursier
43
addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.14.6")
54
addSbtPlugin("com.eed3si9n" % "sbt-buildinfo" % "0.7.0")
65
addSbtPlugin("de.heikoseeberger" % "sbt-header" % "3.0.2")

project/project/plugins.sbt

Lines changed: 0 additions & 1 deletion
This file was deleted.

pyrasterframes/src/main/python/pyrasterframes/rasterfunctions.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@
2727
from pyspark.sql.column import Column, _to_java_column
2828
from pyspark.sql.functions import lit
2929
from .rf_context import RFContext
30-
from .rf_types import CellType, Extent
30+
from .rf_types import CellType, Extent, CRS
3131

3232
THIS_MODULE = 'pyrasterframes'
3333

@@ -338,6 +338,11 @@ def rf_agg_extent(extent_col):
338338
return _apply_column_function('rf_agg_extent', extent_col)
339339

340340

341+
def rf_agg_reprojected_extent(extent_col, src_crs_col, dest_crs):
342+
"""Compute the aggregate extent over a column, first projecting from the row CRS to the destination CRS. """
343+
return Column(RFContext.call('rf_agg_reprojected_extent', _to_java_column(extent_col), _to_java_column(src_crs_col),CRS(dest_crs).__jvm__))
344+
345+
341346
def rf_agg_overview_raster(tile_col: Column, cols: int, rows: int, aoi: Extent,
342347
tile_extent_col: Column = None, tile_crs_col: Column = None):
343348
"""Construct an overview raster of size `cols`x`rows` where data in `proj_raster` intersects the

pyrasterframes/src/main/python/pyrasterframes/rf_types.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,19 @@ def buffer(self, amount):
220220
def __str__(self):
221221
return self.__jvm__.toString()
222222

223+
class CRS(object):
224+
def __init__(self, proj4_str):
225+
self.proj4_str = proj4_str
226+
227+
@cached_property
228+
def __jvm__(self):
229+
comp = RFContext.active().companion_of("org.locationtech.rasterframes.model.LazyCRS")
230+
return comp.apply(self.proj4_str)
231+
232+
def __str__(self):
233+
return self.proj4_str
234+
235+
223236
class CellType(object):
224237
def __init__(self, cell_type_name):
225238
self.cell_type_name = cell_type_name

pyrasterframes/src/main/python/tests/VectorTypesTests.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -195,8 +195,14 @@ def test_z2_index(self):
195195

196196
def test_agg_extent(self):
197197
r = self.df.select(rf_agg_extent(st_extent('poly_geom')).alias('agg_extent')).select('agg_extent.*').first()
198-
self.assertDictEqual(r.asDict(),
199-
Row(xmin=-0.011268955205879273, ymin=-4.011268955205879, xmax=3.0112432169934484,
200-
ymax=-0.9887567830065516).asDict()
201-
)
198+
self.assertDictEqual(
199+
r.asDict(),
200+
Row(xmin=-0.011268955205879273, ymin=-4.011268955205879, xmax=3.0112432169934484, ymax=-0.9887567830065516).asDict()
201+
)
202202

203+
def test_agg_reprojected_extent(self):
204+
r = self.df.select(rf_agg_reprojected_extent(st_extent('poly_geom'), rf_mk_crs("EPSG:4326"), "EPSG:3857")).first()[0]
205+
self.assertDictEqual(
206+
r.asDict(),
207+
Row(xmin=-1254.45435529069, ymin=-446897.63591665257, xmax=335210.0615704097, ymax=-110073.36515944061).asDict()
208+
)

0 commit comments

Comments
 (0)