content: /*
   * Author: Sami Salkosuo, sami.salkosuo@fi.ibm.com
   *
   * (c) Copyright IBM Corp. 2007
   */
  
  package com.ibm.util;
  
  import java.util.Hashtable;
  import java.util.Map;
  
  @SuppressWarnings("unused")
  public class CoordinateConversion {
  
      public static void main(String[] args) {
          CoordinateConversion cc = new CoordinateConversion();
          double[] coords = cc.utm2LatLon("29 0 302881.28125 704585.9375");
          System.out.println(coords[0] + "/" + coords[1]);
      }
  
      public CoordinateConversion() {
  
      }
  
      public double[] utm2LatLon(String UTM) {
          UTM2LatLon c = new UTM2LatLon();
          return c.convertUTMToLatLong(UTM);
      }
  
      public String latLon2UTM(double latitude, double longitude) {
          LatLon2UTM c = new LatLon2UTM();
          return c.convertLatLonToUTM(latitude, longitude);
  
      }
  
      private void validate(double latitude, double longitude) {
          if (latitude < -90.0 || latitude > 90.0 || longitude < -180.0
                  || longitude >= 180.0) {
              throw new IllegalArgumentException(
                      "Legal ranges: latitude [-90,90], longitude [-180,180).");
          }
  
      }
  
      public String latLon2MGRUTM(double latitude, double longitude) {
          LatLon2MGRUTM c = new LatLon2MGRUTM();
          return c.convertLatLonToMGRUTM(latitude, longitude);
  
      }
  
      public double[] mgrutm2LatLon(String MGRUTM) {
          MGRUTM2LatLon c = new MGRUTM2LatLon();
          return c.convertMGRUTMToLatLong(MGRUTM);
      }
  
      public double degreeToRadian(double degree) {
          return degree * Math.PI / 180;
      }
  
      public double radianToDegree(double radian) {
          return radian * 180 / Math.PI;
      }
  
      private double POW(double a, double b) {
          return Math.pow(a, b);
      }
  
      private double SIN(double value) {
          return Math.sin(value);
      }
  
      private double COS(double value) {
          return Math.cos(value);
      }
  
      private double TAN(double value) {
          return Math.tan(value);
      }
  
      private class LatLon2UTM {
          public String convertLatLonToUTM(double latitude, double longitude) {
              validate(latitude, longitude);
              String UTM = "";
  
              setVariables(latitude, longitude);
  
              String longZone = getLongZone(longitude);
              LatZones latZones = new LatZones();
              String latZone = latZones.getLatZone(latitude);
  
              double _easting = getEasting();
              double _northing = getNorthing(latitude);
  
              UTM = longZone + " " + latZone + " " + ((int) _easting) + " "
                      + ((int) _northing);
              // UTM = longZone + " " + latZone + " " +
              // decimalFormat.format(_easting) +
              // " "+ decimalFormat.format(_northing);
  
              return UTM;
  
          }
  
          protected void setVariables(double latitude, double longitude) {
              latitude = degreeToRadian(latitude);
              rho = equatorialRadius * (1 - e * e)
                      / POW(1 - POW(e * SIN(latitude), 2), 3 / 2.0);
  
              nu = equatorialRadius
                      / POW(1 - POW(e * SIN(latitude), 2), (1 / 2.0));
  
              double var1;
              if (longitude < 0.0) {
                  var1 = ((int) ((180 + longitude) / 6.0)) + 1;
              } else {
                  var1 = ((int) (longitude / 6)) + 31;
              }
              double var2 = (6 * var1) - 183;
              double var3 = longitude - var2;
              p = var3 * 3600 / 10000;
  
              S = A0 * latitude - B0 * SIN(2 * latitude) + C0 * SIN(4 * latitude)
                      - D0 * SIN(6 * latitude) + E0 * SIN(8 * latitude);
  
              K1 = S * k0;
              K2 = nu * SIN(latitude) * COS(latitude) * POW(sin1, 2) * k0
                      * (100000000) / 2;
              K3 = ((POW(sin1, 4) * nu * SIN(latitude) * Math.pow(COS(latitude),
                      3)) / 24)
                      * (5 - POW(TAN(latitude), 2) + 9 * e1sq
                              * POW(COS(latitude), 2) + 4 * POW(e1sq, 2)
                              * POW(COS(latitude), 4))
                      * k0
                      * (10000000000000000L);
  
              K4 = nu * COS(latitude) * sin1 * k0 * 10000;
  
              K5 = POW(sin1 * COS(latitude), 3)
                      * (nu / 6)
                      * (1 - POW(TAN(latitude), 2) + e1sq * POW(COS(latitude), 2))
                      * k0 * 1000000000000L;
  
              A6 = (POW(p * sin1, 6) * nu * SIN(latitude) * POW(COS(latitude), 5) / 720)
                      * (61 - 58 * POW(TAN(latitude), 2) + POW(TAN(latitude), 4)
                              + 270 * e1sq * POW(COS(latitude), 2) - 330 * e1sq
                              * POW(SIN(latitude), 2)) * k0 * (1E+24);
  
          }
  
          protected String getLongZone(double longitude) {
              double longZone = 0;
              if (longitude < 0.0) {
                  longZone = ((180.0 + longitude) / 6) + 1;
              } else {
                  longZone = (longitude / 6) + 31;
              }
              String val = String.valueOf((int) longZone);
              if (val.length() == 1) {
                  val = "0" + val;
              }
              return val;
          }
  
          protected double getNorthing(double latitude) {
              double northing = K1 + K2 * p * p + K3 * POW(p, 4);
              if (latitude < 0.0) {
                  northing = 10000000 + northing;
              }
              return northing;
          }
  
          protected double getEasting() {
              return 500000 + (K4 * p + K5 * POW(p, 3));
          }
  
          // Lat Lon to UTM variables
  
          // equatorial radius
          double equatorialRadius = 6378137;
  
          // polar radius
          double polarRadius = 6356752.314;
  
          // flattening
          double flattening = 0.00335281066474748;// (equatorialRadius-polarRadius)/equatorialRadius;
  
          // inverse flattening 1/flattening
          double inverseFlattening = 298.257223563;// 1/flattening;
  
          // Mean radius
          double rm = POW(equatorialRadius * polarRadius, 1 / 2.0);
  
          // scale factor
          double k0 = 0.9996;
  
          // eccentricity
          double e = Math.sqrt(1 - POW(polarRadius / equatorialRadius, 2));
  
          double e1sq = e * e / (1 - e * e);
  
          double n = (equatorialRadius - polarRadius)
                  / (equatorialRadius + polarRadius);
  
          // r curv 1
          double rho = 6368573.744;
  
          // r curv 2
          double nu = 6389236.914;
  
          // Calculate Meridional Arc Length
          // Meridional Arc
          double S = 5103266.421;
  
          double A0 = 6367449.146;
  
          double B0 = 16038.42955;
  
          double C0 = 16.83261333;
  
          double D0 = 0.021984404;
  
          double E0 = 0.000312705;
  
          // Calculation Constants
          // Delta Long
          double p = -0.483084;
  
          double sin1 = 4.84814E-06;
  
          // Coefficients for UTM Coordinates
          double K1 = 5101225.115;
  
          double K2 = 3750.291596;
  
          double K3 = 1.397608151;
  
          double K4 = 214839.3105;
  
          double K5 = -2.995382942;
  
          double A6 = -1.00541E-07;
  
      }
  
      private class LatLon2MGRUTM extends LatLon2UTM {
          public String convertLatLonToMGRUTM(double latitude, double longitude) {
              validate(latitude, longitude);
              String mgrUTM = "";
  
              setVariables(latitude, longitude);
  
              String longZone = getLongZone(longitude);
              LatZones latZones = new LatZones();
              String latZone = latZones.getLatZone(latitude);
  
              double _easting = getEasting();
              double _northing = getNorthing(latitude);
              Digraphs digraphs = new Digraphs();
              String digraph1 = digraphs.getDigraph1(Integer.parseInt(longZone),
                      _easting);
              String digraph2 = digraphs.getDigraph2(Integer.parseInt(longZone),
                      _northing);
  
              String easting = String.valueOf((int) _easting);
              if (easting.length() < 5) {
                  easting = "00000" + easting;
              }
              easting = easting.substring(easting.length() - 5);
  
              String northing;
              northing = String.valueOf((int) _northing);
              if (northing.length() < 5) {
                  northing = "0000" + northing;
              }
              northing = northing.substring(northing.length() - 5);
  
              mgrUTM = longZone + latZone + digraph1 + digraph2 + easting
                      + northing;
              return mgrUTM;
          }
      }
  
      private class MGRUTM2LatLon extends UTM2LatLon {
          public double[] convertMGRUTMToLatLong(String mgrutm) {
              double[] latlon = {
                      0.0, 0.0
              };
              // 02CNR0634657742
              int zone = Integer.parseInt(mgrutm.substring(0, 2));
              String latZone = mgrutm.substring(2, 3);
  
              String digraph1 = mgrutm.substring(3, 4);
              String digraph2 = mgrutm.substring(4, 5);
              easting = Double.parseDouble(mgrutm.substring(5, 10));
              northing = Double.parseDouble(mgrutm.substring(10, 15));
  
              LatZones lz = new LatZones();
              double latZoneDegree = lz.getLatZoneDegree(latZone);
  
              double a1 = latZoneDegree * 40000000 / 360.0;
              double a2 = 2000000 * Math.floor(a1 / 2000000.0);
  
              Digraphs digraphs = new Digraphs();
  
              double digraph2Index = digraphs.getDigraph2Index(digraph2);
  
              double startindexEquator = 1;
              if ((1 + zone % 2) == 1) {
                  startindexEquator = 6;
              }
  
              double a3 = a2 + (digraph2Index - startindexEquator) * 100000;
              if (a3 <= 0) {
                  a3 = 10000000 + a3;
              }
              northing = a3 + northing;
  
              zoneCM = -183 + 6 * zone;
              double digraph1Index = digraphs.getDigraph1Index(digraph1);
              int a5 = 1 + zone % 3;
              double[] a6 = {
                      16, 0, 8
              };
              double a7 = 100000 * (digraph1Index - a6[a5 - 1]);
              easting = easting + a7;
  
              setVariables();
  
              double latitude = 0;
              latitude = 180 * (phi1 - fact1 * (fact2 + fact3 + fact4)) / Math.PI;
  
              if (latZoneDegree < 0) {
                  latitude = 90 - latitude;
              }
  
              double d = _a2 * 180 / Math.PI;
              double longitude = zoneCM - d;
  
              if (getHemisphere(latZone).equals("S")) {
                  latitude = -latitude;
              }
  
              latlon[0] = latitude;
              latlon[1] = longitude;
              return latlon;
          }
      }
  
      private class UTM2LatLon {
          double easting;
  
          double northing;
  
          int zone;
  
          String southernHemisphere = "ACDEFGHJKLM";
  
          protected String getHemisphere(String latZone) {
              String hemisphere = "N";
              if (southernHemisphere.indexOf(latZone) > -1) {
                  hemisphere = "S";
              }
              return hemisphere;
          }
  
          public double[] convertUTMToLatLong(String UTM) {
              double[] latlon = {
                      0.0, 0.0
              };
              String[] utm = UTM.split(" ");
              zone = Integer.parseInt(utm[0]);
              String latZone = utm[1];
              easting = Double.parseDouble(utm[2]);
              northing = Double.parseDouble(utm[3]);
              String hemisphere = getHemisphere(latZone);
              double latitude = 0.0;
              double longitude = 0.0;
  
              if (hemisphere.equals("S")) {
                  northing = 10000000 - northing;
              }
              setVariables();
              latitude = 180 * (phi1 - fact1 * (fact2 + fact3 + fact4)) / Math.PI;
  
              if (zone > 0) {
                  zoneCM = 6 * zone - 183.0;
              } else {
                  zoneCM = 3.0;
  
              }
  
              longitude = zoneCM - _a3;
              if (hemisphere.equals("S")) {
                  latitude = -latitude;
              }
  
              latlon[0] = latitude;
              latlon[1] = longitude;
              return latlon;
  
          }
  
          protected void setVariables() {
              arc = northing / k0;
              mu = arc
                      / (a * (1 - POW(e, 2) / 4.0 - 3 * POW(e, 4) / 64.0 - 5 * POW(
                              e, 6) / 256.0));
  
              ei = (1 - POW((1 - e * e), (1 / 2.0)))
                      / (1 + POW((1 - e * e), (1 / 2.0)));
  
              ca = 3 * ei / 2 - 27 * POW(ei, 3) / 32.0;
  
              cb = 21 * POW(ei, 2) / 16 - 55 * POW(ei, 4) / 32;
              cc = 151 * POW(ei, 3) / 96;
              cd = 1097 * POW(ei, 4) / 512;
              phi1 = mu + ca * SIN(2 * mu) + cb * SIN(4 * mu) + cc * SIN(6 * mu)
                      + cd * SIN(8 * mu);
  
              n0 = a / POW((1 - POW((e * SIN(phi1)), 2)), (1 / 2.0));
  
              r0 = a * (1 - e * e)
                      / POW((1 - POW((e * SIN(phi1)), 2)), (3 / 2.0));
              fact1 = n0 * TAN(phi1) / r0;
  
              _a1 = 500000 - easting;
              dd0 = _a1 / (n0 * k0);
              fact2 = dd0 * dd0 / 2;
  
              t0 = POW(TAN(phi1), 2);
              Q0 = e1sq * POW(COS(phi1), 2);
              fact3 = (5 + 3 * t0 + 10 * Q0 - 4 * Q0 * Q0 - 9 * e1sq)
                      * POW(dd0, 4) / 24;
  
              fact4 = (61 + 90 * t0 + 298 * Q0 + 45 * t0 * t0 - 252 * e1sq - 3
                      * Q0 * Q0)
                      * POW(dd0, 6) / 720;
  
              //
              lof1 = _a1 / (n0 * k0);
              lof2 = (1 + 2 * t0 + Q0) * POW(dd0, 3) / 6.0;
              lof3 = (5 - 2 * Q0 + 28 * t0 - 3 * POW(Q0, 2) + 8 * e1sq + 24 * POW(
                      t0, 2)) * POW(dd0, 5) / 120;
              _a2 = (lof1 - lof2 + lof3) / COS(phi1);
              _a3 = _a2 * 180 / Math.PI;
  
          }
  
          double arc;
  
          double mu;
  
          double ei;
  
          double ca;
  
          double cb;
  
          double cc;
  
          double cd;
  
          double n0;
  
          double r0;
  
          double _a1;
  
          double dd0;
  
          double t0;
  
          double Q0;
  
          double lof1;
  
          double lof2;
  
          double lof3;
  
          double _a2;
  
          double phi1;
  
          double fact1;
  
          double fact2;
  
          double fact3;
  
          double fact4;
  
          double zoneCM;
  
          double _a3;
  
          double b = 6356752.314;
  
          double a = 6378137;
  
          double e = 0.081819191;
  
          double e1sq = 0.006739497;
  
          double k0 = 0.9996;
  
      }
  
      private class Digraphs {
          private Map<Integer, String> digraph1 = new Hashtable<Integer, String>();
  
          private Map<Integer, String> digraph2 = new Hashtable<Integer, String>();
  
          private String[] digraph1Array = {
                  "A", "B", "C", "D", "E", "F", "G",
                  "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T", "U",
                  "V", "W", "X", "Y", "Z"
          };
  
          private String[] digraph2Array = {
                  "V", "A", "B", "C", "D", "E", "F",
                  "G", "H", "J", "K", "L", "M", "N", "P", "Q", "R", "S", "T",
                  "U", "V"
          };
  
          public Digraphs() {
              digraph1.put(new Integer(1), "A");
              digraph1.put(new Integer(2), "B");
              digraph1.put(new Integer(3), "C");
              digraph1.put(new Integer(4), "D");
              digraph1.put(new Integer(5), "E");
              digraph1.put(new Integer(6), "F");
              digraph1.put(new Integer(7), "G");
              digraph1.put(new Integer(8), "H");
              digraph1.put(new Integer(9), "J");
              digraph1.put(new Integer(10), "K");
              digraph1.put(new Integer(11), "L");
              digraph1.put(new Integer(12), "M");
              digraph1.put(new Integer(13), "N");
              digraph1.put(new Integer(14), "P");
              digraph1.put(new Integer(15), "Q");
              digraph1.put(new Integer(16), "R");
              digraph1.put(new Integer(17), "S");
              digraph1.put(new Integer(18), "T");
              digraph1.put(new Integer(19), "U");
              digraph1.put(new Integer(20), "V");
              digraph1.put(new Integer(21), "W");
              digraph1.put(new Integer(22), "X");
              digraph1.put(new Integer(23), "Y");
              digraph1.put(new Integer(24), "Z");
  
              digraph2.put(new Integer(0), "V");
              digraph2.put(new Integer(1), "A");
              digraph2.put(new Integer(2), "B");
              digraph2.put(new Integer(3), "C");
              digraph2.put(new Integer(4), "D");
              digraph2.put(new Integer(5), "E");
              digraph2.put(new Integer(6), "F");
              digraph2.put(new Integer(7), "G");
              digraph2.put(new Integer(8), "H");
              digraph2.put(new Integer(9), "J");
              digraph2.put(new Integer(10), "K");
              digraph2.put(new Integer(11), "L");
              digraph2.put(new Integer(12), "M");
              digraph2.put(new Integer(13), "N");
              digraph2.put(new Integer(14), "P");
              digraph2.put(new Integer(15), "Q");
              digraph2.put(new Integer(16), "R");
              digraph2.put(new Integer(17), "S");
              digraph2.put(new Integer(18), "T");
              digraph2.put(new Integer(19), "U");
              digraph2.put(new Integer(20), "V");
  
          }
  
          public int getDigraph1Index(String letter) {
              for (int i = 0; i < digraph1Array.length; i++) {
                  if (digraph1Array[i].equals(letter)) {
                      return i + 1;
                  }
              }
  
              return -1;
          }
  
          public int getDigraph2Index(String letter) {
              for (int i = 0; i < digraph2Array.length; i++) {
                  if (digraph2Array[i].equals(letter)) {
                      return i;
                  }
              }
  
              return -1;
          }
  
          public String getDigraph1(int longZone, double easting) {
              int a1 = longZone;
              double a2 = 8 * ((a1 - 1) % 3) + 1;
  
              double a3 = easting;
              double a4 = a2 + ((int) (a3 / 100000)) - 1;
              return (String) digraph1.get(new Integer((int) Math.floor(a4)));
          }
  
          public String getDigraph2(int longZone, double northing) {
              int a1 = longZone;
              double a2 = 1 + 5 * ((a1 - 1) % 2);
              double a3 = northing;
              double a4 = (a2 + ((int) (a3 / 100000)));
              a4 = (a2 + ((int) (a3 / 100000.0))) % 20;
              a4 = Math.floor(a4);
              if (a4 < 0) {
                  a4 = a4 + 19;
              }
              return (String) digraph2.get(new Integer((int) Math.floor(a4)));
  
          }
  
      }
  
      private class LatZones {
          private char[] letters = {
                  'A', 'C', 'D', 'E', 'F', 'G', 'H', 'J', 'K',
                  'L', 'M', 'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Z'
          };
  
          private int[] degrees = {
                  -90, -84, -72, -64, -56, -48, -40, -32, -24,
                  -16, -8, 0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 84
          };
  
          private char[] negLetters = {
                  'A', 'C', 'D', 'E', 'F', 'G', 'H', 'J',
                  'K', 'L', 'M'
          };
  
          private int[] negDegrees = {
                  -90, -84, -72, -64, -56, -48, -40, -32,
                  -24, -16, -8
          };
  
          private char[] posLetters = {
                  'N', 'P', 'Q', 'R', 'S', 'T', 'U', 'V',
                  'W', 'X', 'Z'
          };
  
          private int[] posDegrees = {
                  0, 8, 16, 24, 32, 40, 48, 56, 64, 72, 84
          };
  
          private int arrayLength = 22;
  
          public LatZones() {
          }
  
          public int getLatZoneDegree(String letter) {
              char ltr = letter.charAt(0);
              for (int i = 0; i < arrayLength; i++) {
                  if (letters[i] == ltr) {
                      return degrees[i];
                  }
              }
              return -100;
          }
  
          public String getLatZone(double latitude) {
              int latIndex = -2;
              int lat = (int) latitude;
  
              if (lat >= 0) {
                  int len = posLetters.length;
                  for (int i = 0; i < len; i++) {
                      if (lat == posDegrees[i]) {
                          latIndex = i;
                          break;
                      }
  
                      if (lat > posDegrees[i]) {
                          continue;
                      } else {
                          latIndex = i - 1;
                          break;
                      }
                  }
              } else {
                  int len = negLetters.length;
                  for (int i = 0; i < len; i++) {
                      if (lat == negDegrees[i]) {
                          latIndex = i;
                          break;
                      }
  
                      if (lat < negDegrees[i]) {
                          latIndex = i - 1;
                          break;
                      } else {
                          continue;
                      }
                  }
              }
  
              if (latIndex == -1) {
                  latIndex = 0;
              }
              if (lat >= 0) {
                  if (latIndex == -2) {
                      latIndex = posLetters.length - 1;
                  }
                  return String.valueOf(posLetters[latIndex]);
              } else {
                  if (latIndex == -2) {
                      latIndex = negLetters.length - 1;
                  }
                  return String.valueOf(negLetters[latIndex]);
              }
          }
      }
  }
  