Home | History | Annotate | Download | only in navigation
      1 /*
      2  * To change this template, choose Tools | Templates
      3  * and open the template in the editor.
      4  */
      5 package jme3tools.navigation;
      6 
      7 import java.text.DecimalFormat;
      8 
      9 /**
     10  * Coordinate class. Used to store a coordinate in [DD]D MM.M format.
     11  *
     12  * @author Benjamin Jakobus (based on JMarine by Benjamin Jakobus and Cormac Gebruers)
     13  * @version 1.0
     14  * @since 1.0
     15  */
     16 public class Coordinate {
     17 
     18     /* the degree part of the position (+ N/E, -W/S) */
     19     private int deg;
     20 
     21     /* the decimals of a minute */
     22     private double minsDecMins;
     23 
     24     /* the coordinate as a decimal*/
     25     private double decCoordinate;
     26 
     27     /* whether this coordinate is a latitude or a longitude: : LAT==0, LONG==1  */
     28     private int coOrdinate;
     29 
     30     /* The minutes trailing decimal precision to use for positions */
     31     public static final int MINPRECISION = 4;
     32     /* The degrees trailing decimal precision to use for positions */
     33     public static final int DEGPRECISION = 7;
     34 
     35     /* typeDefs for coOrdinates */
     36     public static final int LAT = 0;
     37     public static final int LNG = 1;
     38 
     39     /* typeDefs for quadrant */
     40     public static final int E = 0;
     41     public static final int S = 1;
     42     public static final int W = 2;
     43     public static final int N = 3;
     44 
     45     /**
     46      * Constructor
     47      *
     48      * @param deg
     49      * @param minsDecMins
     50      * @param coOrdinate
     51      * @param quad
     52      * @throws InvalidPositionException
     53      * @since 1.0
     54      */
     55     public Coordinate(int deg, float minsDecMins, int coOrdinate,
     56             int quad) throws InvalidPositionException {
     57         buildCoOrdinate(deg, minsDecMins, coOrdinate, quad);
     58         if (verify()) {
     59         } else {
     60             throw new InvalidPositionException();
     61         }
     62     }
     63 
     64     /**
     65      * Constructor
     66      * @param decCoordinate
     67      * @param coOrdinate
     68      * @throws InvalidPositionException
     69      * @since 1.0
     70      */
     71     public Coordinate(double decCoordinate, int coOrdinate) throws InvalidPositionException {
     72         DecimalFormat form = new DecimalFormat("#.#######");
     73 
     74         this.decCoordinate = decCoordinate;
     75         this.coOrdinate = coOrdinate;
     76         if (verify()) {
     77             deg = new Float(decCoordinate).intValue();
     78             if (deg < 0) {
     79                 minsDecMins = Double.parseDouble(form.format((Math.abs(decCoordinate) - Math.abs(deg)) * 60));
     80             } else {
     81                 minsDecMins = Double.parseDouble(form.format((decCoordinate - deg) * 60));
     82             }
     83         } else {
     84             throw new InvalidPositionException();
     85         }
     86     }
     87 
     88     /**
     89      * This constructor takes a coordinate in the ALRS formats i.e
     90      * 3831.64'N for lat, and 2819.12'W for long
     91      * Note: ALRS positions are occasionally written with the decimal minutes
     92      * apostrophe in the 'wrong' place and with an non CP1252 compliant decimal character.
     93      * This issue has to be corrected in the source database
     94      * @param coOrdinate
     95      * @throws InvalidPositionException
     96      * @since 1.0
     97      */
     98     public Coordinate(String coOrdinate) throws InvalidPositionException {
     99         //firstly split it into its component parts and dispose of the unneeded characters
    100         String[] items = coOrdinate.split("");
    101         int deg = Integer.valueOf(items[0]);
    102 
    103         items = items[1].split("'");
    104         float minsDecMins = Float.valueOf(items[0]);
    105         char quad = items[1].charAt(0);
    106 
    107         switch (quad) {
    108             case 'N':
    109                 buildCoOrdinate(deg, minsDecMins, Coordinate.LAT, Coordinate.N);
    110                 break;
    111             case 'S':
    112                 buildCoOrdinate(deg, minsDecMins, Coordinate.LAT, Coordinate.S);
    113                 break;
    114             case 'E':
    115                 buildCoOrdinate(deg, minsDecMins, Coordinate.LNG, Coordinate.E);
    116                 break;
    117             case 'W':
    118                 buildCoOrdinate(deg, minsDecMins, Coordinate.LNG, Coordinate.W);
    119         }
    120         if (verify()) {
    121         } else {
    122             throw new InvalidPositionException();
    123         }
    124     }
    125 
    126     /**
    127      * Prints out a coordinate as a string
    128      * @return the coordinate in decimal format
    129      * @since 1.0
    130      */
    131     public String toStringDegMin() {
    132         String str = "";
    133         String quad = "";
    134         StringUtil su = new StringUtil();
    135         switch (coOrdinate) {
    136             case LAT:
    137                 if (decCoordinate >= 0) {
    138                     quad = "N";
    139                 } else {
    140                     quad = "S";
    141                 }
    142                 str = su.padNumZero(Math.abs(deg), 2);
    143                 str += "\u00b0" + su.padNumZero(Math.abs(minsDecMins), 2, MINPRECISION) + "'" + quad;
    144                 break;
    145             case LNG:
    146                 if (decCoordinate >= 0) {
    147                     quad = "E";
    148                 } else {
    149                     quad = "W";
    150                 }
    151                 str = su.padNumZero(Math.abs(deg), 3);
    152                 str += "\u00b0" + su.padNumZero(Math.abs(minsDecMins), 2, MINPRECISION) + "'" + quad;
    153                 break;
    154         }
    155         return str;
    156     }
    157 
    158     /**
    159      * Prints out a coordinate as a string
    160      * @return the coordinate in decimal format
    161      * @since 1.0
    162      */
    163     public String toStringDec() {
    164         StringUtil u = new StringUtil();
    165         switch (coOrdinate) {
    166             case LAT:
    167                 return u.padNumZero(decCoordinate, 2, DEGPRECISION);
    168             case LNG:
    169                 return u.padNumZero(decCoordinate, 3, DEGPRECISION);
    170         }
    171         return "error";
    172     }
    173 
    174     /**
    175      * Returns the coordinate's decimal value
    176      * @return float the decimal value of the coordinate
    177      * @since 1.0
    178      */
    179     public double decVal() {
    180         return decCoordinate;
    181     }
    182 
    183     /**
    184      * Determines whether a decimal position is valid
    185      * @return result of validity test
    186      * @since 1.0
    187      */
    188     private boolean verify() {
    189         switch (coOrdinate) {
    190             case LAT:
    191                 if (Math.abs(decCoordinate) > 90.0) {
    192                     return false;
    193                 }
    194                 break;
    195 
    196             case LNG:
    197                 if (Math.abs(decCoordinate) > 180) {
    198                     return false;
    199                 }
    200         }
    201         return true;
    202     }
    203 
    204     /**
    205      * Populate this object by parsing the arguments to the function
    206      * Placed here to allow multiple constructors to use it
    207      * @since 1.0
    208      */
    209     private void buildCoOrdinate(int deg, float minsDecMins, int coOrdinate,
    210             int quad) {
    211         NumUtil nu = new NumUtil();
    212 
    213         switch (coOrdinate) {
    214             case LAT:
    215                 switch (quad) {
    216                     case N:
    217                         this.deg = deg;
    218                         this.minsDecMins = minsDecMins;
    219                         this.coOrdinate = coOrdinate;
    220                         decCoordinate = nu.Round(this.deg + (float) this.minsDecMins / 60, Coordinate.MINPRECISION);
    221                         break;
    222 
    223                     case S:
    224                         this.deg = -deg;
    225                         this.minsDecMins = minsDecMins;
    226                         this.coOrdinate = coOrdinate;
    227                         decCoordinate = nu.Round(this.deg - ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
    228                 }
    229 
    230             case LNG:
    231                 switch (quad) {
    232                     case E:
    233                         this.deg = deg;
    234                         this.minsDecMins = minsDecMins;
    235                         this.coOrdinate = coOrdinate;
    236                         decCoordinate = nu.Round(this.deg + ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
    237                         break;
    238 
    239                     case W:
    240                         this.deg = -deg;
    241                         this.minsDecMins = minsDecMins;
    242                         this.coOrdinate = coOrdinate;
    243                         decCoordinate = nu.Round(this.deg - ((float) this.minsDecMins / 60), Coordinate.MINPRECISION);
    244                 }
    245         }
    246     }
    247 }
    248