仅在叠加层内显示注释

时间:2011-11-15 14:38:19

标签: iphone ios annotations mkmapview overlay

在我的地图中,我必须通过URL显示kml文件中的注释。我还需要只显示多边​​形或圆形区域内的注释(如果用户同时绘制了两个叠加层,则需要显示两个注释)。

我见过问题How to determine if an annotation is inside of MKPolygonView (iOS),但我有两个困惑:

  1. 关于注释坐标,我应该使用addAnnotation方法中注释的坐标吗?
  2. 在上述问题中,会创建一个新的叠加层,但我在其他位置创建了两个不同的叠加层。所以我的问题是:放置此代码的最合适的地方是什么(或类似的东西)?
  3. 编辑:我创建了一些代码:

    -(IBAction)showKmlData:(id)sender
    {
    NSString *path = [[NSBundle mainBundle] pathForResource:@"KMLGenerator" ofType:@"kml"];
    
    kml = [[KMLParser parseKMLAtPath:path] retain];
    
    NSArray *annotationsImmut = [kml points];
    //[mapview addAnnotations:annotations]; not anymore
    NSMutableArray *annotations = [annotationsImmut mutableCopy];
    [self filterAnnotations:annotations];
    
    MKMapRect flyTo = MKMapRectNull;
    
    for (id <MKAnnotation> annotation in annotations) {
        MKMapPoint annotationPoint = MKMapPointForCoordinate(annotation.coordinate);
        MKMapRect pointRect = MKMapRectMake(annotationPoint.x, annotationPoint.y, 0, 0);
        if (MKMapRectIsNull(flyTo)) {
            flyTo = pointRect;
        } else {
            flyTo = MKMapRectUnion(flyTo, pointRect);
        }
    }
    
    mapview.visibleMapRect = flyTo;
    }
    
    
    -(void)filterAnnotations:(NSMutableArray *)annotationsToFilter {
    
    for (int i=0; i<[annotationsToFilter count]; i++) {
    
        CLLocationCoordinate2D mapCoordinate = [[annotationsToFilter objectAtIndex:i] coordinate];
    
        MKMapPoint mapPoint = MKMapPointForCoordinate(mapCoordinate);
    
        MKPolygonView *polygonView = 
            (MKPolygonView *)[mapView viewForOverlay:polygonOverlay];
    
        MKCircleView *circleView = 
            (MKCircleView *)[mapView viewForOverlay:circleOverlay];
    
        CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];
        CGPoint circleViewPoint = [circleView pointForMapPoint:mapPoint];
    
        BOOL mapCoordinateIsInPolygon = 
            CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO);
    
        BOOL mapCoordinateIsInCircle = 
            CGPathContainsPoint(circleView.path, NULL, circleViewPoint, NO);
    
            if( mapCoordinateIsInPolygon || mapCoordinateIsInCircle )
                [annotationsToFilter removeObjectAtIndex:i];
    }
    [mapView addAnnotations:annotationsToFilter];
    }
    

    编辑Nr.2 这是我对viewForOverlay委托方法的实现。我看到我创建的叠加层,圆圈和多边形。我看到它们的所有注释.ALL,叠加层内外的那些...

    -(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay 
    {
        MKCircleView* circleView = [[[MKCircleView alloc] initWithOverlay:overlay] autorelease];
    circleOverlay = circleView;
        circleView.fillColor = [UIColor blueColor];
        circleView.strokeColor = [UIColor blueColor];
        circleView.lineWidth = 5.0;
        circleView.alpha = 0.20;
    
        MKPolygonView *polygonView = [[[MKPolygonView alloc] initWithOverlay:overlay] autorelease];
    polygonOverlay = polygonView;
        polygonView.fillColor = [UIColor blueColor];
        polygonView.strokeColor = [UIColor blueColor];
        polygonView.lineWidth = 5.0;
        polygonView.alpha = 0.20;
    
    
    if ([overlay isKindOfClass:[MKCircle class]])
    {   
        return circleView;
    }
    
    else
        return polygonView;
    

    }

1 个答案:

答案 0 :(得分:1)

总的来说,这看起来不错,但filterAnnotations方法存在一个问题,即如何从annotationsToFilter数组中删除注释。

将会跳过一些注释并且永远不会通过检查。

例如:

  • 假设有5个注释(0 = A,1 = B,2 = C,3 = D,4 = E)
  • for循环从索引0开始,&#34; A&#34;符合移除条件
  • &#34; A&#34;从数组中删除,现在其他注释向下移动一个索引,因此删除后数组为:(0 = B,1 = C,2 = D,3 = E)
  • 现在for循环进入下一个索引,即1(因此检查注释C)
  • 因此跳过注释B并且永远不会检查

解决此问题的一种方法是收集您想要保留在另一个数组中的注释&#34; annotationsToAdd&#34;而不是从原始中删除它们并将注释传递给addAnnotations方法。

以下是建议的修改。我还建议在for循环之外移动viewForOverlay个调用,因为这些引用在循环期间不会发生变化,因此无需重复调用它们。

-(void)filterAnnotations:(NSMutableArray *)annotationsToFilter 
{
    NSMutableArray *annotationsToAdd = [NSMutableArray array];

    //Get a reference to the overlay views OUTSIDE the for-loop since
    //they will remain constant so there's no need to keep calling
    //viewForOverlay repeatedly...
    MKPolygonView *polygonView = (MKPolygonView *)[mapView viewForOverlay:polygonOverlay];

    MKCircleView *circleView = (MKCircleView *)[mapView viewForOverlay:circleOverlay];

    for (int i=0; i < [annotationsToFilter count]; i++) 
    {
        //get a handy reference to the annotation at the current index...
        id<MKAnnotation> currentAnnotation = [annotationsToFilter objectAtIndex:i];

        CLLocationCoordinate2D mapCoordinate = [currentAnnotation coordinate];

        MKMapPoint mapPoint = MKMapPointForCoordinate(mapCoordinate);

        CGPoint polygonViewPoint = [polygonView pointForMapPoint:mapPoint];
        CGPoint circleViewPoint = [circleView pointForMapPoint:mapPoint];

        BOOL mapCoordinateIsInPolygon = CGPathContainsPoint(polygonView.path, NULL, polygonViewPoint, NO);

        BOOL mapCoordinateIsInCircle = CGPathContainsPoint(circleView.path, NULL, circleViewPoint, NO);

        if ( !mapCoordinateIsInPolygon && !mapCoordinateIsInCircle )
            //Note the reversed if-condition because now 
            //we are finding annotations we want to KEEP
        {
            [annotationsToAdd addObject:currentAnnotation];
        }
    }

    [mapView addAnnotations:annotationsToAdd];
}

另外,我注意到在showKmlData方法中您使用变量mapview但在filterAnnotations mapView V(大写viewForOverlay )。希望编译器会给你一个警告。

<小时/> 其他信息:
根据您的评论以及您添加到问题中的class 'MKPolygonView' does not implement the 'MKOverlay' protocol代码...

首先,您收到的编译器警告polygonOverlay表示变量circleOverlayMKPolygonView被声明为MKCircleViewMKPolygon而不是{{ 1}}和MKCircle

其次,viewForOverlay委托方法中的代码是错误的。它会尝试为传入的overlay创建圆形和多边形视图,然后然后检查叠加层是什么类。它似乎也保存了对overlay view 的引用,但其余代码假定我们保留对 overlay MKOverlay对象的引用 - 不是MKOverlayView)。

