I've been stuck on the problem. i'm searching for Tesco stores in this geocoder. Is there anyway way of getting only the closest result of the geo.getFromLocationName?
private void setUpMap() throws IOException {
Geocoder geo = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> addressList= geo.getFromLocationName("Tesco",1);
Address add = addressList.get(0);
String locality = add.getLocality();
double lat = addressList.get(0).getLatitude();
double lng = addressList.get(0).getLongitude();
mMap.addMarker(new MarkerOptions().position(new LatLng(lat,lng)).title("Waitrose"));
}
Modify your method like this:
private void setUpMap() throws IOException {
Geocoder geo = new Geocoder(getApplicationContext(), Locale.getDefault());
List<Address> addressList= geo.getFromLocationName("Tesco",1);
Address yourAddress = // get your location or the address to compare
Address closest = findClosest(addressList, yourAddress);
// do what you need
}
To create the findClosest you have to create a function that iterates over results and use haversine formula to calculate the distance to your location (or the desired one).
public double rad(double x)
{
return x*Math.PI/180.;
}
public Address findClosest( List<Address> addressList, Address yourAddress )
{
double lat = yourAddress.getLatitude(); // your (or desired) latitude
double lng = yourAddress.getLongitude(); // your (or desired) longitude
double R = 6371.; // radius of earth in km
double[] distances = new double[addressList.lenght];
var closest = -1;
for( i=0;i<addressList.lenght; i++ ) {
double mlat = addressList.get(i).getLatitude();
double mlng = addressList.get(i).getLongitude();
double dLat = rad(mlat - lat);
double dLong = rad(mlng - lng);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(rad(lat)) * Math.cos(rad(lat)) * Math.sin(dLong/2) * Math.sin(dLong/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double d = R * c;
distances[i] = d;
if ( closest == -1 || d < distances[closest] ) {
closest = i;
}
}
return addressList.get(closest);
}
Related
I have Created application for geo fence.
I implement location listener which sends me current Lat and Long.
I have array of Lat Long and i created Geofence from this array.
I want to check that Current lat long are within my Geofence Region or not?
Code For Geofence:-
private void createGeofence(double latitude, double longitude, int radius,
String geofenceType, String title) {
Marker stopMarker = googleMap.addMarker(new MarkerOptions()
.draggable(true)
.position(new LatLng(latitude, longitude))
.title(title)
);
googleMap.addCircle(new CircleOptions()
.center(new LatLng(latitude, longitude)).radius(radius)
.fillColor(Color.parseColor("#B2A9F6")));
}
Lat Long from Listener:-
#Override
public void onLocationChanged(Location location) {
// TODO Auto-generated method stub
Lat=location.getLatitude();
Lng=location.getLongitude();
Geocoder geocoder;
List<Address> addresses;
geocoder = new Geocoder(this, Locale.getDefault());
try {
addresses = geocoder.getFromLocation(Lat, Lng, 1);
address = addresses.get(0).getAddressLine(0);
city = addresses.get(0).getAddressLine(1);
country = addresses.get(0).getAddressLine(2);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("Lat Long is "+ Lat + " " + Lng);
}
Please help for this.
You could use the harvesine formula:
public static final double R = 6372.8; // In kilometers
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.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.asin(Math.sqrt(a));
return R * c;
}
That will give you the distance between the two locations. After that you could compare that distance with the geofence region radius to know if is inside the region.
Note: This distance will be in kilometers if your radius is on meters then just multiply the haversine method result with 1000 so that it's converted to meters.
Reference
I'm trying to sum up the total distance between an array of LatLng but failing hard. Here's what I've got so far:
private double sumDistance() {
Location loc = new Location("distance provider");
double previousLatitude;
double previousLongitude;
float[] results = new float[1];
for (LatLng latLng : mMapList) {
previousLatitude = latLng.latitude;
previousLongitude = latLng.longitude;
loc.distanceBetween(previousLatitude, previousLongitude, latLng.latitude, latLng.longitude, results);
}
return 0;
}
The problem with this is that the latlng for both are the same. Is there some way I can get the previous latlng or a cleaner way to do this that I'm not thinking of?
Why don't you assign the "previous variable" after you've calculated the distance? Something like this should work
private double sumDistance() {
Location loc = new Location("distance provider");
double previousLatitude = mMapList.get(0).latitude;
double previousLongitude = mMapList.get(0).longitude;
float[] results;
for (int i=1;i<mMapList.size();i++) {
loc.distanceBetween(previousLatitude, previousLongitude, mMapList.get(i).latitude, mMapList.get(i).longitude, results);
previousLatitude = mMapList[i].latitude;
previousLongitude = mMapList[i].longitude;
}
return 0;
}
double previousLatitude;
double previousLongitude;
float[] results;
for (int i=0; i<mMapList.size(); ++i) {
LatLng latLng = mMapList.get(i);
if (i == 0) {
// Previous weren't set yet, nothing to measure
// Set them and skip loop
previousLatitude = latLng.latitude;
previousLongitude = latLng.longitude;
continue;
}
// Measure previous with current
loc.distanceBetween(previousLatitude, previousLongitude, latLng.latitude, latLng.longitude, results);
// ~ Use the distance
// Modify the previous ones
previousLatitude = latLng.latitude;
previousLongitude = latLng.longitude;
}
I get the data from my database which contains, TITLE, SNIPPET and LOCATION and tried to test to check the distances between my currentlocation. I'm confused how to display the title of the closest marker to my position.
List<MyMarkerObj> m = data.getMyMarkers();
for (int i = 0; i < m.size(); i++) {
String[] slatlng = m.get(i).getPosition().split(" ");
LatLng lat = new LatLng(Double.valueOf(slatlng[0]), Double.valueOf(slatlng[1]));
map.addMarker(new MarkerOptions()
.title(m.get(i).getTitle())
.snippet(m.get(i).getSnippet())
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
.position(lat)
);
float[] distance = new float[1];
Location.distanceBetween(currentlat, currentlong,Double.valueOf(slatlng[0]), Double.valueOf(slatlng[1]), distance);
Toast.makeText(getActivity(), "Marker Distance: "+ m.get(i).getTitle() +" "+distance[0], Toast.LENGTH_LONG).show();
}
I made few changes here. Try it..
List<MyMarkerObj> m = data.getMyMarkers();
float mindist;
int pos=0;
for (int i = 0; i < m.size(); i++) {
String[] slatlng = m.get(i).getPosition().split(" ");
LatLng lat = new LatLng(Double.valueOf(slatlng[0]), Double.valueOf(slatlng[1]));
map.addMarker(new MarkerOptions()
.title(m.get(i).getTitle())
.snippet(m.get(i).getSnippet())
.icon(BitmapDescriptorFactory.defaultMarker(BitmapDescriptorFactory.HUE_AZURE))
.position(lat)
);
float[] distance = new float[1];
Location.distanceBetween(currentlat, currentlong,Double.valueOf(slatlng[0]), Double.valueOf(slatlng[1]), distance);
if(i==0) mindist=distance[0];
else if(mindist>distance[0]) {
mindist=distance[0];
pos=i;
}
}
Toast.makeText(getActivity(), "Closest Marker Distance: "+ m.get(pos).getTitle() +" "+mindist, Toast.LENGTH_LONG).show();
You can use this simple function to calculate distance between two points in latitude and longitude format it works like a charm, and you can then check for which distance is closest from your location. just pass the latitude and longitude of both location in it
public double distanceFrom(double lat1, double lng1, double lat2, double 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 Double(dist * meterConversion).floatValue(); // this will return distance
}
I am having trouble in converting the latitude and longitude values into android esri arcGIS map Point. Here's my code to get latitude and longitude values from GPS coordinates:
LocationManager lm;
String towers;
double lat;
double longi;
TextView txt;
lm = (LocationManager) getSystemService(Context.LOCATION_SERVICE);
Criteria crit = new Criteria();
towers = lm.getBestProvider(crit, false);
Location location = lm.getLastKnownLocation(towers);
if(location != null)
{
lat = location.getLatitude();
longi = location.getLongitude();
}
now I have the latitude and longitude values. Now all I need is to convert these values into valid esri arcGIS MapPoint. Can anyone help me?
Thanks in advance.
Assuming you're using the ESRI Android API? If so, create a graphics layer on your map. Then create a point object
com.esri.core.geometry.Point
Point myPoint = new Point();
then set the x/y values:
myPoint.setX(longi);
myPoint.setY(lat);
then add myPoint to the graphics object.
http://help.arcgis.com/en/arcgismobile/10.0/apis/android/api/index.html
Yes, it is possible. But you don't use the locationmanager in ArcGis.
ArcGIS has the predefined method like LocationListener, that is: OnStatusChangedListener.
See the below code for converting location latitude and longitude into esri arcGIS MapPoint.
mMapView.setOnStatusChangedListener(new OnStatusChangedListener() {
/**
*
*/
private static final long serialVersionUID = 1L;
public void onStatusChanged(Object source, STATUS status) {
if (source == mMapView && status == STATUS.INITIALIZED) {
LocationService ls = mMapView.getLocationService();
ls.setAutoPan(false);
ls.setLocationListener(new LocationListener() {
boolean locationChanged = false;
// Zooms to the current location when first GPS fix
// arrives.
public void onLocationChanged(Location loc) {
if (!locationChanged) {
locationChanged = true;
double locy = loc.getLatitude();
double locx = loc.getLongitude();
Point wgspoint = new Point(locx, locy);
Point mapPoint = (Point) GeometryEngine.project(wgspoint,
SpatialReference.create(4326),
mMapView.getSpatialReference());
Unit mapUnit = mMapView.getSpatialReference().getUnit();
double zoomWidth = Unit.convertUnits(
SEARCH_RADIUS, Unit.create(LinearUnit.Code.MILE_US), mapUnit);
Envelope zoomExtent = new Envelope(mapPoint, zoomWidth, zoomWidth);
mMapView.setExtent(zoomExtent);
GraphicsLayer gLayer = new GraphicsLayer();
PictureMarkerSymbol symbol = new
PictureMarkerSymbol(getResources().getDrawable(R.drawable.twiz_car_red));
Graphic graphic = new Graphic(mapPoint, symbol);
//Graphic point=new Graphic(new Point(x, y),new
SimpleMarkerSymbol(Color.CYAN,20,STYLE.CIRCLE));
gLayer.addGraphic(graphic);
mMapView .addLayer(gLayer);
}
}
public void onProviderDisabled(String arg0) {
}
public void onProviderEnabled(String arg0) {
}
public void onStatusChanged(String arg0, int arg1,
Bundle arg2) {
}
});
ls.start();
}
}
});
I've borrowed some code from here
private Point ToGeographic(Point pnt)
{
double mercatorX_lon = pnt.getX();
double mercatorY_lat = pnt.getY();
if (Math.abs(mercatorX_lon) < 180 && Math.abs(mercatorY_lat) < 90)
return pnt;
if ((Math.abs(mercatorX_lon) > 20037508.3427892) || (Math.abs(mercatorY_lat) > 20037508.3427892))
return pnt;
double x = mercatorX_lon;
double y = mercatorY_lat;
double num3 = x / 6378137.0;
double num4 = num3 * 57.295779513082323;
double num5 = Math.floor((double)((num4 + 180.0) / 360.0));
double num6 = num4 - (num5 * 360.0);
double num7 = 1.5707963267948966 - (2.0 * Math.atan(Math.exp((-1.0 * y) / 6378137.0)));
mercatorX_lon = num6;
mercatorY_lat = num7 * 57.295779513082323;
return new Point(mercatorX_lon, mercatorY_lat);
}
private Point ToWebMercator(Point pnt)
{
double mercatorX_lon = pnt.getX();
double mercatorY_lat = pnt.getY();
if ((Math.abs(mercatorX_lon) > 180 || Math.abs(mercatorY_lat) > 90))
return pnt;
double num = mercatorX_lon * 0.017453292519943295;
double x = 6378137.0 * num;
double a = mercatorY_lat * 0.017453292519943295;
mercatorX_lon = x;
mercatorY_lat = 3189068.5 * Math.log((1.0 + Math.sin(a)) / (1.0 - Math.sin(a)));
return new Point(mercatorX_lon, mercatorY_lat);
}
I make no claims of efficiency, but it's a starting point at least.
Disclaimer: I'm not an expert in this, but want to try to help. :)
There is now an ArcGIS Stack Exchange site. There's more information being added all the time and is a nice consolidated resource compared to what is out there disbursed on the interwebs.
For frameworks, I recommend GeoTools for Android.
As an aside, QGIS for Android is an interesting project from Marco Bernasocchi which you may find helpful as a reference.
Hope you can find what you're looking for!
i made a function that converts the two parameters of a location point to arcgis point :
private Point ConvertMyLocationPoint(final double x, final double y) {
Point wgspoint = new Point(x, y);
Point mapPoint = (Point) GeometryEngine.project(wgspoint, SpatialReference.create(4326),
mMapView.getSpatialReference());
return mapPoint;
}
//convert longitude and latitude to map point X Y
- (AGSPoint *)agsPointFromLatitude:(double)latitude longitude:(double)longitude
{
double mercatorX = longitude * 0.017453292519943295 * 6378137.0;
double a = latitude * 0.017453292519943295;
double mercatorY = 3189068.5 * log((1.0 + sin(a))/(1.0 - sin(a)));
AGSPoint *obj = [AGSPoint pointWithX:mercatorX y:mercatorY spatialReference: [AGSSpatialReference wgs84SpatialReference]];
return obj;
}
Here my code I used below code to calculate the distance between two location using their latitude and longitude. It is giving wrong distance. sometimes getting right and sometimes getting irrelevant distance.
We are getting lat1 and lng1 from database.
//getting lat2 and lng2 from GPS as below
public class MyLocationListener implements LocationListener {
#Override
public void onLocationChanged(Location loc)
{
lat2=loc.getLatitude();
lng2=loc.getLongitude();
String Text = "My current location is: " +"Latitud = "+ loc.getLatitude() +"Longitud = " + loc.getLongitude();
//System.out.println("Lat & Lang form Loc"+Text);
//Toast.makeText( getApplicationContext(), Text,Toast.LENGTH_SHORT).show();
}
#Override
public void onProviderDisabled(String provider)
{
}
#Override
public void onProviderEnabled(String provider)
{
}
#Override
public void onStatusChanged(String provider, int status, Bundle extras)
{
}
//Calculating distance
double earthRadius = 3958.75;
double dLat = Math.toRadians(lat1-lat2);
double dLng = Math.toRadians(lng1-lng2);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(Math.toRadians(lat2)) * Math.cos(Math.toRadians(lat1)) *
Math.sin(dLng/2) * Math.sin(dLng/2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
double dist = earthRadius * c;
There is an android.location.Location.distanceBetween() method which does this quite well.
Android Developer Docs: Location
Here getting distance in miles (mi)
private double distance(double lat1, double lon1, double lat2, double lon2) {
double theta = lon1 - lon2;
double dist = Math.sin(deg2rad(lat1))
* Math.sin(deg2rad(lat2))
+ Math.cos(deg2rad(lat1))
* Math.cos(deg2rad(lat2))
* Math.cos(deg2rad(theta));
dist = Math.acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
return (dist);
}
private double deg2rad(double deg) {
return (deg * Math.PI / 180.0);
}
private double rad2deg(double rad) {
return (rad * 180.0 / Math.PI);
}
Try this code.
startPoint.distanceTo(endPoint) function returns the distance between those places in meters.
Location startPoint=new Location("locationA");
startPoint.setLatitude(17.372102);
startPoint.setLongitude(78.484196);
Location endPoint=new Location("locationA");
endPoint.setLatitude(17.375775);
endPoint.setLongitude(78.469218);
double distance=startPoint.distanceTo(endPoint);
here "distance" is our required result in Meters. I hope it will work for android.
in build.gradle:
compile 'com.google.maps.android:android-maps-utils:0.4'
and then:
public static Double distanceBetween(LatLng point1, LatLng point2) {
if (point1 == null || point2 == null) {
return null;
}
return SphericalUtil.computeDistanceBetween(point1, point2);
}
If you have two Location Objects Location loc1 and Location loc2 you do
float distance = loc1.distanceTo(loc2);
If you have longitude and latitude values you use the static distanceBetween() function
float[] results = new float[1];
Location.distanceBetween(startLatitude, startLongitude,
endLatitude, endLongitude, results);
float distance = results[0];
private String getDistanceOnRoad(double latitude, double longitude,
double prelatitute, double prelongitude) {
String result_in_kms = "";
String url = "http://maps.google.com/maps/api/directions/xml?origin="
+ latitude + "," + longitude + "&destination=" + prelatitute
+ "," + prelongitude + "&sensor=false&units=metric";
String tag[] = { "text" };
HttpResponse response = null;
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
response = httpClient.execute(httpPost, localContext);
InputStream is = response.getEntity().getContent();
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document doc = builder.parse(is);
if (doc != null) {
NodeList nl;
ArrayList args = new ArrayList();
for (String s : tag) {
nl = doc.getElementsByTagName(s);
if (nl.getLength() > 0) {
Node node = nl.item(nl.getLength() - 1);
args.add(node.getTextContent());
} else {
args.add(" - ");
}
}
result_in_kms = String.format("%s", args.get(0));
}
} catch (Exception e) {
e.printStackTrace();
}
return result_in_kms;
}
In Kotlin
private fun distanceInMeter(startLat: Double, startLon: Double, endLat: Double, endLon: Double): Float {
var results = FloatArray(1)
Location.distanceBetween(startLat,startLon,endLat,endLon,results)
return results[0]
}
private float distanceFrom_in_Km(float lat1, float lng1, float lat2, float lng2) {
if (lat1== null || lng1== null || lat2== null || lng2== null)
{
return null;
}
double earthRadius = 6371000; //meters
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));
float dist = (float) (earthRadius * c);
return dist;
}
Use the below method for calculating the distance of two different locations.
public double getKilometers(double lat1, double long1, double lat2, double long2) {
double PI_RAD = Math.PI / 180.0;
double phi1 = lat1 * PI_RAD;
double phi2 = lat2 * PI_RAD;
double lam1 = long1 * PI_RAD;
double lam2 = long2 * PI_RAD;
return 6371.01 * acos(sin(phi1) * sin(phi2) + cos(phi1) * cos(phi2) * cos(lam2 - lam1));}
Try This below method code to get the distance in meter between two location, hope it will help for you
public static double distance(LatLng start, LatLng end){
try {
Location location1 = new Location("locationA");
location1.setLatitude(start.latitude);
location1.setLongitude(start.longitude);
Location location2 = new Location("locationB");
location2.setLatitude(end.latitude);
location2.setLongitude(end.longitude);
double distance = location1.distanceTo(location2);
return distance;
} catch (Exception e) {
e.printStackTrace();
}
return 0;
}
Why are you writing the code for calculating the distance by yourself?
Check the api's in Location class
You should use Haversine Distance Formulas
Haversine Formulas used to calculate the great distance between two points on the earth.
public void haversine(double lat1, double lon1, double lat2, double lon2) {
double Rad = 6372.8; //Earth's Radius In kilometers
// TODO Auto-generated method stub
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.sin(dLon / 2) * Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.asin(Math.sqrt(a));
haverdistanceKM = Rad * c;
}
Updated on October 8, 2021
Returns the approximate distance in meters between this location and the given location. Distance is defined using the WGS84 ellipsoid.
Java
public float getDistance(double startLat,double startLang,double endLat,double endLang) {
Location locStart = new Location("");
locStart.setLatitude(startLat);
locStart.setLongitude(startLang);
Location locEnd = new Location("");
locEnd.setLatitude(endLat);
locEnd.setLongitude(endLang);
return locStart.distanceTo(locEnd);
}
Kotlin
private fun getDistance(
startLat: Double,
startLang: Double,
endLat: Double,
endLang: Double
): Float {
val locStart = Location("")
locStart.latitude = startLat
locStart.longitude = startLang
val locEnd = Location("")
locEnd.latitude = endLat
locEnd.longitude = endLang
return locStart.distanceTo(locEnd)
}
Returns the approximate distance in meters between this location and the given location. Distance is defined using the WGS84 ellipsoid.
public float getMesureLatLang(double lat,double lang) {
Location loc1 = new Location("");
loc1.setLatitude(getLatitute());// current latitude
loc1.setLongitude(getLangitute());//current Longitude
Location loc2 = new Location("");
loc2.setLatitude(lat);
loc2.setLongitude(lang);
return loc1.distanceTo(loc2);
// return distance(getLatitute(),getLangitute(),lat,lang);
}