I am having a list of co-ordinates that represent the path, and source and destination coordinates. So, using spatial4j,JTS,GeoTools or any other library how to calculate the distance between two points(source & destination) over a predefined path(list of coordinates).
Below is the sample which I have tried using spatail4j which is a straight line distance. But the same thing how we can achieve over a path I have used spatial4j but using different libraries like JTS,GeoTools etc.,
public static void main(String[] args) {
SpatialContext ctx = SpatialContext.GEO;
Point p1= ctx.getShapeFactory().pointXY( 77.610099,12.91502);
Point p2= ctx.getShapeFactory().pointXY( 77.59038,12.917055);
System.out.println(ctx.getDistCalc().distance(p1, p2) * DistanceUtils.DEG_TO_KM);
}
// output: 2.149124512680105
Below are the route/path geopoints:
12.91502 , 77.610099
12.91502 , 77.610092
12.913957 , 77.610069
12.913954 , 77.610033
12.91644 , 77.610048
12.916573 , 77.605512
12.916618 , 77.603053
12.916622 , 77.601803
12.916652 , 77.600092
12.916735 , 77.597653
12.916896 , 77.590946
12.916927 , 77.590242
12.916936 , 77.589467
12.917083 , 77.589466
12.917055 , 77.59038
According to the google map the value should be 2.8Km. Is there any other java library using which we achieve the same thing as the resource for spatial4j is very less.
If you want precision, then you should probably go to Haversine Formula, luckily enough, you can always find a useful solution browsing the web
public static Double getDistance(Double lat1, Double lon1, Double lat2, Double lon2) {
final int R = 6371; // Earth Radius in km, use 3959 if you want in miles
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));
return R * c;
}
I've actually just adapted this to your use-case.
public static void main(String[] args) {
ArrayList<Point> points = new ArrayList<>();
points.add(new Point(1, 0));
points.add(new Point(2, 0));
points.add(new Point(3, 0));
int distance = 0;
for (int i = 1; i < points.size(); i++) {
Point smaller = points.get(i-1);
Point bigger = points.get(i);
distance += Math.sqrt(Math.pow(bigger.x-smaller.x, 2)+Math.pow(bigger.y-smaller.y, 2));
}
System.out.println(distance);
}
It can work like this. Use Pythagoras for the distance between Point 1 and 2, then Point 2 and 3. At the end add up all those calculated distances.
Other responses I see here are good, #Luiz's is simple and straightforward, and #8bit's is more precise.
No matter which implementation of them you choose (or even the one you provide in the question itself ctx.getDistCalc().distance), I'd like to give an insight for the problem it seems you're struggling the most: how to apply and accumulate the results of your distance function over the whole list?
IntStream.range(0, path.length)
.map(i -> i == 0
? 0.0d
: ctx.getDistCalc().distance(path[i - 1], path[i]))
.sum()
* DistanceUtils.DEG_TO_KM;
This assumes path is an array with your points.
More info on streams here.
Related
I have to write a program in which I write a,b c,d (coefficients of equation 3 degree) and as a result I should get X1, X2, X3 (solutions of equation). I have to use Viete's formulas and BigDecimal for this, because my lecturer requires it from me.
I came to the conclusion that I have to solve the following system of equations:
x1+x2+x3=-b/a
x1*x2+x1*x3+x2*x3=c/a
x1*x2*x3=-d/a
I have no idea how I can do it in Java.
I tried to use the JAMA package, but I don't think I can use it to solve such a system of equations.
How can I do that?
If you want to find the roots of a cubic polynomial in Java you can do it easily using Newton-Raphson's method.
The algorithm -
1. Input: initial x, func(x), derivFunc(x)
Output: Root of Func()
2. Compute values of func(x) and derivFunc(x) for given initial x
3. Compute h: h = func(x) / derivFunc(x)
4. While h is greater than allowed error ε
- h = func(x) / derivFunc(x)
- x = x – h
Here is a demonstration for solving the cubic equation x^3-x^2+2
class XYZ {
static final double EPSILON = 0.001;
// An example function whose solution
// is determined using Bisection Method.
// The function is x^3 - x^2 + 2
static double func(double x)
{
return x * x * x - x * x + 2;
}
// Derivative of the above function
// which is 3*x^x - 2*x
static double derivFunc(double x)
{
return 3 * x * x - 2 * x;
}
// Function to find the root
static void newtonRaphson(double x)
{
double h = func(x) / derivFunc(x);
while (Math.abs(h) >= EPSILON)
{
h = func(x) / derivFunc(x);
// x(i+1) = x(i) - f(x) / f'(x)
x = x - h;
}
System.out.print("The value of the"
+ " root is : "
+ Math.round(x * 100.0) / 100.0);
}
// Driver code
public static void main (String[] args)
{
// Initial values assumed
double x0 = -20;
newtonRaphson(x0);
}
}
Output - The value of root is : -1.00
To do it your way you have to solve a system of non-linear equations which is harder but can be done using the Newton Raphson's Multivariate method. You might want to look it up. Also note that this is an approximate method and guesses the roots after you put an initial 'guess' of your own (in this case its -20)
The Newton (Raphson, Kantorovich) method for the Viete equations gives you the (Weierstrass-)Durand-Kerner method of simultaneous root approximation. However, in the completed method you will no longer see the Viete identities, they kind of cancel out. You will need complex numbers over the demanded real numbers data type.
If you go with the simple Newton method like in the other answer, then after computing the one real root you can split off the linear factor belonging to it via the Horner-Ruffini scheme and then solve the remaining quadratic equation directly. Then you only need to consider the possible complex nature of the roots in constructing the output strings, as the real and imaginary parts have easy direct formulas.
At first I tried something like this:
Ray ray1 = new Ray();
Vector3f originRay1 = new Vector3f(0, 0, 1);
ray1.setOrigin(originRay1);
Vector3f directionRay1 = new Vector3f(0, 0, -1);
ray1.setDirection(directionRay1 );
Ray ray2 = new Ray();
Vector3f originRay2 = new Vector3f(1, 0, 0);
Vector3f directionRay2 = new Vector3f(-1, 0, 0);
ray2.setDirection(directionRay2 );
ray2.setOrigin(originRay2);
CollisionResults results= new CollisionResults();
int collide = ray1.collideWith(ray2, results);
But that throws an UnsupportedCollisionException, so it's not something that can be calculated using two Ray objects.
To be honest I don't know what I expected when I tried this. There can't be any line collision algorithm without taking into account a delta / margin of error of some sort or a different kind of result altogether by, for example, returning the shortest vector between the two lines. Or at least such an algorithm wouldn't make much sense to me!
In any case I also looked into classes Line and LineSegment but they don't implement the Collidable interface. Then I looked for some candidate that does implement Collidable and resembles a line, but I don't see a clear candidate.
I'd rather do it using jme3 or the JDK libraries if possible, but I'm open to read other suggestions.
As mentioned before I would have to take into account the precision somehow. For example, there would be an intersection if the distance between the lines is below a 'delta' that I pass as parameter and then it returns the point on one of the lines if the shortest distance between the lines is less than that delta.
A safe way is to compute the shortest distance between the two lines.
This is easily done by taking the cross product of the direction vectors of the two lines, which gives the direction of the common perpendicular, normalizing it then computing the scalar product of this vector with any vector from a point of the first line to a point of the second.
Let the vector equations be
A1 + t1 D1
A2 + t2 D2
Then the distance:
d12 = |(A2 - A1).(D1 x D2)| / |D1 x D2|
If the lines are given by points PQ and RS,
d = |(P - R).((Q - P) x (S - R))| / |(Q - P) x (S - R)|
I think it could be useful to someone else if I posted here my Java implementation, which is nothing more than the translation of this c implementation as suggested in the comments above and some unit tests.
I also believe the result is more readable than the original, it throws exceptions when the arguments are invalid instead of returning a null kind of result and the scope of variables is reduced.
A couple of observations about the code:
I understood the epsilon EPS in the original version as the minimum distance between the coordinates of two points in order to define a line. I already use such a constant with the long, explicit name NUMBERS_SHOULD_BE_DIFFERENT_DELTA which is the minimum distance needed between two points so that loss of precision in calculations don't have an adverse effect in the result. I believe in general another such delta is needed in applications with geometry calculations when comparing whether points are almost equal. Hence the long name to differentiate them.
LineSegment3D class, not included here, is just a thin wrapper for jme3's LineSegment in case you are wondering why I'm using jme3 and not jme3's LineSegment.
Not relevant to the question, but the reason for this is that I prefer to distinguish between the semantics of vectors and points (jme3 only uses vectors everywhere).
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Math.abs;
import javax.vecmath.Point3d;
//...
/**
* Calculate the line segment that is the shortest route between the two lines
* determined by the segments.
*
* Even though we are passing segments as arguments the result is the intersection of the lines in which
* the segments are contained, not the intersection of the segments themselves.
*
*/
public static LineSegment3D lineToLineIntersection(LineSegment3D segmentA, LineSegment3D segmentB) {
checkNotNull(segmentA, "Segment cannot be null.");
checkNotNull(segmentB, "Segment cannot be null.");
Point3d p1 = segmentA.getPoints().getValue0();
Point3d p2 = segmentA.getPoints().getValue1();
Point3d p3 = segmentB.getPoints().getValue0();
Point3d p4 = segmentB.getPoints().getValue1();
Point3d p43 = new Point3d(p4.x - p3.x, p4.y - p3.y, p4.z - p3.z);
checkArgument(!(abs(p43.x) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA &&
abs(p43.y) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA &&
abs(p43.z) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA), MSG_INVALID_POINTS_FOR_INTERSECTION_CALCULATION);
Point3d p21 = new Point3d(p2.x - p1.x, p2.y - p1.y, p2.z - p1.z);
checkArgument(!(abs(p21.x) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA &&
abs(p21.y) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA &&
abs(p21.z) < NUMBERS_SHOULD_BE_DIFFERENT_DELTA), MSG_INVALID_POINTS_FOR_INTERSECTION_CALCULATION);
Point3d p13 = new Point3d(p1.x - p3.x, p1.y - p3.y, p1.z - p3.z);
double d1343 = p13.x * p43.x + p13.y * p43.y + p13.z * p43.z;
double d4321 = p43.x * p21.x + p43.y * p21.y + p43.z * p21.z;
double d4343 = p43.x * p43.x + p43.y * p43.y + p43.z * p43.z;
double d2121 = p21.x * p21.x + p21.y * p21.y + p21.z * p21.z;
double denom = d2121 * d4343 - d4321 * d4321;
checkArgument(abs(denom) >= NUMBERS_SHOULD_BE_DIFFERENT_DELTA, MSG_INVALID_POINTS_FOR_INTERSECTION_CALCULATION);
double d1321 = p13.x * p21.x + p13.y * p21.y + p13.z * p21.z;
double numer = d1343 * d4321 - d1321 * d4343;
double mua = numer / denom;
double mub = (d1343 + d4321 * mua) / d4343;
return new LineSegment3D(
new Point3d(p1.x+mua*p21.x, p1.y+mua*p21.y, p1.z+mua*p21.z),
new Point3d(p3.x+mub*p43.x, p3.y+mub*p43.y, p3.z+mub*p43.z));
}
A couple of JUnit 4 test cases. Notice that I'm also using a custom method to test if two points are similar enough to be considered the same:
#Test
public void testLineToLineIntersection_LineAlongZAxis_LineAlongXAxis() {
LineSegment3D segmentA = new LineSegment3D(new Point3d(1, 0, 0), new Point3d(3, 0, 0));
LineSegment3D segmentB = new LineSegment3D(new Point3d(0, 0, -1), new Point3d(0, 0, 5));
LineSegment3D segment = GeometryUtil.lineToLineIntersection(segmentA, segmentB);
Point3d expected = new Point3d(0, 0, 0);
Pair<Point3d, Point3d> segmentPoints = segment.getPoints();
Assert.assertTrue( GeometryUtil.almostEqual(segmentPoints.getValue0(), expected));
Assert.assertTrue( GeometryUtil.almostEqual(segmentPoints.getValue1(), expected));
}
#Test
public void testLineToLineIntersection_LineAlongZAxis_LineParallelXAxis_DoNotCross() {
LineSegment3D segmentA = new LineSegment3D(new Point3d(1, 0, 0), new Point3d(3, 0, 0));
LineSegment3D segmentB = new LineSegment3D(new Point3d(0, 1, -1), new Point3d(0, 1, 5));
LineSegment3D segment = GeometryUtil.lineToLineIntersection(segmentA, segmentB);
Pair<Point3d, Point3d> segmentPoints = segment.getPoints();
Point3d expectedFrom = new Point3d(0, 0, 0);
Point3d expectedTo = new Point3d(0, 1, 0);
Assert.assertTrue( GeometryUtil.almostEqual(segmentPoints.getValue0(), expectedFrom));
Assert.assertTrue( GeometryUtil.almostEqual(segmentPoints.getValue1(), expectedTo));
}
//I created this test by using
//https://technology.cpm.org/general/3dgraph/
//it's pretty easy to create four points and play around until one can ensure that the lines approximately intersect
//The calculations for creating intersecting examples are quite easy too, this just saved a little more time and it's good enough for me
#Test
public void testLineToLineIntersection_RandomLinesAlmostIntersect() {
LineSegment3D segmentA = new LineSegment3D(new Point3d(-3, -2, 4), new Point3d(1, 3, 2));
LineSegment3D segmentB = new LineSegment3D(new Point3d(-1, -2, 1), new Point3d(-1, 4, 6));
LineSegment3D segment = GeometryUtil.lineToLineIntersection(segmentA, segmentB);
Pair<Point3d, Point3d> segmentPoints = segment.getPoints();
double distance = segmentPoints.getValue0().distance(segmentPoints.getValue1());
Assert.assertTrue( distance < 0.1);
}
I have an Arraylist of customer locations with lat/lng values,i need to travel from the nearest customer from my location and proceed based on the nearest located customers from then. how to sort the array of geopoints based on their distnace?
Create Java comparator from code snippet below, and then sort the ArrayList using the same.
Sample code to get distance between 2 geo locations
private double distanceBetween(final GeoLocation from, final GeoLocation to) {
// double earthRadius = 3958.75; // in miles, change to 6371 for
// kilometer output
final double earthRadius = 6371;
final double dLat = Math.toRadians(to.lattitude - from.lattitude);
final double dLng = Math.toRadians(to.longitude - from.longitude);
final double sindLat = Math.sin(dLat / 2);
final double sindLng = Math.sin(dLng / 2);
final double a = Math.pow(sindLat, 2) + Math.pow(sindLng, 2) * Math.cos(Math.toRadians(from.lattitude))
* Math.cos(Math.toRadians(to.lattitude));
final double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
final double dist = earthRadius * c;
return dist;
}
Use Google's Distance Matrix API for your purpose.
Inside a Loop and based on the mode of transport use the Distance Matrix API to get the distance and the duration for you to reach them.
Based on the duration, use any sorting technique to sort the array list.
Finding the distance between the two lat and long's directly works if you're flying.
Apollonian gaskets = They are planar fractals generated from triples of circles, where each circle is tangent to the other two. In his drawing of the gasket, we start with two externally tangent circles which diameter is D1 and D2. Then we add a third circle which diameter is D1+D2 and to which the two original circles are internally tangent. This is the first generation of circles.
Each subsequent generation of circles is constructed by applying the following scheme:
For any three circles A, B C of any previous generations which are tangent to each other a new circle is constructed which is tangent to A,B,C. The new circle must differ from all circles constructed so far. When a generation is complete, i.e no other circle can be added, then the next generation of circles can start being constructed.
There is an additional stopping rule which prevents from generating infinitesimally small circles. A circle can be added to the gasket if and only if the lenght of its diameter is least minD which is a fixed positive value.
Input consists of one line with three decimal numbers D1, D2 and minD. The number are separated by spaces. The format is usual decimal format (see also the examples bellow) with no exponent part.
It holds that 1.0 ≤ D1, D2 ≤ 1000.0, 0.001 ≤ minD ≤ D1+D2.
Ouput consists of one text line containing two decimal numbers L1 and L2. L1 represents the sum of areas of all circles in the gasket except for the bigggest circle. L2 represents the sum of perimeters of all circles in tin the gasket except for the bigggest circle. Both output values are rounded to 6 decimal digits. Decimal digits must be always present in the output even if some of them are zeros.
Maximim output value is less than 107.
Input
17.000000 40.000000 1.000000
Output
2439.258588 835.263228
2
For given D1 and D2, I create this two circles like this (first iteration):
double D1 = 17.00;
double D2 = 40.00;
double minD = 1.00;
int i = 250, j = 350;
comp.addCircle(i, j, (int) D2, randomColor);
comp.addCircle(i + (int) D2 / 2 + (int) D1 / 2, j, (int) D1, randomColor);
comp.addCircle(i + (int) D1 / 2, j, (int) (D1 + D2), randomColor);
UPDATE:
So, solution is based on Descartes' theorem. We well work with radius, not diameter, and Curvature, with is 1/r.
We will use double for all calculation, but if you work with significantly small numbers, I would prefer BigDecimal. It will slow algorithm, and you should use external method for finding square root, because BigDecimal doesn't have any.
For given D1, D2, minD we modify code above for efficiency:
Some preparation:
double D1 = sc.nextDouble() / 2;
double D2 = sc.nextDouble() / 2;
minD = sc.nextDouble() / 2;
double D3 = D1 + D2;
So, first step looks like this:
Next step looks a little bit more complicated.
Assume we want to write a recursion to solve this problem, and according to Descartes' theorem, for given curvatures of three circles, tangent to each other, (pic. below)
, we could find curvatures of two circles, but for our purposes, we need only small one, so, we can simplify formula to
this.curve = a.curve + b.curve + c.curve + 2 * Math.sqrt(Math.abs(a.curve * b.curve + a.curve * c.curve + b.curve * c.curve));
Lets take a look at Apollonian gaskets again: try to play with it.
See? It is same gaskets, but with different start condition. And whats more important for us, is that it is symmetrical! So, we will calculate just a half, and then multiply result by two!
Lets write a recursion! Inputs will be curvatures of three circles. No output, we will use change our global variables.
double radius_sum = 0.0;
double square_radius_sum = 0.0;
void createAG(double a, double b, double c){
double n = a + b + c + Math.sqrt(a*b + a*c + b*c + 4.0);
if ((minD * n) < 1){
radius_sum += 2. / n; //Remember about symmetry?
square_radius_sum += 2. * (1. / n) * (1. / n); //Remember about symmetry?
createAG(a, b, n);
createAG(a, c, n);
createAG(b, c, n);
}
}
To find the result, we will use formulas to calculate area and perimeter of circle.
Perimeter is length of circumference and equal to .
Area is equal to , as you already know, because we already calculated it in previous step, otherwise we had to store every radius and do more calculations.
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
But we forget about our first two circles! Let's fix it!
radius_sum += D1*2 + D2*2;
square_radius_sum += D1*D1 + D2*D2;
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
And there is always a room for improvement. For example, to use IEEE 754 in better way, I assume you will use 1. / x instead of 1 / x.
Thank you!
P.S. Copyright! This task (text and first picture of Apollonian gasket) is created by teachers at CTU, for course ALG. Picture of formulas is from Wikipedia. Everything else is public domain, if not patented, registered e.t.c.
So, solution is based on Descartes' theorem. We well work with radius, not diameter, and Curvature, with is 1/r.
We will use double for all calculation, but if you work with significantly small numbers, I would prefer BigDecimal. It will slow algorithm, and you should use external method for finding square root, because BigDecimal doesn't have any.
For given D1, D2, minD we modify code above for efficiency:
Some preparation:
double D1 = sc.nextDouble() / 2;
double D2 = sc.nextDouble() / 2;
minD = sc.nextDouble() / 2;
double D3 = D1 + D2;
So, first step looks like this:
Next step looks a little bit more complicated.
Assume we want to write a recursion to solve this problem, and according to Descartes' theorem, for given curvatures of three circles, tangent to each other, (pic. below)
, we could find curvatures of two circles, but for our purposes, we need only small one, so, we can simplify formula to
this.curve = a.curve + b.curve + c.curve + 2 * Math.sqrt(Math.abs(a.curve * b.curve + a.curve * c.curve + b.curve * c.curve));
Lets take a look at Apollonian gaskets again: try to play with it.
See? It is same gaskets, but with different start condition. And whats more important for us, is that it is symmetrical! So, we will calculate just a half, and then multiply result by two!
Lets write a recursion! Inputs will be curvatures of three circles. No output, we will use change our global variables.
double radius_sum = 0.0;
double square_radius_sum = 0.0;
void createAG(double a, double b, double c){
double n = a + b + c + Math.sqrt(a*b + a*c + b*c + 4.0);
if ((minD * n) < 1){
radius_sum += 2. / n; //Remember about symmetry?
square_radius_sum += 2. * (1. / n) * (1. / n); //Remember about symmetry?
createAG(a, b, n);
createAG(a, c, n);
createAG(b, c, n);
}
}
To find the result, we will use formulas to calculate area and perimeter of circle.
Perimeter is length of circumference and equal to .
Area is equal to , as you already know, because we already calculated it in previous step, otherwise we had to store every radius and do more calculations.
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
But we forget about our first two circles! Let's fix it!
radius_sum += D1*2 + D2*2;
square_radius_sum += D1*D1 + D2*D2;
radius_sum = 2 * Math.Pi * radius_sum;
square_radius_sum = Math.Pi * square_radius_sum;
And there is always a room for improvement. For example, to use IEEE 754 in better way, I assume you will use 1. / x instead of 1 / x.
Thank you!
P.S. Copyright! This task (text and first picture of Apollonian gasket) is created by teachers at CTU, for course ALG. Picture of formulas is from Wikipedia. Everything else is public domain, if not patented, registered e.t.c.
I have data with latitude and longitude stored in my SQLite database, and I want to get the nearest locations to the parameters I put in (ex. My current location - lat/lng, etc.).
I know that this is possible in MySQL, and I've done quite some research that SQLite needs a custom external function for the Haversine formula (calculating distance on a sphere), but I haven't found anything that is written in Java and works.
Also, if I want to add custom functions, I need the org.sqlite .jar (for org.sqlite.Function), and that adds unnecessary size to the app.
The other side of this is, I need the Order by function from SQL, because displaying the distance alone isn't that much of a problem - I already did it in my custom SimpleCursorAdapter, but I can't sort the data, because I don't have the distance column in my database. That would mean updating the database every time the location changes and that's a waste of battery and performance. So if someone has any idea on sorting the cursor with a column that's not in the database, I'd be grateful too!
I know there are tons of Android apps out there that use this function, but can someone please explain the magic.
By the way, I found this alternative: Query to get records based on Radius in SQLite?
It's suggesting to make 4 new columns for cos and sin values of lat and lng, but is there any other, not so redundant way?
1) At first filter your SQLite data with a good approximation and decrease amount of data that you need to evaluate in your java code. Use the following procedure for this purpose:
To have a deterministic threshold and more accurate filter on data, It is better to calculate 4 locations that are in radius meter of the north, west, east and south of your central point in your java code and then check easily by less than and more than SQL operators (>, <) to determine if your points in database are in that rectangle or not.
The method calculateDerivedPosition(...) calculates those points for you (p1, p2, p3, p4 in picture).
/**
* Calculates the end-point from a given source at a given range (meters)
* and bearing (degrees). This methods uses simple geometry equations to
* calculate the end-point.
*
* #param point
* Point of origin
* #param range
* Range in meters
* #param bearing
* Bearing in degrees
* #return End-point from the source given the desired range and bearing.
*/
public static PointF calculateDerivedPosition(PointF point,
double range, double bearing)
{
double EarthRadius = 6371000; // m
double latA = Math.toRadians(point.x);
double lonA = Math.toRadians(point.y);
double angularDistance = range / EarthRadius;
double trueCourse = Math.toRadians(bearing);
double lat = Math.asin(
Math.sin(latA) * Math.cos(angularDistance) +
Math.cos(latA) * Math.sin(angularDistance)
* Math.cos(trueCourse));
double dlon = Math.atan2(
Math.sin(trueCourse) * Math.sin(angularDistance)
* Math.cos(latA),
Math.cos(angularDistance) - Math.sin(latA) * Math.sin(lat));
double lon = ((lonA + dlon + Math.PI) % (Math.PI * 2)) - Math.PI;
lat = Math.toDegrees(lat);
lon = Math.toDegrees(lon);
PointF newPoint = new PointF((float) lat, (float) lon);
return newPoint;
}
And now create your query:
PointF center = new PointF(x, y);
final double mult = 1; // mult = 1.1; is more reliable
PointF p1 = calculateDerivedPosition(center, mult * radius, 0);
PointF p2 = calculateDerivedPosition(center, mult * radius, 90);
PointF p3 = calculateDerivedPosition(center, mult * radius, 180);
PointF p4 = calculateDerivedPosition(center, mult * radius, 270);
strWhere = " WHERE "
+ COL_X + " > " + String.valueOf(p3.x) + " AND "
+ COL_X + " < " + String.valueOf(p1.x) + " AND "
+ COL_Y + " < " + String.valueOf(p2.y) + " AND "
+ COL_Y + " > " + String.valueOf(p4.y);
COL_X is the name of the column in the database that stores latitude values and COL_Y is for longitude.
So you have some data that are near your central point with a good approximation.
2) Now you can loop on these filtered data and determine if they are really near your point (in the circle) or not using the following methods:
public static boolean pointIsInCircle(PointF pointForCheck, PointF center,
double radius) {
if (getDistanceBetweenTwoPoints(pointForCheck, center) <= radius)
return true;
else
return false;
}
public static double getDistanceBetweenTwoPoints(PointF p1, PointF p2) {
double R = 6371000; // m
double dLat = Math.toRadians(p2.x - p1.x);
double dLon = Math.toRadians(p2.y - p1.y);
double lat1 = Math.toRadians(p1.x);
double lat2 = Math.toRadians(p2.x);
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));
double d = R * c;
return d;
}
Enjoy!
I used and customized this reference and completed it.
Chris's answer is really useful (thanks!), but will only work if you are using rectilinear coordinates (eg UTM or OS grid references). If using degrees for lat/lng (eg WGS84) then the above only works at the equator. At other latitudes, you need to decrease the impact of longitude on the sort order. (Imagine you're close to the north pole... a degree of latitude is still the same as it is anywhere, but a degree of longitude may only be a few feet. This will mean that the sort order is incorrect).
If you are not at the equator, pre-calculate the fudge-factor, based on your current latitude:
<fudge> = Math.pow(Math.cos(Math.toRadians(<lat>)),2);
Then order by:
((<lat> - LAT_COLUMN) * (<lat> - LAT_COLUMN) +
(<lng> - LNG_COLUMN) * (<lng> - LNG_COLUMN) * <fudge>)
It's still only an approximation, but much better than the first one, so sort order inaccuracies will be much rarer.
I know this has been answered and accepted but thought I'd add my experiences and solution.
Whilst I was happy to do a haversine function on the device to calculate the accurate distance between the user's current position and any particular target location there was a need to sort and limit the query results in order of distance.
The less than satisfactory solution is to return the lot and sort and filter after the fact but this would result in a second cursor and many unnecessary results being returned and discarded.
My preferred solution was to pass in a sort order of the squared delta values of the long and lats:
((<lat> - LAT_COLUMN) * (<lat> - LAT_COLUMN) +
(<lng> - LNG_COLUMN) * (<lng> - LNG_COLUMN))
There's no need to do the full haversine just for a sort order and there's no need to square root the results therefore SQLite can handle the calculation.
EDIT:
This answer is still receiving love. It works fine in most cases but if you need a little more accuracy, please check out the answer by #Teasel below which adds a "fudge" factor that fixes inaccuracies that increase as the latitude approaches 90.
In order to increase performance as much as possible I suggest improve #Chris Simpson's idea with the following ORDER BY clause:
ORDER BY (<L> - <A> * LAT_COL - <B> * LON_COL + LAT_LON_SQ_SUM)
In this case you should pass the following values from code:
<L> = center_lat^2 + center_lon^2
<A> = 2 * center_lat
<B> = 2 * center_lon
And you should also store LAT_LON_SQ_SUM = LAT_COL^2 + LON_COL^2 as additional column in database. Populate it inserting your entities into database. This slightly improves performance while extracting large amount of data.
Try something like this:
//locations to calculate difference with
Location me = new Location("");
Location dest = new Location("");
//set lat and long of comparison obj
me.setLatitude(_mLat);
me.setLongitude(_mLong);
//init to circumference of the Earth
float smallest = 40008000.0f; //m
//var to hold id of db element we want
Integer id = 0;
//step through results
while(_myCursor.moveToNext()){
//set lat and long of destination obj
dest.setLatitude(_myCursor.getFloat(_myCursor.getColumnIndexOrThrow(DataBaseHelper._FIELD_LATITUDE)));
dest.setLongitude(_myCursor.getFloat(_myCursor.getColumnIndexOrThrow(DataBaseHelper._FIELD_LONGITUDE)));
//grab distance between me and the destination
float dist = me.distanceTo(dest);
//if this is the smallest dist so far
if(dist < smallest){
//store it
smallest = dist;
//grab it's id
id = _myCursor.getInt(_myCursor.getColumnIndexOrThrow(DataBaseHelper._FIELD_ID));
}
}
After this, id contains the item you want from the database so you can fetch it:
//now we have traversed all the data, fetch the id of the closest event to us
_myCursor = _myDBHelper.fetchID(id);
_myCursor.moveToFirst();
//get lat and long of nearest location to user, used to push out to map view
_mLatNearest = _myCursor.getFloat(_myCursor.getColumnIndexOrThrow(DataBaseHelper._FIELD_LATITUDE));
_mLongNearest = _myCursor.getFloat(_myCursor.getColumnIndexOrThrow(DataBaseHelper._FIELD_LONGITUDE));
Hope that helps!