【问题标题】:MKMapKit draggable annotation and drawing polygonsMKMapKit 可拖动注释和绘制多边形
【发布时间】:2016-07-13 07:16:37
【问题描述】:

我目前正在尝试允许用户向地图添加图钉,然后绘制一个连接这些图钉的多边形。但是我想扩展它以允许用户能够拖动引脚并且多边形将相应地更新。 MKMapView 根据它们在数组中的排列从坐标数组中绘制多边形(如果我没记错的话)。我现在面临的问题是如何在用户重新定位引脚后更新多边形。

var touchCoordinatesWithOrder: [(coordinate: CLLocationCoordinate2D, order: Int)] = []
var counter = 0

func addLongPressGesture() {
    let longPressRecogniser = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
    longPressRecogniser.minimumPressDuration = 1.0
    mapView.addGestureRecognizer(longPressRecogniser)

}

func handleLongPress(gestureRecognizer: UIGestureRecognizer) {
    if gestureRecognizer.state != .Began {
        return
    }

    let touchPoint = gestureRecognizer.locationInView(self.mapView)
    let touchMapCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)

    let annotation = MKPointAnnotation()
    annotation.coordinate = touchMapCoordinate
    mapView.addAnnotation(annotation)

    touchCoordinatesWithOrder.append((coordinate: touchMapCoordinate, order: counter))
    counter += 1

}


@IBAction func drawAction(sender: AnyObject) {
    if touchCoordinatesWithOrder.count <= 2 {
        print("Not enough coordinates")
        return
    }

    var coords = [CLLocationCoordinate2D]()
    for i in 0..<touchCoordinatesWithOrder.count {
        coords.append(touchCoordinatesWithOrder[i].coordinate)
    }

    let polygon = MKPolygon(coordinates: &coords, count: coords.count)
    mapView.addOverlay(polygon)
    counter = 0
}

func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
    // if the user repositioned pin number2 then how to I update my array?
}

func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
    if overlay is MKPolygon {
        let polygonView = MKPolygonRenderer(overlay: overlay)
        polygonView.strokeColor = UIColor.blackColor()
        polygonView.lineWidth = 0.5
        return polygonView
    }
    return MKPolylineRenderer()
}

