Skip to content

Commit

Permalink
Merge branch 'release/0.1.5'
Browse files Browse the repository at this point in the history
  • Loading branch information
rajadain committed Feb 23, 2016
2 parents 0399618 + 454e149 commit 6c1fc5a
Show file tree
Hide file tree
Showing 6 changed files with 94 additions and 15 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## 0.1.5

- Add /flood-value/z/x/y route for calculating the flood value of a
particular point on the tile given a polygon's minElevation and a
certain floodLevel
- Improve contrast in tile output by increasing color range, reducing
number of breaks, and "padding" the high end with the same color,
preserving contrast in low flooding areas

## 0.1.4

- Fix a problem in .travis.yml
Expand Down
2 changes: 1 addition & 1 deletion project/Version.scala
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ object Version {
def either(environmentVariable: String, default: String): String =
Properties.envOrElse(environmentVariable, default)

val version = "0.1.4"
val version = "0.1.5"
val floodmodel = version + either("FLOODMODEL_VERSION_SUFFIX", "-SNAPSHOT")

val scala = "2.10.6"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,9 +35,11 @@ class FloodModelServiceActor(sc: SparkContext) extends Actor with HttpService {
`Access-Control-Allow-Methods`(GET, POST, OPTIONS, DELETE),
`Access-Control-Allow-Headers`("Origin, X-Requested-With, Content-Type, Accept, Accept-Encoding, Accept-Language, Host, Referer, User-Agent, Access-Control-Request-Method, Access-Control-Request-Headers"))

val lightestColor = 0xc2dae8
val darkestColor = 0x393264
val colorTransparency = 0xb3
val LIGHTEST_COLOR = 0xB5D1E8 // Pantone 277
val DARKEST_COLOR = 0x002B7F // Pantone 280
val MAIN_ALPHA = 0xAB // 66% visible
val FINAL_ALPHA = 0xB3 // 70% visible
val FINAL_BREAK = 500.0

def cors: Directive0 = {
val rh = implicitly[RejectionHandler]
Expand All @@ -48,7 +50,8 @@ class FloodModelServiceActor(sc: SparkContext) extends Actor with HttpService {
path("ping") { complete { "OK" } } ~
pathPrefix("elevation") { elevationRoute } ~
pathPrefix("flood-percentages") { floodPercentagesRoute } ~
pathPrefix("flood-tiles") { floodTilesRoute }
pathPrefix("flood-tiles") { floodTilesRoute } ~
pathPrefix("flood-value") { floodValueRoute }

def elevationRoute =
cors {
Expand Down Expand Up @@ -96,7 +99,7 @@ class FloodModelServiceActor(sc: SparkContext) extends Actor with HttpService {
val floodTile = FloodTile(tile, zoom, key, multiPolygon, args.minElevation, args.floodLevel)

// Paint the tile
val breaks = getColorBreaksForRange(args.maxElevation, args.minElevation, 20)
val breaks = getColorBreaksForRange(args.maxElevation, args.minElevation, 7)
floodTile.renderPng(breaks).bytes

case None =>
Expand All @@ -108,10 +111,37 @@ class FloodModelServiceActor(sc: SparkContext) extends Actor with HttpService {
}
}

def floodValueRoute =
pathPrefix(IntNumber / IntNumber / IntNumber) { (zoom, x, y) =>
import spray.json.DefaultJsonProtocol._

entity(as[floodValueArgs]) { (args) =>
complete {
future {
val key = SpatialKey(x, y)
val point = Point(args.lng, args.lat).reproject(LatLng, WebMercator)
val tile = ElevationData(zoom, key)
val extent = ElevationData.getExtent(zoom, key)

JsObject(
"floodValue" -> JsNumber(FloodPointValue(tile, extent, point, args.minElevation, args.floodLevel))
)
}
}
}
}

def getColorBreaksForRange(maxElevation: Double, minElevation: Double, ticks: Int): ColorBreaks = {
val tick = (maxElevation - minElevation) / ticks
val breaks = (1 to ticks).toArray.map(_ * tick)
val colors = ColorRamp.createWithRGBColors(lightestColor, darkestColor).setAlpha(colorTransparency).interpolate(ticks).toArray

// Calculate main breaks, and add a really large one at the end
val main_breaks = (1 to ticks).toArray.map(_ * tick)
val breaks = main_breaks :+ FINAL_BREAK

// Calculate main colors, and add the darkest color at the end
val main_colors = ColorRamp.createWithRGBColors(LIGHTEST_COLOR, DARKEST_COLOR).setAlpha(MAIN_ALPHA).interpolate(ticks).toArray
val final_color = ColorRamp.createWithRGBColors(DARKEST_COLOR).setAlpha(FINAL_ALPHA).toArray
val colors = main_colors ++ final_color

ColorBreaks(breaks, colors)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
package com.azavea.usaceflood.server

import geotrellis.vector._
import geotrellis.raster._
import geotrellis.spark._

import org.apache.spark._

object FloodPointValue {
/**
* Takes a polygon, flood level, zoom level and tile coordinates, and a point.
* Returns the flood amount at that point.
*
* @param tile The tile to get data from
* @param extent Extent to restrict search to
* @param point Point in EPSG:4269 to get output for
* @param minElevation Minimum elevation under this polygon
* @param floodLevel Flood level to use for determining cell flooding
*
* @return Flood level at that point
*/
def apply(tile: Tile, extent: Extent, point: Point, minElevation: Double, floodLevel: Double)(implicit sc: SparkContext): Double = {
val (col, row) = RasterExtent(extent, tile.cols, tile.rows).mapToGrid(point.x, point.y)
val elevation = tile.getDouble(col, row)

getFlooding(elevation, minElevation, floodLevel)
}

/**
* Given the elevation value at a point, and a minElevation and floodLevel,
* returns the flood value at that point.
*
* @param elevation Elevation of this point
* @param minElevation Minimum elevation of the polygon in which this point belongs
* @param floodLevel Flood level to use for determining cell flooding
* @return
*/
def getFlooding(elevation: Double, minElevation: Double, floodLevel: Double): Double =
if (isData(elevation) && elevation - minElevation < floodLevel) {
floodLevel - (elevation - minElevation)
} else {
Double.NaN
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,6 @@ object FloodTile {
val extent = ElevationData.getExtent(zoom, key)
val maskedTile = tile.mask(extent, multiPolygon)

maskedTile.mapDouble { z =>
if (isData(z) && z - minElevation < floodLevel) {
floodLevel - (z - minElevation)
} else {
Double.NaN
}
}
maskedTile.mapDouble { elevation => FloodPointValue.getFlooding(elevation, minElevation, floodLevel) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ import spray.json._
case class elevationArgs (multiPolygon: JsObject)
case class floodPercentagesArgs (multiPolygon: JsObject, minElevation: Double, floodLevels: Array[Double])
case class floodTilesArgs (multiPolygon: JsObject, minElevation: Double, maxElevation: Double, floodLevel: Double)
case class floodValueArgs (lat: Double, lng: Double, minElevation: Double, floodLevel: Double)

object JsonProtocol extends SprayJsonSupport {
import DefaultJsonProtocol._

implicit val elevationFormat = jsonFormat1(elevationArgs)
implicit val floodPercentagesFormat = jsonFormat3(floodPercentagesArgs)
implicit val floodTilesFormat = jsonFormat4(floodTilesArgs)
implicit val floodValueFormat = jsonFormat4(floodValueArgs)
}

0 comments on commit 6c1fc5a

Please sign in to comment.