Cesium贴地车俯仰角跟随地形且动态贴地线

1 实现要求

  • 1 地面车辆按照规定的起点和终点运行
  • 2 地面车辆必须贴地运动
  • 3 地面车辆的必须有俯仰角的变化
  • 4 循环播放,且车辆经过路径动态高亮,下一次循环清除高亮

2 实现效果

在这里插入图片描述

3 实现代码

将如下代码替换到cesium的一个例子中即可:https://sandcastle.cesium.com/index.html?src=Interpolation.html

	var viewer = new Cesium.Viewer("cesiumContainer", {
    
    
    infoBox: false, //Disable InfoBox widget
    selectionIndicator: false, //Disable selection indicator
    shouldAnimate: true, // Enable animations
    terrainProvider: Cesium.createWorldTerrain(),
});

//Enable lighting based on the sun position
viewer.scene.globe.enableLighting = true;

//Enable depth testing so things behind the terrain disappear.
viewer.scene.globe.depthTestAgainstTerrain = true;

//Set the random number seed for consistent results.
Cesium.Math.setRandomNumberSeed(3);

let times = [
    Cesium.JulianDate.fromIso8601("2018-07-19T15:18:00Z"),
    Cesium.JulianDate.fromIso8601("2018-07-19T15:24:00Z")
];
let stTime = times[0];
let endTime = times[1];
var start = stTime.clone();
var stop = endTime.clone();

//Make sure viewer is at the desired time.
viewer.clock.startTime = start.clone();
viewer.clock.stopTime = stop.clone();
viewer.clock.currentTime = start.clone();
viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP; //Loop at the end
viewer.clock.multiplier = 30;

//Set timeline to simulation bounds
viewer.timeline.zoomTo(start, stop);

//Generate a random circular pattern with varying heights.
function computeCirclularFlight(lon, lat, radius) {
    
    
    var property = new Cesium.SampledPositionProperty();
    for (var i = 0; i <= 360; i += 45) {
    
    
        var radians = Cesium.Math.toRadians(i);
        var time = Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());
        var position = Cesium.Cartesian3.fromDegrees(
            lon + radius * 1.5 * Math.cos(radians),
            lat + radius * Math.sin(radians),
            Cesium.Math.nextRandomNumber() * 500 + 1750
        );
        property.addSample(time, position);
        console.log(time.toString(), " -> ", position.toString());

        //Also create a point for each sample we generate.
        viewer.entities.add({
    
    
            position: position,
            point: {
    
    
                pixelSize: 8,
                color: Cesium.Color.TRANSPARENT,
                outlineColor: Cesium.Color.YELLOW,
                outlineWidth: 3,
            },
        });
    }
    return property;
}

let positions = [
    // new Cartesian3(1216348.1632364073, -4736348.958775471, 4081284.5528982095),
    // new Cartesian3(1216369.1229444197, -4736377.467107148, 4081240.888485707)
    new Cesium.Cartesian3(
        -2358138.847340281,
        -3744072.459541374,
        4581158.5714175375
    ),
    new Cesium.Cartesian3(
        -2357231.4925370603,
        -3745103.7886602185,
        4580702.9757762635
    ),
];
let stPos = positions[0];
let endPos = positions[1];

// sampled postion's time resolution
let timeOfResolution = 6;

// using sampled property to get sampled data
let oriSamples = new Cesium.SampledProperty(Cesium.Cartesian3);
oriSamples.addSamples(times, positions);

// get sampled data, ervery "distanceOfResolution" we take a sample
let geodesic = new Cesium.EllipsoidGeodesic(
    Cesium.Cartographic.fromCartesian(stPos),
    Cesium.Cartographic.fromCartesian(endPos)
);
let lenInMeters = Math.ceil(geodesic.surfaceDistance); // avoid overflow when take samples
let samplesNum = Math.floor(
    Cesium.JulianDate.secondsDifference(endTime, stTime) / timeOfResolution
);
//let secondsInterval = Math.floor(Cesium.JulianDate.secondsDifference(endTime, stTime) / samplesNum);
console.log(
    "len: ",
    lenInMeters,
    "samplesNum",
    samplesNum,
    "secondsInterval",
    timeOfResolution
);

// get sampled data, ervery "timeOfResolution" passed, we take a sample
let sampledPositions = [];
let sampledTimes = [];
for (let i = 0; i < samplesNum + 1; i++) {
    
    
    let sampleTime = Cesium.JulianDate.addSeconds(
        stTime,
        i * timeOfResolution,
        new Cesium.JulianDate()
    );
    let tmpPos = oriSamples.getValue(sampleTime);
    console.log(sampleTime.toString(), " -> || -> ", tmpPos.toString());
    sampledPositions.push(Cesium.Cartographic.fromCartesian(tmpPos));
    sampledTimes.push(sampleTime);
}

