In my map, I have to show annotations from a kml file via an URL. I also need to show only the annotations inside a polygon or circle area (or both of them if the user has both overlays drawn).
I have seen the question How to determine if an annotation is inside of MKPolygonView (iOS), but I have two perplexities:
- Regarding the annotation coordinates, should I use the coordinates of the annotations from the
addAnnotationmethod? - In the mentioned question a new overlay is created, but I have two different overlays created elsewhere. So my question is: what is the most suitable place to put this code (or something like that)?
EDIT: I’ve created some code:
-(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 Here is my implementation of viewForOverlay delegate method.I see the overlays, circles and polygons I create.I see all the annotations.ALL of them, those inside and outside the overlays…
-(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;
}
Overall, that looks fine but there is a problem in the
filterAnnotationsmethod with how the annotations are being removed from theannotationsToFilterarray.What will happen is that some annotations will be skipped and never go through the check.
For example:
One way to fix this is to collect the annotations you want to keep in another array “annotationsToAdd” instead of removing them from the original and pass annotationsToAdd to the
addAnnotationsmethod.Below is the suggested modification. I’d also recommend moving the
viewForOverlaycalls outside the for-loop since those references won’t change during the loop so there’s no need to call them repeatedly.Also, I noticed that in the
showKmlDatamethod you are using the variablemapviewbut infilterAnnotationsit’smapView(uppercaseV). Hopefully, the compiler will give you a warning about that.Additional Info:
Based on your comments and the
viewForOverlaycode you added to your question…First, the compiler warning
class 'MKPolygonView' does not implement the 'MKOverlay' protocolthat you are getting implies that the variablespolygonOverlayandcircleOverlayare declared asMKPolygonViewandMKCircleViewinstead ofMKPolygonandMKCircle.Second, the code in the
viewForOverlaydelegate method is wrong. It tries to create both a circle and polygon view for whateveroverlayis passed in and then checks what kind of class the overlay is. It also seems to be saving a reference to the overlay view but the rest of the code assumes that we are keeping a reference to the overlay (theMKOverlayobject–not theMKOverlayView).Try the following changes…
You also mention in your edit that “I see the overlays, circles and polygons”. That sounds like you are creating more than one circle and/or polygon overlay. In that case, having just one polygonOverlay and circleOverlay variable won’t work.
If you really do have multiple overlays of each type, then don’t store references to the overlays. Instead, in the
filterAnnotationsmethod, for each annotation, loop through themapView.overlaysarray and execute theviewForOverlayand point-in-polygon test in the nested loop.