I have used the following code to check GPS coordinates, but problem is that if i am standing at same place the coordinates changes and distance is anywhere between 4 to 20 mts.
I want to change it only when I have moved min 10 mtrs.
locationManager_gps = (LocationManager) this
.getSystemService(Context.LOCATION_SERVICE);
locationManager_gps.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0,
new MyLocationListener_gps());
class MyLocationListener_gps implements LocationListener {
public void onLocationChanged(Location location) {
clat = location.getLatitude();
clon = location.getLongitude();
if (clat != plat || clon != plon) {
float[] results = new float[3];
Location.distanceBetween(plat, plon, clat, clon, results);
if (flag_gps == 0) {
flag_gps = 1;
} else {
GeoPoint geoPoint = new GeoPoint((int) (clat * 1E6),
(int) (clon * 1E6));
mapView.getController().animateTo(geoPoint);
draw = new MyOverLay(geoPoint);
mapView.getOverlays().add(draw);
dist_mtr += results[0];
}
plat = clat;
plon = clon;
}
}
If I use 50 as min distance between updates then it is working fine. I also tried making it 30 but also data was wrong over a period of 4 km while traveling in car.
Please suggest what I should do.
I've seen this too, when taking several location readings and I haven't moved. You can get variable results with different accuracies.
You could try taking, say, 10 location readings and take the one with the best accuracy and disregard the rest. Then when taking the next reading, make sure it is located at a distance which is twice the accuracy of the previous location. For example, if your first location has an accuracy of, say 16 meters, make sure the next reading is at least 32 meters away from the previous location AND has an accuracy better than 32 meters.
You need to use the minTime and minDistance in combination. You pass zero and zero for both, so the min time between updates will be at least zero seconds and the min distance will be zero. So set minTime to a reasonable time and minDistance to 10 for ten meters.
locationManager_gps.requestLocationUpdates(
LocationManager.GPS_PROVIDER, 0, 0,
new MyLocationListener_gps());
There is no magic bullet to solve this... the gps is not 100% accurate and you will always have different readings every time you get a new location update.
You can minimize the issue using a low pass filter for the location values:
clat = plat + (clat-plat) * 0.2; // you should adjust the 0.2 value to the best results
clon = plon + (clon-plon) * 0.2;
....
//your code
....
plat = clat;
plon = clon;
With this the effect of sudden changes to the values will be minimized, which is good for the fake changes in position, but it will also delay the response to the real changes in the positions when the device is moving. You should choose careffuly the value of the constant multiplying (0.2 above) to have the best results.
You can even do better, using a variable instead of a constant, and adjust the value of it based on the accuracy of the loaction update (good accuracy you make the variable close to 1, pour accuracy you make the variable close to 0)
good luck
Related
i trying to get if location is in my radius.
i.e I have my current location "LatLng" object and i have one more "LatLng" object and i want to check if the two object are in rang of 1km?
How can i implement that?
In Location.distanceBetween() function provide you distance in meters and float value ..
distanceBetween(double startLatitude, double startLongitude, double
endLatitude, double endLongitude, float[] results) Computes the
approximate distance in meters between two locations, and optionally
the initial and final bearings of the shortest path between them.
use this it working i've already checked it .....
float[] dist = new float[1];
Location.distanceBetween(firstLoaction.latitude,firstLoaction.longitude,anotherLocation.latitude,anotherLocation.longitude,dist);
if(dist[0]/1000 > 1){
//here your code or alert box for outside 1Km radius area
}
NOTE:- For getting the location distance always use Location.distanceBetween() which is provide by ANDROID .
double distanceInKiloMeters = (currentLocation.distanceTo(someLocation)) / 1000; // as distance is in meter
if(distanceInKiloMeters <= 1) {
// It is in range of 1 km
}
else {
// not in range of 1 km
}
you can try converting LatLng to Location object for both first and then using distanceTo method to find the distance between those two and check if it is 1km or not
distanceto methode to get distance from locCenter and point and just substitute this distance from the radius if <0 so the point out of range , else the point in border or inside the range.. good luck
I have a litte problem. I located a location.getSpeed() method on the onLocationChanged() method, and .getSpeed() usually doesn't update/change to 0km/h when I stay in same place.
Where should I locate a location.getGpeed() method, that the update showed 0km/h when I stay in place?
And another question. This is my locationListener:
private final LocationListener locationListener = new LocationListener()
{public void onLocationChanged(Location location) {
boolean var = false;
float distance;
if (firstRun) { distance=0; firstRun=false; }
else
distance = location.distanceTo (startLocation);
Tspeed.setText("0km/h");
if (location.getSpeed()!=0)
{
Tspeed.setText(""+(location.getSpeed()*3600/1000 +"km/h"));
}
else
{
Tspeed.setText("0km/h");
}
sAllDistance += distance; //
startLocation=location;
Tdistance.setText(""+(int)SAllDistance+" m");
}
The problem is: when the LocationManager get the fix, the first AllDistance returned from location.distanceTo() is ±50 meters.
How can I fix it?
Actually, GPS wont give exact information all the time. Even if you stay at same place, some times, latitude and longitude vary a little bit. I think it depends on minTime and minDistance you provide to requestLocationUpdates(...) method.
Anyway, once try to change these values like below.
locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER,
1000L(minTime), 2000.0f(minDistance), myLocationListener);
Hope it helps.
Edit:
One more thing you can do is, according to the documentation, location.hasSpeed() returns true if this fix contains speed information, false otherwise. When you stay at same place, it returns false I guess.
Based on this, you can do something like setting value for textView etc.
I have not tried but you can try once.
There are continuous, varying errors in GPS location fixes, due to things like atmosphere, satellite geometry, nearby buildings, etc.
The best you can do if you're trying to determine whether the GPS receiver is stationary or not is to check if the speed is below some credible threshold (e.g. 1kph).
You can do things like digitally filtering the speed value e.g.below is a simple adjustable low-pass filter that smooths out changes in the speed... put in a low value (e.g. 3) and the output will be quite responsive to changes in the input, put in a high value (e.g. 10) and the output becomes heavily smoothed.
/**
* Simple recursive filter
*
* #param prev Previous value of filter
* #param curr New input value into filter
* #return New filtered value
*
*/
private float filter(final float prev, final float curr, final int ratio) {
// If first time through, initialise digital filter with current values
if (Float.isNaN(prev))
return curr;
// If current value is invalid, return previous filtered value
if (Float.isNaN(curr))
return prev;
// Calculate new filtered value
return (float) (curr / ratio + prev * (1.0 - 1.0 / ratio));
}
filtSpeed = filter(filtSpeed, speed, 3);
I am fairly new to Android programming, but I am getting pretty good at it (I think: ))
What I am doing is building a situated stories app. It is an app that places audio files at certain GPS markers and enables the user to listen to them at specific locations.
The next step is moving audio files. What I want to do is set a marker at a specific position in a city. (done). Next I want to check the location of a second marker that moves in a circle around it.
What I have so far is this:
public void checkCircularPosition(){
/*
* could be a solution?
*
radius = 250; //offset in meters
gpsLatCenter = 5.1164; //?how can i make this accurate in meters?
gpsLonCenter = 52.0963; //??how can i make this accurate in meters?
degree = 0; //should be variable over time (full circle in 1Hr, 3600sec --> 360/3600 = 0,1 deg/s)
radian;
radian = (degree/180)*Math.PI;
gpsCircleLat = gpsLatCenter+Math.cos(radian)*radius;
gpsCircleLon = gpsLonCenter-Math.sin(radian)*radius;
*/
}
Now, I have checked this code in adobe flash, which made a movie clip move around in a circle. So I know the calculations are somewhat right. But, I have no way of calculating the latitude and longitude of the resulting coordinates.
EDIT!!
i found the solution with the help posted below. still a lot of work to figure out how to use the results. anyway, i posted the resulting function below.
to make this work, you need _radius wich is 6371 (earth's radius), a bearing, a distance, and a start location.
thanks a lot guys!
public static void destinationPoint(double brng, double dist) {
dist = dist/_radius; // convert dist to angular distance in radians
brng = Math.toRadians(brng); //
double lat1 = Math.toRadians(_lat);
double lon1 = Math.toRadians(_lon);
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));
lon2 = (lon2+3*Math.PI) % (2*Math.PI) - Math.PI; // normalise to -180..+180º
Log.i(APPTAG, ""+Math.toDegrees(lat2));
Log.i(APPTAG, ""+Math.toDegrees(lon2));
Location movLoc = new Location("");
movLoc.setLatitude(Math.toDegrees(lat2));
movLoc.setLongitude(Math.toDegrees(lon2));
Log.i(APPTAG, ""+movLoc);
}
You should check the section Destination point given distance and bearing from start point at this website: http://www.movable-type.co.uk/scripts/latlong.html
That website has the proper formula for using your start point (gpsLatCenter/gpsLonCenter) and bearing (degree in you code) to compute the final lat/lon (gpsCircleLat/gpsCircleLon).
I am trying to pass latitude and longitude to another activity and check the distance between this passed co-ordinates and the current co-ordinate.
In the first activity:
GeoPoint p1 = mapView.getProjection().fromPixels((int) event.getX(),(int event.getY());
setter(p1.getLatitudeE6()/ 1E6, p1.getLongitudeE6() /1E6);
public void setter(Double lati,Double longi)
{
latitude=lati;
longitude=longi;
}
on the button click event i am passing this with the help of a bundle. This works fine.
In the second activity:
public Location selected_location=null;
Double lati,longi;
Bundle b=this.getIntent().getExtras();
lati=b.getDouble("latitude");
longi=b.getDouble("longitude");
Till this much it works fine. I even printed the values. The real issue is the the lines given below:
selected_location.setLatitude(lati);
selected_location.setLongitude(longi);
I am trying to set the passed latitude and longitude values to a location variable. But this is causing the activity to terminate.
If possible please suggest a solution. If the question is childish please ignore.
If you aim to calculate only the distance you do not need to construct Location objects use this method. It is static and works with long and lat values. I can also help debuging the error if you put the stack trace of the exception.
EDIT The requested example:
float myGetDistance(double startLatitude, double startLongitude, double endLatitude, double endLongitude) {
float [] results = new float[1]; // You need only the distance, thus only one element
Location.distanceBetween(startLatitude, startLongitude, endLatitude, endLongitude, results);
return results[0];
}
You can complete the distance between two points given by it coordinates like this:
final float[] results= new float[1];
// The computed distance in meters is stored in results[0].
// If results has length 2 or greater, the initial bearing is stored in results[1].
// If results has length 3 or greater, the final bearing is stored in results[2].
Location.distanceBetween(refLat, refLong, latitude, longitude, results);
final float distance = results[0]; // meter!
You may reuse the results array for later computations. If you need bearing information use declare the result array of size 3, if you do not need it use size 1 and save the time for the computation of the not needed information this way.
Im using this code for getting the location for my app:
LocationManager lm = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
lm.requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 200.0f, this);
But when i tried the app in my real android phone it show this location about 80 kilometers away from the location im actualy at.. How would i make this code more accurate.. I want the result to be way more accurate for what im making..
Im using the onLocationChanged to display it at the map.. Here it is:
public void onLocationChanged(Location location) {
if (location != null) {
//Gets users longitude and latitude
lat = location.getLatitude();
lng = location.getLongitude();
//sets the GeoPoint usersLocation equal lat and lng
userLocation = new GeoPoint((int) lat * 1000000, (int) lng * 1000000);
OverlayItem usersLocationIcon = new OverlayItem(userLocation, null, null);
LocationPin myLocationPin = new LocationPin(userIcon, MainActivity.this);
//Removes the previous location
if(previousLocation != null)
mainMap.getOverlays().remove(previousLocation);
myLocationPin.getLocation(usersLocationIcon);
overlayList.add(myLocationPin);
//refresh the map
mainMap.invalidate();
//Making myLocationPin into the previousLocation just to be able to remove it later
previousLocation = myLocationPin;
}
The call requestLocationUpdates(LocationManager.GPS_PROVIDER, 1000L, 200.0f, this); is asking to be updated no more than once every 1000ms when the location from GPS changes by more than 200.0 meters from the last update. If you want finer precision, try lowering these numbers.
However, you shouldn't be off by 80km. Are you testing this outside with a clear view of the sky?
I think the issue is with rounding. You are using new GeoPoint((int) lat * 1000000, (int) lng * 1000000);, but instead do this:
new GeoPoint((int) (lat * 1e6), (int) (lng * 1e6));
The difference is, the double values were converted to integers before the multiplication. This way the multiplication happens afterwards, and so the digits after the decimal point are maintained.
There are 2 possible answers...
You can either ask for fine permission, this uses nearby wi-fi networks along with GPS in order to get a better track on where you are:
http://developer.android.com/reference/android/Manifest.permission.html#ACCESS_FINE_LOCATION
or you might just be getting bad GPS data. Have you tried to restart the phone? Are you getting the correct location in Google Maps?
Hope this helps.