I have inherited a code and it has this small function written to calculate distance between two points.I'm wondering , what it does. I know the lat long data is in decimal degrees. Could anyone please throw some insights, if this calculation is right?
private double calculateDistance(QuoteItem quoteItem, RouteInfo routeInfo) {
final double distance =
((Math.max(routeInfo.getLatitude(), quoteItem.getLatitude()) - Math.min (routeInfo.getLatitude(), quoteItem.getLatitude())) +
(Math.max(routeInfo.getLongitude(), quoteItem.getLongitude()) - Math.min(routeInfo.getLongitude(), quoteItem.getLongitude()))) * 60.0;
return distance;
}
This is a variant of the Manhattan distance calculation where it's not a true Euclidean hypotenuse distance calculation, but rather a simple sum of the two sides of the right triangle multiplied by some multiplier, 60. I usually see it written more simply as
Math.abs(p1.x - p2.x) + Math.abs(p1.y - p2.y)
Which is essentially what your calculation is, except you're also multiplying it by some scaling factor, 60.0.
I've used this in programs where I want to get a quick and dirty estimate of distance with an emphasis on quick since it involves no square roots. For instance, I used it once for very rough (and incorrect but correct enough for the purposes) calculation of the differences between pixel colors, where I had to make this calculation repeatedly for the pixels contained two images, in real time, and where need for speed trumped the need for accuracy.
Related
Say I have calculated the euclidean distance between two images using colour as a feature and also calculated the distance between the two images using their edges. I want to test to see if combining these two distance values will give a better representation of how similar the images are. To combine these two distance measures is it as simple as colourDistance + edgeDistance / 2? Or is there a more sophisticated way of combing distance values?
Any function of colourDistance and edgeDistance could work. You could think of what you described as testing three possible functions:
f1(colourDistance, edgeDistance) = colourDistance
f2(colourDistance, edgeDistance) = edgeDistance
f3(colourDistance, edgeDistance) = (colourDistance + edgeDistance) / 2
You could, in theory, test any other function. One thing that comes immediately to mind is linear combinations:
g(colourDistance, edgeDistance) = w1 * colourDistance + w2 * edgeDistance
For various values of w1, w2. This will allow you to experiment with the visual importance of the two features. Your f3 is one case of this function, with w1=w2=0.5
You might found out that the weight of the features isn't linear, for example, a 1-point difference for very small values is much more (or less) significant than a 1-point difference for large values. You could try functions like:
h(colourDistance, edgeDistance) = w1 * log(colourDistance) + w2 * log(edgeDistance)
Final advice, it's not clear to me if the distances you have are on the same scale. If one distance metric goes from 0-10 and the other from 0-1000, you probably need to either normalize the values, or compensate by the choice of w1 and w2.
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.
If I have an object with properties of x an y, how can I tell which point in an array is the closest without using the distance formula?
You can't get an accurate result without using some variant of the distance formula. But you can save a few cycles by not taking the square root after the fact; the comparison will remain valid.
r = dx2 + dy2
If you don't care about the exact distance, you could perhaps take the difference between the x and y coordinates of your source and destination points to provide you with some ordering.
//The following code does not return the closest point,
//but it somewhat does what you need and complies with
//your requirement to not use the distance formula
//it finds the sum of x and y displacements
Point destination=...
Point nearestPoint= points.get(0);
for (Point p : points){
closenessCoefficient= Math.abs(destination.x-p.x) + Math.abs(a.destination-p.y);
nearestPoint=Math.Min(closenessCoefficient, nearestPoint);
}
return nearestPoint;
If you have to find exactly the closest neighbour, there is no way around evaluating the distance formula, at least for a couple of points. As already pointed out, you can avoid evaluating the expensive sqrt for most of the time when simply comparing the distance-squared r^2 = x^2 + y^2.
However, if you have a big number of points spread out over a large range of distances, you can first use an approximation like the ones shown here http://www.flipcode.com/archives/Fast_Approximate_Distance_Functions.shtml . Then you can calculate the real distance formula only for the points closest as given by the approximation. On architectures where also the multiplication is expensive, this can make a big difference. On modern x86/x86-64 architectures this should not matter much though.
I'm practicing some simple 2D game programming, and came up with a theory that during animation (the actual change in a image position is best calculated with floating point numbers). I have a feeling that if you move an image around with ints the animation won't be as smooth.
In Java it seems you can't draw an image with floating point numbers to give an image a position. But apparently when you initially declare your x and y 's, you can declare them as Double, or Float, and when it comes to actually drawing the image you have to cast them to ints. Like I find HERE :
/**
* Draw this entity to the graphics context provided
*
* #param g The graphics context on which to draw
*/
public void draw(Graphics g) {
sprite.draw(g,(int) x,(int) y);
}
My question is about how Java handles the conversion?
If the code casts these doubles at the last minute, why have them as doubles in the first place?
Does Java hide the numbers after the decimal?
I know in C and C++ the numbers after the decimal get cut off and you only see whats before it. How does Java handle this casting?
Pixels on a display are discrete and limited in number; therefore display coordinates need to be integer numbers - floating point numbers make no sense, as you do not physically have a pixel at e.g. (341.4, 234,7).
That said, integers should only be used at the final drawing stage. When you calculate object movement, speeds etc, you need to use floating point numbers. Integers will cause an amazing number of precision problems. Consider the following snippet:
a = 1;
x = (a / 2) * 2;
If a and x are floating point numbers, x will finally have the expected number of 1. If they are integers, you will get 0.
Baseline: use floating point types for physics computations and convert to int at drawing time. That will allow you to perform the physics calculations with as much precision as required.
EDIT:
As far as the conversion from FP numbers to integers is concerned, while FP numbers have a greater range, the values produced by your physics calculation after normalization to your drawing area size should not normally overflow an int type.
That said, Java truncates the floating point numbers when converting to an integer type, which can create artifacts (e.g. an animation with no pixels at the rightmost pixel column, due to e.g. 639.9 being converted to 639 rather than 640). You might want to have a look at Math.round() or some of the other rounding methods provided by Java for more reasonable results.
Java truncates the decimals. Eg:
(int) 2.34 == 2
(int) 2.90 == 2
The reason for not being able to draw at a floating position is simply that there's no half pixels etc :)
Java casts floats to int by dropping the decimal. But I don't think having x and y coordinates in floats make any sense. You have pixel on the screen which cannot be presented in anything less than one pixel. For example you can't draw a pixel .5px x .5px because on the screen it will just be 1px x 1px pixel. I am not a computer game programmer but I have written one animation engine in Java and it was very smooth. I can share this if you'd like.
Note that you should draw using ints but do all your calculation using doubles. For things like rotating or anything that relies on a mathematical formula should be done in decimal.
The reason x and y need to be doubles is for when they need to be computed mathematically, for example:
x += (delta * dx) / 1000;
You want to avoid overflows and loss of precision up until you paint the pixel.
I have some code doing this right now. It works fine with small to medium sized lists, but when I have a list of size n > 5000 then the my algorithm can take almost 1 minute on a mobile device to run. I'm basically comparing a Coordinate object in Java to a list (Vector) of Coordinate objects.
Here's my basic algorithm:
traverse each element in the list nx
if there is less 10 items in the "10 closest" list then add nx to the list
and go to the next element
if the "10 closest" list has 10 items already, then calculate the
distance between nx and the base
Coordinates
if the distance is less than furthest distance in the "10 closest
list" then remove the furthest item
from that list and replace it with nx
I keep looking at this and am trying to find a more efficient way of doing this. It's sort of like a sorting algorithm problem so there must be a better way.
Here is my distance calculation method:
public static double distance(double lat1, double lon1, double lat2, double lon2, char unit) {
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 = acos(dist);
dist = rad2deg(dist);
dist = dist * 60 * 1.1515;
if (unit == 'K') {
dist = dist * 1.609344;
} else if (unit == 'N') {
dist = dist * 0.8684;
}
return (dist);
}
You could store your coordinates in some space partitioning tree.
Or, for a simpler approach, you could use a two-dimensional array of buckets, and check the closest buckets first, until you found enough nearest neighbors. This only works well if the coordinates are distributed evenly.
Edit: To compare the distances you could precompute 3D coordinates on the sphere and use the square of the Euclidean distance in the comparisons:
dx * dx + dy * dy + dz * dz
Well, maybe it would be faster to do this with arrays. And you could compare the square of the distance instead of the distance, which means that you don't have to work with square roots.
It would be good to have the actual code.
You might be able use something like the approach at this website to restrict the number of points that actually require you to compute the distance.
The website shows how to compute the lat, lon bounding coordinates for a point and a given distance. That is not exactly the same problem that you have, but it could serve as a filter. In your case you are apparently trying to find the 10 (or n) closest points to a given point. You could apply the following algorithm to find the 10 (or n) closest points:
For the first n points, you could go through the full-blown distance
calculation that you have, saving the distance along each point.
Save the overall longest distance. Compute the lat, lon bounding
box as illustrated on the website above.
Continue through the rest of your points.
If any point is outside of the lat, lon bounding box, it cannot be
closer than any of the current 10 closest points. If it is inside
the bounding box, calculate the distance.
Discard the farthest of the previous set of 10 "closest" points.
Recompute the lat, lon bounding box based on the new farthest point.
Repeat until all points processed.
The benefit of this approach is that you might be able to avoid heavy calculations for a large number of your points. Depending on the distribution of your points, you could still suffer from poor performance, such as if the points turn out to be ordered such that they are in decreasing distance from your target points (point[0] is the farthest and point[N] is the closest)).