gt:         GridCoverage2D coverage2d = RasterReader.readRaster(path);
context: /*
   * This file is part of JGrasstools (http://www.jgrasstools.org)
   * (C) HydroloGIS - www.hydrologis.com 
   * 
   * JGrasstools is free software: you can redistribute it and/or modify
   * it under the terms of the GNU General Public License as published by
   * the Free Software Foundation, either version 3 of the License, or
   * (at your option) any later version.
   *
   * This program is distributed in the hope that it will be useful,
   * but WITHOUT ANY WARRANTY; without even the implied warranty of
   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   * GNU General Public License for more details.
   *
   * You should have received a copy of the GNU General Public License
   * along with this program.  If not, see <http://www.gnu.org/licenses/>.
   */
  package org.jgrasstools.modules;
  
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.COLS;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.EAST;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.NORTH;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.ROWS;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.SOUTH;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.WEST;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.XRES;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.YRES;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.buildCoverage;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.createDoubleWritableRaster;
  import static org.jgrasstools.gears.utils.coverage.CoverageUtilities.getRegionParamsFromGridCoverage;
  
  import java.awt.image.WritableRaster;
  import java.util.List;
  
  import javax.media.jai.iterator.RandomIter;
  import javax.media.jai.iterator.RandomIterFactory;
  import javax.media.jai.iterator.WritableRandomIter;
  
  import org.geotools.coverage.grid.GridCoverage2D;
  import org.geotools.coverage.grid.GridEnvelope2D;
  import org.geotools.coverage.grid.GridGeometry2D;
  import org.geotools.geometry.Envelope2D;
  import org.geotools.referencing.CRS;
  import org.jgrasstools.gears.libs.modules.GridNode;
  import org.jgrasstools.gears.libs.modules.JGTConstants;
  import org.jgrasstools.gears.utils.RegionMap;
  import org.jgrasstools.gears.utils.coverage.CoverageUtilities;
  import org.jgrasstools.gears.utils.math.NumericsUtilities;
  import org.opengis.geometry.Envelope;
  import org.opengis.referencing.crs.CoordinateReferenceSystem;
  
  import com.vividsolutions.jts.geom.Coordinate;
  
  /**
   * A simple raster wrapper for scripting environment.
   * 
   * @author Andrea Antonello (www.hydrologis.com)
   */
  public class Raster {
  
      private RegionMap regionMap;
      private CoordinateReferenceSystem crs;
      private RandomIter iter;
      private WritableRaster newWR;
      private final boolean makeNew;
      private final int cols;
      private final int rows;
      private final double west;
      private final double south;
      private final double east;
      private final double north;
      private final double xRes;
      private final double yRes;
      private GridGeometry2D gridGeometry;
  
      /**
       * Create a raster for reading purposes.
       * 
       * @param raster the raster to access.
       */
      public Raster( GridCoverage2D raster ) {
          this(raster, false);
      }
  
      /**
       * Create a new raster using a given raster as template.
       * 
       * @param coverage
       * @param makeNew
       */
      public Raster( GridCoverage2D raster, boolean makeNew ) {
          this.makeNew = makeNew;
  
          crs = raster.getCoordinateReferenceSystem();
          regionMap = getRegionParamsFromGridCoverage(raster);
          cols = regionMap.getCols();
          rows = regionMap.getRows();
          west = regionMap.getWest();
          south = regionMap.getSouth();
          east = regionMap.getEast();
          north = regionMap.getNorth();
          xRes = (east - west) / cols;
          yRes = (north - south) / rows;
  
          if (makeNew) {
              newWR = createDoubleWritableRaster(cols, rows, null, null, JGTConstants.doubleNovalue);
              iter = RandomIterFactory.createWritable(newWR, null);
          } else {
              iter = RandomIterFactory.create(raster.getRenderedImage(), null);
          }
      }
  
      /**
       * Create a new raster using a given raster as template.
       * 
       * @param raster the raster to copy the properties from.
       */
      public Raster( Raster raster ) {
          makeNew = true;
  
          crs = raster.getCrs();
          cols = raster.getCols();
          rows = raster.getRows();
          west = raster.getWest();
          south = raster.getSouth();
          east = raster.getEast();
          north = raster.getNorth();
          xRes = (east - west) / cols;
          yRes = (north - south) / rows;
  
          regionMap = new RegionMap();
          regionMap.put(NORTH, north);
          regionMap.put(SOUTH, south);
          regionMap.put(WEST, west);
          regionMap.put(EAST, east);
          regionMap.put(XRES, xRes);
          regionMap.put(YRES, yRes);
          regionMap.put(ROWS, (double) rows);
          regionMap.put(COLS, (double) cols);
  
          newWR = createDoubleWritableRaster(cols, rows, null, null, JGTConstants.doubleNovalue);
          iter = RandomIterFactory.createWritable(newWR, null);
      }
  
      /**
       * Create a new raster based on the region properties.
       * 
       * @param cols
       * @param rows
       * @param res
       * @param ulEasting
       * @param ulNorthing
       * @param epsg
       */
      public Raster( int cols, int rows, double res, double ulEasting, double ulNorthing, String epsg ) {
          this.cols = cols;
          this.rows = rows;
          xRes = res;
          yRes = res;
          try {
              crs = CRS.decode(epsg);
          } catch (Exception e) {
              throw new IllegalArgumentException("Unable to get CRS from the given epsg: " + epsg);
          }
  
          double width = cols * res;
          double height = rows * res;
          west = ulEasting;
          east = ulEasting + width;
          north = ulNorthing;
          south = ulNorthing - height;
  
          regionMap = new RegionMap();
          regionMap.put(NORTH, north);
          regionMap.put(SOUTH, south);
          regionMap.put(WEST, west);
          regionMap.put(EAST, east);
          regionMap.put(XRES, res);
          regionMap.put(YRES, res);
          regionMap.put(ROWS, (double) rows);
          regionMap.put(COLS, (double) cols);
  
          makeNew = true;
          newWR = createDoubleWritableRaster(cols, rows, null, null, JGTConstants.doubleNovalue);
          iter = RandomIterFactory.createWritable(newWR, null);
      }
  
      public int getRows() {
          return rows;
      }
  
      public int getCols() {
          return cols;
      }
  
      public double getNorth() {
          return north;
      }
  
      public double getSouth() {
          return south;
      }
  
      public double getWest() {
          return west;
      }
      public double getEast() {
          return east;
      }
  
      public double getxRes() {
          return xRes;
      }
  
      public double getyRes() {
          return yRes;
      }
  
      public double getRes() {
          return xRes;
      }
  
      public CoordinateReferenceSystem getCrs() {
          return crs;
      }
  
      /**
       * Get the raster value at a given col/row.
       * 
       * @param col
       * @param row
       * @return the value.
       */
      public double valueAt( int col, int row ) {
          if (isInRaster(col, row)) {
              double value = iter.getSampleDouble(col, row, 0);
              return value;
          }
          return JGTConstants.doubleNovalue;
      }
  
      /**
       * Get world position from col, row.
       * 
       * @param col
       * @param row
       * @return the [x, y] position or <code>null</code> if outside the bounds.
       */
      public double[] positionAt( int col, int row ) {
          if (isInRaster(col, row)) {
              GridGeometry2D gridGeometry = getGridGeometry();
              Coordinate coordinate = CoverageUtilities.coordinateFromColRow(col, row, gridGeometry);
              return new double[]{coordinate.x, coordinate.y};
          }
          return null;
      }
  
      /**
       * Get grid col and row from a world coordinate.
       * 
       * @param x
       * @param y
       * @return the [col, row] or <code>null</code> if the position is outside the bounds.
       */
      public int[] gridAt( double x, double y ) {
          if (isInRaster(x, y)) {
              GridGeometry2D gridGeometry = getGridGeometry();
              int[] colRowFromCoordinate = CoverageUtilities.colRowFromCoordinate(new Coordinate(x, y), gridGeometry, null);
              return colRowFromCoordinate;
          }
          return null;
      }
  
      /**
       * Sets a raster value if the raster is writable.
       * 
       * @param col
       * @param row
       * @param value
       */
      public void setValueAt( int col, int row, double value ) {
          if (makeNew) {
              if (isInRaster(col, row)) {
                  ((WritableRandomIter) iter).setSample(col, row, 0, value);
              } else {
                  throw new RuntimeException("Setting value outside of raster.");
              }
          } else {
              throw new RuntimeException("Writing not allowed.");
          }
      }
  
      /**
       * Get the values of the surrounding cells.
       * 
       * <b>The order of the values is [E, EN, N, NW, W, WS, S, SE].</b>
       * 
       * @param col the col of the center cell.
       * @param row the row of the center cell.
       * @return the array of cell values around them as [E, EN, N, NW, W, WS, S, SE].
       */
      public double[] surrounding( int col, int row ) {
          GridNode node = new GridNode(iter, cols, rows, xRes, yRes, col, row);
          List<GridNode> surroundingNodes = node.getSurroundingNodes();
          double[] surr = new double[8];
          for( int i = 0; i < surroundingNodes.size(); i++ ) {
              GridNode gridNode = surroundingNodes.get(i);
              if (gridNode != null) {
                  surr[i] = gridNode.elevation;
              } else {
                  surr[i] = JGTConstants.doubleNovalue;
              }
          }
          return surr;
      }
  
      public boolean isNoValue( double value ) {
          return JGTConstants.isNovalue(value);
      }
  
      public double novalue() {
          return JGTConstants.doubleNovalue;
      }
  
      public static boolean valuesEqual( double value1, double value2 ) {
          return NumericsUtilities.dEq(value1, value2);
      }
  
      public GridGeometry2D getGridGeometry() {
          if (gridGeometry == null) {
              Envelope envelope = new Envelope2D(crs, west, south, east - west, north - south);
              GridEnvelope2D gridRange = new GridEnvelope2D(0, 0, cols, rows);
              gridGeometry = new GridGeometry2D(gridRange, envelope);
          }
          return gridGeometry;
      }
  
      /**
       * Creates a {@link GridCoverage2D} from the {@link Raster}.
       * 
       * @return the coverage.
       */
      public GridCoverage2D buildRaster() {
          if (makeNew) {
              GridCoverage2D coverage = buildCoverage("raster", newWR, regionMap, crs);
              return coverage;
          } else {
              throw new RuntimeException("The raster is readonly, so no new raster can be built.");
          }
      }
  
      /**
       * Write the raster to file.
       * 
       * @param path th epath to write to.
       * @throws Exception
       */
      public void write( String path ) throws Exception {
          if (makeNew) {
              RasterWriter.writeRaster(path, buildRaster());
          } else {
              throw new RuntimeException("Only new rasters can be dumped.");
          }
      }
  
      /**
       * Read a raster from file.
       * 
       * @param path the path to the raster to read.
       * @return the read raster in readonly mode.
       * @throws Exception
       */
      public static Raster read( String path ) throws Exception {
  