// **********************************************************************
//
// <copyright>
//
// BBN Technologies
// 10 Moulton Street
// Cambridge, MA 02138
// (617) 873-8000
//
// Copyright (C) BBNT Solutions LLC. All rights reserved.
//
// </copyright>
// **********************************************************************
//
// $Source: /cvs/distapps/openmap/src/openmap/com/bbn/openmap/omGraphics/OMGrid.java,v $
// $RCSfile: OMGrid.java,v $
// $Revision: 1.5.2.5 $
// $Date: 2005/08/11 21:03:22 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.omGraphics;
import java.awt.Graphics;
import java.awt.Point;
import com.bbn.openmap.omGraphics.grid.GridData;
import com.bbn.openmap.omGraphics.grid.OMGridData;
import com.bbn.openmap.omGraphics.grid.OMGridGenerator;
import com.bbn.openmap.omGraphics.grid.OMGridObjects;
import com.bbn.openmap.proj.Length;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
/**
* An OMGrid object is a two-dimensional container object for data.
* The grid can be laid out in geographic or pixel space. There are
* two different ways that the OMGrid can be used.
* <P>
* The data placed in the array can represent the attributes of what
* you want the grid to represent - elevation values, temperatures,
* etc. In order to render the data on the screen, you'll need to set
* the OMGridGenerator object, and let it interpret the data to create
* the desired OMGraphics for you.
* <P>
* The OMGrid data values can also contain integer ID keys for objects
* contained in the OMGridObjects object held by the OMGrid. By using
* the OMGrid in this way, the OMGrid becomes a placeholder for other
* graphics, and will manage the generate() function calls to those
* objects that are on the screen.
* <P>
* The OMGridGenerator object will take precidence over the
* OMGridObjects - If the OMGridGenerator is set within the grid, the
* OMGridGenerator will create the OMGraphics to be displayed for the
* grid, as opposed the OMGridObjects getting a chance to generate
* themselves. The OMGrid extends OMGraphicList, and the OMGraphics
* that the OMGridGenerator creates are added to the OMGrid. If you
* want the OMGrid to hide the OMGraphics that are created, make it
* vague.
*/
public class OMGrid extends OMGraphicList {
/**
* The orientation angle of the grid, in radians. Up/North is
* zero.
*/
protected float orientation;
/**
* Number of rows in the data array. Gets set by the OMGrid
* depending on the major of the grid.
*/
protected int rows;
/**
* Number of columns in the data array. Gets set by the OMGrid
* depending on the major of the grid.
*/
protected int columns;
/**
* The starting latitude point of the grid. Only relevant when the
* data points are laid out in a lat/lon grid, or when an x/y grid
* is anchored to a lat/lon location. DOES NOT follow the OpenMap
* convention where area object locations are defined by the upper
* left location - the location of the grid is noted by the lower
* left corner, because grid data is usually defined by the lower
* left location. Makes it easier to deal with overlap rows and
* columns, and to calculate the locations of the rows and
* columns.
*/
protected float latitude;
/**
* The starting longitude point of the grid. Only relevant when
* the data points are laid out in a lat/lon grid, or when an x/y
* grid is anchored to a lat/lon location. DOES NOT follow the
* OpenMap convention where area object locations are defined by
* the upper left location - the location of the grid is noted by
* the lower left corner, because grid data is usually defined by
* the lower left location. Makes it easier to deal with overlap
* rows and columns, and to calculate the locations of the rows
* and columns.
*/
protected float longitude;
/**
* The vertical/latitude interval, the distance between row data
* points in the vertical direction. For x/y grids, this can
* server as a pixel multiplier. For lat/lon grids, it represents
* the decimal degrees between grid points.
*/
protected float verticalResolution;
/**
* The horizontal/longitude interval, the distance between column
* data points in the horizontal direction. For x/y grids, this
* can server as a pixel mulitplier. For lat/lon grids, it
* represents the decimal degrees between grid points.
*/
protected float horizontalResolution;
/**
* The Object holding the data for the OMGrid. The GridData
* abstracts the type of data that is held by the OMGrid. Note:
* the 0 index of the array in both directions is in the lower
* left corner of the matrix. As you increase indexes in both
* dimensions, you go up-right.
*/
public GridData data;
/**
* If needed, the data array can hold numerical identifiers, which
* are keys to objects stored in this hashtable. That way, the
* grid can be used to hold an array of objects. If the objs are
* set, then the OMGrid object automatically assumes that all
* graphic operations are supposed to involve the objs.
*/
protected OMGridObjects gridObjects = null;
/**
* Horizontal screen location of the upper left corner of the grid
* in pixels, before projection, of XY and OFFSET grids.
*/
protected Point point = null;
/**
* Horizontal screen location of the upper left corner of the grid
* in pixels, after projection.
*/
public Point point1 = null;
/**
* Horizontal screen location of the lower right corner of the
* grid in pixels, after projection.
*/
public Point point2 = null;
/**
* Pixel height of grid, set after generate. For non-equidistant
* projections, this will be a bounding box height.
*/
public int height = 0;
/**
* Pixel width of grid, set after generate. For non-equidistant
* projections, this will be a bounding box width.
*/
public int width = 0;
/**
* Value of a bad/invalid point in the grid. Has roots in the DTED
* way of doing things.
*/
public final static int GRID_NULL = -32767;
/** An object that knows how to generate graphics for the matrix. */
protected OMGridGenerator generator = null;
/**
* Means that the first dimension of the array refers to the
* column count.
*/
public static final boolean COLUMN_MAJOR = true;
/**
* Means that the first dimension of the array refers to the row
* count.
*/
public static final boolean ROW_MAJOR = false;
/**
* Keep track of which dimension different parts of the double
* array represent. COLUMN_MAJOR is the default, meaning that the
* first dimension of the array represents the vertical location
* in the array, and the second is the horizontal location in the
* array.
*/
protected boolean major = COLUMN_MAJOR;
/**
* The units, if needed, of the values contained in the grid data
* array. Null value is default and acceptable.
*/
protected Length units = null;
/** Default constructor. */
public OMGrid() {}
/**
* Create a OMGrid that covers a lat/lon area. Column major by
* default. If your data is row major, use null for the data, set
* the major direction, and then set the data.
*
* @param lat latitude of lower left corner of the grid, in
* decimal degrees.
* @param lon longitude of lower left corner of the grid, in
* decimal degrees.
* @param vResolution the vertical resolution of the data, as
* decimal degrees per row.
* @param hResolution the horizontal resolution of the data, as
* decimal degrees per column.
* @param data a double array of integers, representing the rows
* and columns of data.
*/
public OMGrid(float lat, float lon, float vResolution, float hResolution,
int[][] data) {
setRenderType(RENDERTYPE_LATLON);
set(lat, lon, 0, 0, vResolution, hResolution, data);
}
/**
* Create a OMGrid that covers a x/y screen area.Column major by
* default. If your data is row major, use null for the data, set
* the major direction, and then set the data.
*
* @param x horizontal location, in pixels, of the left side of
* the grid from the left side of the map.
* @param y vertical location, in pixels, of the top of the grid
* from the top side of the map.
* @param vResolution the vertical resolution of the data, as
* pixels per row.
* @param hResolution the horizontal resolution of the data, as
* pixels per column.
* @param data a double array of integers, representing the rows
* and columns of data.
*/
public OMGrid(int x, int y, float vResolution, float hResolution,
int[][] data) {
setRenderType(RENDERTYPE_XY);
set(0.0f, 0.0f, x, y, vResolution, hResolution, data);
}
/**
* Create a OMGrid that covers a x/y screen area, anchored to a
* lat/lon point. Column major by default. If your data is row
* major, use null for the data, set the major direction, and then
* set the data.
*
* @param lat latitude of the anchor point of the grid, in decimal
* degrees.
* @param lon longitude of the anchor point of the grid, in
* decimal degrees.
* @param x horizontal location, in pixels, of the left side of
* the grid from the longitude anchor point.
* @param y vertical location, in pixels, of the top of the grid
* from the latitude anchor point.
* @param vResolution the vertical resolution of the data, as
* pixels per row.
* @param hResolution the horizontal resolution of the data, as
* pixels per column.
* @param data a double array of integers, representing the rows
* and columns of data.
*/
public OMGrid(float lat, float lon, int x, int y, float vResolution,
float hResolution, int[][] data) {
setRenderType(RENDERTYPE_OFFSET);
set(lat, lon, x, y, vResolution, hResolution, data);
}
/**
* Create a OMGrid that covers a lat/lon area. Column major by
* default. If your data is row major, use null for the data, set
* the major direction, and then set the data.
*
* @param lat latitude of lower left corner of the grid, in
* decimal degrees.
* @param lon longitude of lower left corner of the grid, in
* decimal degrees.
* @param vResolution the vertical resolution of the data, as
* decimal degrees per row.
* @param hResolution the horizontal resolution of the data, as
* decimal degrees per column.
* @param data GridData object holding rows and columns of grid data.
*/
public OMGrid(float lat, float lon, float vResolution, float hResolution,
GridData data) {
setRenderType(RENDERTYPE_LATLON);
set(lat, lon, 0, 0, vResolution, hResolution, data);
}
/**
* Create a OMGrid that covers a x/y screen area.Column major by
* default. If your data is row major, use null for the data, set
* the major direction, and then set the data.
*
* @param x horizontal location, in pixels, of the left side of
* the grid from the left side of the map.
* @param y vertical location, in pixels, of the top of the grid
* from the top side of the map.
* @param vResolution the vertical resolution of the data, as
* pixels per row.
* @param hResolution the horizontal resolution of the data, as
* pixels per column.
* @param data GridData object holding rows and columns of grid data.
*/
public OMGrid(int x, int y, float vResolution, float hResolution,
GridData data) {
setRenderType(RENDERTYPE_XY);
set(0.0f, 0.0f, x, y, vResolution, hResolution, data);
}
/**
* Create a OMGrid that covers a x/y screen area, anchored to a
* lat/lon point. Column major by default. If your data is row
* major, use null for the data, set the major direction, and then
* set the data.
*
* @param lat latitude of the anchor point of the grid, in decimal
* degrees.
* @param lon longitude of the anchor point of the grid, in
* decimal degrees.
* @param x horizontal location, in pixels, of the left side of
* the grid from the longitude anchor point.
* @param y vertical location, in pixels, of the top of the grid
* from the latitude anchor point.
* @param vResolution the vertical resolution of the data, as
* pixels per row.
* @param hResolution the horizontal resolution of the data, as
* pixels per column.
* @param data GridData object holding rows and columns of grid data.
*/
public OMGrid(float lat, float lon, int x, int y, float vResolution,
float hResolution, GridData data) {
setRenderType(RENDERTYPE_OFFSET);
set(lat, lon, x, y, vResolution, hResolution, data);
}
/**
* Set the parameters of the OMGrid after construction.
*/
protected void set(float lat, float lon, int x, int y, float vResolution,
float hResolution, int[][] data) {
set(lat, lon, x, y, vResolution, hResolution, new OMGridData.Int(data));
}
/**
* Set the parameters of the OMGrid after construction.
*/
protected void set(float lat, float lon, int x, int y, float vResolution,
float hResolution, GridData data) {
latitude = lat;
longitude = lon;
point = new Point(x, y);
verticalResolution = vResolution;
horizontalResolution = hResolution;
setData(data);
}
/**
* Set the vertical number of data points. Should correspond to
* the the data, and to the major setting of the OMGrid. Will be
* set automatically when the data is set.
*
* @deprecated set when data is set.
*/
public void setRows(int rows) {
// this.rows = rows;
}
/**
* Get the vertical number of data points.
*/
public int getRows() {
if (data != null) {
return data.getNumRows();
} else {
return 0;
}
}
public void setLatitude(float lat) {
if (latitude == lat)
return;
latitude = lat;
setNeedToRegenerate(true);
}
/**
* Get the latitude of the lower left anchor point of the grid, in
* decimal degrees.
*/
public float getLatitude() {
return latitude;
}
public void setLongitude(float lon) {
if (longitude == lon)
return;
longitude = lon;
setNeedToRegenerate(true);
}
/**
* Get the latitude of the lower left anchor point of the grid, in
* decimal degrees.
*/
public float getLongitude() {
return longitude;
}
/**
* Get the screen location, or x/y offset from the lat/lon anchor
* point, of the lower left corner of the grid.
*/
public Point getPoint() {
return point;
}
/**
* Set the horizontal number of data points. Should correspond to
* the the data, and to the major setting of the OMGrid. Will be
* set automatically when the data is set. Does nothing.
*
* @deprecated set when the data is set
*/
public void setColumns(int columns) {
// this.columns = columns;
}
/**
* Set the horizontal number of data points.
*/
public int getColumns() {
if (data != null) {
return data.getNumColumns();
} else {
return 0;
}
}
/**
* Set which dimension is defined first in the two dimensional
* array. If COLUMN_MAJOR (true and the default), the first
* dimension of the data array will represent the horizontal
* location of the data, and the second dimension will represent
* the vertical location. Vice versa for COLUMN_ROW. Calling this
* method will reset the column and row count to match the data to
* the new orientation.
*/
public void setMajor(boolean maj) {
if (data != null && maj != data.getMajor()) {
data.setMajor(maj);
}
}
/**
* Set which dimension is defined first in the two dimensional
* array.
*/
public boolean getMajor() {
if (data != null) {
return data.getMajor();
}
return major;
}
/**
* Set the angle that the grid should be rotated. May not be
* implemented for some OMGridGenerators.
*
* @param orient is the angle of the grid, in radians. Up/North is
* zero.
*/
public void setOrientation(float orient) {
orientation = orient;
}
/**
* Get the angle that was set for the grid to be rotated. In
* radians, up/north is zero.
*/
public float getOrientation() {
return orientation;
}
/**
* Set the data of the grid. The major setting will cause this
* method to set the number of rows and columns accordingly. The
* values in the array will be interpreted to the OMGridGenerator
* that you provide to this OMGrid. The OMGridGenerator will
* create what gets drawn on the map based on this data. The
* int[][] will be wrapped by a GridData.Int object.
*/
public void setData(int[][] data) {
setData(new OMGridData.Int(data));
}
/**
* Set the data of the grid. The major setting will cause this
* method to set the number of rows and columns accordingly. The
* values in the array will be interpreted to the OMGridGenerator
* that you provide to this OMGrid. The OMGridGenerator will
* create what gets drawn on the map based on this data.
*/
public void setData(GridData data) {
this.data = data;
}
/**
* Get the data array for the OMGrid. What these numbers represent
* depends on what OMGridGenerator is being used.
*/
public GridData getData() {
return data;
}
/**
* There is an option in the OMGrid where the data array contains
* ID numbers for a set of other objects. So the grid holds onto
* the location of these objects, and the OMGridObjects provides
* the ID mapping to the actual object.
*/
public void setGridObjects(OMGridObjects someGridObjs) {
gridObjects = someGridObjs;
}
/**
* Get the OMGridObjects containing the mapping of the data array
* IDs to a set of Objects.
*/
public OMGridObjects getGridObjects() {
return gridObjects;
}
/**
* Set the OMGridGenerator that will interpret the data array and
* create OMGraphics for it.
*/
public void setGenerator(OMGridGenerator aGenerator) {
generator = aGenerator;
}
/**
* Get the OMGridGenerator being used to interpret the data array.
*/
public OMGridGenerator getGenerator() {
return generator;
}
/**
* Set the number of decimal degrees between horizontal rows.
*/
public void setVerticalResolution(float vRes) {
verticalResolution = vRes;
}
/**
* Get the number of decimal degrees between horizontal rows.
*/
public float getVerticalResolution() {
return verticalResolution;
}
/**
* Set the number of decimal degrees between vertical columns.
*/
public void setHorizontalResolution(float hRes) {
horizontalResolution = hRes;
}
/**
* Get the number of decimal degrees between vertical columns.
*/
public float getHorizontalResolution() {
return horizontalResolution;
}
public int getWidth() {
return width;
}
public int getHeight() {
return height;
}
/**
* Set the units for the grid data.
*/
public void setUnits(Length length) {
units = length;
}
/**
* Get the units for the grid data.
*/
public Length getUnits() {
return units;
}
/**
* Generate OMGraphics based on the data array. If there is an
* OMGridGenerator, it will be used to generate OMGraphics from
* the data array. If not, the OMGridObjects will be used to
* create OMGraphics for the map.
*/
public synchronized boolean generate(Projection proj) {
float upLat;
int columns = getColumns();
int rows = getRows();
// Clear out the OMGraphicList part
super.clear();
setShape(null);
/**
* Let's figure out the dimensions and location of the grid,
* relative to the screen.
*/
if (renderType == RENDERTYPE_LATLON) {
/**
* Means that the latitudeResolution and
* horizontalResolution refer to degrees/datapoint.
*/
float rightLon;
rightLon = longitude + ((float) columns) * horizontalResolution;
upLat = latitude + ((float) rows) * verticalResolution;
point1 = proj.forward(upLat, longitude);
point2 = proj.forward(latitude, rightLon);
/** For later... */
height = point2.y - point1.y;
width = point2.x - point1.x;
if (Debug.debugging("grid")) {
Debug.output("OMGrid.generate: height = " + height
+ ", width = " + width);
}
} else if (renderType == RENDERTYPE_XY
|| renderType == RENDERTYPE_OFFSET) {
width = Math.round((float) columns * horizontalResolution);
height = Math.round((float) rows * verticalResolution);
if (renderType == RENDERTYPE_OFFSET) {
upLat = latitude + columns * verticalResolution;
point1 = proj.forward(upLat, longitude);
point1.x += point.x;
point1.y += point.y;
} else {
point1 = point;
}
point2 = new Point(point1.x + width, point1.y + height);
} else {
return false;
}
if (Debug.debugging("grid")) {
Debug.output("OMGrid generated grid, at " + point1 + " and "
+ point2 + " with height " + height + " and width " + width);
}
// THis has to happen here, in case the generator wants to
// check the OMGrid coverage before deciding to do the work
// for creating OMGraphics.
setShape();
/** Now generate the grid in the desired way... */
if (generator != null && generator.needGenerateToRender()) {
add(generator.generate(this, proj));
} else if (gridObjects != null) {
add(generateGridObjects(proj));
}
setNeedToRegenerate(false);
return true;
}
/**
* Set a bounding rectangle as this OMGrid's shape, based on the
* location and size of the coverage of the grid.
*/
public void setShape() {
// If nothing is available as the shape, generate shape
// that is a boundary of the generated image.
// We'll make it a GeneralPath rectangle.
int w = width;
int h = height;
setShape(createBoxShape(point1.x, point1.y, w, h));
}
/**
* Render the OMGraphics created to represent the grid data.
*/
public void render(Graphics g) {
if (generator != null) {
if ((needToRegenerate && generator.needGenerateToRender())
|| !isVisible()) {
Debug.message("grid",
"OMGrid: need to generate or is not visible!");
return;
}
}
super.render(g);
}
/**
* Called from generate() if there isn't a OMGridGenerator. Goes
* through the grid, figuring out which data array indexes are on
* the map, and then calls generate on those grid objects.
*/
public OMGraphic generateGridObjects(Projection proj) {
OMGraphicList graphiclist = new OMGraphicList();
/**
* There could be some way to optimize the search for objects
* in the grid that are actually visible, but that would
* require knowledge of the specifices of projections. Keeping
* this as generic as possible at this point.
*/
// Since GridObjects only work with a int array, we need to
// check to see if the GridObject is of type GridData.Int and
// only bother returning if it is.
GridData gd = getData();
if (gd instanceof GridData.Int) {
GridData.Int gdi = (GridData.Int) gd;
Point pt = new Point();
boolean major = gdi.getMajor();
int[][] data = gdi.getData();
for (int x = 0; x < data.length; x++) {
for (int y = 0; y < data[0].length; y++) {
// First, calculate if the grid post is even on
// the map
if (major == COLUMN_MAJOR) {
if (renderType == RENDERTYPE_LATLON) {
pt = proj.forward(latitude + y * verticalResolution,
longitude + x * horizontalResolution,
pt);
} else {
pt.y = point1.y + (int) (y * verticalResolution);
pt.x = point1.x + (int) (x * horizontalResolution);
}
} else {
if (renderType == RENDERTYPE_LATLON) {
pt = proj.forward(latitude + x * verticalResolution,
longitude + y * horizontalResolution,
pt);
} else {
pt.y = point1.y + (int) (x * verticalResolution);
pt.x = point1.x + (int) (y * horizontalResolution);
}
}
if ((pt.x >= 0 || pt.x <= proj.getWidth())
&& (pt.y >= 0 || pt.y <= proj.getHeight())) {
// It's on the map! Get a graphic from it!
graphiclist.add(gridObjects.generate(data[x][y], proj));
}
}
}
}
return graphiclist;
}
/**
* The value at the closest SW post to the given lat/lon. This is
* just a go-to-the-closest-post solution.
*
* @param lat latitude in decimal degrees.
* @param lon longitude in decimal degrees.
* @param proj map projection, which is needed for XY or OFFSET
* grids.
* @return value found at the nearest grid point. This is an
* object returned from the GridObject data object, so
* what it is depends on that. You can test if it's a
* java.lang.Number object to get different values out of
* it if it is.
*/
public Object valueAt(float lat, float lon, Projection proj) {
int lat_index = -1;
int lon_index = -1;
if (renderType == RENDERTYPE_LATLON) {
lat_index = Math.round((lat - latitude) / verticalResolution);
lon_index = Math.round((lon - longitude) / horizontalResolution);
} else if (renderType == RENDERTYPE_XY
|| renderType == RENDERTYPE_OFFSET) {
if (getNeedToRegenerate()) {
/** Only care about this if we need to... */
if (proj == null) {
return null;
}
generate(proj);
}
Point pt = proj.forward(lat, lon);
lat_index = Math.round((pt.y - point1.y) / verticalResolution);
lon_index = Math.round((pt.x - point1.x) / horizontalResolution);
}
GridData gd = getData();
if (gd != null && (lat_index >= 0 || lat_index < rows)
&& (lon_index >= 0 || lon_index < columns)) {
Object obj = null;
if (major == COLUMN_MAJOR) {
obj = gd.get(lon_index, lat_index);
} else {
obj = gd.get(lat_index, lon_index);
}
return obj;
}
return null;
}
/**
* Interpolated value at a given lat/lon - should be more precise
* than valueAt(), but that depends on the resolution of the data.
* Works with GridData.Int data objects.
*
* @param lat latitude in decimal degrees.
* @param lon longitude in decimal degrees.
* @param proj map projection, which is needed for XY or OFFSET
* grids.
* @return value at lat/lon
*/
public int interpValueAt(float lat, float lon, Projection proj) {
float lat_index = -1;
float lon_index = -1;
GridData gridData = getData();
if (!(gridData instanceof GridData.Int)) {
Debug.error("OMGrid.interpValueAt only works for integer data.");
return 0;
}
int[][] data = ((GridData.Int) gridData).getData();
boolean major = gridData.getMajor();
if (renderType == RENDERTYPE_LATLON) {
lat_index = (lat - latitude) / verticalResolution;
lon_index = (lon - longitude) / horizontalResolution;
} else if (renderType == RENDERTYPE_XY
|| renderType == RENDERTYPE_OFFSET) {
if (getNeedToRegenerate()) {
/** Only care about this if we need to... */
if (proj == null) {
return GRID_NULL;
}
generate(proj);
}
Point pt = proj.forward(lat, lon);
lat_index = (pt.y - point1.y) / verticalResolution;
lon_index = (pt.x - point1.x) / horizontalResolution;
}
if ((lat_index >= 0 || lat_index < rows)
&& (lon_index >= 0 || lon_index < columns)) {
int lflon_index = (int) Math.floor(lon_index);
int lclon_index = (int) Math.ceil(lon_index);
int lflat_index = (int) Math.floor(lat_index);
int lclat_index = (int) Math.ceil(lat_index);
//////////////////////////////////////////////////////
// Print out grid of 20x20 elevations with
// the "asked for" point being in the middle
if (Debug.debugging("grid")) {
System.out.println("***Elevation Map***");
for (int l = lclat_index + 5; l > lflat_index - 5; l--) {
System.out.println();
for (int k = lflon_index - 5; k < lclon_index + 5; k++) {
if ((l >= 0 || l < rows) && (k >= 0 || k < columns)) {
if (major == COLUMN_MAJOR) {
System.out.print(data[k][l] + " ");
} else {
System.out.print(data[l][k] + " ");
}
}
}
}
System.out.println();
System.out.println();
}
//////////////////////////////////////////////////////
int ul, ur, ll, lr;
if (major == COLUMN_MAJOR) {
ul = data[lflon_index][lclat_index];
ur = data[lclon_index][lclat_index];
ll = data[lflon_index][lclat_index];
lr = data[lclon_index][lclat_index];
} else {
ul = data[lclat_index][lflon_index];
ur = data[lclat_index][lclon_index];
ll = data[lclat_index][lflon_index];
lr = data[lclat_index][lclon_index];
}
float answer = resolve_four_points(ul,
ur,
lr,
ll,
lat_index,
lon_index);
return Math.round(answer);
}
return GRID_NULL; // Considered a null value
}
/**
* A try at interoplating the corners of the surrounding posts,
* given a lat lon. Called from a function where the data for the
* lon has been read in.
*/
private float resolve_four_points(int ul, int ur, int lr, int ll,
float lat_index, float lon_index) {
float top_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (ur - ul))
+ ul;
float bottom_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (lr - ll))
+ ll;
float right_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ur - lr))
+ lr;
float left_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ul - ll))
/ 100.0F + ll;
float lon_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (top_avg - bottom_avg))
+ bottom_avg;
float lat_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (right_avg - left_avg))
+ left_avg;
float result = (lon_avg + lat_avg) / 2.0F;
return result;
}
}