/*
* Copyright (c) 2009-2012 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* * Neither the name of 'jMonkeyEngine' nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
* TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package jme3tools.navigation;
import java.text.DecimalFormat;
/**
* Coordinate class. Used to store a coordinate in [DD]D MM.M format.
*
* @author Benjamin Jakobus (based on JMarine by Benjamin Jakobus and Cormac Gebruers)
* @version 1.0
* @since 1.0
*/
public class Coordinate {
/* the degree part of the position (+ N/E, -W/S) */
private int deg;
/* the decimals of a minute */
private double minsDecMins;
/* the coordinate as a decimal*/
private double decCoordinate;
/* whether this coordinate is a latitude or a longitude: : LAT==0, LONG==1 */
private int coOrdinate;
/* The minutes trailing decimal precision to use for positions */
public static final int MINPRECISION = 4;
/* The degrees trailing decimal precision to use for positions */
public static final int DEGPRECISION = 7;
/* typeDefs for coOrdinates */
public static final int LAT = 0;
public static final int LNG = 1;
/* typeDefs for quadrant */
public static final int E = 0;
public static final int S = 1;
public static final int W = 2;
public static final int N = 3;
/**
* Constructor
*
* @param deg
* @param minsDecMins
* @param coOrdinate
* @param quad
* @throws InvalidPositionException
* @since 1.0
*/
public Coordinate(int deg, float minsDecMins, int coOrdinate,
int quad) throws InvalidPositionException {
buildCoOrdinate(deg, minsDecMins, coOrdinate, quad);
if (verify()) {
} else {
throw new InvalidPositionException();
}
}
/**
* Constructor
* @param decCoordinate
* @param coOrdinate
* @throws InvalidPositionException
* @since 1.0
*/
public Coordinate(double decCoordinate, int coOrdinate) throws InvalidPositionException {
DecimalFormat form = new DecimalFormat("#.#######");
this.decCoordinate = decCoordinate;
this.coOrdinate = coOrdinate;
if (verify()) {
deg = new Float(decCoordinate).intValue();
if (deg < 0) {
minsDecMins = Double.parseDouble(form.format((Math.abs(decCoordinate) - Math.abs(deg)) * 60));
} else {
minsDecMins = Double.parseDouble(form.format((decCoordinate - deg) * 60));
}
} else {
throw new InvalidPositionException();
}
}
/**
* This constructor takes a coordinate in the ALRS formats i.e
* 38∞31.64'N for lat, and 28∞19.12'W for long
* Note: ALRS positions are occasionally written with the decimal minutes
* apostrophe in the 'wrong' place and with an non CP1252 compliant decimal character.
* This issue has to be corrected in the source database
* @param coOrdinate
* @throws InvalidPositionException
* @since 1.0
*/
public Coordinate(String coOrdinate) throws InvalidPositionException {
//firstly split it into its component parts and dispose of the unneeded characters
String[] items = coOrdinate.split("°");
int deg = Integer.valueOf(items[0]);
items = items[1].split("'");
float minsDecMins = Float.valueOf(items[0]);
char quad = items[1].charAt(0);
switch (quad) {
case 'N':
buildCoOrdinate(deg, minsDecMins, Coordinate.LAT, Coordinate.N);
break;
case 'S':
buildCoOrdinate(deg, minsDecMins, Coordinate.LAT, Coordinate.S);
break;
case 'E':
buildCoOrdinate(deg, minsDecMins, Coordinate.LNG, Coordinate.E);
break;
case 'W':
buildCoOrdinate(deg, minsDecMins, Coordinate.LNG, Coordinate.W);
}
if (verify()) {
} else {
throw new InvalidPositionException();
}
}
/**
* Prints out a coordinate as a string
* @return the coordinate in decimal format
* @since 1.0
*/
public String toStringDegMin() {
String str = "";
String quad = "";
StringUtil su = new StringUtil();
switch (coOrdinate) {
case LAT:
if (decCoordinate >= 0) {
quad = "N";
} else {
quad = "S";
}
str = su.padNumZero(Math.abs(deg), 2);
str += "\u00b0" + su.padNumZero(Math.abs(minsDecMins), 2, MINPRECISION) + "'" + quad;
break;
case LNG:
if (decCoordinate >= 0) {
quad = "E";
} else {
quad = "W";
}
str = su.padNumZero(Math.abs(deg), 3);
str += "\u00b0" + su.padNumZero(Math.abs(minsDecMins), 2, MINPRECISION) + "'" + quad;
break;
}
return str;
}
/**
* Prints out a coordinate as a string
* @return the coordinate in decimal format
* @since 1.0
*/
public String toStringDec() {
StringUtil u = new StringUtil();
switch (coOrdinate) {
case LAT:
return u.padNumZero(decCoordinate, 2, DEGPRECISION);
case LNG:
return u.padNumZero(decCoordinate, 3, DEGPRECISION);
}
return "error";
}
/**
* Returns the coordinate's decimal value
* @return float the decimal value of the coordinate
* @since 1.0
*/
public double decVal() {
return decCoordinate;
}
/**
* Determines whether a decimal position is valid
* @return result of validity test
* @since 1.0
*/
private boolean verify() {
switch (coOrdinate) {
case LAT:
if (Math.abs(decCoordinate) > 90.0) {
return false;
}
break;
case LNG:
if (Math.abs(decCoordinate) > 180) {
return false;
}
}
return true;
}
/**
* Populate this object by parsing the arguments to the function
* Placed here to allow multiple constructors to use it
* @since 1.0
*/
private void buildCoOrdinate(int deg, float minsDecMins, int coOrdinate,
int quad) {
NumUtil nu = new NumUtil();
switch (coOrdinate) {
case LAT:
switch (quad) {
case N:
this.deg = deg;
this.minsDecMins = minsDecMins;
this.coOrdinate = coOrdinate;
decCoordinate = nu.Round(this.deg + (float) this.minsDecMins / 60, Coordinate.MINPRECISION);
break;
case S:
this.deg = -deg;
this.minsDecMins = minsDecMins;
this.coOrdinate = coOrdinate;
decCoordinate = nu.Round(this.deg - ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
}
case LNG:
switch (quad) {
case E:
this.deg = deg;
this.minsDecMins = minsDecMins;
this.coOrdinate = coOrdinate;
decCoordinate = nu.Round(this.deg + ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
break;
case W:
this.deg = -deg;
this.minsDecMins = minsDecMins;
this.coOrdinate = coOrdinate;
decCoordinate = nu.Round(this.deg - ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
}
}
}
}