Отображение аннотаций только внутри оверлеев - PullRequest
1 голос
/ 15 ноября 2011

На моей карте я должен показывать аннотации из файла kml через URL.Мне также нужно показывать только аннотации внутри многоугольника или круга (или их обоих, если у пользователя нарисованы оба оверлея).

Я видел вопрос Как определить, находится ли аннотация внутриMKPolygonView (iOS) , но у меня есть два недоумения:

  1. Что касается координат аннотаций, я должен использовать координаты аннотаций из метода addAnnotation?
  2. В упомянутом вопросе создано новое наложение, но у меня есть два разных наложения, созданные в другом месте.Итак, мой вопрос: что является наиболее подходящим местом для размещения этого кода (или что-то подобное)?

EDIT : я создал некоторый код:

-(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];
}

EDIT Nr.2 Вот моя реализация метода делегата viewForOverlay. Я вижу наложения, круги и многоугольники, которые я создаю. Я вижу все аннотации. ВСЕ из них, внутри и снаружиоверлеи ...

-(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 Ответ

1 голос
/ 19 ноября 2011

В целом, это выглядит хорошо, но в методе filterAnnotations есть проблема с тем, как аннотации удаляются из массива annotationsToFilter.

Что произойдет, так это то, что некоторые аннотации будут пропущены и никогда не пройдут проверку.

Например:

  • Скажем, есть 5 аннотаций (0 = A, 1 = B, 2 = C, 3 = D, 4 = E)
  • Цикл for начинается с индекса 0, и «A» удовлетворяет условию удаления
  • «A» удаляется из массива, и теперь другие аннотации перемещаются вниз на один индекс, поэтому после удаления массив выглядит так: (0 = B, 1 = C, 2 = D, 3 = E)
  • Теперь цикл for переходит к следующему индексу, который равен 1 (поэтому проверяется аннотация C)
  • Таким образом, аннотация B пропускается и никогда не проверяется

Один из способов исправить это - собрать аннотации, которые вы хотите сохранить в другом массиве «annotationsToAdd», вместо того, чтобы удалять их из оригинала, и передавать annotationsToAdd методу addAnnotations.

Ниже предложена модификация. Я также рекомендовал бы перемещать вызовы viewForOverlay вне цикла for, так как эти ссылки не будут меняться во время цикла, поэтому нет необходимости вызывать их повторно.

-(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 и circleOverlay объявлены как MKPolygonView и MKCircleView вместо MKPolygon и MKCircle.

Во-вторых, код в методе делегата viewForOverlay неверен. Он пытается создать представление круга и многоугольника для всех передаваемых overlay, а , а затем проверяет, какой класс является оверлеем. Также кажется, что сохраняется ссылка на оверлей view , но остальная часть кода предполагает, что мы сохраняем ссылку на оверлей (объект 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;
}

Вы также упоминаете в своей правке, что "Я вижу наложения, круги и многоугольники". Звучит так, будто вы создаете более одного круга и / или наложения полигонов. В этом случае наличие только одной переменной polygonOverlay и circleOverlay не будет работать.

Если у вас действительно есть несколько оверлеев каждого типа, не храните ссылки на оверлеи. Вместо этого, в методе filterAnnotations, для каждой аннотации , переберите массив mapView.overlays и выполните тест viewForOverlay и точка-полигон во вложенном цикле.

...