/* * Copyright 2010 Bizosys Technologies Limited * * Licensed to the Bizosys Technologies Limited (Bizosys) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The Bizosys licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.bizosys.hsearch.util; /** * It supports Nothing-Eastering and Latitude-Longitude coordinate systems. * It provides machanism to convert values from one system to another. * @author karan * */ public class CoordinateConversion { public CoordinateConversion() { } public float[] utm2LatLon(GeoId UTM) { UTM2LatLon c = new UTM2LatLon(); return c.convertUTMToLatLong(UTM); } public GeoId 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 double degreeToRadian(double degree) { return degree * Math.PI / 180; } public double radianToDegree(double radian) { return radian * 180 / Math.PI; } private class LatLon2UTM { public GeoId convertLatLonToUTM(double latitude, double longitude) { validate(latitude, longitude); setVariables(latitude, longitude); int longZone = getLongZone(longitude); LatZones latZones = new LatZones(); char latZone = latZones.getLatZone(latitude); double _easting = getEasting(); double _northing = getNorthing(latitude); GeoId geoId = new GeoId(latZone, longZone, (int) _northing, (int) _easting); return geoId; } protected void setVariables(double latitude, double longitude) { latitude = degreeToRadian(latitude); rho = equatorialRadius * (1 - e * e) / Math .pow(1 - Math.pow(e * Math.sin(latitude), 2), 3 / 2.0); nu = equatorialRadius / Math.pow(1 - Math.pow(e * Math.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 * Math.sin(2 * latitude) + C0 * Math.sin(4 * latitude) - D0 * Math.sin(6 * latitude) + E0 * Math.sin(8 * latitude); K1 = S * k0; K2 = nu * Math.sin(latitude) * Math.cos(latitude) * Math.pow(sin1, 2) * k0 * (100000000) / 2; K3 = ((Math.pow(sin1, 4) * nu * Math.sin(latitude) * Math.pow(Math .cos(latitude), 3)) / 24) * (5 - Math.pow(Math.tan(latitude), 2) + 9 * e1sq * Math.pow(Math.cos(latitude), 2) + 4 * Math.pow(e1sq, 2) * Math.pow(Math.cos(latitude), 4)) * k0 * (10000000000000000L); K4 = nu * Math.cos(latitude) * sin1 * k0 * 10000; K5 = Math.pow(sin1 * Math.cos(latitude), 3) * (nu / 6) * (1 - Math.pow(Math.tan(latitude), 2) + e1sq * Math.pow(Math.cos(latitude), 2)) * k0 * 1000000000000L; A6 = (Math.pow(p * sin1, 6) * nu * Math.sin(latitude) * Math.pow(Math.cos(latitude), 5) / 720) * (61 - 58 * Math.pow(Math.tan(latitude), 2) + Math.pow(Math.tan(latitude), 4) + 270 * e1sq * Math.pow(Math.cos(latitude), 2) - 330 * e1sq * Math.pow(Math.sin(latitude), 2)) * k0 * (1E+24); } protected int getLongZone(double longitude) { double longZone = 0; if (longitude < 0.0) { longZone = ((180.0 + longitude) / 6) + 1; } else { longZone = (longitude / 6) + 31; } return (int) longZone; } protected double getNorthing(double latitude) { double northing = K1 + K2 * p * p + K3 * Math.pow(p, 4); if (latitude < 0.0) { northing = 10000000 + northing; } return northing; } protected double getEasting() { return 500000 + (K4 * p + K5 * Math.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 = Math.pow(equatorialRadius * polarRadius, 1 / 2.0); // scale factor double k0 = 0.9996; // eccentricity double e = Math.sqrt(1 - Math.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 UTM2LatLon { double easting; double northing; int zone; String southernHemisphere = "ACDEFGHJKLM"; protected char getHemisphere(char latZone) { char hemisphere = 'N'; if (southernHemisphere.indexOf(latZone) > -1) { hemisphere = 'S'; } return hemisphere; } public float[] convertUTMToLatLong(GeoId utm) { float[] latlon = { 0.0f, 0.0f }; zone = utm.longZone; char latZone = utm.latZone; easting = utm.getEasteringInMeters() ; northing = utm.getNorthingInMeters(); char hemisphere = getHemisphere(latZone); float latitude = 0.0f; float longitude = 0.0f; if (hemisphere == 'S') { northing = 10000000 - northing; } setVariables(); latitude = (float) (180 * (phi1 - fact1 * (fact2 + fact3 + fact4)) / Math.PI); if (zone > 0) { zoneCM = 6 * zone - 183.0; } else { zoneCM = 3.0; } longitude = (float) (zoneCM - _a3); if (hemisphere == 'S') { latitude = -latitude; } latlon[0] = latitude; latlon[1] = longitude; return latlon; } protected void setVariables() { arc = northing / k0; mu = arc / (a * (1 - Math.pow(e, 2) / 4.0 - 3 * Math.pow(e, 4) / 64.0 - 5 * Math.pow(e, 6) / 256.0)); ei = (1 - Math.pow((1 - e * e), (1 / 2.0))) / (1 + Math.pow((1 - e * e), (1 / 2.0))); ca = 3 * ei / 2 - 27 * Math.pow(ei, 3) / 32.0; cb = 21 * Math.pow(ei, 2) / 16 - 55 * Math.pow(ei, 4) / 32; cc = 151 * Math.pow(ei, 3) / 96; cd = 1097 * Math.pow(ei, 4) / 512; phi1 = mu + ca * Math.sin(2 * mu) + cb * Math.sin(4 * mu) + cc * Math.sin(6 * mu) + cd * Math.sin(8 * mu); n0 = a / Math.pow((1 - Math.pow((e * Math.sin(phi1)), 2)), (1 / 2.0)); r0 = a * (1 - e * e) / Math.pow((1 - Math.pow((e * Math.sin(phi1)), 2)), (3 / 2.0)); fact1 = n0 * Math.tan(phi1) / r0; _a1 = 500000 - easting; dd0 = _a1 / (n0 * k0); fact2 = dd0 * dd0 / 2; t0 = Math.pow(Math.tan(phi1), 2); Q0 = e1sq * Math.pow(Math.cos(phi1), 2); fact3 = (5 + 3 * t0 + 10 * Q0 - 4 * Q0 * Q0 - 9 * e1sq) * Math.pow(dd0, 4) / 24; fact4 = (61 + 90 * t0 + 298 * Q0 + 45 * t0 * t0 - 252 * e1sq - 3 * Q0 * Q0) * Math.pow(dd0, 6) / 720; // lof1 = _a1 / (n0 * k0); lof2 = (1 + 2 * t0 + Q0) * Math.pow(dd0, 3) / 6.0; lof3 = (5 - 2 * Q0 + 28 * t0 - 3 * Math.pow(Q0, 2) + 8 * e1sq + 24 * Math .pow(t0, 2)) * Math.pow(dd0, 5) / 120; _a2 = (lof1 - lof2 + lof3) / Math.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 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 char 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 posLetters[latIndex]; } else { if (latIndex == -2) { latIndex = negLetters.length - 1; } return negLetters[latIndex]; } } } }