Skip to content

Commit 790d75c

Browse files
authored
Merge pull request #367 from s22s/fix/366
Added abiltiy to pass a crs specification string to `rf_crs`.
2 parents 25d117c + c0eb224 commit 790d75c

File tree

7 files changed

+46
-12
lines changed

7 files changed

+46
-12
lines changed

core/src/main/resources/reference.conf

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ vlm.gdal {
1414
AWS_REQUEST_PAYER = "requester"
1515
GDAL_DISABLE_READDIR_ON_OPEN = "YES"
1616
CPL_VSIL_CURL_ALLOWED_EXTENSIONS = ".tif,.tiff,.jp2,.mrf,.idx,.lrc,.mrf.aux.xml,.vrt"
17+
GDAL_CACHEMAX = 512
18+
GDAL_PAM_ENABLED = "NO"
19+
CPL_VSIL_CURL_CHUNK_SIZE = 1000000
1720
}
1821
// set this to `false` if CPL_DEBUG is `ON`
1922
useExceptions = true

core/src/main/scala/org/locationtech/rasterframes/expressions/accessors/GetCRS.scala

Lines changed: 28 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -21,33 +21,53 @@
2121

2222
package org.locationtech.rasterframes.expressions.accessors
2323

24-
import org.locationtech.rasterframes.encoders.CatalystSerializer._
25-
import org.locationtech.rasterframes.encoders.StandardEncoders.crsEncoder
26-
import org.locationtech.rasterframes.expressions.OnTileContextExpression
2724
import geotrellis.proj4.CRS
2825
import org.apache.spark.sql.catalyst.InternalRow
26+
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult
27+
import org.apache.spark.sql.catalyst.analysis.TypeCheckResult.{TypeCheckFailure, TypeCheckSuccess}
2928
import org.apache.spark.sql.catalyst.expressions._
3029
import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
31-
import org.apache.spark.sql.types.DataType
30+
import org.apache.spark.sql.types.{DataType, StringType}
3231
import org.apache.spark.sql.{Column, TypedColumn}
33-
import org.locationtech.rasterframes.model.TileContext
32+
import org.apache.spark.unsafe.types.UTF8String
33+
import org.locationtech.rasterframes.encoders.CatalystSerializer._
34+
import org.locationtech.rasterframes.encoders.StandardEncoders.crsEncoder
35+
import org.locationtech.rasterframes.expressions.DynamicExtractors.projectedRasterLikeExtractor
36+
import org.locationtech.rasterframes.model.LazyCRS
3437

