ECEF to lla (lat,lon,alt) in java - java

Ive looked through the posts in the site and haven't found my problem ...
as the head line says im trying to convert from ecef to lla .
I'm using this document : Conversion article
in the direct formula , not the iterate formula
and this site for result comparison : ECEF2LLA
Im developing in java so my code is as follows :
public static final double a = 6378137;
public static final double f = 1/298.257223563;
public static final double b = a*(1-f);
public static final double e = Math.sqrt((Math.pow(a, 2)-Math.pow(b, 2))/Math.pow(a, 2));
public static final double e2 = Math.sqrt((Math.pow(a, 2)-Math.pow(b, 2))/Math.pow(b, 2));
public static double[] ecef2lla(double x , double y , double z){
double[] lla = {0,0,0};
double lon,lat,height,N;
double p = Math.sqrt(Math.pow(x, 2)+Math.pow(y, 2));
double theta = Math.atan((z*a)/(p*b));
lon = Math.atan(y/x);
lon = lon*180/Math.PI;
lat = Math.atan(((z+Math.pow(e2, 2)*b*Math.pow(Math.sin(theta), 3))/((p-Math.pow(e,2)*a*Math.pow(Math.cos(theta), 3)))));
lat = (lat*180)/Math.PI;
N= a/(Math.sqrt(1-Math.pow(e*Math.sin(lat), 2)));
height = (p/Math.cos(theta)) - N;
lla[0] = lon;
lla[1] = lat;
lla[2] = height;
return lla;
}
I'm getting wrong height data.
I've tried to move to radians and degrees and what not .
Thank you in advance !

