
geotrellis.server.gtlayer.GTLayerNode.scala Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of geotrellis-server-core_2.11 Show documentation
Show all versions of geotrellis-server-core_2.11 Show documentation
GeoTrellis Server is a set of components designed to simplify viewing, processing, and serving raster data from arbitrary sources with an emphasis on doing so in a functional style.
The newest version!
/*
* Copyright 2020 Azavea
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package geotrellis.server.gtlayer
import geotrellis.server._
import cats.effect._
import cats.data.{NonEmptyList => NEL}
import cats.syntax.all._
import cats.implicits._
import com.azavea.maml.eval.tile._
import io.circe._
import io.circe.generic.semiauto._
import geotrellis.store._
import geotrellis.layer._
import geotrellis.proj4._
import geotrellis.raster._
import geotrellis.vector._
import java.net.URI
import scala.util.Try
case class GTLayerNode(catalog: URI, layer: String) {
lazy val collectionReader = CollectionLayerReader(catalog)
lazy val (maxZoom, allMetadata): (Int, Map[Int, Option[TileLayerMetadata[SpatialKey]]]) = {
val attributeStore = AttributeStore(catalog)
val zs = attributeStore.layerIds
.groupBy(_.name)
.apply(layer)
.map(_.zoom)
.sortWith(_ > _)
(zs.head, zs.map{ z => (z, Try(attributeStore.readMetadata[TileLayerMetadata[SpatialKey]](LayerId(layer, z))).toOption) }.toMap)
}
lazy val crs = allMetadata(maxZoom).get.crs
}
object GTLayerNode {
type MetadataCatalog = Map[String, (Seq[Int], Option[TileLayerMetadata[SpatialKey]])]
implicit val uriEncoder: Encoder[URI] = Encoder.encodeString.contramap[URI](_.toString)
implicit val uriDecoder: Decoder[URI] = Decoder[String].emap { str => Right(URI.create(str)) }
implicit val gtLayerNodeRasterExtents: HasRasterExtents[GTLayerNode] =
new HasRasterExtents[GTLayerNode] {
def rasterExtents(self: GTLayerNode)(implicit contextShift: ContextShift[IO]): IO[NEL[RasterExtent]] =
IO {
val allREs = Range(self.maxZoom, -1, -1).flatMap{ i =>
val md = self.allMetadata(i)
md.map{ meta =>
val ex = meta.layout.mapTransform.boundsToExtent(meta.bounds.asInstanceOf[KeyBounds[SpatialKey]].toGridBounds)
val cs = meta.cellSize
RasterExtent(ex, cs)
}
}
NEL(allREs.head, allREs.tail.toList)
}
def crs(self: GTLayerNode)(implicit contextShift: ContextShift[IO]): IO[CRS] =
IO { self.crs }
}
implicit val gtLayerNodeTmsReification: TmsReification[GTLayerNode] =
new TmsReification[GTLayerNode] {
def tmsReification(self: GTLayerNode, buffer: Int)(implicit contextShift: ContextShift[IO]): (Int, Int, Int) => IO[ProjectedRaster[MultibandTile]] =
(z: Int, x: Int, y: Int) => IO {
val bounds = GridBounds(x - 1, y - 1, x + 1, y + 1)
val values =
self.collectionReader
.query[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](LayerId(self.layer, z))
.where(Intersects(bounds))
.result
.toMap
def p2t(p: (Int, Int)): Tile = values.get(SpatialKey(p._1+x, p._2+y)).get
val nbhd =
(p2t((-1, -1)), p2t((0, -1)), p2t((1, -1)), p2t((-1, 0)), p2t((1, 0)), p2t((-1, 1)), p2t((0, 1)), p2t((1, 1)))
val neighboring = NeighboringTiles(nbhd._1, nbhd._2, nbhd._3, nbhd._4, nbhd._5, nbhd._6, nbhd._7, nbhd._8)
val tile = TileWithNeighbors(values.get(SpatialKey(x, y)).get, Some(neighboring)).withBuffer(buffer)
val ex = self.allMetadata(z).get.layout.mapTransform(SpatialKey(x, y))
ProjectedRaster(MultibandTile(tile), ex, self.crs)
}
}
implicit val gtLayerNodeExtentReification: ExtentReification[GTLayerNode] = new ExtentReification[GTLayerNode] {
def extentReification(self: GTLayerNode)(implicit contextShift: ContextShift[IO]): (Extent, CellSize) => IO[ProjectedRaster[MultibandTile]] =
{ (ex: Extent, cs: CellSize) =>
IO {
def csToDiag(cell: CellSize) = math.sqrt(cell.width * cell.width + cell.height * cell.height)
val reqDiag = csToDiag(cs)
val z = self.allMetadata.mapValues{ md => csToDiag(md.get.cellSize) - reqDiag }
.filter(_._2 <= 0)
.map(_._1)
.toList
.sortBy{i => -i}
.headOption
.getOrElse(self.maxZoom)
val raster = self.collectionReader
.query[SpatialKey, Tile, TileLayerMetadata[SpatialKey]](LayerId(self.layer, z))
.where(Intersects(ex))
.result
.stitch
.crop(ex)
ProjectedRaster(MultibandTile(raster.tile), raster.extent, self.crs)
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy