5

Is there a method to return the length of a Cesium JS polyline, in real-world units?

For example, if I create a polyline:

var orangeOutlined = viewer.entities.add({
        name : 'Orange line with black outline at height and following the surface',
        polyline : {
            positions : Cesium.Cartesian3.fromDegreesArray([-104.606667,50.454722,
                                                        15.71666666, 69.1 ]),
            width : 5,
            material : new Cesium.PolylineOutlineMaterialProperty({
                color : Cesium.Color.ORANGE,
                outlineWidth : 2,
                outlineColor : Cesium.Color.BLACK
            })
        }
    });

... is there a method to return the length of that line, like:

console.log(orangeOutlined.length)
4

So, there is a Cartesian3.distance function, however, the answer here is not as simple as just calling this on all the pairs of points in positions.

The problem is the line in your example has significant Earth curvature showing, and simply calling distance will get a straight-line geometric distance, cutting through the Earth's crust to get where it's going. Clearly the line showing on the Cesium globe doesn't do this, so, we need to reach into the guts of Cesium a bit to get all the intermediate points along this line. These intermediate points add to the polyline's total length by following the curvature of the Earth's surface.

But first, extract a variable for your positions:

var positions = Cesium.Cartesian3.fromDegreesArray([
    -104.606667,50.454722,
    15.71666666, 69.1 ]);

(or, alternately, var positions = orangeOutlined.polyline.positions.getValue(); which is the same thing in this case)

Next, call PolylinePipeline.generateArc to generate the intermediate points from these positions. Note this whole class is marked @private which means the API is subject to change between versions without notice, but there's no other way to get to this helper function.

var surfacePositions = Cesium.PolylinePipeline.generateArc({
    positions: positions
});

The return value here is a flat array of raw Cartesian values, not Cartesian3 objects. We sum up the distances between adjacent pairs, like so:

var scratchCartesian3 = new Cesium.Cartesian3();
var surfacePositionsLength = surfacePositions.length;
var totalDistanceInMeters = 0;
for (var i = 3; i < surfacePositionsLength; i += 3) {
    scratchCartesian3.x = surfacePositions[i] - surfacePositions[i - 3];
    scratchCartesian3.y = surfacePositions[i + 1] - surfacePositions[i - 2];
    scratchCartesian3.z = surfacePositions[i + 2] - surfacePositions[i - 1];
    totalDistanceInMeters += Cesium.Cartesian3.magnitude(scratchCartesian3);
}

Finally, we can display the distance.

var totalDistanceInKm = totalDistanceInMeters * 0.001;
console.log('Distance: ' + totalDistanceInKm + ' km');

For this sample line, I get a reported distance of 5881.7 km. The Google Maps measure tool reports 5,862 km for a similar measurement, so this seems like a good sanity check that the method described here works.

  • Thanks, worked like a charm. I'm still figuring out the Cesium documentation system. Do you know if there is any documentation re: PolylinePipeline or is it omitted by virtue of being @private? – phloem Jan 3 '16 at 21:50
  • Yes, like all Cesium docs, the PolylinePipeline.generateArc documentation originates here in the source code, however, the @private keyword at the top of the class does mean the whole class is officially declared private, and thus no documentation is generated for any member of this class. The output of this particular helper is more suited to the rendering engine than the public API, but the above solution works around that. – emackey Jan 3 '16 at 23:40
  • is this still the best way to do this? – kujosHeist Apr 20 '17 at 20:00
  • 1
    @kujosHeist Actually, although Kaji's answer initially attracted down-votes for being too short, it's correct and it uses public Cesium API that I wasn't familiar with when I first wrote this. So yes, use surfaceDistance for this. – emackey Apr 20 '17 at 20:36
5

You could use Cesium.EllipsoidGeodesic#surfaceDistance to calculate the distance in meters, and then convert to kilometers.

var startCartesian3Point = Cesium.Cartesian3.fromDegrees(48.862165, 2.305189);
var endCartesian3Point = Cesium.Cartesian3.fromDegrees(45.755675, 4.822185);

var startCartographicPoint = Cesium.Cartographic.fromCartesian(startCartesian3Point);
var endCartographicPoint = Cesium.Cartographic.fromCartesian(endCartesian3Point);

var ellipsoidGeodesic = new Cesium.EllipsoidGeodesic(startCartographicPoint,
    endCartographicPoint );
var distance = ellipsoidGeodesic.surfaceDistance;
var distanceInKm = distance * 0.001;

console.log('Geodesic distance: ' + distanceInKm + ' Km');

We're looking for long answers that provide some explanation and context. Don't just give a one-line answer; explain why your answer is right, ideally with citations. Answers that don't include explanations may be removed.

  • User tinlyx explain me why EllipsoidGeodesic#surfaceDistance is not a useful method because i intend to use it @tinlyx – Kaji Apr 15 '17 at 9:30
  • I didn't down-vote your answer as I am not an expert in Cesium. I only edited it to improve (hopefully) the formatting of the method you speak of. – tinlyx Apr 15 '17 at 9:33
  • sorry user tinlyx – Kaji Apr 15 '17 at 9:44
  • You might want to consider explaining your answer briefly, or add citation/quote a creditable source, even if your answer is correct or useful. It may not be obvious to others. – tinlyx Apr 15 '17 at 9:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.