Select to view content in your preferred language

How to extract coordinates from KML (KmlDataset+KmlLayer) using KmlGeometry?

3476
8
12-11-2018 02:36 PM
SasiPrabhakaran
Emerging Contributor

I'm trying to extract the contents from a KML file using the KmlGeometry in Qt QML environment using Esri.ArcGISRuntime 100.4. I was able to read the KML dataset and the KML layer, which is appended to the map to visualize the KML layer. But I need to extract the Placemark name and coordinates from the KML file for other processes.  

0 Kudos
8 Replies
LucasDanzinger
Esri Frequent Contributor

Where are you running into issues? Once you get the KmlGeometry, you can access the Geometry object from it directly. You can obtain an individual KmlPlacemark by calling identifyLayer on the Map/SceneView.

For example, you could try this workflow:

- Click on the map and use the screen coordinates and KML Layer in MapView::identifyLayer - GeoView QML Type | ArcGIS for Developers 

- Obtain the identify layer results and get the KmlPlacemarks

- Iterate through the placemarks and get the Geometry of each

SasiPrabhakaran
Emerging Contributor

Thanks, Lucas. I would like to extract the geometry programmatically with no room for error. MapView::identifyLayer requires screen coordinates! The idea is to extract the Placemark coordinates and build a polyline and to perform some geodetic operations at an instance after creating the KmlDataset.      

0 Kudos
LucasDanzinger
Esri Frequent Contributor

I see the confusion. Our doc is missing some of the inheritance information. What you will want to do is this:

- once the KmlDataset is loaded, get the rootNodes. This will give you a list of KmlNodes. KmlDataset QML Type | ArcGIS for Developers  

- Go through all the nodes and check the kmlNodeType. If it is a KmlPlacemark, get the Geometry directly from that. If it is a KmlDocument or a KmlFolder, that means it is a KmlContainer (and in that case, that has a list of child nodes) KmlContainer QML Type | ArcGIS for Developers  

- You will have to recursively traverse the entire tree to find all of the KmlPlacemarks in the dataset KmlPlacemark QML Type | ArcGIS for Developers  

Here is the inheritance hierarchy that is missing from the doc. We will get this fixed up

KmlNode
    KmlContainer
        KmlDocument
        KmlFolder
    KmlGroundOverlay
    KmlNetworkLink
    KmlPhotoOverlay
    KmlPlacemark
    KmlScreenOverlay
    KmlTour

SasiPrabhakaran
Emerging Contributor

I've already tried rootNodes and it is returning qml: [object Object]

Here is the snippet:

function createFromUrl() {
        // create the dataset from an online URL
        var kmlDataset = ArcGISRuntimeEnvironment.createObject("KmlDataset", {url: "KmlUrl"});
            var rootL = kmlDataset.load();
            if (kmlDataset.loadStatus === 1){
                var rootObj = kmlDataset.rootNodes;
                console.log("KML rootNodes :" + kmlDataset.rootNodes);
            }
}

The console log returns....

qml: KML rootNodes :[object Object]

The source KML file is as follows:

<?xml version="1.0" encoding="utf-16"?>
<Document xmlns="http://www.opengis.net/kml/2.2">
  <Placemark>
    <name>WP H Alt: 186.705815115468</name>
    <Point>
      <altitudeMode>absolute</altitudeMode>
      <coordinates>-76.1826995015144,42.9201978003155,186.705815115468
</coordinates>
    </Point>
  </Placemark>
  <Placemark>
    <name>WP 1 Alt: 2</name>
    <Point>
      <altitudeMode>absolute</altitudeMode>
      <coordinates>-76.1827075,42.9203392,2
</coordinates>
    </Point>
  </Placemark>
  <Placemark>
    <name>WPs</name>
    <Style id="yellowLineGreenPoly">
      <LineStyle>
        <color>ff00ffff</color>
        <width>4</width>
      </LineStyle>
    </Style>
    <LineString>
      <extrude>false</extrude>
      <tessellate>true</tessellate>
      <altitudeMode>absolute</altitudeMode>
      <coordinates>-76.1826995015144,42.9201978003155,186.705815115468
-76.1827075,42.9203392,2
</coordinates>
    </LineString>
  </Placemark>
  <Placemark>
    <name>onground</name>
    <Style id="yellowLineGreenPoly">
      <LineStyle>
        <color>7f00ffff</color>
        <width>4</width>
      </LineStyle>
    </Style>
    <LineString>
      <extrude>false</extrude>
      <tessellate>true</tessellate>
      <altitudeMode>clampToGround</altitudeMode>
      <coordinates>-76.1826995015144,42.9201978003155,186.705815115468
-76.1827075,42.9203392,2
</coordinates>
    </LineString>
  </Placemark>
</Document>

Also, I've tried the native XmlListModel approach to query the coordinates, but XmlListModel in QML can't handle UTF-16 XML and the server encodes the KML in UTF-16. 

 

0 Kudos
LucasDanzinger
Esri Frequent Contributor

That makes sense to me that it is printing out that you have a list of Objects. Instead of printing that out, you will need to loop through all the root nodes and check the node type

0 Kudos
SasiPrabhakaran
Emerging Contributor

Can I loop through the Objects using keys or values or entries? 

console.log(kmlDataset.rootNodes.hasOwnProperty()) returns False and
console.log(JSON.stringify(kmlDataset.rootNodes)) crashes the program!
0 Kudos
LucasDanzinger
Esri Frequent Contributor

It's not a map (key/value) but a regular list of KmlNodes. Stringifying anything but a JSON object (which this is not) will have adverse effects.

For example:

for (var i = 0; i < kmlDataset.rootNodes.length; i++) {

    var node = kmlDataset.rootNodes;

    if (node.kmlNodeType === Enums.KmlNodeTypeKmlPlacemark) {

        console.log(JSON.stringify(node.geometry.json));

    ....

0 Kudos
SasiPrabhakaran
Emerging Contributor

Length of the rootNodes object is one! (kmlDataset.rootNodes.length=1) and all my attempts to identify the KmlNodeType returned as "undefined".

0 Kudos