let promise = Cesium.sampleTerrainMostDetailed(
    viewer.terrainProvider,
    sampledPositions
).then(() => {
    
    
    console.log(
        "start adding!",
        "time and pos size: ",
        sampledTimes.length,
        sampledPositions.length
    );

    let carPositionProperty = new Cesium.SampledPositionProperty();

    // add positions which are clamped to ground to the carPositionProperty
    for (let i = 0; i < samplesNum + 1; i++) {
    
    
        carPositionProperty.addSample(
            sampledTimes[i],
            // new Cesium.Cartesian3.fromDegrees( // this way of changing pos is not right, all should be under WGS84
            // sampledPositions[i].longitude,
            // sampledPositions[i].latitude,
            // sampledPositions[i].height));
            Cesium.Ellipsoid.WGS84.cartographicToCartesian(sampledPositions[i])
        );
        // console.log(sampledTimes[i], " ------->>> ", sampledPositions[i]);
    }

    // after the clamped to ground data computed, dynamically show the path
    let isConstant = false;
    let curSegmentNo = 0; // the polyLine are divided into samplesNum's segements
    let lastSegementNo = -1;
    let p2 = Cesium.Ellipsoid.WGS84.cartographicToCartesian(sampledPositions[1]);
    let curPolyline = [stPos]; // represent the polyline
    console.log("init 2 points are: ", stPos.toString(), " ", p2.toString());
    //let timeNow = Cesium.JulianDate.now().clone();

    console.log("starting add entity");
    viewer.entities.add({
    
    
        polyline: {
    
    
            // This callback updates positions each frame.
            // Ellipsoid.WGS84.cartographicArrayToCartesianArray(sampledPositions),
            positions: new Cesium.CallbackProperty(function (time, result) {
    
    
                //console.log("len: ", lenInMeters, "samplesNum", samplesNum, "timeOfResolution", timeOfResolution);

                //let st
                curSegmentNo = Math.floor(
                    Cesium.JulianDate.secondsDifference(time, stTime) / timeOfResolution
                );
                console.log(curSegmentNo);
                if (curSegmentNo !== lastSegementNo) {
    
    
                    //console.log("curSegmentNo is: ", curSegmentNo.toString(), "\ncurTime: ", time.toString(), "\nstTime: ", stTime.toString());
                    // tmmP => curPolyine[lastSegementNo+1 : CurSegmentNo]
                    let tmpP = Cesium.Ellipsoid.WGS84.cartographicToCartesian(
                        sampledPositions[curSegmentNo]
                    );
                    //console.log("adding new points: ", tmpP.toString(), "\nsize is:", curPolyline.length);
                    curPolyline.push(tmpP);
                    lastSegementNo = curSegmentNo;
                }
                // if reach the end of sampled positions, clear the polyline's positions
                if (curSegmentNo === samplesNum - 1) {
    
    
                    curSegmentNo = 0;
                    curPolyline = [];
                    console.log("cleared!");
                }

                return curPolyline;
            }, isConstant),
            //clampToGround: true,
            width: 5,
            material: Cesium.Color.RED,
            availability: new Cesium.TimeIntervalCollection([
                new Cesium.TimeInterval({
    
    
                    start: stTime,
                    stop: endTime,
                }),
            ]),
        },
    });
    console.log("end adding polyline");

    //Compute the entity position property.
    //var position = computeCirclularFlight(-112.110693, 36.0994841, 0.03);
    var position = carPositionProperty;
    //Actually create the entity
    var entity = viewer.entities.add({
    
    
        //Set the entity availability to the same interval as the simulation time.
        availability: new Cesium.TimeIntervalCollection([
            new Cesium.TimeInterval({
    
    
                start: start,
                stop: stop,
            }),
        ]),

        //Use our computed positions
        position: position,

        //Automatically compute orientation based on position movement.
        orientation: new Cesium.VelocityOrientationProperty(position),

        //Load the Cesium plane model to represent the entity
        model: {
    
    
            uri: "../SampleData/models/CesiumAir/Cesium_Air.glb",
            minimumPixelSize: 64,
        },

        //Show the path as a pink line sampled in 1 second increments.
        path: {
    
    
            resolution: 1,
            material: new Cesium.PolylineGlowMaterialProperty({
    
    
                glowPower: 0.1,
                color: Cesium.Color.YELLOW,
            }),
            width: 1,
        },
    });

    //Add button to view the path from the top down
    Sandcastle.addDefaultToolbarButton("View Top Down", function () {
    
    
        viewer.trackedEntity = undefined;
        viewer.zoomTo(
            viewer.entities,
            new Cesium.HeadingPitchRange(0, Cesium.Math.toRadians(-90))
        );
    });

    //Add button to view the path from the side
    Sandcastle.addToolbarButton("View Side", function () {
    
    
        viewer.trackedEntity = undefined;
        viewer.zoomTo(
            viewer.entities,
            new Cesium.HeadingPitchRange(
                Cesium.Math.toRadians(-90),
                Cesium.Math.toRadians(-15),
                7500
            )
        );
    });

    //Add button to track the entity as it moves
    Sandcastle.addToolbarButton("View Aircraft", function () {
    
    
        // viewer.trackedEntity = entity;
        viewer.zoomTo(
            viewer.entities,
            new Cesium.HeadingPitchRange(
                Cesium.Math.toRadians(15),
                Cesium.Math.toRadians(-45),
                2500
            )
        );
    });

    //Add a combo box for selecting each interpolation mode.
    Sandcastle.addToolbarMenu(
        [
            {
    
    
                text: "Interpolation: Linear Approximation",
                onselect: function () {
    
    
                    entity.position.setInterpolationOptions({
    
    
                        interpolationDegree: 1,
                        interpolationAlgorithm: Cesium.LinearApproximation,
                    });
                },
            },
            {
    
    
                text: "Interpolation: Lagrange Polynomial Approximation",
                onselect: function () {
    
    
                    entity.position.setInterpolationOptions({
    
    
                        interpolationDegree: 5,
                        interpolationAlgorithm: Cesium.LagrangePolynomialApproximation,
                    });
                },
            },
            {
    
    
                text: "Interpolation: Hermite Polynomial Approximation",
                onselect: function () {
    
    
                    entity.position.setInterpolationOptions({
    
    
                        interpolationDegree: 2,
                        interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
                    });
                },
            },
        ],
        "interpolationMenu"
    );
});

4 参考

Guess you like

Origin blog.csdn.net/cxy_hust/article/details/112398913