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

geotrellis.TileRaster.scala Maven / Gradle / Ivy

The newest version!
package geotrellis

import geotrellis.raster._
import spire.syntax.cfor._
import scala.collection.mutable

object TileRaster {
  def apply(r:Raster,tileLayout:TileLayout):TileRaster =
    r match {
      case tr:TileRaster =>
        if(tileLayout != tr.tileLayout) {
          throw new GeoAttrsError("This raster is a tile raster with a different layout than" +
                                  " the argument tile layout." +  
                                 s" $tileLayout does not match ${tr.tileLayout}")
        }
        tr
      case _ =>
        wrap(r, tileLayout)
    }

  /** Converts a raster into a TileRaster with the given tileLayout.
    * 
    * @param        r              Raster to wrap.
    * @param        tileLayout     TileLayout of the resulting 
    *                              TileRaster.
    * @param        cropped        Set this flag to false if you
    *                              want the tiles to be ArrayRasters,
    *                              otherwise they will be CroppedRasters
    *                              with the raster 'r' as the backing raster.
    */ 
  def wrap(r:Raster,tileLayout:TileLayout, cropped:Boolean = true):TileRaster = {
    TileRaster(split(r,tileLayout, cropped),r.rasterExtent.adjustTo(tileLayout),tileLayout)
  }

  /** Splits a raster into a TileRaster into tiles.
    * 
    * @param        r              Raster to split.
    * @param        tileLayout     TileLayout defining the tiles to be 
    *                              generated.
    * @param        cropped        Set this flag to false if you
    *                              want the tiles to be ArrayRasters,
    *                              otherwise they will be CroppedRasters
    *                              with the raster 'r' as the backing raster.
    */ 
  def split(r:Raster,tileLayout:TileLayout, cropped:Boolean = true):Seq[Raster] = {
    val pCols = tileLayout.pixelCols
    val pRows = tileLayout.pixelRows

    val tiles = mutable.ListBuffer[Raster]()
    cfor(0)(_ < tileLayout.tileRows, _ + 1) { trow =>
      cfor(0)(_ < tileLayout.tileCols, _ + 1) { tcol =>
        val firstCol = tcol * pCols
        val lastCol = firstCol + pCols - 1
        val firstRow = trow * pRows
        val lastRow = firstRow + pRows - 1
        val gb = GridBounds(firstCol,firstRow,lastCol,lastRow)
        tiles += {
          if(cropped) CroppedRaster(r,gb)
          else CroppedRaster(r,gb).toArrayRaster
        }
      }
    }
    return tiles
  }
}

