// **********************************************************************
//
// <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/proj/coords/MGRSPoint.java,v $
// $RCSfile: MGRSPoint.java,v $
// $Revision: 1.20 $
// $Date: 2009/01/21 01:24:41 $
// $Author: dietrick $
//
// **********************************************************************
package com.bbn.openmap.proj.coords;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import java.io.PrintStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import com.bbn.openmap.proj.Ellipsoid;
import com.bbn.openmap.util.ArgParser;
import com.bbn.openmap.util.Debug;
/**
* A class representing a MGRS coordinate that has the ability to provide the
* decimal degree lat/lon equivalent, as well as the UTM equivalent. This class
* does not do checks to see if the MGRS coordinates provided actually make
* sense. It assumes that the values are valid.
*/
public class MGRSPoint
extends ZonedUTMPoint {
/**
* UTM zones are grouped, and assigned to one of a group of 6 sets.
*/
protected final static int NUM_100K_SETS = 6;
/**
* The column letters (for easting) of the lower left value, per set.
*/
public final static int[] SET_ORIGIN_COLUMN_LETTERS = {
'A',
'J',
'S',
'A',
'J',
'S'
};
/**
* The row letters (for northing) of the lower left value, per set.
*/
public final static int[] SET_ORIGIN_ROW_LETTERS = {
'A',
'F',
'A',
'F',
'A',
'F'
};
/**
* The column letters (for easting) of the lower left value, per set,, for
* Bessel Ellipsoid.
*/
public final static int[] BESSEL_SET_ORIGIN_COLUMN_LETTERS = {
'A',
'J',
'S',
'A',
'J',
'S'
};
/**
* The row letters (for northing) of the lower left value, per set, for
* Bessel Ellipsoid.
*/
public final static int[] BESSEL_SET_ORIGIN_ROW_LETTERS = {
'L',
'R',
'L',
'R',
'L',
'R'
};
public final static int SET_NORTHING_ROLLOVER = 20000000;
/**
* Use 5 digits for northing and easting values, for 1 meter accuracy of
* coordinate.
*/
public final static int ACCURACY_1_METER = 5;
/**
* Use 4 digits for northing and easting values, for 10 meter accuracy of
* coordinate.
*/
public final static int ACCURACY_10_METER = 4;
/**
* Use 3 digits for northing and easting values, for 100 meter accuracy of
* coordinate.
*/
public final static int ACCURACY_100_METER = 3;
/**
* Use 2 digits for northing and easting values, for 1000 meter accuracy of
* coordinate.
*/
public final static int ACCURACY_1000_METER = 2;
/**
* Use 1 digits for northing and easting values, for 10000 meter accuracy of
* coordinate.
*/
public final static int ACCURACY_10000_METER = 1;
/** The set origin column letters to use. */
protected int[] originColumnLetters = SET_ORIGIN_COLUMN_LETTERS;
/** The set origin row letters to use. */
protected int[] originRowLetters = SET_ORIGIN_ROW_LETTERS;
public final static int A = 'A';
public final static int I = 'I';
public final static int O = 'O';
public final static int V = 'V';
public final static int Z = 'Z';
protected boolean DEBUG = false;
protected final static Logger logger = Logger.getLogger("com.bbn.openmap.proj.coords.MGRSPoint");
/** The String holding the MGRS coordinate value. */
protected String mgrs;
/**
* Controls the number of digits that the MGRS coordinate will have, which
* directly affects the accuracy of the coordinate. Default is
* ACCURACY_1_METER, which indicates that MGRS coordinates will have 10
* digits (5 easting, 5 northing) after the 100k two letter code, indicating
* 1 meter resolution.
*/
protected int accuracy = ACCURACY_1_METER;
/**
* Point to create if you are going to use the static methods to fill the
* values in.
*/
public MGRSPoint() {
DEBUG = logger.isLoggable(Level.FINE);
}
/**
* Constructs a new MGRS instance from a MGRS String, validating the string
* as a MGRS coordinate.
*/
public MGRSPoint(String mgrsString)
throws NumberFormatException {
this();
setMGRS(mgrsString);
}
/**
* Constructs a new MGRSPoint instance from values in another MGRSPoint.
*/
public MGRSPoint(MGRSPoint point) {
this();
mgrs = point.mgrs;
northing = point.northing;
easting = point.easting;
zone_number = point.zone_number;
zone_letter = point.zone_letter;
accuracy = point.accuracy;
}
/**
* Create a MGRSPoint from standard values.
*
* @param northing northing offset
* @param easting easting offset
* @param zoneNumber the MGRS zone number
* @param zoneLetter the MGRS zone letter.
*/
public MGRSPoint(double northing, double easting, int zoneNumber, char zoneLetter) {
super(northing, easting, zoneNumber, zoneLetter);
}
/**
* Construct a MGRSPoint from a LatLonPoint, assuming a WGS_84 ellipsoid.
*/
public MGRSPoint(LatLonPoint llpoint) {
this(llpoint, Ellipsoid.WGS_84);
}
/**
* Construct a MGRSPoint from a LatLonPoint and a particular ellipsoid.
*/
public MGRSPoint(LatLonPoint llpoint, Ellipsoid ellip) {
this();
LLtoMGRS(llpoint, ellip, this);
}
/**
* Set the MGRS value for this Point. Will be decoded, and the MGRS values
* figured out. You can call toLatLonPoint() to translate it to lat/lon
* decimal degrees.
*/
public void setMGRS(String mgrsString)
throws NumberFormatException {
try {
mgrs = mgrsString.toUpperCase(); // Just to make sure.
decode(mgrs);
} catch (StringIndexOutOfBoundsException sioobe) {
throw new NumberFormatException("MGRSPoint has bad string: " + mgrsString);
} catch (NullPointerException npe) {
// Blow off
}
}
/**
* Get the MGRS string value - the honkin' coordinate value.
*/
public String getMGRS() {
if (mgrs == null) {
resolve();
}
return mgrs;
}
/**
* Convert this MGRSPoint to a LatLonPoint, and assume a WGS_84 ellipsoid.
*/
public LatLonPoint toLatLonPoint() {
return toLatLonPoint(Ellipsoid.WGS_84, new LatLonPoint.Double());
}
/**
* Convert this MGRSPoint to a LatLonPoint, and use the given ellipsoid.
*/
public LatLonPoint toLatLonPoint(Ellipsoid ellip) {
return toLatLonPoint(ellip, new LatLonPoint.Double());
}
/**
* Fill in the given LatLonPoint with the converted values of this MGRSPoint,
* and use the given ellipsoid.
*/
public LatLonPoint toLatLonPoint(Ellipsoid ellip, LatLonPoint llpoint) {
return MGRStoLL(this, ellip, llpoint);
}
/**
* Returns a string representation of the object.
*
* @return String representation
*/
public String toString() {
return "MGRSPoint[" + mgrs + "]";
}
/**
* Create a LatLonPoint from a MGRSPoint.
*
* @param mgrsp to convert.
* @param ellip Ellipsoid for earth model.
* @param llp a LatLonPoint to fill in values for. If null, a new LatLonPoint
* will be returned. If not null, the new values will be set in this
* object, and it will be returned.
* @return LatLonPoint with values converted from MGRS coordinate.
*/
public static LatLonPoint MGRStoLL(MGRSPoint mgrsp, Ellipsoid ellip, LatLonPoint llp) {
return UTMtoLL(ellip, mgrsp.northing, mgrsp.easting, mgrsp.zone_number, MGRSPoint.MGRSZoneToUTMZone(mgrsp.zone_letter), llp);
}
/**
* Create a LatLonPoint from a MGRSPoint.
*
* @param ellip ellipsoid
* @param northing northing in meters
* @param easting easting in meters
* @param zoneNumber zone number for mgrs
* @param zoneLetter zone letter for mgrs
* @param llp LatLonPoint object to use for answer, ok if null.
* @return LatLonPoint from MGRSPoint
*/
public static LatLonPoint MGRStoLL(Ellipsoid ellip, double northing, double easting, int zoneNumber, char zoneLetter,
LatLonPoint llp) {
return UTMtoLL(ellip, northing, easting, zoneNumber, MGRSPoint.MGRSZoneToUTMZone(zoneLetter), llp);
}
/**
* Converts a LatLonPoint to a MGRS Point, assuming the WGS_84 ellipsoid.
*
* @return MGRSPoint, or null if something bad happened.
*/
public static MGRSPoint LLtoMGRS(LatLonPoint llpoint) {
return LLtoMGRS(llpoint, Ellipsoid.WGS_84, new MGRSPoint());
}
/**
* Converts a LatLonPoint to a MGRS Point.
*
* @param llpoint the LatLonPoint to convert.
* @param mgrsp a MGRSPoint to put the results in. If it's null, a MGRSPoint
* will be allocated.
* @return MGRSPoint, or null if something bad happened. If a MGRSPoint was
* passed in, it will also be returned on a successful conversion.
*/
public static MGRSPoint LLtoMGRS(LatLonPoint llpoint, MGRSPoint mgrsp) {
return LLtoMGRS(llpoint, Ellipsoid.WGS_84, mgrsp);
}
/**
* Create a MGRSPoint from a LatLonPoint.
*
* @param llp LatLonPoint to convert.
* @param ellip Ellipsoid for earth model.
* @param mgrsp a MGRSPoint to fill in values for. If null, a new MGRSPoint
* will be returned. If not null, the new values will be set in this
* object, and it will be returned.
* @return MGRSPoint with values converted from lat/lon.
*/
public static MGRSPoint LLtoMGRS(LatLonPoint llp, Ellipsoid ellip, MGRSPoint mgrsp) {
if (mgrsp == null || !(mgrsp instanceof MGRSPoint)) {
mgrsp = new MGRSPoint();
}
// Calling LLtoUTM here results in N/S zone letters! wrong!
mgrsp = (MGRSPoint) LLtoUTM(llp, ellip, mgrsp);
// Need to add this to set the right letter for the latitude.
mgrsp.zone_letter = mgrsp.getLetterDesignator(llp.getLatitude());
mgrsp.resolve();
return mgrsp;
}
/**
* Convert MGRS zone letter to UTM zone letter, N or S.
*
* @param mgrsZone
* @return N of given zone is equal or larger than N, S otherwise.
*/
public static char MGRSZoneToUTMZone(char mgrsZone) {
if (Character.toUpperCase(mgrsZone) >= 'N') {
return 'N';
} else {
return 'S';
}
}
/**
* Method that provides a check for MGRS zone letters. Returns an uppercase
* version of any valid letter passed in.
*/
protected char checkZone(char zone) {
zone = Character.toUpperCase(zone);
if (zone <= 'A' || zone == 'B' || zone == 'Y' || zone >= 'Z' || zone == 'I' || zone == 'O') {
throw new NumberFormatException("Invalid MGRSPoint zone letter: " + zone);
}
return zone;
}
/**
* Set the number of digits to use for easting and northing numbers in the
* mgrs string, which reflects the accuracy of the coordinate. From 5 (1
* meter) to 1 (10,000 meter).
*/
public void setAccuracy(int value) {
accuracy = value;
mgrs = null;
}
public int getAccuracy() {
return accuracy;
}
/**
* Set the MGRS parameters from a MGRS coordinate string.
*
* @param mgrsString an UPPERCASE coordinate string is expected.
*/
protected void decode(String mgrsString)
throws NumberFormatException {
if (mgrsString == null || mgrsString.length() == 0) {
throw new NumberFormatException("MGRSPoint coverting from nothing");
}
// Ensure an upper-case string
mgrsString = mgrsString.toUpperCase();
int length = mgrsString.length();
String hunK = null;
StringBuffer sb = new StringBuffer();
char testChar;
int i = 0;
// get Zone number
while (!Character.isLetter(testChar = mgrsString.charAt(i))) {
if (i >= 2) {
throw new NumberFormatException("MGRSPoint bad conversion from: " + mgrsString
+ ", first two characters need to be a number between 1-60.");
}
sb.append(testChar);
i++;
}
zone_number = Integer.parseInt(sb.toString());
if (zone_number < 1 || zone_number > 60) {
throw new NumberFormatException("MGRSPoint bad conversion from: " + mgrsString
+ ", first two characters need to be a number between 1-60.");
}
if (i == 0 || i + 3 > length) {
// A good MGRS string has to be 4-5 digits long,
// ##AAA/#AAA at least.
throw new NumberFormatException("MGRSPoint bad conversion from: " + mgrsString
+ ", MGRS string must be at least 4-5 digits long");
}
zone_letter = mgrsString.charAt(i++);
// Should we check the zone letter here? Why not.
if (zone_letter <= 'A' || zone_letter == 'B' || zone_letter == 'Y' || zone_letter >= 'Z' || zone_letter == 'I'
|| zone_letter == 'O') {
throw new NumberFormatException("MGRSPoint zone letter " + (char) zone_letter + " not handled: " + mgrsString);
}
hunK = mgrsString.substring(i, i += 2);
// Validate, check the zone, make sure each letter is between A-Z, not I
// or O
char char1 = hunK.charAt(0);
char char2 = hunK.charAt(1);
if (char1 < 'A' || char2 < 'A' || char1 > 'Z' || char2 > 'Z' || char1 == 'I' || char2 == 'I' || char1 == 'O' || char2 == 'O') {
throw new NumberFormatException("MGRSPoint bad conversion from " + mgrsString + ", invalid 100k designator");
}
int set = get100kSetForZone(zone_number);
float east100k = getEastingFromChar(char1, set);
float north100k = getNorthingFromChar(char2, set);
// We have a bug where the northing may be 2000000 too low.
// How do we know when to roll over?
while (north100k < getMinNorthing(zone_letter)) {
north100k += 2000000;
}
// calculate the char index for easting/northing separator
int remainder = length - i;
if (remainder % 2 != 0) {
throw new NumberFormatException(
"MGRSPoint has to have an even number \nof digits after the zone letter and two 100km letters - front \nhalf for easting meters, second half for \nnorthing meters"
+ mgrsString);
}
int sep = remainder / 2;
float sepEasting = 0f;
float sepNorthing = 0f;
if (sep > 0) {
if (DEBUG)
logger.fine(" calculating e/n from " + mgrs.substring(i));
float accuracyBonus = 100000f / (float) Math.pow(10, sep);
if (DEBUG)
logger.fine(" calculated accuracy bonus as " + accuracyBonus);
String sepEastingString = mgrsString.substring(i, i + sep);
if (DEBUG)
logger.fine(" parsed easting as " + sepEastingString);
sepEasting = Float.parseFloat(sepEastingString) * accuracyBonus;
String sepNorthingString = mgrsString.substring(i + sep);
if (DEBUG)
logger.fine(" parsed northing as " + sepNorthingString);
sepNorthing = Float.parseFloat(sepNorthingString) * accuracyBonus;
}
easting = sepEasting + east100k;
northing = sepNorthing + north100k;
if (DEBUG) {
logger.fine("Decoded " + mgrsString + " as zone number: " + zone_number + ", zone letter: " + zone_letter + ", easting: "
+ easting + ", northing: " + northing + ", 100k: " + hunK);
}
}
/**
* Create the mgrs string based on the internal MGRS parameter settings,
* should be called if the accuracy changes.
*
* @param digitAccuracy The number of digits to use for the northing and
* easting numbers. 5 digits reflect a 1 meter accuracy, 4 - 10 meter,
* 3 - 100 meter, 2 - 1000 meter, 1 - 10,000 meter.
*/
public void resolve(int digitAccuracy) {
setAccuracy(digitAccuracy);
resolve();
}
/**
* Create the mgrs string based on the internal MGRS parameter settings,
* using the accuracy set in the MGRSPoint.
*/
public void resolve() {
if (zone_letter == 'Z') {
mgrs = "Latitude limit exceeded";
} else {
StringBuffer sb =
new StringBuffer(Integer.toString(zone_number)).append(zone_letter)
.append(get100kID(easting, northing, zone_number));
StringBuffer seasting = new StringBuffer(Integer.toString((int) easting));
StringBuffer snorthing = new StringBuffer(Integer.toString((int) northing));
if (DEBUG) {
logger.fine(" Resolving MGRS from easting: " + seasting + " derived from " + easting + ", and northing: " + snorthing
+ " derived from " + northing);
}
while (accuracy + 1 > seasting.length()) {
seasting.insert(0, '0');
}
// We have to be careful here, the 100k values shouldn't
// be
// used for calculating stuff here.
while (accuracy + 1 > snorthing.length()) {
snorthing.insert(0, '0');
}
while (snorthing.length() > 6) {
snorthing.deleteCharAt(0);
}
if (DEBUG) {
logger.fine(" -- modified easting: " + seasting + " and northing: " + snorthing);
}
try {
sb.append(seasting.substring(1, accuracy + 1)).append(snorthing.substring(1, accuracy + 1));
mgrs = sb.toString();
} catch (IndexOutOfBoundsException ioobe) {
mgrs = null;
}
}
}
/**
* Given a MGRS/UTM zone number, figure out the MGRS 100K set it is in.
*/
protected int get100kSetForZone(int i) {
int set = i % NUM_100K_SETS;
if (set == 0)
set = NUM_100K_SETS;
return set;
}
/**
* Provided so that extensions to this class can provide different origin
* letters, in case of different ellipsoids. The int[] represents all of the
* first letters in the bottom left corner of each set box, as shown in an
* MGRS 100K box layout.
*/
protected int[] getOriginColumnLetters() {
return originColumnLetters;
}
/**
* Provided so that extensions to this class can provide different origin
* letters, in case of different ellipsoids. The int[] represents all of the
* first letters in the bottom left corner of each set box, as shown in an
* MGRS 100K box layout.
*/
protected void setOriginColumnLetters(int[] letters) {
originColumnLetters = letters;
}
/**
* Provided so that extensions to this class can provide different origin
* letters, in case of different ellipsoids. The int[] represents all of the
* second letters in the bottom left corner of each set box, as shown in an
* MGRS 100K box layout.
*/
protected int[] getOriginRowLetters() {
return originRowLetters;
}
/**
* Provided so that extensions to this class can provide different origin
* letters, in case of different ellipsoids. The int[] represents all of the
* second letters in the bottom left corner of each set box, as shown in an
* MGRS 100K box layout.
*/
protected void setOriginRowLetters(int[] letters) {
originRowLetters = letters;
}
/**
* Get the two letter 100k designator for a given MGRS/UTM easting, northing and
* zone number value.
*/
protected String get100kID(double easting, double northing, int zone_number) {
int set = get100kSetForZone(zone_number);
int setColumn = ((int) easting / 100000);
int setRow = ((int) northing / 100000) % 20;
return get100kID(setColumn, setRow, set);
}
/**
* Given the first letter from a two-letter MGRS 100k zone, and given the
* MGRS table set for the zone number, figure out the easting value that
* should be added to the other, secondary easting value.
*/
protected float getEastingFromChar(char e, int set) {
int baseCol[] = getOriginColumnLetters();
// colOrigin is the letter at the origin of the set for the
// column
int curCol = baseCol[set - 1];
float eastingValue = 100000f;
boolean rewindMarker = false;
while (curCol != e) {
curCol++;
if (curCol == I)
curCol++;
if (curCol == O)
curCol++;
if (curCol > Z) {
if (rewindMarker) {
throw new NumberFormatException("Bad character: " + e);
}
curCol = A;
rewindMarker = true;
}
eastingValue += 100000f;
}
if (DEBUG) {
logger.fine("Easting value for " + (char) e + " from set: " + set + ", col: " + curCol + " is " + eastingValue);
}
return eastingValue;
}
/**
* Given the second letter from a two-letter MGRS 100k zone, and given the
* MGRS table set for the zone number, figure out the northing value that
* should be added to the other, secondary northing value. You have to
* remember that Northings are determined from the equator, and the vertical
* cycle of letters mean a 2000000 additional northing meters. This happens
* approx. every 18 degrees of latitude. This method does *NOT* count any
* additional northings. You have to figure out how many 2000000 meters need
* to be added for the zone letter of the MGRS coordinate.
*
* @param n second letter of the MGRS 100k zone
* @param set the MGRS table set number, which is dependent on the MGRS/UTM zone
* number.
*/
protected float getNorthingFromChar(char n, int set) {
if (n > 'V') {
throw new NumberFormatException("MGRSPoint given invalid Northing " + n);
}
int baseRow[] = getOriginRowLetters();
// rowOrigin is the letter at the origin of the set for the
// column
int curRow = baseRow[set - 1];
float northingValue = 0f;
boolean rewindMarker = false;
while (curRow != n) {
curRow++;
if (curRow == I)
curRow++;
if (curRow == O)
curRow++;
// fixing a bug making whole application hang in this loop
// when 'n' is a wrong character
if (curRow > V) {
if (rewindMarker) { // making sure that this loop ends
throw new NumberFormatException("Bad character: " + n);
}
curRow = A;
rewindMarker = true;
}
northingValue += 100000f;
}
if (DEBUG) {
logger.fine("Northing value for " + (char) n + " from set: " + set + ", row: " + curRow + " is " + northingValue);
}
return northingValue;
}
/**
* Get the two-letter MGRS 100k designator given information translated from
* the MGRS/UTM northing, easting and zone number.
*
* @param setColumn the column index as it relates to the MGRS 100k set
* spreadsheet, created from the MGRS/UTM easting. Values are 1-8.
* @param setRow the row index as it relates to the MGRS 100k set
* spreadsheet, created from the MGRS/UTM northing value. Values are from
* 0-19.
* @param set the set block, as it relates to the MGRS 100k set spreadsheet,
* created from the MGRS/UTM zone. Values are from 1-60.
* @return two letter MGRS 100k code.
*/
protected String get100kID(int setColumn, int setRow, int set) {
if (DEBUG) {
System.out.println("set (" + set + ") column = " + setColumn + ", row = " + setRow);
}
int baseCol[] = getOriginColumnLetters();
int baseRow[] = getOriginRowLetters();
// colOrigin and rowOrigin are the letters at the origin of
// the set
int colOrigin = baseCol[set - 1];
int rowOrigin = baseRow[set - 1];
if (DEBUG) {
System.out.println("starting at = " + (char) colOrigin + (char) rowOrigin);
}
// colInt and rowInt are the letters to build to return
int colInt = colOrigin + setColumn - 1;
int rowInt = rowOrigin + setRow;
boolean rollover = false;
if (colInt > Z) {
colInt = colInt - Z + A - 1;
rollover = true;
if (DEBUG)
System.out.println("rolling over col, new value: " + (char) colInt);
}
if (colInt == I || (colOrigin < I && colInt > I) || ((colInt > I || colOrigin < I) && rollover)) {
colInt++;
if (DEBUG)
System.out.println("skipping I in col, new value: " + (char) colInt);
}
if (colInt == O || (colOrigin < O && colInt > O) || ((colInt > O || colOrigin < O) && rollover)) {
colInt++;
if (DEBUG)
System.out.println("skipping O in col, new value: " + (char) colInt);
if (colInt == I) {
colInt++;
if (DEBUG)
System.out.println(" hit I, new value: " + (char) colInt);
}
}
if (colInt > Z) {
colInt = colInt - Z + A - 1;
if (DEBUG)
System.out.println("rolling(2) col, new value: " + (char) rowInt);
}
if (rowInt > V) {
rowInt = rowInt - V + A - 1;
rollover = true;
if (DEBUG)
System.out.println("rolling over row, new value: " + (char) rowInt);
} else {
rollover = false;
}
if (rowInt == I || (rowOrigin < I && rowInt > I) || ((rowInt > I || rowOrigin < I) && rollover)) {
rowInt++;
if (DEBUG)
System.out.println("skipping I in row, new value: " + (char) rowInt);
}
if (rowInt == O || (rowOrigin < O && rowInt > O) || ((rowInt > O || rowOrigin < O) && rollover)) {
rowInt++;
if (DEBUG)
System.out.println("skipping O in row, new value: " + (char) rowInt);
if (rowInt == I) {
rowInt++;
if (DEBUG)
System.out.println(" hit I, new value: " + (char) rowInt);
}
}
if (rowInt > V) {
rowInt = rowInt - V + A - 1;
if (DEBUG)
System.out.println("rolling(2) row, new value: " + (char) rowInt);
}
String twoLetter = (char) colInt + "" + (char) rowInt;
if (DEBUG) {
System.out.println("ending at = " + twoLetter);
}
return twoLetter;
}
/**
* Testing method, used to print out the MGRS 100k two letter set tables.
*/
protected void print100kSets() {
StringBuffer sb = null;
for (int set = 1; set <= 6; set++) {
System.out.println("-------------\nFor 100K Set " + set + ":\n-------------\n");
for (int i = 19; i >= 0; i -= 1) {
sb = new StringBuffer(Integer.toString(i * 100000)).append("\t| ");
for (int j = 1; j <= 8; j++) {
sb.append(" ").append(get100kID(j, i, set));
}
sb.append(" |");
System.out.println(sb);
}
}
}
/**
* The function getMinNorthing returns the minimum northing value of a MGRS
* zone.
*
* portted from Geotrans' c Latitude_Band_Value structure table. zoneLetter :
* MGRS zone (input)
*/
protected float getMinNorthing(char zoneLetter)
throws NumberFormatException {
float northing;
switch (zoneLetter) {
case 'C':
northing = 1100000.0f;
break;
case 'D':
northing = 2000000.0f;
break;
case 'E':
northing = 2800000.0f;
break;
case 'F':
northing = 3700000.0f;
break;
case 'G':
northing = 4600000.0f;
break;
case 'H':
northing = 5500000.0f;
break;
case 'J':
northing = 6400000.0f;
break;
case 'K':
northing = 7300000.0f;
break;
case 'L':
northing = 8200000.0f;
break;
case 'M':
northing = 9100000.0f;
break;
case 'N':
northing = 0.0f;
break;
case 'P':
northing = 800000.0f;
break;
case 'Q':
northing = 1700000.0f;
break;
case 'R':
northing = 2600000.0f;
break;
case 'S':
northing = 3500000.0f;
break;
case 'T':
northing = 4400000.0f;
break;
case 'U':
northing = 5300000.0f;
break;
case 'V':
northing = 6200000.0f;
break;
case 'W':
northing = 7000000.0f;
break;
case 'X':
northing = 7900000.0f;
break;
default:
northing = -1.0f;
}
if (northing >= 0.0) {
return northing;
} else {
throw new NumberFormatException("Invalid zone letter: " + zone_letter);
}
}
private static void runTests(String fName, String inType) {
LineNumberReader lnr = null;
PrintStream pos = null;
String record = null;
StringBuffer outStr1 = new StringBuffer();
StringBuffer outStr2 = new StringBuffer();
try {
/*
* File inFile = new File(fName + ".dat"); File outFile = new
* File(fName + ".out"); FileInputStream fis = new
* FileInputStream(inFile); FileOutputStream fos = new
* FileOutputStream(outFile); BufferedInputStream bis = new
* BufferedInputStream(fis);
*/
pos = new PrintStream(new FileOutputStream(new File(fName + ".out")));
lnr = new LineNumberReader(new InputStreamReader(new BufferedInputStream(new FileInputStream(new File(fName)))));
if (inType.equalsIgnoreCase("MGRS")) {
outStr1.append("MGRS to LatLonPoint\n\tMGRS\t\tLatitude Longitude\n");
outStr2.append("MGRS to UTM\n\tMGRS\t\tZone Easting Northing\n");
} else if (inType.equalsIgnoreCase("UTM")) {
outStr1.append("UTM to LatLonPoint\n\tUTM\t\tLatitude Longitude\n");
outStr2.append("UTM to MGRS\n\tUTM\t\tMGRS\n");
} else if (inType.equalsIgnoreCase("LatLon")) {
outStr1.append("LatLonPoint to UTM\nLatitude Longitude\t\tZone Easting Northing \n");
outStr2.append("LatLonPoint to MGRS\nLatitude Longitude\t\tMGRS\n");
}
while ((record = lnr.readLine()) != null) {
if (inType.equalsIgnoreCase("MGRS")) {
try {
MGRSPoint mgrsp = new MGRSPoint(record);
record = record.trim();
mgrsp.decode(record);
outStr1.append(record).append(" is ").append(mgrsp.toLatLonPoint()).append("\n");
outStr2.append(record).append(" to UTM: ").append(mgrsp.zone_number).append(" ").append(mgrsp.easting)
.append(" ").append(mgrsp.northing).append("\n");
} catch (NumberFormatException nfe) {
logger.warning(nfe.getMessage());
}
} else if (inType.equalsIgnoreCase("UTM")) {
MGRSPoint mgrsp;
UTMPoint utmp;
float e, n;
int z;
char zl;
String tmp;
record = record.trim();
tmp = record.substring(0, 2);
z = Integer.parseInt(tmp);
tmp = record.substring(5, 11);
e = Float.parseFloat(tmp);
tmp = record.substring(12, 19);
n = Float.parseFloat(tmp);
zl = record.charAt(3);
utmp = new UTMPoint(n, e, z, zl);
LatLonPoint llp = utmp.toLatLonPoint();
mgrsp = LLtoMGRS(llp);
outStr1.append(record).append(" is ").append(llp).append(" back to ").append(LLtoUTM(llp)).append("\n");
outStr2.append(record).append(" is ").append(mgrsp).append("\n");
} else if (inType.equalsIgnoreCase("LatLon")) {
float lat, lon;
int index;
String tmp;
record = record.trim();
index = record.indexOf("\040");
if (index < 0) {
index = record.indexOf("\011");
}
tmp = record.substring(0, index);
lat = Float.parseFloat(tmp);
tmp = record.substring(index);
lon = Float.parseFloat(tmp);
LatLonPoint llp = new LatLonPoint.Double(lat, lon);
// UTMPoint utmp = LLtoUTM(llp);
MGRSPoint mgrsp = LLtoMGRS(llp);
outStr1.append(record).append(" to UTM: ").append(mgrsp.zone_number).append(" ").append(mgrsp.easting).append(" ")
.append(mgrsp.northing).append("\n");
outStr2.append(record).append(" -> ").append(mgrsp.mgrs).append("\n");
}
}
} catch (IOException e) {
// catch io errors from FileInputStream or readLine()
System.out.println("IO error: " + e.getMessage());
} finally {
if (pos != null) {
pos.print(outStr1.toString());
pos.print("\n");
pos.print(outStr2.toString());
pos.close();
}
// if the file opened okay, make sure we close it
if (lnr != null) {
try {
lnr.close();
} catch (IOException ioe) {
}
}
}
}
public static void main(String[] argv) {
Debug.init();
ArgParser ap = new ArgParser("MGRSPoint");
ap.add("mgrs", "Print Latitude and Longitude for MGRS value", 1);
ap.add("latlon", "Print MGRS for Latitude and Longitude values", 2, true);
ap.add("sets", "Print the MGRS 100k table");
ap.add("altsets", "Print the MGRS 100k table for the Bessel ellipsoid");
ap.add("rtc", "Run test case, with filename and input data type [MGRS | UTM | LatLon]", 2);
if (!ap.parse(argv)) {
ap.printUsage();
System.exit(0);
}
String arg[];
arg = ap.getArgValues("sets");
if (arg != null) {
new MGRSPoint().print100kSets();
}
arg = ap.getArgValues("altsets");
if (arg != null) {
MGRSPoint mgrsp = new MGRSPoint();
mgrsp.setOriginColumnLetters(BESSEL_SET_ORIGIN_COLUMN_LETTERS);
mgrsp.setOriginRowLetters(BESSEL_SET_ORIGIN_ROW_LETTERS);
mgrsp.print100kSets();
}
arg = ap.getArgValues("mgrs");
if (arg != null) {
try {
MGRSPoint mgrsp = new MGRSPoint(arg[0]);
Debug.output(arg[0] + " is " + mgrsp.toLatLonPoint());
} catch (NumberFormatException nfe) {
Debug.error(nfe.getMessage());
}
}
arg = ap.getArgValues("latlon");
if (arg != null) {
try {
float lat = Float.parseFloat(arg[0]);
float lon = Float.parseFloat(arg[1]);
LatLonPoint llp = new LatLonPoint.Double(lat, lon);
MGRSPoint mgrsp = LLtoMGRS(llp);
UTMPoint utmp = LLtoUTM(llp);
if (utmp.zone_letter == 'Z') {
Debug.output(llp + "to UTM: latitude limit exceeded.");
} else {
Debug.output(llp + " is " + utmp);
}
Debug.output(llp + " is " + mgrsp);
} catch (NumberFormatException nfe) {
Debug.error("The numbers provided: " + argv[0] + ", " + argv[1] + " aren't valid");
}
}
arg = ap.getArgValues("rtc");
if (arg != null) {
runTests(arg[0], arg[1]);
}
}
}