001 /** 002 * 003 */ 004 package org.wdssii.core; 005 006 import java.util.Date; 007 008 import org.apache.commons.logging.Log; 009 import org.apache.commons.logging.LogFactory; 010 011 import ucar.units.ConversionException; 012 import ucar.units.Converter; 013 import ucar.units.Unit; 014 015 /** 016 * 017 * A regularly spaced grid where the first dimension is latitude and the second dimension is longitude. 018 * The (0,0) location is the north-west corner. In the first dimension, latitude decreases (southward) 019 * and in the second dimension, longitude increases (eastward). 020 * 021 * @author lakshman 022 * 023 */ 024 public class LatLonGrid extends DataType { 025 private static Log log = LogFactory.getLog(LatLonGrid.class); 026 private final float deltaLat, deltaLon; 027 private float[][] values; 028 029 /** {@inheritDoc} */ 030 public LatLonGrid(LatLonGrid master){ 031 super(master); 032 deltaLat = master.deltaLat; 033 deltaLon = master.deltaLon; 034 values = copyOf(master.values); 035 } 036 037 public LatLonGrid(Location nwCorner, Date time, String typeName, float deltaLat, float deltaLon, float[][] values){ 038 super(nwCorner, time, typeName); 039 this.deltaLat = deltaLat; 040 this.deltaLon = deltaLon; 041 this.values = values; 042 } 043 044 /** All the values are initialized to zero */ 045 public LatLonGrid(Location nwCorner, Date time, String typeName, float deltaLat, float deltaLon, int numLat, int numLon){ 046 this(nwCorner, time, typeName, deltaLat, deltaLon, new float[numLat][numLon] ); 047 } 048 049 public float[][] getValues(){ 050 return values; 051 } 052 053 public int getNumLat(){ 054 return values.length; 055 } 056 057 public int getNumLon(){ 058 if ( values.length == 0 ){ 059 return 0; 060 } else { 061 return values[0].length; 062 } 063 } 064 065 /** positive number that indicates the size of a pixel in lat-direction */ 066 public float getDeltaLat(){ 067 return deltaLat; 068 } 069 070 /** positive number that indicates the size of a pixel in lon-direction */ 071 public float getDeltaLon(){ 072 return deltaLon; 073 } 074 075 /** Converts all the values in this grid to the specified unit. 076 * @see UdUnits.parse() 077 * @param grid 078 * @param toUnit Use UdUnits.parse() to create this Unit 079 */ 080 public void convertToUnit(Unit toUnit) { 081 if (this.getUnit() == null) { 082 log.debug("Missing units in " + this.getTypeName() + " assuming " 083 + toUnit); 084 return; 085 } 086 Unit gridUnit = UdUnits.parse(this.getUnit()); 087 if (gridUnit.equals(toUnit)) { 088 return; 089 } 090 try { 091 Converter converter = gridUnit.getConverterTo(toUnit); 092 float[][] values = this.getValues(); 093 for (int i = 0; i < values.length; ++i) { 094 for (int j = 0; j < values.length; ++j) { 095 values[i][j] = converter.convert(values[i][j]); 096 } 097 } 098 } catch (ConversionException e) { 099 log.error("Unit in " + this.getTypeName() + " is " + gridUnit 100 + "; expected something compatible with " + toUnit); 101 } 102 } 103 104 /** Get the value at a Location. The height is ignored and MissingData is returned for values outside */ 105 public float getValue(Location loc){ 106 try{ 107 // not reusing Pixel code since this is more efficient 108 int i = (int) Math.rint( (this.getLocation().getLatitude() - loc.getLatitude()) / this.deltaLat); 109 int j = (int) Math.rint( (loc.getLongitude() - this.getLocation().getLongitude()) / this.deltaLon); 110 return values[i][j]; 111 } catch(Exception e) { 112 return DataType.MissingData; 113 } 114 } 115 116 /** returns the Pixel corresponding to the location. The height is ignored but a null value is 117 * returned if the location is outside the grid. 118 */ 119 public Pixel getPixel(Location loc){ 120 int i = (int) Math.rint( (this.getLocation().getLatitude() - loc.getLatitude()) / this.deltaLat); 121 int j = (int) Math.rint( (loc.getLongitude() - this.getLocation().getLongitude()) / this.deltaLon); 122 if ( i >= 0 && i < getNumLat() && j >= 0 && j < getNumLon() ){ 123 return new Pixel(i,j); 124 } else { 125 return null; 126 } 127 } 128 129 public float getValue(Pixel p){ 130 return values[p.x][p.y]; 131 } 132 133 public static class Pixel { 134 public int x; 135 public int y; 136 public Pixel(int x, int y){ 137 this.x = x; 138 this.y = y; 139 } 140 } 141 142 /** Can be used to set all the values of the grid at once. */ 143 public void setValues(float[][] values2) { 144 values = values2; 145 } 146 }