I have been trying to work out if a tap gesture is in an overlay polygon, to no avail.
I am trying to make a map of country overlays - on clicking on an overlay I want to be able to tell what country the overlay is of.
First I found this: Detecting touches on MKOverlay in iOS7 (MKOverlayRenderer) and this: detect if a point is inside a MKPolygon overlay which suggest either:
- make a tiny rectangle around your touch point and see if it intersects any overlays.
```
//point clicked
let point = MKMapPointForCoordinate(newCoordinates)
//make a rectangle around this click
let mapRect = MKMapRectMake(point.x, point.y, 0,0);
//loop through the polygons on the map and
for polygon in worldMap.overlays as! [MKPolygon] {
if polygon.intersectsMapRect(mapRect) {
print("found intersection")
}
}
```
- Using
viewForOverlay
with a promising sounding functionCGPathContainsPoint
, howeverviewForOverlay
is now deprecated.
This led me to find Detecting a point in a MKPolygon broke with iOS7 (CGPathContainsPoint) which suggests the following method:
- Make a mutable polygon from the points of each overlay(instead of using the deprecated
viewForOverlay
) and then useCGPathContainsPoint
to return if the clicked point is in the overlay. However I am unable to make this code work.
```
func overlaySelected (gestureRecognizer: UIGestureRecognizer) {
let pointTapped = gestureRecognizer.locationInView(worldMap)
let newCoordinates = worldMap.convertPoint(pointTapped, toCoordinateFromView: worldMap)
let mapPointAsCGP = CGPointMake(CGFloat(newCoordinates.latitude), CGFloat(newCoordinates.longitude));
print(mapPointAsCGP.x, mapPointAsCGP.y)
for overlay: MKOverlay in worldMap.overlays {
if (overlay is MKPolygon) {
let polygon: MKPolygon = (overlay as! MKPolygon)
let mpr: CGMutablePathRef = CGPathCreateMutable()
for p in 0..<polygon.pointCount {
let mp = polygon.points()[p]
print(polygon.coordinate)
if p == 0 {
CGPathMoveToPoint(mpr, nil, CGFloat(mp.x), CGFloat(mp.y))
}
else {
CGPathAddLineToPoint(mpr, nil, CGFloat(mp.x), CGFloat(mp.y))
}
}
if CGPathContainsPoint(mpr, nil, mapPointAsCGP, false) {
print("------ is inside! ------")
}
}
}
}
```
The first method works but no matter how small I try and make the height and width of the rectangle around the click point let mapRect = MKMapRectMake(point.x, point.y, 0.00000000001,0.00000000001);
the accuracy of the tap is not reliable and so you can end up clicking on several polygons at once.
Currently I am working on deciding on which county is nearer to the tap by using the 'MKPolygon' property coordinate
- which gives the central point of the polygon. With this one can then measure the distance from this polygon to the tapped point to find the closest one. But this is not ideal as the user may never be able to tap on the country that they intend.
So, to sum up my questions:
- Is there something that I am not implementing correctly in the second method above (one using
CGPathContainsPoint
)? - Is there a more accurate way to register an on click event with the rectangle method?
- Any other suggestions or pointers on how to achieve my goal of clicking the map and seeing if the click is on an overlay.