尝试以下更改......

//polygonOverlay and circleOverlay should be declared as MKOverlay objects...
@property (nonatomic, retain) MKPolygon *polygonOverlay;
@property (nonatomic, retain) MKCircle *circleOverlay;

//save a reference to them when you call addOverlay...
self.polygonOverlay = [MKPolygon polygonWithCoordinates:polyCoords count:coordsCount];
[mapView addOverlay:polygonOverlay];
self.circleOverlay = [MKCircle circleWithCenterCoordinate:cirleCenter radius:circleRadius];
[mapView addOverlay:circleOverlay];

//the viewForOverlay delegate method...
-(MKOverlayView *)mapView:(MKMapView *)mapView viewForOverlay:(id)overlay
{
    if ([overlay isKindOfClass:[MKCircle class]])
    {
        MKCircleView* circleView = [[[MKCircleView alloc] initWithOverlay:overlay] autorelease];
        circleView.fillColor = [UIColor blueColor];
        circleView.strokeColor = [UIColor blueColor];
        circleView.lineWidth = 5.0;
        circleView.alpha = 0.20;
        return circleView;
    }
    else
        if ([overlay isKindOfClass:[MKPolygon class]])
        {
            MKPolygonView *polygonView = [[[MKPolygonView alloc] initWithOverlay:overlay] autorelease];
            polygonView.fillColor = [UIColor blueColor];
            polygonView.strokeColor = [UIColor blueColor];
            polygonView.lineWidth = 5.0;
            polygonView.alpha = 0.20;
            return polygonView;
        }

    return nil;
}

您还在编辑中提到&#34;我看到了叠加层,圆圈和多边形&#34;。这听起来像是在创建多个圆形和/或多边形叠加层。在这种情况下,只有一个polygonOverlay和circleOverlay变量不起作用。

如果您确实拥有每种类型的多个叠加层,则不要存储对叠加层的引用。相反,在每个注释的filterAnnotations方法中,循环遍历mapView.overlays数组并在嵌套循环中执行viewForOverlay和多边形点测试