3538
/**
3639
* Expression to extract the CRS out of a RasterRef or ProjectedRasterTile column.
3740
*
3841
* @since 9/9/18
3942
*/
4043
@ExpressionDescription(
41-
usage = "_FUNC_(raster) - Fetches the CRS of a ProjectedRasterTile or RasterSource.",
44+
usage = "_FUNC_(raster) - Fetches the CRS of a ProjectedRasterTile or RasterSource, or converts a proj4 string column.",
4245
examples = """
4346
Examples:
4447
> SELECT _FUNC_(raster);
4548
....
4649
""")
47-
case class GetCRS(child: Expression) extends OnTileContextExpression with CodegenFallback {
50+
case class GetCRS(child: Expression) extends UnaryExpression with CodegenFallback {
4851
override def dataType: DataType = schemaOf[CRS]
4952
override def nodeName: String = "rf_crs"
50-
override def eval(ctx: TileContext): InternalRow = ctx.crs.toInternalRow
53+
54+
override def checkInputDataTypes(): TypeCheckResult = {
55+
if (child.dataType != StringType && !projectedRasterLikeExtractor.isDefinedAt(child.dataType)) {
56+
TypeCheckFailure(s"Input type '${child.dataType}' does not conform to `String` or `ProjectedRasterLike`.")
57+
}
58+
else TypeCheckSuccess
59+
}
60+
61+
override protected def nullSafeEval(input: Any): Any = {
62+
input match {
63+
case s: UTF8String => LazyCRS(s.toString).toInternalRow
64+
case row: InternalRow
65+
val prl = projectedRasterLikeExtractor(child.dataType)(row)
66+
prl.crs.toInternalRow
67+
case o throw new IllegalArgumentException(s"Unsupported input type: $o")
68+
}
69+
}
70+
5171
}
5272

5373
object GetCRS {

core/src/main/scala/org/locationtech/rasterframes/model/LazyCRS.scala

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121

2222
package org.locationtech.rasterframes.model
2323

24-
import LazyCRS.EncodedCRS
2524
import com.github.blemale.scaffeine.Scaffeine
2625
import geotrellis.proj4.CRS
2726
import org.locationtech.proj4j.CoordinateReferenceSystem
27+
import org.locationtech.rasterframes.encoders.CatalystSerializer
28+
import org.locationtech.rasterframes.model.LazyCRS.EncodedCRS
2829

2930
class LazyCRS(val encoded: EncodedCRS) extends CRS {
3031
private lazy val delegate = LazyCRS.cache.get(encoded)
@@ -68,4 +69,6 @@ object LazyCRS {
6869
else throw new IllegalArgumentException(
6970
"crs string must be either EPSG code, +proj string, or OGC WKT")
7071
}
72+
73+
implicit val crsSererializer: CatalystSerializer[LazyCRS] = CatalystSerializer.crsSerializer.asInstanceOf[CatalystSerializer[LazyCRS]]
7174
}

core/src/test/scala/org/locationtech/rasterframes/RasterFunctionsSpec.scala

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,11 @@ class RasterFunctionsSpec extends TestEnvironment with RasterMatchers {
318318
checkDocs("rf_crs")
319319
}
320320

321+
it("should parse a CRS from string") {
322+
val e = Seq(crs.toProj4String).toDF("crs").select(rf_crs($"crs")).first()
323+
e should be (crs)
324+
}
325+
321326
it("should get the Geometry of a ProjectedRasterTile") {
322327
val g = Seq(randPRT).toDF("tile").select(rf_geometry($"tile")).first()
323328
g should be (extent.jtsGeom)

core/src/test/scala/org/locationtech/rasterframes/TestEnvironment.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@
2020
*/
2121
package org.locationtech.rasterframes
2222

23-
import java.io.File
2423
import java.nio.file.{Files, Path}
2524

2625
import com.typesafe.scalalogging.LazyLogging
2726
import geotrellis.raster.testkit.RasterMatchers
28-
import org.apache.hadoop.fs.FileUtil
2927
import org.apache.spark.sql._
3028
import org.apache.spark.sql.functions.col
3129
import org.apache.spark.sql.types.StructType

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
## 0.8.x
44

5+
### 0.8.3
6+
7+
* Updated `rf_crs` to accept string columns containing CRS specifications. ([#366](https://github.com/locationtech/rasterframes/issues/366))
8+
59
### 0.8.2
610

711
* Added ability to pass config options to convenience PySpark session constructor. ([#361](https://github.com/locationtech/rasterframes/issues/361))

pyrasterframes/src/main/python/docs/reference.pymd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,9 @@ Fetches the extent (bounding box or envelope) of a `ProjectedRasterTile` or `Ras
9898

9999
Struct rf_crs(ProjectedRasterTile proj_raster)
100100
Struct rf_crs(RasterSource proj_raster)
101+
Struct rf_crs(String crs_spec)
101102

102-
Fetch CRS structure representing the coordinate reference system of a `ProjectedRasterTile` or `RasterSource` type tile columns.
103+
Fetch CRS structure representing the coordinate reference system of a `ProjectedRasterTile` or `RasterSource` type tile columns, or from a column of strings in the form supported by @ref:[`rf_mk_crs`](reference.md#rf-mk-crs).
103104

104105
### rf_mk_crs
105106

0 commit comments

Comments
 (0)