// // AREAnav.java // /* This source file is part of the edu.wisc.ssec.mcidas package and is Copyright (C) 1998 - 2006 by Tom Whittaker, Tommy Jasmin, Tom Rink, Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden and others. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ /** * The AREAnav is the superclass for AREA file navigation modules. * When used with AreaFile class, set up like this: * *
* AreaFile af;
* try {
* af = new AreaFile("/home/user/mcidas/data/AREA0001");
* } catch (AreaFileException e) {
* System.out.println(e);
* return;
* }
* int[] dir;
* try { dir=af.getDir();
* } catch (AreaFileException e){
* System.out.println(e);
* return;
* }
* int[] nav;
* try { nav=af.getNav();
* } catch (AreaFileException e){
* System.out.println(e);
* return;
* }
* try {
* AREAnav ng = new XXXXnav(nav); // XXXXnav is the specific implementation
* } catch (IllegalArgumentException excp) {
* System.out.println(excp);
* return;
* }
* ng.setImageStart(dir[5], dir[6]);
* ng.setRes(dir[11], dir[12]);
* ng.setStart(0,0);
* ng.setMag(1,1);
* ......................
*
*
* By convention, latitudes are positive North (negative South), and
* longitudes are positive East (negative West).
*
* @author Tom Whittaker/Don Murray
*
*/
public abstract class AREAnav
implements java.io.Serializable
{
static final long serialVersionUID = 2334637524537406773L;
/** Constant for radians to degrees conversion */
public final static double RADIANS_TO_DEGREES = 180./Math.PI;
/** Constant for degrees to radians conversion */
public final static double DEGREES_TO_RADIANS = Math.PI/180.;
/** Code value in AREA files used to designate DMSP navigation */
public static final int DMSP = 0x444D5250;
/** Code value in AREA files used to designate GMSX (GMS) navigation */
public static final int GMSX = 0x474D5358;
/** Code value in AREA files used to designate GOES (GOES D-H) navigation */
public static final int GOES = 0x474F4553;
/** Code value in AREA files used to designate GVAR (GOES I-M) navigation */
public static final int GVAR = 0x47564152;
/** Code value in AREA files used to designate MOLL (Mollweide)
navigation */
public static final int MOLL = 0x4D4F4C4C;
/** Code value in AREA files used to designate MSAT (Meteosat)
navigation */
public static final int MSAT = 0x4D534154;
/** Code value in AREA files used to designate MSGT navigation */
public static final int MSGT = 0x4D534754;
/** Code value in AREA files used to designate MSG navigation */
public static final int MSG = 0x4D534720;
/** Code value in AREA files used to designate POES navigation */
public static final int POES = 0x5449524F;
/** Code value in AREA files used to designate RADR (radar) navigation */
public static final int RADR = 0x52414452;
/** Code value in AREA files used to designate RECT (rectilinear)
navigation */
public static final int RECT = 0x52454354;
/** Code value in AREA files used to designate PS (polar stereographic)
navigation */
public static final int PS = 0x50532020;
/** Code value in AREA files used to designate MERC (mercator) navigation */
public static final int MERC = 0x4D455243;
/** Code value in AREA files used to designate TANC (tangent cone)
navigation */
public static final int TANC = 0x54414E43;
/** Code value in AREA files used to designate LAMB (lambert conformal)
navigation */
public static final int LAMB = 0x4C414D42;
/** Code value in AREA files used to designate Lat/Lon */
public static final int LALO = 0x4C414C4F;
/** Code value for specifying Latitude/Longitude transformations */
public static final int LL = 123;
/** Code value for specifying Cartesian (X/Y) transformations */
public static final int XY = 234;
/** "Line" index in line/element array */
public final int indexLine=1;
/** "Element" index in line/element array */
public final int indexEle=0;
/** "Latitude" index in latitude/longitude array */
public final int indexLat=0;
/** "Longitude" index in latitude/longitude array */
public final int indexLon=1;
private boolean isLineFlipped = false;
private float lineOffset = 0.0f;
// the following are ancillary info set by the set/get
// public methods Res, Mag, and Start
private float resLine = 1.f;
private float resElement = 1.f;
private float magLine = 1.f;
private float magElement = 1.f;
private float startLine = 0.f;
private float startElement = 0.f;
private float startImageLine = 0.f;
private float startImageElement = 0.f;
/** converts from satellite coordinates to latitude/longitude
*
* @param linele[][] array of line/element pairs. Where
* linele[indexLine][] is a 'line' and
* linele[indexEle][] is an element. These are in
* 'file' coordinates (not "image" coordinates.)
*
* @return latlon[][] array of lat/long pairs. Output array is
* latlon[indexLat][] of latitudes and
* latlon[indexLon][] of longitudes.
*
*/
public abstract double[][] toLatLon(double[][] linele);
/**
* toLinEle converts lat/long to satellite line/element
*
* @param latlon[][] array of lat/long pairs. Where latlon[indexLat][]
* are latitudes and latlon[indexLon][] are longitudes.
*
* @return linele[][] array of line/element pairs. Where
* linele[indexLine][] is a line and linele[indexEle][]
* is an element. These are in 'file' coordinates
* (not "image" coordinates);
*/
public abstract double[][] toLinEle(double[][] latlon);
/** converts from satellite coordinates to latitude/longitude.
* This implementation converts the input array to doubles
* and calls the double signature of {@link toLatLon(double[][])}.
* Subclasses should implement a real float version for better
* performance.
*
* @param linele[][] array of line/element pairs. Where
* linele[indexLine][] is a 'line' and
* linele[indexEle][] is an element. These are in
* 'file' coordinates (not "image" coordinates.)
*
* @return latlon[][] array of lat/long pairs. Output array is
* latlon[indexLat][] of latitudes and
* latlon[indexLon][] of longitudes.
*
*/
public float[][] toLatLon(float[][] linele) {
return doubleToFloat(toLatLon(floatToDouble(linele)));
}
/**
* toLinEle converts lat/long to satellite line/element
* This implementation converts the input array to doubles
* and calls the double signature of {@link toLineEle(double[][])}.
* Subclasses should implement a real float version for better
* performance.
*
* @param latlon[][] array of lat/long pairs. Where latlon[indexLat][]
* are latitudes and latlon[indexLon][] are longitudes.
*
* @return linele[][] array of line/element pairs. Where
* linele[indexLine][] is a line and linele[indexEle][]
* is an element. These are in 'file' coordinates
* (not "image" coordinates);
*/
public float[][] toLinEle(float[][] latlon) {
return doubleToFloat(toLinEle(floatToDouble(latlon)));
}
/**
* Define the resolution of the image.
* values range from 1 (highest) to n (lowest). Note
* that when an image is blown down during display, this
* value is changed in the frame object to reflect this
* (rather than changing the magnification).
*
* @param resLine is the resolution in the 'line' direction.
* This value is always > 0.
*
* @param resElement is the resolution in the 'element'
* direction. The value is always >0.
*
*/
public void setRes(int resLine, int resElement)
{
this.resLine = (float)resLine;
this.resElement = (float)resElement;
}
/**
* Define the resolution of the image.
* values range from 1 (highest) to n (lowest). Note
* that when an image is blown down during display, this
* value is changed in the frame object to reflect this
* (rather than changing the magnification).
*
* @param resLine is the resolution in the 'line' direction.
* This value is always > 0.
*
* @param resElement is the resolution in the 'element'
* direction. The value is always >0.
*
*/
public void setRes(float resLine, float resElement)
{
this.resLine = resLine;
this.resElement = resElement;
}
/**
* define the magnification factor (in case an image
* was blown up when displayed). This value is always > 0.
*
* @param magLine is the (line) magnification factor that might have
* been used when the image was displayed.
*
* @param magElment is the (element) magnification factor
* that might have been used when the image was displayed.
*
*/
public void setMag(int magLine, int magElement)
{
this.magLine = (float)magLine;
this.magElement = (float)magElement;
}
/** define the magnification factor (in case an image
* was blown up when displayed). This value is always > 0.
*
* @param magLine is the (line) magnification factor that might have
* been used when the image was displayed.
*
* @param magElment is the (element) magnification factor
* that might have been used when the image was displayed.
*
*/
public void setMag(float magLine, float magElement)
{
this.magLine = magLine;
this.magElement = magElement;
}
/** define the starting line and element of another
* coordinate system -- usually a TV (note that the TV
* coordinates start at (1,1).
*
* @param startLine the starting line number in another
* coordinate system
*
* @param startElement the starting element number in another
* coordinate system
*
*/
public void setStart(int startLine, int startElement)
{
this.startLine = (float)startLine;
this.startElement = (float)startElement;
}
/** define the coordinate in the [0][0] position of the image.
*
* @param startImageLine redefines the starting image line number
* (may be different than the signal indicated)
*
* @param startImageElement redefines the starting image element number
* (may be different than the signal indicated)
*
*/
public void setImageStart(int startImageLine, int startImageElement)
{
this.startImageLine = (float)startImageLine;
this.startImageElement = (float)startImageElement;
}
/**
* specify whether the line coordinates are inverted and the line
* offset.
*
* @param line ending line number
*
*/
public void setFlipLineCoordinates(int line)
{
isLineFlipped = true;
lineOffset = (float) line;
}
/**
* Determine if navigation is using flipped coordinates
*
* @return true if using flipped line coordinates, otherwise false
*/
public boolean isFlippedLineCoordinates()
{
return isLineFlipped;
}
/**
* Get the line offset for flipped coordinates
*
* @return line offset
*/
public double getLineOffset()
{
return (double) lineOffset;
}
/**
* Converts line/element array values from AREA (file) to Image
* coordinates. Creates new array instead of mucking with input.
*
* @param linele input line/element array in AREA coordinates
* @return array in Image coordinates
*/
public double[][] areaCoordToImageCoord(double[][] linele)
{
double newvals[][] = new double[2][linele[0].length];
double line;
for (int i = 0; i < linele[0].length; i++)
{
// account for flipped coordinates
line = isLineFlipped ? lineOffset - linele[indexLine][i]
: linele[indexLine][i];
newvals[indexLine][i] =
startImageLine + (resLine * (line - startLine)) / magLine;
newvals[indexEle][i] =
startImageElement + (resElement * (linele[indexEle][i] -
startElement))/magElement;
}
return newvals;
}
/**
* Converts line/element array values from Image to AREA (File)
* coordinates. Creates new array instead of mucking with input.
*
* @param linele input line/element array Image coordinates
* @return array in AREA coordinates
*/
public double[][] imageCoordToAreaCoord(double[][] linele)
{
double newvals[][] = new double[2][linele[0].length];
for (int i = 0; i < linele[0].length; i++)
{
newvals[indexLine][i] = startLine +
( magLine * (linele[indexLine][i] -
startImageLine)) / resLine;
// account for flipped coordinates
if (isLineFlipped) newvals[indexLine][i] =
lineOffset - newvals[indexLine][i];
newvals[indexEle][i] = startElement +
( magElement * (linele[indexEle][i] -
startImageElement)) / resElement;
}
return newvals;
}
/**
* Converts line/element array values from AREA (file) to Image
* coordinates. Creates new array instead of mucking with input.
*
* @param linele input line/element array in AREA coordinates
* @return array in Image coordinates
*/
public float[][] areaCoordToImageCoord(float[][] linele)
{
float newvals[][] = new float[2][linele[0].length];
float line;
for (int i = 0; i < linele[0].length; i++)
{
// account for flipped coordinates
line = isLineFlipped ? lineOffset - linele[indexLine][i]
: linele[indexLine][i];
newvals[indexLine][i] =
startImageLine + (resLine * (line - startLine)) / magLine;
newvals[indexEle][i] =
startImageElement + (resElement * (linele[indexEle][i] -
startElement))/magElement;
}
return newvals;
}
/**
* Converts line/element array values from Image to AREA (File)
* coordinates. Creates new array instead of mucking with input.
*
* @param linele input line/element array Image coordinates
* @return array in AREA coordinates
*/
public float[][] imageCoordToAreaCoord(float[][] linele)
{
float newvals[][] = new float[2][linele[0].length];
for (int i = 0; i < linele[0].length; i++)
{
newvals[indexLine][i] = startLine +
( magLine * (linele[indexLine][i] -
startImageLine)) / resLine;
// account for flipped coordinates
if (isLineFlipped) newvals[indexLine][i] =
lineOffset - newvals[indexLine][i];
newvals[indexEle][i] = startElement +
( magElement * (linele[indexEle][i] -
startImageElement)) / resElement;
}
return newvals;
}
/**
* Determines whether or not the Object
in question is
* the same as this AREAnav
. Right now, this returns
* false until we can figure out when two navigations are equal.
* Subclasses could override if desired.
*
* @param obj the AREAnav in question
*/
public boolean equals(Object obj)
{
// return false; WLH 13 April 2000, this broke visad.data.mcidas.TestArea
if (obj instanceof AREAnav)
{
// this should really be done in the subclasses, but that will
// have to wait for another day.
AREAnav nav = (AREAnav) obj;
return (resLine == nav.resLine &&
resElement == nav.resElement &&
magLine == nav.magLine &&
magElement == nav.magElement &&
startLine == nav.startLine &&
startElement == nav.startElement &&
startImageLine == nav.startImageLine &&
startImageElement == nav.startImageElement &&
isLineFlipped == nav.isLineFlipped &&
lineOffset == nav.lineOffset);
}
else
{
return false;
}
}
/**
* Return a String
representation of this nav module
* @return wordy string.
*/
public String toString() {
String className = getClass().getName();
int lastDot = className.lastIndexOf('.');
className = className.substring(lastDot+1);
return className.substring(0,className.indexOf("nav"));
}
public static double[][] floatToDouble(float[][] value) {
if (value == null) return null;
double[][] val = new double[value.length][];
for (int i=0; i