001/* 002 * Copyright (c) 2004-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 030package org.ecoinformatics.seek.gis.java_gis; 031 032import java.io.File; 033import java.util.Hashtable; 034 035import ptolemy.actor.lib.SequenceActor; 036import ptolemy.actor.lib.Transformer; 037import ptolemy.data.BooleanToken; 038import ptolemy.data.DoubleToken; 039import ptolemy.data.IntToken; 040import ptolemy.data.StringToken; 041import ptolemy.data.expr.FileParameter; 042import ptolemy.data.expr.Parameter; 043import ptolemy.data.expr.StringParameter; 044import ptolemy.data.type.BaseType; 045import ptolemy.kernel.CompositeEntity; 046import ptolemy.kernel.Port; 047import ptolemy.kernel.util.IllegalActionException; 048import ptolemy.kernel.util.InternalErrorException; 049import ptolemy.kernel.util.NameDuplicationException; 050 051/** 052 * <p> 053 * This actor converts an ascii raster grid file into another ascii grid file 054 * with different extent and cell spacing A ASC grid file is read as input. (The 055 * file name(s) are connected to the input port.)<br/> 056 * The xllcorner, yllcorner, cellsize, numrows and numcols of the desired grid 057 * are also input and a new ASC file is created. Algorithms are disk based 058 * meaning that very large rasters can be handled. 059 * </p> 060 * 061 * <p> 062 * The input is a multiport so multiple input file names can be attached to that 063 * port. Multiple tokens are output in a sequence if multiple input filenames 064 * are attached. Token consumption and production rates are automatically 065 * calculated 066 * </p> 067 * 068 * <p> 069 * A useExistingFile boolean parameter has been added. When true, the actor 070 * checks to see if the output file already exists. If it does, it is just sent 071 * to the output port without repeating the calculation. 072 * </p> 073 */ 074public class GridRescaler extends Transformer implements SequenceActor { 075 076 /** 077 * The x-value of the lower left corner of the output grid Usually this is a 078 * longitude. This is input as a string and converted to a double. 079 */ 080 public Parameter xllcorner; 081 082 /** 083 * The y-value of the lower left corner of the output grid Usually this is a 084 * latitude. This is input as a string and converted to a double. 085 */ 086 public Parameter yllcorner; 087 088 /** 089 * The cell size of the output grid. The grid is assumed square so that x 090 * and y grid sizes are equal and converted to a double.. 091 */ 092 public Parameter cellsize; 093 094 /** 095 * The number of rows (cells in the y-direction) in the output grid. This 096 * determines the extent of y-values in the grid when combined with the cell 097 * size This is input as a string and converted to a integer. 098 */ 099 public Parameter numrows; 100 101 /** 102 * The number of columns (cells in the x-direction) in the output grid. This 103 * determines the extent of x-values in the grid when combined with the cell 104 * size This is input as a string and converted to a integer. 105 */ 106 public Parameter numcols; 107 108 /** 109 * This is the algoritm to be used in calculating cell values in the output 110 * grid from the values in the input grid Currently there are two choices: 111 * 'Nearest Neighbor' or 'Inverse Distance Weighted' 112 */ 113 public StringParameter algorithm; 114 115 /** 116 * This is the name to be given to the output file. If left empty, the input 117 * file name plus a suffix (".out"+i) will be used for output file names 118 * Note that the input port is a multiport so multiple input can be 119 * converted in a single firing. If this parameter is a directory name, 120 * output file(s) will be placed in that directory 121 */ 122 public FileParameter outputFilename; 123 124 /** 125 * Boolean setting to determine whether or not to use currently existing 126 * output file, if it exists 127 */ 128 public Parameter useExistingFile; 129 130 /** 131 * Boolean setting to determine whether or not to use disk for storing grid 132 * data rather than putting all data in RAM arrays 133 */ 134 public Parameter useDisk; 135 136 private Parameter output_tokenProductionRate; 137 private Parameter input_tokenConsumptionRate; 138 private Grid inputGrid; 139 private Grid newg; 140 141 private boolean finished; 142 private String prevAscFilename = ""; 143 private String prevOutFilename = ""; 144 private String cachedLine = ""; 145 private Hashtable header = null; 146 147 private int algorithmToUse = _NEAREST_NEIGHBOR; 148 private static final int _NEAREST_NEIGHBOR = 0; 149 private static final int _INVERSE_DISTANCE = 1; 150 151 /** 152 * constructor 153 * 154 *@param container 155 * The container. 156 *@param name 157 * The name of this actor. 158 *@exception IllegalActionException 159 * If the actor cannot be contained by the proposed 160 * container. 161 *@exception NameDuplicationException 162 * If the container already has an actor with this name. 163 */ 164 public GridRescaler(CompositeEntity container, String name) 165 throws NameDuplicationException, IllegalActionException { 166 super(container, name); 167 168 xllcorner = new Parameter(this, "xllcorner"); 169 yllcorner = new Parameter(this, "yllcorner"); 170 cellsize = new Parameter(this, "cellsize"); 171 numrows = new Parameter(this, "numrows"); 172 numcols = new Parameter(this, "numcols"); 173 174 algorithm = new StringParameter(this, "algorithm"); 175 algorithm.setExpression("Nearest Neighbor"); 176 algorithm.addChoice("Nearest Neighbor"); 177 algorithm.addChoice("Inverse Distance"); 178 179 input.setMultiport(true); 180 output_tokenProductionRate = new Parameter(output, 181 "tokenProductionRate"); 182 output_tokenProductionRate.setExpression("0"); 183 outputFilename = new FileParameter(this, "outputFileName"); 184 185 useExistingFile = new Parameter(this, "use Existing File"); 186 useExistingFile.setTypeEquals(BaseType.BOOLEAN); 187 useExistingFile.setToken(BooleanToken.FALSE); 188 189 useDisk = new Parameter(this, "use disk storage (for large grids)"); 190 useDisk.setTypeEquals(BaseType.BOOLEAN); 191 useDisk.setToken(BooleanToken.TRUE); 192 193 } 194 195 /** 196 * Resets the output token production rate based on width of input port 197 */ 198 public void connectionsChanged(Port port) { 199 super.connectionsChanged(port); 200 if (port == input) { 201 try { 202 output_tokenProductionRate.setToken(new IntToken(input 203 .getWidth())); 204 // NOTE: schedule is invalidated automatically already 205 // by the changed connections. 206 } catch (IllegalActionException ex) { 207 throw new InternalErrorException(this, ex, 208 "Failed to set the token production rate of the " 209 + "output port"); 210 } 211 } 212 } 213 214 /** 215 * Creates rescaled ascii grid for each input grid using the input 216 * parameters Uses the 'Grid' class that is disk-based, thus allowing very 217 * large grids. 218 * 219 *@exception IllegalActionException 220 * If there is no director. 221 */ 222 public void fire() throws IllegalActionException { 223 boolean calculateFlag = true; 224 super.fire(); 225 try { 226 String ascfilename = null; 227 String ascOutfilename = null; 228 String ascfileshortname = null; 229 String temp = ""; 230 int width = input.getWidth(); 231 232 boolean useExistingFileValue = ((BooleanToken) useExistingFile 233 .getToken()).booleanValue(); 234 boolean useDiskValue = ((BooleanToken) useDisk.getToken()) 235 .booleanValue(); 236 237 for (int iii = 0; iii < width; iii++) { 238 ascfilename = ((StringToken) input.get(iii)).stringValue(); 239 System.out.println("ascfilename: " + ascfilename); 240 if (ascfilename.indexOf("/") > -1) { 241 ascfileshortname = ascfilename.substring(ascfilename 242 .lastIndexOf("/") + 1, ascfilename.length()); 243 } else if (ascfilename.indexOf("\\") > -1) { 244 ascfileshortname = ascfilename.substring(ascfilename 245 .lastIndexOf("\\") + 1, ascfilename.length()); 246 } else { 247 ascfileshortname = ascfilename; 248 } 249 System.out.println("ascfileshortname: " + ascfileshortname); 250 temp = outputFilename.stringValue(); 251 if (temp.trim().length() == 0) { 252 temp = ascfilename; 253 int dotloc = temp.lastIndexOf("."); 254 temp = temp.substring(0, dotloc); 255 temp = temp + ".out" + iii; 256 outputFilename.setExpression(temp); 257 ascOutfilename = outputFilename.asFile().getPath(); 258 } else { // check to see if the output file is a dir 259 File of = outputFilename.asFile(); 260 if (of.isDirectory()) { 261 temp = ascfileshortname; 262 int dotloc = temp.lastIndexOf("."); 263 temp = temp.substring(0, dotloc); 264 temp = temp + ".out" + iii; 265 ascOutfilename = of.getPath() + "/" + temp; 266 } else { 267 ascOutfilename = outputFilename.asFile().getPath(); 268 } 269 } 270 if (useExistingFileValue) { 271 // check to see if output file 272 File of1 = outputFilename.asFile(); 273 if (of1.exists()) { 274 if (of1.isFile()) { 275 calculateFlag = false; 276 } 277 } 278 } 279 280 System.out.println("ascOutfilename: " + ascOutfilename); 281 282 File file = new File(ascfilename); 283 284 if (file.exists()) { 285 if (calculateFlag) { 286 inputGrid = new Grid(file, !useDiskValue); // a 'false' 287 // !useDiskValue 288 // forces 289 // the use 290 // of disk 291 // rather 292 // than RAM 293 System.out.println("nrows: " + inputGrid.nrows); 294 System.out.println("ncols: " + inputGrid.ncols); 295 System.out.println("delx: " + inputGrid.delx); 296 System.out.println("dely: " + inputGrid.dely); 297 // 298 int nrows; 299 try { 300 nrows = ((IntToken) numrows.getToken()).intValue(); 301 } catch (Exception w) { 302 nrows = 50; 303 } 304 305 int ncols; 306 try { 307 ncols = ((IntToken) numcols.getToken()).intValue(); 308 } catch (Exception w) { 309 ncols = 50; 310 } 311 312 double xmin; 313 try { 314 xmin = ((DoubleToken) xllcorner.getToken()) 315 .doubleValue(); 316 } catch (Exception w) { 317 xmin = 0.0; 318 } 319 320 double ymin; 321 try { 322 ymin = ((DoubleToken) yllcorner.getToken()) 323 .doubleValue(); 324 } catch (Exception w) { 325 ymin = 0.0; 326 } 327 328 double cs; 329 try { 330 cs = ((DoubleToken) cellsize.getToken()) 331 .doubleValue(); 332 } catch (Exception w) { 333 cs = 1.0; 334 } 335 temp = algorithm.stringValue(); 336 if (temp.equals("Inverse Distance")) { 337 algorithmToUse = _INVERSE_DISTANCE; 338 } else { 339 algorithmToUse = _NEAREST_NEIGHBOR; 340 } 341 newg = inputGrid.rescale(nrows, ncols, cs, cs, xmin, 342 ymin, algorithmToUse); 343 newg.createAsc(ascOutfilename); 344 System.out.println("ready to send: " + ascOutfilename); 345 346 } 347 output.broadcast(new StringToken(ascOutfilename)); 348 } else { 349 throw new IllegalActionException("Input file " 350 + ascfilename + " does not exist."); 351 } 352 } 353 } catch (Exception eee) { 354 throw new IllegalActionException("Problem Reading File"); 355 } 356 } 357 358 /** 359 * Post fire the actor. Return false to indicate that the process has 360 * finished. If it returns true, the process will continue indefinitely. 361 * 362 * */ 363 public boolean postfire() throws IllegalActionException { 364 if (inputGrid != null) { 365 inputGrid.delete(); 366 newg.delete(); 367 } 368 return super.postfire(); 369 } 370 371 /** 372 * Pre fire the actor. Calls the super class's prefire in case something is 373 * set there. 374 * 375 * *@exception IllegalActionException 376 */ 377 public boolean prefire() throws IllegalActionException { 378 return super.prefire(); 379 } 380 381}