Skip to content

Commit

Permalink
Fix WCS projections support (#361)
Browse files Browse the repository at this point in the history
  • Loading branch information
pomadchin authored Apr 22, 2021
1 parent d4f4f3a commit 15d82e1
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 50 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Interoperability of STAC and non-STAC layers in mapalgebra layers [#309](https://github.com/geotrellis/geotrellis-server/issues/309)
- OGC endpoints format parameter and HTTP response mime-type not matching [#255](https://github.com/geotrellis/geotrellis-server/issues/255)
- WMS 1.3.0 Boolean representation [#332](https://github.com/geotrellis/geotrellis-server/issues/332)
- Fix WCS projections support [#361](https://github.com/geotrellis/geotrellis-server/pull/361)

## Added
- WCS services support configuration of `supported-projections` [#314](https://github.com/geotrellis/geotrellis-server/pull/314)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -230,12 +230,9 @@ class CapabilitiesView[F[_]: Functor](wcsModel: WcsModel[F], serviceUrl: URL, ex
object CapabilitiesView {
def coverageSummaries[F[_]: Functor](wcsModel: WcsModel[F]): F[List[CoverageSummaryType]] =
wcsModel.sources.store.map(_.map { src =>
val crs = src.nativeCrs.head
val wgs84extent = ReprojectRasterExtent(src.nativeRE, crs, LatLng).extent

val uniqueCrs: List[CRS] = (
crs :: LatLng :: wcsModel.supportedProjections
).distinct
val crs = src.nativeCrs.head
val wgs84extent = ReprojectRasterExtent(src.nativeRE, crs, LatLng).extent
val uniqueCrs: List[CRS] = (crs :: LatLng :: wcsModel.supportedProjections).distinct

CoverageSummaryType(
Title = LanguageStringType(src.title) :: Nil,
Expand All @@ -245,7 +242,7 @@ object CapabilitiesView {
LowerCorner = wgs84extent.ymin :: wgs84extent.xmin :: Nil,
UpperCorner = wgs84extent.ymax :: wgs84extent.xmax :: Nil
) :: Nil,
SupportedCRS = new URI("urn:ogc:def:crs:OGC::imageCRS") :: (uniqueCrs flatMap { crs => (URN.fromCrs(crs) map { new URI(_) }) }),
SupportedCRS = new URI("urn:ogc:def:crs:OGC::imageCRS") :: (uniqueCrs flatMap { crs => URN.fromCrs(crs).map(new URI(_)) }),
SupportedFormat = OutputFormat.all.reverse,
coveragesummarytypeoption = DataRecord(None, "Identifier".some, src.name)
)
Expand Down
94 changes: 51 additions & 43 deletions ogc/src/main/scala/geotrellis/server/ogc/wcs/CoverageView.scala
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class CoverageView[F[_]: Functor](wcsModel: WcsModel[F], serviceUrl: URL, identi
val sources = if (identifiers == Nil) wcsModel.sources.store else wcsModel.sources.find(withNames(identifiers.toSet))
val sourcesMap: F[Map[String, List[OgcSource]]] = sources.map(_.groupBy(_.name))
val coverageTypeMap = sourcesMap.map(_.mapValues(CoverageView.sourceDescription(wcsModel.supportedProjections, _)))
coverageTypeMap map { coverageType =>
coverageTypeMap.map { coverageType =>
scalaxb
.toXML[CoverageDescriptions](
obj = CoverageDescriptions(coverageType.values.toList),
Expand All @@ -58,19 +58,15 @@ class CoverageView[F[_]: Functor](wcsModel: WcsModel[F], serviceUrl: URL, identi
}

object CoverageView {

def sourceDescription(supportedProjections: List[CRS], sources: List[OgcSource]): CoverageDescriptionType = {
val source = sources.head
val nativeCrs = source.nativeCrs.head
val re = source.nativeRE
val llre = source match {
private def extractRasterExtent(source: OgcSource, targetCRS: CRS): GridExtent[Long] =
source match {
case mas: MapAlgebraSource =>
mas.sourcesList
.map { rs =>
ReprojectRasterExtent(
rs.gridExtent,
rs.crs,
LatLng,
targetCRS,
Options.DEFAULT.copy(mas.resampleMethod)
)
}
Expand All @@ -87,12 +83,16 @@ object CoverageView {
ReprojectRasterExtent(
rs.gridExtent,
rs.crs,
LatLng,
targetCRS,
Options.DEFAULT.copy(rasterOgcLayer.resampleMethod)
)
}

def sourceDescription(supportedProjections: List[CRS], sources: List[OgcSource]): CoverageDescriptionType = {
val source = sources.head
val nativeCrs = source.nativeCrs.head
val re = source.nativeRE
val ex = re.extent
val llex = llre.extent
val Dimensions(w, h) = re.dimensions

/** WCS expects this very specific format for its time strings, which is not quite (TM)
Expand Down Expand Up @@ -124,8 +124,7 @@ object CoverageView {
) :: Nil
case OgcTimeEmpty => Nil
}
if (records.nonEmpty) TimeSequenceType(records).some
else None
if (records.nonEmpty) TimeSequenceType(records).some else None
}

val uniqueCrs: List[CRS] = (nativeCrs :: LatLng :: supportedProjections).distinct
Expand All @@ -147,33 +146,40 @@ object CoverageView {
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: OwsDataRecord(
BoundingBoxType(
LowerCorner = ex.xmin :: ex.ymin :: Nil,
UpperCorner = ex.xmax :: ex.ymax :: Nil,
attributes = Map(
"@crs" -> DataRecord(new URI(URN.unsafeFromCrs(nativeCrs))),
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: OwsDataRecord(
BoundingBoxType(
LowerCorner = llex.ymin :: llex.xmin :: Nil,
UpperCorner = llex.ymax :: llex.xmax :: Nil,
attributes = Map(
"@crs" -> DataRecord(new URI(URN.unsafeFromCrs(LatLng))),
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: OwsDataRecord(
WGS84BoundingBoxType(
LowerCorner = llex.ymin :: llex.xmin :: Nil,
UpperCorner = llex.ymax :: llex.xmax :: Nil,
attributes = Map(
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: Nil,
) :: uniqueCrs.flatMap {
case crs if crs == LatLng =>
val lex = extractRasterExtent(source, crs).extent
OwsDataRecord(
BoundingBoxType(
LowerCorner = lex.ymin :: lex.xmin :: Nil,
UpperCorner = lex.ymax :: lex.xmax :: Nil,
attributes = Map(
"@crs" -> DataRecord(new URI(URN.unsafeFromCrs(crs))),
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: OwsDataRecord(
WGS84BoundingBoxType(
LowerCorner = lex.ymin :: lex.xmin :: Nil,
UpperCorner = lex.ymax :: lex.xmax :: Nil,
attributes = Map(
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: Nil
case crs =>
val lex = extractRasterExtent(source, crs).extent
OwsDataRecord(
BoundingBoxType(
LowerCorner = lex.ymin :: lex.xmin :: Nil,
UpperCorner = lex.ymax :: lex.xmax :: Nil,
attributes = Map(
"@crs" -> DataRecord(new URI(URN.unsafeFromCrs(crs))),
"@dimensions" -> DataRecord(BigInt(2))
)
)
) :: Nil
},
GridCRS = Some(
GridCrsType(
GridBaseCRS = new URI(URN.unsafeFromCrs(nativeCrs)),
Expand All @@ -193,14 +199,16 @@ object CoverageView {
possibleValuesOption1 = OwsDataRecord(AnyValue())
),
InterpolationMethods = InterpolationMethods(
InterpolationMethod = InterpolationMethodType("nearest neighbor") ::
InterpolationMethod = InterpolationMethodType("nearest-neighbor") ::
InterpolationMethodType("bilinear") ::
InterpolationMethodType("bicubic") :: Nil,
Default = "nearest neighbor".some
InterpolationMethodType("cubic-convolution") ::
InterpolationMethodType("cubic-spline") ::
InterpolationMethodType("lanczos") :: Nil,
Default = "nearest-neighbor".some
)
) :: Nil
),
SupportedCRS = new URI("urn:ogc:def:crs:OGC::imageCRS") :: (uniqueCrs flatMap { proj => URN.fromCrs(proj) map { new URI(_) } }),
SupportedCRS = new URI("urn:ogc:def:crs:OGC::imageCRS") :: uniqueCrs.flatMap(proj => URN.fromCrs(proj).map(new URI(_))),
SupportedFormat = OutputFormat.all.reverse
)
}
Expand Down

0 comments on commit 15d82e1

Please sign in to comment.