001/*
002 * Copyright (c) 2003-2010 The Regents of the University of California.
003 * All rights reserved.
004 *
005 * '$Author: welker $'
006 * '$Date: 2010-05-06 05:21:26 +0000 (Thu, 06 May 2010) $' 
007 * '$Revision: 24234 $'
008 * 
009 * Permission is hereby granted, without written agreement and without
010 * license or royalty fees, to use, copy, modify, and distribute this
011 * software and its documentation for any purpose, provided that the above
012 * copyright notice and the following two paragraphs appear in all copies
013 * of this software.
014 *
015 * IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
016 * FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
017 * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
018 * THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
019 * SUCH DAMAGE.
020 *
021 * THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
022 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
023 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
024 * PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
025 * CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
026 * ENHANCEMENTS, OR MODIFICATIONS.
027 *
028 */
029
030/**
031 *         Name: Grid.java
032 *      Purpose: Used to represent georeferenced grids of values; includes
033 *               methods for manipulating those grids. especially regridding.
034 *               The emphasis is on equally spaced grids (like those described in
035 *               *.ASC files).
036 *
037 *      Author : Dan Higgins
038 *
039 */
040
041package org.ecoinformatics.seek.gis.java_gis;
042
043import java.awt.Shape;
044import java.io.BufferedReader;
045import java.io.File;
046import java.io.FileNotFoundException;
047import java.io.FileOutputStream;
048import java.io.FileReader;
049import java.io.PrintWriter;
050import java.util.Hashtable;
051import java.util.StringTokenizer;
052
053import util.PersistentVector;
054
055public class Grid {
056
057        public int nrows;
058        public int ncols;
059
060        public double xllcorner;
061        public double yllcorner;
062        public double delx;
063        public double dely;
064        // ASC files have square cells; i.e. a cellsize = delx = dely
065        // we make it slightly more general here
066        public static String NODATA_value_String = "-9999";
067
068        public boolean inMemFlag = false;
069
070        // assume a cell is defined by row and column index of upper left corner
071        // and there is a numeric value associated with each cell
072
073        public double[][] dataArray = null;
074        public PersistentVector pv = null;
075
076        // last row string array;used to speed up access when PersistenVector is
077        // used
078        private String[] rowSA = null;
079        // last row index
080        private int last_y = -1;
081        // next to last row string array;used to speed up access when
082        // PersistenVector is used
083        private String[] next2lastrowSA = null;
084        // next to last row index
085        private int next2last_y = -1;
086
087        private String cachedLine = "";
088        private Hashtable header = null;
089
090        private double no_val_threshold = 1.0E100;
091
092        static final int NEAREST_NEIGHBOR = 0;
093        static final int INVERSE_DISTANCE = 1;
094
095        public Grid() {
096                // just generate a simple grid
097                nrows = 10;
098                ncols = 10;
099                delx = 1.0;
100                dely = 1.0;
101                xllcorner = 0.0;
102                yllcorner = 0.0;
103                // note that no data storage for grid values has been created
104        }
105
106        public Grid(int nx, int ny, double dx, double dy, double xmin, double ymin) {
107                this.ncols = nx;
108                this.nrows = ny;
109                this.delx = dx;
110                this.dely = dy;
111                this.xllcorner = xmin;
112                this.yllcorner = ymin;
113                // note that no data storage for grid values has been created
114        }
115
116        // create a Grid from an .ASC file
117        public Grid(File ascfile) {
118                FileReader inReader = null;
119                BufferedReader bufReader = null;
120                try {
121                        inReader = new FileReader(ascfile);
122                        bufReader = new BufferedReader(inReader);
123                        header = getHeaderInformation(bufReader);
124                } catch (Exception ee) {
125                        System.out.println("Exception at main!");
126                }
127                // first non-header line should be in cachedLine string
128                // and header values should be in header hash
129                // test
130                // System.out.println("header hash: "+header);
131                if (header.containsKey("NODATA_value")) {
132                        NODATA_value_String = (String) header.get("NODATA_value");
133                }
134                nrows = (new Integer((String) header.get("nrows"))).intValue();
135                ncols = (new Integer((String) header.get("ncols"))).intValue();
136                delx = (new Double((String) header.get("cellsize"))).doubleValue();
137                dely = (new Double((String) header.get("cellsize"))).doubleValue();
138                xllcorner = (new Double((String) header.get("xllcorner")))
139                                .doubleValue();
140                yllcorner = (new Double((String) header.get("yllcorner")))
141                                .doubleValue();
142
143                if (inMemFlag) {
144                        // now create the actual data array
145                        dataArray = new double[ncols][nrows];
146                        int i = 0;
147                        int j = 0;
148                        while (cachedLine != null) {
149                                StringTokenizer st = new StringTokenizer(cachedLine);
150                                i = 0;
151                                while (st.hasMoreTokens()) {
152                                        String nextToken = st.nextToken().trim();
153                                        if (!nextToken.equals(NODATA_value_String)) {
154                                                double val = Double.parseDouble(nextToken);
155                                                dataArray[i][j] = val;
156                                        } else {
157                                                // missing value
158                                                dataArray[i][j] = 1.0E101;
159                                        }
160                                        i++;
161                                }
162                                try {
163                                        cachedLine = bufReader.readLine();
164                                        j++;
165                                } catch (Exception eee) {
166                                        cachedLine = null;
167                                }
168                        }
169                } else {
170
171                        // an ObjectFile version
172
173                        pv = new PersistentVector();
174                        pv.setFirstRow(6);
175                        pv.setFieldDelimiter("#x20");
176                        System.out.println("filename: " + ascfile.getPath());
177                        pv.init(ascfile.getPath());
178                }
179                try {
180                        bufReader.close();
181                } catch (Exception w) {
182                        System.out.println("Error in creating grid from asc file!");
183                }
184
185        }
186
187        // used to create a Grid from ASC file and determine whether to save it in
188        // memory (or use disk)
189        public Grid(File ascfile, boolean inMemory) {
190                inMemFlag = inMemory;
191                FileReader inReader = null;
192                BufferedReader bufReader = null;
193                try {
194                        inReader = new FileReader(ascfile);
195                        bufReader = new BufferedReader(inReader);
196                        header = getHeaderInformation(bufReader);
197                } catch (Exception ee) {
198                        System.out.println("Exception at main!");
199                }
200                // first non-header line should be in cachedLine string
201                // and header values should be in header hash
202                // test
203                // System.out.println("header hash: "+header);
204                if (header.containsKey("NODATA_value")) {
205                        NODATA_value_String = (String) header.get("NODATA_value");
206                }
207                nrows = (new Integer((String) header.get("nrows"))).intValue();
208                ncols = (new Integer((String) header.get("ncols"))).intValue();
209                delx = (new Double((String) header.get("cellsize"))).doubleValue();
210                dely = (new Double((String) header.get("cellsize"))).doubleValue();
211                xllcorner = (new Double((String) header.get("xllcorner")))
212                                .doubleValue();
213                yllcorner = (new Double((String) header.get("yllcorner")))
214                                .doubleValue();
215
216                if (inMemFlag) {
217                        // now create the actual data array
218                        dataArray = new double[ncols][nrows];
219                        int i = 0;
220                        int j = 0;
221                        while (cachedLine != null) {
222                                StringTokenizer st = new StringTokenizer(cachedLine);
223                                i = 0;
224                                while (st.hasMoreTokens()) {
225                                        String nextToken = st.nextToken().trim();
226                                        if (!nextToken.equals(NODATA_value_String)) {
227                                                double val = Double.parseDouble(nextToken);
228                                                dataArray[i][j] = val;
229                                        } else {
230                                                // missing value
231                                                dataArray[i][j] = 1.0E101;
232                                        }
233                                        i++;
234                                }
235                                try {
236                                        cachedLine = bufReader.readLine();
237                                        j++;
238                                } catch (Exception eee) {
239                                        cachedLine = null;
240                                }
241                        }
242                } else {
243
244                        // an ObjectFile version
245
246                        pv = new PersistentVector();
247                        pv.setFirstRow(6);
248                        pv.setFieldDelimiter("#x20");
249                        System.out.println("filename: " + ascfile.getPath());
250                        pv.init(ascfile.getPath());
251                }
252                try {
253                        bufReader.close();
254                } catch (Exception w) {
255                        System.out.println("Error in creating grid from asc file!");
256                }
257        }
258
259        // Note that the data is indexed from the top left, not the lower left
260        public double getValue(int x, int y) {
261                String val;
262                double ret = 1.0E101; // assume any number > than no_val_threshold is
263                                                                // missing data
264                if ((x < 0) || (x > ncols - 1))
265                        return ret; // outside grid
266                if ((y < 0) || (y > nrows - 1))
267                        return ret; // outside grid
268                // assume for now that the array is in memory
269                if (dataArray != null) {
270                        ret = dataArray[x][y];
271                }
272                if (pv != null) {
273                        if ((y != next2last_y) && (y != last_y)) {
274                                next2last_y = last_y;
275                                next2lastrowSA = rowSA;
276                                rowSA = (String[]) (pv.elementAt(y));
277                                last_y = y;
278                        }
279                        if (y == last_y) {
280                                val = rowSA[x];
281                        } else {
282                                val = next2lastrowSA[x];
283                        }
284                        if (val.equals(NODATA_value_String)) {
285                                ret = 1.0E101;
286                        } else {
287                                ret = new Double(val).doubleValue();
288                        }
289                }
290                return ret;
291        }
292
293        // Note that the data is indexed from the top left, not the lower left
294        // but the location is described from the lowerleft corner (as doubles)
295        public double interpValue(double x, double y, int scalingAlgorithm) {
296                x = x + .01 * delx; // slight shift to avoid round off problems - DFH
297                y = y - .01 * dely; // slight shift to avoid round off problems - DFH
298                if (scalingAlgorithm == INVERSE_DISTANCE) {
299                        return interpValue_IDW(x, y);
300                }
301                double ret = 1.0E101;
302                int xint = (int) ((x - xllcorner) / delx);
303                int yint = nrows - 1 - (int) ((y - yllcorner) / dely);
304                if (yint == -1)
305                        yint = 0;
306                ret = getValue(xint, yint);
307                return ret;
308        }
309
310        public double interpValue_IDW(double x, double y) {
311                int delij = 1;
312                int deliij = 1;
313                int delijj = 1;
314                int deliijj = 1;
315                double ret = 1.0E101;
316                int xint = (int) ((x - xllcorner) / delx);
317                int yint = nrows - 1 - (int) ((y - yllcorner) / dely);
318                if (yint == -1)
319                        yint = 0;
320                if (xint >= ncols - 1)
321                        xint = ncols - 2;
322                if (yint >= nrows - 1)
323                        yint = nrows - 2;
324                double valij = getValue(xint, yint);
325                double valiij = getValue(xint + 1, yint);
326                double valijj = getValue(xint, yint + 1);
327                double valiijj = getValue(xint + 1, yint + 1);
328                if ((valij >= no_val_threshold) && (valiij >= no_val_threshold)
329                                && (valijj >= no_val_threshold)
330                                && (valiijj >= no_val_threshold)) {
331                        return ret;
332                }
333                // no_values are often set at boundaries; i.e. oceans
334                // in order to interpolate near these boundaries, the values
335                // of cells with no data must be ignored. The checks below implement
336                // this.
337                if (valij >= no_val_threshold)
338                        delij = 0;
339                if (valiij >= no_val_threshold)
340                        deliij = 0;
341                if (valijj >= no_val_threshold)
342                        delijj = 0;
343                if (valiijj >= no_val_threshold)
344                        deliijj = 0;
345
346                // calculate distances to enclosing grid points.
347                // if the distance is very small, just return the value at the corner
348                // since
349                // it will dominate anyway
350                double dist2center = (delx * delx + dely * dely) / 4.0;
351                double distij2 = ((x - xllcorner) % delx) * ((x - xllcorner) % delx)
352                                + ((dely - (y - yllcorner) % dely))
353                                * ((dely - (y - yllcorner) % dely));
354                if (distij2 < 1E-99)
355                        return valij;
356                if ((distij2 < dist2center) && (delij == 0))
357                        return valij;
358                double distiij2 = ((delx - (x - xllcorner) % delx))
359                                * ((delx - (x - xllcorner) % delx))
360                                + ((dely - (y - yllcorner) % dely))
361                                * ((dely - (y - yllcorner) % dely));
362                if (distiij2 < 1E-99)
363                        return valiij;
364                if ((distiij2 < dist2center) && (deliij == 0))
365                        return valiij;
366                double distijj2 = ((x - xllcorner) % delx) * ((x - xllcorner) % delx)
367                                + ((y - yllcorner) % dely) * ((y - yllcorner) % dely);
368                if (distijj2 < 1E-99)
369                        return valijj;
370                if ((distijj2 < dist2center) && (delijj == 0))
371                        return valijj;
372                double distiijj2 = ((delx - (x - xllcorner) % delx))
373                                * ((delx - (x - xllcorner) % delx)) + ((y - yllcorner) % dely)
374                                * ((y - yllcorner) % dely);
375                if (distiijj2 < 1E-99)
376                        return valiijj;
377                if ((distiijj2 < dist2center) && (deliijj == 0))
378                        return valiijj;
379
380                double weightij = delij / distij2;
381                double weightiij = deliij / distiij2;
382                double weightijj = delijj / distijj2;
383                double weightiijj = deliijj / distiijj2;
384                double sumw = weightij + weightiij + weightijj + weightiijj;
385
386                ret = (valij * weightij + valiij * weightiij + valijj * weightijj + valiijj
387                                * weightiijj)
388                                / sumw;
389
390                return ret;
391        }
392
393        public void createAsc(String filename) {
394                PrintWriter out = null;
395                try {
396                        out = new PrintWriter(new FileOutputStream(filename));
397                        out.print("nrows  " + nrows);
398                        out.println();
399                        out.print("ncols  " + ncols);
400                        out.println();
401                        out.print("xllcorner  " + xllcorner);
402                        out.println();
403                        out.print("yllcorner  " + yllcorner);
404                        out.println();
405                        out.print("cellsize  " + delx);
406                        out.println();
407                        out.print("NODATA_value  " + NODATA_value_String);
408                        out.println();
409                        if (dataArray != null) {
410                                for (int r = 0; r < nrows; r++) {
411                                        for (int c = 0; c < ncols; c++) {
412                                                double val = dataArray[c][r];
413                                                if (val > no_val_threshold) {
414                                                        out.print(NODATA_value_String + " ");
415                                                } else {
416                                                        out.print(val + " ");
417                                                }
418                                        }
419                                        out.println();
420                                }
421                        }
422                        if (pv != null) {
423                                for (int r = 0; r < nrows; r++) {
424                                        String[] rs = (String[]) pv.elementAt(r);
425                                        String temp = "";
426                                        for (int c = 0; c < ncols; c++) {
427                                                temp = temp + rs[c] + " ";
428                                        }
429                                        out.println(temp);
430                                }
431                        }
432                        out.close();
433                } catch (FileNotFoundException e) {
434                        System.out.println("Problem creating Asc File!");
435                }
436        }
437
438        // rescale this grid as indicated using nearest neighbor
439        public Grid rescale(int nr, int nc, double dx, double dy, double xmin,
440                        double ymin, int scalingAlgorithm) {
441                Grid newGrid = new Grid(nc, nr, dx, dy, xmin, ymin);
442                if (inMemFlag && (dataArray != null)) {
443                        double[][] newDataArray = new double[nc][nr];
444                        newGrid.dataArray = newDataArray;
445                        for (int j = 0; j < nr; j++) {
446                                // System.out.println("Working on row # "+j);
447                                double yloc = ymin + nr * dy - j * dy;
448                                for (int i = 0; i < nc; i++) {
449                                        double xloc = xmin + i * dx;
450                                        double val = this.interpValue(xloc, yloc, scalingAlgorithm);
451                                        newDataArray[i][j] = val;
452                                }
453                        }
454                } else { // using PersistentVector for data storage
455                        newGrid.pv = new PersistentVector();
456                        newGrid.pv.setFirstRow(6);
457                        newGrid.pv.setFieldDelimiter("#x20");
458                        String[] rowvals = new String[nc];
459                        for (int j = 0; j < nr; j++) {
460                                // System.out.println("Working on row # "+j);
461                                double yloc = ymin + nr * dy - j * dy;
462                                for (int i = 0; i < nc; i++) {
463                                        double xloc = xmin + i * dx;
464                                        double val = this.interpValue(xloc, yloc, scalingAlgorithm);
465                                        String valStr;
466                                        if (val > no_val_threshold) {
467                                                valStr = NODATA_value_String;
468                                        } else {
469                                                valStr = (new Double(val)).toString();
470                                        }
471                                        rowvals[i] = valStr;
472                                }
473                                newGrid.pv.addElement(rowvals);
474                                rowvals = new String[nc]; // needed to make sure new object
475                                                                                        // added to pv
476                        }
477                }
478                return newGrid;
479        }
480
481        // reset values in range (minval,maxval) to newvalue
482        public Grid reset(double minval, double maxval, double newvalue) {
483                // create a new Grid with same parameters as this one
484                Grid newGrid = new Grid(ncols, nrows, delx, dely, xllcorner, yllcorner);
485                if (inMemFlag && (dataArray != null)) {
486                        double[][] newDataArray = new double[ncols][nrows];
487                        newGrid.dataArray = newDataArray;
488                        for (int j = 0; j < nrows; j++) {
489                                for (int i = 0; i < ncols; i++) {
490                                        double val = this.getValue(i, j);
491                                        if ((val > minval) && (val < maxval))
492                                                val = newvalue;
493                                        newDataArray[i][j] = val;
494                                }
495                        }
496                } else { // using PersistentVector for data storage
497                        newGrid.pv = new PersistentVector();
498                        newGrid.pv.setFirstRow(6);
499                        newGrid.pv.setFieldDelimiter("#x20");
500                        String[] rowvals = new String[ncols];
501                        for (int j = 0; j < nrows; j++) {
502                                for (int i = 0; i < ncols; i++) {
503                                        double val = this.getValue(i, j);
504                                        if ((val > minval) && (val < maxval))
505                                                val = newvalue;
506                                        String valStr;
507                                        if (val > no_val_threshold) {
508                                                valStr = NODATA_value_String;
509                                        } else {
510                                                valStr = (new Double(val)).toString();
511                                        }
512                                        rowvals[i] = valStr;
513                                }
514                                newGrid.pv.addElement(rowvals);
515                                rowvals = new String[ncols]; // needed to make sure new object
516                                                                                                // added to pv
517                        }
518                }
519                return newGrid;
520        }
521
522        // transform values in range (minval,maxval) to by a multiplication and/or
523        // addition
524        public Grid transform(double minval, double maxval, double multFactor,
525                        double addFactor) {
526                // create a new Grid with same parameters as this one
527                Grid newGrid = new Grid(ncols, nrows, delx, dely, xllcorner, yllcorner);
528                if (inMemFlag && (dataArray != null)) {
529                        double[][] newDataArray = new double[ncols][nrows];
530                        newGrid.dataArray = newDataArray;
531                        for (int j = 0; j < nrows; j++) {
532                                for (int i = 0; i < ncols; i++) {
533                                        double val = this.getValue(i, j);
534                                        if ((val > minval) && (val < maxval)) {
535                                                val = multFactor * val + addFactor;
536                                        }
537                                        newDataArray[i][j] = val;
538                                }
539                        }
540                } else { // using PersistentVector for data storage
541                        newGrid.pv = new PersistentVector();
542                        newGrid.pv.setFirstRow(6);
543                        newGrid.pv.setFieldDelimiter("#x20");
544                        String[] rowvals = new String[ncols];
545                        for (int j = 0; j < nrows; j++) {
546                                for (int i = 0; i < ncols; i++) {
547                                        double val = this.getValue(i, j);
548                                        if ((val > minval) && (val < maxval)) {
549                                                val = multFactor * val + addFactor;
550                                        }
551                                        String valStr;
552                                        if (val > no_val_threshold) {
553                                                valStr = NODATA_value_String;
554                                        } else {
555                                                valStr = (new Double(val)).toString();
556                                        }
557                                        rowvals[i] = valStr;
558                                }
559                                newGrid.pv.addElement(rowvals);
560                                rowvals = new String[ncols]; // needed to make sure new object
561                                                                                                // added to pv
562                        }
563                }
564                return newGrid;
565        }
566
567        public int getNumberMissingDataPixels() {
568                int cnt = 0;
569                if (dataArray != null) { // in memory
570                        for (int i = 0; i < ncols; i++) {
571                                for (int j = 0; j < nrows; j++) {
572                                        double val = getValue(i, j);
573                                        if (val > no_val_threshold)
574                                                cnt++;
575                                }
576                        }
577                        return cnt;
578                }
579                if (pv != null) {
580                        for (int j = 0; j < nrows; j++) {
581                                String[] rowSA = (String[]) (pv.elementAt(j));
582                                for (int i = 0; i < ncols; i++) {
583                                        String val = rowSA[i];
584                                        if (val.equals(NODATA_value_String)) {
585                                                cnt++;
586                                        }
587                                }
588                        }
589                }
590                return cnt;
591        }
592
593        // remove this Grid object
594        // in particular, delete the potentially large Object file associated with
595        // the PersistentVector
596        public void delete() {
597                if (pv != null) {
598                        pv.delete();
599                        pv = null;
600                }
601                if (dataArray != null) {
602                        dataArray = null;
603                }
604        }
605
606        public double getFractionMissingDataPixels() {
607                double frac = ((double) getNumberMissingDataPixels()) / (ncols * nrows);
608                return frac;
609        }
610
611        // count the pixels with value 'val' within the distance 'thresh'
612        public int getNumberPixelsWithValue(double val, double thresh) {
613                double tval;
614                int cnt = 0;
615                if (dataArray != null) { // in memory
616                        for (int i = 0; i < ncols; i++) {
617                                for (int j = 0; j < nrows; j++) {
618                                        double temp = getValue(i, j);
619                                        if (Math.abs(temp - val) < thresh)
620                                                cnt++;
621                                }
622                        }
623                        return cnt;
624                }
625                if (pv != null) {
626                        for (int j = 0; j < nrows; j++) {
627                                String[] rowSA = (String[]) (pv.elementAt(j));
628                                for (int i = 0; i < ncols; i++) {
629                                        String ts = rowSA[i];
630                                        if (!(ts.equals(NODATA_value_String))) {
631                                                tval = new Double(ts).doubleValue();
632                                                if (Math.abs(tval - val) < thresh)
633                                                        cnt++;
634                                        }
635                                }
636                        }
637                }
638                return cnt;
639        }
640
641        // get fraction of nonMissing data pixels with value
642        public double getFractionPixelsWithValue(double val, double thresh) {
643                double frac = ((double) getNumberPixelsWithValue(val, thresh))
644                                / ((ncols * nrows) - getNumberMissingDataPixels());
645                return frac;
646        }
647
648        // createRectangularMask takes this grid and sets alls cells outside the
649        // specified rectangle to one value and all cells inside to another
650        public void createRectangularMask(double xmin, double ymin, double xmax,
651                        double ymax, double outvalue, double invalue) {
652                String invalueStr;
653                if (invalue > no_val_threshold) {
654                        invalueStr = NODATA_value_String;
655                } else {
656                        invalueStr = (new Double(invalue)).toString();
657                }
658                String outvalueStr;
659                if (outvalue > no_val_threshold) {
660                        outvalueStr = NODATA_value_String;
661                } else {
662                        outvalueStr = (new Double(outvalue)).toString();
663                }
664
665                if (inMemFlag && (dataArray != null)) {
666                        for (int j = 0; j < nrows; j++) {
667                                double yloc = yllcorner + nrows * dely - j * dely;
668                                for (int i = 0; i < ncols; i++) {
669                                        double xloc = xllcorner + i * delx;
670                                        if ((xloc > xmin) && (xloc < xmax)) {
671                                                if ((yloc > ymin) && (yloc < ymax)) {
672                                                        // inside the rectangle
673                                                        dataArray[i][j] = invalue;
674                                                }
675                                        } else {
676                                                dataArray[i][j] = outvalue;
677                                        }
678                                }
679                        }
680                } else { // using PersistentVector for data storage
681                        if (pv == null) {
682                                pv = new PersistentVector();
683                                pv.setFirstRow(6);
684                                pv.setFieldDelimiter("#x20");
685                        }
686                        String[] rowvals = new String[ncols];
687                        for (int j = 0; j < nrows; j++) {
688                                double yloc = yllcorner + nrows * dely - j * dely;
689                                for (int i = 0; i < ncols; i++) {
690                                        double xloc = xllcorner + i * delx;
691                                        if ((xloc > xmin) && (xloc < xmax)) {
692                                                if ((yloc > ymin) && (yloc < ymax)) {
693                                                        // inside the rectangle
694                                                        rowvals[i] = (new Double(invalue)).toString();
695                                                }
696                                        } else {
697                                                rowvals[i] = (new Double(outvalue)).toString();
698                                        }
699                                }
700                                pv.addElement(rowvals);
701                                rowvals = new String[ncols]; // needed to make sure new object
702                                                                                                // added to pv
703                        }
704
705                }
706        }
707
708        // createShapeMask takes this grid and sets alls cells outside the
709        // specified Shape to one value and all cells inside to another
710        public void createShapeMask(Shape shape, double outvalue, double invalue) {
711                String invalueStr;
712                if (invalue > no_val_threshold) {
713                        invalueStr = NODATA_value_String;
714                } else {
715                        invalueStr = (new Double(invalue)).toString();
716                }
717                String outvalueStr;
718                if (outvalue > no_val_threshold) {
719                        outvalueStr = NODATA_value_String;
720                } else {
721                        outvalueStr = (new Double(outvalue)).toString();
722                }
723
724                if (inMemFlag && (dataArray != null)) {
725                        for (int j = 0; j < nrows; j++) {
726                                double yloc = yllcorner + nrows * dely - j * dely;
727                                for (int i = 0; i < ncols; i++) {
728                                        double xloc = xllcorner + i * delx;
729                                        if (shape.contains(xloc, yloc)) {
730                                                // inside the rectangle
731                                                dataArray[i][j] = invalue;
732                                        } else {
733                                                dataArray[i][j] = outvalue;
734                                        }
735                                }
736                        }
737                } else { // using PersistentVector for data storage
738                        if (pv == null) {
739                                pv = new PersistentVector();
740                                pv.setFirstRow(6);
741                                pv.setFieldDelimiter("#x20");
742                        }
743                        String[] rowvals = new String[ncols];
744                        for (int j = 0; j < nrows; j++) {
745                                double yloc = yllcorner + nrows * dely - j * dely;
746                                for (int i = 0; i < ncols; i++) {
747                                        double xloc = xllcorner + i * delx;
748                                        if (shape.contains(xloc, yloc)) {
749                                                // inside the rectangle
750                                                rowvals[i] = invalueStr;
751                                        } else {
752                                                rowvals[i] = outvalueStr;
753                                        }
754                                }
755                                pv.addElement(rowvals);
756                                rowvals = new String[ncols]; // needed to make sure new object
757                                                                                                // added to pv
758                        }
759
760                }
761        }
762
763        public static void main(String[] args) {
764                File testFile = new File("./test.asc");
765                Grid grid = new Grid(testFile);
766                System.out.println("nrows: " + grid.nrows);
767                System.out.println("ncols: " + grid.ncols);
768                System.out.println("delx: " + grid.delx);
769                System.out.println("dely: " + grid.dely);
770
771                System.out.println("(0,0): " + grid.getValue(0, 0));
772                System.out.println("(1,1): " + grid.getValue(1, 1));
773                System.out.println("(2,2): " + grid.getValue(2, 2));
774                System.out.println("(2.5,2.5): "
775                                + grid.interpValue(2.5, 2.5, NEAREST_NEIGHBOR));
776                System.out.println("(0.0,0.0): "
777                                + grid.interpValue(0.0, 0.0, NEAREST_NEIGHBOR));
778
779                System.out
780                                .println("Starting to create an ASC file! ------------------");
781
782                grid.createAsc("outtest.asc");
783                System.out.println("Finished creating an ASC file! ------------------");
784
785                System.out.println("Starting to rescale! ------------------");
786                Grid newg = grid
787                                .rescale(grid.nrows / 2, grid.ncols / 2, grid.delx * 2,
788                                                grid.dely * 2, grid.xllcorner, grid.yllcorner,
789                                                NEAREST_NEIGHBOR);
790                System.out.println("Finished rescaling! ------------------");
791                // newg.createAsc("outtest2.asc");
792
793                // String[] arr = (String[])grid.pv.elementAt(5);
794
795                // System.out.println("Str: "+arr[0]);
796        }
797
798        private Hashtable getHeaderInformation(BufferedReader br) {
799                Hashtable headerVals = new Hashtable();
800                // unsure exactly how many header lines may occur
801                // but each line should have only two string tokens with the first being
802                // a name
803                // assume the 'name' is NOT a number
804                boolean eoh = false; // eoh -> end of header
805                while (!eoh) {
806                        try {
807                                cachedLine = br.readLine();
808                        } catch (Exception w) {
809                                System.out
810                                                .println("error reading next line in getHeaderInformation!");
811                                eoh = true;
812                        }
813                        StringTokenizer st = new StringTokenizer(cachedLine);
814                        int cnt = st.countTokens(); // should be only 2
815                        if (cnt != 2)
816                                eoh = true;
817                        String firstToken = st.nextToken().trim();
818                        String secondToken = st.nextToken().trim();
819                        eoh = true;
820                        try {
821                                Double.parseDouble(firstToken);
822                        } catch (Exception e) {
823                                eoh = false;
824                        }
825                        if (!eoh) {
826                                headerVals.put(firstToken, secondToken);
827                        }
828                        if (!headerVals.containsKey("NODATA_value")) {
829                                headerVals.put("NODATA_value", "-9999"); // set a default
830                        }
831                }
832                return headerVals;
833        }
834
835}