I found this post and was ready to use the "accepted answer" in part of my application but I decided to run a couple of tests first to validate the algorithm. I used sample data generated by an online conversion calculator (http://www.sysense.com/products/ecef_lla_converter/index.html). I got less than stellar results as shown by the output below.
-----Test 1---------
Inputs: -576793.17, -5376363.47, 3372298.51
Expected: 32.12345, -96.12345, 500.0
Actuals: 32.12306332822881, 83.87654999786477, 486.5472474489361
-----Test 2---------
Inputs: 2297292.91, 1016894.94, -5843939.62
Expected: -66.87654, 23.87654, 1000.0
Actuals: -66.876230479461, 23.87653991401422, 959.6879360172898
Then I reran the same tests using the code from the following post (https://gist.github.com/klucar/1536194) and got much better results as shown by the output below.
-----Test 1---------
Inputs: -576793.17, -5376363.47, 3372298.51
Expected: 32.12345, -96.12345, 500.0
Actuals: 32.12345004807767, -96.12345000213524, 499.997958839871
-----Test 2---------
Inputs: 2297292.91, 1016894.94, -5843939.62
Expected: -66.87654, 23.87654, 1000.0
Actuals: -66.87654001741278, 23.87653991401422, 999.9983866894618
I didn't take the time to find the error in the solution provided in the "accepted answer" but my suggested answer: Use this code...
/*
*
* ECEF - Earth Centered Earth Fixed
*
* LLA - Lat Lon Alt
*
* ported from matlab code at
* https://gist.github.com/1536054
* and
* https://gist.github.com/1536056
*/
// WGS84 ellipsoid constants
private final double a = 6378137; // radius
private final double e = 8.1819190842622e-2; // eccentricity
private final double asq = Math.pow(a,2);
private final double esq = Math.pow(e,2);
private double[] ecef2lla(double[] ecef){
double x = ecef[0];
double y = ecef[1];
double z = ecef[2];
double b = Math.sqrt( asq * (1-esq) );
double bsq = Math.pow(b,2);
double ep = Math.sqrt( (asq - bsq)/bsq);
double p = Math.sqrt( Math.pow(x,2) + Math.pow(y,2) );
double th = Math.atan2(a*z, b*p);
double lon = Math.atan2(y,x);
double lat = Math.atan2( (z + Math.pow(ep,2)*b*Math.pow(Math.sin(th),3) ), (p - esq*a*Math.pow(Math.cos(th),3)) );
double N = a/( Math.sqrt(1-esq*Math.pow(Math.sin(lat),2)) );
double alt = p / Math.cos(lat) - N;
// mod lat to 0-2pi
lon = lon % (2*Math.PI);
// correction for altitude near poles left out.
double[] ret = {lat, lon, alt};
return ret;
}

OK so i got this working.
The problem was a misplaced variable, so for the sake of our future here's the working JAVA implementation :
public static final double a = 6378137;
public static final double f = 0.0034;
public static final double b = 6.3568e6;
public static final double e = Math.sqrt((Math.pow(a, 2) - Math.pow(b, 2)) / Math.pow(a, 2));
public static final double e2 = Math.sqrt((Math.pow(a, 2) - Math.pow(b, 2)) / Math.pow(b, 2));
public static double[] ecef2lla(double x, double y, double z) {
double[] lla = { 0, 0, 0 };
double lan, lon, height, N , theta, p;
p = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
theta = Math.atan((z * a) / (p * b));
lon = Math.atan(y / x);
lat = Math.atan(((z + Math.pow(e2, 2) * b * Math.pow(Math.sin(theta), 3)) / ((p - Math.pow(e, 2) * a * Math.pow(Math.cos(theta), 3)))));
N = a / (Math.sqrt(1 - (Math.pow(e, 2) * Math.pow(Math.sin(lat), 2))));
double m = (p / Math.cos(lat));
height = m - N;
lon = lon * 180 / Math.PI;
lat = lat * 180 / Math.PI;
lla[0] = lat;
lla[1] = lon;
lla[2] = height;
return lla;
}
Note : The units for the ECEF X Y Z are in Meters !

If you are interested in using a published java library to convert between cartesian and geodetic coordinate systems, you can use the java orbit propagation library orekit.
While Orekit provides some advanced features, it is not very easy to dive into. To help get you started I've written a sample code does some conversions. My code is in Scala but it uses the java library, so it should still be helpful. See the example code here.

Related

False longitudinale when calculating a new gps point with bearing, distance and startpoint in china

I am using a function created on the basis of this website and it works good. but i am facing a problem as mention in the heading, that the calculation does not work in china.
https://www.movable-type.co.uk/scripts/latlong.html
Calculate the distance and bearing between two gps points:
GPS point 1: 40.0166447,116.3063929
GPS point 2: 40.016705900000005,116.30665250000001
Distance in Meter: 14.511659385475214
I then use the below funciton to calculate the middlepoint but in China, I get a false longitude:
False output of the new Point: 40.01693515930434,63.69358559958683
Please give me a tip or a solution. What have I forgotten?
public static double[] middlPoint(double bearing, double distance,
double lat, double lon) {
double[] ret = new double[2];
double R = 6371;
lat = Math.toRadians(lat);
lon = Math.toRadians(lon);
ret[0] = Math.asin(Math.sin(lat) * Math.cos(distance / R) +
Math.cos(lat) * Math.sin(distance / R) * Math.cos(bearing));
ret[1] = lon + Math.atan2(Math.sin(bearing) * Math.sin(distance / R)
* Math.cos(lat),Math.cos(distance / R) - Math.sin(lat) * Math.sin(ret[0]));
ret[0] = Math.toDegrees(ret[0]);
ret[1] = Math.toDegrees((ret[1] + 540) % 360 - 180);
return ret;
}

java interpolate between two gps points with a speed

I'm trying to come up with function that could fill in gps coordinates between two points every second. There are few posts about this here, but I couldn't find something complete. The closest answer I found was:
Interpolate between 2 GPS locations based on walking speed
I modified one of the answer using the bearing. However, it still doesn't seem to work. Especially I think the distance calculation is wrong. Could someone look at the code below and change?
Thank you!
import java.util.ArrayList;
public class Test {
double radius = 6371;
public Test() {
Location start = new Location(lat, lon);
Location end = new Location(lat, lon);
double speed = 1.39;
double distance = CalculateDistanceBetweenLocations(start, end);
double duration = distance / speed;
System.out.println(distance + ", " + speed + ", " + duration);
ArrayList<Location> locations = new ArrayList<Location>();
for (double i = 0; i < duration; i += 1.0) {
double bearing = CalculateBearing(start, end);
double distanceInKm = speed / 1000;
Location intermediaryLocation = CalculateDestinationLocation(start, bearing, distanceInKm);
locations.add(intermediaryLocation);
System.out.println(intermediaryLocation.latitude + ", " + intermediaryLocation.longitude);
start = intermediaryLocation;
}
}
double DegToRad(double deg) {
return (deg * Math.PI / 180);
}
double RadToDeg(double rad) {
return (rad * 180 / Math.PI);
}
double CalculateBearing(Location startPoint, Location endPoint) {
double lat1 = DegToRad(startPoint.latitude);
double lat2 = DegToRad(endPoint.latitude);
double deltaLon = DegToRad(endPoint.longitude - startPoint.longitude);
double y = Math.sin(deltaLon) * Math.cos(lat2);
double x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(deltaLon);
double bearing = Math.atan2(y, x);
return (RadToDeg(bearing) + 360) % 360;
}
Location CalculateDestinationLocation(Location point, double bearing, double distance) {
distance = distance / radius;
bearing = DegToRad(bearing);
double lat1 = DegToRad(point.latitude);
double lon1 = DegToRad(point.longitude);
double lat2 = Math
.asin(Math.sin(lat1) * Math.cos(distance) + Math.cos(lat1) * Math.sin(distance) * Math.cos(bearing));
double lon2 = lon1 + Math.atan2(Math.sin(bearing) * Math.sin(distance) * Math.cos(lat1),
Math.cos(distance) - Math.sin(lat1) * Math.sin(lat2));
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
return new Location(RadToDeg(lat2), RadToDeg(lon2));
}
double CalculateDistanceBetweenLocations(Location startPoint, Location endPoint) {
double lat1 = DegToRad(startPoint.latitude);
double lon1 = DegToRad(startPoint.longitude);
double lat2 = DegToRad(endPoint.latitude);
double lon2 = DegToRad(endPoint.longitude);
double deltaLat = lat2 - lat1;
double deltaLon = lon2 - lon1;
double a = Math.sin(deltaLat / 2) * Math.sin(deltaLat / 2)
+ Math.cos(lat1) * Math.cos(lat2) * Math.sin(deltaLon / 2) * Math.sin(deltaLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
return (radius * c);
}
public static void main(String[] args) {
new Test();
}
class Location {
public double latitude, longitude;
public Location(double lat, double lon) {
latitude = lat;
longitude = lon;
}
}
}
You have a typing error in line
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
It should be
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
Your method CalculateDistanceBetweenLocations contains an this line:
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - 1));
which is equivalent to
double c = 2 * Math.atan2(Math.sqrt(a), 0.0);
which means that the result of Math.atan2 is always pi, independent of the value of a as long as a is positive.
Therefore CalculateDistanceBetweenLocations always returns 20015.086796020572 independent of the input coordinates.

Not able to get perfect distance between two places

i have used Haversine for calculating distance between two location.
public static class Haversine {
static int Radius = 6371;
public static double haversine(double lat1, double lon1, double lat2,
double lon2) {
double dLat = Math.toRadians(lat2 - lat1);
double dLon = Math.toRadians(lon2 - lon1);
lat1 = Math.toRadians(lat1);
lat2 = Math.toRadians(lat2);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(Math.toRadians(lat1))
* Math.cos(Math.toRadians(lat2)) * Math.sin(dLon / 2)
* Math.sin(dLon / 2);
double c = 2 * Math.asin(Math.sqrt(a));
double valueResult = Radius * c;
double km = valueResult / 1;
DecimalFormat newFormat = new DecimalFormat("####");
int kmInDec = Integer.valueOf(newFormat.format(km));
double meter = valueResult % 1000;
int meterInDec = Integer.valueOf(newFormat.format(meter));
Log.i("Radius Value", "" + valueResult + " KM " + kmInDec
+ " Meter " + meterInDec);
return Radius * c;
/*double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1)* Math.cos(lat2);
double c = 2 * Math.asin(Math.sqrt(a));
return R * 2 * Math.asin(Math.sqrt(a));*/
}
}
From the above code i am not able to get exact distance between 2 location.
When i run the above mehtod then it shows 4.32 km from my two places but when i checked on the google map then it shows the 5.3 km .
i have also used Location.distanceBetween method still it shows the 4.32 km .
How can i get exact distance between location?
You can see this link.
Haversine and Location.distanceBetween method are both the origin to the point at which a line.
So, you can use http://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&sensor=false to get the real distance.
From Google official repository link
SphericalUtil
MathUtil
Usage
double distance = SphericalUtil.computeDistanceBetween(new LatLng(9.000,10.00), new LatLng(9.000,11.00));
The above method will returns the distance between two LatLngs, in meters. Or try this
private String getDistance(LatLng my_latlong,LatLng frnd_latlong){
Location l1=new Location("One");
l1.setLatitude(my_latlong.latitude);
l1.setLongitude(my_latlong.longitude);
Location l2=new Location("Two");
l2.setLatitude(frnd_latlong.latitude);
l2.setLongitude(frnd_latlong.longitude);
float distance=l1.distanceTo(l2);
String dist=distance+" M";
if(distance>1000.0f)
{
distance=distance/1000.0f;
dist=distance+" KM";
}
return dist;
}
or you can give a look at link

How to quickly calculate what points are within a given distance of my point

I have a large number of Longitude and Latitudes and I want to quickly find out which ones are within say a 5km radius of a certain Longitude Latitude.
Instead of using a datastructure (Which would be overkill), I should be able to perform n do products very quickly. I've just done something wrong and can't seem to see what.
I have been trying to implement this in Java:
final List<CoOrds> coOrds = Create20x20Grid();
// Determine point X (centre of earth)
final Vector2 X = new Vector2(0,0);
// My CoOrd I want to check
final double srclon = coOrds.get(0).getLongitude();
final double srclat = coOrds.get(0).getLatitude();
final Vector2 A = new Vector2(srclon, srclat, true);
final double brng = 0;
final double d = 5;
final double R = 6371.1;
double dist = 0;
dist = d / R; // convert dist to angular distance in radians
final double lat1 = Math.toRadians(srclat);
final double lon1 = Math.toRadians(srclon);
final double lat2 = Math.asin(Math.sin(lat1) * Math.cos(dist)+ Math.cos(lat1) * Math.sin(dist) * Math.cos(brng));
double lon2 = lon1 + Math.atan2(Math.sin(brng) * Math.sin(dist) * Math.cos(lat1),Math.cos(dist) - Math.sin(lat1) * Math.sin(lat2));
// normalise to -180..+180ยบ
lon2 = (lon2 + 3 * Math.PI) % (2 * Math.PI) - Math.PI;
//Create another point which is the distance is d away from your point
final Vector2 B = new Vector2(Math.toDegrees(lon2),Math.toDegrees(lat2), true);
// Create a vector from X->A
final Vector2 X_A = new Vector2((A.getX() - X.getX()),(A.getY() - X.getY()));
// Create a vector from X->B
final Vector2 X_B = new Vector2((B.getX() - X.getX()),(B.getY() - X.getY()));
// Normalize XA
final Vector2 nX_A = X_A.normalize();
// Normalize XB
final Vector2 nX_B = X_B.normalize();
// Calculate the Dot Product
final Double Alpha = nX_A.dot(nX_B);
int count = 0;
for (final CoOrds c : coOrds) {
final Vector2 P = c.getPosition();
final Vector2 X_P = new Vector2((P.getX() - X.getX()),(P.getY() - X.getY()));
final Vector2 nX_P = X_P.normalize());
final Double Beta = nX_A.dot(nX_P);
if (Beta < Alpha) {
System.out.println(count + " -- " + Beta + " : " + Alpha);
count++;
}
}
System.out.println("Number of CoOrds within Distance : " + count);
The new point P is correct as I've loaded it into Google Maps, but I am not entirely sure if I have the calculations correct.
I have created a custom Vector2 class, which stores the Longitude and Latitude. It also coverts them to Cartesian:
private void convertSphericalToCartesian(final double latitude, final double longitude) {
x = (earthRadius * Math.cos(latitude) * Math.cos(longitude)) ;
y = (earthRadius * Math.cos(latitude) * Math.sin(longitude)) ;
}
The Dot Product:
public double dot(final Vector2 v2) {
return ((getX() * v2.getX()) + (getY() * v2.getY()));
}
The Normalize:
public Vector2 normalize() {
final double num2 = (getX() * getX()) + (getY() * getY());
final double num = 1d / Math.sqrt(num2);
double a = x;
double b = y;
a *= num;
b *= num;
return new Vector2(a, b);
}
Any help with this would be really appreciated
I used this website: http://www.movable-type.co.uk/scripts/latlong.html
To help me calculate point B.
I used this website : http://rbrundritt.wordpress.com/2008/10/14/conversion-between-spherical-and-cartesian-coordinates-systems/
To help me transform Spherical CoOrdinates to Cartesian CoOrdinates.
Thanks
[EDIT]
The test case I am currently running is:
0-0-0
2-2-0
1-2-0
Where the above is a grid of 9 points. The point I am checking is "1". I expect it to return all the points "2". But it is returning all the points in the grid. I have manually checked the distances on Google Maps and it should only be returning the points "2".
Thanks
From the comments above, you're not sure if your formulae are accurate.
The first step is to figure that out.
Select a few well-known points on the globe (North Pole, South Pole, Greenwich UK, etc), and create a test case that invokes convertSphericaltoCartesian() with these coordinates. Check the results and see if they make any sense.