case class TileRaster(tiles:Seq[Raster],
                      rasterExtent:RasterExtent,
                      tileLayout:TileLayout) extends Raster {
  private val tileList = tiles.toList
  private val tileCols = tileLayout.tileCols
  private def getTile(tcol:Int,trow:Int) = tileList(trow*tileCols+tcol)

  val rasterType = tiles(0).rasterType

  def warp(target:RasterExtent) = toArrayRaster.warp(target)

  def toArrayRaster():ArrayRaster = {
    if (cols.toLong*rows.toLong > Int.MaxValue.toLong) {
      sys.error("This tiled raster is too big to convert into an array.") 
    } else {
      val data = RasterData.allocByType(rasterType,cols,rows)
      val len = cols*rows
      val tileCols = tileLayout.tileCols
      val tileRows = tileLayout.tileRows
      val pixelCols = tileLayout.pixelCols
      val pixelRows = tileLayout.pixelRows
      if(!isFloat) {
        cfor(0)(_ < tileCols, _ + 1) { tcol =>
          cfor(0)(_ < tileRows, _ + 1) { trow =>
            val tile = getTile(tcol,trow)
            cfor(0)(_ < pixelRows, _ + 1) { prow =>
              cfor(0)(_ < pixelCols, _ + 1) { pcol =>
                val acol = (pixelCols * tcol) + pcol
                val arow = (pixelRows * trow) + prow
                data.set(acol,arow,tile.get(pcol,prow))
              }
            }
          }
        }
      } else {
        cfor(0)(_ < tileCols, _ + 1) { tcol =>
          cfor(0)(_ < tileRows, _ + 1) { trow =>
            val tile = getTile(tcol,trow)
            cfor(0)(_ < pixelRows, _ + 1) { prow =>
              cfor(0)(_ < pixelCols, _ + 1) { pcol =>
                val acol = (pixelCols * tcol) + pcol
                val arow = (pixelRows * trow) + prow
                data.setDouble(acol,arow,tile.getDouble(pcol,prow))
              }
            }
          }
        }
      }
      ArrayRaster(data,rasterExtent)
    }
  }

  def toArray():Array[Int] = {
    if (cols.toLong*rows.toLong > Int.MaxValue.toLong) {
      sys.error("This tiled raster is too big to convert into an array.") 
    } else {
      val arr = Array.ofDim[Int](cols*rows)
      val len = cols*rows
      val tileCols = tileLayout.tileCols
      val tileRows = tileLayout.tileRows
      val pixelCols = tileLayout.pixelCols
      val pixelRows = tileLayout.pixelRows
      val totalCols = tileCols*pixelCols

      cfor(0)(_ < tileCols, _ + 1) { tcol =>
        cfor(0)(_ < tileRows, _ + 1) { trow =>
          val tile = getTile(tcol,trow)
          cfor(0)(_ < pixelRows, _ + 1) { prow =>
            cfor(0)(_ < pixelCols, _ + 1) { pcol =>
              val acol = (pixelCols * tcol) + pcol
              val arow = (pixelRows * trow) + prow
              arr(arow*totalCols + acol) = tile.get(pcol,prow)
            }
          }
        }
      }
      arr
    }
  }

  def toArrayDouble():Array[Double] = {
    if (cols.toLong*rows.toLong > Int.MaxValue.toLong) {
      sys.error("This tiled raster is too big to convert into an array.") 
    } else {
      val arr = Array.ofDim[Double](cols*rows)
      val len = cols*rows
      val tileCols = tileLayout.tileCols
      val tileRows = tileLayout.tileRows
      val pixelCols = tileLayout.pixelCols
      val pixelRows = tileLayout.pixelRows
      val totalCols = tileCols*pixelCols

      cfor(0)(_ < tileCols, _ + 1) { tcol =>
        cfor(0)(_ < tileRows, _ + 1) { trow =>
          val tile = getTile(tcol,trow)
          cfor(0)(_ < pixelRows, _ + 1) { prow =>
            cfor(0)(_ < pixelCols, _ + 1) { pcol =>
              val acol = (pixelCols * tcol) + pcol
              val arow = (pixelRows * trow) + prow
              arr(arow*totalCols + acol) = tile.getDouble(pcol,prow)
            }
          }
        }
      }
      arr
    }
  }

  def toArrayByte():Array[Byte] = toArrayRaster.toArrayByte

  def get(col:Int, row:Int):Int = {
    val tcol = col / tileLayout.pixelCols
    val trow = row / tileLayout.pixelRows
    val pcol = col % tileLayout.pixelCols
    val prow = row % tileLayout.pixelRows

    getTile(tcol, trow).get(pcol, prow)
  }

  def getDouble(col:Int, row:Int) = {
    val tcol = col / tileLayout.pixelCols
    val trow = row / tileLayout.pixelRows
    val pcol = col % tileLayout.pixelCols
    val prow = row % tileLayout.pixelRows
    getTile(tcol, trow).getDouble(pcol, prow)
  }

  def convert(rasterType:RasterType):Raster =
    TileRaster(tiles.map(_.convert(rasterType)),rasterExtent,tileLayout)

  def map(f: Int => Int): Raster = {
    val data = RasterData.allocByType(rasterType,cols,rows)
    cfor(0)(_ < rows, _ + 1) { row =>
      cfor(0)(_ < cols, _ + 1) { col =>
        data.set(col,row, get(col,row))
      }
    }
    ArrayRaster(data,rasterExtent)
  }

  def combine(r2:Raster)(f:(Int, Int) => Int):Raster = {
    if(this.rasterExtent != r2.rasterExtent) {
      throw new GeoAttrsError("Cannot combine rasters with different raster extents." +
                             s"$rasterExtent does not match ${r2.rasterExtent}")
    }
    val data = RasterData.allocByType(rasterType,cols,rows)
    cfor(0)(_ < rows, _ + 1) { row =>
      cfor(0)(_ < cols, _ + 1) { col =>
        data.set(col,row, f(get(col,row),r2.get(col,row)))
      }
    }
    Raster(data,rasterExtent)
  }

  def mapDouble(f:Double =>Double):Raster = {
    val data = RasterData.allocByType(rasterType,cols,rows)
    cfor(0)(_ < rows, _ + 1) { row =>
      cfor(0)(_ < cols, _ + 1) { col =>
        data.setDouble(col,row, getDouble(col,row))
      }
    }
    ArrayRaster(data,rasterExtent)
  }

  def combineDouble(r2:Raster)(f:(Double, Double) => Double):Raster = {
    if(this.rasterExtent != r2.rasterExtent) {
      throw new GeoAttrsError("Cannot combine rasters with different raster extents." +
                             s"$rasterExtent does not match ${r2.rasterExtent}")
    }
    val data = RasterData.allocByType(rasterType,cols,rows)
    cfor(0)(_ < rows, _ + 1) { row =>
      cfor(0)(_ < cols, _ + 1) { col =>
        data.setDouble(col,row, f(getDouble(col,row),r2.getDouble(col,row)))
      }
    }
    Raster(data,rasterExtent)
  }

  override
  def asciiDraw():String = {
    val sb = new StringBuilder
    for(tileRow <- 0 until tileLayout.tileRows) {
      for(row <- 0 until tileLayout.pixelRows) {
        for(tileCol <- 0 until tileLayout.tileCols) {
          val tile = getTile(tileCol,tileRow)

          for(col <- 0 until tileLayout.pixelCols) {
            val v = tile.get(col,row)
            val s = if(isNoData(v)) {
              "ND"
            } else {
              s"$v"
            }
            val pad = " " * math.max(6 - s.length,0)
            sb.append(s"$pad$s")
          }
          if(tileCol != tileLayout.tileCols - 1) {
            val pad = " " * 5
            sb.append(s"$pad| ")
          }
        }
        sb.append(s"\n")
      }
      if(tileRow != tileLayout.tileRows - 1) {
        val rowDiv = "-" * (6 * tileLayout.pixelCols * tileLayout.tileCols - 2) + 
                     "-" * (6 * tileLayout.tileCols)
        sb.append(s"  $rowDiv\n")
      }
    }
    sb.toString
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy