I have an arrayList of markers and I want to find the closest marker to my current location.
I had no idea how to find that marker so I searched and found same problem in here.
Google Maps Api v3 - find nearest markers
then I tried to convert those code to java but it doesn't work now.
closest doesn't change and always it is -1.
Is there any better solution for this problem or I can make the following code usable?
public void findNearMarker(){
double pi = Math.PI;
int R = 6371; //equatorial radius
double[] distances = new double[2];
double d = 0;
int i;
int closest = -1;
for ( i = 0; i == markerArrayList.size(); i++){
double lat2 = markerArrayList.get(i).getPosition().latitude;
double lon2 = markerArrayList.get(i).getPosition().longitude;
double chLat = lat2 - currentLocation.getLatitude();
double chLon = lon2 - currentLocation.getLongitude();
double dLat = chLat*(pi/180);
double dLon = chLon*(pi/180);
double rLat1 = currentLocation.getLatitude()*(pi/180);
double rLat2 = lat2 * (pi/180);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.sin(dLon/2)
* Math.sin(dLon /2) * Math.cos(rLat1) * Math.cos(rLat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
d = R * c;
distances[i] = d;
if (closest == -1 || d< distances[closest]){
closest = i;
}
}
}
first you need to import the location class of the android sdk
import android.location.Location;
ArrayList<Marker> markers = new ArrayList<>();
markers = sortListbyDistance(markers, currentLocation.getLocation());
public static ArrayList<Marker> sortListbyDistance(ArrayList<Marker> markers, final LatLng location){
Collections.sort(markers, new Comparator<Marker>() {
#Override
public int compare(Marker marker2, Marker marker1) {
//
if(getDistanceBetweenPoints(marker1.getLocation(),location)>getDistanceBetweenPoints(marker2.getLocation(),location)){
return -1;
} else {
return 1;
}
}
});
return markers;
}
public static float getDistanceBetweenPoints(double firstLatitude, double firstLongitude, double secondLatitude, double secondLongitude) {
float[] results = new float[1];
Location.distanceBetween(firstLatitude, firstLongitude, secondLatitude, secondLongitude, results);
return results[0];
}
and to get the nearest marker just get first item in markers, cheers :)
If you follow
Comparing two locations using their Longitude and Latitude
/** 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 kilometer output
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; // output distance, in MILES
}
loop through your list with this function and get the lowest return value.
You can also use the Maps API
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
locationB.setLongitude(lngB);
float distance = locationA.distanceTo(locationB);
Related
I had a previous question where I was wondering how I could find the distance between two locations based on latitude and longitude. I was linked to an answer and now I am trying to implement SortPlaces.java but it cannot resolve the symbol Place. The IDE also does not give me an option to import the class. Does this mean I have to create the Place class myself? If so what would that like or? Or does the Place class already exist and I can't import it because I don't have the proper library?
Thanks, here is the code.
import com.google.android.gms.maps.model.LatLng;
public class SortPlaces implements Comparator<Place> {
LatLng currentLoc;
public SortPlaces(LatLng current){
currentLoc = current;
}
#Override
public int compare(final Place place1, final Place place2) {
double lat1 = place1.latlng.latitude;
double lon1 = place1.latlng.longitude;
double lat2 = place2.latlng.latitude;
double lon2 = place2.latlng.longitude;
double distanceToPlace1 = distance(currentLoc.latitude, currentLoc.longitude, lat1, lon1);
double distanceToPlace2 = distance(currentLoc.latitude, currentLoc.longitude, lat2, lon2);
return (int) (distanceToPlace1 - distanceToPlace2);
}
public double distance(double fromLat, double fromLon, double toLat, double toLon) {
double radius = 6378137; // approximate Earth radius, *in meters*
double deltaLat = toLat - fromLat;
double deltaLon = toLon - fromLon;
double angle = 2 * Math.asin( Math.sqrt(
Math.pow(Math.sin(deltaLat/2), 2) +
Math.cos(fromLat) * Math.cos(toLat) *
Math.pow(Math.sin(deltaLon/2), 2) ) );
return radius * angle;
}
}
Looking at your other question, you will need to replace the Place class with your Campsite class in the sorting code:
public class SortCampgrounds implements Comparator<Campsite> {
LatLng currentLoc;
public SortCampgrounds(LatLng current){
currentLoc = current;
}
#Override
public int compare(final Campsite campsite1, final Campsite campsite2) {
double lat1 = campsite1.getLatitude();
double lon1 = campsite1.getLongitude();
double lat2 = campsite2.getLatitude();
double lon2 = campsite2.getLongitude();
double distanceToCampsite1 = distance(currentLoc.latitude, currentLoc.longitude, lat1, lon1);
double distanceToCampsite2 = distance(currentLoc.latitude, currentLoc.longitude, lat2, lon2);
return (int) (distanceToCampsite1 - distanceToCampsite2);
}
public double distance(double fromLat, double fromLon, double toLat, double toLon) {
double radius = 6378137; // approximate Earth radius, *in meters*
double deltaLat = toLat - fromLat;
double deltaLon = toLon - fromLon;
double angle = 2 * Math.asin( Math.sqrt(
Math.pow(Math.sin(deltaLat/2), 2) +
Math.cos(fromLat) * Math.cos(toLat) *
Math.pow(Math.sin(deltaLon/2), 2) ) );
return radius * angle;
}
}
Then use the custom comparator in order to sort the Campsites by distance to current location, and get the closest:
public void onMapReady(GoogleMap googleMap) {
mMap = googleMap;
// GET ALL CAMPSITES FROM DATABASE
ArrayList<Campsite> campsites = db.getAllCampsites();
// LOOP THROUGH EACH CAMPSITE AND ADD A MARKER FOR EACH CAMPSITE
for (Campsite campsite : campsites) {
LatLng latLng = new LatLng(campsite.getLatitude(), campsite.getLongitude());
mMap.addMarker(new MarkerOptions().position(latLng).title(campsite.getName()));
}
// PLACE MARKER FOR CURRENT LOCATION (STATIC LOCATION)
LatLng currentLocation = new LatLng(34.1691, -118.4167);
mMap.addMarker(new MarkerOptions().position(currentLocation).title("Your location"));
// Add this to sort and get the closest Campsite:
Collections.sort(campsites, new SortCampgrounds(currentLocation));
// Get the first one from the list, this will be the closest:
Campsite closestCampsite = campsites.get(0);
}
I want to draw a curved polyline between two points on a map with the Mapbox SDK.
I could not find any solution from the Mapbox SDK. The Turf library is not ready yet to use it on Android.
I found a solution with the google maps sdk so I converted it to use only the Mapbox sdk :
Inspired by Can I draw a curved dashed line in Google Maps Android?
public static List<LatLng> computeCurvedPolyline(LatLng from, LatLng to, double k) {
//Calculate distance and heading between two points
double distance = from.distanceTo(to);
double heading = computeHeading(from, to);
//Midpoint position
LatLng p = computeOffset(from, distance * 0.5, heading);
//Apply some mathematics to calculate position of the circle center
double x = (1 - k * k) * distance * 0.5 / (2 * k);
double r = (1 + k * k) * distance * 0.5 / (2 * k);
LatLng c = computeOffset(p, x, heading + 90.0);
//Polyline options
List<LatLng> mapboxLatlng = new ArrayList<>();
//Calculate heading between circle center and two points
double h1 = computeHeading(c, from);
double h2 = computeHeading(c, to);
//Calculate positions of points on circle border and add them to polyline options
int numpoints = 100;
double step = (h2 - h1) / numpoints;
for (int i = 0; i < numpoints; i++) {
LatLng pi = computeOffset(c, r, h1 + i * step);
mapboxLatlng.add(pi);
}
return mapboxLatlng;
}
static double computeHeading(LatLng from, LatLng to) {
double fromLat = Math.toRadians(from.getLatitude());
double fromLng = Math.toRadians(from.getLongitude());
double toLat = Math.toRadians(to.getLatitude());
double toLng = Math.toRadians(to.getLongitude());
double dLng = toLng - fromLng;
double heading = Math.atan2(Math.sin(dLng) * Math.cos(toLat), Math.cos(fromLat) * Math.sin(toLat) - Math.sin(fromLat) * Math.cos(toLat) * Math.cos(dLng));
return wrap(Math.toDegrees(heading), -180.0D, 180.0D);
}
static double wrap(double n, double min, double max) {
return n >= min && n < max ? n : mod(n - min, max - min) + min;
}
static double mod(double x, double m) {
return (x % m + m) % m;
}
static LatLng computeOffset(LatLng from, double distance, double heading) {
distance /= 6371009.0D;
heading = Math.toRadians(heading);
double fromLat = Math.toRadians(from.getLatitude());
double fromLng = Math.toRadians(from.getLongitude());
double cosDistance = Math.cos(distance);
double sinDistance = Math.sin(distance);
double sinFromLat = Math.sin(fromLat);
double cosFromLat = Math.cos(fromLat);
double sinLat = cosDistance * sinFromLat + sinDistance * cosFromLat * Math.cos(heading);
double dLng = Math.atan2(sinDistance * cosFromLat * Math.sin(heading), cosDistance - sinFromLat * sinLat);
return new LatLng(Math.toDegrees(Math.asin(sinLat)), Math.toDegrees(fromLng + dLng));
}
This code will return a list of LatLng points that you can draw on your map, enjoy !
The result produced by this code (not the blurred part of course!):
Any improvement to this code is welcomed !
Sir,
I have referred to this website for calculating new coordinate from given old starting point (22.36818013084568,114.11599405109882) , bearing (in Rad) 1.1583078679283372 , and distance (in meters) :134.07025146484375
). When it comes to execution , it wrongly gives (0.3904068271541288,1.9917206728639663) . Would you please tell me the which part I get it wrong or any revised algorithm for calculating the new position ?
public static double getDistanceInMeters(LatLng sp1, LatLng sp2) {
int lat = (int) (sp1.latitude * 1E6);
int lng = (int) (sp1.longitude * 1E6);
GeoPoint p1 = new GeoPoint(lat, lng);
int latX = (int) (sp2.latitude * 1E6);
int lngX = (int) (sp2.longitude * 1E6);
GeoPoint p2 = new GeoPoint(latX, lngX);
double lat1 = ((double)p1.getLatitudeE6()) / 1e6;
double lng1 = ((double)p1.getLongitudeE6()) / 1e6;
double lat2 = ((double)p2.getLatitudeE6()) / 1e6;
double lng2 = ((double)p2.getLongitudeE6()) / 1e6;
float [] dist = new float[1];
Location.distanceBetween(lat1, lng1, lat2, lng2, dist);
return dist[0] ;
}
double distance = SystemUtils.getDistanceInMeters(dronePosition, devicePos )- followDist;
public static LatLng fromBearingDistance(LatLng originalPosition, double brng, double d) {
double lat1 = Math.toRadians(originalPosition.latitude) ;
double lon1 = Math.toRadians(originalPosition.longitude);
long R = 6371000; // distance of earth's radius in meters
d = d /(double) R;
System.out.println("d/R :" + d/R ) ;
System.out.println(" Math.cos(d/R) :" + Math.cos(d/R) ) ;
System.out.println(" Math.sin(d/R) :" + Math.sin(d/R) ) ;
//(in km)
double lat2 = Math.asin( Math.sin(lat1)*Math.cos( d ) + Math.cos(lat1)*Math.sin( d )*Math.cos(brng) );
double lon2 = lon1 + Math.atan2(Math.sin(brng)*Math.sin(d )*Math.cos(lat1),
Math.cos(d )-Math.sin(lat1)*Math.sin(lat2));
return new LatLng(lat2,lon2);
}
I'm not really good with mathematics but I need to calculate the distance of two different locations of the markers. Something like this:
public double CalculationByDistance(double initialLat, double initialLong, double finalLat, double finalLong){
return distance;
}
Or is there any alternative ways that I can calculate the distance of two markers, also I tried to google for answers.. but couldn't find any.
Reference:
http://en.wikipedia.org/wiki/Haversine_formula
Comments are appreciated :) Thanks!!
Try this, much simpler than Haversine!
Location me = new Location("");
Location dest = new Location("");
me.setLatitude(myLat);
me.setLongitude(myLong);
dest.setLatitude(destLat);
dest.setLongitude(destLong);
float dist = me.distanceTo(dest);
If you want to stick with Haversine, something like this:
public double CalculationByDistance(double initialLat, double initialLong,
double finalLat, double finalLong){
int R = 6371; // km (Earth radius)
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
initialLat = toRadians(initialLat);
finalLat = toRadians(finalLat);
double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.sin(dLon/2) * Math.sin(dLon/2) * Math.cos(initialLat) * Math.cos(finalLat);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
public double toRadians(double deg) {
return deg * (Math.PI/180);
}
Also, you need to create a method toRadians() that convert values from degrees to radians, which is quite easy.
Hope it helps!
From your wikipedia link, applying the formula directly you can do the following:
public double CalculationByDistance(double initialLat, double initialLong, double finalLat, double finalLong){
/*PRE: All the input values are in radians!*/
double latDiff = finalLat - initialLat;
double longDiff = finalLong - initialLong;
double earthRadius = 6371; //In Km if you want the distance in km
double distance = 2*earthRadius*Math.asin(Math.sqrt(Math.pow(Math.sin(latDiff/2.0),2)+Math.cos(initialLat)*Math.cos(finalLat)*Math.pow(Math.sin(longDiff/2),2)));
return distance;
}
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
/**
* This is the implementation Haversine Distance Algorithm between two places
* #author ananth
* R = earth’s radius (mean radius = 6,371km)
Δlat = lat2− lat1
Δlong = long2− long1
a = sin²(Δlat/2) + cos(lat1).cos(lat2).sin²(Δlong/2)
c = 2.atan2(√a, √(1−a))
d = R.c
*
*/
public class HaversineDistance {
/**
* #param args
* arg 1- latitude 1
* arg 2 — latitude 2
* arg 3 — longitude 1
* arg 4 — longitude 2
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
final int R = 6371; // Radious of the earth
Double lat1 = Double.parseDouble(args[0]);
Double lon1 = Double.parseDouble(args[1]);
Double lat2 = Double.parseDouble(args[2]);
Double lon2 = Double.parseDouble(args[3]);
Double latDistance = toRad(lat2-lat1);
Double lonDistance = toRad(lon2-lon1);
Double a = Math.sin(latDistance / 2) * Math.sin(latDistance / 2) +
Math.cos(toRad(lat1)) * Math.cos(toRad(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;
System.out.println(“The distance between two lat and long is::” + distance);
}
private static Double toRad(Double value) {
return value * Math.PI / 180;
}
}
This is my code:
private final static double[] multipliers = {
1.0, 1.0936133, 0.001, 0.000621371192
};
private final static String[] unitstrings = {
"m", "y", "km", "mi"
};
private void updateMeasurement() {
double distance = calcGeoDistance(startLat, startLon, currentLat, currentLon) * multipliers[unitindex];
String distanceText = "" + RoundDecimal(distance, 2) + " " + unitstrings[unitindex];
((TextView)findViewById(R.id.distance)).setText(distanceText);
}
private double calcGeoDistance(final double lat1, final double lon1, final double lat2, final double lon2)
{
double distance = 0.0;
try
{
final float[] results = new float[3];
Location.distanceBetween(lat1, lon1, lat2, lon2, results);
distance = (double)results[0];
}
catch (final Exception ex)
{
distance = 0.0;
}
return distance;
}
I get 8310 km even when I shake the mobile.
public float distanceFrom(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();
}
Are you using Long and Lat in degrees of the correct format? It would help to see the values you are passing in
double startLatitude = pointStart.getLatitudeE6() / DEG_RATE;
double startLongitude= pointStart.getLongitudeE6() / DEG_RATE;
double endLatitude = pointEnd.getLatitudeE6() / DEG_RATE;
double endLongitude= pointEnd.getLongitudeE6() / DEG_RATE;
float[] result = new float[1];
Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, result);
Where pointStart and pointEnd are com.google.android.maps.GeoPoint
Reference -
http://www.java2s.com/Code/Android/Core-Class/GetDistancebetweentwoGeoPoint.htm