SampledPositionProperty with NaN

Afternoon Cesium folks,

I have been struggling with a problem in my code that caused this vague “you did something bad” kind of error.

I was using the SampledPositionProperty to draw a path along with some objects in the viewer. I had no problem drawing one Entity, but any more and ku-boom. I feared a race condition or a threading problem and started instrumenting my code for deep debugging. A couple of days later I still had no smoking gun.

To make a long story short, the below code reproduces my error. If you run this in a browser and comment out the second “entityTilted” entity, then hit fast-forward, everything works as expected. Now, uncomment that second entity, refresh your browser and FF again. Splat.

Maybe this is a Cesium bug, I don’t know how you would classify it, the SampledPositionProperty does have Number.NaNs in it.

But if it works for one entity?

<!DOCTYPE html>
<html>
<head>
    <title>Satellite.js Example</title>
    <script src="https://cesium.com/downloads/cesiumjs/releases/1.117/Build/Cesium/Cesium.js"></script>
    <link href="https://cesium.com/downloads/cesiumjs/releases/1.117/Build/Cesium/Widgets/widgets.css" rel="stylesheet">
</head>
<body>

    <div id="cesiumContainer" style="width:100%; height:100%; position:absolute; top:0; left:0;"></div>
    <script type="module">
    // Your access token can be found at: https://cesium.com/ion/tokens.
    // This is the default access token from the Sandcastle example and is limited to use on localhost.
    // If you're deploying your app to other hosts, you'll need to get your own access token.
    Cesium.Ion.defaultAccessToken = '';
    let positionAndVelocityArray = [];
    // Initialize the Cesium Viewer in the HTML element with the `cesiumContainer` ID.
    const viewer = new Cesium.Viewer('cesiumContainer', {
        terrain: Cesium.Terrain.fromWorldTerrain(),
    });

    const totalSecs = 86400; // seconds in a day
    const timeStep = 120;    // steps between propagations

    let positionsOverTime = new Cesium.SampledPositionProperty(Cesium.ReferenceFrame.FIXED);
    positionsOverTime.setInterpolationOptions({
        interpolationDegree: 5,
        interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
    }); 
    let positionsOverTimeTilted = new Cesium.SampledPositionProperty(Cesium.ReferenceFrame.FIXED);
    positionsOverTimeTilted.setInterpolationOptions({
        interpolationDegree: 5,
        interpolationAlgorithm: Cesium.HermitePolynomialApproximation,
    }); 
    const now = viewer.clock.currentTime;
    const start = Cesium.JulianDate.addHours(now, -12, new Cesium.JulianDate());
    const stop = Cesium.JulianDate.addHours(now, 12, new Cesium.JulianDate());

    const earthRadius = 6371.0; // Earth's radius in kilometers
    const altitude = 1000 * 1.60934; // Convert miles to kilometers
    const totalRadius = earthRadius + altitude; // Total radius in kilometers
    let numElem = 0;
    for (let i = 0; i < totalSecs; i += timeStep) {
        numElem++;
        const time = Cesium.JulianDate.addSeconds(start, i, new Cesium.JulianDate());
        const jsDate = Cesium.JulianDate.toDate(time);

        // Calculate the current latitude in radians
        const latitude = (i / totalSecs) * 2 * Math.PI - Math.PI / 2;

        // Calculate the position values
        let x, y, z;
        if (i >= 40 * timeStep && i <= 55 * timeStep) {
            x = Number.NaN;
            y = Number.NaN;
            z = Number.NaN;
        } else {
            x = 0; // The x value is 0 because the line is on the Z axis
            y = 0; // The y value is 0 because the line is on the Z axis
            z = totalRadius * Math.sin(latitude);
        }

        const positionAndVelocity = {
            position: [x * 1000, y * 1000, z * 1000], // Convert kilometers to meters
            velocity: [0.1,0.7,-0.9],
        }

        const posECFmeters = new Cesium.Cartesian3(
            positionAndVelocity.position[0],
            positionAndVelocity.position[1],
            positionAndVelocity.position[2]
        );
        const posECFmetersTilted = Cesium.Matrix3.multiplyByVector(Cesium.Matrix3.fromRotationZ(Cesium.Math.toRadians(45)), posECFmeters, new Cesium.Cartesian3());
        positionAndVelocityArray.push(positionAndVelocity);
        positionsOverTime.addSample(time, posECFmeters);
        positionsOverTimeTilted.addSample(time, posECFmetersTilted);
    }

    console.log(`${numElem}: samples loaded.`);
    // Print every positionAndVelocity to the console
    positionAndVelocityArray.forEach((positionAndVelocity, index) => {
        console.log(`positionAndVelocity at index ${index}:`, positionAndVelocity);
    });
    var entity = viewer.entities.add({
        position: positionsOverTime,
        path:{
            resolution: 10,
            width: 10,
            trailTime: 50000,
            leadTime: 50,
            show: true,
        }
    });
    var entityTilted = viewer.entities.add({
        position: positionsOverTimeTilted,
        path:{
            resolution: 10,
            width: 10,
            trailTime: 50000,
            leadTime: 50,
            show: true,
        }
    });
    console.log(Cesium.JulianDate.toDate(start).toString());
    viewer.clock.startTime = start;
    viewer.clock.stopTime = stop;
    viewer.clock.currentTime = start;
    viewer.clock.clockRange = Cesium.ClockRange.LOOP_STOP;
    viewer.clock.multiplier = 60;
    viewer.clock.shouldAnimate = true;

    viewer.timeline.zoomTo(start, stop);
</script>
</body>
</html>