public void Add(MotionEvaluator <Cartesian> evaluator, JulianDate epoch)
        {
            Cartesian position = evaluator.Evaluate(epoch);

            m_noAccessPositions.Add(position);

            m_satellites.Add(evaluator);
        }
        private void OnTimeChanged(object sender, TimeChangedEventArgs e)
        {
            if (m_temeToFixedEvaluator == null)
            {
                return;
            }

            JulianDate date        = e.Time;
            Matrix3By3 temeToFixed = new Matrix3By3(m_temeToFixedEvaluator.Evaluate(date));

            KinematicTransformation transformation = m_fixedToFacilityTopoEvaluator.Evaluate(date, 0);

            List <int> satellitesToRemove = null;

            m_satellites.ClearPositions();

            for (int i = 0; i < m_satellites.Count; ++i)
            {
                MotionEvaluator <Cartesian> satellite = m_satellites.GetSatellite(i);

                try
                {
                    // Update position of marker representing this satellite
                    Cartesian position = satellite.Evaluate(date).Rotate(temeToFixed);

                    // Compute access from satellite to facility
                    if (m_showAccess)
                    {
                        Cartesian             positionInTopo        = transformation.Transform(position);
                        AzimuthElevationRange azimuthElevationRange = new AzimuthElevationRange(positionInTopo);
                        m_satellites.AppendPosition(position, azimuthElevationRange.Elevation > 0.0);
                    }
                    else
                    {
                        m_satellites.AppendPosition(position, false);
                    }
                }
                catch (Exception)
                {
                    if (satellitesToRemove == null)
                    {
                        satellitesToRemove = new List <int>();
                    }

                    satellitesToRemove.Add(i);
                }
            }

            // Remove satellites that could not be evaluated
            if (satellitesToRemove != null)
            {
                m_satellites.RemoveUsingIndexList(satellitesToRemove);
                SetText(m_satellites.Count);
            }

            m_satellites.SetMarkerBatches();
        }
        /// <summary>
        /// Method to calculate all the data required for the graphs.
        /// </summary>
        private void OnAddReceiverClick(object sender, EventArgs e)
        {
            #region CreateAndConfigureReceiver
            // Let's create the GPSReceiver. The receiver stores many properties and has a defined location. This location
            // is the point of reference for visibility calculations.
            receiver = new GpsReceiver();

            // add receiver to the tree
            TreeNode newNode = new TreeNode(Localization.Receiver);
            rootNode.Nodes.Add(newNode);

            // Easy reference to Earth Central body used to initialize the ElevationAngleAccessConstraint and
            // to calculate the Az/El/Range Data.
            EarthCentralBody earth = CentralBodiesFacet.GetFromContext().Earth;

            // set the receiver properties based on user selections
            // The receiver has a receiver FrontEnd that contains the visibility and tracking constraints
            // Be sure to convert your angles to Radians!
            double minimumAngle = Trig.DegreesToRadians(Double.Parse(MaskAngle.Text));
            receiver.ReceiverConstraints.Clear();
            receiver.ReceiverConstraints.Add(new ElevationAngleConstraint(earth, minimumAngle));
            receiver.NumberOfChannels = (int)NumberOfChannels.Value;
            receiver.NoiseModel       = new ConstantGpsReceiverNoiseModel(0.8);

            // The receiver's methods of reducing the number of visible satellites to the limit imposed by the number of channels
            if (BestNSolType.Checked)
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.BestN;
            }
            else
            {
                receiver.ReceiverSolutionType = GpsReceiverSolutionType.AllInView;
            }

            // create a new location for the receiver by using the Cartographic type from AGI.Foundation.Coordinates
            // again, remember to convert from degrees to Radians! (except the height of course)
            Cartographic position = new Cartographic(Trig.DegreesToRadians(double.Parse(Longitude.Text)),
                                                     Trig.DegreesToRadians(double.Parse(Latitude.Text)),
                                                     double.Parse(ReceiverHeight.Text));

            // Now create an antenna for the GPS receiver. We specify the location of the antenna by assigning a
            // PointCartographic instance to the LocationPoint property. We specify that the antenna should be oriented
            // according to the typically-used East-North-Up axes by assigning an instance of AxesEastNorthUp to
            // the OrientationAxes property. While the orientation of the antenna won't affect which satellites are visible
            // or tracked in this case, it will affect the DOP values. For example, the EDOP value can be found in
            // DilutionOfPrecision.X, but only if we've configured the antenna to use East-North-Up axes.
            PointCartographic antennaLocationPoint = new PointCartographic(earth, position);
            Platform          antenna = new Platform
            {
                LocationPoint   = antennaLocationPoint,
                OrientationAxes = new AxesEastNorthUp(earth, antennaLocationPoint)
            };
            receiver.Antenna = antenna;

            #endregion

            // update the tree to reflect the correct receiver info
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.FixedMaskAngle + "= {0:0.00} " + Localization.degrees, MaskAngle.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.NumberOfChannels + "= {0}", NumberOfChannels.Value)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.SolutionType + "= {0}", receiver.ReceiverSolutionType == GpsReceiverSolutionType.AllInView ? Localization.AllInView : Localization.BestN)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Latitude + "= {0:0.000000} " + Localization.degrees, Latitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Longitude + "= {0:0.000000} " + Localization.degrees, Longitude.Text)));
            newNode.Nodes.Add(new TreeNode(string.Format(Localization.Height + "= {0:0.000} " + Localization.meters, ReceiverHeight.Text)));

            rootNode.Expand();
            newNode.Expand();

            #region CalculateDataForGraphs

            // Now, we'll open the almanac
            SemAlmanac almanac;
            using (Stream stream = openAlmanacDialog.OpenFile())
                using (StreamReader reader = new StreamReader(stream))
                {
                    // Read the SEM almanac from an almanac stream reader.
                    almanac = SemAlmanac.ReadFrom(reader, 1);
                }

            // Now create a PlatformCollection to hold GpsSatellite object instances. The SemAlmanac method CreateSatellitesFromRecords returns
            // just such a collection. We'll use this set of satellites as the set from which we'll try and track. There is a
            // GpsSatellite object for each satellite specified in the almanac.
            PlatformCollection gpsSatellites = almanac.CreateSatelliteCollection();

            // We provide the receiver with the complete set of gpsSatellites to consider for visibility calculations.
            // This is usually all SVs defined in the almanac - however you may want to remove SVs that aren't healthy. This can
            // be done by creating the gpsSatellites collection above using another version of the CreateSatellitesFromRecords method that
            // takes a SatelliteOutageFileReader.
            receiver.NavigationSatellites = gpsSatellites;

            // Optimization opportunity: Add the following code in a thread. This will help for long duration analyses.

            // Now that we have the receiver and location setup, we need to evaluate all the pertinent data.
            // using a SatelliteTrackingEvaluator, we can track satellites and using a DOP Evaluator,
            // we can calculate DOP at a specified time.
            // The receiver's GetSatelliteTrackingEvaluator method will provide a SatelliteTrackingEvaluator for you.
            // Similarly, the GetDilutionOfPrecisionEvaluator provides the DOP evaluator.
            // We create all evaluators in the same EvaluatorGroup for the best performance.

            EvaluatorGroup    group = new EvaluatorGroup();
            Evaluator <int[]> satTrackingEvaluator       = receiver.GetSatelliteTrackingIndexEvaluator(group);
            Evaluator <DilutionOfPrecision> dopEvaluator = receiver.GetDilutionOfPrecisionEvaluator(group);

            // We also need to create an evaluator to compute Azimuth/Elevation for each of the SVs
            MotionEvaluator <AzimuthElevationRange>[] aerEvaluators = new MotionEvaluator <AzimuthElevationRange> [gpsSatellites.Count];
            for (int i = 0; i < gpsSatellites.Count; ++i)
            {
                Platform satellite            = receiver.NavigationSatellites[i];
                VectorTrueDisplacement vector = new VectorTrueDisplacement(antenna.LocationPoint, satellite.LocationPoint);
                aerEvaluators[i] = earth.GetAzimuthElevationRangeEvaluator(vector, group);
            }

            // First we'll initialize the data structures used to plot the data
            for (int i = 0; i < DOPData.Length; i++)
            {
                // PointPairList is defined in the ZedGraph reference
                DOPData[i] = new PointPairList();
            }

            // We need to know which time standard to use here. If the user has specified that GPS time is to be used
            // we need to create the JulianDates with the GlobalPositioningSystemTime standard.
            if (GPSTimeRadio.Checked)
            {
                startjd = new JulianDate(StartTime.Value, TimeStandard.GlobalPositioningSystemTime);
                stopjd  = new JulianDate(StopTime.Value, TimeStandard.GlobalPositioningSystemTime);
            }
            else
            {
                // otherwise, the default time standard is UTC
                startjd = new JulianDate(StartTime.Value);
                stopjd  = new JulianDate(StopTime.Value);
            }

            // Now we''ll create the variables we'll need for iterating through time.
            // The propagator requires a Duration type be used to specify the timestep.
            Duration dur      = stopjd - startjd;
            double   timestep = Double.Parse(TimeStep.Text);

            // Initialize the progressbar with appropriate values
            progressBar1.Maximum = (int)dur.TotalSeconds;
            progressBar1.Step    = (int)timestep;

            // now we'll iterate through time by adding seconds to the start time JulianDate
            // creating a new JulianDate 'evaluateTime' each time step.
            for (double t = 0; t <= dur.TotalSeconds; t += timestep)
            {
                JulianDate evaluateTime = startjd.AddSeconds(t);

                // The string 'trackedSVs' is the start of a string we'll continue to build through this time
                // iteration. It will contain the info we'll need to put in the DOP graph tooltips for the different
                // DOP series (VDOP, HDOP, etc.)
                String trackedSVs = Localization.Tracked + ": ";

                // The evaluator method GetTrackedSatellites will take the current time and the initial list of satellites and
                // determine which satellites can be tracked based on the receiver constraints setup earlier. This method
                // returns a PlatformCollection object as well (though we'll cast each member of the Collection to a GPSSatellite type)
                int[] trackedSatellites = satTrackingEvaluator.Evaluate(evaluateTime);

                foreach (int satelliteIndex in trackedSatellites)
                {
                    Platform satellite = receiver.NavigationSatellites[satelliteIndex];

                    // Now we have access to a Platform object representing a GPS satellite and calculate the azimuth and elevation
                    // of each.  Note that we're just calculating the azimuth and elevation, but could just as easily get the
                    // range as well.
                    AzimuthElevationRange aer = aerEvaluators[satelliteIndex].Evaluate(evaluateTime);

                    // Get the GpsSatelliteExtension attached to the platform. The extension extends a
                    // platform with GPS-specific information. In this case, we need the
                    // satellites PRN.
                    GpsSatelliteExtension extension = satellite.Extensions.GetByType <GpsSatelliteExtension>();

                    // Create two separate PointPairLists to hold the data stored by Time and Azimuth
                    PointPairList thisTimePointList, thisAzPointList;

                    // Before we can arbitrarily create new PointPair Lists, we have to see if the Data Storage structures already contain a list
                    // for this PRN.
                    // The variables AzElData_TimeBased and AzElData_AzimuthBased are dictionaries that hold the PointPairLists using the PRN
                    // as a key. We use this structure to store a large amount of data for every satellite in a single, easy to access, variable.
                    // if the satellite we're currently looking at already has a list defined in the dictionary, we'll use that one, otherwise
                    // we'll create a new list
                    if (AzElData_TimeBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisTimePointList = AzElData_TimeBased[extension.PseudoRandomNumber];
                        AzElData_TimeBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisTimePointList = new PointPairList();
                    }

                    if (AzElData_AzimuthBased.ContainsKey(extension.PseudoRandomNumber))
                    {
                        thisAzPointList = AzElData_AzimuthBased[extension.PseudoRandomNumber];
                        AzElData_AzimuthBased.Remove(extension.PseudoRandomNumber);
                    }
                    else
                    {
                        thisAzPointList = new PointPairList();
                    }

                    // Now to get the actual Azimuth and elevation data

                    // Converting your Radians to degrees here makes the data appear in a more readable format. We also constrain the azimuth
                    // to be within the interval [0, 2*pi]
                    double azimuth   = Trig.RadiansToDegrees(Trig.ZeroToTwoPi(aer.Azimuth));
                    double elevation = Trig.RadiansToDegrees(aer.Elevation);
                    #endregion

                    // now create the point for the Azimuth based data
                    PointPair thisAzPoint = new PointPair(azimuth, elevation);
                    // and add the tooltip (ZedGraph uses the Tag property on a PointPair for the tooltip on that datapoint )
                    thisAzPoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // and finally add this point to the list
                    thisAzPointList.Add(thisAzPoint);

                    // now we'll do the same for the time-based data, instead of adding the Az and El, we'll add the time and El.
                    // Create a new XDate object to store the time for this point
                    double txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the time and elevation data to this point
                    PointPair thisTimePoint = new PointPair(txd, Trig.RadiansToDegrees(aer.Elevation));
                    // Create the tooltip tag
                    thisTimePoint.Tag = String.Format("PRN {0}, {1}, " + Localization.Az + ": {2:0.000}, " + Localization.El + ": {3:0.000}", extension.PseudoRandomNumber, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), azimuth, elevation);
                    // finally add this point to the list
                    thisTimePointList.Add(thisTimePoint);

                    //Now that this data is all calculated, we'll add the point lists to the correct data structures for the GpsSatellite we're working with
                    AzElData_TimeBased.Add(extension.PseudoRandomNumber, thisTimePointList);
                    AzElData_AzimuthBased.Add(extension.PseudoRandomNumber, thisAzPointList);

                    // now update the 'trackedSVs' string to be used for the DOP data tooltip
                    // wee need to do this inside the GpsSatellite loop because we need to get the entire list of tracked SVs for this time step.
                    // we won't use this string until we're out of the loop however.
                    trackedSVs += extension.PseudoRandomNumber.ToString() + ", ";
                }

                // now we're out of the GpsSatellite loop, we'll do some string manipulation to get the tooltip for the DOP data.
                // (gets rid of the last inserted comma)
                string svs = trackedSVs.Substring(0, trackedSVs.LastIndexOf(' ') - 1);
                try
                {
                    // Now we use the evaluator to calculate the DilutionOfPrecision for us for this timestep
                    DilutionOfPrecision dop = dopEvaluator.Evaluate(evaluateTime);

                    // if the dop object throws an exception, there aren't enough tracked satellites to form a navigation solution (typically < 4 tracked)
                    // in that case we leave the data for this time unfilled. The graph will then have empty spots for this time.

                    // Here we create a new PointPair and a new XDate to add to the X-Axis
                    PointPair pp;
                    double    txd = (double)new XDate(evaluateTime.ToDateTime());
                    // add the East DOP value and the time to the PointPair and set the tooltip tag property for this series.
                    pp     = new PointPair(txd, dop.X);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.EDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.X);
                    // add the point to the 0th element of the DOPData structure
                    DOPData[0].Add(pp);
                    // repeat for North DOP
                    pp     = new PointPair(txd, dop.Y);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.NDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Y);
                    DOPData[1].Add(pp);
                    // repeat for the Vertical DOP
                    pp     = new PointPair(txd, dop.Z);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.VDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Z);
                    DOPData[2].Add(pp);
                    // repeat for the Horizontal DOP
                    pp     = new PointPair(txd, dop.XY);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.HDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.XY);
                    DOPData[3].Add(pp);
                    // repeat for the Position DOP
                    pp     = new PointPair(txd, dop.Position);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.PDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Position);
                    DOPData[4].Add(pp);
                    // repeat for the Time DOP
                    pp     = new PointPair(txd, dop.Time);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.TDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Time);
                    DOPData[5].Add(pp);
                    // repeat for the Geometric DOP
                    pp     = new PointPair(txd, dop.Geometric);
                    pp.Tag = String.Format("{0}\n{1} " + Localization.GDOP + ": {2:0.000}", svs, evaluateTime.ToDateTime().ToString("M/d/yyyy, h:mm tt"), dop.Geometric);
                    DOPData[6].Add(pp);

                    // Notice here that the different DOP values (East, North, etc) were denoted by the dop.X, dop.Y etc. This is because the
                    // DOP values could be in any coordinate system. In our case, we're in the ENU coordinate system an X represents East, Y
                    // represents North, Z represents Vertical, XY represents horizontal. You can change the reference frame the DOP is reported in
                    // but you will then have to understand that the dop.X value corresponds to your X-defined axis and so on.
                }
                catch
                {
                    // Do Nothing here - we just won't add the data to the data list
                }
                // update the progress bar - we're done with this time step!
                progressBar1.PerformStep();
            }
            // finally update the graphs
            UpdateDopGraph();
            updateAzElGraph();

            // reset the progress bar
            progressBar1.Value = 0;

            // and set the appropriate button states
            SetControlStates(true);
        }