地図の位置として、緯度経度を取り扱うクラスがなかったので、ずーっと前からチマチマ書いてた。
位置から位置までの地点間の距離を求めるdistanceメソッドは、地球を真球として球体の表面の距離を計算する計算式で実装してみた。
位置情報も含めて、そんなに精度が欲しいって場合じゃないし。
GeoLocationクラス
/** * 地図位置クラス * @author saku.jp */ public class GeoLocation { /** * 赤道の半径[m] */ private static double EARTH_R = 6378137d; /** * 緯度(北緯は+0d〜+90d、南緯は-0d〜-90d) */ private double latitude = 0d; /** * 経度(東経は+0d〜+180d、西経は-0d〜-180d) */ private double longitude = 0d; /** * 緯度を取得する。 * @return 緯度 */ public double getLatitude() { return this.latitude; } /** * 緯度を設定する。 * @param latitude 緯度 */ private void setLatitude(double latitude) { this.latitude = latitude; } /** * 経度を取得する。 * @return 経度 */ public double getLongitude() { return this.longitude ; } /** * 経度を設定する。 * @param longitude 経度 */ private void setLongitude(double longitude ) { this.longitude = longitude ; } /** * コンストラクタ * @param latitude 緯度 * @param longitude 経度 */ public GeoLocation(double latitude, double longitude) { super(); setLatitude(latitude); setLongitude(longitude); } /** * 地点間の距離[m]を求める。(地球を真球として計算) * @param location 地点 * @return 地点間の距離[m] */ public double distance(GeoLocation location) { // 起点(自分自身のラジアン位置) double lng0 = this.getLongitude() * Math.PI / 180d; double lat0 = this.getLatitude() * Math.PI / 180d; // 終点(指定されたラジアン位置) double lng1 = location.getLongitude() * Math.PI / 180d; double lat1 = location.getLatitude() * Math.PI / 180d; // 地球(球体)の表面の距離を計算 return EARTH_R * Math.acos(Math.sin(lat0) * Math.sin(lat1) + Math.cos(lat0) * Math.cos(lat1) * Math.cos(lng1 - lng0)); } }
GeoLocationクラスのテストクラス
distanceメソッドだけね。
import static org.junit.Assert.assertEquals; import org.junit.Test; public class GeoLocationTest { /** * 1[m]未満は許容 */ private static double ERR_RANGE = 0.9999999999d; @Test public void testDistance() { // 東京駅を基準にする GeoLocation tokyo = new GeoLocation(35.681257d, 139.767138d); // 品川駅までの距離[m](東京駅から6,415[m]<6.41[km]>くらい、ERR_RANGEは許容) GeoLocation shinagawa = new GeoLocation(35.628452d, 139.738733d); assertEquals(tokyo.distance(shinagawa), 6415.197981237259d, ERR_RANGE); // 岡山駅までの距離[m](東京駅から543,961[m]<543[km]>くらい、ERR_RANGEは許容) GeoLocation okayama = new GeoLocation(34.666204d, 133.918477d); assertEquals(tokyo.distance(okayama), 543961.8995168353d, ERR_RANGE); // シドニーまでの距離[m](東京駅から7,839,152[m]<7,839[km]>くらい、ERR_RANGEは許容) GeoLocation sydney = new GeoLocation(-33.9277d, 151.171885d); assertEquals(tokyo.distance(sydney), 7839152.635102973d, ERR_RANGE); // 自由の女神までの距離[m](東京駅から10,859,371[m]<10,859[km]>くらい、ERR_RANGEは許容) GeoLocation liberty = new GeoLocation(40.692874d, -74.044962d); assertEquals(tokyo.distance(liberty), 10859371.457276043d, ERR_RANGE); // リオデジャネイロ までの距離[m](東京駅から18,588,043[m]<18,588[km]>くらい、ERR_RANGEは許容) GeoLocation rio = new GeoLocation(-22.912248d, -43.166574d); assertEquals(tokyo.distance(rio), 18588043.66302361d, ERR_RANGE); } }