Search code examples
javascriptkmlcesiumjs

Cesium get coordinates from Entity loaded from KML


I am trying to draw an arrowhead for each point in a kml file. For this I plan to fetch coordinates for each point by getById. So far I am getting an error:

Uncaught TypeError: Cannot read property 'position' of undefined (on line 14)

Here is my code:

var src = Cesium.KmlDataSource.load('../../My_KML/plots.kml', options);
viewer.dataSources.add(src).then(function(data) {viewer.flyTo(data);});

//-------------------********--------------**********-----------------//
var point = viewer.entities.getById('geom_20102');

var entities = viewer.entities;

 var cartographicPosition = Cesium.Cartographic.fromCartesian(point.position.getValue(Cesium.JulianDate.now()));
            var latitude = Cesium.Math.toDegrees(cartographicPosition.latitude);
            var longitude = Cesium.Math.toDegrees(cartographicPosition.longitude);

var line1 = entities.add({
    polyline : {
        positions : Cesium.Cartesian3.fromDegreesArrayHeights([longitude, latitude, 360, longitude + 1, latitude + 1, 400]),
        width : 10,
        followSurface : false,
        material : new Cesium.PolylineArrowMaterialProperty(Cesium.Color.BLUE)
    }
});

I have specified the element with id 'geom_20102' as a linestring wrapped around by a placemark in the kml. Also I would like to know which id to specify as both placemark and linestring have an id. Or am I confusing kml id with entity id?

I am new to Cesium.Js and I followed this example partially: Cesium Workshop

KML snippet:

 <Placemark id="feat_20125">
        <name>874</name>
        <styleUrl>#stylesel_20102</styleUrl>
        <LineString id="geom_20102">
            <coordinates>104.99108,10.4118,247.3 72.991075,26.25412,247.6</coordinates>
            <altitudeMode>relativeToGround</altitudeMode>
        </LineString>
    </Placemark>

Solution

  • Two things are going on here.

    First, the Cesium.KmlDataSource.load() function returns a JavaScript "Promise" which represents the eventual completion (or failure) of an asynchronous operation. At the time the viewer.entities is referenced in the code, the KML file has not yet loaded so the collection in viewer.entities is empty and calling getById() on it will return undefined. You should only access the viewer.entities or data.entities after the async Promise is completed and the "then" callback is invoked. Only at that time are the entities populated.

    var src = Cesium.KmlDataSource.load('../../My_KML/plots.kml', options);
    viewer.dataSources.add(src).then(function(data) {
        
        var entities = data.entities;
        console.log("f=" + entities.getById('feat_20125')); // f=[object Object]
        console.log("g=" + entities.getById('geom_20102')); // undefined
    
        viewer.flyTo(data);
    });
    

    Next, notice that the 'feat_20125' returns an object but the 'geom_20102' is not found. Only the "id" on the placemarks are populated when KML is converted into Cesium entities. Ids on any other KML element are discarded.