んで、やりたかったのは、「緯度経度で地図上のあるエリアの範囲内かどうか?」というのを判定する、みたいなこと。
要素 | 役割 | |
---|---|---|
IGeoArea | 地図エリアインターフェース | 地図上のあるエリアのインターフェース |
GeoCircleArea | 地図エリア(円形)クラス | 地図上のある円形エリアのクラス |
GeoRectangleArea | 地図エリア(矩形)クラス | 地図上のある矩形エリアのクラス 矩形の開始・終了位置の経度の大小が逆転した場合は、反対方向への範囲を示す。 (必ず、開始位置が西側、終了位置が東側となるようなエリアとなる) |
昨日のGeoLocation#distanceメソッドも、円形エリア内かどうかの判定(withinメソッド)で使いたかった訳で。
GeoRectangleArea#withinメソッドは、境界値の判定を見直してみたり。
IGeoAreaインターフェース
/** * 地図エリアインターフェース * @author saku.jp */ public interface IGeoArea { /** * エリア内かどうか判定する。 * @param location エリア内か判定する位置 * @return エリア内かどうか */ public boolean within(GeoLocation location); }
GeoCircleAreaクラス
/** * 地図エリア(円形)クラス * @author saku.jp */ public class GeoCircleArea implements IGeoArea { /** * エリアの中心 */ private GeoLocation location = null; /** * エリアの半径[m] */ private int radius = 0; /** * エリアの中心を取得する。 * @return エリアの中心 */ public GeoLocation getLocation() { return this.location; } /** * エリアの中心を設定する。 * @param location エリアの中心 */ private void setLocation(GeoLocation location) { this.location = location; } /** * エリアの半径[m]を取得する。 * @return エリアの半径[m] */ public int getRadius() { return this.radius; } /** * エリアの半径[m]を設定する。 * @param radius エリアの半径[m] */ private void setRadius(int radius) { this.radius = radius; } /** * コンストラクタ * @param location エリアの中心 * @param radius エリアの半径[m] */ public GeoCircleArea(GeoLocation location, int radius) { super(); setLocation(location); setRadius(radius ); } @Override public boolean within(GeoLocation location) { // 指定された位置と中心との距離が半径以下であれば範囲内 return (getLocation().distance(location) <= getRadius()); } }
GeoRectangleAreaクラス
/** * 地図エリア(矩形)クラス * 矩形の開始・終了位置の経度の大小が逆転した場合は、反対方向への範囲を示す。 * @author saku.jp */ public class GeoRectangleArea implements IGeoArea { /** * 矩形エリア開始位置 */ private GeoLocation startLocation = null; /** * 矩形エリア終了位置 */ private GeoLocation endLocation = null; /** * 矩形エリア開始位置を取得する。 * @return 矩形エリア開始位置 */ public GeoLocation getStartLocation() { return this.startLocation; } /** * 矩形エリア開始位置を設定する。 * @param startLocation 矩形エリア開始位置 */ private void setStartLocation(GeoLocation startLocation) { this.startLocation = startLocation; } /** * 矩形エリア終了位置を取得する。 * @return 矩形エリア終了位置 */ public GeoLocation getEndLocation() { return this.endLocation; } /** * 矩形エリア終了位置を設定する。 * @param endLocation 矩形エリア終了位置 */ private void setEndLocationTo(GeoLocation endLocation) { this.endLocation = endLocation; } /** * コンストラクタ * @param startLocation 矩形エリア開始位置 * @param endLocation 矩形エリア終了位置 */ public GeoRectangleArea(GeoLocation startLocation, GeoLocation endLocation) { super(); setStartLocation(startLocation); setEndLocationTo(endLocation ); } @Override public boolean within(GeoLocation location) { // 緯度の範囲 double minLat = Math.min(getStartLocation().getLatitude(), getEndLocation().getLatitude()); double maxLat = Math.max(getStartLocation().getLatitude(), getEndLocation().getLatitude()); // 緯度が範囲外ならfalse if ((minLat > location.getLatitude()) || (maxLat < location.getLatitude())) { return false; } // 経度の範囲 double minLng = getStartLocation().getLongitude(); double maxLng = getEndLocation().getLongitude(); // 経度が範囲外ならfalse if (minLng <= maxLng) { if ((minLng > location.getLongitude()) || (maxLng < location.getLongitude())) { return false; } } else { // 東経(+)から西経(-)に跨ぐ場合の判定 if ((minLng > location.getLongitude()) && (maxLng < location.getLongitude())) { return false; } } // 範囲内 return true; } }
GeoCircleAreaクラスのテストクラス
public class GeoCircleAreaTest { @Test public void testWithin() { // 東京駅を基準にする GeoLocation tokyo = new GeoLocation(35.681257, 139.767138); GeoCircleArea area1 = new GeoCircleArea(tokyo, 1000); // 半径 1[km] GeoCircleArea area10 = new GeoCircleArea(tokyo, 10000); // 半径 10[km] GeoCircleArea area100 = new GeoCircleArea(tokyo, 100000); // 半径 100[km] GeoCircleArea area1000 = new GeoCircleArea(tokyo, 1000000); // 半径 1,000[km] GeoCircleArea area10000 = new GeoCircleArea(tokyo, 10000000); // 半径 10,000[km] GeoCircleArea area100000 = new GeoCircleArea(tokyo, 100000000); // 半径100,000[km] // 品川駅(東京駅から6,415[m]<6.41[km]>くらい)がエリア内かどうか GeoLocation shinagawa = new GeoLocation(35.628452, 139.738733); assertEquals(area1.within(shinagawa), false); assertEquals(area10.within(shinagawa), true); assertEquals(area100.within(shinagawa), true); assertEquals(area1000.within(shinagawa), true); assertEquals(area10000.within(shinagawa), true); assertEquals(area100000.within(shinagawa), true); // 岡山駅(東京駅から543,961[m]<543[km]>くらい)がエリア内かどうか GeoLocation okayama = new GeoLocation(34.666204, 133.918477); assertEquals(area1.within(okayama), false); assertEquals(area10.within(okayama), false); assertEquals(area100.within(okayama), false); assertEquals(area1000.within(okayama), true); assertEquals(area10000.within(okayama), true); assertEquals(area100000.within(okayama), true); // シドニー(東京駅から7,839,152[m]<7,839[km]>くらい)がエリア内かどうか GeoLocation sydney = new GeoLocation(-33.9277, 151.171885); assertEquals(area1.within(sydney), false); assertEquals(area10.within(sydney), false); assertEquals(area100.within(sydney), false); assertEquals(area1000.within(sydney), false); assertEquals(area10000.within(sydney), true); assertEquals(area100000.within(sydney), true); // 自由の女神(東京駅から10,859,371[m]<10,859[km]>くらい)がエリア内かどうか GeoLocation liberty = new GeoLocation(40.692874,-74.044962); assertEquals(area1.within(liberty), false); assertEquals(area10.within(liberty), false); assertEquals(area100.within(liberty), false); assertEquals(area1000.within(liberty), false); assertEquals(area10000.within(liberty), false); assertEquals(area100000.within(liberty), true); // リオデジャネイロ(東京駅から18,588,043[m]<18,588[km]>くらい)がエリア内かどうか GeoLocation rio = new GeoLocation(-22.912248,-43.166574); assertEquals(area1.within(rio), false); assertEquals(area10.within(rio), false); assertEquals(area100.within(rio), false); assertEquals(area1000.within(rio), false); assertEquals(area10000.within(rio), false); assertEquals(area100000.within(rio), true); } }
GeoRectangleAreaクラスのテストクラス
import static org.junit.Assert.*; import org.junit.Test; public class GeoRectangleAreaTest { @Test public void testWithin() { // 長野駅 GeoLocation nagano = new GeoLocation(36.642946, 138.188763); // 高松駅 GeoLocation takamatsu = new GeoLocation(34.350682,134.046919); // 長野駅から高松駅の範囲(反対方向) GeoRectangleArea area1 = new GeoRectangleArea(nagano, takamatsu); // 高松駅から長野駅の範囲 GeoRectangleArea area2 = new GeoRectangleArea(takamatsu, nagano); // 大阪駅がエリア内かどうか GeoLocation osaka = new GeoLocation(34.70191, 135.494977); assertEquals(area1.within(osaka), false); // 経度が外れてエリア外 assertEquals(area2.within(osaka), true); // エリア内 // 名古屋駅がエリア内かどうか GeoLocation naogoya = new GeoLocation(35.170693, 136.881628); assertEquals(area1.within(naogoya), false); // 経度が外れてエリア外 assertEquals(area2.within(naogoya), true); // エリア内 // 金沢駅がエリア内かどうか GeoLocation kanazawa = new GeoLocation(36.578252, 136.647771); assertEquals(area1.within(kanazawa), false); // 経度が外れてエリア外 assertEquals(area2.within(kanazawa), true); // エリア内 // 品川駅がエリア内かどうか GeoLocation shinagawa = new GeoLocation(35.628452, 139.738733); assertEquals(area1.within(shinagawa), true); // 反対方向でエリア内 assertEquals(area2.within(shinagawa), false); // 経度が外れてエリア外 // 岡山駅がエリア内かどうか GeoLocation okayama = new GeoLocation(34.666204, 133.918477); assertEquals(area1.within(okayama), true); // 反対方向でエリア内 assertEquals(area2.within(okayama), false); // 経度が外れてエリア外 // 富山駅がエリア内かどうか GeoLocation toyama = new GeoLocation(36.701221, 137.213179); assertEquals(area1.within(toyama), false); // 緯度経度が外れてエリア外 assertEquals(area2.within(toyama), false); // 緯度が外れてエリア外 // 徳島駅がエリア内かどうか GeoLocation tokushima = new GeoLocation(34.074662, 134.550761); assertEquals(area1.within(tokushima), false); // 緯度経度が外れてエリア外 assertEquals(area2.within(tokushima), false); // 緯度が外れてエリア外 // 札幌 GeoLocation sapporo = new GeoLocation(43.062617, 141.35416); // ケープタウン GeoLocation capetown = new GeoLocation(-33.924631, 18.42423); // 札幌からケープタウンの範囲(反対方向) GeoRectangleArea area3 = new GeoRectangleArea(sapporo, capetown); // ケープタウンから札幌の範囲 GeoRectangleArea area4 = new GeoRectangleArea(capetown, sapporo); // ニューデリーがエリア内かどうか GeoLocation newdelhi = new GeoLocation(28.635289, 77.224957); assertEquals(area3.within(newdelhi), false); // 経度が外れてエリア外 assertEquals(area4.within(newdelhi), true); // エリア内 // 北京がエリア内かどうか GeoLocation beijing = new GeoLocation(39.904033, 116.407527); assertEquals(area3.within(beijing), false); // 経度が外れてエリア外 assertEquals(area4.within(beijing), true); // エリア内 // メキシコシティがエリア内かどうか GeoLocation mexico = new GeoLocation(19.432606, -99.133207); assertEquals(area3.within(mexico), true); // 反対方向でエリア内 assertEquals(area4.within(mexico), false); // 経度が外れてエリア外 // ハワイがエリア内かどうか GeoLocation hawaii = new GeoLocation(19.897018, -155.582571); assertEquals(area3.within(hawaii), true); // 反対方向でエリア内 assertEquals(area4.within(hawaii), false); // 経度が外れてエリア外 // シドニーがエリア内かどうか GeoLocation sydney = new GeoLocation(-33.9277, 151.171885); assertEquals(area3.within(sydney), false); // 緯度が外れてエリア外 assertEquals(area4.within(sydney), false); // 緯度経度が外れてエリア外 // ロンドンがエリア内かどうか GeoLocation london = new GeoLocation(51.5073, -0.127645); assertEquals(area3.within(london), false); // 緯度が外れてエリア外 assertEquals(area4.within(london), false); // 緯度経度が外れてエリア外 // 札幌がエリア内かどうか assertEquals(area3.within(sapporo), true); // 境界でエリア内 assertEquals(area4.within(sapporo), true); // 境界でエリア内 // ケープタウンがエリア内かどうか assertEquals(area3.within(capetown), true); // 境界でエリア内 assertEquals(area4.within(capetown), true); // 境界でエリア内 } }