/// <summary> /// Create a Platform for the requested satellite using a TLE for position. /// The satellite will be visually represented by a labeled glTF model, /// the satellite's orbit will be shown, and vectors will be drawn for /// the body axes of the satellite, plus a vector indicating the direction /// of the sun. /// </summary> private void CreateSatellite() { // Get the current TLE for the given satellite identifier. var tleList = TwoLineElementSetHelper.GetTles(m_satelliteIdentifier, JulianDate.Now); // Use the epoch of the first TLE, since the TLE may have been loaded from offline data. m_epoch = tleList[0].Epoch; // Propagate the TLE and use that as the satellite's location point. var locationPoint = new Sgp4Propagator(tleList).CreatePoint(); m_satellite = new Platform { Name = "Satellite " + m_satelliteIdentifier, LocationPoint = locationPoint, // Orient the satellite using Vehicle Velocity Local Horizontal (VVLH) axes. OrientationAxes = new AxesVehicleVelocityLocalHorizontal(m_earth.FixedFrame, locationPoint), }; // Set the identifier for the satellite in the CZML document. m_satellite.Extensions.Add(new IdentifierExtension(m_satelliteIdentifier)); // Configure a glTF model for the satellite. m_satellite.Extensions.Add(new ModelGraphicsExtension(new ModelGraphics { // Link to a binary glTF file. Model = new CesiumResource(GetModelUri("satellite.glb"), CesiumResourceBehavior.LinkTo), // By default, Cesium plays all animations in the model simultaneously, which is not desirable. RunAnimations = false, })); // Configure a label for the satellite. m_satellite.Extensions.Add(new LabelGraphicsExtension(new LabelGraphics { // Use the name of the satellite as the text of the label. Text = m_satellite.Name, // Change the color of the label after 12 hours. This demonstrates specifying that // a value varies over time using intervals. FillColor = new TimeIntervalCollection <Color> { // Green for the first half day... new TimeInterval <Color>(JulianDate.MinValue, m_epoch.AddDays(0.5), Color.Green, true, false), // Red thereafter. new TimeInterval <Color>(m_epoch.AddDays(0.5), JulianDate.MaxValue, Color.Red, false, true), }, // Only show label when camera is far enough from the satellite, // to avoid visually clashing with the model. DistanceDisplayCondition = new Bounds(1000.0, double.MaxValue), })); // Configure graphical display of the orbital path of the satellite. m_satellite.Extensions.Add(new PathGraphicsExtension(new PathGraphics { // Configure the visual appearance of the line. Material = new PolylineOutlineMaterialGraphics { Color = Color.White, OutlineWidth = 1.0, OutlineColor = Color.Black, }, Width = 2.0, // Lead and Trail time indicate how much of the path to render. LeadTime = Duration.FromMinutes(44.0).TotalSeconds, TrailTime = Duration.FromMinutes(44.0).TotalSeconds, })); // Create vectors for the X, Y, and Z axes of the satellite. m_satelliteXAxis = CreateAxesVector(m_satellite, CartesianElement.X, Color.Green, "SatelliteX"); m_satelliteYAxis = CreateAxesVector(m_satellite, CartesianElement.Y, Color.Red, "SatelliteY"); m_satelliteZAxis = CreateAxesVector(m_satellite, CartesianElement.Z, Color.Blue, "SatelliteZ"); // Create a vector from the satellite to the Sun. // Compute the vector from the satellite's location to the Sun's center of mass. var sunCenterOfMassPoint = CentralBodiesFacet.GetFromContext().Sun.CenterOfMassPoint; var vectorSatelliteToSun = new VectorTrueDisplacement(m_satellite.LocationPoint, sunCenterOfMassPoint); // Create the visual vector. m_satelliteSunVector = new GraphicalVector { LocationPoint = m_satellite.LocationPoint, Vector = vectorSatelliteToSun, VectorGraphics = new VectorGraphics { Length = 5.0, Color = Color.Yellow, }, }; // Set the identifier for the vector in the CZML document. m_satelliteSunVector.Extensions.Add(new IdentifierExtension("SunVector")); // Orient the solar panels on the satellite model to point at the sun. var satelliteYVector = m_satellite.OrientationAxes.GetVectorElement(CartesianElement.Y); // allow only Z axis to rotate to follow sun vector. Constrain sun vector to Y, and satellite Y vector to X. var constrainedAxes = new AxesAlignedConstrained(satelliteYVector, AxisIndicator.First, vectorSatelliteToSun, AxisIndicator.Second); // Satellite axes are Vehicle Velocity Local Horizontal (VVLH) axes, where X is forward and Z is down, // but Cesium model axes are Z forward, Y up. So, create an axes rotates to the Cesium model axes. var offset = new UnitQuaternion(new ElementaryRotation(AxisIndicator.First, -Math.PI / 2)) * new UnitQuaternion(new ElementaryRotation(AxisIndicator.Third, Math.PI / 2)); var cesiumModelAxes = new AxesFixedOffset(m_satellite.OrientationAxes, offset); // The rotation will be from the Cesium model axes to the constrained axes. var solarPanelRotationAxes = new AxesInAxes(constrainedAxes, cesiumModelAxes); // Add a node transformation to rotate the SolarPanels node of the model. m_satellite.Extensions.GetByType <ModelGraphicsExtension>().ModelGraphics.NodeTransformations = new Dictionary <string, NodeTransformationGraphics> { { "SolarPanels", new NodeTransformationGraphics { Rotation = new AxesCesiumProperty(solarPanelRotationAxes) } } }; }
/// <summary> /// Create an aircraft with two sensors. /// The aircraft will be visually represented by a labeled glTF model. /// </summary> private void CreateAircraft() { // Define waypoints for the aircraft's path and use the propagated point as the location point. Cartographic point1 = new Cartographic(Trig.DegreesToRadians(-122.0), Trig.DegreesToRadians(46.3), 4000.0); Cartographic point2 = new Cartographic(Trig.DegreesToRadians(-122.28), Trig.DegreesToRadians(46.25), 4100.0); Cartographic point3 = new Cartographic(Trig.DegreesToRadians(-122.2), Trig.DegreesToRadians(46.1), 6000.0); Cartographic point4 = new Cartographic(Trig.DegreesToRadians(-121.5), Trig.DegreesToRadians(46.0), 7000.0); Waypoint waypoint1 = new Waypoint(m_epoch, point1, 20.0, 0.0); Waypoint waypoint2 = new Waypoint(waypoint1, m_earth.Shape, point2, 20.0); Waypoint waypoint3 = new Waypoint(waypoint2, m_earth.Shape, point3, 20.0); Waypoint waypoint4 = new Waypoint(waypoint3, m_earth.Shape, point4, 20.0); var waypointPropagator = new WaypointPropagator(m_earth, waypoint1, waypoint2, waypoint3, waypoint4); var locationPoint = waypointPropagator.CreatePoint(); m_aircraft = new Platform { Name = "Aircraft", LocationPoint = locationPoint, OrientationAxes = new AxesVehicleVelocityLocalHorizontal(m_earth.FixedFrame, locationPoint), }; // Set the identifier for the aircraft in the CZML document. m_aircraft.Extensions.Add(new IdentifierExtension("Aircraft")); // Hermite interpolation works better for aircraft-like vehicles. m_aircraft.Extensions.Add(new CesiumPositionExtension { InterpolationAlgorithm = CesiumInterpolationAlgorithm.Hermite }); // Configure a glTF model for the aircraft. m_aircraft.Extensions.Add(new ModelGraphicsExtension(new ModelGraphics { // Link to a binary glTF file. Model = new CesiumResource(GetModelUri("aircraft.glb"), CesiumResourceBehavior.LinkTo), // Flip the model visually to point Z in the correct direction. NodeTransformations = new Dictionary <string, NodeTransformationGraphics> { { "Aircraft", new NodeTransformationGraphics { Rotation = new UnitQuaternion(new ElementaryRotation(AxisIndicator.Third, Math.PI)) } } }, RunAnimations = false, })); // Show the path of the aircraft. m_aircraft.Extensions.Add(new PathGraphicsExtension(new PathGraphics { Width = 2.0, LeadTime = Duration.FromHours(1.0).TotalSeconds, TrailTime = Duration.FromHours(1.0).TotalSeconds, Material = new PolylineOutlineMaterialGraphics { Color = Color.White, OutlineColor = Color.Black, OutlineWidth = 1.0, }, })); // Configure label for the aircraft. m_aircraft.Extensions.Add(new LabelGraphicsExtension(new LabelGraphics { Text = m_aircraft.Name, // Change label color over time. FillColor = new TimeIntervalCollection <Color> { // Green by default... TimeInterval.Infinite.AddData(Color.Green), // Red between first and second waypoints. new TimeInterval <Color>(waypoint1.Date, waypoint2.Date, Color.Red), }, // Only show label when camera is far enough from the aircraft, // to avoid visually clashing with the model. DistanceDisplayCondition = new Bounds(1000.0, double.MaxValue), })); // Define a description for the aircraft which will be shown when selected in Cesium. m_aircraft.Extensions.Add(new DescriptionExtension(new Description("Aircraft with two offset sensors"))); // Create 30 degree simple conic sensor definition var sensorCone = new ComplexConic(); sensorCone.SetHalfAngles(0.0, Trig.DegreesToRadians(15)); sensorCone.SetClockAngles(Trig.DegreesToRadians(20), Trig.DegreesToRadians(50)); sensorCone.Radius = double.PositiveInfinity; // Create a sensor pointing "forward". // Position sensor underneath the wing. var sensorOneLocationPoint = new PointFixedOffset(m_aircraft.ReferenceFrame, new Cartesian(-3.0, 8.0, 0.0)); var sensorAxesOne = new AxesAlignedConstrained(m_aircraft.OrientationAxes.GetVectorElement(CartesianElement.Z), AxisIndicator.Third, m_aircraft.OrientationAxes.GetVectorElement(CartesianElement.X), AxisIndicator.First); // This rotation points the z-axis of the volume back along the x-axis of the ellipsoid. var rotationOne = new UnitQuaternion(new ElementaryRotation(AxisIndicator.Second, Constants.HalfPi / 4)); m_aircraftSensorOne = new Platform { LocationPoint = sensorOneLocationPoint, OrientationAxes = new AxesFixedOffset(sensorAxesOne, rotationOne), }; // Set the identifier for the sensor in the CZML document. m_aircraftSensorOne.Extensions.Add(new IdentifierExtension("AircraftSensorOne")); m_aircraftSensorOne.Extensions.Add(new CesiumPositionExtension { InterpolationAlgorithm = CesiumInterpolationAlgorithm.Hermite }); // Define the sensor geometry. m_aircraftSensorOne.Extensions.Add(new FieldOfViewExtension(sensorCone)); // Configure graphical display of the sensor. m_aircraftSensorOne.Extensions.Add(new FieldOfViewGraphicsExtension(new SensorFieldOfViewGraphics { // Configure the outline of the projection onto the earth. EllipsoidSurfaceMaterial = new SolidColorMaterialGraphics(Color.White), IntersectionWidth = 2.0, LateralSurfaceMaterial = new GridMaterialGraphics { Color = Color.FromArgb(171, Color.Blue), }, })); // Create sensor pointing to the "side". // Position sensor underneath the wing. var sensorTwoLocationPoint = new PointFixedOffset(m_aircraft.ReferenceFrame, new Cartesian(-3.0, -8.0, 0.0)); var sensorAxesTwo = new AxesAlignedConstrained(m_aircraft.OrientationAxes.GetVectorElement(CartesianElement.Z), AxisIndicator.Third, m_aircraft.OrientationAxes.GetVectorElement(CartesianElement.Y), AxisIndicator.Second); // This rotation points the z-axis of the volume back along the x-axis of the ellipsoid. var rotationTwo = new UnitQuaternion(new ElementaryRotation(AxisIndicator.First, Constants.HalfPi / 2)); m_aircraftSensorTwo = new Platform { LocationPoint = sensorTwoLocationPoint, OrientationAxes = new AxesFixedOffset(sensorAxesTwo, rotationTwo), }; // Set the identifier for the sensor in the CZML document. m_aircraftSensorTwo.Extensions.Add(new IdentifierExtension("AircraftSensorTwo")); m_aircraftSensorTwo.Extensions.Add(new CesiumPositionExtension { InterpolationAlgorithm = CesiumInterpolationAlgorithm.Hermite }); // Define the sensor geometry. m_aircraftSensorTwo.Extensions.Add(new FieldOfViewExtension(sensorCone)); // Configure graphical display of the sensor. m_aircraftSensorTwo.Extensions.Add(new FieldOfViewGraphicsExtension(new SensorFieldOfViewGraphics { // Configure the outline of the projection onto the earth. EllipsoidSurfaceMaterial = new SolidColorMaterialGraphics(Color.White), IntersectionWidth = 2.0, LateralSurfaceMaterial = new GridMaterialGraphics { Color = Color.FromArgb(171, Color.Red), }, })); // Create an access link between the aircraft and the observer position // on Mount St. Helens, using the same azimuth elevation mask to constrain access. m_aircraftAzimuthElevationMaskLink = new LinkInstantaneous(m_maskPlatform, m_aircraft); // Set the identifier for the link in the CZML document. m_aircraftAzimuthElevationMaskLink.Extensions.Add(new IdentifierExtension("AircraftMountStHelensAccess")); // Constrain access using the azimuth-elevation mask. var query = new AzimuthElevationMaskConstraint(m_aircraftAzimuthElevationMaskLink, LinkRole.Transmitter); // Configure graphical display of the access link. m_aircraftAzimuthElevationMaskLink.Extensions.Add(new LinkGraphicsExtension(new LinkGraphics { // Show the access link only when access is satisfied. Show = new AccessQueryCesiumProperty <bool>(query, true, false, false), Material = new SolidColorMaterialGraphics(Color.Yellow), })); }