I have searched all over for this, but I can't seem to find the best approach to this. I have about 22000 lat/lon points and I want to find the closest one's to the current location of the iPhone. I've seen people ask about Quad Trees, Dijkstra's Algorithm, and spatial databases. Which is the best for the iPhone? Spatial databases seem easiest, but I am not sure.
EDIT: there are actually over 20,000 points. You think iterating through all of them is the way to do it? But thanks for you input.
Thanks.
Actually, it is best to use Haversine (great circle) calculation for Lat/Long points, otherwise increasingly large distances will be wrong, especially if you use simple trig like in Jherico's answer.
A quick search provides this javascript example:
var R = 6371; // km Radius of earth
var dLat = (lat2-lat1).toRad();
var dLon = (lon2-lon1).toRad();
var a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1.toRad()) * Math.cos(lat2.toRad()) *
Math.sin(dLon/2) * Math.sin(dLon/2);
var c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));
var d = R * c;
In terms of the datastructure, Geohash is worth looking at.
If you need better than O(N), you can only get that if you first pay N lg N for building a spatial hash of some sort (a quadtree, octree, hash grid, or similar). Then each test will be approximately O(lg N), and can be much better typically by caching the last location you checked, if there's a lot of coherency (generally, there is).
I would probably build an octree in Euler (geocentric, XYZ) space, because that allows me to get "true" distance, not "warped" lat/lon distance. However, in practice, a quad tree in lat/lon space will probably work well enough. Once you have a hit, you hold on to that tree node (assuming the tree isn't re-built at runtime), and the next query starts walking from that tree node, and only needs to worry about nodes that may be closer if the previous point moved further away from the previous answer.
As you are on iPhone, you can use CoreLoaction to perform the geographic distance - using CLLocation's – getDistanceFrom:
I would be tempted to use a brute force linear search though all 2k points nad, if that isn't fast enough, switch to something like GeoHash to store meta data against your points for search.
Why not tile the globe into regions? (Think hexes.) Then, either when you add points to your list, or in one big pre-processing loop, for each point, store the region it is.
Then, when searching for points near point A in hex X, you only need to check points in hex X and a maximum of 3 neighbouring hexes.
If this is still too many points to check, add subregions.
you must consider that to use Dijkstra you must know your node position in the graph, that is instead the problem you're trying to solve; you're not in the graph, but you want to know the closest point to you
so simply, as already Chaos told you, you must calculate all distances beetween your position and all 20.000 points, then sort them
I think this algorithm works:
Create an array sorted by latitude
Create an array sorted by longitude
To find the closest, first find the closest by latitude by
doing a binary search in the latitude array. Do the
same for the longitude array. Now you have 2 points, one
closest by latitude, the other closest by longitude.
Compute the distances to each point via the pythagorean theorem.
The closest point wins.
Roger
Related
I have a map with a 600*600 aequidistant x,y grid with associated scalar values.
I have around 1000 x,y coordinates at which I would like to get the bi-linear interpolated map values. Those are randomly placed in an inner center area of the map with arround 400*400 size.
I decided to go with the griddata function with method linear. My understanding is that with linear interpolation I would only need the three nearest grid positions around each coordinate do get the well defined interpolated values. So I would require around 3000 data points of the map to perform the interpolation. The 360k data points are highly unnecessary for this task.
Throwing stupidly the complete map in results in long excecution times of a half minute. Since it's easy to narrow the map already down to the area of interest I could reduce excecution time to nearly 20%.
I am now wondering if I oversaw something in my assumption that I need only the three nearest neighbours for my task. And if not, whether there is a fast solution to filter those 3000 out of the 360k. I assume looping 3000 times over the 360k lines will take longer than to just throw in the inner map.
Edit: I had also a look at the comparisson of the result with 600*600 and the reduced data points. I am actually surprised and concerned about the observation, that the interpolation results differ partly significantly.
So I found out that RegularGridinterpolator is the way to go for me. It's fast and I have a regular grid already.
I tried to sort out my findings with the differences in interpolation value and found griddata to show unexpected behavior for me.
Check out the issue I created for details.
https://github.com/scipy/scipy/issues/17378
I have a problem with my android app, I have x value (whatever it is) and I have data in the database, I want to compare the value of x with all the data in the database at the same time in real time
the app is using sqlite.
I used a loop but when the database is large in this case my app lags in comparing all the data.my code is
public void Check_Distance(Location Current_Location,ArrayList<Location> LocationArrayList1)
{
double Distance;
for(int i=0;i<LocationArrayList1.size();i++)
{
Distance=distanceBetween(Current_Location,LocationArrayList1.get(i));
if(Distance<=0.1*1000){ // if distance is less then 100m give a sound
Notification_Sound();
}
}
}
You can't look at every record in the database at the exact same time. That's called quantum computing, and is currently an active research area where people far smarter than you or I are currently spending millions of dollars to try and create a machine that can do this kind of parallel processing.
That being said, you can make your algorithm more efficient, but that takes some effort to do. Both of the below are based on the idea of eliminating the majority of the locations that are obviously too far away very quickly, and performing more in-depth checks on those that could be in range.
One method is to sort the locations in ascending order in two arrays - one by North/South and the other by East/West. Find all entries within a given distance of the current position in each list, then combine the results to get a list of points within a box of X distance from the location. This box will have a much smaller number of points within it that you can then apply an iterative, circular, distance based approach to.
Another is to create a quadtree. This would subdivide the map area into a set of bounding volumes, where each volume would have a set of points, or additional bounding volumes. You can then place down your search area and find all the quadtree volumes that intersect with your circular search area, greatly minimizing the number of locations you need to do a true distance check on.
I would like to calculate a graph similiar to an isochrone using pgsql. Therefore, I already used the algorithm pgr_drivingDistance. You provide a starting point and a distance value and receives an isochrone.
The output using the algorithm is received with code which looks something like:
SELECT * FROM pgr_drivingDistance(
'SELECT id, source, target, cost FROM edge_table',
2, 2, false -- starting point, distance, directed
);
The red star represents the starting point.
Now, I want a graph which works the same way, like starting at one point and get routes in all directions. The difference is, that I don't want to provide a travel distance, but a list with point coordinates, which are lying on the road network. The route in every direction has to stop at the first reached point lying on each route. The distance on every route is different and I don't know which points are the closest ones.
The desired output using the "stopping" points, which are visualized in green, is supposed to look like this.
I tried already:
Using the given algorithm pgr_drivingDistance and raising the distance value every time no point is reached -> problem here: the distance is equal for all directions and not individual for each route.
Using the algorithm pgr_dijkstra for each route -> problem here: because you don't know which point is affected you don't know which end point to choose for the calculation. You also cannot take the closest one in the immediate vicinity because you need the closest one on the specific route.
I know that I have to build an almost complete new algorithm, but maybe someone has an idea how to start or even experience with this kind of problem.
Thank you in advance!
This is a one to many routing problem. You have to compute the route to each end point to find the shortest one. I have not looked at the pgRouting function recently, but I believe there is a one to many, many to one and many to many Dijkstra function(s). You should be able to use the one to many to compute all the routs in one go and then you can sort the routs based on length to find the shortest one.
I have an array of points representing a street (black line) and points, representing a places on map (red points). I want to find all the points near the specified street, sorted by distance. I also need to have the ability to specify max distance (blue and green areas). Here is a simple example:
I thought of using the $near operator but it only accepts Point as an input, not LineString.
How mongodb can handle this type of queries?
As you mentioned, Mongo currently doesn't support anything other than Point. Have you come across the concept of a route boxer? 1 It was very popular a few years back on Google Maps. Given the line that you've drawn, find stops that are within dist(x). It was done by creating a series of bounding boxes around each point in the line, and searching for points that fall within the bucket.
I stumbled upon your question after I just realised that Mongo only works with points, which is reasonable I assume.
I already have a few options of how to do it (they expand on what #mnemosyn says in the comment). With the dataset that I'm working on, it's all on the client-side, so I could use the routeboxer, but I would like to implement it server-side for performance reasons. Here are my suggestions:
break the LineString down into its individual coordinate sets, and query for $near using each of those, combine results and extract an unique set. There are algorithms out there for simplifying a complex line, by reducing the number of points, but a simple one is easy to write.
do the same as above, but as a stored procedure/function. I haven't played around with Mongo's stored functions, and I don't know how well they work with drivers, but this could be faster than the first option above as you won't have to do roundtrips, and depending on the machine that your instance(s) of Mongo is(are) hosted, calculations could be faster by microseconds.
Implement the routeboxer approach server-side (has been done in PHP), and then use either of the above 2 to find stops that are $within the resulting bounding boxes. Heck since the routeboxer method returns rectangles, it would be possible to merge all these rectangles into one polygon covering your route, and just do a $within on that. (What #mnemosyn suggested).
EDIT: I thought of this but forgot about it, but it might be possible to achieve some of the above using the aggregation framework.
It's something that I'm going to be working on soon (hopefully), I'll open-source my result(s) based on which I end up going with.
EDIT: I must mention though that 1 and 2 have the flaw that if you have 2 points in a line that are say 2km apart, and you want points that are within 1.8km of your line, you'll obviously miss all the points between that part of your line. The solution is to inject points onto your line when simplifying it (I know, beats the objective of reducing points when adding new ones back in).
The flaw with 3 then is that it won't always be accurate as some points within your polygon are likely to have a distance greater than your limit, though the difference wouldn't be a significant percentage of your limit.
[1] google maps utils routeboxer
As you said Mongo's $near only works on points not lines as the centre point however if you flip your premise from find points near the line to find the line near the point then you can use your points as the centre and line as the target
this is the difference between
foreach line find points near it
and
foreach point find line near it
if you have a large number of points to check you can combine this with nevi_me's answer to reduce the list of points that need checking to a much smaller subset
I have had a search around on this, but being new to matlab I could do with more specific help with my issue.
I have a huge matrix <2182824x9double> where each row represents a particle being tracked over time with columns including (numerical) TrackID, Time, Lat and Long.
What I need to do is for each unique TrackID, take time=0 and call that the start position, and for every other row within that TrackID (where time is not 0), find the distance (as the crow flies) from the start lat long (this is in order to find the maximal distance from the start point achieved being not necessarily the end point of the track).
To further complicate this i have a non-standard radius for the earth so I need a method which will allow me to stipulate this radius (6371.001km).
I don't really know where to start on this, and am worried about computational effort given the size of my matrix (I have many more such matrices to do the same thing to) - any suggestions would be much appreciated!
Many thanks for your time and attention,
All the best,
Bex