How to retrieve a set of locations within particular range from user's location from SQLite database

偶尔善良 提交于 2019-12-04 06:18:35

问题


I have some location coordinates stored in my SQLite database table. I want to retrieve the locations within 1 km range from the use's current location. Right now I am fetching all values from database and have written a method to retrieve the values within my range. This leaves me great overhead as my table might contain more than 1000 coordinates.

So i am looking for a better way to do this. Is it possible to directly retrieve locations within my range directly using SELECT query? I found question 1 and question 2 but couldn't find a possible workaround.Any help will be greatly appreciated.

This is my SELECT Query now :

String selectQuery = "SELECT  "+COLUMN_OBJECTID+","+COLUMN_OBJECTNAME_ENGLISH+"," 
                      +COLUMN_OBJECTNAME_ARABIC+","+COLUMN_OBJECTLATITUDE+","+COLUMN_OBJECTLONGITUDE+"," 
                              +COLUMN_OBJECTCATEGORYID+","+COLUMN_OBJECTADDRESS_ENGLISH+","+COLUMN_OBJECTADDRESS_ARABIC 
                              +" FROM " + TABLE_OBJECTLIST+" WHERE "+COLUMN_OBJECTCATEGORYID+"='"+categoryId+"' AND "+ 
                              ((userLat-Double.parseDouble(COLUMN_OBJECTLATITUDE))*(userLat-Double.parseDouble(COLUMN_OBJECTLATITUDE)) 
                                      +(userLong-Double.parseDouble(COLUMN_OBJECTLONGITUDE))*(userLong-Double.parseDouble(COLUMN_OBJECTLONGITUDE))<=range);

回答1:


You can write a SQL query with following where condition :

where ( (my_lat - LAT)*(my_lat - LAT) + (my_lon - LON)*(my_lon - LON) ) <= 1KM

The idea is that use Pythagoras method to calculate approx location and filter based on that. Here I have not taken the square root because I guess SQL functions in SQLite don't have sqrt.

This is good for approximate calculations ...

I used following SQL and it worked ...

// Table with columns as String and Float
CREATE TABLE "locations" ("id" INTEGER PRIMARY KEY  AUTOINCREMENT  NOT NULL , "lat_string" VARCHAR, "long_string" VARCHAR, "lat_val" FLOAT, "long_val" FLOAT)

// Insert example data
INSERT INTO "locations" VALUES(1,'12.9587926','77.7477416',12.9587926,77.7477416);
INSERT INTO "locations" VALUES(2,'12.9973486','77.6967362',12.9973486,77.69673619999999);
INSERT INTO "locations" VALUES(3,'12.9715987','77.5945627',12.9715987,77.5945627);
INSERT INTO "locations" VALUES(4,'12.9629354','77.7122996',12.9629354,77.7122996);

// Select when column format is string. This works in SQLIte
SELECT id, ( (77.7580827 - long_string)*(77.7580827 - long_string) + (12.9905542 - lat_string)*(12.9905542 - lat_string) ) as dist FROM locations

// Select when column format is float. This works in SQLIte
SELECT id, ( (77.7580827 - long_val)*(77.7580827 - long_val) + (12.9905542 - lat_val)*(12.9905542 - lat_val) ) as dist FROM locations



回答2:


Here is some code which should give you an idea how to get it working:

public static double[] getNeighbourhoodArea(
            final double lat, final double lng, final int distInMtrs) {

        double[] area = new double[4];

        final double latRadian = Math.toRadians(lat);

        final double degLatKm = 110.574235;
        final double degLngKm = 110.572833 * Math.cos(latRadian);
        final double deltaLat = distInMtrs / 1000.0 / degLatKm;
        final double deltaLong = distInMtrs / 1000.0 / degLngKm;

        final double minLat = lat - deltaLat;
        final double minLng = lng - deltaLong;
        final double maxLat = lat + deltaLat;
        final double maxLng = lng + deltaLong;

        area[0] = minLat;
        area[1] = minLng;
        area[2] = maxLat;
        area[3] = maxLng;

        return area;
    }


    /**
     * search POIs in the neighbourhood
     */
    private PntInrtst collectPOIs(double lat, double lng) {

        if (mDb == null) return Const.NULL_POI;

        Cursor cursorStat = mDb.getPoisInArea(lat, lng, Const.SIDE_LENGTH_GEO_OFFSET);

        double area[] = Logic.getProtectionArea(lat, lng, Const.SIDE_LENGTH_GEO_OFFSET);

        ArrayList<PntInrtst> poiArray = new ArrayList<PntInrtst>();

        PntInrtst poi = Const.NULL_POI;

        if (cursorStat.moveToFirst()) {
            for (int i = 0; i < cursorStat.getCount(); i++) {
                double potLat = cursorStat.getFloat(Const.COL_LA);
                double potLng = cursorStat.getFloat(Const.COL_LO);

                if ((potLat < area[Const.MAX_LAT] && potLat > area[Const.MIN_LAT])
                    && (potLng < area[Const.MAX_LNG] && potLng > area[Const.MIN_LNG])) {

                    poi = Logic.getPoiByCursor(getApplicationContext(), cursorStat);
                    poiArray.add(poi);

                }
                cursorStat.moveToNext();
            } // End "Cursor"
        }
        cursorStat.close();

        // more than once, fire the nearest
        if (poiArray.size() > 1) return closest(poiArray, lat, lng);
        else return poi; // one or null
    }


    /**
     * filter POIs which won't be useful (avoids flooding the cache)
     */
    public Cursor getPoisInArea(double latitude, double longitude, int range) {

        double area[] = getNeighbourhoodArea(latitude, longitude, range);

        String where = "la" + "<" + area[MAX_LAT] +
                       " AND " + "la" + ">" + area[MIN_LAT] +
                       " AND " + "lo" + "<" + area[MAX_LNG] +
                       " AND " + "lo" + ">" + area[MIN_LNG];

        SQLiteDatabase db = mDbHelper.getReadableDatabase();
        return db.query(Const.POI_DB_TABLE, null, where, null, null, null, null);
    }


来源:https://stackoverflow.com/questions/33492505/how-to-retrieve-a-set-of-locations-within-particular-range-from-users-location

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!