Polyline drapes over terrain. HOW TO (ORIGINAL)

I've just started learning Cesium API.

My problem is: I want to reach visual effect like when polyline drapes over terrain. I have lng lat input points to draw polyline.

When I switch to STK World Terrain Meshes view layer my polyline is buried under the ground at some locations. It's obvious if I don't specify any heights.

I try to use sampleTerrain (with level 9 as in the API example) method, it renders better but still my polyline is buried at some locations.

Can you give me some detailed instructions on how to reach drape effect like in the image link attached:

How to get camera current tile level of detail (in the API example it hardcoded with 9)?

Should I redraw my polyline on each came zoom in event and how to do it (as currently I set my polyline once at creation point) ?

What interpolation algorithm is better to use to get intermediate polyline points(as got a few only) and thus to drape my polyline smoothly ?

Can I achieve the same smooth drape effect with PolylineVolume (shape - tube(compute circle) as in the API example) ?

Please see image link attached. This image illustrates what exactly I want to achieve.

Best regards

Here what I got at the moment

Copy/paste code below into Cesium/Sandcastle editor and run:

var cesiumViewer = new Cesium.Viewer('cesiumContainer',
{
    terrainProvider: new Cesium.CesiumTerrainProvider({ url: '//assets.agi.com/stk-terrain/world' })
    , baseLayerPicker: false
});
drawPolylineOnTerrain();
function drawPolylineOnTerrain() {
    var polylinePoints =
    [
        {lng:150.644, lat:-34.397},
        {lng:150.644, lat:-35.397},
        {lng:156.644, lat:-35.397},
        {lng:156.644, lat:-36.397},
        {lng:158.644, lat:-37.397},
        {lng:160.644, lat:-39.397}
    ];
    var polylinePointsExtended = extendWithIntermediatePoints(polylinePoints);

    Cesium.when(Cesium.sampleTerrain(cesiumViewer.terrainProvider, 9, polylinePointsExtended), sampleTerrainSuccess);
}
function extendWithIntermediatePoints(polylinePoints) {
    var extendedPoints = ;
    var previousPoint = polylinePoints[0];
    extendedPoints.push(Cesium.Cartographic.fromDegrees(previousPoint.lng, previousPoint.lat));
    var minDistance = 0.001;
    for (var i = 1; i < polylinePoints.length; i++) {
        var current = polylinePoints[i];
        var lngDiff = current.lng - previousPoint.lng;
        var latDiff = current.lat - previousPoint.lat;

        var max = Math.max(Math.abs(lngDiff), Math.abs(latDiff));

        var pointCount = parseInt(max / minDistance, 10);
        var lngIncrement = lngDiff / (pointCount ? pointCount : 1);
        var latIncrement = latDiff / (pointCount ? pointCount : 1);

        var count = 1;
        while (count <= pointCount) {
            extendedPoints.push(Cesium.Cartographic.fromDegrees(previousPoint.lng + count * lngIncrement, previousPoint.lat + count * latIncrement));
            count++;
        }
        extendedPoints.push(Cesium.Cartographic.fromDegrees(current.lng, current.lat));
        previousPoint = current;
    }

    return extendedPoints;
}
function sampleTerrainSuccess(sampleTerrainPoints) {
        var updatedPolyLinePoints = ;
        for (var i = 0; i < sampleTerrainPoints.length; ++i) {
            var updatedPoint = sampleTerrainPoints[i];
            updatedPolyLinePoints.push(Cesium.Math.toDegrees(updatedPoint.longitude), Cesium.Math.toDegrees(updatedPoint.latitude), updatedPoint.height);
        }
        function computeCircle(radius) {
            var positions = ;
            for (var i = 0; i < 360; i++) {
                var radians = Cesium.Math.toRadians(i);
                positions.push(new Cesium.Cartesian2(radius * Math.cos(radians), radius * Math.sin(radians)));
            }
            return positions;
        }
        cesiumViewer.entities.add({
            //polylineVolume:
            polyline: {
                positions: Cesium.Cartesian3.fromDegreesArrayHeights(updatedPolyLinePoints),
                //shape :computeCircle(1000),
                width:5,
                material: Cesium.Color.BLACK
            }
        });
        cesiumViewer.zoomTo(cesiumViewer.entities);
}

Sorry I forgot one detail.

If I use polylineVolume the polyline is not rendered at all

Polylines on terrain are actually really complicated and something that needs to be handled at the shader/GPU level to be done properly. It is being actively worked and will be available out-of-the-box in Cesium within the next few months. So unfortunately, there’s currently no good solution built into Cesium for doing what you want. Sampling can provide an interim solution, but as you already found out depending on what zoom level you sample at you may still have issues in other zoom levels.

I’m sorry I don’t have a better answer for you; but like I said, in a few months this will all be built in functionality that you can just enable (and will eventually be enabled by default. The same goes for polygons,billboards, points, labels, and models.

PolylineVolume is quite a bit different and we’re not sure what options will be available there yet.

The only heights that need to be measured are where the line crosses over a triangle edge from the Bird’s eye view (where z is ignored.)

So there should be a function where the inputs are:

-Point A

-Point B

-a tile (at a certain LOD)

And the outputs are are series of points in which the line from PointA to PointB crosses triangle edges of the tile mesh.

How the function should function:

A brute force and extremely inefficient method would be to do intersection tests with every triangle edge with the line from PointA to PointB.

A more efficient method would involve a ‘triangle interconnection system’. With this ‘triangle interconnection system’ when you hit a triangle edge you already know what 2 triangles use this triangle edge. So all you have test against are the remaining triangle edges of those 2 triangles, that’s only 4 edges. If you also know what direction the line is traveling that’s only 2 edges!

Currently terrain triangles are defined by vertices directly

https://cesiumjs.org/data-and-assets/terrain/formats/quantized-mesh-1.0.html

If instead triangles were defined by edges, and edges were defined by vertices a ‘triangle interconnection system’ would be easy to create. The memory for each tile would be slightly increased, but it would make polyline draping easier. I suppose one could generate a ‘triangle interconnection system’ from the current mesh system, but it might take a lot of run time processing.

Correspondence lists for quick lookup (either stored or generated at run time)

-A list for each edge showing which 2 triangles they belong to

-A list for each verticie showing which edges and/or triangles they belong to (can be quite a few)

If the line crosses directly over a verticie you’d check each edge that connects to it, then what triangles belong to those edges.

Hello guys.

I found that as of 1.13 version the ground primitive stuff was added.

Any plans in the future releases to add ground polyline that drapes over the terrain ?

Thank you.

Hello,

We plan on adding polylines on terrain, but there is a lot of research that needs to be done to figure out the best way to implement this. You can watch this issue for progress: https://github.com/AnalyticalGraphicsInc/cesium/issues/2172

-Hannah

Would PointPrimitives on the ground also likely come at the same time?

Hi,

Instead of using point primitives, you can clamp billboards to terrain today. In the future, Cesium may support point primitives on terrain, but we are still thinking through it since it adds a fair amount of per-point overhead, and the point primitive is designed to be lightweight.

Patrick

Hi Folks:

Are there any updates on supporting polylines in GroundPrimitieves so that I can ‘drape’ a track over the terrain? I have tried CorridorGeometry and it works, but it is not exactly what I am looking for due to the fact that the corridor width scales with the zoom (as it is supposed to do). Draping a polyline would be more appropriate for my application (rikitraki.com).

Thank you,

Ricardo

Hi Ricardo,

No update yet, but I suspect we will start on something soon-ish as this is high on our list for 3D Tiles, and the current styling work is starting to take shape.

In the meantime, you could try a few different corridors with different widths, and then showing/hiding them based on the view distance or viewer altitude.

Patrick

Hi,
I believe polyline clamped to ground is available in build 1.23.
Any sample for this?
Thanks.
S

Hello,

We unfortunately do not yet have support for polylines on terrain. We recently added support for many other geometry types, but we have to do a bit more research to figure out the best way to get polylines on terrain as well.

Best,

Hannah

Hello Hannah,
Thanks always for the quick reply, I guess I am left with breaking line into segments and calculating heights of each endpoints using sampleTerrain ?

Best Regards,
S

Hello

Has there been any progress for polyline clamp to ground ?

Or are there any other known workarounds for creating a path that doesn't drift when navigating the map ?

Thanks

Tim

Hi Tim,

If you're OK with the polyline width being defined in meters, not pixels,
and you don't have a ton of polylines, try using a CorridorGeometry with
the GroundPrimitive.

Patrick

Hi Patrick

Thanks for your feedback.

Using CorridorGeometry may be beyond my capabilities.

As I’ve understood it CorridorGeometry scales with zoom, which I wouldn’t want all the time since the polyline is being used to display a route path along roads.

Or perhaps there is an example of how to control the CorridorGeometry through zooms ?

The other thing though is that presumably the polygon count is going to jump greatly if a route following roads around the road switches from a stroked polyline to a potential 8 polys per waypoint when using CorridorGeometry.

Tim

Hi Tim,

Sorry, there isn’t an easy way to make the CorridorGeometry resize as the camera zooms the way the polyline does.

-Hannah

Hi Hannah,

Thanks for your input.

Seems there is no rock solid solution/workaround to clamping a route/path along roads that behaves in the way we have all come to expect of route maps then.

Feeling a bit stuck and not sure if you guys have a concrete timeline on when to introduce clamp to ground for polylines.

Does this issue have a low priority compared to other milestone tasks ?

I wish there was something I could do to help. Is there any reading material on this specific subject ?

Tim :slight_smile:

This is something that is also stopping my team from being able to utilise 3D terrain. Everything we have works on terrain except polylines, which unfortunately is core functionality for our web app.

We just need to be able to draw polylines between two billboard entities that have been clamped to ground. The lines themselves only need to be clamped on either side, and then 'connect' the two entities that are clamped to ground. Unfortunately there is no way to get the 'clamped' height of the entities, otherwise i'd just reference that in the line position callback.

I too am interested in if there is a way I could help you guys to implement this functionality.