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

geotrellis.Extent.scala Maven / Gradle / Ivy

The newest version!
package geotrellis

import scala.math.{min,max}

import geotrellis.feature.Polygon

case class ExtentRangeError(msg:String) extends Exception(msg)

object Extent {
  /** Parses a string in the format "xmin,ymin,xmax,ymax" form, e.g.
    * 100.00,600.00,300.00,800.00
    */
  def fromString(s:String) = {
    val Array(xmin,ymin,xmax,ymax) = s.split(",").map(_.toDouble)
    Extent(xmin,ymin,xmax,ymax)
  }
}

/**
 * An Extent represents a rectangular region of geographic space (with a
 * particular projection). It is expressed in map coordinates. It is not
 * concerned with details of e.g. cell sizes (for that, see RasterExtent).
 */
case class Extent(xmin:Double, ymin:Double, xmax:Double, ymax:Double) {
  if (xmin > xmax) throw ExtentRangeError(s"x: $xmin to $xmax")
  if (ymin > ymax) throw ExtentRangeError(s"y: $ymin to $ymax")
  
  val height = ymax - ymin
  val width = xmax - xmin
  
  /**
   * Orders two extents by their (geographically) lower-left corner. The extent
   * that is further south (or west in the case of a tie) comes first.
   *
   * If the lower-left corners are the same, the upper-right corners are
   * compared. This is mostly to assure that 0 is only returned when the
   * extents are equal.
   *
   * Return type signals:
   *
   *   -1 this extent comes first
   *    0 the extents have the same lower-left corner
   *    1 the other extent comes first
   */
  def compare(other:Extent):Int = {
    var cmp = ymin compare other.ymin
    if (cmp != 0) return cmp

    cmp = xmin compare other.xmin
    if (cmp != 0) return cmp

    cmp = ymax compare other.ymax
    if (cmp != 0) return cmp

    xmax compare other.xmax
  }
  
  /**
   * Return a the smallest extent that contains this extent and the provided
   * extent. This is provides a union of the two extents.
   */
  def combine(other:Extent):Extent = {
    val xminNew = min(xmin, other.xmin)
    val xmaxNew = max(xmax, other.xmax)
    val yminNew = min(ymin, other.ymin)
    val ymaxNew = max(ymax, other.ymax)
    Extent(xminNew, yminNew, xmaxNew, ymaxNew)
  }

  /**
   * Takes the intersection of two extents.
   */
  def intersect(other:Extent):Option[Extent] = {
    val xminNew = max(xmin, other.xmin)
    val xmaxNew = min(xmax, other.xmax)
    val yminNew = max(ymin, other.ymin)
    val ymaxNew = min(ymax, other.ymax)
    if(xminNew <= xmaxNew && yminNew <= ymaxNew) {
      Some(Extent(xminNew, yminNew, xmaxNew, ymaxNew))
    } else { None }
  }

  /**
   * Returns true if these extents share at least
   * one point in common.
   */
  def intersects(other:Extent):Boolean =
    !(other.xmax < xmin ||
      other.xmin > xmax) &&
    !(other.ymax < ymin ||
      other.ymin > ymax)
  
  /**
   * Determine whether the given point lies within the extent. The boundary
   * is excluded, so that Extent(a, b, c, d) does not contain (a, b).
   */
  def containsPoint(x:Double, y:Double) = {
    x > xmin && x < xmax && y > ymin && y < ymax
  }

  /**
   * Determines whether the given extent is contained within the extent.
   */
  def containsExtent(other:Extent) = {
    other.xmin >= xmin &&
    other.ymin >= ymin &&
    other.xmax <= xmax &&
    other.ymax <= ymax
  }
  
  /**
   * Return SW corner (xmin, ymin) as tuple.
   */
  def southWest = (xmin, ymin)

  /**
   * Return SE corner (xmax, ymin) as tuple.
   */
  def southEast = (xmax, ymin)
 
  /**
   * Return NE corner (xmax, ymax) as tuple.
   */
  def northEast = (xmax, ymax)

  /**
   * Return NW corner (xmin, ymax) as tuple.
   */
  def northWest = (xmin, ymax)

  /**
   * Return extent as feature.
   */
  def asFeature[D](data:D) = Polygon(
    List(northEast, southEast, southWest, northWest, northEast),
    data
  )
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy