MKPolyline 'inside' an MKOverlay: How do I access the points that construct the line?

My question yesterday - https://developer.apple.com/forums/thread/680107 - was probably to complex for anyone to want to try to answer, I am sorry!
So now I will break it up, and start with a smaller question:
I am trying to show 10 simple lines on a map with Map Kit. The lines have been loaded into a list called 'overlays' by a module called KMLviewer, or more exactly KMLparser, inside KMLviewer - from https://github.com/ooper-shlab/KMLViewer-Swift .
As you can see from my debugging log below, 'overlays' is a list of elements of the type 'MKOverlay', although in reality they are all MKPolyline(s). So how do I access the 2 geographic points that make up each line?
MKPolyline inherits from MKMultiPoint, which has a function:

Code Block
func points() -> UnsafeMutablePointer<MKMapPoint>

"Returns an array of map points associated with the shape. "

But as you can see from my debugging below, I can't seem to access that function, now that the MKPolyline is "inside" an MKOverlay. So how do I access the points?:

(lldb) po overlays
▿ 10 elements
    - 0 : <MKPolyline: 0x60000368bc60>
    - 1 : <MKPolyline: 0x60000368bcd0>
    - 2 : <MKPolyline: 0x60000368bd40>
    - 3 : <MKPolyline: 0x60000368bdb0>
    - 4 : <MKPolyline: 0x60000368be20>
    - 5 : <MKPolyline: 0x60000368be90>
    - 6 : <MKPolyline: 0x60000368bf00>
    - 7 : <MKPolyline: 0x60000368bf70>
    - 8 : <MKPolyline: 0x600003690000>
    - 9 : <MKPolyline: 0x600003690070>

(lldb) po overlays[0]
<MKPolyline: 0x60000368bc60>

(lldb) po overlays[0].coordinate
▿ CLLocationCoordinate2D
    - latitude : 64.47726683920816
    - longitude : -21.420572185955933

(lldb) po overlays[0].points()
error: <EXPR>:3:13: error: value of type 'MKOverlay' has no member 'points'
overlays[0].points()
~~~ ^~

(lldb)
Answered by OOPer in 674734022

So the overall question still remains: Why are none of the MKPolyline(s) visible on the map?
For more information on this project, see https://developer.apple.com/forums/thread/680107

So, thanks for checking. As suggested by Claud31, it seems KMLParser cannot detect the right styles for LineString in kml.
As you know, the original KML_Sample.kml does not contain LineString elements, I guess the feature was not fully tested.

I wrote some partial answer on the original thread you have shown.
But, to show your kml file more precisely as it is, you may need to update KMLParser and all related types.
MKOverlay is a protocol. And type is effectively MKPolyline

In the GitHub code, they note:
Code Block
// MKPointAnnotations and are not MKOverlays.
var points: [MKAnnotation] {
return _placemarks.compactMap{$0.point}
}

So, to get the points, instead of using
        let overlays = self.kmlParser.overlays
did you try using
        let points = self.kmlParser.points
(but that may be only the coordinates of the annotation, not your line).


(lldb) po overlays[0]                     
<MKPolyline: 0x60000368bc60>

If overlays[0] is in fact a MKPolyline
Did you try
Code Block
(overlays[0] as MKPolyline).points()

Thank you for the suggestion!

I inserted this in the code:
Code Block swift
let temp_debug = (overlays[0] as! MKPolyline).points()

And tried this, when debugging:

(lldb) po temp_debug
▿ 0x0000600000cb3380
  • pointerValue : 105553129583488

That doesn't show the geographic points, at least not directly. Am I doing something wrong here?
Can you show your example kml?
Yes! I have attached the KML file.

EDIT: I clicked the 'Text attachment' icon below this editor, but I can't see the file here... So I have put it here instead: transformation.dk/deling/geo-esp-series-2.kml

Thanks, I could have downloaded the xml file.

A bit long, but can you try this?
Code Block
po overlays.map {$0 as! MKPolyline}.map {Array(UnsafeBufferPointer(start:$0.points(),count:$0.pointCount))}


Thank you!
That command is a bit cryptic to me... :-)
And the result is not exactly as expected - I mean latitudes and longitudes are within [-90;+90] and [-180;+180], but the numbers below are much much larger?

(lldb) po overlays.map {$0 as! MKPolyline}.map {Array(UnsafeBufferPointer(start:$0.points(),count:$0.pointCount))}
▿ 10 elements
▿ 0 : 2 elements
▿ 0 : MKMapPoint
  • x : 117883367.59539957

  • y : 70861444.881933

▿ 1 : MKMapPoint
  • x : 118607415.83505598

  • y : 70680834.53921854

▿ 1 : 2 elements
▿ 0 : MKMapPoint
  • x : 118441733.74494734

  • y : 71578008.7574973

▿ 1 : MKMapPoint
  • x : 117749165.70252322

  • y : 71814479.09122863

▿ 2 : 2 elements
▿ 0 : MKMapPoint
  • x : 118311383.29024056

  • y : 71083267.28620416

▿ 1 : MKMapPoint
  • x : 119039612.1903483

  • y : 70938560.8337035

▿ 3 : 2 elements
▿ 0 : MKMapPoint
  • x : 117349946.79156

  • y : 71842649.73875001

▿ 1 : MKMapPoint
  • x : 117798366.05769886

  • y : 72412616.11056598

▿ 4 : 2 elements
▿ 0 : MKMapPoint
  • x : 117630562.56314905

  • y : 70896032.54940976

▿ 1 : MKMapPoint
  • x : 116901460.90088205

  • y : 71039800.62831044

▿ 5 : 2 elements
▿ 0 : MKMapPoint
  • x : 117238216.79458134

  • y : 71348308.82833827

▿ 1 : MKMapPoint
  • x : 117001456.46769533

  • y : 72040794.67949402

▿ 6 : 2 elements
▿ 0 : MKMapPoint
  • x : 117987254.6410381

  • y : 72066796.5154083

▿ 1 : MKMapPoint
  • x : 118291226.77453867

  • y : 71401739.6663419

▿ 7 : 2 elements
▿ 0 : MKMapPoint
  • x : 117274415.68432339

  • y : 71712389.33240001

▿ 1 : MKMapPoint
  • x : 116717162.22724375

  • y : 71232706.02820335

▿ 8 : 2 elements
▿ 0 : MKMapPoint
  • x : 118103113.58567446

  • y : 70920013.76664141

▿ 1 : MKMapPoint
  • x : 117442255.64753546

  • y : 71255771.67482962

▿ 9 : 2 elements
▿ 0 : MKMapPoint
  • x : 118404987.20831521

  • y : 71705176.99185553

▿ 1 : MKMapPoint
  • x : 119010223.05936122

  • y : 72110774.61697051

(lldb)

the numbers below are much much larger? 

MKPolyline converts CLLocationCoordinate2D (which holds latitudes and longitudes) into MKMapPoint.
I am not sure if the shown values are too large or sort of invalid as MKMapPoint.
OK. Thanks!
I guess I will have to look at the definition of MKMapPoint tomorrow - now it's bed time. :-)
If you want to unconvert MKMapPoint in MKPolyline to CLLocationCoordinate2D, you may need a little more complex code.
Please add these lines in the code where overlays is valid:
Code Block
overlays.forEach {overlay in
if let polyline = overlay as? MKPolyline {
var coords = Array(repeating: CLLocationCoordinate2D(), count: polyline.pointCount)
polyline.getCoordinates(&coords, range: NSRange(0..<polyline.pointCount))
print(coords)
}
}

Have a good sleep.
Thank you very much!
When converted like that, the geographic coordinates look perfect. So the overall question still remains: Why are none of the MKPolyline(s) visible on the map?
For more information on this project, see https://developer.apple.com/forums/thread/680107

This is the main swift file in the KMLviewer project:

