// **********************************************************************
//
// <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.11 $
// $Date: 2006/02/16 16:22:47 $
// $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 precedence 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 double 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 double 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 double 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 double 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 multiplier. For lat/lon grids, it represents the decimal degrees
* between grid points.
*/
protected double 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(double lat, double lon, double vResolution, double 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, double vResolution, double 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(double lat, double lon, int x, int y, double vResolution, double 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(double lat, double lon, double vResolution, double 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, double vResolution, double 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(double lat, double lon, int x, int y, double vResolution, double 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(double lat, double lon, int x, int y, double vResolution, double 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(double lat, double lon, int x, int y, double vResolution, double 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(double 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 double getLatitude() {
return latitude;
}
public void setLongitude(double 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 double 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(double orient) {
orientation = orient;
}
/**
* Get the angle that was set for the grid to be rotated. In radians,
* up/north is zero.
*/
public double 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(double vRes) {
verticalResolution = vRes;
}
/**
* Get the number of decimal degrees between horizontal rows.
*/
public double getVerticalResolution() {
return verticalResolution;
}
/**
* Set the number of decimal degrees between vertical columns.
*/
public void setHorizontalResolution(double hRes) {
horizontalResolution = hRes;
}
/**
* Get the number of decimal degrees between vertical columns.
*/
public double 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) {
double 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.
*/
double rightLon;
rightLon = longitude + columns * horizontalResolution;
upLat = latitude + rows * verticalResolution;
point1 = (Point) proj.forward(upLat, longitude, new Point());
point2 = (Point) proj.forward(latitude, rightLon, new Point());
/** 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 = (int) Math.round(columns * horizontalResolution);
height = (int) Math.round(rows * verticalResolution);
if (renderType == RENDERTYPE_OFFSET) {
upLat = latitude + columns * verticalResolution;
point1 = (Point) proj.forward(upLat, longitude, new Point());
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));
}
setLabelLocation(getShape(), 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 specifics 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 = (Point) 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 = (Point) 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(double lat, double lon, Projection proj) {
int lat_index = -1;
int lon_index = -1;
if (renderType == RENDERTYPE_LATLON) {
lat_index = (int) Math.round((lat - latitude) / verticalResolution);
lon_index = (int) 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 = (Point) proj.forward(lat, lon, new Point());
lat_index = (int) Math.round((pt.y - point1.y) / verticalResolution);
lon_index = (int) 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(double lat, double lon, Projection proj) {
double lat_index = -1;
double 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 = (Point) proj.forward(lat, lon, new Point());
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];
}
double answer = resolve_four_points(ul, ur, lr, ll, lat_index, lon_index);
return (int) Math.round(answer);
}
return GRID_NULL; // Considered a null value
}
/**
* A try at interpolating 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 double resolve_four_points(int ul, int ur, int lr, int ll, double lat_index, double lon_index) {
double top_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (ur - ul)) + ul;
double bottom_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (float) (lr - ll)) + ll;
double right_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ur - lr)) + lr;
double left_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (float) (ul - ll)) / 100.0F + ll;
double lon_avg = ((lat_index - new Double(Math.floor(lat_index)).floatValue()) * (top_avg - bottom_avg)) + bottom_avg;
double lat_avg = ((lon_index - new Double(Math.floor(lon_index)).floatValue()) * (right_avg - left_avg)) + left_avg;
double result = (lon_avg + lat_avg) / 2.0;
return result;
}
public void restore(OMGeometry source) {
super.restore(source);
if (source instanceof OMGrid) {
OMGrid grid = (OMGrid) source;
this.orientation = grid.orientation;
this.rows = grid.rows;
this.columns = grid.columns;
this.latitude = grid.latitude;
this.longitude = grid.longitude;
this.verticalResolution = grid.verticalResolution;
this.horizontalResolution = grid.horizontalResolution;
this.height = grid.height;
this.width = grid.width;
this.major = grid.major;
this.units = grid.units;
if (grid.data != null) {
this.data = grid.data.deepCopy();
}
if (grid.point != null) {
this.point = new Point(grid.point);
}
if (grid.point1 != null) {
this.point1 = new Point(grid.point1);
}
if (grid.point2 != null) {
this.point2 = new Point(grid.point2);
}
// Not sure how to handle this, since gridObjects are pretty vague.
if (grid.gridObjects != null) {
this.gridObjects = grid.gridObjects;
}
if (grid.generator != null) {
this.generator = grid.generator;
}
}
}
}