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"
);
});