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

geotrellis.raster.io.ascii.ReadState.scala Maven / Gradle / Ivy

/*
 * Copyright (c) 2014 Azavea.
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package geotrellis.raster.io.ascii

import scala.math.{Numeric, min, max, abs, round, floor, ceil}
import java.io.{File, FileInputStream, FileOutputStream}

import geotrellis._
import geotrellis.raster._

import spire.syntax.cfor._

trait ReadState {
  val rasterExtent: RasterExtent
  val target: RasterExtent

  /**
    * Defines the type of Raster this ReadState will read.
    */
  def getType: CellType

  /**
    * Creates the Tile of the resampled Raster.
    * By default creates an ArrayTile of the 
    * type defined by getType.
    */
  def createTile(cols: Int, rows: Int): MutableArrayTile = ArrayTile.empty(getType, cols, rows)

  /**
    * This function is called to initialize the source
    * data in preperation for resampling and assigning into
    * the destination RasterData.
    */
  protected[this] def initSource(position: Int, size: Int): Unit

  /**
    * Assign an indexed source value to the
    * destination RasterData at the specified index.
    */
  protected[this] def assignFromSource(sourceIndex: Int, dest: MutableArrayTile, destIndex: Int): Unit

  /**
    * Called for cleanup after the ReadState is no longer used.
    */
  def destroy() {}

  /**
    * Overwrite this to translate data from source to destination,
    * for example to tranlsate NoData values.
    */
  protected[this] def translate(data: MutableArrayTile): Unit = ()

  def loadRaster(): Tile = {
    val re = rasterExtent

    // keep track of cell size in our source raster
    val src_cellwidth =  re.cellwidth
    val src_cellheight = re.cellheight
    val src_cols = re.cols
    val src_rows = re.rows
    val src_xmin = re.extent.xmin
    val src_ymin = re.extent.ymin
    val src_xmax = re.extent.xmax
    val src_ymax = re.extent.ymax

    // the dimensions to resample to
    val dst_cols = target.cols
    val dst_rows = target.rows

    // calculate the dst cell size
    val dst_cellwidth  = (target.extent.xmax - target.extent.xmin) / dst_cols
    val dst_cellheight = (target.extent.ymax - target.extent.ymin) / dst_rows

    // save "normalized map coordinates" for destination cell (0, 0)
    val xbase = target.extent.xmin - src_xmin + (dst_cellwidth / 2)
    val ybase = target.extent.ymax - src_ymin - (dst_cellheight / 2)

    // track height/width in map units
    val src_map_width  = src_xmax - src_xmin
    val src_map_height = src_ymax - src_ymin

    // initialize the whole raster
    // TODO: only initialize the part we will read from
    val src_size = src_rows * src_cols
    initSource(0, src_size)
    
    // this is the resampled destination array
    val dst_size = dst_cols * dst_rows
    val resampled = createTile(dst_cols, dst_rows)

    // these are the min and max columns we will access on this row
    val min_col = (xbase / src_cellwidth).asInstanceOf[Int]
    val max_col = ((xbase + dst_cols * dst_cellwidth) / src_cellwidth).asInstanceOf[Int]

    // start at the Y-center of the first dst grid cell
    var y = ybase

    // loop over rows
    cfor(0)(_ < dst_rows, _ + 1) { dst_row =>
      // calculate the Y grid coordinate to read from
      val src_row = (src_rows - (y / src_cellheight).asInstanceOf[Int] - 1)

      // pre-calculate some spans we'll use a bunch
      val src_span = src_row * src_cols
      val dst_span = dst_row * dst_cols

      // xyz
      if (src_span + min_col < src_size && src_span + max_col >= 0) {

        // start at the X-center of the first dst grid cell
        var x = xbase
        
        // loop over cols
        cfor(0)(_ < dst_cols, _ + 1) { dst_col =>
          // calculate the X grid coordinate to read from
          val src_col = (x / src_cellwidth).asInstanceOf[Int]
          
          // compute src and dst indices and ASSIGN!
          val src_i = src_span + src_col

          if (src_col >= 0 &&
            src_col < src_cols &&
            src_i < src_size &&
            src_i >= 0) {
            val dst_i = dst_span + dst_col
            assignFromSource(src_i, resampled, dst_i)
          }
          
          // increase our X map coordinate
          x += dst_cellwidth
        }
      }

      // decrease our Y map coordinate
      y -= dst_cellheight
    }

    // build a raster object from our array and return
    translate(resampled)
    resampled
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy