VKDefault - 三角器未能完全三角化多边形 MapKit

2024-04-05

我遇到了收到警告的问题[VKDefault] Triangulator failed to fully triangulate polygon MapKit放大和缩小地图上的特定区域时。

我正在从 json 数据创建多边形,该数据可以包含 MKPolygon 或 MKMultiPolygon。 200 多个多边形中只有几个存在问题。

对我来说,数据看起来不错。我尝试删除坐标数组中的重复项(如果它们包含任何重复项),但没有成功。也许我做得不对,因为 MKMultiPolygon 是从 [[[[Double]]]] 创建的

这是该项目的链接 -https://www.dropbox.com/s/zwy08upcne11dyy/VectorMaps%203.zip?dl=0 https://www.dropbox.com/s/zwy08upcne11dyy/VectorMaps%203.zip?dl=0

这只是一个原型,所以请不要强迫我强行展开。

这就是带有警告的区域的样子。

我在 ViewController 中添加了我遇到问题的区域列表。

解决警告的额外奖励VectorMaps[1611:116104] [VKDefault] Style Z is requested for an invisible rect

struct SubRegion: Decodable {
    var id: Int
    var name: String
    var geometry: Geometry

    enum CodingKeys: String, CodingKey {
        case id, name, geometry = "geojson_geometry"
    }
}

enum PolygonType: String {
    case multiPolygon = "MultiPolygon"
    case polygon = "Polygon"
}

struct Geometry: Decodable {
    var type: String
    var coordinates: Array<Any>
    var convexHullGeometry: ConvexGeometry?

    enum CodingKeys: String, CodingKey {
        case type, coordinates, convexHullGeometry = "convex_hull_geojson_geometry"
    }

    enum ParseError: Error {
        case notRecognizedType(Any)
    }

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        type = try container.decode(String.self, forKey: .type)

        switch type {
        case "Polygon":
            coordinates = try container.decode([[[Double]]].self, forKey: .coordinates)
        case "MultiPolygon":
            coordinates = try container.decode([[[[Double]]]].self, forKey: .coordinates)
        default:
            throw ParseError.notRecognizedType(type)
        }
    }
}

struct ConvexGeometry: Codable {
    var coordinates: [[[Double]]]
}

class ViewController: UIViewController {
    var activeMultiRenders = [MKMultiPolygonRenderer]()
    var activeRenders = [MKPolygonRenderer]()
    var mapView: MKMapView!

    let pinView = LocationPinView()
    var showMarker = false
    var showAnnotation = false

    var this = MKPointAnnotation()

    typealias Polygon = [[[Double]]]
    typealias MultiPolygon = [[[[Double]]]]

    let staticMarkerButton: UIButton = {
        let button = UIButton()
        button.setTitle("Show static marker", for: .normal)
        button.addTarget(self, action: #selector(addMarker), for: .touchUpInside)
        button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
        button.setTitleColor(.blue, for: .normal)
        button.backgroundColor = .white
        button.layer.cornerRadius = 5
        return button
    }()

    let mapButton: UIButton = {
        let button = UIButton()
        button.setTitle("Radius Map", for: .normal)
        button.addTarget(self, action: #selector(visitRadius), for: .touchUpInside)
        button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
        button.setTitleColor(.blue, for: .normal)
        button.backgroundColor = .white
        button.layer.cornerRadius = 5
        return button
    }()

    let showLabelButton: UIButton = {
        let button = UIButton()
        button.setTitle("Show labels", for: .normal)
        button.addTarget(self, action: #selector(addAnnotations), for: .touchUpInside)
        button.contentEdgeInsets = UIEdgeInsets(top: 10, left: 15, bottom: 10, right: 15)
        button.setTitleColor(.blue, for: .normal)
        button.backgroundColor = .white
        button.layer.cornerRadius = 5
        return button
    }()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        mapView = MKMapView(frame: self.view.frame)
        mapView.isRotateEnabled = false
        mapView.mapType = .standard

        addPolygonsToMap()

        mapView.delegate = self
        self.view.addSubview(mapView)
        
        let tap = UITapGestureRecognizer(target: self, action: #selector(mapTapped(_:)))
        self.mapView.addGestureRecognizer(tap)

        self.view.addSubview(pinView)
        pinView.frame = CGRect(x: mapView.center.x, y: mapView.center.y - pinView.frame.height,
                               width: pinView.frame.width, height: pinView.frame.height)
        pinView.isHidden = true

        view.addSubview(staticMarkerButton)
        staticMarkerButton.translatesAutoresizingMaskIntoConstraints = false
        staticMarkerButton.topAnchor.constraint(equalTo: view.topAnchor, constant: 100).isActive = true
        staticMarkerButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        view.addSubview(mapButton)
        mapButton.translatesAutoresizingMaskIntoConstraints = false
        mapButton.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: -100).isActive = true
        mapButton.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true

        view.addSubview(showLabelButton)
        showLabelButton.translatesAutoresizingMaskIntoConstraints = false
        showLabelButton.leadingAnchor.constraint(equalTo: mapButton.trailingAnchor, constant: 10).isActive = true
        showLabelButton.topAnchor.constraint(equalTo: mapButton.topAnchor).isActive = true
    }

    func addPolygonsToMap() {
        let fileURL = Bundle.main.url(forResource: "subregion", withExtension: "json")!
        let decoder = JSONDecoder()

        do {
            let data = try Data(contentsOf: fileURL)
            let subregions = try decoder.decode([SubRegion].self, from: data)

            for each in subregions {
                let geometry = each.geometry

//                if !badData.contains(each.name) {
//                    continue
//                }

                // Type is either a Polygon or MultiPolygon
                let geometryType = each.geometry.type

                if geometryType == PolygonType.polygon.rawValue {
                    // Cast the coordinates to a Polygon type-alias.
                    let coords = geometry.coordinates as! Polygon
                    let lCoords = getCoordinatesFromPolygonArray(coords)
                                        
                    // Create a MKPolygon with locationCoordinates
                    let polygon = MKPolygon(coordinates: lCoords, count: lCoords.count)

                    // Add the MKPolygon to the map
                    mapView.addOverlay(polygon)
                } else if geometryType == PolygonType.multiPolygon.rawValue {
                    // Cast the coordinates to a MultiPolygon type-alias.
                    let coords = geometry.coordinates as! MultiPolygon
                    
                    var polygons:[MKPolygon] = []
                    coords.forEach { polygon in

                        let lCoords = getCoordinatesFromPolygonArray(polygon)

                        // Create a MKPolygon with locationCoordinates
                        let polygon = MKPolygon(coordinates: lCoords, count: lCoords.count)

                        polygons.append(polygon)
                    }
                    
                    let multiPolygon = MKMultiPolygon(polygons)
                    mapView.addOverlay(multiPolygon)
                }
            }
        } catch let error {
            print("Error", error)
        }
    }

    let badData = ["Central Coast", "Dapto and Port Kembla", "Wellington", "South West Perth", "East Arnhem", "Charters Towers", "Ormeau", "Murray River", "Wodonga", "Bruny Island", "Katherine", "Far North", "Tweed Valley", "Richmond Valley", "South East Coast", "Gympie", "Meander Valley"]
    
    private func getCoordinatesFromPolygonArray(_ polygon: Polygon) -> [CLLocationCoordinate2D] {
        var locationCoordinates = [CLLocationCoordinate2D]()

        if let coordinates = polygon.first?.map({ CLLocationCoordinate2D(latitude: $0[1] , longitude: $0[0]) }) {
            locationCoordinates.append(contentsOf: coordinates)
        }

        return locationCoordinates
    }

    
    func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
        if let polygon = overlay as? MKPolygon {
            let renderer = MKPolygonRenderer(polygon: polygon)
            renderer.strokeColor = UIColor.blue.withAlphaComponent(0.4)
            return renderer
        } else if let multiPolygon = overlay as? MKMultiPolygon {
            let renderer = MKMultiPolygonRenderer(multiPolygon: multiPolygon)
            renderer.strokeColor = UIColor.blue.withAlphaComponent(0.4)
            return renderer
        }
        
        return MKOverlayRenderer(overlay: overlay)
    }

    @objc func mapTapped(_ gesture: UITapGestureRecognizer) {
        let point = gesture.location(in: self.mapView)
        let coordinate = self.mapView.convert(point, toCoordinateFrom: nil)
        let mappoint = MKMapPoint(coordinate)

        for renderer in self.mapView.polygonRenderers {
            let tapPoint = renderer.point(for: mappoint)
            if renderer.path.contains(tapPoint) && activeRendersContains(renderer) {
                renderer.strokeColor = UIColor.blue.withAlphaComponent(0.4)
                renderer.fillColor = UIColor.clear
                removeActive(renderer)

            } else if renderer.path.contains(tapPoint) {
                renderer.fillColor = UIColor.blue.withAlphaComponent(0.4)
                renderer.strokeColor = UIColor.blue
                appendActive(renderer)
            }
        }
    }

    func activeRendersContains(_ renderer: MKOverlayPathRenderer) -> Bool {
        if let multiRenderer = renderer as? MKMultiPolygonRenderer {
            return activeMultiRenders.contains(multiRenderer)
        } else if let polyRenderer = renderer as? MKPolygonRenderer {
            return activeRenders.contains(polyRenderer)
        } else {
            return false
        }
    }

    func appendActive(_ renderer: MKOverlayPathRenderer) {
        if let multiRenderer = renderer as? MKMultiPolygonRenderer {
            activeMultiRenders.append(multiRenderer)
        } else if let polyRenderer = renderer as? MKPolygonRenderer {
            activeRenders.append(polyRenderer)
        }
    }

    func removeActive(_ renderer: MKOverlayPathRenderer) {
        if let multiRenderer = renderer as? MKMultiPolygonRenderer {
            activeMultiRenders.removeAll(where: {$0 == multiRenderer})
        } else if let polyRenderer = renderer as? MKPolygonRenderer {
            activeRenders.removeAll(where: {$0 == polyRenderer})
        }
    }

    @objc func addMarker() {
        showMarker.toggle()

        if showMarker {
            staticMarkerButton.setTitle("Hide marker", for: .normal)
            pinView.isHidden = false
        } else {
            staticMarkerButton.setTitle("Show marker", for: .normal)
            pinView.isHidden = true
        }
    }

    @objc func visitRadius() {
        let radiusVC = RadiusViewController()
        radiusVC.modalPresentationStyle = .fullScreen
        present(radiusVC, animated: false, completion: nil)
    }

    @objc func addAnnotations() {
        showAnnotation.toggle()

        if showAnnotation {
            // Gets the coordinates and titles of each polygon renderer.
            let details = mapView.activePointDetailsFor(activeRenders)

            // Creates and adds annotations to the map with given details.
            mapView.addAnnotationsWith(details)
        } else {
            mapView.removeAllAnnotations()
        }
    }
}

extension ViewController: MKMapViewDelegate {

    func mapView(_ mapView: MKMapView, regionWillChangeAnimated animated: Bool) {
        pinView.pinPosition = .up
    }

    func mapView(_ mapView: MKMapView, regionDidChangeAnimated animated: Bool) {
        if showMarker {
            pinView.pinPosition = .down
        }
    }

    func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
        let annotationView = LabelAnnotationView(annotation: annotation, reuseIdentifier: annotation.title!)
        return annotationView
    }
}

extension MKMapView {
    var polygonRenderers: [MKOverlayPathRenderer] {
        var renders = [MKOverlayPathRenderer]()
        for overlay in self.overlays {
            if let polygon = overlay as? MKPolygon {
                guard let renderer = self.renderer(for: polygon) as? MKPolygonRenderer else { continue }
                renders.append(renderer)
            } else if let multiPolygon = overlay as? MKMultiPolygon {
                guard let renderer = self.renderer(for: multiPolygon) as? MKMultiPolygonRenderer else { continue }
                renders.append(renderer)
            }
        }
        return renders
    }

    typealias PointDetails = (coordinate: CLLocationCoordinate2D ,title: String)

    func activePointDetailsFor(_ renders: [MKPolygonRenderer]) -> [PointDetails] {
        var details = [PointDetails]()

        for each in renders {
            let title: String = each.polygon.title ?? ""
            let coordinate = each.polygon.coordinate

            let detail = (coordinate: coordinate ,title: title)
            details.append(detail)
        }

        return details
    }

    func addAnnotationsWith(_ details: [PointDetails]) {
        for each in details {
            let annotation = MKPointAnnotation()
            annotation.coordinate = each.coordinate
            annotation.title = each.title
            self.addAnnotation(annotation)
        }
    }

    func removeAllAnnotations() {
        let annotations = self.annotations
        self.removeAnnotations(annotations)
    }
}
 

我仍在弄清楚,但在 iOS 16.1 中我遇到了类似的问题。但是,我已从地图中删除了多边形的绘制和注释。

List has 13 nodes:
    33 34 35 37 30 32 21 23 24 26 38 4 0 
[VKDefault] Building failed to triangulate!
Wrapped around the polygon without finishing... :-(
List has 15 nodes:
    10 17 23 32 7 8 1 30 27 28 32 26 21 13 9 
[VKDefault] Building failed to triangulate!
Wrapped around the polygon without finishing... :-(
List has 14 nodes:
    55 50 43 44 38 39 41 50 52 53 48 35 37 54 
 [VKDefault] Building failed to triangulate!
 Missing MeshRenderables for ground mesh layer for (4/4) of ground tiles. Tile debug info: (Key: 7.4.4.255 t:34 kt:0, 
Has mesh errors: 0, MeshInstance count: 2, PendingMaterial count: 2, Invisible MeshInstances count: 0 | Key: 7.5.4.255 t:34 kt:0, 
Has mesh errors: 0, MeshInstance count: 2, PendingMaterial count: 2, Invisible MeshInstances count: 0 | Key: 8.4.4.255 t:34 kt:0, 
Has mesh errors: 0, MeshInstance count: 2, PendingMaterial count: 2, Invisible MeshInstances count: 0 | Key: 8.5.4.255 t:34 kt:0,
Has mesh errors: 0, MeshInstance count: 2, PendingMaterial count: 2, Invisible MeshInstances count: 0)

当我有注释和多边形时,应用程序会冻结但不会崩溃。

我也得到

[VKDefault] Exceeded Metal Buffer threshold of 50000 with a count of 50892 resources,  
  pruning resources now (Time since last prune:6.497636): Assertion with expression - false : 
  Failed in file - /Library/Caches/com.apple.xbs/Sources/VectorKit/src/MDMapEngine.mm line - 1363
Exceeded Metal Buffer threshold of 50000 with a count of 51462 resources, 
  pruning resources now (Time since last prune:6.809683): Assertion with expression - false :
  Failed in file - /Library/Caches/com.apple.xbs/Sources/VectorKit/src/MDMapEngine.mm line - 1363

迄今为止唯一的解决方案是

mapView.mapType = MKMapType.hybrid
mapView.mapType = MKMapType.standard

清除应用程序的缓存。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

VKDefault - 三角器未能完全三角化多边形 MapKit 的相关文章

  • 在 Swift 3 中单击和双击 UITableViewCell

    我在 TableView Cell 上有故事板 segue 我用它来在单元格单击中传输到另一个 VCdidSelectRowAt方法 现在我双击了TapGestureRecognizer处理手机上的点击问题 问题是 单击时 segue 正在
  • 我可以在 NS_SWIFT_NAME 中使用保留关键字吗?

    我正在尝试使 Objective C 委托协议更漂亮以便在 Swift 中使用 但我在弄清楚如何使用时遇到了一些麻烦NS SWIFT NAME 是否可以使用NS SWIFT NAME指定 Swift 名称中与 Objective C 关键字
  • 应用程序图标未刷新

    我更改了新版本应用程序中的图标图像 并且我在设备中安装了旧版本应用程序 然后我安装了新版本 它在 iOS 5 中运行良好 但在 iOS 6 中 图标没有刷新 它仍然显示旧版本图标 徽标 如果没有安装旧版本应用程序 该设备在 iOS 5 和
  • 如何在 Swift 中使用 substringToIndex? [复制]

    这个问题在这里已经有答案了 我在这一行收到编译器错误 UIDevice currentDevice identifierForVendor UUIDString substringToIndex 8 类型 String Index 不符合协
  • 从 Plist 中存储和检索 [重复]

    这个问题在这里已经有答案了 可能的重复 iOS 在 plist 文件中存储两个 NSMutableArray https stackoverflow com questions 6070568 ios store two nsmutable
  • Swift 数组设置索引值不起作用

    我有一个方法 下面的内容 其中queue2只是一个 Int 我打印了很多东西 看看一切是否都正常 public func cool item Int println item println back queue2 insert item
  • 使用 Push Transition 效果更改 RootViewcontroller

    在我的iOS应用程序中 我需要更改应用程序之间窗口的rootviewController 因此 当我动态更改我的rootviewcontroller时 它会在更改之前轻拂视图 但我想要的是在更改rootviewcontroller时提供平滑
  • iOS App布局错误,调用状态栏

    在主动通话和应用程序布局期间面临状态栏问题 我正在使用自动布局 当我运行应用程序 然后开始通话时 一切正常 UI 会随着状态栏的更改而正确缩放 但是 如果我首先开始通话 然后运行应用程序 应用程序屏幕会移动到底部 20pt 就像它们对新状态
  • 使用 UIImagePickerController 的应用程序在拍照后选择“使用照片”时冻结

    我现在正在开发一个简单的照片和视频捕获应用程序 该应用程序成功地允许用户按下按钮即可拍摄照片或视频 但是 一旦您完成拍摄照片或视频 它就会提供 2 个选项 重新拍摄 和 使用照片 或 使用视频 具体取决于您使用的选项 如果用户点击 重新拍摄
  • iOS 内存警告

    我正在尝试使用从 Parse 数据库下载的图像填充集合视图 但我收到内存警告 然后偶尔崩溃 有谁知道其他应用程序如何设法呈现这么多图像而不崩溃 有人可以告诉我如何优化我已有的东西吗 这是所有相关代码 https gist github co
  • 切换到工作区并在 Xcode 中添加 CocoaPods 后提交 git 吗?

    我刚刚在 Xcode 5 中将 CocoaPods 添加到我当前的项目中 当然 CocoaPods 创建了一个工作区 并且我已在 Xcode 中启动了该工作区 我在工作区中看到了我的项目和 Pods 项目 我的项目从第一天起就处于源代码控制
  • iOS 中的等宽字体是什么?

    我想要在我的 iOS 应用程序中为 UILabel 使用等宽字体 不幸的是 我找不到一个 甚至 美国打字机 实际上也不是等宽的 XCode 中可用的等宽字体是什么 iOS 等宽字体 Courier Courier Bold Courier
  • 更改 UITextField 辅助功能描述

    有没有办法将 UITextField 的辅助功能标签设置为 文本字段 之外的其他内容 因此 我不想将其称为 文本字段 而是将其命名为 代码验证字段 我的建议是不要试图在内置语音输出上智取系统 对于盲人用户来说 文本字段正在编辑 相当于 该项
  • 如何使用自签名证书为 TLS 创建 iOS NWConnection?

    我正在尝试将 Apple 的新 NWConnection 类用于我的 MQTT 客户端 为了进行测试 我需要能够创建到本地测试代理的 TLS 连接 该代理具有自签名证书 到目前为止 我只是使用以下命令设置连接 self connection
  • 在模拟器中运行应用程序时删除本地通知的 iOS 权限警报

    我正在尝试编写验收测试KIF https github com kif framework KIF在一个很早就要求本地通知权限的应用程序上 不幸的是 由于 iOS 模拟器安全原因无法使用 KIF 自动接受 iOS 权限警报 https gi
  • 维护 UISegmentedControl 中的选择

    我可以保持 UISegmentViewControl 段的选定状态吗 即 即使用户选择了另一个段 也可以保持一个段显示为选中状态 我似乎在任何地方都找不到任何可以做到这一点的东西 这是不可能开箱即用的 看如何才能选择 UISegmented
  • 打印附加结构(swift 4)

    我有三个 textifled 用于将数据附加到结构中 如何打印我附加的内容 现在我收到一条错误消息 import UIKit class ViewController UIViewController IBOutlet var c UITe
  • 应用未能及时恢复

    我在一个非常具体的场景中遇到 未能及时恢复 崩溃 我认为与看门狗相关 仅在从后台恢复时 并且仅在进入后台后在很短的时间内执行此操作 a最多几秒钟 这似乎是相关的崩溃日志 Incident Identifier E30F2238 5B15 4
  • 播放(非库)Apple Music 内容 - 请求失败

    我正在尝试使用以下代码播放专辑 let predicate MPMediaPropertyPredicate value 1459938538 forProperty MPMediaItemPropertyAlbumPersistentID
  • 如何自动为 Swift 类创建初始化程序?

    UPDATE 使用结构而不是类 struct 在很多方面都更好 它有自己的初始化器 这是我的模型课 是否有可能创建init自动方法 每次我都必须将所有变量一一初始化 这会花费很多时间 class Profile var id String

随机推荐