/* * Copyright (C) 2011-2012 Dr. John Lindsay <jlindsay@uoguelph.ca> * * This program 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 whitebox.geospatialfiles; import java.util.ArrayList; import java.util.Arrays; import java.io.*; import java.nio.*; import java.nio.channels.FileChannel; import java.util.Date; /** * The whiteboxRaster is used to manipulate Whitebox GAT raster files (.dep and .tas). * @author John Lindsay */ public class WhiteboxRaster { // ************************ // Fields // ************************ private double[][] grid; private Date[] lastUsed; private boolean[] rowIsDirty; private int blockSize = 0; private int numRowsInMemory = 0; private double initialValue; private boolean isDirty = false; /** * Set to false if the header and data files (.dep and .tas) should be deleted * when the object is closed. */ public boolean isTemporaryFile = false; /** * Set to true when the getValue function should reflect beyond the edges. */ public boolean isReflectedAtEdges = false; // ************************ // Constructors // ************************ /** * Class constructor. Notice that the data file name will also be set based on the * specified header file name. * @param HeaderFile The name of the WhiteboxRaster header file. * @param FileAccess Sets the file access. Either "r" (read-only) or "rw" (read/write). */ public WhiteboxRaster(String HeaderFile, String FileAccess) { // set the header file and data file. headerFile = HeaderFile; dataFile = headerFile.replace(".dep", ".tas"); statsFile = headerFile.replace(".dep", ".wstat"); setFileAccess(FileAccess); readHeaderFile(); setBlockData(); } /** * Class constructor. Notice that the data file name will also be set based on the * specified header file name. * @param HeaderFile The name of the WhiteboxRaster header file. * @param FileAccess Sets the file access. Either "r" (read-only) or "rw" (read/write). * @param BufferSize Determines the how much data can be stored in memory. */ public WhiteboxRaster(String HeaderFile, String FileAccess, double BufferSize) { // set the header file and data file. headerFile = HeaderFile; dataFile = headerFile.replace(".dep", ".tas"); statsFile = headerFile.replace(".dep", ".wstat"); setFileAccess(FileAccess); setBufferSize(BufferSize); readHeaderFile(); setBlockData(); } /** * Class constructor. Notice that the data file name will also be set based on the * specified header file name. * @param HeaderFile The name of the WhiteboxRaster header file. * @param FileAccess Sets the file access. Either "r" (read-only) or "rw" (read/write). * @param BaseRasterHeader The name of a WhiteboxRaster header file to base this new object on. * @param DataType The data type of the new WhiteboxRaster. Can be 'double', 'float', 'integer', or 'byte' * @param InitialValue Double indicating the value used to initialize the grid. It is recommended to use the noDataValue. */ public WhiteboxRaster(String HeaderFile, String FileAccess, String BaseRasterHeader, String DataType, double InitialValue) { // set the header file and data file. headerFile = HeaderFile; dataFile = headerFile.replace(".dep", ".tas"); statsFile = headerFile.replace(".dep", ".wstat"); File f1 = new File(this.headerFile); f1.delete(); f1 = new File(this.dataFile); f1.delete(); f1 = new File(this.statsFile); f1.delete(); initialValue = InitialValue; setFileAccess(FileAccess); setPropertiesUsingAnotherRaster(BaseRasterHeader, DataType); setBlockData(); } /** * Class constructor. Notice that the data file name will also be set based on the * specified header file name. * @param HeaderFile The name of the WhiteboxRaster header file. * @param FileAccess Sets the file access. Either "r" (read-only) or "rw" (read/write). * @param BaseRasterHeader The name of a WhiteboxRaster header file to base this new object on. * @param DataType The data type of the new WhiteboxRaster. Can be 'double', 'float', 'integer', or 'byte' * @param InitialValue Double indicating the value used to initialize the grid. It is recommended to use the noDataValue. * @param BufferSize Determines how much data can be stored in memory. */ public WhiteboxRaster(String HeaderFile, String FileAccess, String BaseRasterHeader, String DataType, double InitialValue, double BufferSize) { // set the header file and data file. headerFile = HeaderFile; dataFile = headerFile.replace(".dep", ".tas"); statsFile = headerFile.replace(".dep", ".wstat"); File f1 = new File(this.headerFile); f1.delete(); f1 = new File(this.dataFile); f1.delete(); f1 = new File(this.statsFile); f1.delete(); initialValue = InitialValue; setFileAccess(FileAccess); setBufferSize(BufferSize); setPropertiesUsingAnotherRaster(BaseRasterHeader, DataType); setBlockData(); } // *********************************** // Property getter and setter methods. // *********************************** private String headerFile; /** * Gets the header file (*.dep) name for this Whitebox raster grid. * Notice that the header file name is set during object creation. * @return A string containing the reference to the header file. */ public String getHeaderFile() { return headerFile; } private String dataFile; /** * Gets the data file (*.tas) name for this Whitebox raster grid. * Notice that the data file name is set during object creation. * @return A string containing the reference to the data file. */ public String getDataFile() { return dataFile; } /** * Used to determine the size of the data file (.tas). * @return long containing the size of the data file in bytes. */ public long getDataFileSize() { File file = new File(dataFile); return file.length(); } private String statsFile; /** * Gets the statistical distribution file (*.wstat) name for this Whitebox raster * grid. Notice that the stats file name is set during object creation. * @return A string containing the reference to the stats file. */ public String getStatsFile() { return statsFile; } private final double largeValue = (double)Float.MAX_VALUE; private final double smallValue = (double)-Float.MAX_VALUE; private double minimumValue = largeValue; /** * Retrieves the minimum value in the Whitebox grid. * @return The minimum value. */ public double getMinimumValue() { return this.minimumValue; } /** * Sets the minimum value in the Whitebox grid. * @param MinimumValue The minimum value. */ public void setMinimumValue(double MinimumValue) { this.minimumValue = MinimumValue; } private double maximumValue = smallValue; /** * Retrieves the maximum value in the Whitebox grid. * @return The maximum value. */ public double getMaximumValue() { return maximumValue; } /** * Sets the maximum value in the Whitebox grid. * @param MaximumValue The minimum value. */ public void setMaximumValue(double MaximumValue) { maximumValue = MaximumValue; } private double north; /** * Retrieves the coordinate of the northern edge. * @return The coordinate of the northern edge. */ public double getNorth() { return north; } /** * Sets the coordinate of the northern edge. * @param North The coordinate of the northern edge. */ public void setNorth(float North) { north = North; } private double south; /** * Retrieves the coordinate of the southern edge. * @return The coordinate of the southern edge. */ public double getSouth() { return south; } /** * Sets the coordinate of the southern edge. * @param South The coordinate of the southern edge. */ public void setSouth(float South) { south = South; } private double west; /** * Retrieves the coordinate of the western edge. * @return The coordinate of the western edge. */ public double getWest() { return west; } /** * Sets the coordinate of the western edge. * @param West The coordinate of the western edge. */ public void setWest(float West) { west = West; } private double east; /** * Retrieves the coordinate of the eastern edge. * @return The coordinate of the eastern edge. */ public double getEast() { return east; } /** * Sets the coordinate of the eastern edge. * @param East The coordinate of the eastern edge. */ public void setEast(float East) { east = East; } private int numberColumns; /** * Retrieves the number of columns in the grid. * @return The number of columns. */ public int getNumberColumns() { return numberColumns; } private int numberRows; /** * Retrieves the number of rows in the grid. * @return The number of rows. */ public int getNumberRows() { return numberRows; } private int cellSizeInBytes = 8; private String dataType = "double"; /** * Retrieves the data type for this Whitebox grid. Data type may be <b><i>float</i></b> (decimal * numbers), <i><b>integer</i></b> (whole numbers from -32,768 to 32,767), or <i><b>byte</i></b> * (whole number from 0 to 255). * @return Data type. */ public String getDataType() { return dataType; } /** * Sets the data type for this Whitebox grid. Data type may be <b><i>float</i></b> (decimal * numbers), <i><b>integer</i></b> (whole numbers from -32,768 to 32,767), or <i><b>byte</i></b> (whole * number from 0 to 255). * @param DataType The specified data type. */ public void setDataType(String DataType) { if (DataType.toLowerCase().equals("float")) { dataType = "float"; cellSizeInBytes = 4; } else if (DataType.toLowerCase().contains("int")) { dataType = "integer"; cellSizeInBytes = 2; } else if (DataType.toLowerCase().equals("byte")) { dataType = "byte"; cellSizeInBytes = 1; } else if (DataType.toLowerCase().equals("double")) { dataType = "double"; cellSizeInBytes = 8; } else { dataType = "float"; cellSizeInBytes = 4; } } public static final int DATA_SCALE_CONTINUOUS = 0; public static final int DATA_SCALE_CATEGORICAL = 1; public static final int DATA_SCALE_BOOLEAN = 2; public static final int DATA_SCALE_RGB = 3; private int dataScale = DATA_SCALE_CONTINUOUS; /** * Retrieves the data scale for this Whitebox grid. Data scale may be <b><i>DATA_SCALE_CONTINUOUS</i></b> (0), * <i><b>DATA_SCALE_CATEGORICAL</i></b> (1), <i><b>DATA_SCALE_BOOLEAN</i></b> (2), or <i><b>DATA_SCALE_RGB</i></b> (3). * @return int Data scale. */ public int getDataScale() { return dataScale; } /** * Sets the data scale for this Whitebox grid. Data scale may be <b><i>DATA_SCALE_CONTINUOUS</i></b> (0), * <i><b>DATA_SCALE_CATEGORICAL</i></b> (1), <i><b>DATA_SCALE_BOOLEAN</i></b> (2), or <i><b>DATA_SCALE_RGB</i></b> (3). * @param DataScale The specified data type. */ public void setDataScale(int DataScale) { if (DataScale < 0) { DataScale = 0; } if (DataScale > 3) { DataScale = 3; } dataScale = DataScale; } private String zUnits = "not specified"; /** * Retrieves the Z units for this Whitebox grid. * @return Z Units. */ public String getZUnits() { return zUnits; } /** * Sets units of the attribute data, i.e. the z-values in the raster image. * @param ZUnits The specified data type. */ public void setZUnits(String ZUnits) { zUnits = ZUnits.toLowerCase(); } private String xyUnits = "not specified"; /** * Retrieves the XY units for this Whitebox grid. * @return XY Units. */ public String getXYUnits() { return xyUnits; } /** * Sets units of the attribute data, i.e. the xy-values in the raster image. * @param XYUnits The specified data type. */ public void setXYUnits(String XYUnits) { xyUnits = XYUnits.toLowerCase(); } private String projection = "not specified"; /** * Retrieves the projection for this Whitebox grid. * @return Projection. */ public String getProjection() { return projection; } /** * Sets projection the raster image. * @param Projection The specified projection. */ public void setProjection(String Projection) { projection = Projection; } private double displayMinimum = largeValue; /** * Retrieves the display minimum for this Whitebox grid. * @return Display minimum. */ public double getDisplayMinimum() { return displayMinimum; } /** * Sets display minimum. * @param DisplayMinimum The specified projection. */ public void setDisplayMinimum(double DisplayMinimum) { displayMinimum = DisplayMinimum; } private double displayMaximum = smallValue; /** * Retrieves the display maximum for this Whitebox grid. * @return Display maximum. */ public double getDisplayMaximum() { return displayMaximum; } /** * Sets display maximum. * @param DisplayMaximum The specified projection. */ public void setDisplayMaximum(double DisplayMaximum) { displayMaximum = DisplayMaximum; } private String preferredPalette = "not specified"; /** * Retrieves the preferred palette for this Whitebox grid. * @return Preferred palette. */ public String getPreferredPalette() { return preferredPalette; } /** * Sets the preferred palette used to display the raster image. * @param PreferredPalette The default palette used to display the image, * e.g. <b><i>earthtones.pal</b></i> or <b><i>spectrum.pal</b></i>. */ public void setPreferredPalette(String PreferredPalette) { PreferredPalette.replace(".plt", ".pal"); preferredPalette = PreferredPalette; } private long bufferSize = Runtime.getRuntime().totalMemory(); //20 * 1048576; //in bytes /** * Retrieves the maximum memory usage for this Whitebox grid in megabytes. * @return Maximum memory. */ public double getBufferSize() { return bufferSize / 1048576; } /** * Sets maximum memory usage for this Whitebox grid in megabytes. * @param BufferSize maximum memory usage. */ private void setBufferSize(double BufferSize) { bufferSize = (long) (BufferSize * 1048576); } /** * Retrieves the block size contained in memory. * @return Long containing block size */ public long getBlockSize() { return blockSize; } private double noDataValue = -32768d; /** * Retrieves the numeric value used to specify a grid cell containing no data or void. * @return float NoData value. */ public double getNoDataValue() { return noDataValue; } /** * Sets the NoData value used in this raster image. * @param value A float specifying the value used. Default value is -32768. */ public void setNoDataValue(double value) { noDataValue = value; } private double cellSizeX = 0; /** * The grid resolution in the X direction. * @return float containing the x-direction grid resolution */ public double getCellSizeX() { if (cellSizeX == 0) { cellSizeX = Math.abs(this.east - this.west) / this.numberColumns; } return cellSizeX; } private double cellSizeY = 0; /** * The grid resolution in the Y direction. * @return float containing the y-direction grid resolution */ public double getCellSizeY() { if (cellSizeY == 0) { cellSizeY = Math.abs(this.east - this.west) / this.numberColumns; } return cellSizeY; } private long numberOfDataFileReads = 0; /** * The number of times that the data file (.tas) has been read by this object. * @return long stating the number of reads. */ public long getNumberOfDataFileReads() { return numberOfDataFileReads; } private long numberOfDataFileWrites = 0; /** * The number of times that the data file (.tas) has been written by this object. * @return long stating the number of reads. */ public long getNumberOfDataFileWrites() { return numberOfDataFileWrites; } private ByteOrder byteOrder = java.nio.ByteOrder.nativeOrder(); // "LITTLE_ENDIAN"; /** * Gets the file byte order (either LITTLE_ENDIAN or BIG_ENDIAN). * @return */ public String getByteOrder() { return byteOrder.toString(); } /** * Sets the file byte order (either LITTLE_ENDIAN or BIG_ENDIAN). * @param value */ public void setByteOrder(String value) { if ((value.toLowerCase().contains("little")) || (value.toLowerCase().contains("lsb")) || (value.toLowerCase().contains("least")) || (value.toLowerCase().contains("intel"))) { byteOrder = ByteOrder.LITTLE_ENDIAN; } else { byteOrder = ByteOrder.BIG_ENDIAN; } } private boolean saveChanges = true; /** * Used to determine the file access mode set during object construction. * @return "rw" (read/write) or "r" (read-only). */ public String getFileAccess() { if (saveChanges) { return "rw"; } else { return "r"; } } private void setFileAccess(String value) { if (value.toLowerCase().contains("w")) { saveChanges = true; } else { saveChanges = false; } } private ArrayList<String> metadata = new ArrayList<String>(); /** * Adds a metadata entry to the header file. * @param value String containing the metadata entry. */ public void addMetadataEntry(String value) { metadata.add(value.replaceAll(";", ":")); } /** * Retrieves an ArrayList containing all of the metadata entries for this raster. * @return ArrayList of metadata strings. */ public ArrayList<String> getMetadata() { return metadata; } /** * Used to delete a metadata entry * @param i The entry number in the metadata arraylist to delete. */ public void deleteMetadataEntry(int i) { if (i < metadata.size()) { metadata.remove(i); } } private double stdDeviation = noDataValue; public double getStandardDeviation() { if (stdDeviation == noDataValue) { readStatsFile(); } return stdDeviation; } private double mode = noDataValue; public double getMode() { if (mode == noDataValue) { readStatsFile(); } return mode; } private double mean = noDataValue; public double getMean() { if (mean == noDataValue) { readStatsFile(); } return mean; } private double median = noDataValue; public double getMedian() { if (median == noDataValue) { readStatsFile(); } return median; } private long[] histo = null; public long[] getHisto() { if (mean == noDataValue) { readStatsFile(); } return histo; } private double binWidth = noDataValue; public double getHistoBinWidth() { if (binWidth == noDataValue) { readStatsFile(); } return binWidth; } private long numValidCells = (long)noDataValue; public long getnumValidCells() { if (numValidCells == (long)noDataValue) { readStatsFile(); } return numValidCells; } //******************************************** // Available methods. // ******************************************* /** * This method should be used when you need to access an entire row of data * at a time. It has less overhead that the getValue method and can be used * to efficiently scan through a raster image row by row. It will read the * specified row from disk and will not store it internally within the * WhiteboxRaster. As such, this method is appropriate when each of the cells * in the raster need to be accessed sequentially one time only. This is the * case, for example, when the raster is displayed as an image. * @param row An int stating the zero-based row to be returned. * @return An array of doubles containing the values store in the specified row. */ public double[] getRowValues(int row) { if (row < 0 || row >= numberRows) { return null; } double[] retVals = new double[numberColumns]; RandomAccessFile rIn = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(dataFile); if (!file.exists()) { createNewDataFile(); } // what is the starting and ending cell? long startingCell = row * numberColumns; long endingCell = startingCell + numberColumns - 1; int writeLengthInCells = (int)(endingCell - startingCell + 1); buf = ByteBuffer.allocate((int) (writeLengthInCells * cellSizeInBytes)); rIn = new RandomAccessFile(dataFile, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(startingCell * cellSizeInBytes); inChannel.read(buf); // Check the byte order. buf.order(byteOrder); if (dataType.equals("double")) { buf.rewind(); DoubleBuffer db = buf.asDoubleBuffer(); retVals = new double[writeLengthInCells]; db.get(retVals); db = null; buf = null; } else if (dataType.equals("float")) { buf.rewind(); FloatBuffer fb = buf.asFloatBuffer(); float[] fa = new float[writeLengthInCells]; fb.get(fa); fb = null; buf = null; retVals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { retVals[j] = fa[j]; } fa = null; } else if (dataType.equals("integer")) { buf.rewind(); ShortBuffer ib = buf.asShortBuffer(); short[] ia = new short[writeLengthInCells]; ib.get(ia); ib = null; buf = null; retVals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { retVals[j] = ia[j]; } ia = null; } else if (dataType.equals("byte")) { buf.rewind(); byte[] ba = new byte[writeLengthInCells]; buf.get(ba); buf = null; retVals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { retVals[j] = ba[j]; } ba = null; } } catch (Exception e) { System.err.println("Caught exception: " + e.toString()); System.err.println(e.getStackTrace()); } finally { if (rIn != null) { try{ rIn.close(); } catch (Exception e){} } numberOfDataFileReads++; return retVals.clone(); } } private boolean readRow(int row) { double[] vals = new double[numberColumns]; RandomAccessFile rIn = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(dataFile); if (!file.exists()) { createNewDataFile(); } // what is the starting and ending cell? long startingCell = row * numberColumns; long endingCell = startingCell + numberColumns - 1; int writeLengthInCells = (int)(endingCell - startingCell + 1); buf = ByteBuffer.allocate((int) (writeLengthInCells * cellSizeInBytes)); rIn = new RandomAccessFile(dataFile, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(startingCell * cellSizeInBytes); inChannel.read(buf); // Check the byte order. buf.order(byteOrder); if (dataType.equals("double")) { buf.rewind(); DoubleBuffer db = buf.asDoubleBuffer(); vals = new double[writeLengthInCells]; db.get(vals); db = null; buf = null; } else if (dataType.equals("float")) { buf.rewind(); FloatBuffer fb = buf.asFloatBuffer(); float[] fa = new float[writeLengthInCells]; fb.get(fa); fb = null; buf = null; vals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { vals[j] = fa[j]; } fa = null; } else if (dataType.equals("integer")) { buf.rewind(); ShortBuffer ib = buf.asShortBuffer(); short[] ia = new short[writeLengthInCells]; ib.get(ia); ib = null; buf = null; vals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { vals[j] = ia[j]; } ia = null; } else if (dataType.equals("byte")) { buf.rewind(); byte[] ba = new byte[writeLengthInCells]; buf.get(ba); buf = null; vals = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { vals[j] = ba[j]; } ba = null; } if (numRowsInMemory >= blockSize) { Date minLastUsedTime = lastUsed[0]; int whichRow = 0; for (int i = 1; i < numberRows; i++) { if (lastUsed[i].before(minLastUsedTime)) { minLastUsedTime = lastUsed[i]; whichRow = i; } } if (rowIsDirty[whichRow] && saveChanges) { writeRow(whichRow); } grid[whichRow] = null; numRowsInMemory--; } grid[row] = vals; numRowsInMemory++; return true; } catch (Exception e) { System.err.println("Caught exception: " + e.toString()); System.err.println(e.getStackTrace()); return false; } finally { if (rIn != null) { try{ rIn.close(); } catch (Exception e){} } numberOfDataFileReads++; } } private boolean writeRow(int row) { if (!saveChanges) { return false; } // update the minimum and maximum values double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (int i = 0; i < numberColumns; i++) { if (grid[row][i] < min && grid[row][i] != noDataValue) { min = grid[row][i]; } if (grid[row][i] > max && grid[row][i] != noDataValue) { max = grid[row][i]; } } if (max > maximumValue) { maximumValue = max; } if (min < minimumValue) { minimumValue = min; } RandomAccessFile rOut = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(dataFile); if (!file.exists()) { createNewDataFile(); } long startingCell = row * numberColumns; long endingCell = startingCell + numberColumns - 1; rOut = new RandomAccessFile(dataFile, "rw"); FileChannel outChannel = rOut.getChannel(); outChannel.position(startingCell * cellSizeInBytes); int writeLengthInCells = (int) (endingCell - startingCell + 1); if (dataType.equals("double")) { buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); DoubleBuffer db = buf.asDoubleBuffer(); db.put(grid[row]); db = null; outChannel.write(buf); } else if (dataType.equals("float")) { float[] fa = new float[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { fa[j] = (float)grid[row][j]; } buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); FloatBuffer fb = buf.asFloatBuffer(); fb.put(fa); fb = null; fa = null; outChannel.write(buf); } else if (dataType.equals("integer")) { short[] ia = new short[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { ia[j] = (short)grid[row][j]; } buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); ShortBuffer ib = buf.asShortBuffer(); ib.put(ia); ib = null; ia = null; outChannel.write(buf); } else if (dataType.equals("byte")) { byte[] ba = new byte[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { ba[j] = (byte)grid[row][j]; } buf = ByteBuffer.wrap(ba); ba = null; outChannel.write(buf); } outChannel.close(); } catch (Exception e) { System.err.println("Caught exception: " + e.toString()); System.err.println(e.getStackTrace()); } finally { buf = null; if (rOut != null) { try{ rOut.close(); } catch (Exception e){} } rowIsDirty[row] = false; numberOfDataFileWrites++; return true; } } private void writeAllRows() { for (int i = 0; i < numberRows; i++) { if (saveChanges && rowIsDirty[i]) { writeRow(i); } } } /** * Retrieves the value contained at a specified cell in the raster grid. * @param row The zero-based row number. * @param column The zero-based column number. * @return The value contained in the raster grid at the specified grid cell. */ public double getValue(int row, int column){ if (column >= 0 && column < numberColumns && row >= 0 && row < numberRows) { if (grid[row] == null) { readRow(row); } return grid[row][column]; } else { if (!isReflectedAtEdges) { return noDataValue; } // if you get to this point, it is reflected at the edges if (row < 0) { row = -row; } if (row >= numberRows) { row = numberRows - (row - numberRows); } if (column < 0) { column = -column; } if (column >= numberColumns) { column = numberColumns - (column - numberColumns); } if (column >= 0 && column < numberColumns && row >= 0 && row < numberRows) { return getValue(row, column); } else { // it was too off grid to be reflected. return noDataValue; } } } /** * Sets the value of a specified cell in the raster grid. * @param row the zero-based row number. * @param column The zero-based column number. * @param value The value to place in the grid cell. */ public void setValue(int row, int column, double value){ if (saveChanges && column >= 0 && column < this.numberColumns && row >= 0 && row < this.numberRows) { if (grid[row] == null) { readRow(row); } grid[row][column] = value; rowIsDirty[row] = true; isDirty = true; } } /** * Reads the contents of the header file and fills the properties of the * Whitebox grid. */ private void readHeaderFile() { DataInputStream in = null; BufferedReader br = null; boolean byteOrderRead = false; try { // Open the file that is the first command line parameter FileInputStream fstream = new FileInputStream(this.headerFile); // Get the object of DataInputStream in = new DataInputStream(fstream); br = new BufferedReader(new InputStreamReader(in)); if (this.headerFile != null) { String line; String[] str; //Read File Line By Line while ((line = br.readLine()) != null) { str = line.split("\t"); if (str[0].toLowerCase().contains("min:") && (str[0].toLowerCase().contains("display") == false)) { this.minimumValue = Float.parseFloat(str[1]); } else if (str[0].toLowerCase().contains("max:") && (str[0].toLowerCase().contains("display") == false)) { this.maximumValue = Float.parseFloat(str[1]); } else if (str[0].toLowerCase().contains("north")) { this.north = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("south")) { this.south = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("west")) { this.west = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("east")) { this.east = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("cols")) { this.numberColumns = Integer.parseInt(str[1]); } else if (str[0].toLowerCase().contains("rows")) { this.numberRows = Integer.parseInt(str[1]); } else if (str[0].toLowerCase().contains("data type")) { this.setDataType(str[1]); } else if (str[0].toLowerCase().contains("data scale")) { if (str[1].toLowerCase().contains("continuous")) { this.setDataScale(DATA_SCALE_CONTINUOUS); } else if (str[1].toLowerCase().contains("categorical")) { this.setDataScale(DATA_SCALE_CATEGORICAL); } else if (str[1].toLowerCase().contains("bool")) { this.setDataScale(DATA_SCALE_BOOLEAN); } else if (str[1].toLowerCase().contains("rgb")) { this.setDataScale(DATA_SCALE_RGB); } } else if (str[0].toLowerCase().contains("z units")) { this.setZUnits(str[1]); } else if (str[0].toLowerCase().contains("xy units")) { this.setXYUnits(str[1]); } else if (str[0].toLowerCase().contains("projection")) { this.projection = str[1]; } else if (str[0].toLowerCase().contains("display min")) { this.displayMinimum = Float.parseFloat(str[1]); } else if (str[0].toLowerCase().contains("display max")) { this.displayMaximum = Float.parseFloat(str[1]); } else if (str[0].toLowerCase().contains("preferred palette")) { this.preferredPalette = str[1].replace(".plt", ".pal"); } else if (str[0].toLowerCase().contains("byte order")) { this.setByteOrder(str[1]); byteOrderRead = true; } else if (str[0].toLowerCase().contains("nodata")) { this.noDataValue = Double.parseDouble(str[1]); System.out.println(str[1]); } else if (str[0].toLowerCase().contains("metadata entry")) { if (str.length > 1) { this.addMetadataEntry(str[1]); } } } //Close the input stream in.close(); br.close(); if (byteOrderRead == false) { this.byteOrder = ByteOrder.LITTLE_ENDIAN; } } } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { try { if (in != null || br!= null) { in.close(); br.close(); } } catch (java.io.IOException ex) { } } } /** * Writes the whiteboxRaster header file (.dep) to disc. */ public void writeHeaderFile() { String str1 = null; File file = new File(this.headerFile); FileWriter fw = null; BufferedWriter bw = null; PrintWriter out = null; try { if (this.displayMaximum == smallValue) { this.displayMaximum = this.maximumValue; } if (this.displayMinimum == largeValue) { this.displayMinimum = this.minimumValue; } fw = new FileWriter(file, false); bw = new BufferedWriter(fw); out = new PrintWriter(bw, true); str1 = "Min:\t" + Double.toString(this.minimumValue); out.println(str1); str1 = "Max:\t" + Double.toString(this.maximumValue); out.println(str1); str1 = "North:\t" + Double.toString(this.north); out.println(str1); str1 = "South:\t" + Double.toString(this.south); out.println(str1); str1 = "East:\t" + Double.toString(this.east); out.println(str1); str1 = "West:\t" + Double.toString(this.west); out.println(str1); str1 = "Cols:\t" + Integer.toString(this.numberColumns); out.println(str1); str1 = "Rows:\t" + Integer.toString(this.numberRows); out.println(str1); str1 = "Data Type:\t" + this.dataType; out.println(str1); str1 = "Z Units:\t" + this.zUnits; out.println(str1); str1 = "XY Units:\t" + this.xyUnits; out.println(str1); str1 = "Projection:\t" + this.projection; out.println(str1); if (this.dataScale == DATA_SCALE_CONTINUOUS) { str1 = "Data Scale:\tcontinuous"; } else if (this.dataScale == DATA_SCALE_CATEGORICAL) { str1 = "Data Scale:\tcategorical"; } else if (this.dataScale == DATA_SCALE_BOOLEAN) { str1 = "Data Scale:\tboolean"; } else if (this.dataScale == DATA_SCALE_RGB) { str1 = "Data Scale:\trgb"; } out.println(str1); str1 = "Display Min:\t" + Double.toString(this.displayMinimum); out.println(str1); str1 = "Display Max:\t" + Double.toString(this.displayMaximum); out.println(str1); str1 = "Preferred Palette:\t" + this.preferredPalette.replace(".plt", ".pal"); out.println(str1); str1 = "NoData:\t" + Double.toString(this.noDataValue); out.println(str1); str1 = "Byte Order:\t" + this.byteOrder; out.println(str1); // Write the metadata entries to the file if (metadata.size() > 0) { for (int i = 0; i < metadata.size(); i++) { str1 = "Metadata Entry:\t" + metadata.get(i).replaceAll(":", ";"); out.println(str1); } } } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { if (out != null || bw != null) { out.flush(); out.close(); } } } private void setBlockData() { try { blockSize = (int) (Math.round(Math.floor(bufferSize / 8))) / 3; if (blockSize > (numberRows * numberColumns)) { blockSize = numberRows * numberColumns; bufferSize = blockSize * 8; } blockSize = (int) blockSize / numberColumns; grid = new double[numberRows][]; lastUsed = new Date[numberRows]; Arrays.fill(lastUsed, new Date()); rowIsDirty = new boolean[numberRows]; } catch (Exception e) { System.out.println("Error: " + e.getMessage()); } } private void createNewDataFile() { RandomAccessFile rOut = null; ByteBuffer buf = null; try { long numberCells = numberRows * numberColumns; int writeLength = 2000000; long numCellsWritten = 0; rOut = new RandomAccessFile(dataFile, "rw"); FileChannel outChannel = rOut.getChannel(); outChannel.position(0); if (dataType.equals("double")) { do { if ((numCellsWritten + writeLength) > numberCells) { writeLength = (int)(numberCells - numCellsWritten); } double[] da = new double[writeLength]; Arrays.fill(da, initialValue); buf = ByteBuffer.allocate(cellSizeInBytes * writeLength); buf.order(byteOrder); DoubleBuffer db = buf.asDoubleBuffer(); db.put(da); outChannel.write(buf); db = null; da = null; numCellsWritten += writeLength; } while (numCellsWritten < numberCells); } else if (dataType.equals("float")) { do { if ((numCellsWritten + writeLength) > numberCells) { writeLength = (int)(numberCells - numCellsWritten); } float[] fa = new float[writeLength]; Arrays.fill(fa, (float)initialValue); buf = ByteBuffer.allocate(cellSizeInBytes * writeLength); buf.order(byteOrder); FloatBuffer fb = buf.asFloatBuffer(); fb.put(fa); outChannel.write(buf); fb = null; fa = null; numCellsWritten += writeLength; } while (numCellsWritten < numberCells); } else if (dataType.equals("integer")) { do { if ((numCellsWritten + writeLength) > numberCells) { writeLength = (int)(numberCells - numCellsWritten); } short[] ia = new short[(int)writeLength]; Arrays.fill(ia, (short)initialValue); buf = ByteBuffer.allocate(cellSizeInBytes * writeLength); buf.order(byteOrder); ShortBuffer ib = buf.asShortBuffer(); ib.put(ia); outChannel.write(buf); ib = null; ia = null; numCellsWritten += writeLength; } while (numCellsWritten < numberCells); } else if (dataType.equals("byte")) { do { if ((numCellsWritten + writeLength) > numberCells) { writeLength = (int)(numberCells - numCellsWritten); } byte[] ba = new byte[writeLength]; Arrays.fill(ba, (byte)initialValue); buf = ByteBuffer.wrap(ba); outChannel.write(buf); ba = null; numCellsWritten += writeLength; } while (numCellsWritten < numberCells); } outChannel.close(); } catch (Exception e) { System.out.println(e.getMessage()); } finally { buf = null; if (rOut != null) { try{ rOut.close(); } catch (Exception e){} } } } /* private void readDataBlock() { RandomAccessFile rIn = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(dataFile); if (file.exists() == false) { createNewDataFile(); } // What is the ending cell? long endCell = blockStartingCell + blockSize; if (endCell > (numberRows * numberColumns - 1)) { endCell = numberRows * numberColumns - 1; } blockEndingCell = endCell; int writeLengthInCells = (int)(blockEndingCell - blockStartingCell + 1); buf = ByteBuffer.allocate((int) (writeLengthInCells * cellSizeInBytes)); rIn = new RandomAccessFile(dataFile, "r"); FileChannel inChannel = rIn.getChannel(); inChannel.position(blockStartingCell * cellSizeInBytes); inChannel.read(buf); // Check the byte order. buf.order(byteOrder); if (dataType.equals("double")) { buf.rewind(); DoubleBuffer db = buf.asDoubleBuffer(); grid = new double[writeLengthInCells]; db.get(grid); db = null; buf = null; } else if (dataType.equals("float")) { buf.rewind(); FloatBuffer fb = buf.asFloatBuffer(); float[] fa = new float[writeLengthInCells]; fb.get(fa); fb = null; buf = null; grid = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { grid[j] = fa[j]; } fa = null; } else if (dataType.equals("integer")) { buf.rewind(); ShortBuffer ib = buf.asShortBuffer(); short[] ia = new short[writeLengthInCells]; ib.get(ia); ib = null; buf = null; grid = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { grid[j] = ia[j]; } ia = null; } else if (dataType.equals("byte")) { buf.rewind(); byte[] ba = new byte[writeLengthInCells]; buf.get(ba); buf = null; grid = new double[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { grid[j] = ba[j]; } ba = null; } } catch (Exception e) { System.err.println("Caught exception: " + e.toString()); System.err.println(e.getStackTrace()); } finally { if (rIn != null) { try{ rIn.close(); } catch (Exception e){} } numberOfDataFileReads++; } } * */ /** * Dumps the data block currently in memory to the data file. */ /*private void writeDataBlock() { if (saveChanges == false) { return; } // update the minimum and maximum values double min = Double.MAX_VALUE; double max = Double.MIN_VALUE; for (int i = 0; i < grid.length; i++) { if (grid[i] < min && grid[i] != noDataValue) { min = grid[i]; } if (grid[i] > max && grid[i] != noDataValue) { max = grid[i]; } } if (max > maximumValue) { maximumValue = max; } if (min < minimumValue) { minimumValue = min; } RandomAccessFile rOut = null; ByteBuffer buf = null; try { // See if the data file exists. File file = new File(dataFile); if (!file.exists()) { createNewDataFile(); } rOut = new RandomAccessFile(dataFile, "rw"); FileChannel outChannel = rOut.getChannel(); outChannel.position(blockStartingCell * cellSizeInBytes); int writeLengthInCells = (int) (blockEndingCell - blockStartingCell + 1); if (dataType.equals("double")) { buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); DoubleBuffer db = buf.asDoubleBuffer(); db.put(grid); db = null; outChannel.write(buf); } else if (dataType.equals("float")) { float[] fa = new float[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { fa[j] = (float)grid[j]; } buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); FloatBuffer fb = buf.asFloatBuffer(); fb.put(fa); fb = null; fa = null; outChannel.write(buf); } else if (dataType.equals("integer")) { short[] ia = new short[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { ia[j] = (short)grid[j]; } buf = ByteBuffer.allocate(cellSizeInBytes * writeLengthInCells); buf.order(byteOrder); ShortBuffer ib = buf.asShortBuffer(); ib.put(ia); ib = null; ia = null; outChannel.write(buf); } else if (dataType.equals("byte")) { byte[] ba = new byte[writeLengthInCells]; for (int j = 0; j < writeLengthInCells; j++) { ba[j] = (byte)grid[j]; } buf = ByteBuffer.wrap(ba); ba = null; outChannel.write(buf); } outChannel.close(); } catch (Exception e) { System.err.println("Caught exception: " + e.toString()); System.err.println(e.getStackTrace()); } finally { buf = null; if (rOut != null) { try{ rOut.close(); } catch (Exception e){} } isDirty = false; numberOfDataFileWrites++; } }*/ private void setPropertiesUsingAnotherRaster(String BaseRasterHeader, String DataType) { // Set the data type. if (DataType.toLowerCase().equals("float")) { dataType = "float"; cellSizeInBytes = 4; } else if (DataType.toLowerCase().equals("integer")) { dataType = "integer"; cellSizeInBytes = 2; } else if (DataType.toLowerCase().equals("byte")) { dataType = "byte"; cellSizeInBytes = 1; } else if (DataType.toLowerCase().equals("double")) { dataType = "double"; cellSizeInBytes = 8; } else { dataType = "float"; cellSizeInBytes = 4; } // Set the properties of this WhiteboxRaster to those of the base raster. DataInputStream in = null; BufferedReader br = null; try { // Open the file that is the first command line parameter FileInputStream fstream = new FileInputStream(BaseRasterHeader); // Get the object of DataInputStream in = new DataInputStream(fstream); br = new BufferedReader(new InputStreamReader(in)); if (BaseRasterHeader != null) { String line; String[] str; //Read File Line By Line while ((line = br.readLine()) != null) { str = line.split("\t"); if (str[0].toLowerCase().contains("north")) { this.north = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("south")) { this.south = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("west")) { this.west = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("east")) { this.east = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("cols")) { this.numberColumns = Integer.parseInt(str[1]); } else if (str[0].toLowerCase().contains("rows")) { this.numberRows = Integer.parseInt(str[1]); } else if (str[0].toLowerCase().contains("data scale")) { if (str[1].toLowerCase().contains("continuous")) { this.setDataScale(DATA_SCALE_CONTINUOUS); } else if (str[1].toLowerCase().contains("categorical")) { this.setDataScale(DATA_SCALE_CATEGORICAL); } else if (str[1].toLowerCase().contains("bool")) { this.setDataScale(DATA_SCALE_BOOLEAN); } else if (str[1].toLowerCase().contains("rgb")) { this.setDataScale(DATA_SCALE_RGB); } } else if (str[0].toLowerCase().contains("xy units")) { this.xyUnits = str[1]; } else if (str[0].toLowerCase().contains("projection")) { this.projection = str[1]; } else if (str[0].toLowerCase().contains("nodata value")) { this.noDataValue = Float.parseFloat(str[1]); } } } } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { try { if (in != null || br!= null) { in.close(); br.close(); } } catch (java.io.IOException ex) { } } // Save the header file. this.writeHeaderFile(); } /** * Used to find the minimum and maximum values in the raster. NoDataValues are ignored. * Minimum and maximum values are stored in the minimumValue and maximumValue fields. */ public void findMinAndMaxVals() { double[] data; double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; double z; for (int row = 0; row < numberRows; row++) { data = getRowValues(row); for (int col = 0; col < numberColumns; col++) { z = data[col]; if (z != noDataValue) { if (z < min) { min = z; } if (z > max) { max = z; } } } } maximumValue = max; minimumValue = min; } private double[] cumulativeHisto = null; public double getPercentileValue(double percentile) { if (mean == noDataValue) { readStatsFile(); } percentile = percentile / 100; double retVal = 0; double x1, x2; double y1, y2; if (cumulativeHisto == null) { cumulativeHisto = new double[histo.length]; cumulativeHisto[0] = histo[0]; for (int i = 1; i < histo.length; i++) { cumulativeHisto[i] = histo[i] + cumulativeHisto[i - 1]; } for (int i = 0; i < histo.length; i++) { cumulativeHisto[i] = cumulativeHisto[i] / numValidCells; } } for (int i = 0; i < histo.length; i++) { if (cumulativeHisto[i] >= percentile) { // find the first bin with a value greater than percentile. if (i > 0) { x1 = minimumValue + (i - 1) * binWidth; x2 = minimumValue + i * binWidth; y1 = cumulativeHisto[i - 1]; y2 = cumulativeHisto[i]; } else { x1 = minimumValue + (i - 1) * binWidth; x2 = minimumValue + i * binWidth; y1 = 0; y2 = cumulativeHisto[i]; } retVal = x1 + (percentile - y1) / (y2 - y1) * binWidth; break; } } return retVal; } public void readStatsFile() { File file = new File(statsFile); if (!file.exists()) { createStatsFile(); return; } DataInputStream in = null; BufferedReader br = null; boolean statsFlag = false; boolean histoFlag = false; int i = 0; long histoVal = 0; try { // Open the file that is the first command line parameter FileInputStream fstream = new FileInputStream(statsFile); // Get the object of DataInputStream in = new DataInputStream(fstream); br = new BufferedReader(new InputStreamReader(in)); if (statsFile != null) { String line; String[] str; //Read File Line By Line while ((line = br.readLine()) != null) { str = line.split("\t"); if (str[0].toLowerCase().contains("start_stats")) { statsFlag = true; } if (str[0].toLowerCase().contains("end_stats")) { statsFlag = false; } if (str[0].toLowerCase().contains("start_histo")) { histoFlag = true; } if (str[0].toLowerCase().contains("end_histo")) { histoFlag = false; } if (statsFlag) { if (str[0].toLowerCase().contains("mean")) { this.mean = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("median")) { this.median = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("mode")) { this.mode = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("std_dev")) { this.stdDeviation = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("num_valid_cells")) { this.numValidCells = Long.parseLong(str[1]); } } else if (histoFlag) { if (str[0].toLowerCase().contains("bin_width")) { this.binWidth = Double.parseDouble(str[1]); } else if (str[0].toLowerCase().contains("num_bins")) { histo = new long[Integer.parseInt(str[1])]; i = 0; } else if (str[0].toLowerCase().contains("start_histo") == false) { histo[i] = Long.parseLong(str[0]); i++; } } } //Close the input stream in.close(); br.close(); } } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { try { if (in != null || br!= null) { in.close(); br.close(); } } catch (java.io.IOException ex) { } } } /** * Creates a .wst file to store information about the statistical distribution * of the raster, including the min, max, mean, mode, stdev, and the histogram. These * data are used for clipping the tails of the distribution for enhanced visualization. */ public void createStatsFile() { File file = new File(statsFile); if (file.exists()) { file.delete(); } mean = 0; mode = 0; long n = 0; double[] data; double imageTotalDeviation = 0; double min = Double.MAX_VALUE; double max = -Double.MAX_VALUE; double z; double[] rowMedians = new double[numberRows]; binWidth = 0; int binNum = 0; int numberOfBins = 0; if (dataScale != DATA_SCALE_RGB) { // calculate the mean, min and max. for (int row = 0; row < numberRows; row++) { data = getRowValues(row); for (int col = 0; col < numberColumns; col++) { z = data[col]; if (z != noDataValue) { mean += z; n++; if (z < min) { min = z; } if (z > max) { max = z; } } } } maximumValue = max; minimumValue = min; mean = mean / n; numValidCells = n; if (dataType.equals("integer")) { numberOfBins = (int)(max - min + 1); binWidth = 1; } else if (dataType.equals("float") || dataType.equals("double")) { if ((max - min) < 1024) { numberOfBins = 1024; } else if ((max - min) < 2048) { numberOfBins = 2048; } else if ((max - min) < 4096) { numberOfBins = 4096; } else { numberOfBins = 8196; } binWidth = (max - min) / (numberOfBins - 1); } histo = new long[numberOfBins]; // figure out how many bins should be in the histogram for (int row = 0; row < numberRows; row++) { data = getRowValues(row); for (int col = 0; col < numberColumns; col++) { z = data[col]; if (z != noDataValue) { imageTotalDeviation += (z - mean) * (z - mean); binNum = (int)(Math.floor((z - min) / binWidth)); histo[binNum]++; } } } stdDeviation = Math.sqrt(imageTotalDeviation / (n - 1)); long highestVal = 0; int highestBin = 0; for (int i = 0; i < histo.length; i++) { if (histo[i] > highestVal) { highestVal = histo[i]; highestBin = i; } } mode = highestBin * binWidth; median = getPercentileValue(50.0d); String str = null; FileWriter fw = null; BufferedWriter bw = null; PrintWriter out = null; try { fw = new FileWriter(file, false); bw = new BufferedWriter(fw); out = new PrintWriter(bw, true); str = "START_STATS:"; out.println(str); str = "MIN: \t" + Double.toString(this.minimumValue); out.println(str); str = "MAX: \t" + Double.toString(this.maximumValue); out.println(str); str = "MEAN: \t" + Double.toString(mean); out.println(str); str = "MEDIAN: \t" + Double.toString(median); out.println(str); str = "MODE: \t" + Double.toString(mode); out.println(str); str = "STD_DEV: \t" + Double.toString(stdDeviation); out.println(str); str = "NUM_VALID_CELLS: \t" + Long.toString(n); out.println(str); str = "END_STATS"; out.println(str); str = "START_HISTO"; out.println(str); str = "BIN_WIDTH: \t" + binWidth; out.println(str); str = "NUM_BINS: \t" + numberOfBins; out.println(str); for (int i = 0; i < histo.length; i++) { str = String.valueOf(histo[i]); out.println(str); } str = "END_HISTO"; out.println(str); } catch (java.io.IOException e) { System.err.println("Error: " + e.getMessage()); } catch (Exception e) { //Catch exception if any System.err.println("Error: " + e.getMessage()); } finally { if (out != null || bw != null) { out.flush(); out.close(); } } } else { numberOfBins = 256; } } /** * Used to perform closing functionality when a whiteboxRaster is no longer needed. */ public void close() { if (this.isTemporaryFile) { File f1 = new File(this.headerFile); f1.delete(); f1 = new File(this.dataFile); f1.delete(); } else { if (saveChanges) { if (isDirty) { writeAllRows(); } findMinAndMaxVals(); writeHeaderFile(); } } grid = null; } }