package com.papagiannis.tuberun.osref;
import java.util.ArrayList;
import uk.me.jstott.jcoord.LatLng;
import uk.me.jstott.jcoord.RefEll;
/**
* Class to represent an Ordnance Survey grid reference
*
* (c) 2006 Jonathan Stott
*
* Created on 11-02-2006
*
* @author Jonathan Stott
* @version 1.0
* @since 1.0
*/
public class OSRef {
/**
* Easting
*/
private double easting;
/**
* Northing
*/
private double northing;
/**
* Create a new Ordnance Survey grid reference.
*
* @param easting
* the easting in metres
* @param northing
* the northing in metres
* @since 1.0
*/
public OSRef(double easting, double northing) {
this.easting = easting;
this.northing = northing;
}
/**
* Return a String representation of this OSGB grid reference showing the
* easting and northing.
*
* @return a String represenation of this OSGB grid reference
* @since 1.0
*/
public String toString() {
return "(" + easting + ", " + northing + ")";
}
/**
* Convert this OSGB grid reference to a latitude/longitude pair using the
* OSGB36 datum. Note that, the LatLng object may need to be converted to the
* WGS84 datum depending on the application.
*
* @return a LatLng object representing this OSGB grid reference using the
* OSGB36 datum
* @since 1.0
*/
public LatLng toLatLng() {
//The ugly debug lines have been added as an explicit attempt to slow down
//the computation. They probably prevent JITing of the transformation code
//and therefore the code below doesn't break on the Galaxy S4.
double OSGB_F0 = 0.9996012717;
debug.add(Double.toString(OSGB_F0));
double N0 = -100000.0;
debug.add(Double.toString(N0));
double E0 = 400000.0;
debug.add(Double.toString(E0));
double phi0 = Math.toRadians(49.0);
debug.add(Double.toString(phi0));
double lambda0 = Math.toRadians(-2.0);
debug.add(Double.toString(lambda0));
double a = RefEll.AIRY_1830.getMaj();
debug.add(Double.toString(a));
double b = RefEll.AIRY_1830.getMin();
debug.add(Double.toString(b));
double eSquared = RefEll.AIRY_1830.getEcc();
debug.add(Double.toString(eSquared));
double phi = 0.0;
debug.add(Double.toString(phi));
double lambda = 0.0;
debug.add(Double.toString(lambda));
double E = this.easting;
debug.add(Double.toString(E));
double N = this.northing;
debug.add(Double.toString(N));
double n = (a - b) / (a + b);
debug.add(Double.toString(n));
double M = 0.0;
debug.add(Double.toString(M));
double phiPrime = ((N - N0) / (a * OSGB_F0)) + phi0;
debug.add(Double.toString(phiPrime));
do {
M =
(b * OSGB_F0)
* (((1 + n + ((5.0 / 4.0) * n * n) + ((5.0 / 4.0) * n * n * n)) * (phiPrime - phi0))
- (((3 * n) + (3 * n * n) + ((21.0 / 8.0) * n * n * n))
* Math.sin(phiPrime - phi0) * Math.cos(phiPrime + phi0))
+ ((((15.0 / 8.0) * n * n) + ((15.0 / 8.0) * n * n * n))
* Math.sin(2.0 * (phiPrime - phi0)) * Math
.cos(2.0 * (phiPrime + phi0))) - (((35.0 / 24.0) * n * n * n)
* Math.sin(3.0 * (phiPrime - phi0)) * Math
.cos(3.0 * (phiPrime + phi0))));
phiPrime += (N - N0 - M) / (a * OSGB_F0);
debug.add(Double.toString(phiPrime));
} while ((N - N0 - M) >= 0.001);
double v =
a * OSGB_F0
* Math.pow(1.0 - eSquared * Util.sinSquared(phiPrime), -0.5);
debug.add(Double.toString(v));
double rho =
a * OSGB_F0 * (1.0 - eSquared)
* Math.pow(1.0 - eSquared * Util.sinSquared(phiPrime), -1.5);
debug.add(Double.toString(rho));
double etaSquared = (v / rho) - 1.0;
debug.add(Double.toString(etaSquared));
double VII = Math.tan(phiPrime) / (2 * rho * v);
debug.add(Double.toString(VII));
double VIII =
(Math.tan(phiPrime) / (24.0 * rho * Math.pow(v, 3.0)))
* (5.0 + (3.0 * Util.tanSquared(phiPrime)) + etaSquared - (9.0 * Util
.tanSquared(phiPrime) * etaSquared));
debug.add(Double.toString(VIII));
double IX =
(Math.tan(phiPrime) / (720.0 * rho * Math.pow(v, 5.0)))
* (61.0 + (90.0 * Util.tanSquared(phiPrime)) + (45.0 * Util
.tanSquared(phiPrime) * Util.tanSquared(phiPrime)));
debug.add(Double.toString(IX));
double X = Util.sec(phiPrime) / v;
debug.add(Double.toString(X));
double XI =
(Util.sec(phiPrime) / (6.0 * v * v * v))
* ((v / rho) + (2 * Util.tanSquared(phiPrime)));
debug.add(Double.toString(XI));
double XII =
(Util.sec(phiPrime) / (120.0 * Math.pow(v, 5.0)))
* (5.0 + (28.0 * Util.tanSquared(phiPrime)) + (24.0 * Util
.tanSquared(phiPrime) * Util.tanSquared(phiPrime)));
debug.add(Double.toString(XII));
double XIIA =
(Util.sec(phiPrime) / (5040.0 * Math.pow(v, 7.0)))
* (61.0
+ (662.0 * Util.tanSquared(phiPrime))
+ (1320.0 * Util.tanSquared(phiPrime) * Util
.tanSquared(phiPrime)) + (720.0 * Util.tanSquared(phiPrime)
* Util.tanSquared(phiPrime) * Util.tanSquared(phiPrime)));
debug.add(Double.toString(XIIA));
phi =
phiPrime - (VII * Math.pow(E - E0, 2.0))
+ (VIII * Math.pow(E - E0, 4.0)) - (IX * Math.pow(E - E0, 6.0));
debug.add(Double.toString(phi));
lambda =
lambda0 + (X * (E - E0)) - (XI * Math.pow(E - E0, 3.0))
+ (XII * Math.pow(E - E0, 5.0)) - (XIIA * Math.pow(E - E0, 7.0));
debug.add(Double.toString(lambda));
return new LatLng(Math.toDegrees(phi), Math.toDegrees(lambda));
}
private ArrayList<String> debug=new ArrayList<String>();
public String getDebugString() {
StringBuilder sb=new StringBuilder();
for (String s: debug) sb.append(s + "|");
return sb.toString();
}
/**
* Get the easting.
*
* @return the easting in metres
* @since 1.0
*/
public double getEasting() {
return easting;
}
/**
* Get the northing.
*
* @return the northing in metres
* @since 1.0
*/
public double getNorthing() {
return northing;
}
}