Created
July 22, 2015 19:47
-
-
Save lossyrob/f95984cc81d810556184 to your computer and use it in GitHub Desktop.
OAM tile server
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import geotrellis.raster._ | |
import geotrellis.raster.render._ | |
import geotrellis.raster.resample._ | |
import geotrellis.raster.io.geotiff._ | |
import geotrellis.vector._ | |
import geotrellis.vector.io.json._ | |
import geotrellis.vector.reproject._ | |
import geotrellis.spark._ | |
import geotrellis.spark.tiling._ | |
import geotrellis.proj4._ | |
import spire.syntax.cfor._ | |
import akka.actor.ActorSystem | |
import scala.concurrent._ | |
import scala.concurrent.ExecutionContext.Implicits.global | |
import spray.http.{MediaTypes } | |
import spray.httpx.SprayJsonSupport._ | |
import spray.json._ | |
import spray.routing._ | |
import spray.util.LoggingContext | |
import spray.http.StatusCodes._ | |
object TMSService extends App with SimpleRoutingApp { | |
implicit val system = ActorSystem("foundry-server-system") | |
val rootPath = "/Users/rob/proj/oam/data/oam-tiled-zoomedThrough" | |
val layers = List( | |
("20140903_154221_0906_visual-reprojected-correctbands", 15), | |
("20140903_154222_0906_visual-reprojected-correctbands", 15), | |
("20140903_154223_0906_visual-reprojected-correctbands", 15), | |
("20140903_154224_0906_visual-reprojected-correctbands", 15), | |
("20140903_154225_0906_visual-reprojected-correctbands", 15), | |
("20140903_154226_0906_visual-reprojected-correctbands", 15), | |
("20140903_154227_0906_visual-reprojected-correctbands", 15), | |
("20140903_154228_0906_visual-reprojected-correctbands", 15), | |
("20140903_154229_0906_visual-reprojected-correctbands", 15), | |
("20140903_154230_0906_visual-reprojected-correctbands", 15), | |
("20140903_154231_0906_visual-reprojected-correctbands", 15), | |
("20140903_154232_0906_visual-reprojected-correctbands", 15), | |
("20140903_154233_0906_visual-reprojected-correctbands", 15), | |
("20140903_154239_0906_visual-reprojected-correctbands", 15), | |
("20150424_182320_081f_visual-reprojected-correctbands", 15), | |
("20150506_134129_0822_visual-reprojected-correctbands", 15), | |
("20150514_151301_0822_visual-reprojected-correctbands", 15), | |
("20150514_151311_0822_visual-reprojected-correctbands", 15), | |
("20150608_160416_0906_visual-reprojected-correctbands", 15), | |
("20150609_155942_0905_visual-reprojected-correctbands", 15), | |
("20150609_155943_0905_visual-reprojected-correctbands", 15), | |
("20150609_155945_0905_visual-reprojected-correctbands", 15), | |
("20150609_155946_0905_visual-reprojected-correctbands", 15), | |
("20150609_155947_0905_visual-reprojected-correctbands", 15), | |
("20150609_155949_0905_visual-reprojected-correctbands", 15), | |
("20150624_160324_0905_visual-reprojected-correctbands", 15), | |
("LC80200282014245LGN00_bands_432-reprojected-correctbands", 12), | |
("LC80210282014156LGN00_RGB-reprojected-correctbands", 12), | |
("LC80220282015102LGN01_bands_432-reprojected-correctbands", 12) | |
) | |
val mapTransforms: Function1[Int, MapKeyTransform] = { | |
val worldExtent = Extent(-20037508.342789244, -20037508.342789244, 20037508.342789244, 20037508.342789244) | |
println(f"WORLD EXTENT: ${worldExtent.xmin}%f ${worldExtent.ymin}%f ${worldExtent.xmax}%f ${worldExtent.ymax}%f") | |
(1 to 24) | |
.map { z => | |
val layoutCols = math.pow(2, z).toInt | |
val layoutRows = layoutCols | |
(z, MapKeyTransform(worldExtent, layoutCols, layoutRows)) | |
} | |
.toMap | |
} | |
def tmsRoute = | |
pathPrefix(IntNumber / IntNumber / IntNumber) { (zoom, x, y) => | |
respondWithMediaType(MediaTypes.`image/png`) { | |
val paths = | |
layers | |
.flatMap { case (layer, maxZoom) => | |
val (lz, lx, ly) = { | |
if(zoom <= maxZoom) | |
(zoom, x, y) | |
else { | |
val d = math.pow(2, zoom - maxZoom) | |
(maxZoom, (x / d).toInt, (y / d).toInt) | |
} | |
} | |
val path = s"$rootPath/$layer/$lz/$lx/$ly.tiff" | |
if(!new java.io.File(path).exists) { | |
None | |
} | |
else { | |
Some((path, lz, lx, ly)) | |
} | |
} | |
if(paths.isEmpty) { | |
reject | |
} else { | |
complete { | |
Future { | |
paths.foreach(println) | |
val ordered = | |
paths.map { case (path, lz, lx, ly) => | |
val converted: MultiBandTile = { | |
val gt = MultiBandGeoTiff(path) | |
if(zoom == lz) | |
gt.tile.convert(TypeInt) | |
else { | |
val t = gt.tile | |
val re = RasterExtent(mapTransforms(zoom)(x, y), 256, 256) | |
val arr = Array.ofDim[Tile](t.bandCount) | |
cfor(0)(_ < 3, _ + 1) { b => | |
arr(b) = t.band(b).convert(TypeInt).map { z => if(isNoData(z)) 128 else z.toByte & 0xFF }.resample(gt.extent, re, Bilinear) | |
} | |
ArrayMultiBandTile(arr) | |
} | |
} | |
if(converted.bandCount == 3) { | |
converted.combine(0, 1, 2) { (r, g, b) => | |
if(r == 0 && g == 0 && b == 0) 0 | |
else { | |
val cr = if(isNoData(r)) 128 else r.toByte & 0xFF | |
val cg = if(isNoData(g)) 128 else g.toByte & 0xFF | |
val cb = if(isNoData(b)) 128 else b.toByte & 0xFF | |
(cr << 24) | (cg << 16) | (cb << 8) | 0xFF | |
} | |
} | |
} else { | |
converted.combine(0, 1, 2, 3) { (r, g, b, a) => | |
if(a != 255.toByte || (r == 0 && g == 0 && b == 0)) { | |
0 | |
} else { | |
val cr = if(isNoData(r)) 128 else r.toByte & 0xFF | |
val cg = if(isNoData(g)) 128 else g.toByte & 0xFF | |
val cb = if(isNoData(b)) 128 else b.toByte & 0xFF | |
(cr << 24) | (cg << 16) | (cb << 8) | 0xFF | |
} | |
} | |
} | |
} | |
.toArray | |
val m = ordered(0).mutable | |
cfor(1)(_ < ordered.size, _ + 1) { i => | |
val s = ordered(i) | |
cfor(0)(_ < 256, _ + 1) { row => | |
cfor(0)(_ < 256, _ + 1) { col => | |
val v1 = m.get(col, row) | |
val v2 = s.get(col, row) | |
if(v1 == 0) { | |
m.set(col, row, v2) | |
} | |
} | |
} | |
} | |
val rgb = m | |
rgb.renderPng.bytes | |
} | |
} | |
} | |
} | |
} | |
def root = { | |
pathPrefix("tms") { tmsRoute } | |
} | |
startServer(interface = "0.0.0.0", port = 8088) { | |
root | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment