Find average location and remove other locations: - java

Let's say that I am collecting users location data every 20 minutes. At the end of the day I have an ArrayList of objects that contain lat and long fields and other data.
I have two problems that I am facing and trying to figure out:
Some of the locations are taken from inside of a building so they are not very accurate and could be spread around the actual location where the user was at the time.
Some of the locations are taken at different times but from the same location, as the user didn't moved.
What I want to achieve is to find all the locations that are near one another: lets say 70 meters, find the average location of all those locations and replace them only with this one average location.
So I am coming to the two important questions:
What would be the best way to find all near locations < 70 meter distance (Take in mind that the array contains valid changes in location. So I have to find the groups of near ones and leave the others intact).
Is there a method or a way to find the average location of many near ones?

Regarding near positions I previously answered a similar question here: Android Maps v2 - animate camera to include most markers
Specifically I think you would be able to use this piece of code:
private List<Marker> getSurroundingMarkers(List<Marker> markers,
LatLng origin, int maxDistanceMeters) {
List<Marker> surroundingMarkers = surroundingMarkers = new ArrayList<Marker>();
if (markers == null) return surroundingMarkers ;
for (Marker marker : markers) {
double dist = distBetween(origin, marker.getPosition());
if (dist < maxDistanceMeters) {
surroundingMarkers.add(marker);
}
}
return surroundingMarkers;
}
private float distBetween(LatLng pos1, LatLng pos2) {
return distBetween(pos1.latitude, pos1.longitude, pos2.latitude,
pos2.longitude);
}
/** distance in meters **/
private float distBetween(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 (float) (dist * meterConversion);
}
Possibly rewriting the Marker part to use LatLng instead.
regarding the averaging, it should be a simple matter of (say you have n LatLng's):
lat_avg = (lat1+lat2+...+latn)/n
lng_avg = (lng1+lng2+...+lngn)/n
latlng_avg = new LatLng(lat_avg, lat_lng)

I' not sure how you're getting the user's location - whether your using a traditional LocationManager or play services. I've always modeled my location getting on this approach documented on the android developers blog. If you're flexible in switching between location gathering methods, whether the person is inside or outside should not matter that much. You should be getting the best possible location at any given time.
Assuming you're getting locations on a sufficient time schedule (I don't know when you're checking for updates but since you want everything inside a 70m radius I'm assuming its on a time schedule and not distance change) the basic way to find the average point is:
(1) Convert each lat/long pair into a unit-length 3D vector.
(2) Sum each of those vectors
(3) Normalise the resulting vector
(4) Convert back to spherical coordinates
That approach is documented here as well as in a much earlier SO post on calculating the average of a set of angles
The example code is pretty easy to follow - just plug in the lat long values you get from your location grab and you should be ok.

Well for markers that come from the same location I have created the following method:
public ArrayList<MyLocation> removeSameLocationMarkers(List<ParseObject> objects, int maxDistanceMeters)
{
boolean isLocationExist;
ArrayList<MyLocation> acceptedLocations = new ArrayList<MyLocation>();
if (objects == null) return acceptedLocations;
for (ParseObject location1 : objects)
{
isLocationExist = false;
for (MyLocation location2 : acceptedLocations)
{
if (!location1.equals(location2))
{
float distance = distBetween(location1.getDouble("latitude"), location1.getDouble("longitude"), location2.getLatitude(), location2.getLongitude());
if (distance < maxDistanceMeters)
{
location2.addTimeToLocation(location1.getString("time"));
isLocationExist = true;
}
}
}
if (!isLocationExist)
{
Location newLocation = new Location("");
newLocation.setLatitude(location1.getDouble("latitude"));
newLocation.setLongitude(location1.getDouble("longitude"));
String provider = location1.getString("provider");
if (provider != null)
{
newLocation.setProvider(provider);
}
MyLocation newMyLocation = new MyLocation(newLocation);
newMyLocation.addTimeToLocation(location1.getString("time"));
acceptedLocations.add(newMyLocation);
}
}
return acceptedLocations;
}

Related

finding other user according to my location

