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

geotrellis.raster.RasterData.scala Maven / Gradle / Ivy

The newest version!
package geotrellis.raster

import geotrellis._

import spire.syntax.cfor._

object RasterData {
  def largestType(lhs: RasterData, rhs: RasterData) = {
    lhs.getType.union(rhs.getType)
  }
  def largestByType(lhs: RasterData, rhs: RasterData) = {
    if (largestType(lhs, rhs) == lhs.getType) lhs else rhs
  }
  def largestAlloc(lhs: RasterData, rhs: RasterData, cols: Int, rows: Int) = {
    largestByType(lhs, rhs).alloc(cols, rows)
  }

  def allocByType(t: RasterType, cols: Int, rows: Int): MutableRasterData = t match {
    case TypeBit    => BitArrayRasterData.ofDim(cols, rows)
    case TypeByte   => ByteArrayRasterData.ofDim(cols, rows)
    case TypeShort  => ShortArrayRasterData.ofDim(cols, rows)
    case TypeInt    => IntArrayRasterData.ofDim(cols, rows)
    case TypeFloat  => FloatArrayRasterData.ofDim(cols, rows)
    case TypeDouble => DoubleArrayRasterData.ofDim(cols, rows)
  }

  def emptyByType(t: RasterType, cols: Int, rows: Int): MutableRasterData = t match {
    case TypeBit    => BitArrayRasterData.empty(cols, rows)
    case TypeByte   => ByteArrayRasterData.empty(cols, rows)
    case TypeShort  => ShortArrayRasterData.empty(cols, rows)
    case TypeInt    => IntArrayRasterData.empty(cols, rows)
    case TypeFloat  => FloatArrayRasterData.empty(cols, rows)
    case TypeDouble => DoubleArrayRasterData.empty(cols, rows)
  }

  def fromArrayByte(bytes: Array[Byte], awType: RasterType, cols: Int, rows: Int) = awType match {
    case TypeBit    => BitArrayRasterData.fromArrayByte(bytes, cols, rows)
    case TypeByte   => ByteArrayRasterData.fromArrayByte(bytes, cols, rows)
    case TypeShort  => ShortArrayRasterData.fromArrayByte(bytes, cols, rows)
    case TypeInt    => IntArrayRasterData.fromArrayByte(bytes, cols, rows)
    case TypeFloat  => FloatArrayRasterData.fromArrayByte(bytes, cols, rows)
    case TypeDouble => DoubleArrayRasterData.fromArrayByte(bytes, cols, rows)
  }

  def apply(arr: Array[Byte], cols: Int, rows: Int) = ByteArrayRasterData(arr,cols,rows)
  def apply(arr: Array[Short], cols: Int, rows: Int) = ShortArrayRasterData(arr,cols,rows)
  def apply(arr: Array[Int], cols: Int, rows: Int) = IntArrayRasterData(arr,cols,rows)
  def apply(arr: Array[Float], cols: Int, rows: Int) = FloatArrayRasterData(arr,cols,rows)
  def apply(arr: Array[Double], cols: Int, rows: Int) = DoubleArrayRasterData(arr,cols,rows)
}

/**
 * RasterData provides access and update to the grid data of a raster.
 *
 * Designed to be a near drop-in replacement for Array in many cases.
 */
trait RasterData extends Serializable {
  def force: RasterData
  def getType: RasterType
  def alloc(cols: Int, rows: Int): MutableRasterData

  def isFloat = getType.float
  def convert(typ: RasterType): RasterData = LazyConvert(this, typ)
  def lengthLong = length

  def isLazy: Boolean = false

  def copy: RasterData
  def length: Int

  def cols: Int
  def rows: Int

  def mutable(): MutableRasterData

  /**
   * For every cell in the given raster, run the given integer function.
   *
   * The order of the traversal from the lowest to highest columns, across each
   * row, but this should probably not be relied upon. In the future we'd like
   * to be able to parallelize foreach.
   */
  def foreach(f: Int => Unit): Unit = {
    var i = 0
    val len = length
    while (i < len) {
      f(apply(i))
      i += 1
    }
  }