Java code for WGS84 to Google map position and back

Searching for some sample code for converting a point in WGS84 coordinate system to a map position in Google Maps (pixel position), also supporting zoom levels.
If the codes is well commented, then it can also be in some other language.
You can also point me to a open source Java project :)
Some resources found:
OpenLayer implementation.
JOSM project
Excellent Java Map Projection Library from JH LABS. This is a pure java PROJ.4 port. Does projection from WGS84 to meters. From there it's quite straightforward to convert meters to tile pixels.
Tile utility code in Java on mapki.com (great resource for google map developers)
Here are the functions in JavaSCript ... As extracted from OpenLayers
function toMercator (lon, lat) {
var x = lon * 20037508.34 / 180;
var y = Math.log(Math.tan((90 + lat) * Math.PI / 360)) / (Math.PI / 180);
y = y * 20037508.34 / 180;
return [x, y];
}
function inverseMercator (x, y) {
var lon = (x / 20037508.34) * 180;
var lat = (y / 20037508.34) * 180;
lat = 180/Math.PI * (2 * Math.atan(Math.exp(lat * Math.PI / 180)) - Math.PI / 2);
return [lon, lat];
}
Fairly straightforward to convert to Java
GeoTools has code to transform to and from about any coordinate system you could imagine, and among them also Google Map's. It's also open source. However, it should also be pointed out that GeoTools is a large library, so if you're looking something small, quick and easy, it's likely not the way to go.
I would highly recommend it though if you're going to do other GIS/coordinate transformations, etc. as well.
If you use GeoTools or something similar, you might also be interested in knowing that the Google Map coordinate system is called EPSG 3785.
I ported this to PHP - here's the code, if anyone would need it:
To mercator:
$lon = ($lon * 20037508.34) / 180;
$lat = log(tan((90 + $lat) * M_PI / 360)) / (M_PI / 180);
$lat = $lat * 20037508.34 / 180;
From mercator:
$lon = ($lon / 20037508.34) * 180;
$lat = ($lat / 20037508.34) * 180;
$lat = 180/M_PI * (2 * atan(exp($lat * M_PI / 180)) - M_PI / 2);
/*
* Utility functions to transform between wgs84 and google projection coordinates
* Derived from openmap http://openmap.bbn.com/
*/
public class MercatorTransform {
public final static double NORTH_POLE = 90.0;
public final static double SOUTH_POLE = -NORTH_POLE;
public final static double DATELINE = 180.0;
public final static double LON_RANGE = 360.0;
final public static transient double wgs84_earthEquatorialRadiusMeters_D = 6378137.0;
private static double latfac = wgs84_earthEquatorialRadiusMeters_D;
private static double lonfac = wgs84_earthEquatorialRadiusMeters_D;
final public static transient double HALF_PI_D = Math.PI / 2.0d;
/**
* Returns google projection coordinates from wgs84 lat,long coordinates
*/
public static double[] forward(double lat, double lon) {
lat = normalizeLatitude(lat);
lon = wrapLongitude(lon);
double latrad = Math.toRadians(lat);
double lonrad = Math.toRadians(lon);
double lat_m = latfac * Math.log(Math.tan(((latrad + HALF_PI_D) / 2d)));
double lon_m = lonfac * lonrad;
double[] x = { lon_m, lat_m };
return x;
}
/**
* Returns wgs84 lat,long coordinates from google projection coordinates
*/
public static float[] inverse(float lon_m, float lat_m) {
double latrad = (2d * Math.atan(Math.exp(lat_m / latfac))) - HALF_PI_D;
double lonrad = lon_m / lonfac;
double lat = Math.toDegrees(latrad);
double lon = Math.toDegrees(lonrad);
lat = normalizeLatitude(lat);
lon = wrapLongitude(lon);
float[] x = { (float) lat, (float) lon };
return x;
}
private static double wrapLongitude(double lon) {
if ((lon < -DATELINE) || (lon > DATELINE)) {
lon += DATELINE;
lon = lon % LON_RANGE;
lon = (lon < 0) ? DATELINE + lon : -DATELINE + lon;
}
return lon;
}
private static double normalizeLatitude(double lat) {
if (lat > NORTH_POLE) {
lat = NORTH_POLE;
}
if (lat < SOUTH_POLE) {
lat = SOUTH_POLE;
}
return lat;
}
}
Someone took the javascript code from Google Maps and ported it to python: gmerc.py
I've used this and it works great.

Categories

Resources