I'm using firebase (android) to store data and I'm saving users like below:
users{
abcdefghi{
name:"abc",
lat:"12.988",
long:-0.123,
desc:"all other desc"
},KLMNGHT{
name:"def",
lat:"11.988",
long:-1.123,
desc:" other desc"
}
}
I want to display all users who comes into my radius zone(proximity zone) which are defined by me according to my location . I am out of ideas . I looked upon Haversine formula. But i don't know to achieve that.
What is the best algorithm to find user?
private const double EARTH_RADIUS = 6378.137;
private static double rad(double d)
{
return d * Math.PI / 180.0;
}
public static double GetDistance(double lat1, double lng1, double lat2, double lng2)
{
double radLat1 = rad(lat1);
double radLat2 = rad(lat2);
double a = radLat1 - radLat2;
double b = rad(lng1) - rad(lng2);
double s = 2 * Math.Asin(Math.Sqrt(Math.Pow(Math.Sin(a/2),2) +
Math.Cos(radLat1)*Math.Cos(radLat2)*Math.Pow(Math.Sin(b/2),2)));
s = s * EARTH_RADIUS;
s = Math.Round(s * 10000) / 10000;
return s;
}
Maybe this code can help you.
So is the question strictly: given two points on earth A(lan1,lon1) B(lan2,lon2) find the distance between A and B? When you are saying 'best algorithm',do you mean best in terms of development time,time,memory?!
Anyways,assuming 'best' in terms of development time you could use:
1.Google's API explained here: https://developers.google.com/maps/documentation/distance-matrix/intro#DistanceMatrixRequests
2.Here is a simple implementation- but I haven't tested it myself yet-
https://www.geodatasource.com/developers/java

Correct way to use delaying method in android

I'm trying to create an adndroid application which will shows a distance from moment when I started the app.
I'm using Location Manager and this is my idea:
Check coordinates.
(2 sec delay)
Chceck coordinates2
If coordinates2 != coordinates then calculate distance between them and add it to double distance.
Repeat
public void onLocationChanged(final Location location) {
sz = location.getLatitude();
dl = location.getLongitude();
String dls = String.valueOf(dl);
String szs = String.valueOf(sz);
aktualna_dlg.setText(dls);
aktualna_szg.setText(szs);
lat1 = location.getLatitude();
lon1 = location.getLongitude();
int secs = 2; // Delay in seconds
Utils.delay(secs, new Utils.DelayCallback() {
#Override
public void afterDelay() {
lat2 = location.getLatitude();
lon2 = location.getLongitude();
}
});
if (lat1!=lat2 || lon1!=lon2){
distance += DistanceCalculator.distance(lat1,lon1,lat2,lon2, "K");
}
if(distance<1000){
String distance_s = String.valueOf(distance*1000);
distance_tv.setText(distance_s + " m");
}
else if(distance>=1000){
String distance_s = String.valueOf(distance/1000);
distance_tv.setText(distance_s + " km");
}
}
But when I compile the app and catch GPS, I'm getting a distance ~ 6km.
What am I doing wrong?
I'm not sure what utils.delay does, since it isn't part of the framework. But assuming it works correctly- it happens on a delay. That means lat2 and lon2 won't update until its called. All of the code that uses those variables has to happen in afterDelay, they aren't valid until then.
Eliminate the delays and simply compare the argument to onLocationChanged with the argument from the last time it was called. As for why you're recording a huge distance traveled...
Use a high-pass filter
How far do you expect to move in 2 seconds? Probably less than your GPS receiver's accuracy, unless you're in an aircraft. Most of your "movement" is actually just random noise.
In one of my apps, I save the starting GPS location as a point of reference. On each call to onLocationChanged, I compute the distance between the current location and the point of reference. If the distance is larger than some high-pass value, I add the distance to the running total and set the new location as the point of reference. I use 100 meters as my high-pass value because I've seen a few devices with 100 meter accuracy or worse around tall buildings.

Location in Java and iOS

I hope you understand my question my english is not too good.
Anyway, I’m working on a application with locations. Its only a fun app which should help me to learn more.
Its a iOS application and the server is a WebObjects/WOnder application(Java). What im trying to do is on the iOS app I fetch the user location then send the data to the server. And on the server I fetch annotation points from a database. but only send the annotations which are in near of the users location back.
My only problem now is I don’t know how to calculate the locations in the near of the user. I googled a lot but did not find something that work.
Only something which give me the „bounding box“ of the user.
//To calculate the search bounds...
//First we need to calculate the corners of the map so we get the points
CGPoint nePoint = CGPointMake(self.mapView.bounds.origin.x + mapView.bounds.size.width, mapView.bounds.origin.y);
CGPoint swPoint = CGPointMake((self.mapView.bounds.origin.x), (mapView.bounds.origin.y + mapView.bounds.size.height));
//Then transform those point into lat,lng values
CLLocationCoordinate2D neCoord;
neCoord = [mapView convertPoint:nePoint toCoordinateFromView:mapView];
CLLocationCoordinate2D swCoord;
swCoord = [mapView convertPoint:swPoint toCoordinateFromView:mapView];
Dose anyone have a good idea how to do that in Java?
I use c# code to calculate the distance. I enumerate all of the data in the database and if the data is in range of my distance I add it to the array and after that I pass it to the device. In my code I provide lat and lon for user current position and lat and lon for object from database. I also provide unit K - km and M - miles. This is a c# code but you can easy convert it to java:
public double GetDistanceFromLatLong(double lat1, double lon1, double lat2, double lon2, string unit)
{
double ReturnValue = 0;
double theta = 0;
double dist = 0;
theta = lon1 - lon2;
dist = Math.Sin(DegreesToRadians(lat1)) * Math.Sin(DegreesToRadians(lat2)) + Math.Cos(DegreesToRadians(lat1)) *
Math.Cos(DegreesToRadians(lat2)) * Math.Cos(DegreesToRadians(theta));
dist = Math.Acos(dist);
dist = RadiansToDegrees(dist);
ReturnValue = dist * 60 * 1.1515;
switch (unit.ToUpper())
{
case "K":
ReturnValue = ReturnValue * 1.609344;
break;
case "M":
ReturnValue = ReturnValue * 0.8684;
break;
}
return ReturnValue;
}

android app: get distance between two addresses

This is my first time development in android application. This app will calculate the total distance between two address that input by the user in order to get the total distance. Is it ok to calculate the distance that assume the road is straight? by the way, this application will not show map and does not need GPS! It just needs to use geocoder to get the latitude-longitude.
Here are my questions:
what would the AndroidManifest.xml would look like? do i need to include android:name=".permission.MAPS_RECEIVE".
In the main_activity.java, should i use activity or use fragment activity?
public class MainActivity extends Activity
Thanks for your reply and i would like to appreciate u guys and if possible can you please show the full AndroidManifext.xml code?
Thanks.
http://developer.android.com/reference/android/location/Location.html
Look into distanceTo or distanceBetween. You can create a Location object from a latitude and longitude:
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);
or
private double gps2m(float lat_a, float lng_a, float lat_b, float lng_b) {
float pk = (float) (180/3.14169);
float a1 = lat_a / pk;
float a2 = lng_a / pk;
float b1 = lat_b / pk;
float b2 = lng_b / pk;
float t1 = FloatMath.cos(a1)*FloatMath.cos(a2)*FloatMath.cos(b1)*FloatMath.cos(b2);
float t2 = FloatMath.cos(a1)*FloatMath.sin(a2)*FloatMath.cos(b1)*FloatMath.sin(b2);
float t3 = FloatMath.sin(a1)*FloatMath.sin(b1);
double tt = Math.acos(t1 + t2 + t3);
return 6366000*tt;
}
You don't need to include the maps permissions.
To get the distance between 2 locations you can use the Geocoder class. This shouldn't need an y location permissions either.
The Geocoder class has a method
getFromLocationName(String locationName, int maxResults)
which returns a list of Addresses for a location input. The addresses have a latitude/longitude.
You need to convert the Address into a Location object which has methods for calculating distance between 2 locations:
distanceTo(Location dest)
Returns the approximate distance in meters between this location and the given location.
As for your second question. You should use Fragments inside of your activity. Have a read through this to understand a bit more about fragments and their advantages.
Use the Geocoder to get the latitude and longitude for place 1 and place 2. Apply those values in the following method.
Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, results)

Problems using the acos function in J2ME in eclipse

"I'm working with J2ME in eclipse, and need to use the method acos() belongs to the Math package, the question is that the package available for J2ME Math is not that function (limitations of mobiles), then I want an algorithm or method alternative to calculate the cosine.
I need the "acos" to calculate the following formula:
long2 = cood[i].getLongitud();
lat2 = cood[i].getLatitud();
dlong = (long1 - long2);
c = dlong * degtorad;
dvalue = (Math.sin(a) * Math.sin(b))+(Math.cos(a) * Math.cos(b)*Math.cos(c));
dd = Math.acos(dvalue) * radtodeg;
km = (dd * 111.302);
This function allows me from two geographical coordinates to calculate the distance in kilometers between them. If there is an alternative method to calculate this distance (where the cosine is not used), I also would be useful.
Any help on this?
public static double acos(double a)
{
final double epsilon=1.0E-7;
double x=a;
do {
x-=(Math.sin(x)-a)/Math.cos(x);
}
while (Math.abs(Math.sin(x)-a)>epsilon);
// returned angle is in radians
return -1*(x-Math.PI/2);
}
You could try to implement the arccosine as shown here.
If you have the Location API available you can use the distance method from the Coordinates class. From the Coordinates API:
public float distance(Coordinates to)
Calculates the geodetic distance between the two points
according to the ellipsoid model of WGS84.
Altitude is neglected from calculations.
The implementation shall calculate this as exactly as it can.
However, it is required that the result is within 0.35% of the correct result.

Categories