一連の緯度/経度座標の周囲の最小外接長方形を決定するアルゴリズムはありますか?
座標が離れすぎないため、地球が平らであると想定しても問題ありません。疑似コードは問題ありませんが、誰かが Objective-C でこれを行った場合、それはさらに良いでしょう。私がやろうとしているのは、マップに表示されるポイントの数に基づいてマップのズーム レベルを設定することです。
一連の緯度/経度座標の周囲の最小外接長方形を決定するアルゴリズムはありますか?
座標が離れすぎないため、地球が平らであると想定しても問題ありません。疑似コードは問題ありませんが、誰かが Objective-C でこれを行った場合、それはさらに良いでしょう。私がやろうとしているのは、マップに表示されるポイントの数に基づいてマップのズーム レベルを設定することです。
これにより、左上のポイントの最小の緯度/経度と、右下のポイントの最大の緯度/経度が検出されます。
double minLat = 900;
double minLon = 900;
double maxLat = -900;
double maxLon = -900;
foreach(Point point in latloncollection )
{
minLat = Math.min( minLat, point.lat );
minLon = Math.min( minLon, point.lon );
maxLat = Math.max( maxLat, point.lat );
maxLon = Math.max( maxLon, point.lon );
}
OP は外接する四角形を使用してマップ上に設定する必要があるため、アルゴリズムは、緯度と経度が球座標系にあり、マップが 2 次元座標系を使用しているという事実を考慮する必要があります。これまでに投稿されたソリューションはどれもこれを考慮していないため、間違った境界四角形になってしまいますが、幸いなことに、WWDC 2013 の「Whats new in MapKit」のサンプル コードにある MKMapPointForCoordinate メソッドを使用して、有効なソリューションを簡単に作成できます。セッションビデオ。
MKMapRect MapRectBoundingMapPoints(MKMapPoint points[], NSInteger pointCount){
double minX = INFINITY, maxX = -INFINITY, minY = INFINITY, maxY = -INFINITY;
NSInteger i;
for(i = -; i< pointCount; i++){
MKMapPoint p = points[i];
minX = MIN(p.x,minX);
minY = MIN(p.y,minY);
maxX = MAX(p.x,maxX);
maxY = MAX(p.y,maxY);
}
return MKMapRectMake(minX,minY,maxX - minX,maxY-minY);
}
CLLocationCoordinate2D london = CLLocationCoordinate2DMake(51.500756,-0.124661);
CLLocationCoordinate2D paris = CLLocationCoordinate2DMake(48.855228,2.34523);
MKMapPoint points[] = {MKMapPointForCoordinate(london),MKMapPointForCoordinate(paris)};
MKMapRect rect = MapRectBoundingMapPoints(points,2);
rect = MKMapRectInset(rect,
-rect.size.width * 0.05,
-rect.size.height * 0.05);
MKCoordinateRegion coordinateRegion = MKCoordinateRegionForMapRect(rect);
必要に応じて、注釈の NSArray で機能するようにメソッドを簡単に変更できます。たとえば、アプリケーションで使用している方法は次のとおりです。
- (MKCoordinateRegion)regionForAnnotations:(NSArray*)anns{
MKCoordinateRegion r;
if ([anns count] == 0){
return r;
}
double minX = INFINITY, maxX = -INFINITY, minY = INFINITY, maxY = -INFINITY;
for(id<MKAnnotation> a in anns){
MKMapPoint p = MKMapPointForCoordinate(a.coordinate);
minX = MIN(p.x,minX);
minY = MIN(p.y,minY);
maxX = MAX(p.x,maxX);
maxY = MAX(p.y,maxY);
}
MKMapRect rect = MKMapRectMake(minX,minY,maxX - minX,maxY-minY);
rect = MKMapRectInset(rect,
-rect.size.width * 0.05,
-rect.size.height * 0.05);
return MKCoordinateRegionForMapRect(rect);
}
public BoundingRectangle calculateBoundingRectangle()
{
Coordinate bndRectTopLeft = new Coordinate();
Coordinate bndRectBtRight = new Coordinate();
// Initialize bounding rectangle with first point
Coordinate firstPoint = getVertices().get(0);
bndRectTopLeft.setLongitude(firstPoint.getLongitude());
bndRectTopLeft.setLatitude(firstPoint.getLatitude());
bndRectBtRight.setLongitude(firstPoint.getLongitude());
bndRectBtRight.setLatitude(firstPoint.getLatitude());
double tempLong;
double tempLat;
// Iterate through all the points
for (int i = 0; i < getVertices().size(); i++)
{
Coordinate curNode = getVertices().get(i);
tempLong = curNode.getLongitude();
tempLat = curNode.getLatitude();
if (bndRectTopLeft.getLongitude() > tempLong) bndRectTopLeft.setLongitude(tempLong);
if (bndRectTopLeft.getLatitude() < tempLat) bndRectTopLeft.setLatitude(tempLat);
if (bndRectBtRight.getLongitude() < tempLong) bndRectBtRight.setLongitude(tempLong);
if (bndRectBtRight.getLatitude() > tempLat) bndRectBtRight.setLatitude(tempLat);
}
bndRectTopLeft.setLatitude(bndRectTopLeft.getLatitude());
bndRectBtRight.setLatitude(bndRectBtRight.getLatitude());
// Throw an error if boundaries contains poles
if ((Math.toRadians(topLeft.getLatitude()) >= (Math.PI / 2)) || (Math.toRadians(bottomRight.getLatitude()) <= -(Math.PI / 2)))
{
// Error
throw new Exception("boundaries contains poles");
}
// Now calculate bounding x coordinates
// Calculate it along latitude circle for the latitude closure to the
// pole
// (either north or south). For the other end the loitering distance
// will be slightly higher
double tempLat1 = bndRectTopLeft.getLatitude();
if (bndRectBtRight.getLatitude() < 0)
{
if (tempLat1 < (-bndRectBtRight.getLatitude()))
{
tempLat1 = (-bndRectBtRight.getLatitude());
}
}
bndRectTopLeft.setLongitude(bndRectTopLeft.getLongitude());
bndRectBtRight.setLongitude(bndRectBtRight.getLongitude());
// What if international date line is coming in between ?
// It will not affect any calculation but the range for x coordinate for the bounding rectangle will be -2.PI to +2.PI
// But the bounding rectangle should not cross itself
if ((Math.toRadians(bottomRight.getLongitude()) - Math.toRadians(topLeft.getLongitude())) >= (2 * Math.PI))
{
// Throw some error
throw new Exception("Bounding Rectangle crossing itself");
}
return new BoundingRectangle(bndRectTopLeft, bndRectBtRight);
}
これは、領域が極を横切る場合の例外を処理します。
一番左、一番上、一番右、一番下の値を取得するだけです。これは並べ替えによって非常に簡単に行うことができ、セットが大きすぎない限り、それほど高価ではありません。
と呼ばれる緯度/経度クラスのメソッドを指定するcompareLatitude:
とcompareLongitude:
、さらに簡単になります。
CGFloat north, west, east, south;
[latLongCollection sortUsingSelector:@selector(compareLongitude:)];
west = [[latLongCollection objectAtIndex:0] longitude];
east = [[latLongCollection lastObject] longitude];
[latLongCollection sortUsingSelector:@selector(compareLatitude:)];
south = [[latLongCollection objectAtIndex:0] latitude];
north = [[latLongCollection lastObject] latitude];
座標のコレクションが NSMutableArray であると仮定すると、そのようなものが機能するはずです。
やりたいことについては、おそらく Lat と Long の最小値と最大値を見つけて、それらを長方形の境界として使用することができます。より高度なソリューションについては、次を参照してください。
Objective-C を使用している場合は、代わりに Objective-C++ を使用できる場合があります。その場合、STL を使用して多くの面倒な作業を行うことができます。
#include <vector>
#include <algorithm>
std::vector<float> latitude_set;
std::vector<float> longitude_set;
latitude_set.push_back(latitude_a);
latitude_set.push_back(latitude_b);
latitude_set.push_back(latitude_c);
latitude_set.push_back(latitude_d);
latitude_set.push_back(latitude_e);
longitude_set.push_back(longitude_a);
longitude_set.push_back(longitude_b);
longitude_set.push_back(longitude_c);
longitude_set.push_back(longitude_d);
longitude_set.push_back(longitude_e);
float min_latitude = *std::min_element(latitude_set.begin(), latitude_set.end());
float max_latitude = *std::max_element(latitude_set.begin(), latitude_set.end());
float min_longitude = *std::min_element(longitude_set.begin(), longitude_set.end());
float max_longitude = *std::max_element(longitude_set.begin(), longitude_set.end());