MKPolygon - 如何确定 CLLocationCoordinate2D 是不是在 CLLocationCoordinate2D 多边形中?
Posted
技术标签:
【中文标题】MKPolygon - 如何确定 CLLocationCoordinate2D 是不是在 CLLocationCoordinate2D 多边形中?【英文标题】:MKPolygon - How to determine if a CLLocationCoordinate2D is in a CLLocationCoordinate2D polygon?MKPolygon - 如何确定 CLLocationCoordinate2D 是否在 CLLocationCoordinate2D 多边形中? 【发布时间】:2015-07-17 06:45:28 【问题描述】:我有下面的快速代码,它绘制一个多边形并在 MKMapView 上放置一个注释。我想弄清楚如何确定注释的坐标是否在多边形内?
import UIKit
import MapKit
class ViewController: UIViewController
@IBOutlet weak var mapView: MKMapView!
override func viewDidLoad()
super.viewDidLoad()
let initialLocation = CLLocation(latitude: 49.140838, longitude: -123.127886)
centerMapOnLocation(initialLocation)
addBoundry()
var annotation = MKPointAnnotation()
annotation.coordinate = point1
annotation.title = "Roatan"
annotation.subtitle = "Honduras"
mapView.addAnnotation(annotation)
var points = [CLLocationCoordinate2DMake(49.142677, -123.135139),
CLLocationCoordinate2DMake(49.142730, -123.125794),
CLLocationCoordinate2DMake(49.140874, -123.125805),
CLLocationCoordinate2DMake(49.140885, -123.135214)]
var point1 = CLLocationCoordinate2DMake(49.141821, -123.131577)
func addBoundry()
let polygon = MKPolygon(coordinates: &points, count: points.count)
mapView.addOverlay(polygon)
let regionRadius: CLLocationDistance = 1000
func centerMapOnLocation(location: CLLocation)
let coordinateRegion = MKCoordinateRegionMakeWithDistance(location.coordinate, regionRadius * 2.0, regionRadius * 2.0)
mapView.setRegion(coordinateRegion, animated: true)
func mapView(mapView: MKMapView!, rendererForOverlay overlay: MKOverlay!) -> MKOverlayRenderer!
if overlay is MKPolygon
let polygonView = MKPolygonRenderer(overlay: overlay)
polygonView.strokeColor = UIColor.magentaColor()
return polygonView
return nil
【问题讨论】:
【参考方案1】:我创建了@StefanS 的答案的 Swift 版本,并通过从 answer 移植代码使其更易于阅读
func isPoint(point: MKMapPoint, insidePolygon poly: MKPolygon) -> Bool
let polygonVerticies = poly.points()
var isInsidePolygon = false
for i in 0..<poly.pointCount
let vertex = polygonVerticies[i]
let nextVertex = polygonVerticies[(i + 1) % poly.pointCount]
// The vertices of the edge we are checking.
let xp0 = vertex.x
let yp0 = vertex.y
let xp1 = nextVertex.x
let yp1 = nextVertex.y
if ((yp0 <= point.y) && (yp1 > point.y) || (yp1 <= point.y) && (yp0 > point.y))
// If so, get the point where it crosses that line. This is a simple solution
// to a linear equation. Note that we can't get a division by zero here -
// if yp1 == yp0 then the above if be false.
let cross = (xp1 - xp0) * (point.y - yp0) / (yp1 - yp0) + xp0
// Finally check if it crosses to the left of our test point. You could equally
// do right and it should give the same result.
if cross < point.x
isInsidePolygon = !isInsidePolygon
return isInsidePolygon
【讨论】:
【参考方案2】:- (BOOL)isPoint:(MKMapPoint)point insidePolygon:(MKPolygon *)poly
MKMapPoint *a = poly.points;
BOOL isInsidePolygon = NO;
double testx = point.x;
double testy = point.y;
NSUInteger i = 0, j = 0, nvert = [poly pointCount];
for (i = 0, j = nvert - 1; i < nvert; j = i++)
if (((a[i].y >= testy) != (a[j].y >= testy)) &&
(testx <= (a[j].x - a[i].x) * (testy - a[i].y) / (a[j].y - a[i].y) + a[i].x))
isInsidePolygon = !isInsidePolygon;
return isInsidePolygon;
因为点 x y 在墨卡托投影坐标中,这是有道理的,您无需转换为球坐标进行计算。
为什么这是一个正确的计算here。
编辑:更新后,计算也将线上的一个点视为多边形内部。
【讨论】:
【参考方案3】:使用 MkPolygon.intersect() 怎么样?这需要将点转换为一个微小的 MKMapRect,但它更简单,并且可能会从底层 API 获得一些加速:
func pointIsInside(point: MKMapPoint, polygon: MKPolygon) -> Bool
let mapRect = MKMapRectMake(point.x, point.y, 0.0001, 0.0001)
return polygon.intersects(mapRect)
【讨论】:
这必须被覆盖,否则它只会与边界矩形而不是正确的 MKPolygon 进行比较【参考方案4】:您可以创建一个多边形渲染器对象并根据地图中的位置检查它的路径是否包含该点:
func checkIf(_ location: CLLocationCoordinate2D, areInside polygon: MKPolygon) -> Bool
let polygonRenderer = MKPolygonRenderer(polygon: polygon)
let mapPoint = MKMapPointForCoordinate(location)
let polygonPoint = polygonRenderer.point(for: mapPoint)
return polygonRenderer.path.contains(polygonPoint)
【讨论】:
【参考方案5】:附加到手势识别器的方法:
@objc
func mapTapped(_ tap: UILongPressGestureRecognizer)
if tap.state == .recognized
let touchPoint = tap.location(in: mapView)
let coord = mapView.convert(touchPoint, toCoordinateFrom: mapView)
for overlay: MKOverlay in mapView.overlays
if let polygon = overlay as? MKPolygon
let renderer = MKPolygonRenderer(polygon: polygon)
let mapPoint = MKMapPoint(coord)
let rendererPoint = renderer.point(for: mapPoint)
if renderer.path.contains(rendererPoint)
// here comes your code
【讨论】:
以上是关于MKPolygon - 如何确定 CLLocationCoordinate2D 是不是在 CLLocationCoordinate2D 多边形中?的主要内容,如果未能解决你的问题,请参考以下文章
如何区分几个不同的 MKPolygon 叠加层,以便我可以为每个叠加层赋予不同的属性?
来自点 + 半径/距离的 MKPolygon (iPhone SDK)
验证 latlong 是不是在 iOS 的 MKPolygon 内