/* * 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); } } } }