【问题讨论】:

    标签: ios swift mkmapview


    【解决方案1】:

    要使引脚可拖动,您需要在MKAnnotationView 上设置draggable = true。实现viewForAnnotation 并出列或创建注解,然后设置draggable = true。确保设置了 MKMapView 委托,否则将不会调用任何委托方法。

    您可能还会发现将注释存储在数组中比仅存储坐标更容易。地图视图保留了对数组中注解的引用,所以当点在地图中移动时,注解会自动更新。

    您的问题并未说明您是否需要在这些点周围 或通过这些点绘制路径。如果要绘制围绕点的叠加层,则还需要计算坐标的凸包。代码示例就是这样做的,尽管它很容易被删除。

    例子:

    class MapAnnotationsOverlayViewController: UIViewController, MKMapViewDelegate {
    
        @IBOutlet var mapView: MKMapView!
    
        // Array of annotations - modified when the points are changed.
        var annotations = [MKPointAnnotation]()
    
        // Current polygon displayed in the overlay.
        var polygon: MKPolygon?
    
        override func viewDidLoad() {
            super.viewDidLoad()
            mapView.delegate = self    
            addLongPressGesture()
        }
    
        func addLongPressGesture() {
            let longPressRecogniser = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPress))
            longPressRecogniser.minimumPressDuration = 0.25
            mapView.addGestureRecognizer(longPressRecogniser)
    
        }
    
        func handleLongPress(gestureRecognizer: UIGestureRecognizer) {
    
            guard gestureRecognizer.state == .Began else {
                return
            }
    
            let touchPoint = gestureRecognizer.locationInView(self.mapView)
            let touchMapCoordinate = mapView.convertPoint(touchPoint, toCoordinateFromView: mapView)
    
    
            let annotation = MKPointAnnotation()
    
            // The annotation must have a title in order for it to be selectable.
            // Without a title the annotation is not selectable, and therefore not draggable.
            annotation.title = "Point \(annotations.count)"
            annotation.coordinate = touchMapCoordinate
            mapView.addAnnotation(annotation)
    
            // Add the new annotation to the list.
            annotations.append(annotation)
    
            // Redraw the overlay.
            updateOverlay()
        }
    
        @IBAction func drawAction(sender: AnyObject) {
            updateOverlay()
        }
    
        func mapView(mapView: MKMapView, viewForAnnotation annotation: MKAnnotation) -> MKAnnotationView? {
    
            var view = mapView.dequeueReusableAnnotationViewWithIdentifier("pin")
    
            if let view = view {
                view.annotation = annotation
            }
            else {
                view = MKPinAnnotationView(annotation: annotation, reuseIdentifier: "pin")
    
                // Allow the pin to be repositioned.
                view?.draggable = true
            }
    
            return view
        }
    
        func mapView(mapView: MKMapView, annotationView view: MKAnnotationView, didChangeDragState newState: MKAnnotationViewDragState, fromOldState oldState: MKAnnotationViewDragState) {
    
        // The map view retains a reference to the same annotations in the array.
        // The annotation in the array is automatically updated when the pin is moved.
    
            updateOverlay()
        }
    
        func updateOverlay() {
    
            // Remove existing overlay.
            if let polygon = self.polygon {
                mapView.removeOverlay(polygon)
            }
    
            self.polygon = nil
    
            if annotations.count < 3 {
                print("Not enough coordinates")
                return
            }
    
            // Create coordinates for new overlay.
            let coordinates = annotations.map({ $0.coordinate })
    
            // Sort the coordinates to create a path surrounding the points.
            // Remove this if you only want to draw lines between the points.
            var hull = sortConvex(coordinates)
    
            let polygon = MKPolygon(coordinates: &hull, count: hull.count)
            mapView.addOverlay(polygon)
    
            self.polygon = polygon
        }
    
        func mapView(mapView: MKMapView, rendererForOverlay overlay: MKOverlay) -> MKOverlayRenderer {
            if overlay is MKPolygon {
                let polygonView = MKPolygonRenderer(overlay: overlay)
                polygonView.strokeColor = UIColor.blackColor()
                polygonView.lineWidth = 0.5
                return polygonView
            }
            return MKPolylineRenderer()
        }
    }
    

    这是凸包排序算法(改编自Gist on GitHub)。

    func sortConvex(input: [CLLocationCoordinate2D]) -> [CLLocationCoordinate2D] {
    
        // X = longitude
        // Y = latitude
    
        // 2D cross product of OA and OB vectors, i.e. z-component of their 3D cross product.
        // Returns a positive value, if OAB makes a counter-clockwise turn,
        // negative for clockwise turn, and zero if the points are collinear.
        func cross(P: CLLocationCoordinate2D, _ A: CLLocationCoordinate2D, _ B: CLLocationCoordinate2D) -> Double {
            let part1 = (A.longitude - P.longitude) * (B.latitude - P.latitude)
            let part2 = (A.latitude - P.latitude) * (B.longitude - P.longitude)
            return part1 - part2;
        }
    
        // Sort points lexicographically
        let points = input.sort() {
            $0.longitude == $1.longitude ? $0.latitude < $1.latitude : $0.longitude < $1.longitude
        }
    
        // Build the lower hull
        var lower: [CLLocationCoordinate2D] = []
        for p in points {
            while lower.count >= 2 && cross(lower[lower.count-2], lower[lower.count-1], p) <= 0 {
                lower.removeLast()
            }
            lower.append(p)
        }
    
        // Build upper hull
        var upper: [CLLocationCoordinate2D] = []
        for p in points.reverse() {
            while upper.count >= 2 && cross(upper[upper.count-2], upper[upper.count-1], p) <= 0 {
                upper.removeLast()
            }
            upper.append(p)
        }
    
        // Last point of upper list is omitted because it is repeated at the
        // beginning of the lower list.
        upper.removeLast()
    
        // Concatenation of the lower and upper hulls gives the convex hull.
        return (upper + lower)
    }
    

    这是使用凸包排序(围绕点绘制的路径)的外观:

    这是没有排序的样子(从点到点依次绘制的路径):

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-06-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-12-30
      • 2023-03-27
      • 1970-01-01
      相关资源
      最近更新 更多