ユーザーの場所がMKCoordinateRegionに属しているかどうかを確認する必要があります。このための単純な関数が見つからないことに驚きましたCGRectContainsCGPoint(rect、point)のようなもの。
次のコードが見つかりました:
CLLocationCoordinate2D topLeftCoordinate =
CLLocationCoordinate2DMake(region.center.latitude
+ (region.span.latitudeDelta/2.0),
region.center.longitude
- (region.span.longitudeDelta/2.0));
CLLocationCoordinate2D bottomRightCoordinate =
CLLocationCoordinate2DMake(region.center.latitude
- (region.span.latitudeDelta/2.0),
region.center.longitude
+ (region.span.longitudeDelta/2.0));
if (location.latitude < topLeftCoordinate.latitude || location.latitude > bottomRightCoordinate.latitude || location.longitude < bottomRightCoordinate.longitude || location.longitude > bottomRightCoordinate.longitude) {
// Coordinate fits into the region
}
ただし、ドキュメントでは領域の長方形の計算方法が正確に指定されていないため、正確かどうかはわかりません。
それを行うためのより簡単な方法がなければなりません。 MapKitフレームワークのドキュメントでいくつかの機能を見落としていませんか?
緯度と経度で混乱している人が他にいる場合は、ここでテスト済みの実用的なソリューションを紹介します。
MKCoordinateRegion region = self.mapView.region;
CLLocationCoordinate2D location = user.gpsposition.coordinate;
CLLocationCoordinate2D center = region.center;
CLLocationCoordinate2D northWestCorner, southEastCorner;
northWestCorner.latitude = center.latitude - (region.span.latitudeDelta / 2.0);
northWestCorner.longitude = center.longitude - (region.span.longitudeDelta / 2.0);
southEastCorner.latitude = center.latitude + (region.span.latitudeDelta / 2.0);
southEastCorner.longitude = center.longitude + (region.span.longitudeDelta / 2.0);
if (
location.latitude >= northWestCorner.latitude &&
location.latitude <= southEastCorner.latitude &&
location.longitude >= northWestCorner.longitude &&
location.longitude <= southEastCorner.longitude
)
{
// User location (location) in the region - OK :-)
NSLog(@"Center (%f, %f) span (%f, %f) user: (%f, %f)| IN!", region.center.latitude, region.center.longitude, region.span.latitudeDelta, region.span.longitudeDelta, location.latitude, location.longitude);
}else {
// User location (location) out of the region - NOT ok :-(
NSLog(@"Center (%f, %f) span (%f, %f) user: (%f, %f)| OUT!", region.center.latitude, region.center.longitude, region.span.latitudeDelta, region.span.longitudeDelta, location.latitude, location.longitude);
}
受け入れられた解決策は私の意見では有効ではないので、私はこの回答を投稿しています。この答えも完璧ではありませんが、座標が360度の境界を囲む場合を処理します。これは、私の状況に適しているのに十分です。
+ (BOOL)coordinate:(CLLocationCoordinate2D)coord inRegion:(MKCoordinateRegion)region
{
CLLocationCoordinate2D center = region.center;
MKCoordinateSpan span = region.span;
BOOL result = YES;
result &= cos((center.latitude - coord.latitude)*M_PI/180.0) > cos(span.latitudeDelta/2.0*M_PI/180.0);
result &= cos((center.longitude - coord.longitude)*M_PI/180.0) > cos(span.longitudeDelta/2.0*M_PI/180.0);
return result;
}
現在地をMKMapPointForCoordinate
でポイントに変換してから、マップビューのMKMapRectContainsPoint
でvisibleMapRect
を使用できます。これは完全に頭から離れています。動作するかどうか教えてください。
他の答えにはすべて欠点があります。受け入れられた答えは少し冗長であり、国際日付変更線の近くで失敗します。コサインの答えは実行可能ですが、非常に小さな領域では失敗します(デルタコサインは正弦であり、ゼロに近いゼロに近づく傾向があるため、angular差はゼロの変化を期待します)この答えは正しく機能するはずですすべての状況で、より簡単です。
迅速:
/* Standardises and angle to [-180 to 180] degrees */
class func standardAngle(var angle: CLLocationDegrees) -> CLLocationDegrees {
angle %= 360
return angle < -180 ? -360 - angle : angle > 180 ? 360 - 180 : angle
}
/* confirms that a region contains a location */
class func regionContains(region: MKCoordinateRegion, location: CLLocation) -> Bool {
let deltaLat = abs(standardAngle(region.center.latitude - location.coordinate.latitude))
let deltalong = abs(standardAngle(region.center.longitude - location.coordinate.longitude))
return region.span.latitudeDelta >= deltaLat && region.span.longitudeDelta >= deltalong
}
目的C:
/* Standardises and angle to [-180 to 180] degrees */
+ (CLLocationDegrees)standardAngle:(CLLocationDegrees)angle {
angle %= 360
return angle < -180 ? -360 - angle : angle > 180 ? 360 - 180 : angle
}
/* confirms that a region contains a location */
+ (BOOL)region:(MKCoordinateRegion*)region containsLocation:(CLLocation*)location {
CLLocationDegrees deltaLat = fabs(standardAngle(region.center.latitude - location.coordinate.latitude))
CLLocationDegrees deltalong = fabs(standardAngle(region.center.longitude - location.coordinate.longitude))
return region.span.latitudeDelta >= deltaLat && region.span.longitudeDelta >= deltalong
}
ただし、この方法は、いずれかの極を含む領域では失敗しますが、座標系自体は極で失敗します。ほとんどのアプリケーションでは、このソリューションで十分です。 (注、Objective Cではテストされていません)
このコードを使用して、座標が円形領域(周囲に半径のある座標)内にあるかどうかを判断しました。
- (BOOL)location:(CLLocation *)location isNearCoordinate:(CLLocationCoordinate2D)coordinate withRadius:(CLLocationDistance)radius
{
CLCircularRegion *circularRegion = [[CLCircularRegion alloc] initWithCenter:location.coordinate radius:radius identifier:@"radiusCheck"];
return [circularRegion containsCoordinate:coordinate];
}
Owen Godfrey、Objective-Cコードが機能しない、これは良いコードです:Objective-Cで失敗します、これは良いコードです:
/* Standardises and angle to [-180 to 180] degrees */
- (CLLocationDegrees)standardAngle:(CLLocationDegrees)angle {
angle=fmod(angle,360);
return angle < -180 ? -360 - angle : angle > 180 ? 360 - 180 : angle;
}
-(BOOL)thisRegion:(MKCoordinateRegion)region containsLocation:(CLLocation *)location{
CLLocationDegrees deltaLat =fabs([self standardAngle:(region.center.latitude-location.coordinate.latitude)]);
CLLocationDegrees deltaLong =fabs([self standardAngle:(region.center.longitude-location.coordinate.longitude)]);
return region.span.latitudeDelta >= deltaLat && region.span.longitudeDelta >=deltaLong;
}
CLLocationDegrees deltalong = fabs(standardAngle(region.center.longitude - location.coordinate.longitude));
return region.span.latitudeDelta >= deltaLat && region.span.longitudeDelta >= deltalong;
}
ありがとう!
チャームのように機能します(Swift 5)
func check(
location: CLLocationCoordinate2D,
contains childLocation: CLLocationCoordinate2D,
with radius: Double)
-> Bool
{
let region = CLCircularRegion(center: location, radius: radius, identifier: "SearchId")
return region.contains(childLocation)
}
同じ計算で問題が発生しました。私はオーウェン・ゴッドフリーによって提案された概念が好きです ここ 、フェルナンドさえもパン ここ 緯度が経度とは異なって包まれ、異なる範囲を持っているという事実を見逃しました。私の提案を明確にするために、私はあなたが自分でそれをチェックできるようにテストでそれを投稿します。
import XCTest
import MapKit
// MARK - The Solution
extension CLLocationDegrees {
enum WrapingDimension: Double {
case latitude = 180
case longitude = 360
}
/// Standardises and angle to [-180 to 180] or [-90 to 90] degrees
func wrapped(diemension: WrapingDimension) -> CLLocationDegrees {
let length = diemension.rawValue
let halfLenght = length/2.0
let angle = self.truncatingRemainder(dividingBy: length)
switch diemension {
case .longitude:
// return angle < -180.0 ? 360.0 + angle : angle > 180.0 ? -360.0 + angle : angle
return angle < -halfLenght ? length + angle : angle > halfLenght ? -length + angle : angle
case .latitude:
// return angle < -90.0 ? -180.0 - angle : angle > 90.0 ? 180.0 - angle : angle
return angle < -halfLenght ? -length - angle : angle > halfLenght ? length - angle : angle
}
}
}
extension MKCoordinateRegion {
/// confirms that a region contains a location
func contains(_ coordinate: CLLocationCoordinate2D) -> Bool {
let deltaLat = abs((self.center.latitude - coordinate.latitude).wrapped(diemension: .latitude))
let deltalong = abs((self.center.longitude - coordinate.longitude).wrapped(diemension: .longitude))
return self.span.latitudeDelta/2.0 >= deltaLat && self.span.longitudeDelta/2.0 >= deltalong
}
}
// MARK - Unit tests
class MKCoordinateRegionContaingTests: XCTestCase {
func testRegionContains() {
var region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0, 0), MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
var coords = CLLocationCoordinate2DMake(0, 0)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(0.5, 0.5)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(-0.5, 0.5)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(0.5, 0.5000001)
XCTAssert(!region.contains(coords)) // NOT Contains
coords = CLLocationCoordinate2DMake(0.5, -0.5000001)
XCTAssert(!region.contains(coords)) // NOT Contains
coords = CLLocationCoordinate2DMake(1, 1)
XCTAssert(!region.contains(coords)) // NOT Contains
region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(0, 180), MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
coords = CLLocationCoordinate2DMake(0, 180.5)
XCTAssert(region.contains(coords))
coords.longitude = 179.5
XCTAssert(region.contains(coords))
coords.longitude = 180.5000001
XCTAssert(!region.contains(coords)) // NOT Contains
coords.longitude = 179.5000001
XCTAssert(region.contains(coords))
coords.longitude = 179.4999999
XCTAssert(!region.contains(coords)) // NOT Contains
region = MKCoordinateRegionMake(CLLocationCoordinate2DMake(90, -180), MKCoordinateSpan(latitudeDelta: 1, longitudeDelta: 1))
coords = CLLocationCoordinate2DMake(90.5, -180.5)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(89.5, -180.5)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(90.50000001, -180.5)
XCTAssert(!region.contains(coords)) // NOT Contains
coords = CLLocationCoordinate2DMake(89.50000001, -180.5)
XCTAssert(region.contains(coords))
coords = CLLocationCoordinate2DMake(89.49999999, -180.5)
XCTAssert(!region.contains(coords)) // NOT Contains
}
func testStandardAngle() {
var angle = 180.5.wrapped(diemension: .longitude)
var required = -179.5
XCTAssert(self.areAngleEqual(angle, required))
angle = 360.5.wrapped(diemension: .longitude)
required = 0.5
XCTAssert(self.areAngleEqual(angle, required))
angle = 359.5.wrapped(diemension: .longitude)
required = -0.5
XCTAssert(self.areAngleEqual(angle, required))
angle = 179.5.wrapped(diemension: .longitude)
required = 179.5
XCTAssert(self.areAngleEqual(angle, required))
angle = 90.5.wrapped(diemension: .latitude)
required = 89.5
XCTAssert(self.areAngleEqual(angle, required))
angle = 90.5000001.wrapped(diemension: .latitude)
required = 89.4999999
XCTAssert(self.areAngleEqual(angle, required))
angle = -90.5.wrapped(diemension: .latitude)
required = -89.5
XCTAssert(self.areAngleEqual(angle, required))
angle = -90.5000001.wrapped(diemension: .latitude)
required = -89.4999999
XCTAssert(self.areAngleEqual(angle, required))
}
/// compare doubles with presition to 8 digits after the decimal point
func areAngleEqual(_ a:Double, _ b:Double) -> Bool {
let presition = 0.00000001
let equal = Int(a / presition) == Int(b / presition)
print(String(format:"%14.9f %@ %14.9f", a, equal ? "==" : "!=", b) )
return equal
}
}
Lukaszソリューションに基づいていますが、Swiftでは、誰でもSwiftを利用できる場合に備えて:
func isInRegion (region : MKCoordinateRegion, coordinate : CLLocationCoordinate2D) -> Bool {
let center = region.center;
let northWestCorner = CLLocationCoordinate2D(latitude: center.latitude - (region.span.latitudeDelta / 2.0), longitude: center.longitude - (region.span.longitudeDelta / 2.0))
let southEastCorner = CLLocationCoordinate2D(latitude: center.latitude + (region.span.latitudeDelta / 2.0), longitude: center.longitude + (region.span.longitudeDelta / 2.0))
return (
coordinate.latitude >= northWestCorner.latitude &&
coordinate.latitude <= southEastCorner.latitude &&
coordinate.longitude >= northWestCorner.longitude &&
coordinate.longitude <= southEastCorner.longitude
)
}