mye*_*l0w 26 mapkit mkmapview ios mkoverlay mkpolyline
在iPhone上内置Maps.app上显示方向时,您可以"选择"通过点击它显示的通常3个路线选项之一.我不想复制这个功能并检查一个tap是否在给定的MKPolyline中.
目前我检测到MapView上的点击如下:
// Add Gesture Recognizer to MapView to detect taps
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handleMapTap:)];
// we require all gesture recognizer except other single-tap gesture recognizers to fail
for (UIGestureRecognizer *gesture in self.gestureRecognizers) {
if ([gesture isKindOfClass:[UITapGestureRecognizer class]]) {
UITapGestureRecognizer *systemTap = (UITapGestureRecognizer *)gesture;
if (systemTap.numberOfTapsRequired > 1) {
[tap requireGestureRecognizerToFail:systemTap];
}
} else {
[tap requireGestureRecognizerToFail:gesture];
}
}
[self addGestureRecognizer:tap];
Run Code Online (Sandbox Code Playgroud)
我按如下方式处理水龙头:
- (void)handleMapTap:(UITapGestureRecognizer *)tap {
if ((tap.state & UIGestureRecognizerStateRecognized) == UIGestureRecognizerStateRecognized) {
// Check if the overlay got tapped
if (overlayView != nil) {
// Get view frame rect in the mapView's coordinate system
CGRect viewFrameInMapView = [overlayView.superview convertRect:overlayView.frame toView:self];
// Get touch point in the mapView's coordinate system
CGPoint point = [tap locationInView:self];
// Check if the touch is within the view bounds
if (CGRectContainsPoint(viewFrameInMapView, point)) {
[overlayView handleTapAtPoint:[tap locationInView:self.directionsOverlayView]];
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
这按预期工作,现在我需要检查水龙头是否在给定的MKPolyline overlayView内(不严格,我用户点击折线附近的某处,这应该作为命中处理).
这样做的好方法是什么?
- (void)handleTapAtPoint:(CGPoint)point {
MKPolyline *polyline = self.polyline;
// TODO: detect if point lies withing polyline with some margin
}
Run Code Online (Sandbox Code Playgroud)
谢谢!
Jen*_*son 47
这个问题相当陈旧,但我的回答可能对寻找这个问题的解决方案的其他人有用.
此代码检测多边形线上的触摸,每个缩放级别的最大距离为22像素.只需将您UITapGestureRecognizer到handleTap:
/** Returns the distance of |pt| to |poly| in meters
*
* from http://paulbourke.net/geometry/pointlineplane/DistancePoint.java
*
*/
- (double)distanceOfPoint:(MKMapPoint)pt toPoly:(MKPolyline *)poly
{
double distance = MAXFLOAT;
for (int n = 0; n < poly.pointCount - 1; n++) {
MKMapPoint ptA = poly.points[n];
MKMapPoint ptB = poly.points[n + 1];
double xDelta = ptB.x - ptA.x;
double yDelta = ptB.y - ptA.y;
if (xDelta == 0.0 && yDelta == 0.0) {
// Points must not be equal
continue;
}
double u = ((pt.x - ptA.x) * xDelta + (pt.y - ptA.y) * yDelta) / (xDelta * xDelta + yDelta * yDelta);
MKMapPoint ptClosest;
if (u < 0.0) {
ptClosest = ptA;
}
else if (u > 1.0) {
ptClosest = ptB;
}
else {
ptClosest = MKMapPointMake(ptA.x + u * xDelta, ptA.y + u * yDelta);
}
distance = MIN(distance, MKMetersBetweenMapPoints(ptClosest, pt));
}
return distance;
}
/** Converts |px| to meters at location |pt| */
- (double)metersFromPixel:(NSUInteger)px atPoint:(CGPoint)pt
{
CGPoint ptB = CGPointMake(pt.x + px, pt.y);
CLLocationCoordinate2D coordA = [mapView convertPoint:pt toCoordinateFromView:mapView];
CLLocationCoordinate2D coordB = [mapView convertPoint:ptB toCoordinateFromView:mapView];
return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB));
}
#define MAX_DISTANCE_PX 22.0f
- (void)handleTap:(UITapGestureRecognizer *)tap
{
if ((tap.state & UIGestureRecognizerStateRecognized) == UIGestureRecognizerStateRecognized) {
// Get map coordinate from touch point
CGPoint touchPt = [tap locationInView:mapView];
CLLocationCoordinate2D coord = [mapView convertPoint:touchPt toCoordinateFromView:mapView];
double maxMeters = [self metersFromPixel:MAX_DISTANCE_PX atPoint:touchPt];
float nearestDistance = MAXFLOAT;
MKPolyline *nearestPoly = nil;
// for every overlay ...
for (id <MKOverlay> overlay in mapView.overlays) {
// .. if MKPolyline ...
if ([overlay isKindOfClass:[MKPolyline class]]) {
// ... get the distance ...
float distance = [self distanceOfPoint:MKMapPointForCoordinate(coord)
toPoly:overlay];
// ... and find the nearest one
if (distance < nearestDistance) {
nearestDistance = distance;
nearestPoly = overlay;
}
}
}
if (nearestDistance <= maxMeters) {
NSLog(@"Touched poly: %@\n"
" distance: %f", nearestPoly, nearestDistance);
}
}
}
Run Code Online (Sandbox Code Playgroud)
Ras*_*n L 15
@Jensemanns在Swift 4中回答,顺便说一句,这是我找到的唯一能够帮助我检测点击次数的解决方案MKPolyline:
let map = MKMapView()
let mapTap = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
map.addGestureRecognizer(mapTap)
func mapTapped(_ tap: UITapGestureRecognizer) {
if tap.state == .recognized {
// Get map coordinate from touch point
let touchPt: CGPoint = tap.location(in: map)
let coord: CLLocationCoordinate2D = map.convert(touchPt, toCoordinateFrom: map)
let maxMeters: Double = meters(fromPixel: 22, at: touchPt)
var nearestDistance: Float = MAXFLOAT
var nearestPoly: MKPolyline? = nil
// for every overlay ...
for overlay: MKOverlay in map.overlays {
// .. if MKPolyline ...
if (overlay is MKPolyline) {
// ... get the distance ...
let distance: Float = Float(distanceOf(pt: MKMapPointForCoordinate(coord), toPoly: overlay as! MKPolyline))
// ... and find the nearest one
if distance < nearestDistance {
nearestDistance = distance
nearestPoly = overlay as! MKPolyline
}
}
}
if Double(nearestDistance) <= maxMeters {
print("Touched poly: \(nearestPoly) distance: \(nearestDistance)")
}
}
}
func distanceOf(pt: MKMapPoint, toPoly poly: MKPolyline) -> Double {
var distance: Double = Double(MAXFLOAT)
for n in 0..<poly.pointCount - 1 {
let ptA = poly.points()[n]
let ptB = poly.points()[n + 1]
let xDelta: Double = ptB.x - ptA.x
let yDelta: Double = ptB.y - ptA.y
if xDelta == 0.0 && yDelta == 0.0 {
// Points must not be equal
continue
}
let u: Double = ((pt.x - ptA.x) * xDelta + (pt.y - ptA.y) * yDelta) / (xDelta * xDelta + yDelta * yDelta)
var ptClosest: MKMapPoint
if u < 0.0 {
ptClosest = ptA
}
else if u > 1.0 {
ptClosest = ptB
}
else {
ptClosest = MKMapPointMake(ptA.x + u * xDelta, ptA.y + u * yDelta)
}
distance = min(distance, MKMetersBetweenMapPoints(ptClosest, pt))
}
return distance
}
func meters(fromPixel px: Int, at pt: CGPoint) -> Double {
let ptB = CGPoint(x: pt.x + CGFloat(px), y: pt.y)
let coordA: CLLocationCoordinate2D = map.convert(pt, toCoordinateFrom: map)
let coordB: CLLocationCoordinate2D = map.convert(ptB, toCoordinateFrom: map)
return MKMetersBetweenMapPoints(MKMapPointForCoordinate(coordA), MKMapPointForCoordinate(coordB))
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
7199 次 |
| 最近记录: |