Find nearest point in polyline/path

前端 未结 2 1894
一生所求
一生所求 2020-12-15 02:36

I need to find nearest point from given CLLocationCoordinate2D on array of GMSPolyline. I can convert this to GMSPath if that\'s bette

2条回答
  •  眼角桃花
    2020-12-15 02:36

    Ok, I've managed to write it. Method nearestPointToPoint:onLineSegmentPointA:pointB:distance: allows you both to find closest coordinate and distance between selected point and segment line (so line with start and end).

    - (CLLocationCoordinate2D)nearestPolylineLocationToCoordinate:(CLLocationCoordinate2D)coordinate {
        GMSPolyline *bestPolyline;
        double bestDistance = DBL_MAX;
        CGPoint bestPoint;
        CGPoint originPoint = CGPointMake(coordinate.longitude, coordinate.latitude);
    
        for (GMSPolyline *polyline in self.polylines) {
            if (polyline.path.count < 2) { // we need at least 2 points: start and end
                return kCLLocationCoordinate2DInvalid;
            }
    
            for (NSInteger index = 0; index < polyline.path.count - 1; index++) {
                CLLocationCoordinate2D startCoordinate = [polyline.path coordinateAtIndex:index];
                CGPoint startPoint = CGPointMake(startCoordinate.longitude, startCoordinate.latitude);
                CLLocationCoordinate2D endCoordinate = [polyline.path coordinateAtIndex:(index + 1)];
                CGPoint endPoint = CGPointMake(endCoordinate.longitude, endCoordinate.latitude);
                double distance;
                CGPoint point = [self nearestPointToPoint:originPoint onLineSegmentPointA:startPoint pointB:endPoint distance:&distance];
    
                if (distance < bestDistance) {
                    bestDistance = distance;
                    bestPolyline = polyline;
                    bestPoint = point;
                }
            }
        }
    
        return CLLocationCoordinate2DMake(bestPoint.y, bestPoint.x);
    }
    

    Method nearestPolylineLocationToCoordinate: will browse through all polylines (you just need to supply polylines array == self.polylines) and find the best one.

    // taken and modified from: http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
    - (CGPoint)nearestPointToPoint:(CGPoint)origin onLineSegmentPointA:(CGPoint)pointA pointB:(CGPoint)pointB distance:(double *)distance {
        CGPoint dAP = CGPointMake(origin.x - pointA.x, origin.y - pointA.y);
        CGPoint dAB = CGPointMake(pointB.x - pointA.x, pointB.y - pointA.y);
        CGFloat dot = dAP.x * dAB.x + dAP.y * dAB.y;
        CGFloat squareLength = dAB.x * dAB.x + dAB.y * dAB.y;
        CGFloat param = dot / squareLength;
    
        CGPoint nearestPoint;
        if (param < 0 || (pointA.x == pointB.x && pointA.y == pointB.y)) {
            nearestPoint.x = pointA.x;
            nearestPoint.y = pointA.y;
        } else if (param > 1) {
            nearestPoint.x = pointB.x;
            nearestPoint.y = pointB.y;
        } else {
            nearestPoint.x = pointA.x + param * dAB.x;
            nearestPoint.y = pointA.y + param * dAB.y;
        }
    
        CGFloat dx = origin.x - nearestPoint.x;
        CGFloat dy = origin.y - nearestPoint.y;
        *distance = sqrtf(dx * dx + dy * dy);
    
        return nearestPoint;
    }
    

    You can use it eg in:

    - (void)mapView:(GMSMapView *)mapView didEndDraggingMarker:(GMSMarker *)marker {
        marker.position = [self nearestPolylineLocationToCoordinate:marker.position];
    }
    

提交回复
热议问题