  /**
   * Map each cell in the given raster to a new one, using the given function.
   */
  def map(f:Int=>Int):RasterData = {
    val output = alloc(cols, rows)
    var i = 0
    val len = length
    while (i < len) {
      output(i) = f(apply(i))
      i += 1
    }
    output
  }
//  def map(f:Int=>Int):RasterData = LazyMap(this,f)

  /**
   * Combine two RasterData's cells into new cells using the given integer
   * function. For every (x,y) cell coordinate, get each RasterData's integer
   * value, map them to a new value, and assign it to the output's (x,y) cell.
   */
  def combine(other: RasterData)(f: (Int, Int) => Int): RasterData = {
    if (lengthLong != other.lengthLong) {
      val size1 = s"${cols} x ${rows}"
      val size2 = s"${other.cols} x ${other.rows}"
      sys.error(s"Cannot combine rasters of different sizes: $size1 vs $size2")
    }
    val output = RasterData.largestAlloc(this, other, cols, rows)
    var i = 0
    val len = length
    while (i < len) {
      output(i) = f(apply(i), other(i))
      i += 1
    }
    output
  }
  // def combine(other:RasterData)(f:(Int,Int) => Int):RasterData =
  //   LazyCombine(this,other,f)

  /**
   * For every cell in the given raster, run the given double function.
   *
   * The order of the traversal from the lowest to highest columns, across each
   * row, but this should probably not be relied upon. In the future we'd like
   * to be able to parallelize foreach.
   */
  def foreachDouble(f: Double => Unit): Unit = {
    var i = 0
    val len = length
    while (i < len) {
      f(applyDouble(i))
      i += 1
    }
  }

  /**
   * Map each cell in the given raster to a new one, using the given function.
   */
  def mapDouble(f:Double => Double):RasterData = {
    val len = length
    val data = alloc(cols, rows)
    var i = 0
    while (i < len) {
      data.updateDouble(i, f(applyDouble(i)))
      i += 1
    }
    data
  }
//  def mapDouble(f:Double => Double):RasterData = LazyMapDouble(this, f)

  /**
   * Combine two RasterData's cells into new cells using the given double
   * function. For every (x,y) cell coordinate, get each RasterData's double
   * value, map them to a new value, and assign it to the output's (x,y) cell.
   */
  def combineDouble(other: RasterData)(f: (Double, Double) => Double): RasterData = {
    if (lengthLong != other.lengthLong) {
      val size1 = s"${cols} x ${rows}"
      val size2 = s"${other.cols} x ${other.rows}"
      sys.error(s"Cannot combine rasters of different sizes: $size1 vs $size2")
    }
    val output = RasterData.largestAlloc(this, other, cols, rows)
    var i = 0
    val len = length
    while (i < len) {
      output.updateDouble(i, f(applyDouble(i), other.applyDouble(i)))
      i += 1
    }
    output
  }
  // def combineDouble(other: RasterData)(f: (Double, Double) => Double): RasterData =
  //   LazyCombineDouble(this, other, f)

  override def equals(other: Any): Boolean = other match {
    case r: RasterData => {
      if (r == null) return false
      val len = length
      if (len != r.length) return false
      var i = 0
      while (i < len) {
        if (apply(i) != r(i)) return false
        i += 1
      }
      true
    }
    case _ => false
  }

  def apply(i: Int): Int
  def applyDouble(i: Int): Double

  def get(col: Int, row: Int) = apply(row * cols + col)
  def getDouble(col: Int, row: Int) = applyDouble(row * cols + col)

  def toList = toArray.toList
  def toListDouble = toArrayDouble.toList

  def toArray: Array[Int] = {
    val len = length
    val arr = Array.ofDim[Int](len)
    var i = 0
    while (i < len) {
      arr(i) = apply(i)
      i += 1
    }
    arr
  }

  def toArrayDouble: Array[Double] = {
    val len = length
    val arr = Array.ofDim[Double](len)
    var i = 0
    while (i < len) {
      arr(i) = applyDouble(i)
      i += 1
    }
    arr
  }

  def toArrayByte: Array[Byte]

  def warp(current:RasterExtent,target:RasterExtent):RasterData 
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy