Grid.java [src/java/util] Revision: default  Date:
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package util;

import csip.api.server.ServiceException;
import java.io.*;
import java.util.Scanner;
import java.util.Set;
import java.util.HashSet;
import util.WeppConstants.GridType;

/**
 * Handles ArcGIS ASCII grids.
 *
 * @author jrf
 */
public class Grid {

  int rows;
  int cols;
  int nodata;
  double cellsize;
  double xllcorner;
  double yllcorner;

  GridType type;

  float[][] fdata;
  int[][] idata;
  byte[][] bdata;

  //
  // reads an existing grid

  public Grid(GridType ty, String filename) throws IOException, ServiceException {
    rows = 0;
    cols = 0;
    int curRow = 0;
    boolean processHeader = true;
    boolean hasnodata = false;
    this.type = ty;
    xllcorner = -9999;
    yllcorner = -9999;
    cellsize = 0;

    BufferedReader input = new BufferedReader(new FileReader(filename));

    while (input.ready()) {
      String line = input.readLine();
      if (processHeader) {
        Scanner sc = new Scanner(line);
        String name = sc.next();
        if (name.equals("nrows")) {
          rows = sc.nextInt();
        } else if (name.equals("ncols")) {
          cols = sc.nextInt();
        } else if (name.equals("xllcorner")) {
          xllcorner = sc.nextDouble();
        } else if (name.equals("yllcorner")) {
          yllcorner = sc.nextDouble();
        } else if (name.equals("NODATA_value")) {
          nodata = sc.nextInt();
          hasnodata = true;
        } else if (name.equals("cellsize")) {
          cellsize = sc.nextDouble();
        } else {
          throw new ServiceException("Grid header unrecognized : " + filename);
        }
        if ((rows > 0) && (cols > 0) && (xllcorner != -9999) && (yllcorner != -9999) && (cellsize > 0) && (hasnodata)) {
          processHeader = false;
          curRow = 0;
          if (ty == GridType.INT_GRID) {
            idata = new int[rows][cols];
          }
          if (ty == GridType.FLOAT_GRID) {
            fdata = new float[rows][cols];
          }
          if (ty == GridType.BYTE_GRID) {
            bdata = new byte[rows][cols];
          }
        }

      } else {
        int row = 0;
        line = line.trim();
        String[] inData = line.split("\\s+");
        if (ty == GridType.INT_GRID) {
          for (int c = 0; c < cols; c++) {
            idata[curRow][c] = Integer.parseInt(inData[c]);
          }
        } else if (ty == GridType.FLOAT_GRID) {
          for (int c = 0; c < cols; c++) {
            fdata[curRow][c] = Float.parseFloat(inData[c]);
          }
        } else {
          for (int c = 0; c < cols; c++) {
            bdata[curRow][c] = Byte.parseByte(inData[c]);
          }
        }
        curRow = curRow + 1;
      }

    }

  }

  // clones an existing grid

  public Grid(Grid par) {
    this.rows = par.rows;
    this.cols = par.cols;
    this.nodata = par.nodata;
    this.cellsize = par.cellsize;
    this.type = par.type;
    this.xllcorner = par.xllcorner;
    this.yllcorner = par.yllcorner;
    this.type = par.type;

    if (type == GridType.INT_GRID) {
      idata = new int[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          idata[i][j] = 0;
//        }
//      }
    } else if (type == GridType.FLOAT_GRID) {
      fdata = new float[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          fdata[i][j] = 0;
//        }
//      }
    } else {
      bdata = new byte[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          bdata[i][j] = 0;
//        }
//      }
    }

  }
  // clones an existing grid


  public Grid(Grid par, GridType ty, int nod) {
    this.rows = par.rows;
    this.cols = par.cols;
    this.nodata = nod;
    this.cellsize = par.cellsize;
    this.type = ty;
    this.xllcorner = par.xllcorner;
    this.yllcorner = par.yllcorner;

    if (ty == GridType.INT_GRID) {
      idata = new int[rows][cols];
      for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
          idata[i][j] = nod;
        }
      }
    } else if (ty == GridType.FLOAT_GRID) {
      fdata = new float[rows][cols];
      for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
          fdata[i][j] = nod;
        }
      }
    } else {
      bdata = new byte[rows][cols];
      for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
          bdata[i][j] = (byte) nod;
        }
      }
    }

  }

  // creates a new, empty grid, initialized to zero

  public Grid(GridType ty, int rows, int cols, int nodata, double cellsize, double xllcorner, double yllcorner) {
    this.rows = rows;
    this.cols = cols;
    this.nodata = nodata;
    this.cellsize = cellsize;
    this.type = ty;
    this.xllcorner = xllcorner;
    this.yllcorner = yllcorner;

    if (ty == GridType.INT_GRID) {
      idata = new int[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          idata[i][j] = 0;
//        }
//      }
    } else if (ty == GridType.FLOAT_GRID) {
      fdata = new float[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          fdata[i][j] = 0;
//        }
//      }
    } else {
      bdata = new byte[rows][cols];
//      for (int i = 0; i < rows; i++) {
//        for (int j = 0; j < cols; j++) {
//          bdata[i][j] = 0;
//        }
//      }
    }

  }


  public void clear() {
    if (rows == 0) {
      return;
    }
    if (type == GridType.INT_GRID) {
      for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
          idata[i][j] = nodata;
        }
      }
    } else if (type == GridType.FLOAT_GRID) {
      for (int i = 0; i < rows; i++) {
        for (int j = 0; j < cols; j++) {
          fdata[i][j] = nodata;
        }
      }
    }

  }


  public int[][] getIntData() throws ServiceException {
    if (rows == 0) {
      return null;
    }
    if (type == GridType.INT_GRID) {
      return idata;
    } else {
      throw new ServiceException("Grid type mismatch, int");
    }
  }


  public float[][] getFloatData() throws ServiceException {
    if (rows == 0) {
      return null;
    }
    if (type == GridType.FLOAT_GRID) {
      return fdata;
    } else {
      throw new ServiceException("Grid type mismatch, float");
    }
  }


  public byte[][] getByteData() throws ServiceException {
    if (rows == 0) {
      return null;
    }
    if (type == GridType.BYTE_GRID) {
      return bdata;
    } else {
      throw new ServiceException("Grid type mismatch, byte");
    }
  }


  public int rowCount() {
    return rows;
  }


  public int colCount() {
    return cols;
  }


  public int getNoData() {
    return nodata;
  }


  public float getFloatRowCol(int r, int c) {
    if (fdata != null) {
      if ((r < rows) && (c < cols)) {
        return fdata[r][c];
      }
    }
    return nodata;
  }


  public int getIntRowCol(int r, int c) {
    if (idata != null) {
      if ((r < rows) && (c < cols)) {
        return idata[r][c];
      }
    }
    return nodata;
  }


  public void writeWeightedGrid(Grid sedWeight, File f) throws IOException, ServiceException {
    if (f.exists()) {
      f.delete();
    }
    if (!f.createNewFile()) {
      throw new ServiceException("Could not save grid file");
    }

    PrintStream o = new PrintStream(f);

    o.println("ncols " + cols);
    o.println("nrows " + rows);
    o.println("xllcorner " + xllcorner);
    o.println("yllcorner " + yllcorner);
    o.println("cellsize " + cellsize);
    o.println("NODATA_value " + nodata);

    StringBuffer b = new StringBuffer();
    if (type == GridType.INT_GRID) {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          b.append((idata[r][c]) / sedWeight.idata[r][c]);
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    } else if (type == GridType.FLOAT_GRID) {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          if (fdata[r][c] == nodata) {
            b.append(nodata);
          } else {
            b.append((fdata[r][c]) / sedWeight.fdata[r][c]);
          }
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    } else {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          b.append((bdata[r][c]) / sedWeight.bdata[r][c]);
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    }

    o.close();

  }


  public void writeGrid(File f) throws IOException, ServiceException {
    if (f.exists()) {
      f.delete();
    }
    if (!f.createNewFile()) {
      throw new ServiceException("Could not save grid file");
    }

    PrintStream o = new PrintStream(f);

    o.println("ncols " + cols);
    o.println("nrows " + rows);
    o.println("xllcorner " + xllcorner);
    o.println("yllcorner " + yllcorner);
    o.println("cellsize " + cellsize);
    o.println("NODATA_value " + nodata);

    StringBuffer b = new StringBuffer();
    if (type == GridType.INT_GRID) {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          b.append(idata[r][c]);
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    } else if (type == GridType.FLOAT_GRID) {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          if (fdata[r][c] == nodata) {
            b.append(nodata);
          } else {
            b.append(fdata[r][c]);
          }
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    } else {
      for (int r = 0; r < rows; r++) {
        b.delete(0, b.length());
        for (int c = 0; c < cols; c++) {
          b.append(bdata[r][c]);
          if (c < (cols - 1)) {
            b.append(" ");
          }
        }
        o.println(b);
      }
    }
    o.close();
  }


  public Set<Integer> intersect(Grid gr) throws ServiceException {
    Set<Integer> subs = new HashSet<>();

    int gdata[][] = gr.getIntData();
    int gnodata = gr.getNoData();

    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        if (idata[i][j] != nodata) {
          if (gdata[i][j] != gnodata) {
            subs.add(gdata[i][j]);
          }
        }
      }
    }
    return subs;
  }

  // 
  // A template grid that contains the id's that have to match the key passed to this 
  // function. When the key matches the template cell this grids data cell is
  // updated with the val passed. Tpically used to fill in a subcatchment with a 
  // single value.
  // 

  public void update(Grid template, int key, float val) throws ServiceException {
    int data[][] = template.getIntData();

    for (int i = 0; i < template.rowCount(); i++) {
      for (int j = 0; j < template.colCount(); j++) {
        if (data[i][j] == key) {
          fdata[i][j] = val;
        }
      }
    }
  }

  // 
  // A template grid that contains all ids in the correct positions. When one
  // of the vals match the template grid the new value is set in this grid.
  // This is a seletive mask that only copies a portion of the template grid.
  //

  public void maskSubareas(Grid template, int vals[], int newVal) throws ServiceException {
    int data[][] = template.getIntData();

    for (int i = 0; i < template.rowCount(); i++) {
      for (int j = 0; j < template.colCount(); j++) {
        for (int k = 0; k < vals.length; k++) {
          if (data[i][j] == vals[k]) {
            idata[i][j] = newVal;
            break;
          }
        }
      }
    }
  }


  public void maskChannels(Grid sl, Grid sy, Grid r, int nod) throws ServiceException {
    float sl_grid[][] = sl.getFloatData();
    float sy_grid[][] = sy.getFloatData();
    float r_grid[][] = r.getFloatData();

    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        if (idata[i][j] != nodata) {
          sl_grid[i][j] = nod;
          sy_grid[i][j] = nod;
          r_grid[i][j] = nod;
        }
      }
    }
  }


  public void updatePathWeightedLoss(float val[], int row[], int col[], float weight) {
    for (int i = 0; i < val.length; i++) {
      int x = row[i];
      int y = col[i];
      if (fdata[x][y] <= -999) {
        fdata[x][y] = 0;
      }
      fdata[x][y] += (val[i] * weight);
    }
  }


  public void updatePathWeight(int row[], int col[], float weight) {
    for (int i = 0; i < row.length; i++) {
      int x = row[i];
      int y = col[i];
      fdata[x][y] += weight;
    }
  }


  public void updatePathMaxLoss(float val[], int row[], int col[]) {
    for (int i = 0; i < val.length; i++) {
      int x = row[i];
      int y = col[i];
      if (val[i] > fdata[x][y]) {
        fdata[x][y] = val[i];
      }
    }
  }


  public double getCellsize() {
    return cellsize;
  }


  public int cellCountWithMask(int key, Grid mask) throws ServiceException {
    int data[][] = mask.getIntData();
    boolean lookingForStart = true;
    boolean sawVal;
    int count = 0;

    for (int i = 0; i < rows; i++) {
      sawVal = false;
      for (int j = 0; j < cols; j++) {
        if (idata[i][j] == key) {
          sawVal = true;
          lookingForStart = false;
          if (data[i][j] == 1) {
            count++;
          }
        }
      }
      if ((lookingForStart == false) && (sawVal == false)) {
        break;
      }
    }
    return count;
  }


  public int majorValue(int key, Grid subGrid) throws ServiceException {
    int data[][] = subGrid.getIntData();
    boolean lookingForStart = true;
    boolean sawVal = false;
    int counts[] = new int[WeppConstants.MAX_IDS];
    
    if (key < 0) {
        return -999;
    }

    for (int i = 0; i < WeppConstants.MAX_IDS; i++) {
      counts[i] = 0;
    }
    for (int i = 0; i < subGrid.rowCount(); i++) {
      sawVal = false;
      for (int j = 0; j < subGrid.colCount(); j++) {
        if (data[i][j] == key) {
          sawVal = true;
          lookingForStart = false;
          if (idata[i][j] < WeppConstants.MAX_IDS) {
            if (idata[i][j] >= 0) {
                counts[idata[i][j]]++;
            } else {
                // there is really no data here in the grid.
            }
          } else {
              throw new ServiceException("Grid::majorValue contains more that MAX number of ID's");
          }
        }
      }
      if ((lookingForStart == false) && (sawVal == false)) {
        break;
      }
    }

    if (lookingForStart == true) {
      // not found
      return -999;
    }
    int max = 0;
    int majorId = 0;
    for (int i = 0; i < WeppConstants.MAX_IDS; i++) {
      if (counts[i] > max) {
        max = counts[i];
        majorId = i;
      }
    }
    return majorId;
  }


  public int cellCount(int key) throws ServiceException {
    boolean lookingForStart = true;
    boolean sawVal = false;
    int count = 0;

    for (int i = 0; i < rows; i++) {
      sawVal = false;
      for (int j = 0; j < cols; j++) {
        if (idata[i][j] == key) {
          count++;
        }
      }
      if ((lookingForStart == false) && (sawVal == false)) {
        break;
      }
    }
    return count;
  }


  public boolean verifyFloat(double min, double max) {
    boolean rc = true;
    for (int i = 0; i < rows; i++) {
      for (int j = 0; j < cols; j++) {
        if (fdata[i][j] != nodata) {
          if ((fdata[i][j] < min) || (fdata[i][j] > max)) {
            // outside range
            return false;
          }
        }
      }
    }
    return rc;
  }


  public void print(PrintStream o) throws IOException, ServiceException {

    o.println("ncols " + cols);
    o.println("nrows " + rows);
    o.println("xllcorner " + xllcorner);
    o.println("yllcorner " + yllcorner);
    o.println("cellsize " + cellsize);
    o.println("NODATA_value " + nodata);

    if (type == GridType.INT_GRID) {
      for (int r = 0; r < rows; r++) {
        StringBuilder b = new StringBuilder();
        for (int c = 0; c < cols; c++) {
          b.append(idata[r][c]).append(" ");
        }
        o.println(b);
      }
    } else if (type == GridType.FLOAT_GRID) {
      for (int r = 0; r < rows; r++) {
        StringBuilder b = new StringBuilder();
        for (int c = 0; c < cols; c++) {
          b.append(fdata[r][c]).append(" ");
        }
        o.println(b);
      }
    } else {
      for (int r = 0; r < rows; r++) {
        StringBuilder b = new StringBuilder();
        for (int c = 0; c < cols; c++) {
          b.append(bdata[r][c]).append(" ");
        }
        o.println(b);
      }
    }
  }

}