I have this table in sqlite
Locations
ID
Lat ( latitude)
Lon ( longitude)
Type
Name
City
I have for example 100 records
what I need is to get (using my own coordinates) the nearest point in my table.
What I did is to get the shortest distance between my current point and each one in the table, and return the shortest one, but I am searching for a better solution
Thanks
A possible solution is to use a grid for the whole map your are interested in and pre-assign points to a particular row/column. Then:
Calculate the grid location of your new point - add a column to the database for this.
Calculate the distance of all coordinates in the current grid - if one exists
You still need to calculate all the distances in the next grid out (you are unlikely to be perfectly centered in your current square, you always need to check one grid distance out from the one your best match was in.)
Should cut down a lot on the number of calculations you need to do.
If you expect to always find a location within X distance you could query for x/y coords that would fall within that range your coords +/- x KM (a square), calculate if they then fall within the xKM circle from your point, and then choose the shortest.
UPDATE - Grid option
I am assuming you already are doing the distance between two points calculation and will not describe that.
If you have an atlas handy you can see an example by looking a place up in the index. It will give you a page and a grid location like M5. If you go to that page it will have rows and columns labeled with numbers and letters and if you look in the square where row M and column 5 intersect you will find the city there. To do it for your system you need to:
determine how big your grid should be (how dense are your points - would be no good to have a big grid and all your points land in one square).
For each point calculate which grid it is in. If your polygons are complex there is tons of point in polygon code out there to copy. If (as my example is) you just use squares, you just need to determine which row/column each point is between.
See map for user location and closest points example:
So if the user is the green marker, he would be in C4. You would search all other points in C4 and determine that the closest is #2. Then you would also have to check one grid out all the way around to make sure there wasn't a closer item than the one you found, so this includes squares: B3,B4,B5,C3,C5,D3,D4,D5. When you do you will pick #3 from C3 and you are finished.
If the user had been in square D2 where there are no other points your would have found your first match in say C2. When checking C1,C2,C3,D1,D3,E1,E2,E3. Once found you would then again need to check another radius out, which would have be: B0-4, C0,C4,D0,D4,E0,E4,F0-4. etc. You can see that grid selection will be important to make this as efficient as possible.
Also Note this assumes your grids are equal unlike my hand drawn example.
Option 2:
If you expect a result within X km, and you want something your DB will calculate quickly you can do this:
LatMin = currentLatCoord-radiusValInDegrees
LatMax = currentLatCoord+radiusValInDegrees
LonMin = currentLonCoord-radiusValInDegrees
LonMax = currentLonCoord+radiusValInDegrees
SELECT *
From Locations
WHERE Lat BETWEEN LatMin AND LatMax
AND Lon BETWEEN LonMin AND LonMax
Now this gives you all results in a square. It is important that you then check they are actually in the circle - you need to drop any in the corners as there may actually be closer coordinates than those on the edge of the circle. So for each point check if it is inside the circle first (Equation for testing if a point is inside a circle) then calculate the distance and keep the closest one. If you do not get a result, widen the circle.
Again, selecting a good radius will depend on your data.
Have you check this Site of how to count for the distance between two points on Earth?
But just keep in mind that it give the Distance based on Earth Surface not based on the actual path to reach at that position. So if you want to count distance based on the Actual Path to reach that position then you can get it by using Google MAP API.
Google Maps API gives the distance between two point based on the actual path.
Hope this information surly help you.
Enjoy Coding... :)
Distance between two points: ((x1 - x2) ^ 2 + (y1 - y2) ^ 2) ^ 0.5. However, distance between these points are straight lines. Most likely, there are variables like local vs highway, not to mention one-way streets and waterways, where you need to find the nearest bridge. Therefore, I suggest using Google and Bing maps api. The are free for a limited number of searches.
There's a rather clever solution over at Query to get records based on Radius in SQLite?
based on precalculating some trigonometric values for each position when inserting the rows which then lets you calculate the distance in your query only using arithmetic functions.
I've used it very successfully in my own code
Let me make sure this is right: You have point a, and a table of points a[]. Currently, you do something like:
loop over b[]
get distance from b[i] to a
if distance is less than minimumDistance
set minimumDistance = distance
set closestPoint = i
return closestPoint
If so, you're finding it in O(n) time, which can't really be improved upon much. You have to check all the points to see which are the closest.
However, as Matthew points out, you can prune n by assigning points to a grid. This can drastically reduce the amount of points needed to compare. The expense is a bit of time preprocessing, and slightly more complicated logic. If you have a long list of points(or the distance() function takes a long time), you'll definitely want to do something like this.
Depends how much you care about being correct when near the poles
if closest by pythagorean distance is good enough you can use this in the orderby of the sql
eg. SELECT * FROM locations ORDERBY (Lat-myLat)*(Lat-myLat) + (Lon-myLon)*(Lon-myLon) LIMIT 1
Not technically the most correct, but saves getting all locations from the database and looping over them, let sqlite do that for you
You can use my php class hilbert curve # phpclasses.org. It uses a monster curve and a quadkey to find the shortest distance. To search the quadkey you can use any depth.
Though this is not a best option.
Let you are trying to figure out shortest distance within N mile/km radious for fixed no of locations/your location table data are not changing regularly.
Add another column Distance_Index (DI) a self multi reference key ArrayType. Once run a procedure and update the DI with ID in ascending order accoording to distance from this DI.
Now from next time onwords distance is with you. just make a query to the database and use it.
Now, in your problem no of location are less within N, then DI will not be too much long.Just as an opinion.
Related
I have collection of 100 geo points. I want to create triangles (each triangle is a single zone), as many as possible. Now the only criteria to make a side of triangle is that two points can't be further than 5KM. So I need 3 points ABC where
|AB| <= 5
|BC| <= 5
|CA| <= 5
Now the only thing I could think was that I check every point with the rest of points. Of course I'm breaking loop when I have 3 points. But I think this is not the fastest way.
What I have ? I have List of points, each point has latitude and longitude so using google api I can in easy way get distance between points.
Points are stored in SQLite database where each point has latitude and longitude in seperate columns
any ideas ? what alhorithm should I use ? or maybe the one I thought is the only good ?
1) In the worst case, every point is within 5km of every other point, and you will end up creating (100 choose 3) triangles, and clever data structures won't speed this up. So you might be better off just doing the simple thing you have described.
2) Suppose you find, for each point, how for north of a reference point it is, and how far east of that reference point it is. Then think of a grid with one of its intersections at the reference point and with its lines just over 5km apart. Sort each point into the box in the grid that it lies in. Now iterate over the boxes in the grid, combining the points in them to make up triangles. Because the grid width is 5km you don't need to compare points from different grid boxes unless those grid boxes touch, at least at the corners. If they don't touch, those grid boxes are separated by at least 5km, and so are all of the points in them. (You could use some value slightly larger than 5km if you are worried about the curvature of the earth upsetting the implicit assumptions here)
Here are some notes and examples to explain (2) a bit more:
Examples of some of these ideas:
Pick the first point as the reference point. Suppose it is at 54.37N, 5.56W. By definition this is at (0, 0). Take a point at 54.32N, 5.703W. Ignoring the curvature of the earth, work out the distance from 54.37N, 5.56W to 54.32N, 5.56W to find out how far south the second point is from the first. Similarly find out how far west of the first point it is and give it a grid location of (-X, -Y) based on this. Do that for all points. Now use these grid locations to put the points into boxes, where each box holds all the points in a 5km x 5km grid square. You can do this just by dividing by five and then using floor() to turn this into an integer, which gives you a co-ordinate in a grid of boxes.
Iterate over all boxes. Suppose you are working on the box with its southwest point at (10, 15). You have to compare every point in that box with every other point in that box. You have to compare every point in that box with every point in the box with southwest point (10,20), because those two boxes lie alongside each other, so points on either side of the line joining them could be less than 5km apart. You even have to compare every point in the box with southwest point at (10, 15) with every point in the box with southwest point (15, 20) because you could have point (14, 19) in the first box and point (16, 21) in the second box and these are less than 5km apart. You DON'T have to compare any point in the box with southwest point (10, 15) with any point in the box with southwest point (20, 15) because the difference in north distances for these boxes means that every point in the (10, 15) box is more than 5km south of every point in the (20,15) box (if the way you put points into boxes is consistent even points exactly at grid locations won't go into two boxes this far apart unless they are MORE than 5km apart).
So the idea is that because you have sorted points into boxes and you only have to compare the points in a box with the points in the nine boxes that are its boxes and the boxes that neighbour its box, there are a lot of comparisons of points that you don't have to make. - But in the worst case every point ends up in the same box and you are sunk.
I have a polyline with point A & B dropped on a map.
At present I am calculating the distance from the line from my location by using the
computeOffset()
and dropping points every five feet on that line and then looping through with the
computeDistanceBetween()
to find the nearest point.
Is there another method or classes out there for this because 5 ft is terribly far away when using an external GPS receiver. I could go to infinitesimally small increments but with the loop and point storage memory would be used up in no time.
Is there anything built into Android at the moment that supports automatic distance calculation from a line?
If you ignore the spherical nature of the surface, which should be o.k. for small distances, your location and the line are forming a triangle. The distance is just the height of this triangle.
So you just need enough information about the triangle, e.g. the length of all sides, to calculate the height.
The length of all sides is just the distance between the 3 points (your location and the two ends of the line). Call the side formed by your line A, and the other sides B and C. The height can be computed then as
H=(2/A)sqrt[s(s-A)(s-B)(s-C)] with s=(1/2)(A+B+C)
(Just looked up this formula. Did not try it.)
EDIT
The solution above gives the distance to the straight line defined as prolongation of your polyline, but without considering the endpoints.
I guess you are looking for the distance to the line limited by its endpoints.
Thus you need to find out in addition, whether the orthogonal projection of your location to the line lies within the endpoints or outside, or with other words, whether the angles between the triangle sides A and B or A and C are greater than 90 degrees.
This can only be the case if B or C are longer than A. If so, take the shorter one (let' say its B) and check whether B*B + A*A is greater than C*C.
(It follows from the law of cosines, that the angle is then greater than 90 degrees.) In this case, B is the distance you are looking for.
I am looking for good solution to calculate distance between two points.
I want to sort by distance my Geo points.
I have:
Cursor c = database.rawQuery("SELECT name,latitude,longitude,((longitude-21.15)*(longitude-21.15) +(latitude-54.05)*(latitude-54.05)) AS len FROM Object ORDER BY len;", null);
But this is wrong solution...
Distance is wrong...
Please help me.
The problem you have here is that you're combining:
GPS coordinates (WGS84) that are used to represent a point on a sphere.
Pythagoras theorem, requires a 2D rectangular coordinate system, to determine distance.
This will simply not work if you're after accuracy!
Here are some options that I've used.
Option 1 - Use great circle distance
This formula is used to calculate the distance in meters between two GPS co-ordinates
Android provides a function distanceBetween as part of the android.location.Location class to assist with this.
The downside is you have to pull out all your points from SQLite in order to calculate the distance.
I have also seen some hybrids such as:
treating WGS84 (GPS) as rectangular
specifying a zones in your db to limit the size of data you pull out when calculating distance.
and then using the distanceBetween function to further filter the results.
Option 2 - Use a rectangular coordinate system
If your distances are small then you can solve this problem is by storing the database points in UTM which is rectangular.
Using a formula almost identical, but using easting and northings, the SQLite db can be used to provide the x closest points to a UTM point. Once these points are identified the square-root function can be performed on the x results to get the distance in meters.
Huh?
There are some caveats about using UTM also. It might help you looking at Calculating Distance Between Two Sets of Coordinates
So your solution ultimately depends on your application and is a compromise between speed and accuracy.
You are calculating the square of the distance. Since SQLite doesn't have a square-root function, you will need to calculate this in your Java code.
If all you need is to sort by distance, then your current code is fine.
You can use static method distanceBetween of android.location.Location class. Then based on calculated distance you can produce some sorted collection of object like SortedMap.
Assume that my current point is lat = 50.000 and long = 50.000 and I want to show some bus stations on these location but my limit should depends on zoom level.
So far, for that aim I find a way: If a can take left-up corner and right-down corners lat's long's ; I will find stations between these locations.
Do you know how can I take these points or any different idea about this situation?
Thanks in advance..
Well you can easily get the top left and bottom right lat/lon coordinates using
GeoPoint tlGpt; // Top left
GeoPoint brGpt; // Bottom right
tlGpt = mapView.getProjection().fromPixels(0, 0);
brGpt = mapView.getProjection().fromPixels(mapView.getWidth(), mapView.getHeight());
At any zoom level where you could actually see the bus stations on the map, then the top left longitude could be considered the same as the bottom left longitude, similarly bottom left long would be approx = bottom right long. Thus you could consider the bounding box as a rectangle, rather than an isosceles trapezium (trapezoid in US English)
If you just want a rough measure to pick up a reasonable sample of objects, then lat/long "distance" is good enough. Just make sure you divide the latitude range by the cosine of the latitude, to get the longitude range (i.e., ∆long = ∆lat/cos(lat)). This is to compensate for the contraction of longitude lines as you approach the poles. You use ∆lat as the basis because latitude lines have the same distance between them everywhere on the globe.
For a more accurate measure, there are some complicated functions that allow you to compute great circle distances from lat/long pairs, but it is conceptually much easier to convert lat/long pairs into 3-D coordinates, and use a simple pythagorean distance to approximate the great circle distance. You could use 2*r*acos(d/(2*r)) (if my whiteboard geometry serves me well), where r is the nominal radius of the earth, to get the exact great circle. But if all you want is to get objects within a range, you can invert the formula to get the pythagorean-distance equivalent of the great-circle limit. This can also be used to derive a 3-D bounding box to speed up the search. If your database supports R-trees, then you're laughing! SQLite supports R*Trees, but they are disabled in the default build, so I don't know if they're available on Android (it seems that it isn't).
My android application loads some markers on an overlay onto a MapView.
The markers are placed based on a dynamic list of GeoPoints.
I want to move the map center and zoom into the area with most items.
Naively, I can calculate the superposition of all the points, but I would like to remove the points that are very far from the mass of points from the calculation.
Is there a known way to calculate this ? (e.g. probability, statistics .. ?)
I once solved the exact same problem you describe for a real estate app I wrote a little while ago. What worked for me was:
Calculate a center point somehow
(centroid, average the lats and
lons, or whatever)
Calc the distances between this imaginary point and each of your real pins
Use a Standard Deviation algorithm and remove any pin whose distance has a StdDev >
2 (or whatever threshold for you)
Repeat steps 1 - 3 (you'll be using a new center point each time
you loop) until there are no more
outliers to remove at step 3
This approach work great for my needs. But I'm sure there's more interesting ways to solve the same problem if you look around. For example, I found this interesting CompSci paper...
http://people.scs.carleton.ca/~michiel/outliers.pdf
Good luck!