Code Block swift
//
// KMLViewerViewController.swift
// KMLViewer
//
// Translated by OOPer in cooperation with shlab.jp, on 2015/10/17.
//
//
/*
Copyright (C) 2015 Apple Inc. All Rights Reserved.
See LICENSE.txt for this sample’s licensing information
Abstract:
Displays an MKMapView and demonstrates how to use the included KMLParser class to place annotations and overlays from a parsed KML file on top of the MKMapView.
*/
import UIKit
import MapKit
@objc(KMLViewerViewController)
class KMLViewerViewController: UIViewController, MKMapViewDelegate {
@IBOutlet private weak var map: MKMapView!
private var kmlParser: KMLParser!
override func viewDidLoad() {
super.viewDidLoad()
map.mapType = .hybridFlyover
// Locate the path to the file in the application's bundle
// and parse it with the KMLParser.
let url = Bundle.main.url(forResource: "KML_Sample", withExtension: "kml")!
self.kmlParser = KMLParser(url: url)
self.kmlParser.parseKML()
// Add all of the MKOverlay objects parsed from the KML file to the map.
let overlays = self.kmlParser.overlays
overlays.forEach {overlay in
if let polyline = overlay as? MKPolyline {
var coords = Array(repeating: CLLocationCoordinate2D(), count: polyline.pointCount)
polyline.getCoordinates(&coords, range: NSRange(0..<polyline.pointCount))
print(coords)
}
}
self.map.addOverlays(overlays)
let temp_debug = overlays.map {$0 as! MKPolyline}.map {Array(UnsafeBufferPointer(start:$0.points(),count:$0.pointCount))}
// Add all of the MKAnnotation objects parsed from the KML file to the map.
let annotations = self.kmlParser.points
self.map.addAnnotations(annotations)
// Walk the list of overlays and annotations and create a MKMapRect that
// bounds all of them and store it into flyTo.
var flyTo = MKMapRect.null
for overlay in overlays {
if flyTo.isNull {
flyTo = overlay.boundingMapRect
} else {
flyTo = flyTo.union(overlay.boundingMapRect)
}
}
for annotation in annotations {
let annotationPoint = MKMapPoint(annotation.coordinate)
let pointRect = MKMapRect(x: annotationPoint.x, y: annotationPoint.y, width: 0, height: 0)
if flyTo.isNull {
flyTo = pointRect
} else {
flyTo = flyTo.union(pointRect)
}
}
// Position the map so that all overlays and annotations are visible on screen.
self.map.visibleMapRect = flyTo
}
//MARK: MKMapViewDelegate
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
return self.kmlParser.rendererForOverlay(overlay)!
}
func mapView(_ mapView: MKMapView, viewFor annotation: MKAnnotation) -> MKAnnotationView? {
return self.kmlParser.viewForAnnotation(annotation)
}
}


Did you set color and line width for the poly line ?

You should do this in
Code Block
func mapView(_ mapView: MKMapView, rendererFor overlay: MKOverlay) -> MKOverlayRenderer {
if let routePolyline = overlay as? MKPolyline {
let renderer = MKPolylineRenderer(polyline: routePolyline)
renderer.strokeColor = UIColor.blue.cgColor
renderer.lineWidth = 2
return renderer
}
return MKOverlayRenderer()
}

Get more details here:
https://stackoverflow.com/questions/58013956/mapkit-draw-poly-line-from-coordinates-swift-5

Accepted Answer

So the overall question still remains: Why are none of the MKPolyline(s) visible on the map?
For more information on this project, see https://developer.apple.com/forums/thread/680107

So, thanks for checking. As suggested by Claud31, it seems KMLParser cannot detect the right styles for LineString in kml.
As you know, the original KML_Sample.kml does not contain LineString elements, I guess the feature was not fully tested.

I wrote some partial answer on the original thread you have shown.
But, to show your kml file more precisely as it is, you may need to update KMLParser and all related types.
Thank you very much to both of you!
Now it works!
I choose the solution where the code is put in the KMLparser and not in the main file. That seems more correct and as kind of a preparation for implementing detecting style elements inside Linestring. But since I don't have different styles on different lines, I haven't bothered enhancing the parser itself. I am still a beginner in Swift. :-)
MKPolyline 'inside' an MKOverlay: How do I access the points that construct the line?
 
 
Q