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 */ Coordinate(int deg, float minsDecMins, int coOrdinate, int quad)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 */ Coordinate(double decCoordinate, int coOrdinate)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 * 38∞31.64'N for lat, and 28∞19.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 */ Coordinate(String coOrdinate)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 */ toStringDegMin()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 */ toStringDec()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 */ decVal()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 */ verify()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 */ buildCoOrdinate(int deg, float minsDecMins, int coOrdinate, int quad)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