All Downloads are FREE. Search and download functionalities are using the official Maven repository.

geotrellis.raster.op.hydrology.Fill.scala Maven / Gradle / Ivy

The newest version!
package geotrellis.raster.op.hydrology

import geotrellis.raster.op.focal._
import geotrellis._
import geotrellis.raster.TileNeighbors

import scala.math._

case class FillOptions(threshold:Double)
object FillOptions {
  val default = FillOptions(20.0)
}

/** Fills sink values in a raster. Returns a raster of TypeDouble
  *
  * @param    r         Raster on which to run the focal operation.
  * @param    options   FillOptions. This allows you to set the threshold appropriately.
  * @param    n         Neighborhood to use for this operation (e.g., [[Square]](1))
  * @param    tns       TileNeighbors that describe the neighboring tiles.

  * @return             Returns a double value raster that is the computed Fill for each neighborhood.
  * 
  * @note               The threshold in the options will be used to determine whether
  *                     or not something is a sink, so if you find that this operation
  *                     is incorrectly classifying your data, make sure you have set
  *                     the threshold appropriately.      
  */
case class Fill(r:Op[Raster],options:FillOptions,tns:Op[TileNeighbors])
    extends FocalOp1(r,Square(1),tns,options)({
      (r,n) =>
      if(r.isFloat) { new CursorFillCalcDouble }
      else { new CursorFillCalc }
    })

object Fill {
  def apply(r:Op[Raster]) = new Fill(r,FillOptions.default,TileNeighbors.NONE)
  def apply(r:Op[Raster],o:FillOptions) = new Fill(r,o,TileNeighbors.NONE)
}

case class CursorFillCalc() extends CursorCalculation[Raster]
                               with Initialization1[FillOptions]
                               with IntRasterDataResult {
  private var threshold:Int = 0

  def init(r:Raster,options:FillOptions) = {
    threshold = options.threshold.toInt
    super.init(r)
  }

  def calc(r:Raster,c:Cursor) = {
    var count:Int = 0
    var totalCount:Int = 0
    var sum:Int = 0
    val cVal = r.get(c.col,c.row)
    c.allCells
      .foreach { (col,row) =>
      if(c.col != col || c.row != row){
        if((r.get(col,row)-cVal).abs > threshold ){
          count = count + 1
        }
        totalCount = totalCount + 1
        sum = sum + r.get(col,row)
      }

    }

    if(count == totalCount){
      data.set(c.col,c.row, sum/totalCount)
    } else {
      data.set(c.col,c.row,cVal)
    }
  }
}

case class CursorFillCalcDouble() extends CursorCalculation[Raster]
                                     with Initialization1[FillOptions]
                                     with DoubleRasterDataResult {
  private var threshold:Double = 0.0

    def init(r:Raster,options:FillOptions) = {
    threshold = options.threshold.toInt
    super.init(r)
  }

  def calc(r:Raster,c:Cursor) = {
    var count:Int = 0
    var totalCount:Int = 0
    var sum:Double = 0
    val cVal:Double = r.getDouble(c.col,c.row)
    c.allCells.foreach { (col,row) =>
      if(c.col != col || c.row != row){
        if((r.getDouble(col,row)-cVal).abs > threshold ){
          count = count + 1
        }
        totalCount = totalCount + 1
        sum = sum + r.get(col,row)
      }
    }
    if(count == totalCount){
      data.setDouble(c.col,c.row, sum/totalCount)
    } else {
      data.setDouble(c.col,c.row,cVal)
    }
  }
}





© 2015 - 2024 Weber Informatics LLC | Privacy Policy