Java code for WGS84 to Google map position and back - java

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.

Related

How to get the correct distance covered in a location app?

I am trying to measure the distance a user has covered in my location app which uses google maps.
I want it to work real-time, i.e I don't know how long the journey will be, but I only want it to keep track of the distance the user has covered from the starting point to wherever he/she ends the journey.
I searched on stack overflow on how to do that and came across some code to calculate it for me. Howeverthe issue I have is this: The distance is recalculated even when I am not moving again.
And it also keeps increasing and decreasing sometimes while I am walking when it is only supposed to increase.
Here is the code:
private Location lastLocation;
private double distanceCovered = 0.0;
public static double distance(double lat1, double lat2, double lon1,
double lon2, double el1, double el2) {
final int R = 6371; // Radius of the earth
double latDistance = Math.toRadians(lat2 - lat1);
double lonDistance = Math.toRadians(lon2 - lon1);
double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2)
+ Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2))
* Math.sin(lonDistance / 2) * Math.sin(lonDistance / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double distance = R * c * 1000; // convert to meters
double height = el1 - el2;
distance = Math.pow(distance, 2) + Math.pow(height, 2);
return Math.sqrt(distance);
}
public static double distanceBetweenLocations(Location l1, Location l2) {
if(l1.hasAltitude() && l2.hasAltitude()) {
return distance(l1.getLatitude(), l2.getLatitude(), l1.getLongitude(), l2.getLongitude(), l1.getAltitude(), l2.getAltitude());
}
return l1.distanceTo(l2);
}
// I am now calling the method in my OnLocationChanged method
#Override
public void onLocationChanged(Location location) {
distanceCovered = distanceBetweenLocations(lastLocation,location);
customerStartATrip.setText("Distance Covered: "+distanceCovered);
lastLocation = location;
LatLng latLng = new LatLng(location.getLatitude(),location.getLongitude());
mMap.moveCamera(CameraUpdateFactory.newLatLng(latLng));
mMap.animateCamera(CameraUpdateFactory.zoomTo(19));
}
The distance can be 0.238784784 increases to 1.23899849 and then to 2.something and suddenly it can decrease back to 0.something while I am still walking.
I don't know if the method is in-correct or if it's only working on a straight distance.

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;
}

Location Manager

Can we use android location https://developer.android.com/reference/android/location/Location.html
inside the java standalone application. I have to find the distance between two lat/lng pairs. Now i am using
public double Haversine(double lat1,double lon1,double lat2,double lon2)
{
double R = 6372.8; // Earth Radius in Kilometers
double dLat = Deg2Rad(lat2 - lat1);
double dLon = Deg2Rad(lon2 - lon1);
double a = (Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Deg2Rad(lat1)) * Math.cos(Deg2Rad(lat2)) *
Math.sin(dLon / 2) * Math.sin(dLon / 2));
double c = (2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)));
double d = R * c;
// Return Distance in Kilometers
return d;
}
public double Deg2Rad( double deg) {
public double Deg2Rad( double deg) {
return (deg * Math.PI / 180);
}
But the above code gives the air distance. But i need roadway distance. Please help me out.. thanks in advance
You can do this using Directions API of Google Maps
https://developers.google.com/maps/documentation/directions/
Good example is : http://javapapers.com/android/draw-path-on-google-maps-android-api/
This is example of Distance API of Google Map, but you can refer to it and use Directions API in same way
You can use Google direction API for this. http://code.google.com/apis/maps/documentation/directions/
I think you will find this helpful
How To Calculate Distance Between Two Points in Driving Direction Mode in Android

ECEF to lla (lat,lon,alt) in 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.

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.

Categories

Resources