public Main() { InitializeComponent(); m_insight3D = new Insight3D(); m_insight3D.Dock = DockStyle.Fill; m_insight3DPanel.Controls.Add(m_insight3D); // We don't have a call placed yet. m_hangUpButton.Enabled = false; m_callPlaced = false; // Load a texture which we will use for our phone locations. m_phoneTexture = SceneManager.Textures.FromUri(Path.Combine(Application.StartupPath, "Data/Markers/facility.png")); // Create a ServiceProviderDisplay to be used for visualization. m_display = new ServiceProviderDisplay(); // Create the font to use for labeling. We are using the same font as the control, only smaller. m_labelFont = new Font(Font.FontFamily, 10, Font.Style, Font.Unit, Font.GdiCharSet, Font.GdiVerticalFont); // The call will be taking place at a frequency of 1620.5e6. m_intendedSignal = new IntendedSignalByFrequency(1620.5e6); // Create the transmitting phone that we will use for our call and add it to the display. m_transmittingPhone = CreateTransmittingPhone(); m_display.ServiceProviders.Add(m_transmittingPhone); // Do the same for the receiving phone. m_receivingPhone = CreateReceivingPhone(); m_display.ServiceProviders.Add(m_receivingPhone); // Create an instance of IridiumSatellite for each of the three satellites we will // be using and add them to the display. // IridiumSatellite is a Platform-based class that adds default graphics and a // Transceiver object for communication. var analysisDate = new JulianDate(new GregorianDate(2011, 8, 2, 18, 1, 0)); var iridium49Tles = TwoLineElementSetHelper.GetTles("25108", analysisDate); var iridium49 = new IridiumSatellite("Iridium 49", iridium49Tles, m_labelFont, m_intendedSignal.TargetFrequency); m_display.ServiceProviders.Add(iridium49); var iridium58Tles = TwoLineElementSetHelper.GetTles("25274", analysisDate); var iridium58 = new IridiumSatellite("Iridium 58", iridium58Tles, m_labelFont, m_intendedSignal.TargetFrequency); m_display.ServiceProviders.Add(iridium58); var iridium4Tles = TwoLineElementSetHelper.GetTles("24796", analysisDate); var iridium4 = new IridiumSatellite("Iridium 4", iridium4Tles, m_labelFont, m_intendedSignal.TargetFrequency); m_display.ServiceProviders.Add(iridium4); // If the TLE epoch is too far from our expected analysis date, then we are // offline and loading cached data. Adjust the analysis date to match. if (iridium49Tles[0].Epoch.DaysDifference(analysisDate) > 5) { analysisDate = iridium49Tles[0].Epoch; } // Iridium 49 will be the receiving end of our caller's "uplink". // Modify the receiving antenna to be isotropic. iridium49.Transceiver.InputAntennaGainPattern = new IsotropicGainPattern(); // Iridium 4 will be the transmitting end of our call receiver's "downlink". // Modify the transmitting antenna to be isotropic. iridium4.Transceiver.OutputAntennaGainPattern = new IsotropicGainPattern(); // Now that we've created all of our definition objects, we need to build // the links between them that make up our communication system. m_communicationSystem = new CommunicationSystem(); // Add a link for each hop in the chain. // This could have been accomplished with a single call to AddChain. // However, since we plan on further configuring each of the individual links // generated for us, we add them one at a time. var linkCollection = m_communicationSystem.Links; m_callerToIridium49UpLink = linkCollection.Add("Uplink to Iridium 49", m_transmittingPhone, iridium49.Transceiver); m_iridium49To58Crosslink = linkCollection.Add("Iridium 49 -> Iridium 58", iridium49.Transceiver, iridium58.Transceiver); m_iridium58To4Crosslink = linkCollection.Add("Iridium 58 -> Iridium 4", iridium58.Transceiver, iridium4.Transceiver); m_iridium4ToReceiverDownLink = linkCollection.Add("Downlink from Iridium 4", iridium4.Transceiver, m_receivingPhone); // Now that we have the links, we can add an AccessConstraintsExtension to them so // that each link is only valid if they have line of sight to each other. var earth = CentralBodiesFacet.GetFromContext().Earth; var callerToIridium49Constraint = new CentralBodyObstructionConstraint(m_callerToIridium49UpLink, earth); m_callerToIridium49UpLink.Extensions.Add(new AccessConstraintsExtension(callerToIridium49Constraint)); var iridium49To58Constraint = new CentralBodyObstructionConstraint(m_iridium49To58Crosslink, earth); m_iridium49To58Crosslink.Extensions.Add(new AccessConstraintsExtension(iridium49To58Constraint)); var iridium58To4Constraint = new CentralBodyObstructionConstraint(m_iridium58To4Crosslink, earth); m_iridium58To4Crosslink.Extensions.Add(new AccessConstraintsExtension(iridium58To4Constraint)); var iridium4ToReceiverConstraint = new CentralBodyObstructionConstraint(m_iridium4ToReceiverDownLink, earth); m_iridium4ToReceiverDownLink.Extensions.Add(new AccessConstraintsExtension(iridium4ToReceiverConstraint)); m_linkComboBox.DisplayMember = "Name"; m_linkComboBox.Items.Add(m_callerToIridium49UpLink); m_linkComboBox.Items.Add(m_iridium49To58Crosslink); m_linkComboBox.Items.Add(m_iridium58To4Crosslink); m_linkComboBox.Items.Add(m_iridium4ToReceiverDownLink); m_linkComboBox.SelectedItem = m_iridium4ToReceiverDownLink; // Even though we haven't added any link graphics yet, we will later, so add them // to the display now. m_display.ServiceProviders.Add(m_callerToIridium49UpLink); m_display.ServiceProviders.Add(m_iridium49To58Crosslink); m_display.ServiceProviders.Add(m_iridium58To4Crosslink); m_display.ServiceProviders.Add(m_iridium4ToReceiverDownLink); // While we have set the location for our two phones and the satellite // transceivers, what we haven't done is assign their orientations. This can be // done automatically using the ConfigureAntennaTargeting method. Note that // ConfigureAntennaTargeting is a best effort method and returns status information // in regards to any problems it encounters. We don't check them here // simply because we know it will succeed. m_communicationSystem.ConfigureAntennaTargeting(); // Now that our initial configuration is complete, make sure we call ApplyChanges // on the display so that the visualization is created. m_display.ApplyChanges(); // Update the display to the current time. m_display.Update(SceneManager.Time); // Set up the animation time for our call. var animation = new SimulationAnimation { StartTime = analysisDate, EndTime = analysisDate.AddMinutes(15.0), TimeStep = Duration.FromSeconds(0.5), StartCycle = SimulationAnimationCycle.Loop, EndCycle = SimulationAnimationCycle.Loop }; SceneManager.Animation = animation; // Subscribe to the time changed event so we can update our display. SceneManager.TimeChanged += SceneManagerTimeChanged; // Reset to the beginning. animation.Reset(); // Configure the animation toolbar that overlays the 3D view. OverlayToolbar animationToolbar = new OverlayToolbar(m_insight3D); animationToolbar.Overlay.Origin = ScreenOverlayOrigin.BottomCenter; // Zoom to a location that includes both the caller and receiver. m_insight3D.Scene.Camera.ViewExtent(earth, Trig.DegreesToRadians(39.6333), Trig.DegreesToRadians(11.1333), Trig.DegreesToRadians(77.5833), Trig.DegreesToRadians(12.9833)); // Move the camera further back so that all satellites are visible. m_insight3D.Scene.Camera.Distance += 5000000.0; // Turn off lighting since it's the middle of the night and we want to be able to see everything, m_insight3D.Scene.Lighting.Enabled = false; // Create our link budget overlay helper which will display // the complete link budget for a selected link on top of the display. m_linkBudgetOverlayHelper = new LinkBudgetOverlayHelper(m_labelFont); //Hide it until the call is initiated m_linkBudgetOverlayHelper.Overlay.Display = false; // Add the actual overlay to Insight3D SceneManager.ScreenOverlays.Add(m_linkBudgetOverlayHelper.Overlay); }
/// <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) } } }; }