2010-01-09 7 views
4

J'utilise une base de données SQLITE pour stocker les latitudes et les longitudes des emplacements.Android sqlite tri sur colonne calculée (distance des coordonnées)

Je souhaite être capable de trier les résultats par distance approximative par rapport à l'emplacement actuel. J'ai déjà l'emplacement actuel de l'appareil en tant que double (lat, lng), le lat et le lng dans la base de données sont également doubles.

Ce que je veux, c'est une requête qui va créer une colonne virtuelle que je suis capable de trier les résultats.

J'utilise actuellement une fonction pour afficher la distance pour un enregistrement sélectionné:

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);

Par exemple, un MySQL sélectionnez pourrait être (tirée de: 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

Actuellement, je sélectionner les emplacements en utilisant les éléments suivants:

OK est-il possible d'utiliser la base de données SQLITE de cette manière? Si ce n'est pas la seule option que je peux penser est d'avoir une colonne supplémentaire, itérer à travers les lignes exécutant la fonction ci-dessus sur chaque ligne et remplir une colonne supplémentaire sur la ligne, puis le tri sur cette colonne?

Répondre

4

Cela ne va pas complètement aider, mais pour des situations comme celle-ci, sérieusement envisager d'utiliser rawQuery() au lieu de query(), de sorte que vous pouvez transmettre une instruction SQL complète par rapport à devoir couper en morceaux.


Votre plus gros problème est que je ne vois pas que SQLite a des fonctions trigonométriques.

Vous n'indiquez pas comment vous utilisez le Cursor vous revenez de votre requête.Par exemple, si vous mettez le Cursor dans une sorte de CursorAdapter, vous pouvez:

  • convertir le Cursor en un ArrayList<Position>, où Position est une classe Java vous définissez avec vos données
  • fermer la Cursor, à libérer la RAM, il prend
  • sorte le ArrayList<Position> en utilisant Arrays.sort()
  • enroulez le ArrayList<Position> dans un ArrayAdapter<Position> et utiliser que lorsque vous aviez utilisé votre CursorAdapter
+0

intégré d'android OK pour le test, j'ai créé un ArrayList > et rempli avec tous les détails requis. J'ai également créé une classe simple qui étend l'objet, ArrayList . Je parcourt le curseur et place les données, actuellement, dans les deux listes comme je le fais. J'effectue le calcul de la distance et je l'ajoute. Comment puis-je effectuer le tri? La classe est: classe locationRowDist extends Object { public String title; public double lat; public double lon; public double dist; } – Scoobler

+0

Si "locationRowDist" est une classe, faites-la implémenter l'interface Comparable, puis utilisez Arrays.sort() pour le trier. – CommonsWare

3

Oui, cela fonctionne parfaitement.

il peut être transformé en une procédure stockée comme ceci:

http://www.thismuchiknow.co.uk/?p=71 [Fonction de distance pour sqlite]

il y a aussi le Perst spatial database for android qui est excellent, et la base de données spatiale SpatiaLite qui est aussi génial, que vous pourrait lier à dans votre application.

En utilisant une lib spécialisée, vous pouvez approximer la distance de quelques façons (la calculer comme si elle était planaire) puis utiliser la formule de Haversine pour trier le sous-ensemble plus tard, utiliser une table de correspondance , sin, etc., regrouper les emplacements dans 5 zones de mile et rechercher les cellules voisines jusqu'au maximum, etc ...)

+3

La technique que vous décrivez ne semble pas être applicable à Android, qui ne peut pas utiliser sqlite3_create_fun ction(). – CommonsWare

+0

ouais avec une grande base de données de localisation serait bon d'utiliser votre propre sqlite/perst/spatialite au lieu de – jspcal

0

Je viens d'écrire une application qui a besoin de trier un ensemble de coordonnées en fonction de la distance. Ce que j'ai fait a été de créer un tableau d'ID et de Distances, puis de les trier dans Java. Ensuite, je pourrais trouver les endroits les plus proches et les sélectionner dans la base de données. Bien sûr, cette approche peut ne pas fonctionner pour vous en fonction du nombre de points que vous avez et comment vous accédez à la base de données. Cela a bien fonctionné pour ~ 350 points, dans mon application Finder Nando.

De plus j'ai utilisé Location.distanceBetween (..) du SDK pour calculer les distances pour moi. J'espère que cette méthode serait mise en œuvre en C pour assurer qu'il est rapide, cependant, un coup d'oeil à la SDK source montre qu'il est écrit en Java :(

3

Dans mon application BostonBusMap j'ai utilisé une approximation pour accélérer le calcul Vous pouvez modifier la longitude par cos(latitude) puis utiliser la formule de Pythagore pour calculer une distance de tri (en omettant la route car elle n'est pas nécessaire pour une distance de comparaison.) Elle fonctionne raisonnablement bien pour les petites distances

Source: http://en.wikipedia.org/wiki/Geographical_distance#Spherical_Earth_projected_to_a_plane

Questions connexes