I have a table in MySQL db which two of it's columns are the latitude and the longitude of a given geo-point. it's defined as Float(2,6).
I want to select only the records within a specific radius from a given point.
I found the following code in Java, that checks the distance between to geo-points:
public class Location {
private int latitudeE6;
private int longitudeE6;
...
}
public static double CalculateDistance(Location StartP, Location EndP) {
double lat1 = StartP.getLatitudeE6()/1E6;
double lat2 = EndP.getLatitudeE6()/1E6;
double lon1 = StartP.getLongitudeE6()/1E6;
double lon2 = EndP.getLongitudeE6()/1E6;
double dLat = Math.toRadians(lat2-lat1);
double dLon = Math.toRadians(lon2-lon1);
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.atan2(Math.sqrt(a), Math.sqrt(1-a));
return earthradius * c;
}
Currently, I'm doing SELECT without the location, and then I go over the result set and checks if it's in the radius given. (in Java).
This is surely not the most elegant, efficient way of doing it.
Can you think of a better way ?
Here's a presentation that describes (I think) how to do what you're attempting to accomplish in MySQL: Geo/Spatial Search with MySQL
Related
I'm developing an Android application which receives a given address. I would like to only let the app run on the device, if the user is on that address, or closer to it.
Is that possible to do only with google maps api?
You could get the address and from the address get the latitude and longitude:
Geocoder coder = new Geocoder(this);
List<Address> address;
try {
address = coder.getFromLocationName(strAddress,5);
if (address == null) {
return null;
}
Address location = address.get(0);
location.getLatitude();
location.getLongitude();
}
And then compare it with your location:
if (distance(mylocation.latitude, mylocation.longitude, location.getLatitude(), location.getLongitude()) < 0.1) { // if distance < 0.1
// launch the activity
}else {
finish();
}
/** calculates the distance between two locations in MILES */
private double distance(double lat1, double lng1, double lat2, double lng2) {
double earthRadius = 3958.75; // in miles, change to 6371 for kilometers
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double sindLat = Math.sin(dLat / 2);
double sindLng = Math.sin(dLng / 2);
double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2)
* Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2));
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
return dist;
}
EDIT:
As #FelipeMosso was saying, you can also use distanceBetween that computes the approximate distance in meters between two locations or the distanceTo that gives you the distance between where you are at and the destination..
The GMSCore Locations API also has Geocoding, which allows you to detect the proximity of the device to one or more Geofence locations. You can use Maps to get the lat lng for an address.
This won't stop your app from running. A better solution is to start the app, then allow it to go into the background. When the user crosses a Geofence, put up a notification. When the user clicks the notification, bring up an Activity.
See Creating and Monitoring Geofences
I have entities in a simulation whose initial locations and paths are code using Java in decimal degrees. I need to scale the sensor radius (it's in nautical miles) and speed (nautical miles/hr) to match decimal degrees. The purpose is to visualize the sim in OpenMap and Google Earth.
I've seen How to convert Distance(miles) to degrees?, but the suggestions there don't work.
Any help is appreciated! I'm thinking it will involve using great circle distance formulas... but can't quite get it.
Ed Williams' Aviation Formula https://edwilliams.org/avform.htm is a good, and accessible, place to start. And I often reference http://movable-type.co.uk/scripts/latlong.html.
I am guessing that you need a vector of some sort (your question is a bit unclear).
What I use (in C, not Java) to calculate a fix-radial-distance is:
void polarToLatLong(double lat, double lon, double dist, double radial,
double *outlat, double *outlon) {
if (!dist) { // distance zero, so just return the point
*outlat = lat;
*outlon = lon;
}
else if (lat > 89.9999) { // North Pole singularity. Dist is in NM.
*outlat = 90 - dist / 60;
*outlon = fmod(radial + 180) - 180;
}
else { // normal case
double sinlat, coslon;
dist /= 3442; // = Earth's radius in nm (not WGS84!)
sinlat = Sin(lat) * cos(dist) + Cos(lat) * sin(dist) * Cos(radial);
*outlat = Arcsin(sinlat);
coslon = (cos(dist) - Sin(lat) * sinlat) / (Cos(lat) * Cos(*outlat));
*outlon = lon + (Sin(radial) >= 0 : -1 : 1) * Arccos(coslon);
}
}
In the above code Sin(), with an upper-case S, is just a wrapper of sin() for degrees:
#define CLAMP(a,x,b) MIN(MAX(a, x), b) // GTK+ GLib version slightly different
double Sin(double deg) {return sin(deg * (PI / 180));} // wrappers for degrees
double Cos(double deg) {return cos(deg * (PI / 180));}
double Arcsin(double x) {return asin(CLAMP(-1, x, 1)) * (180 / PI);}
double Arccos(double x) {return acos(CLAMP(-1, x, 1)) * (180 / PI);}
How to select between two point range in google map. EX: 50m or 100m
i'm use this code to calculate distance.
public class DistanceCalculator {
public static final double Radius = 6378.1;
public double CalculationByDistance(GeoPoint startp, GeoPoint endp) {
double lat1 = startp.getLatitudeE6()/1E6;
double lat2 = endp.getLatitudeE6()/1E6;
double lon1 = startp.getLongitudeE6()/1E6;
double lon2 = endp.getLongitudeE6()/1E6;
double dLat = Math.toRadians(lat2-lat1);
double dLon = Math.toRadians(lon2-lon1);
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.atan2(Math.sqrt(a), Math.sqrt(1-a));
return Radius * c;
}
}
MapViewController has a method called zoomToSpan(int, int). So all you need to do it find the center of the two points and then zoom to the span between them. Here is the documentation:
public void zoomToSpan(int latSpanE6,int lonSpanE6)
Attempts to adjust the zoom of the map so that the given span of latitude and longitude will be
displayed. Because the zoom can only achieve discrete levels, and
because the aspect ratio of the map may not match the ratio given, the
quality of the fit may vary. The only thing we guarantee is that,
after the zoom, at least one of the new latitude or the new longitude
will be within a factor of 2 from the corresponding parameter.
You try by calculating using the latittudes and longitudes by converting the degrees to distance (for instance from 1 degree lattitude to nautical mile).
I'm having a hard time wrapping my head around some Trigonometry. I am trying to deduce a destination latitude and longitude from a start lat and log and distance and bearing.
Fortunately, I found an amazing site which describes exactly the function I need:
http://www.movable-type.co.uk/scripts/latlong.html " Destination point given distance and bearing from start point "
I tried it in my java program but it is not working for me. I deployed it as the website said. Here is my code:
double dist = 150/6371;
double brng = Math.toRadians(90);
double lat1 = Math.toRadians(26.88288045572338);
double lon1 = Math.toRadians(75.78369140625);
double lat2 = Math.asin( Math.sin(lat1)*Math.cos(dist) + Math.cos(lat1)*Math.sin(dist)*Math.cos(brng) );
double a = Math.atan2(Math.sin(brng)*Math.sin(dist)*Math.cos(lat1), Math.cos(dist)-Math.sin(lat1)*Math.sin(lat2));
System.out.println("a = " + a);
double lon2 = lon1 + a;
lon2 = (lon2+ 3*Math.PI) % (2*Math.PI) - Math.PI;
System.out.println("Latitude = "+Math.toDegrees(lat2)+"\nLongitude = "+Math.toDegrees(lon2));
But it shows the output is:
a = 0.0
Latitude = 26.882880455723377
Longitude = 75.78369140625
I am not getting where i am doing the mistake. Please anybody can help me to find out the problem.
Thanx in Advance. :-)
Your problem is on your first line.
Try
double dist = 150.0 / 6371.0;
The reason is that 150/6371 gets calculated as 0, because it performs integer division (rather than floating point division). This is true even though the result is being stored in a double. You can force floating point division by making one of the two numbers a floating point literal.
if anyone needs a function that calculates point coordinates from other point moved by some distance, below is the working code. For me, it's just moving a point by some distance.
import static java.lang.Math.*;
void movePoint(double latitude, double longitude, double distanceInMetres, double bearing) {
double brngRad = toRadians(bearing);
double latRad = toRadians(latitude);
double lonRad = toRadians(longitude);
int earthRadiusInMetres = 6371000;
double distFrac = distanceInMetres / earthRadiusInMetres;
double latitudeResult = asin(sin(latRad) * cos(distFrac) + cos(latRad) * sin(distFrac) * cos(brngRad));
double a = atan2(sin(brngRad) * sin(distFrac) * cos(latRad), cos(distFrac) - sin(latRad) * sin(latitudeResult));
double longitudeResult = (lonRad + a + 3 * PI) % (2 * PI) - PI;
System.out.println("latitude: " + toDegrees(latitudeResult) + ", longitude: " + toDegrees(longitudeResult));
}
latitude, longitude - entry point coordinates
distanceInMetres - distance that you want to move the point by
bearing - an angle, direction towards which you want to move the point. 0 is towards the North, 90 - East, 180 - South, 270 - West. And all between, i.e. 45 is North East.
earthRadiusInMetres - Earth radius in metres.
You can change the radius to 6371 if you want to have the input in kilometres or to miles if you want to have input in miles.
I want to calculate the difference between two double values
for example : lat1=12.2345673 and lat2=12.2345672 . here i want result as 0.0000001. this much exactly i am not getting while calculate double res=Double.compare(lat1,lat2) in eclipse. it showing 0.0.
Please specify the exact formula to overcome this
Can u try the following code ,
double lat1=12.2345673;
double lat2=12.2345672;
double dif=lat1-lat2;
DecimalFormat df = new DecimalFormat("###.#######");
System.out.println("Diff Val : "+df.format(dif));
Output :
Diff Val : 0.0000001
You can use following method for calculating distance between two lat-long points.
/**
*
* #param lat1 Latitude of the First Location
* #param lng1 Logitude of the First Location
* #param lat2 Latitude of the Second Location
* #param lng2 Longitude of the Second Location
* #return distance between two lat-lon in float format
*/
public static float distFrom (float lat1, float lng1, float lat2, float lng2 )
{
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat2-lat1);
double dLng = Math.toRadians(lng2-lng1);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
int meterConversion = 1609;
return new Float(dist * meterConversion).floatValue();
}
Multiply both numbers by 10 million, then subtract, then divide by same would be one solution.
Turn it into an int.
When I work with Lat/Long values I usually work with 1E6 accuracy and store as an int.
I learned this pattern from the GeoPoint class in Google's Android Map library.
Looks like you need more than 1E6 though, so you might want to use higher accuracy and use long instead.
Use BigDecimal.