Pad*_*215 17 objective-c mapkit mkmapview ios
我希望能够判断tap是否在MKPolygon中.
我有一个MKPolygon:
CLLocationCoordinate2D points[4];
points[0] = CLLocationCoordinate2DMake(41.000512, -109.050116);
points[1] = CLLocationCoordinate2DMake(41.002371, -102.052066);
points[2] = CLLocationCoordinate2DMake(36.993076, -102.041981);
points[3] = CLLocationCoordinate2DMake(36.99892, -109.045267);
MKPolygon* poly = [MKPolygon polygonWithCoordinates:points count:4];
[self.mapView addOverlay:poly];
//create UIGestureRecognizer to detect a tap
UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(foundTap:)];
tapRecognizer.numberOfTapsRequired = 1;
tapRecognizer.numberOfTouchesRequired = 1;
[self.mapView addGestureRecognizer:tapRecognizer];
Run Code Online (Sandbox Code Playgroud)
它只是科罗拉多州的基本轮廓.
我得到了lat/long转换设置:
-(IBAction)foundTap:(UITapGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:self.mapView];
CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view];
}
Run Code Online (Sandbox Code Playgroud)
但如果我的分接点在MKPolygon内,我不确定如何技术.似乎没有办法做这个检查,所以我猜我需要将MKPolygon转换为CGRect并使用CGRectContainsPoint.
MKPolygon有一个.points属性,但我似乎无法让它们退出.
有什么建议?
编辑:
以下两种解决方案均适用于iOS 6或更低版本,但在iOS 7中有效.在iOS 7中,该polygon.path属性始终返回NULL.安娜女士非常友好地提供了另一个SO问题的解决方案.它涉及从多边形点创建自己的路径以进入CGPathContainsPoint().
我的多边形的图像:

