[解決済み] SQlite 最寄り位置の取得(緯度・経度付き)
質問
SQLiteデータベースに緯度経度のデータが保存されているのですが、入力したパラメータ(例:現在地-lat/lngなど)に最も近い場所を取得したいのです。
私はこれがMySQLで可能であることを知っており、SQLiteがHaversine式(球面上の距離計算)のためのカスタム外部関数を必要とすることをかなり調査しましたが、Javaで書かれていて動作するものを見つけられませんでした。
また、カスタム関数を追加したい場合は
org.sqlite
.jar (
org.sqlite.Function
の場合)、アプリに不必要なサイズが追加されます。
この反対側は、距離だけを表示することはそれほど問題ではないので、SQL からの Order by 関数が必要です。私はすでにカスタムの SimpleCursorAdapter でそれを行いましたが、データベースに距離カラムがないので、データをソートすることはできません。それは場所が変わるたびにデータベースを更新することを意味し、それはバッテリーとパフォーマンスの浪費です。なので、どなたかデータベースにないカラムでカーソルをソートするアイデアがあれば、私もありがたいです
この機能を使うAndroidアプリが大量にあるのは知っていますが、どなたかマジックを解説してください。
ちなみに、こんな代替案もありました。 SQLiteでRadiusに基づくレコードを取得するクエリ?
緯度と経度のcosとsinの値のために4つの新しいカラムを作成することを提案していますが、他のあまり冗長でない方法はありますか?
どのように解決するのですか?
1) まず、SQLiteのデータを良い近似値でフィルタリングし、Javaコードで評価する必要のあるデータ量を減らしてください。そのために、以下の手順を使用します。
決定論的な
閾値
を計算し、より正確なフィルタリングを行うことができます。
4ヶ所
にある
radius
メートル、中心点から北、西、東、南にある
をjavaコードで指定します。
と入力し、次に
よりも小さい、またはより大きいSQL演算子(>, <)で簡単にチェックできます。
を使って、データベース内の点がその矩形に収まっているかどうかを判断します。
メソッド
calculateDerivedPosition(...)
はこれらの点(図ではp1, p2, p3, p4)を計算します。
/**
* Calculates the end-point from a given source at a given range (meters)
* and bearing (degrees). This methods uses simple geometry equations to
* calculate the end-point.
*
* @param point
* Point of origin
* @param range
* Range in meters
* @param bearing
* Bearing in degrees
* @return End-point from the source given the desired range and bearing.
*/
public static PointF calculateDerivedPosition(PointF point,
double range, double bearing)
{
double EarthRadius = 6371000; // m
double latA = Math.toRadians(point.x);
double lonA = Math.toRadians(point.y);
double angularDistance = range / EarthRadius;
double trueCourse = Math.toRadians(bearing);
double lat = Math.asin(
Math.sin(latA) * Math.cos(angularDistance) +
Math.cos(latA) * Math.sin(angularDistance)
* Math.cos(trueCourse));
double dlon = Math.atan2(
Math.sin(trueCourse) * Math.sin(angularDistance)
* Math.cos(latA),
Math.cos(angularDistance) - Math.sin(latA) * Math.sin(lat));
double lon = ((lonA + dlon + Math.PI) % (Math.PI * 2)) - Math.PI;
lat = Math.toDegrees(lat);
lon = Math.toDegrees(lon);
PointF newPoint = new PointF((float) lat, (float) lon);
return newPoint;
}
そして、クエリを作成します。
PointF center = new PointF(x, y);
final double mult = 1; // mult = 1.1; is more reliable
PointF p1 = calculateDerivedPosition(center, mult * radius, 0);
PointF p2 = calculateDerivedPosition(center, mult * radius, 90);
PointF p3 = calculateDerivedPosition(center, mult * radius, 180);
PointF p4 = calculateDerivedPosition(center, mult * radius, 270);
strWhere = " WHERE "
+ COL_X + " > " + String.valueOf(p3.x) + " AND "
+ COL_X + " < " + String.valueOf(p1.x) + " AND "
+ COL_Y + " < " + String.valueOf(p2.y) + " AND "
+ COL_Y + " > " + String.valueOf(p4.y);
COL_X
は緯度の値を格納するデータベースのカラムの名前であり
COL_Y
は経度のためのものです。
中心点の近くに、近似の良いデータがあるわけですね。
2) さて、これらのフィルタリングされたデータをループさせ、以下の方法で本当に自分のポイント(円内)の近くにいるかどうかを判断することができます。
public static boolean pointIsInCircle(PointF pointForCheck, PointF center,
double radius) {
if (getDistanceBetweenTwoPoints(pointForCheck, center) <= radius)
return true;
else
return false;
}
public static double getDistanceBetweenTwoPoints(PointF p1, PointF p2) {
double R = 6371000; // m
double dLat = Math.toRadians(p2.x - p1.x);
double dLon = Math.toRadians(p2.y - p1.y);
double lat1 = Math.toRadians(p1.x);
double lat2 = Math.toRadians(p2.x);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) + Math.sin(dLon / 2)
* Math.sin(dLon / 2) * Math.cos(lat1) * Math.cos(lat2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
double d = R * c;
return d;
}
お楽しみに
私は この参照 を使い、完成させました。
関連
-
実行中にEclipseがポップアップする A Java Exception has occurred
-
executeQuery()でデータ操作文が発行できない。解決方法
-
スレッド "main" での例外 java.lang.ArrayIndexOutOfBoundsException:5 エラー
-
強制型変換について
-
-bash: java: コマンドが見つからない 解決方法
-
API の戻り値を処理するために ResponseEntity を使用する
-
java 365*1000*60*60*24 計算問題
-
[解決済み] SQLiteのINSERT/per-secondのパフォーマンスを向上させる
-
[解決済み] ATTACHで開いたSQLiteデータベースファイルのテーブルを一覧表示するにはどうすればよいですか?
-
[解決済み] 緯度と経度の座標を使用して、ある場所からタイムゾーンを取得する方法は?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン