/// <summary>
        /// Constructing an ObjectGrid this way assumes the values are not in ram and will
        /// simply buffer 3 rows.
        /// </summary>
        /// <param name="sourceRaster"></param>
        public DoubleValueGrid(DoubleRaster sourceRaster)
        {
            _sourceRaster = sourceRaster;

            if (sourceRaster.IsInRam == true)
            {
                // we will just be forwarding requests to the data array
            }
            else
            {
                _rowBuffer = new double[3][];
                _topRow = 0;
                for (int row = 0; row < 3; row++)
                {
                    _rowBuffer[row] = _sourceRaster.ReadRow(row);
                }
            }

        }
        // ----------------------------------- FROM AND TO IN RAM ONLY ---------------------------------
        /// <summary>
        /// This creates an IN MEMORY ONLY window from the in-memory window of this raster.  If, however, the requested range
        /// is outside of what is contained in the in-memory portions of this raster, an appropriate cast
        /// is required to ensure that you have the correct File handling, like a BinaryRaster etc.
        /// </summary>
        /// <param name="startRow">The 0 based integer index of the top row to get from this raster.  If this raster is itself a window, 0 represents the startRow from the file.</param>
        /// <param name="endRow">The integer index of the bottom row to get from this raster.  The largest allowed value is NumRows - 1.</param>
        /// <param name="startColumn">The 0 based integer index of the leftmost column to get from this raster.  If this raster is a window, 0 represents the startColumn from the file.</param>
        /// <param name="endColumn">The 0 based integer index of the rightmost column to get from this raster.  The largest allowed value is NumColumns - 1</param>
        /// <param name="inRam">Boolean.  If this is true and the window is small enough, a copy of the values will be loaded To memory.</param>
        /// <returns>An implementation of IRaster</returns>
        public IRaster GetWindow(int startRow, int endRow, int startColumn, int endColumn, bool inRam)
        {
            if (IsInRam == false)
            {
                throw new ArgumentException(MessageStrings.RasterRequiresCast);
            }
            if (startRow < StartRow || endRow > EndRow || StartColumn < startColumn || EndColumn > endColumn)
            {
                // the requested extents are outside of the extents that have been windowed into ram.  File Handling is required.
                throw new ArgumentException(MessageStrings.RasterRequiresCast);
            }

            int numCols = endColumn - startColumn + 1;
            int numRows = endRow - startRow + 1;
            DoubleRaster result = new DoubleRaster();
            result.Filename = Filename;
            result.Projection = Projection;
            result.DataType = typeof (double);
            result.NumRows = numRows;
            result.NumColumns = numCols;
            result.NumRowsInFile = NumRowsInFile;
            result.NumColumnsInFile = NumColumnsInFile;
            result.NoDataValue = NoDataValue;
            result.StartColumn = startColumn;
            result.StartRow = startRow;
            result.EndColumn = endColumn;
            result.EndRow = EndRow;
            result.FileType = FileType;

            // Reposition the new "raster" so that it matches the specified window, not the whole raster
            // X = [0] + [1] * column + [2] * row;
            // Y = [3] + [4] * column + [5] * row;
            result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]);
            result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1] * startColumn + Bounds.AffineCoefficients[2] * startRow;
            result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1];
            result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2];
            result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4] * startColumn + Bounds.AffineCoefficients[5] * startRow;
            result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4];
            result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5];



            // Now we can copy any values currently in memory.


            ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, endRow);
            pm.StartValue = startRow;
            // copy values directly using both data structures
            for (int row = 0; row < numRows; row++)
            {
                for (int col = 0; col < numCols; col++)
                {
                    result.Data[row][col] = Data[startRow + row][startColumn + col];
                }
                pm.CurrentValue = row;
            }
            pm.Reset();

            result.Value = new DoubleValueGrid(result);
            return result;
        }
        // ------------------------------------------FROM AND TO IN RAM ONLY -----------------
        /// <summary>
        /// This creates a completely new raster from the windowed domain on the original raster.  This new raster
        /// will not have a source file, and values like NumRowsInFile will correspond to the in memory version.
        /// All the values will be copied to the new source file.  InRam must be true at this level.
        /// </summary>
        /// <param name="filename"></param>
        /// <param name="startRow">The 0 based integer index of the top row to copy from this raster.  If this raster is itself a window, 0 represents the startRow from the file.</param>
        /// <param name="endRow">The integer index of the bottom row to copy from this raster.  The largest allowed value is NumRows - 1.</param>
        /// <param name="startColumn">The 0 based integer index of the leftmost column to copy from this raster.  If this raster is a window, 0 represents the startColumn from the file.</param>
        /// <param name="endColumn">The 0 based integer index of the rightmost column to copy from this raster.  The largest allowed value is NumColumns - 1</param>
        /// <param name="copyValues">If this is true, the valeus are saved to the file.  If this is false and the data can be loaded into Ram, no file handling is done.  Otherwise, a file of NoData values is created.</param>
        /// <param name="inRam">Boolean.  If this is true and the window is small enough, a copy of the values will be loaded into memory.</param>
        /// <returns>An implementation of IRaster</returns>
        public IRaster CopyWindow(string filename, int startRow, int endRow, int startColumn, int endColumn, bool copyValues, bool inRam)
        {
            if (inRam == false || (endColumn - startColumn + 1) * (endRow - startRow + 1) > 64000000)
            {
                throw new ArgumentException(MessageStrings.RasterRequiresCast);
            }
            if (IsInRam == false)
            {
                throw new ArgumentException(MessageStrings.RasterRequiresCast);
            }
            int numCols = endColumn - startColumn + 1;
            int numRows = endRow - startRow + 1;

            DoubleRaster result = new DoubleRaster(numRows, numCols);

            result.Projection = Projection;

            // The affine coefficients defining the world file are the same except that they are translated over.  Only the position of the
            // upper left corner changes.  Everything else is the same as the previous raster.

            // X = [0] + [1] * column + [2] * row;
            // Y = [3] + [4] * column + [5] * row;
            result.Bounds = new RasterBounds(result.NumRows, result.NumColumns, new double[6]);
            result.Bounds.AffineCoefficients[0] = Bounds.AffineCoefficients[0] + Bounds.AffineCoefficients[1] * startColumn + Bounds.AffineCoefficients[2] * startRow;
            result.Bounds.AffineCoefficients[1] = Bounds.AffineCoefficients[1];
            result.Bounds.AffineCoefficients[2] = Bounds.AffineCoefficients[2];
            result.Bounds.AffineCoefficients[3] = Bounds.AffineCoefficients[3] + Bounds.AffineCoefficients[4] * startColumn + Bounds.AffineCoefficients[5] * startRow;
            result.Bounds.AffineCoefficients[4] = Bounds.AffineCoefficients[4];
            result.Bounds.AffineCoefficients[5] = Bounds.AffineCoefficients[5];


            ProgressMeter pm = new ProgressMeter(ProgressHandler, MessageStrings.CopyingValues, numRows);
            // copy values directly using both data structures
            for (int row = 0; row < numRows; row++)
            {
                for (int col = 0; col < numCols; col++)
                {
                    result.Data[row][col] = Data[startRow + row][startColumn + col];
                }
                pm.CurrentValue = row;
            }
            pm.Reset();


            result.Value = new DoubleValueGrid(result);
            return result;

        }