I am using an SQLITE database to store latitudes and longitudes of locations.
I want to be able to sort the results by rough distance from the current location. I already have the current location of the device as a double (lat, lng), the lat and lng in the database are also doubles.
What I want is a query that will create a virtual column that I am able to sort the results by.
I currently use a function to show the distance for a selected record:
float pk = (float) (180/3.14159);
float a1 = (float) (db_lat / pk);
float a2 = (float) (db_lon / pk);
float b1 = (float) (current_lat / pk);
float b2 = (float) (current_lon / pk);
float t1 = FloatMath.cos(a1)*FloatMath.cos(a2)*FloatMath.cos(b1)*FloatMath.cos(b2);
float t2 = FloatMath.cos(a1)*FloatMath.sin(a2)*FloatMath.cos(b1)*FloatMath.sin(b2);
float t3 = FloatMath.sin(a1)*FloatMath.sin(b1);
double tt = Math.acos(t1 + t2 + t3);
double dist = (6366000*tt);
For example, a MySQL select could be (taken from: www.movable-type.co.uk):
Select Lat, Lon, acos(sin($lat)*sin(radians(Lat)) + cos($lat)*cos(radians(Lat))cos(radians(Lon)-$lon))$R As dist
From MyTable
ORDER BY dist DESC
Currently I select locations using the following:
public Cursor locationGetAllRows(long groupid)
{
try
{
return db.query(LOCATION_DATABASE_TABLE, new String[] {
"_id", "lat","lon","groupid"},
"groupid="+groupid, null, null, null, null);
}
catch (SQLException e)
{
Log.e("Exception on query: ", e.toString());
return null;
}
}
OK so is it possible to use the SQLITE database in this way? If not the only option I can think of is to have an extra column, iterate through the rows running the above function on each row and filling out an extra column on the row, then sorting on that column?
In my app BostonBusMap I used an approximation to speed up the calculation of closest objects to a point. You can scale the longitude by
cos(latitude)
and then just use the Pythagorean formula to calculate a sorting distance (omitting the square route since it's not necessary for a comparison distance). It works reasonably well for small distances.Source: http://en.wikipedia.org/wiki/Geographical_distance#Spherical_Earth_projected_to_a_plane
This won't completely help, but for situations like this, seriously consider using
rawQuery()
instead ofquery()
, so you can pass in a full SQL statement vs. having to chop it into pieces.Your bigger problem is that I don't see that SQLite has trigonometric functions.
You do not indicate how you are using the
Cursor
you are getting back from your query. For example, if you are putting theCursor
into some sort ofCursorAdapter
, you could:Cursor
into anArrayList<Position>
, wherePosition
is some Java class you define with your dataCursor
, to release the RAM it takes upArrayList<Position>
usingArrays.sort()
ArrayList<Position>
in anArrayAdapter<Position>
and use that where you had been using yourCursorAdapter
I've just written an app that needs to sort a set of coordinates based on distance. What I did was create an array of IDs and Distances and then sorted them within Java. Then I could find the nearest locations and select them from the Database. Of course this approach may not work for you depending on how many points you have and how you access the database. This worked fine for ~350 points, in my Nando's Finder app.
Additionally I used Location.distanceBetween(..) from the SDK to calculate the distances for me. I would hope this method would be implemented in C to ensure it is fast, however, a quick look at the SDK source shows it is written in Java :(.
yeah, that works perfectly.
it can be made into a stored procedure like so:
http://www.thismuchiknow.co.uk/?p=71 [Distance function for sqlite]
there's also the Perst spatial database for android which is excellent, and the SpatiaLite spatial database which is also awesome, which you could link to in your app.
w/out using a specialized lib, you could approximate the distance a few ways (calculate it just as if it were planar (rectangular) then use the Haversine formula to sort the subset later, use a lookup table that approximates cos, sin, etc, group locations into 5 sq. mile zones and search neighboring cells up to the max, etc...)