STK to Cesium CZML - View flips when viewing 3d model

1. A concise explanation of the problem you’re experiencing.

When selecting an object, in this case, a 3d model of a satellite, the view/camera flips every second when tracking the satellite

2. A minimal code example. If you’ve found a bug, this helps us reproduce and repair it.

Using this code here, please excuse the mess.

Cesium Demo @import url(../templates/bucket.css);

Loading...

3. Context. Why do you need to do this? We might know a better way to accomplish your goal.

4. The Cesium version you’re using, your operating system and browser.

Version 71.0.3578.98 (Official Build) (64-bit

I am using Cesium 1.42. I’ll update Cesium to latest and see if that solves the issue.

What kind of “flip” does the camera do? Do you have a video/gif of it?

Do update and let me know if it works. Also the STK terrain has been replaced by Cesium ion terrain & imagery, so I think you’ll need to update that as well.

If you can share a Sandcastle (https://cesiumjs.org/Cesium/Build/Apps/Sandcastle/) with me that I can run to reproduce the issue it’ll help me look into it.

Hi Omar,

I am feeding dynamic data that I get from STK and relaying that data to Cesium in the form of CZML packets.

I think I solved it by setting the Orientation epoch to the start time of the STK scenario and then only sending the CZML packet every so often with a use of a counter.

Specifically, I wait for the counter to reach a value of 10 (tried 5 but it was still flipping the camera) and then send the CZML packets. Sorry, forgot to upload the video - please see attached video of the problem.

For more clarity - I am also obtaining the STK current time and feeding that into the CZML packet but I am uncertain about whether to use the current time or the start of the STK scenario for the Orientation, Position, LeadTime, Trailtime Epoch objects in the CZML packet.

For the quaternion and cartesian data time values, I am obtaining the current time of STK and subtracting that from the STK start time to obtain the total seconds.

I feel like my solution is real janky - do you have any thoughts on a better approach?

Thank you for your help!

Test_Copy.mp4 (2.14 MB)

I should probably explain some the architecture involved. I am running the scenario in STK and a C# application to obtain the Quaternion/Cartesian data. The C# application packages the JSON/CZML packet then sends it to the JS/Cesium side.

Omar,

Below is the code on the C# side when I obtain data from STK and package it up CZML style (please excuse the mess):

if (counter == 10)

{

string strSTKTIME = sc.StartTime;

DateTime dtStartTime = DateTime.Parse(strSTKTIME);

TimeSpan totSecs = Current_dt - dtStartTime;

rT = totSecs.TotalSeconds;

Console.WriteLine("Epsec: " + rT.ToString());

// FIRST CZML PACKET

RootObject1 JsonRoot1 = new RootObject1();

JsonRoot1.id = “document”;

JsonRoot1.name = “CesiumTest”;

JsonRoot1.version = “1.0”;

Clock JsonClock = new Clock();

JsonClock.interval = “2018-08-30T18:00:00Z/2018-09-06T18:00:00Z”;

string currTime = “2018-08-30T18:00:00Z”;

//2018-08-30T18:04:18Z

// DEBUG - TEST

//string currTime = “2018-02-01T” + STKtime + “Z”;

//Console.WriteLine(currTime);

//JsonClock.currentTime = DateTime.Parse(currTime);

//JsonClock.currentTime = DateTime.Parse(Ces_dt);

//JsonClock.currentTime = currTime;

JsonClock.currentTime = Ces_dt; // Current Time of STK

JsonClock.multiplier = 5;

JsonClock.range = “LOOP_STOP”;

JsonClock.step = “SYSTEM_CLOCK_MULTIPLIER”;

JsonRoot1.clock = JsonClock;

string dataJSON1 = JsonConvert.SerializeObject(JsonRoot1);

// SECOND CZML PACKET

RootObject JsonRoot = new RootObject();

JsonRoot.id = “Satellite/ButtSat”;

JsonRoot.availability = “2018-08-30T18:00:00Z/2018-09-06T18:00:00Z”;

JsonRoot.name = “ButtSat”;

Orientation JsonOrientation = new Orientation();

JsonOrientation.interpolationAlgorithm = “LINEAR”;

JsonOrientation.interpolationDegree = 1;

string strEpoch = “2018-08-30T18:00:00Z”;

//string strEpoch = Current_dt;

//string strEpoch = currTime;

//DateTime dtEpoch = DateTime.Parse(strEpoch);

//DateTime dtEpoch = Current_dt;

//JsonOrientation.epoch = dtEpoch;

JsonOrientation.epoch = strEpoch;

//JsonOrientation.epoch = Ces_dt;

// SECOND CZML PACKET WITH QUATERNION DATA

List dbQuat = new List();

Console.WriteLine(rT.ToString());

dbQuat.Add(rT);

dbQuat.Add(ATD_QEST_CBI2BDY0);

dbQuat.Add(ATD_QEST_CBI2BDY1);

dbQuat.Add(ATD_QEST_CBI2BDY2);

dbQuat.Add(ATD_QEST_CBI2BDY3);

JsonOrientation.unitQuaternion = dbQuat;

JsonRoot.orientation = JsonOrientation;

// SECOND CZML PACKET WITH POSITION DATA

Position JsonPosition = new Position();

JsonPosition.interpolationAlgorithm = “LAGRANGE”;

JsonPosition.interpolationDegree = 5;

JsonPosition.referenceFrame = “INERTIAL”;

//JsonPosition.epoch = dtEpoch;

JsonPosition.epoch = Ces_dt;

//JsonPosition.epoch = strEpoch;

List dbPos = new List();

dbPos.Add(rT);

dbPos.Add(EPH_POS_CBIX);

dbPos.Add(EPH_POS_CBIY);

dbPos.Add(EPH_POS_CBIZ);

JsonPosition.cartesian = dbPos;

JsonRoot.position = JsonPosition;

// SECOND CZML PACKET WITH SHOW DATA

SOLIS_CMD_TLM.Show JsonShow = new SOLIS_CMD_TLM.Show();

JsonShow.interval = “2018-08-30T18:00:00Z/2018-09-06T18:00:00Z”;

JsonShow.boolean = true;

// SECOND CZML PACKET WITH LEADTIME DATA

SOLIS_CMD_TLM.LeadTime JsonLeadTime = new SOLIS_CMD_TLM.LeadTime();

JsonLeadTime.interval = “2018-08-30T18:00:00Z/2018-09-06T18:00:00Z”;

//JsonLeadTime.epoch = dtEpoch;

//JsonLeadTime.epoch = strEpoch;

JsonLeadTime.epoch = Ces_dt;

List dbNumber = new List();

//dbNumber.Add(0);

////dbNumber.Add(5669.061404426997);

////dbNumber.Add(5669.061404426997);

//dbNumber.Add(0);

//dbNumber.Add(0);

//dbNumber.Add(0);

//dbNumber.Add(0);

//dbNumber.Add(604800);

//dbNumber.Add(604800);

//dbNumber.Add(0);

dbNumber.Add(0);

dbNumber.Add(0);

dbNumber.Add(0);

dbNumber.Add(0);

JsonLeadTime.number = dbNumber;

// SECOND CZML PACKET WITH TRAILTIME DATA

SOLIS_CMD_TLM.TrailTime JsonTrailTime = new SOLIS_CMD_TLM.TrailTime();

JsonTrailTime.interval = “2018-08-30T18:00:00Z/2018-09-06T18:00:00Z”;

//JsonTrailTime.epoch = dtEpoch;

//JsonTrailTime.epoch = strEpoch;

JsonTrailTime.epoch = Ces_dt;

List dbNumber1 = new List();

//dbNumber1.Add(0);

////dbNumber1.Add(5669.061404426997);

////dbNumber1.Add(5669.061404426997);

//dbNumber1.Add(0);

//dbNumber1.Add(0);

//dbNumber1.Add(0);

//dbNumber.Add(0);

//dbNumber.Add(0);

//dbNumber.Add(604800);

//dbNumber.Add(604800);

dbNumber.Add(0);

dbNumber.Add(0);

dbNumber.Add(0);

dbNumber.Add(0);

JsonTrailTime.number = dbNumber1;

// SECOND CZML PACKET WITH COLOR2 DATA

SOLIS_CMD_TLM.Color2 JsonColor2 = new SOLIS_CMD_TLM.Color2();

List lstRGBA = new List();

lstRGBA.Add(0);

lstRGBA.Add(255);

lstRGBA.Add(255);

lstRGBA.Add(255);

JsonColor2.rgba = lstRGBA;

// SECOND CZML PACKET WITH SOLID COLOR DATA

SOLIS_CMD_TLM.SolidColor JsonSolidColor = new SOLIS_CMD_TLM.SolidColor();

JsonSolidColor.color = JsonColor2;

// SECOND CZML PACKET WITH MATERIAL DATA

SOLIS_CMD_TLM.Material JsonMaterial = new SOLIS_CMD_TLM.Material();

JsonMaterial.solidColor = JsonSolidColor;

// SECOND CZML PACKET WITH PATH DATA

SOLIS_CMD_TLM.Path JsonPath = new SOLIS_CMD_TLM.Path();

List lstShow = new List();

lstShow.Add(JsonShow);

JsonPath.show = lstShow;

JsonPath.width = 1;

JsonPath.material = JsonMaterial;

//JsonPath.resolution = 1200;

JsonPath.resolution = 10;

List lstLeadTime = new List();

lstLeadTime.Add(JsonLeadTime);

List lstTrailTime = new List();

lstTrailTime.Add(JsonTrailTime);

JsonPath.leadTime = lstLeadTime;

JsonPath.trailTime = lstTrailTime;

// MODEL DATA

SOLIS_CMD_TLM.Model JsonModel = new SOLIS_CMD_TLM.Model();

JsonModel.gltf = “https://assets.agi.com/models/ikonos.gltf”;

//JsonModel.gltf = “…/…/SampleData/models/CesiumSpace/ikonos.gltf”;

JsonModel.scale = 1;

JsonModel.runAnimations = false;

JsonModel.show = true;

// COLOR DATA

SOLIS_CMD_TLM.Color JsonColor = new SOLIS_CMD_TLM.Color();

List lstRGBA1 = new List();

lstRGBA1.Add(255);

lstRGBA1.Add(0);

lstRGBA1.Add(0);

lstRGBA1.Add(255);

JsonColor.rgba = lstRGBA1;

// EYEOFFSET DATA

SOLIS_CMD_TLM.EyeOffset JsonEyeOffset = new SOLIS_CMD_TLM.EyeOffset();

List lstCartesian = new List();

lstCartesian.Add(0);

lstCartesian.Add(0);

lstCartesian.Add(0);

JsonEyeOffset.cartesian = lstCartesian;

// PIXEL OFFSET

SOLIS_CMD_TLM.PixelOffset JsonPixelOffset = new SOLIS_CMD_TLM.PixelOffset();

List lstCartesian1 = new List();

lstCartesian1.Add(0);

lstCartesian1.Add(0);

JsonPixelOffset.cartesian2 = lstCartesian1;

// BILLBOARD DATA

SOLIS_CMD_TLM.Billboard JsonBillboard = new SOLIS_CMD_TLM.Billboard();

JsonBillboard.color = JsonColor;

JsonBillboard.eyeOffset = JsonEyeOffset;

JsonBillboard.horizontalOrigin = “CENTER”;

JsonBillboard.image = “data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAjSURBVChTYyAa/EcDUGEIgIphAKg0XRSAAFQMDqDChAADAwDC13+BJ+0oDwAAAABJRU5ErkJgggAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==”;

JsonBillboard.pixelOffset = JsonPixelOffset;

JsonBillboard.scale = 1;

JsonBillboard.show = true;

JsonBillboard.verticalOrigin = “CENTER”;

// FILL COLOR DATA

SOLIS_CMD_TLM.FillColor JsonFillColor = new SOLIS_CMD_TLM.FillColor();

List lstRGBA_FillColor = new List();

lstRGBA_FillColor.Add(0);

lstRGBA_FillColor.Add(255);

lstRGBA_FillColor.Add(255);

lstRGBA_FillColor.Add(255);

JsonFillColor.rgba = lstRGBA_FillColor;

// OUTLINE COLOR DATA

SOLIS_CMD_TLM.OutlineColor JsonOutlineColor = new SOLIS_CMD_TLM.OutlineColor();

List lstRGBA_OutlineColor = new List();

lstRGBA_OutlineColor.Add(0);

lstRGBA_OutlineColor.Add(0);

lstRGBA_OutlineColor.Add(0);

lstRGBA_OutlineColor.Add(255);

JsonOutlineColor.rgba = lstRGBA_OutlineColor;

// PIXELOFFSET2 DATA

SOLIS_CMD_TLM.PixelOffset2 JsonPixelOffset2 = new SOLIS_CMD_TLM.PixelOffset2();

List lstRGBA_PixelOffset2 = new List();

lstRGBA_PixelOffset2.Add(5);

lstRGBA_PixelOffset2.Add(-4);

JsonPixelOffset2.cartesian2 = lstRGBA_PixelOffset2;

// LABEL DATA

SOLIS_CMD_TLM.Label JsonLabel = new SOLIS_CMD_TLM.Label();

JsonLabel.fillColor = JsonFillColor;

JsonLabel.font = “21pt Lucida Console”;

JsonLabel.horizontalOrigin = “LEFT”;

JsonLabel.outlineColor = JsonOutlineColor;

JsonLabel.outlineWidth = 2;

JsonLabel.pixelOffset = JsonPixelOffset2;

JsonLabel.scale = 0.5;

JsonLabel.show = true;

JsonLabel.style = “FILL_AND_OUTLINE”;

JsonLabel.text = “BLAHSat”;

JsonLabel.verticalOrigin = “CENTER”;

// ADDING MORE TO THE ROOTOBJECT

JsonRoot.label = JsonLabel;

JsonRoot.billboard = JsonBillboard;

JsonRoot.model = JsonModel;

JsonRoot.path = JsonPath;

//**********************************************************************************************//

// THIS IS TO SEND THE JSON DATA TO CESIUM

// COMMENTED THE BELOW ON 3/31 - UNCOMMENT TO PASS DATA TO CESIUM VIA

//**********************************************************************************************//

string dataJSON = JsonConvert.SerializeObject(JsonRoot);

serverStream = tcpClient.GetStream();

JObject JSONobj1 = JObject.Parse(dataJSON1);

JObject JSONobj = JObject.Parse(dataJSON);

//string SendJSON = “[” + dataJSON1 + “,” + dataJSON + “]”;

string SendJSON = “[” + dataJSON1 + “,” + dataJSON + “]”;

byte outStream = Encoding.ASCII.GetBytes(SendJSON);

serverStream.Write(outStream, 0, outStream.Length);

//Log(SendJSON);

serverStream.Flush();

Console.WriteLine(“CZML Packet Sent!”);

//Console.WriteLine(SendJSON);

//**********************************************************************************************//

//Console.WriteLine(SendJSON);

//sendBytes = Encoding.ASCII.GetBytes(SendJSON);

////udp.SendAsync(sendBytes, sendBytes.Length);

//udp.Send(sendBytes, sendBytes.Length);

//Array.Clear(sendBytes, 0, sendBytes.Length);

//**********************************************************************************************//

counter = 0;

counterRt = 1;

}

}

What data are you getting from STK? Does CZML exported from STK exhibit the same problem?

Scott

Hey Scott,

I am obtaining Quaternions and Cartesian coordinates while the STK scenario is running. Exporting the scenario to a CZML works perfectly fine.

I think I am having trouble with the timing involved when relaying the STK data to Cesium such as the animation step value/multiplier and other values such as Epoch via Cesium and the time-stamp that I give the Quaternion and Cartesian values.

I got it to work somewhat with setting the orientation epoch to the start time of STK and fed the CZML packets to Cesium every so often but sometimes the timing gets out of sync and this is where the glitch (camera flips, satellite disappears) happens.

What does the multiplier need to be in STK and or Cesium or does this matter at all since I am obtaining the STK time while the scenario is being animated?

What do you think the Epoch values need to be in Cesium - the current time of the scenario or the actual start time in STK?

How do I take care of the time-stamp or what time-stamp value should I give the Quaternions/Cartesian data - should I just send the CZML packets every X seconds instead of sending them every ~ 15 ms?

Thank you for your help!

Hi RG,

I would expect the epoch you provide in the CZML should match the scenario start time in STK.

Can you share more about what you are trying to accomplish? What are you trying to keep in sync?

Scott

Hi Scott,

I am trying to keep the STK scenario in sync with Cesium. I tried to the CZML epoch but to no avail.

It looks like I need to mess with the clock multiplier on both STK and Cesium.

Thank you,

RG