Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
I want to calculate actual distance traveled by mobile (iOS and Android). I know through google map API, we can find optimum route distance between 2 coordinates. But I want to calculate distance, actual path mobile(in vehicle) has covered.
One Algo I came to know is saving coordinates after x seconds, lets say after 5 or 10 seconds, and then calculate distance between consecutive coordinates, and there sum will give total distance.
I want to discuss better approach of its solution , Is there any better solution?
Edit : How Apps like Nike running app and Uber works?
------------------UPDATE----------------------
There is two major point in your question.
1) get the phone coordinates (which has been treated in the first part of this response)
2) Calculate the real distance between this two coordinates
IMHO, calculus could be done by a web service: calculation based only
on the distance between two coordinates can lead to really wrong result.
Here is an exemple of such a web service
https://graphhopper.com/#directions-api
The demo app: https://graphhopper.com/api/1/examples/
It's based on traffic flow (as many of this tools)
So you have to be careful with the order of the coordinates
because it can bring wrong result.
For exemple with two point in the right order:
This gives a good result
But if you give wrong order (with the same coordinates)
For the same coordinates, it can lead to an extremely different result.
So for coordinates ABCD (in chrnological order)
you need to do:
A->B B->C C->D
Graphhopper seems able to do offline distance calculus
Here are the lib on iOS and Android
https://github.com/graphhopper/graphhopper-ios/
https://github.com/graphhopper/graphhopper/tree/master/android
---------------------------------------------------
You have to define how your app work. Foreground or background?
As said in other responses, you'll have to get the user position every X seconds. Then calculate the distance.
For iOS:
You can use information on this website: http://mobileoop.com/
It talks about tracking user location on iOS when the app is in background.
Here is the github: https://github.com/voyage11/Location
Then you have to convert the point thanks to
CLLocationDistance distance = [aCLLocationA distanceFromLocation:aCLLocationB];
You can also check this (from apple doc) https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/LocationAwarenessPG/CoreLocation/CoreLocation.html:
Make sure the location manager’s pausesLocationUpdatesAutomatically property is set to YES. When this property is set to YES, Core Location pauses location updates (and powers down the location hardware) whenever it makes sense to do so, such as when the user is unlikely to be moving anyway. (Core Location also pauses updates when it can’t obtain a location fix.)
Assign an appropriate value to the location manager’s activityType property. The value in this property helps the location manager determine when it is safe to pause location updates. For an app that provides turn-by-turn automobile navigation, setting the property to CLActivityTypeAutomotiveNavigation causes the location manager to pause events only when the user does not move a significant distance over a period of time.
CLActivityTypeAutomotiveNavigation insure you to get a position which is on a road.
For Android:
You can use this project:
https://github.com/quentin7b/android-location-tracker
That can easily helps you to get the user's position thru time
Thanks to the TrackerSettings object
TrackerSettings settings =
new TrackerSettings()
.setUseGPS(true)
.setUseNetwork(true)
.setUsePassive(true)
.setTimeBetweenUpdates(30 * 60 * 1000)
.setMetersBetweenUpdates(100);
To find the distance between two point on Android, you can check this:
Get the distance between two geo points
Both OS
Based on a position picked up every X second you have to reduce time between picking location data to improve accuracy.
As you want to calculate distance on a road context, setup the Location manager in navigation mode, this mode gives you coordinates that are on road.
Finally
If you want to improve the accuracy of your distance calculus,
you can use a google API:
https://developers.google.com/maps/documentation/distance-matrix/intro
By setting the right mode parameter:
Optional parameters
mode (defaults to driving) — Specifies the mode of transport to use when calculating distance. Valid values and other request details are specified in the Travel Modes section of this document.
I'm working on something similar on Andoriod, but the principals are the same for iOS either:
For each GPS sample, check its accuracy. If it's over some threshold (say 20 meters) - ignore it.
Remember that even if the mobile device is static, different GPS samples will give you different locations, depending on the accuracy. A car standing still for a long time in a traffic light, will show that you've advanced few dozens of meters, so add a method that detects if the mobile is static or not. I've implemented this by reading the accelerometer - if the delta between two readings if bigger than some threshold - the device is moving. If it's too small - ignore the GPS.
If you intend to use it in a car, you can read the GPS whenever it has a new reading (in Android use the onLocationChanged method). If you use it for running/walking, take into account that your speed is slow - two consecutive readings will be relativly close, but due to the GPS's accuracy, you can get quite a large distance betwwen them. It can be fixed by increasing the time between two consecutive readings, or by ignoring some of them (i.e. take into account only each 10th reading).
Use the Haversine formula to calculate the distance between two consecutive readings. In Android it can be done with the Location.distanceTo() method.
You'll have to test it against the odometer in your car and adjust the thresholds for the accelerometer.
4 years ago, I just made an app called Landsurvayor that calculates the actual distance of two geo-graphical points drawn on Google Map. I don't know that might help you or not but there is a formula called Haversine formula that calculates the actual distance between two geo-graphical points. You might give it a try and see whether it is useful for you or not. Below is the sample code of Haversine formula:
public double CalculationByDistance(double initialLat, double initialLong,
double finalLat, double finalLong){
int R = 6371; // km
double dLat = toRadians(finalLat-initialLat);
double dLon = toRadians(finalLong-initialLong);
lat1 = toRadians(lat1);
lat2 = 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.atan2(Math.sqrt(a), Math.sqrt(1-a));
return R * c;
}
public double toRadians(deg) {
return deg * (Math.PI/180)
}
More about Haversine formula:
https://en.wikipedia.org/wiki/Haversine_formula
There is another simple Android SDK built-in approach to calculate distance between two lat, lng:
Location locationA = new Location("point A");
locationA.setLatitude(latA);
locationA.setLongitude(lngA);
Location locationB = new Location("point B");
locationB.setLatitude(latB);
LocationB.setLongitude(lngB);
distance = locationA.distanceTo(locationB) ;
I hope it might help you.
You can achieve more accuracy with a combination of the following strategies.
As mentioned in other Answers, you can store the position of the mobile
every X seconds(say 10 seconds) using GPS and measure the
consecutive time between the points.
Also when the user makes quick turns, make sure to read that by
using Magnetic Sensor values too, so in such event, decrease the
"timing between position storing" to say 1-2 seconds(Will be needed for accuracy)
As a final step, use Map data(such as Google Maps etc.) to make sure
you are being tracked properly(if on road).
And then sum up all the values to get the accurate distance.
P.S. I gave information about the strategies alone since I'm not sure about its implementation in Android(or iOS).
Hope this helps :)
One problem with using GPS coordinates is that they (obviously) are not accurate. If you are travelling in a straight line, the GPS coordinates might show you travelling on a zig-zag path, hence returning a greater distance travelled than the true distance. Even with good GPS accuracy this error can be significant. Using less coordinates could result in a more accurate calculation, or not.
What you need is a way to smooth the GPS path plotted, with due consideration to your required accuracy (again a trade-off).
My first thought is to break the points into groups, and fit line segments to each group (look up "linear regression"). Then find where each consecutive line-pair overlap to define each line segment. Then simply sum the line segment lengths.
You could curve-fit segments, but that's much more intense mathematically, and might not yield a better result (and which curve formula to use?). There may be better mathematical ways I'm not aware of.
Hope this helps.
If you are looking for exact (or nearly exact) distance information, you need to track the path followed, which means checking coordinates every few seconds (depending upon expected speed traveled). You can save space by discarding the old coordinates after calculating each segment and just storing current distance traveled.
Android :: how to calculate distance while walking in android?
There are different ways to do this:
1.GPS: Keep adding GPS distance between 2 points every X seconds (say 10 sec). Check Android Location.distanceTo or distanceBetween. Check
My Tracks app, it is open source. GPS is not available indoors and
would have error if user is changing direction very frequently (read
every 1-2 second)
2.Accelerometer: Look for code/library for step detection using accelerometer. Distance comes from double integration of acceleration,
errors can add up very quickly here.
3.Step detector: Built-in in Nexus 5. Google must have taken care of accelerometer errors to extent possible. This is hardware-based
computation, consumes less battery but not available in most of
handsets as of date.
The 2nd option seem very similar to what you suggested and I do think its the best way to achieve it since iOS and Android defer in code and in functionality therefor the best method to achieve it is saving currentLocation and previousLocation in a while loop that will .sleep() and just sum the entire loop as the distance traveled.
the bigger question is this supposedly app is a distance summerizing app? does it just a small function inside of it? how do you decide when to stop calculating the distance?
If accuracy is critical, you can use data from accelerometer and gyroscope. You can find very simple formula for solving simple cinematic task so you get acc in global axis. Than you just have to use integral twice (first to get velocity, than to get position).
Just to show another perspective.
Use GPS to get lat lon of both places and after getting both pass it below method.Its will return distance in km
public static double getDistanceFromLatLonInKm(double lat1, double lon1,
double lat2, double lon2) {
double R = 6371; // Radius of the earth in km
double dLat = deg2rad(lat2 - lat1); // deg2rad below
double dLon = deg2rad(lon2 - lon1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2)
+ Math.cos(deg2rad(lat1)) * Math.cos(deg2rad(lat2))
* Math.sin(dLon / 2) * Math.sin(dLon / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c; // Distance in km
return d;
}
public static double deg2rad(double deg) {
return deg * (Math.PI / 180);
}
}
Log points every x seconds (maybe 2-3?) and use distance formula below for every point logged.
Distance = sqrt((x2−x1)^2+(y2−y1)^2)
Sum them all up and you get distance
Related
I'm looking to detect some basic movement gestures using real-time accelerometer data (from the phone). My problem is that I need something generally "rotation invariant".
What I mean is that if user holds the phone upside down, then does a gesture, it won't be the same signal. Given a specific orientation, I know how to compare the real-time acc data to a given "template" of a gesture.
But what about for other orientations? E.g. the user holding the phone upside down (alright, this is easy as I can do the same basic comparison treating one axis as another) or harder yet, somewhere in-between?
As soon as the acceleration values do not change (or stay within a defined range) for some time (for instance 1 sec) you could assume that the user is in a steady position and store those values. If the values go out of that range, you can subtract the previously stored values from the new ones. That is assuming that you problem is gravity, and that you mean "orientation invariant"... right?
For a very simple case, where you just need the z-axis acceleration to have a peak:
x_wanted = 0
y_wanted = 0
z_wanted = 10
Your user in a steady position, with the device tilted at 45 degrees:
x_rest = 0
y_rest = sin(45) g
z_rest = -cos(45) g
and then brings the phone towards him, i.e z-axis (phone reference) being 10:
x_phone = x_measured - x_rest = (0) - 0 = 0
y_phone = y_measured - y_rest = (sin(45)*g) - sin(45)*g = 0
x_phone = z_measured - x_rest = (-cos(45)*g + 10) - (-cos(45)*g) = 10
It sounds like your problem is a basic transformation of coordinates. The first thing I would do is blow off the Cartesian coordinates in favor of spherical coordinates. The big advantage in doing this is the spherical radius (or vector magnitude, in cartesian-speak), which will be the same regardless of the orientation of the axes. The radius is calculated
r = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2) + Math.pow(z, 2))
A very simple way to normalize the two coordinate systems is to compare the radius of each as two time-series. This should at least eliminate a lot of the cruft, and might perform as well as you need in terms of motion identification.
Now if you really want to compare the motions in all directions, maybe after you've already found a candidate based on the radius time-series, look at Euler angles. You'll have to do some multivariate regression, but with three channels of data, three governing equations, three unknowns (alpha, beta, and gamma), and linear algebra, you can normalize all three channels in an unknown orientation back to your template orientation, and compare each channel individually.
This question already has an answer here:
How do I work out the future position of a moving object? [closed]
(1 answer)
Closed 10 years ago.
I have asked this question previously and it was closed due to it not being a programming question, this is entirely as I worded it wrong. I would like this to implemented into java. I am creating a little game and I have a photon torpedo which is being fired from a ship towards a target. Now as the speed of the torpedo is slow the ship will never hit any targets if they're moving and I want to fix this. I have drew up multiple theories and mapped out lots of mathematical stuff to find out the best way to accomplish this and in the end I deduced the following:
I find the time it takes for the photon torpedo to get to the target.
I find how far the target will have traveled in the time it takes for the torpedo to arrive.
I then find the distance between the new position of the target and the original ship.
this then gives me the opportunity to use the Cosine rule (SSS) to find out the trajectory at which the bullet needs to be fired to have a much higher chance of hitting.
Here is a digram:
Now the only problem that I need to rotate line a to the correct orientation as by default it's parallel to line c which messes up the entire equation. Can anyone help with this? And also if you can think of a better way to find the new position suggestions are very welcome. My java game entity mechanic works as follows:
Each entity has two Vectors which control movement. Position and Velocity. However, velocity is not tracked entirely properly as instead of it being a speed and a direction, to make things easier it's an xSpeed and a ySpeed.
The entities are all updates once per tick and the ship which shoots the torpedo must calculate the future position in this one tick and not over multiple ticks.
I ask this question not to be closed again, because this time I really need the answer to be implemented into Java.
This is the math i've tried so far:
double dis = level.distanceBetween(photonTargetTop, this);
double speed = 5;
double time = dis / speed;
double d1 = photonTargetTop.velocity.x * time;
double d2 = photonTargetTop.velocity.y * time;
double dis2 = level.distanceBetween(this, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double dis3 = level.distanceBetween(photonTargetTop, photonTargetTop.pos.x + d1, photonTargetTop.pos.y + d2);
double cosAngle = Math.pow(dis2, 2) + Math.pow(dis, 2) - Math.pow(dis3, 2) / 2 * dis2 * dis;
double angle = Math.acos(cosAngle);
EntityPhoton p = new EntityPhoton(this, level);
p.rotation = angle;
level.addEntity(p, pos);
Let's assume the target ship has no acceleration, meaning that it's speed and direction is not changing.
Let's also assume that once fired, your torpedo has no acceleration. And it always goes at constant speed.
Let's also call (0,0) the point where your torpedo is fired.
The ship describes a straight line. Choose a point on this line (if the ship is following a course that does not go through (0,0) you can find the closest point to the central position with some geometry that you can look up on wikipedia).
Once you have chosen the position where you want to hit the enemy ship, you know the distance between (0,0) and that position, and given that the speed of the torpedo is always the same, you can also know when to fire the torpedo.
Then you must also find the direction, meaning the values of speed to give on x and y, but that's not so difficult.
In general the problem is a system with multiple solutions, so presuming that the torpedo is faster than the target, there are infinite points where you can hit it, so you must use some heuristic to choose a point that's convenient to you.
I have around 1000 points. I'm trying to group this points base on distance. Im using the harversine formula, but it seems to be super slow. In android for 1000 points takes 4 seconds. In my local environment takes 60 ms.
I do not care about precession and the points are no more than 25 km apart.
Is there another formula I can use?
First, for items that close to each other, curvature of the Earth is not going to matter too much. Hence, you can treat it as flat, at which point you're looking at the Pythagorean Theorem for distance (square root of the sum of the squares of the x/y distances).
Second, if all you are doing is sorting/grouping, you can drop the square root calculation and just sort/group on the square of the distance. On devices lacking a floating point coprocessor, such as the first couple of generations of Android phones, that will do a lot of good right there.
Third, you don't indicate the coordinate system you are using for the points, but if you can do your calculations using fixed-point math, that too will boost performance, particularly on coprocessor-less devices. That's why the Google Maps add-on for Android uses GeoPoint and microdegrees rather than the Java double degrees in the Location you get back from LocationManager.
So long as you don't need to cope with near the polls and an aproximation is OK which for grouping it should be. Then you can work out the relative scaling between the lattitude degrees and the longitude degrees just the once and use it for every straight X squared + y squared calculation, for relative distances you can skip the square root.
If your working with degrees to scale them to be the same relative distance for lattitude and longitude you use cos of the lattitude. I would scale the latitude to the longitude then each degrees map to a good knowen distance the calculation will will be something like.
(lattitude diference for two points) * 1/cos(latitude)
You work out the 1/cos(latitude) just the once for all points assuming the latitude is not changeing much over your sample set.
Perhaps remove the calculation of the curvature of the earth..?
If the functionality of your app permits this, do so.
This format always holds true. Given two points, you can always plot them, draw the right triangle, and then find the length of the hypotenuse. The length of the hypotenuse is the distance between the two points. Since this format always works, it can be turned into a formula:
Distance Formula: Given the two points (x1, y1) and (x2, y2), the distance between these points is given by the formula: http://www.purplemath.com/modules/distform.htm
Distance = sqrt( (x2 - x1)^2 + (y2 - y1)^2 )
Update with correct notation:
double distance = Math.sqrt(Math.pow(x2 - x1, 2) + Math.pow(y2 - y1, 2));
As far as I know, best way to do this is to use Graph Theory, and it has Dikstra's algorithm , it's the fastest algorthm in my knowledge for this kind of task.
Really worth learning, optimizes work very well.
Alright, this is probably gonna be a pretty simple question to answer. I haven't had a math class dealing with logarithms in a few years, so I apologize. So I have a USB Controller that I'm using to control the mouse on the screen with the left joystick. Now how this works right now is the controller returns a double between 0.00 and 1.00 depending on how far the push the joystick in the direction (0.00 center, 1.00 pushed all the way over). I'm using this to adjust the speed of the mouse movement by multiplying the returned value by a given speed (returned double * speed). This gives me a linear speed. But for the purpose of accuracy of the mouse and clicking things on screen, I'd like it to be more logarithmic, so as it's really slow when barely pushing, and then the speed increases logarithmically as you move the joystick farther. That way you can get good speed for moving across the screen, while also having good sensitivity when moving it slowly. So I just need help with the formula, as I'm sure it's pretty simple. Also, I'm working in Java.
Right now my formula is:
double value (value given by controller)
int speed = 25;
value += value * speed;
I then use this to move the mouse.
Thanks,
Brayden
I presume you meant exponential. An exponential function looks like http://hotmath.com/images/gt/lessons/genericalg1/exponential_graph.gif: the more value is, the larger the derivative (the more speed will increase for the same change in value).
double value = ...;
int base = 25;
value = java.lang.Math.pow(base, value);
Not sure if java.lang.Math is necessary in its full form or whether you need to import java.lang.Math first. I'm not a Java programmer.
I agree with MvanGeest, I think you want an exponential formula. That way its small with little distance, and very big with larger distances.
I'm not sure what mouse speed values are fast or slow, but you could do something like
double value (value given by controller);
int speed (maximum speed value);
value = Math.pow(speed, value);
You could also make the value something like 2*(whatever the controller gives you) to make a wider range of speeds.
Something like:
f(value) = value * MAXSPEED * Math.Pow (base, 1 - value)
f(0) = 0 // no movement
f(1) = MAXSPEED // maximum movement when joystick is full throttle
All values should be covered in the range. Base in this case can be any value greater than 1.
Our VB.NET project is using a Java library from Vivid Solutoins (com.vividsolutions.jts.geom.Geometry) to do Geometry calculations. The help is here: http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/geom/Geometry.html
What I can't figure out are the units specifically for the Buffer property, or any other distance for that matter. My program is dealing with Nautical Miles, and the documentation gives no indication if the units are degrees, miles, Nautical Miles, Kilometers, inches, etc.
Has anyone used this library who knows the answer? Thanks in advance.
First of all, I don't know this API, I've just browsed the link you've given.
Judging by the Javadocs for Coordinate, it says:
[Coordinate is a] lightweight class used to store coordinates on the 2-dimensional Cartesian plane. It is distinct from Point, which is a subclass of Geometry. Unlike objects of type Point (which contain additional information such as an envelope, a precision model, and spatial reference system information)
So it would seem that Geometry has no units as such, but Point, its subclass, does, and you can specify them.
I wouldn't be surprised if the Geometry class doesn't have any units as such, and just represents the concept of a point in space in any particular coordinate system.
This is an old post, but here is the answer for anyone else who is looking, since incredibly the java docs do not state the units returned by the method. The distance returned is in central angle degrees. You can then use any number of formulas to convert to your required unit of measure. The simplest is to convert to radians. 1 radian = 180 degrees divided by pi (rad=180deg/pi). From there, you can multiply radians by the average radius of the earth in your choice of units (6371 km for instance) to get distance between two points. More accurate methods are also available, but you can look them up on the net.
I confirmed with one of the author's of the library, and by testing it myself using geospatial files with different projections, that the distance units depend on the source file's CRS. This is covered in their FAQ here: https://locationtech.github.io/jts/jts-faq.html#B5
A quick way to find this is to look up the EPSG code at http://epsg.io/ and find the units. For example, EPSG 3347 has units of metres.
As I recently worked on this library (http://tsusiatsoftware.net/jts/javadoc/com/vividsolutions/jts/geom/Geometry.html) and after investigation I found that the unit distance returned when call some of the methods distance calculation with this api will be in degree unit. To convert it to kilometer, assumes that value returned is d then you need to convert it to radian and multiply with earth radius 6371km. The formula would be d / 180 * PI * 6371.