小智 12
我创建了这个MKPolygon类别,以防有人想要使用它.似乎运作良好.您必须考虑内部多边形(即多边形中的孔):
@interface MKPolygon (PointInPolygon)
-(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView;
@end
@implementation MKPolygon (PointInPolygon)
-(BOOL) pointInPolygon:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView {
MKMapPoint mapPoint = MKMapPointForCoordinate(point);
MKPolygonView * polygonView = (MKPolygonView*)[mapView viewForOverlay:self];
CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];
return CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO) &&
![self pointInInteriorPolygons:point mapView:mapView];
}
-(BOOL) pointInInteriorPolygons:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView {
return [self pointInInteriorPolygonIndex:0 point:point mapView:mapView];
}
-(BOOL) pointInInteriorPolygonIndex:(int) index point:(CLLocationCoordinate2D) point mapView: (MKMapView*) mapView {
if(index >= [self.interiorPolygons count])
return NO;
return [[self.interiorPolygons objectAtIndex:index] pointInPolygon:point mapView:mapView] || [self pointInInteriorPolygonIndex:(index+1) point:point mapView:mapView];
}
@end
Run Code Online (Sandbox Code Playgroud)
你的foundTap方法:
-(IBAction)foundTap:(UITapGestureRecognizer *)recognizer
{
CGPoint point = [recognizer locationInView:self.mapView];
CLLocationCoordinate2D tapPoint = [self.mapView convertPoint:point toCoordinateFromView:self.view];
[self pointInsideOverlay:tapPoint];
if (isInside)
{
....
}
}
Run Code Online (Sandbox Code Playgroud)
以下是从上一个调用以检查该点是否在叠加层内的方法:
-(void)pointInsideOverlay:(CLLocationCoordinate2D )tapPoint
{
isInside = FALSE;
MKPolygonView *polygonView = (MKPolygonView *)[mapView viewForOverlay:polygonOverlay];
MKMapPoint mapPoint = MKMapPointForCoordinate(tapPoint);
CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];
BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO);
if ( !mapCoordinateIsInPolygon )
//we are finding points that are inside the overlay
{
isInside = TRUE;
}
}
Run Code Online (Sandbox Code Playgroud)
确定一个点是否在任意多边形中并非易事,Apple 不将其作为 MKPolygon 的一部分提供也就不足为奇了。您可以访问这些点,这允许您在边缘上进行迭代。
要确定点 p 是否在多边形 s 内,请将每条边视为 s 中的一条有向线段。如果来自 p 的任何固定方向(通常平行于 X 轴或 Y 轴)的射线与该线段相交,则取该射线与该有向线段的叉积的 Z 分量的符号。如果 Z 分量 > 0,则向计数器加 1。如果它 < 0,则减去 1。实现这一点的技巧是避免当边缘几乎平行于光线时出现问题,或者当光线通过一个顶点时(它必须只计算一次,而不是每条边一次) .
当您对 s 中的所有边执行此操作后,您将计算光线与多边形轮廓相交的次数,如果边是从左到右添加的,以及如果是从右到左添加,你减去。如果结果总和为零,则您在多边形之外。否则你就在里面。
有许多可能的优化。其中之一是在更完整的测试之前进行快速边界框测试。另一种方法是拥有一个在所有边缘上都有边界的数据结构,以简单地丢弃不与射线相交的边缘。
编辑: AXB 的 Z 分量( A 与 B 的叉积)由下式给出:
a.x * b.y - a.y * b.x
Run Code Online (Sandbox Code Playgroud)
因为你关心的只是标志,你可以检查
a.x * b.y > a.y * b.x
Run Code Online (Sandbox Code Playgroud)
我从字符串中的xml文件中获取MKPolygon数据点.我将数据字符串解析为数组点并使用http://alienryderflex.com/polygon/中的方法给出
这个对我有用....
-(BOOL)isPoint:(CLLocationCoordinate2D)findLocation inPloygon:(NSArray*)polygon{
NSMutableArray *tempPolygon=[NSMutableArray arrayWithArray:polygon];
int i, j=(int)tempPolygon.count-1 ;
bool oddNodes=NO;
double x=findLocation.latitude;
double y=findLocation.longitude;
for (i=0; i<tempPolygon.count; i++) {
NSString*coordString=[tempPolygon objectAtIndex:i];
NSArray*pointsOfCoordString=[coordString componentsSeparatedByString:@","];
CLLocationCoordinate2D point=CLLocationCoordinate2DMake([[pointsOfCoordString objectAtIndex:1] doubleValue], [[pointsOfCoordString objectAtIndex:0] doubleValue]);
NSString*nextCoordString=[tempPolygon objectAtIndex:j];
NSArray*nextPointsOfCoordString=[nextCoordString componentsSeparatedByString:@","];
CLLocationCoordinate2D nextPoint=CLLocationCoordinate2DMake([[nextPointsOfCoordString objectAtIndex:1] doubleValue], [[nextPointsOfCoordString objectAtIndex:0] doubleValue]);
if ((point.longitude<y && nextPoint.longitude>=y)
|| (nextPoint.longitude<y && point.longitude>=y)) {
if (point.latitude+(y-point.longitude)/(nextPoint.longitude-point.longitude)*(nextPoint.latitude-point.latitude)<x) {
oddNodes=!oddNodes; }}
j=i; }
return oddNodes;
}
Run Code Online (Sandbox Code Playgroud)
我的多边形(NSArray)对象是字符串,例如 @"-89.860021,44.944266,0"
这在#Swift 4.2 中对我有用:
extension MKPolygon {
func isCoordinateInsidePolyon(coordinate: CLLocationCoordinate2D) -> Bool {
let polygonRenderer = MKPolygonRenderer(polygon: self)
let currentMapPoint: MKMapPoint = MKMapPoint(coor)
let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
if polygonRenderer.path == nil {
return false
}else{
return polygonRenderer.path.contains(polygonViewPoint)
}
}
}
Run Code Online (Sandbox Code Playgroud)
感谢@Steve Stomp,这里是Swift 3的更新版本
extension MKPolygon {
func contains(coordinate: CLLocationCoordinate2D) -> Bool {
let polygonRenderer = MKPolygonRenderer(polygon: self)
let currentMapPoint: MKMapPoint = MKMapPointForCoordinate(coordinate)
let polygonViewPoint: CGPoint = polygonRenderer.point(for: currentMapPoint)
return polygonRenderer.path.contains(polygonViewPoint)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
11592 次 |
| 最近记录: |