/// <summary> /// Sorts the aircraft list using the parameters in the args object. /// </summary> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param>] /// <param name="distances"></param> private void SortAircraft(List <IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary <int, double?> distances) { IAircraftComparer comparer = Factory.Singleton.Resolve <IAircraftComparer>(); comparer.BrowserLocation = args.BrowserLatitude == null || args.BrowserLongitude == null ? null : new Coordinate((float)args.BrowserLatitude, (float)args.BrowserLongitude); foreach (var sortBy in args.SortBy) { comparer.SortBy.Add(sortBy); } foreach (var distance in distances) { comparer.PrecalculatedDistances.Add(distance.Key, distance.Value); } aircraftListSnapshot.Sort(comparer); }
/// <summary> /// Creates an object that holds all of the aircraft list arguments that were extracted from the request. /// </summary> /// <param name="args"></param> /// <param name="aircraftList"></param> /// <param name="isFlightSimulator"></param> /// <returns></returns> private AircraftListJsonBuilderArgs ConstructBuildArgs(RequestReceivedEventArgs args, IAircraftList aircraftList, bool isFlightSimulator) { var result = new AircraftListJsonBuilderArgs() { AircraftList = aircraftList, BrowserLatitude = QueryNDouble(args, "lat"), BrowserLongitude = QueryNDouble(args, "lng"), Filter = isFlightSimulator ? null : ConstructFilter(args), IsFlightSimulatorList = isFlightSimulator, IsInternetClient = args.IsInternetRequest, PreviousDataVersion = QueryLong(args, "ldv", -1), ResendTrails = QueryString(args, "refreshTrails", false) == "1", ShowShortTrail = QueryString(args, "trFmt", true) == "S", }; for (int sortColumnCount = 0; sortColumnCount < 2; ++sortColumnCount) { var sortColumn = QueryString(args, String.Format("sortBy{0}", sortColumnCount + 1), true); var sortOrder = QueryString(args, String.Format("sortOrder{0}", sortColumnCount + 1), true); if (String.IsNullOrEmpty(sortColumn) || String.IsNullOrEmpty(sortOrder)) { break; } result.SortBy.Add(new KeyValuePair <string, bool>(sortColumn, sortOrder == "ASC")); } if (result.SortBy.Count == 0) { result.SortBy.Add(new KeyValuePair <string, bool>(AircraftComparerColumn.FirstSeen, false)); } var previousAircraftIds = args.Request.Headers["X-VirtualRadarServer-AircraftIds"]; if (!String.IsNullOrEmpty(previousAircraftIds)) { var decodedPreviousAircraftIds = HttpUtility.UrlDecode(previousAircraftIds); foreach (var chunk in decodedPreviousAircraftIds.Split(',')) { int id; if (int.TryParse(chunk, out id)) { result.PreviousAircraft.Add(id); } } } return(result); }
/// <summary> /// Returns a fully-formed <see cref="AircraftListJson"/> from the aircraft list passed across. /// </summary> /// <param name="args"></param> /// <returns></returns> public AircraftListJson Build(AircraftListJsonBuilderArgs args) { if (args == null) { throw new ArgumentNullException("aircraftList"); } if (args.AircraftList == null) { throw new InvalidOperationException("The AircraftList must be supplied"); } var result = new AircraftListJson() { FlagHeight = 20, FlagWidth = 85, ShowFlags = _ShowFlags && !args.IsFlightSimulatorList, ShowPictures = _ShowPictures && (!args.IsInternetClient || _ShowPicturesToInternetClients) && !args.IsFlightSimulatorList, ShowSilhouettes = _ShowSilhouettes && !args.IsFlightSimulatorList, ShortTrailLengthSeconds = _ShortTrailLength, Source = (int)args.AircraftList.Source, }; long timestamp, dataVersion; var aircraft = args.AircraftList.TakeSnapshot(out timestamp, out dataVersion); result.AvailableAircraft = aircraft.Count; result.LastDataVersion = dataVersion.ToString(); result.ServerTime = JavascriptHelper.ToJavascriptTicks(timestamp); Dictionary <int, double?> distances = new Dictionary <int, double?>(); aircraft = FilterAircraft(aircraft, args, ref distances); SortAircraft(aircraft, args, distances); CopyAircraft(result, aircraft, args, distances); return(result); }
/// <summary> /// Builds the full or short coordinates list and attaches it to the aircraft JSON object. /// </summary> /// <param name="shortCoordinates"></param> /// <param name="firstTimeSeen"></param> /// <param name="aircraftJson"></param> /// <param name="aircraftSnapshot"></param> /// <param name="args"></param> /// <param name="sendAltitude"></param> /// <param name="sendSpeed"></param> private void BuildCoordinatesList(bool shortCoordinates, bool firstTimeSeen, AircraftJson aircraftJson, IAircraft aircraftSnapshot, AircraftListJsonBuilderArgs args, bool sendAltitude, bool sendSpeed) { aircraftJson.ResetTrail = firstTimeSeen || args.ResendTrails || aircraftSnapshot.FirstCoordinateChanged > args.PreviousDataVersion; List <double?> list = new List <double?>(); List <Coordinate> coordinates = shortCoordinates ? aircraftSnapshot.ShortCoordinates : aircraftSnapshot.FullCoordinates; Coordinate lastCoordinate = null; Coordinate nextCoordinate = null; for (var i = 0; i < coordinates.Count; ++i) { var coordinate = nextCoordinate ?? coordinates[i]; nextCoordinate = i + 1 == coordinates.Count ? null : coordinates[i + 1]; if (aircraftJson.ResetTrail || coordinate.DataVersion > args.PreviousDataVersion) { // If this is a full coordinate list then entries can be in here that only record a change in altitude or speed, and not a change in track. Those // entries are to be ignored. They can be identified by having a track that is the same as their immediate neighbours in the list. if (!shortCoordinates && lastCoordinate != null && nextCoordinate != null) { var dupeHeading = lastCoordinate.Heading == coordinate.Heading && coordinate.Heading == nextCoordinate.Heading; if (dupeHeading && !sendAltitude && !sendSpeed) { continue; } var dupeAltitude = lastCoordinate.Altitude == coordinate.Altitude && coordinate.Altitude == nextCoordinate.Altitude; if (sendAltitude && dupeHeading && dupeAltitude) { continue; } var dupeSpeed = lastCoordinate.GroundSpeed == coordinate.GroundSpeed && coordinate.GroundSpeed == nextCoordinate.GroundSpeed; if (sendSpeed && dupeHeading && dupeSpeed) { continue; } } list.Add(Round.Coordinate(coordinate.Latitude)); list.Add(Round.Coordinate(coordinate.Longitude)); if (shortCoordinates) { list.Add(JavascriptHelper.ToJavascriptTicks(coordinate.Tick)); } else { list.Add((int?)coordinate.Heading); } if (sendAltitude) { list.Add(coordinate.Altitude); } else if (sendSpeed) { list.Add(coordinate.GroundSpeed); } } lastCoordinate = coordinate; } if (aircraftSnapshot.Latitude != null && aircraftSnapshot.Longitude != null && (lastCoordinate.Latitude != aircraftSnapshot.Latitude || lastCoordinate.Longitude != aircraftSnapshot.Longitude) && aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) { list.Add(Round.Coordinate(aircraftSnapshot.Latitude)); list.Add(Round.Coordinate(aircraftSnapshot.Longitude)); if (shortCoordinates) { list.Add(JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value)); } else { list.Add((int?)Round.TrackHeading(aircraftSnapshot.Track)); } if (sendAltitude) { list.Add(Round.TrackAltitude(aircraftSnapshot.Altitude)); } else if (sendSpeed) { list.Add(Round.TrackGroundSpeed(aircraftSnapshot.GroundSpeed)); } } if (list.Count != 0) { if (shortCoordinates) { aircraftJson.ShortCoordinates = list; } else { aircraftJson.FullCoordinates = list; } } }
/// <summary> /// Copies the aircraft from the snapshot to the JSON object. /// </summary> /// <param name="aircraftListJson"></param> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> private void CopyAircraft(AircraftListJson aircraftListJson, List <IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary <int, double?> distances) { var now = Provider.UtcNow; var configuration = _SharedConfiguration.Get(); var positionTimeoutThreshold = now.AddSeconds(-(configuration.BaseStationSettings.DisplayTimeoutSeconds + BoostStalePositionSeconds)); HashSet <int> previousAircraftSet = null; List <int> previousAircraft = args.PreviousAircraft; if (previousAircraft.Count > 15) { previousAircraftSet = new HashSet <int>(previousAircraft); previousAircraft = null; } double?distance = null; for (var i = 0; i < aircraftListSnapshot.Count; ++i) { var aircraftSnapshot = aircraftListSnapshot[i]; if (distances != null) { distances.TryGetValue(aircraftSnapshot.UniqueId, out distance); } var aircraftJson = new AircraftJson() { UniqueId = aircraftSnapshot.UniqueId, IsSatcomFeed = aircraftSnapshot.LastSatcomUpdate != DateTime.MinValue, }; if (!args.OnlyIncludeMessageFields) { aircraftJson.BearingFromHere = GreatCircleMaths.Bearing(args.BrowserLatitude, args.BrowserLongitude, aircraftSnapshot.Latitude, aircraftSnapshot.Longitude, null, false, true); aircraftJson.DistanceFromHere = distance == null ? (double?)null : Math.Round(distance.Value, 2); if (aircraftJson.BearingFromHere != null) { aircraftJson.BearingFromHere = Math.Round(aircraftJson.BearingFromHere.Value, 1); } } var firstTimeSeen = previousAircraft != null ? !previousAircraft.Contains(aircraftSnapshot.UniqueId) : !previousAircraftSet.Contains(aircraftSnapshot.UniqueId); if (firstTimeSeen || aircraftSnapshot.AirPressureInHgChanged > args.PreviousDataVersion) { aircraftJson.AirPressureInHg = aircraftSnapshot.AirPressureInHg; } if (firstTimeSeen || aircraftSnapshot.AltitudeChanged > args.PreviousDataVersion) { aircraftJson.Altitude = aircraftSnapshot.Altitude; } if (firstTimeSeen || aircraftSnapshot.AltitudeTypeChanged > args.PreviousDataVersion) { aircraftJson.AltitudeType = (int)aircraftSnapshot.AltitudeType; } if (firstTimeSeen || aircraftSnapshot.CallsignChanged > args.PreviousDataVersion) { aircraftJson.Callsign = aircraftSnapshot.Callsign; } if (firstTimeSeen || aircraftSnapshot.CallsignIsSuspectChanged > args.PreviousDataVersion) { aircraftJson.CallsignIsSuspect = aircraftSnapshot.CallsignIsSuspect; } if (firstTimeSeen || aircraftSnapshot.GroundSpeedChanged > args.PreviousDataVersion) { aircraftJson.GroundSpeed = Round.GroundSpeed(aircraftSnapshot.GroundSpeed); } if (firstTimeSeen || aircraftSnapshot.EmergencyChanged > args.PreviousDataVersion) { aircraftJson.Emergency = aircraftSnapshot.Emergency; } if (firstTimeSeen || aircraftSnapshot.GeometricAltitudeChanged > args.PreviousDataVersion) { aircraftJson.GeometricAltitude = aircraftSnapshot.GeometricAltitude; } if (firstTimeSeen || args.AlwaysShowIcao || aircraftSnapshot.Icao24Changed > args.PreviousDataVersion) { aircraftJson.Icao24 = aircraftSnapshot.Icao24; } if (firstTimeSeen || aircraftSnapshot.IsTisbChanged > args.PreviousDataVersion) { aircraftJson.IsTisb = aircraftSnapshot.IsTisb; } if (firstTimeSeen || aircraftSnapshot.LatitudeChanged > args.PreviousDataVersion) { aircraftJson.Latitude = Round.Coordinate(aircraftSnapshot.Latitude); } if (firstTimeSeen || aircraftSnapshot.LongitudeChanged > args.PreviousDataVersion) { aircraftJson.Longitude = Round.Coordinate(aircraftSnapshot.Longitude); } if (firstTimeSeen || aircraftSnapshot.OnGroundChanged > args.PreviousDataVersion) { aircraftJson.OnGround = aircraftSnapshot.OnGround; } if (firstTimeSeen || aircraftSnapshot.PositionIsMlatChanged > args.PreviousDataVersion) { aircraftJson.PositionIsMlat = aircraftSnapshot.PositionIsMlat; } if (firstTimeSeen || aircraftSnapshot.SignalLevelChanged > args.PreviousDataVersion) { aircraftJson.HasSignalLevel = aircraftSnapshot.SignalLevel != null; aircraftJson.SignalLevel = aircraftSnapshot.SignalLevel; } if (firstTimeSeen || aircraftSnapshot.SpeedTypeChanged > args.PreviousDataVersion) { aircraftJson.SpeedType = (int)aircraftSnapshot.SpeedType; } if (firstTimeSeen || aircraftSnapshot.SquawkChanged > args.PreviousDataVersion) { aircraftJson.Squawk = String.Format("{0:0000}", aircraftSnapshot.Squawk); } if (firstTimeSeen || aircraftSnapshot.TargetAltitudeChanged > args.PreviousDataVersion) { aircraftJson.TargetAltitude = aircraftSnapshot.TargetAltitude; } if (firstTimeSeen || aircraftSnapshot.TargetTrackChanged > args.PreviousDataVersion) { aircraftJson.TargetTrack = aircraftSnapshot.TargetTrack; } if (firstTimeSeen || aircraftSnapshot.TrackChanged > args.PreviousDataVersion) { aircraftJson.Track = Round.Track(aircraftSnapshot.Track); } if (firstTimeSeen || aircraftSnapshot.TrackIsHeadingChanged > args.PreviousDataVersion) { aircraftJson.TrackIsHeading = aircraftSnapshot.TrackIsHeading; } if (firstTimeSeen || aircraftSnapshot.TransponderTypeChanged > args.PreviousDataVersion) { aircraftJson.TransponderType = (int)aircraftSnapshot.TransponderType; } if (firstTimeSeen || aircraftSnapshot.VerticalRateChanged > args.PreviousDataVersion) { aircraftJson.VerticalRate = aircraftSnapshot.VerticalRate; } if (firstTimeSeen || aircraftSnapshot.VerticalRateTypeChanged > args.PreviousDataVersion) { aircraftJson.VerticalRateType = (int)aircraftSnapshot.VerticalRateType; } if (args.OnlyIncludeMessageFields) { if (aircraftJson.Latitude != null || aircraftJson.Longitude != null || aircraftJson.PositionIsMlat != null) { if (aircraftJson.Latitude == null) { aircraftJson.Latitude = Round.Coordinate(aircraftSnapshot.Latitude); } if (aircraftJson.Longitude == null) { aircraftJson.Longitude = Round.Coordinate(aircraftSnapshot.Longitude); } if (aircraftJson.PositionIsMlat == null) { aircraftJson.PositionIsMlat = aircraftSnapshot.PositionIsMlat; } } if (aircraftJson.Altitude != null || aircraftJson.GeometricAltitude != null || aircraftJson.AltitudeType != null) { if (aircraftJson.Altitude == null) { aircraftJson.Altitude = aircraftSnapshot.Altitude; } if (aircraftJson.AltitudeType == null) { aircraftJson.AltitudeType = (int)aircraftSnapshot.AltitudeType; } if (aircraftJson.GeometricAltitude == null) { aircraftJson.GeometricAltitude = aircraftSnapshot.GeometricAltitude; } } } else if (!args.OnlyIncludeMessageFields) { if (firstTimeSeen || aircraftSnapshot.ConstructionNumberChanged > args.PreviousDataVersion) { aircraftJson.ConstructionNumber = aircraftSnapshot.ConstructionNumber; } if (firstTimeSeen || aircraftSnapshot.CountMessagesReceivedChanged > args.PreviousDataVersion) { aircraftJson.CountMessagesReceived = aircraftSnapshot.CountMessagesReceived; } if (firstTimeSeen || aircraftSnapshot.DestinationChanged > args.PreviousDataVersion) { aircraftJson.Destination = aircraftSnapshot.Destination; } if (firstTimeSeen || aircraftSnapshot.EnginePlacementChanged > args.PreviousDataVersion) { aircraftJson.EnginePlacement = (int)aircraftSnapshot.EnginePlacement; } if (firstTimeSeen || aircraftSnapshot.EngineTypeChanged > args.PreviousDataVersion) { aircraftJson.EngineType = (int)aircraftSnapshot.EngineType; } if (firstTimeSeen || aircraftSnapshot.FirstSeenChanged > args.PreviousDataVersion) { aircraftJson.FirstSeen = aircraftSnapshot.FirstSeen; } if (firstTimeSeen || aircraftSnapshot.FlightsCountChanged > args.PreviousDataVersion) { aircraftJson.FlightsCount = aircraftSnapshot.FlightsCount; } if (firstTimeSeen || aircraftSnapshot.Icao24CountryChanged > args.PreviousDataVersion) { aircraftJson.Icao24Country = aircraftSnapshot.Icao24Country; } if (firstTimeSeen || aircraftSnapshot.Icao24InvalidChanged > args.PreviousDataVersion) { aircraftJson.Icao24Invalid = aircraftSnapshot.Icao24Invalid; } if (firstTimeSeen || aircraftSnapshot.IsInterestingChanged > args.PreviousDataVersion) { aircraftJson.IsInteresting = aircraftSnapshot.IsInteresting; } if (firstTimeSeen || aircraftSnapshot.IsMilitaryChanged > args.PreviousDataVersion) { aircraftJson.IsMilitary = aircraftSnapshot.IsMilitary; } if (firstTimeSeen || aircraftSnapshot.ManufacturerChanged > args.PreviousDataVersion) { aircraftJson.Manufacturer = aircraftSnapshot.Manufacturer; } if (firstTimeSeen || aircraftSnapshot.ModelChanged > args.PreviousDataVersion) { aircraftJson.Model = aircraftSnapshot.Model; } if (firstTimeSeen || aircraftSnapshot.NumberOfEnginesChanged > args.PreviousDataVersion) { aircraftJson.NumberOfEngines = aircraftSnapshot.NumberOfEngines; } if (firstTimeSeen || aircraftSnapshot.OperatorChanged > args.PreviousDataVersion) { aircraftJson.Operator = aircraftSnapshot.Operator; } if (firstTimeSeen || aircraftSnapshot.OperatorIcaoChanged > args.PreviousDataVersion) { aircraftJson.OperatorIcao = aircraftSnapshot.OperatorIcao; } if (firstTimeSeen || aircraftSnapshot.OriginChanged > args.PreviousDataVersion) { aircraftJson.Origin = aircraftSnapshot.Origin; } if (firstTimeSeen || aircraftSnapshot.PictureFileNameChanged > args.PreviousDataVersion) { aircraftJson.HasPicture = !String.IsNullOrEmpty(aircraftSnapshot.PictureFileName); } if (firstTimeSeen || aircraftSnapshot.PictureHeightChanged > args.PreviousDataVersion) { aircraftJson.PictureHeight = aircraftSnapshot.PictureHeight == 0 ? (int?)null : aircraftSnapshot.PictureHeight; } if (firstTimeSeen || aircraftSnapshot.PictureWidthChanged > args.PreviousDataVersion) { aircraftJson.PictureWidth = aircraftSnapshot.PictureWidth == 0 ? (int?)null : aircraftSnapshot.PictureWidth; } if (firstTimeSeen || aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) { aircraftJson.PositionTime = aircraftSnapshot.PositionTime == null ? (long?)null : JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value); } if (firstTimeSeen || aircraftSnapshot.ReceiverIdChanged > args.PreviousDataVersion) { aircraftJson.ReceiverId = aircraftSnapshot.ReceiverId; } if (firstTimeSeen || aircraftSnapshot.RegistrationChanged > args.PreviousDataVersion) { aircraftJson.Registration = aircraftSnapshot.Registration; } if (firstTimeSeen || aircraftSnapshot.SpeciesChanged > args.PreviousDataVersion) { aircraftJson.Species = (int)aircraftSnapshot.Species; } if (firstTimeSeen || aircraftSnapshot.TypeChanged > args.PreviousDataVersion) { aircraftJson.Type = aircraftSnapshot.Type; } if (firstTimeSeen || aircraftSnapshot.UserTagChanged > args.PreviousDataVersion) { aircraftJson.UserTag = aircraftSnapshot.UserTag; } if (firstTimeSeen || aircraftSnapshot.WakeTurbulenceCategoryChanged > args.PreviousDataVersion) { aircraftJson.WakeTurbulenceCategory = (int)aircraftSnapshot.WakeTurbulenceCategory; } if (firstTimeSeen || aircraftSnapshot.YearBuiltChanged > args.PreviousDataVersion) { aircraftJson.YearBuilt = aircraftSnapshot.YearBuilt; } if (aircraftSnapshot.Stopovers.Count > 0 && (firstTimeSeen || aircraftSnapshot.StopoversChanged > args.PreviousDataVersion)) { aircraftJson.Stopovers = new List <string>(); aircraftJson.Stopovers.AddRange(aircraftSnapshot.Stopovers); } aircraftJson.SecondsTracked = (long)((now - aircraftSnapshot.FirstSeen).TotalSeconds); aircraftJson.PositionIsStale = aircraftSnapshot.LastSatcomUpdate == DateTime.MinValue && // Never flag satcom aircraft as having a stale position aircraftSnapshot.PositionTime != null && aircraftSnapshot.PositionTime < positionTimeoutThreshold ? true : (bool?)null; } if (args.TrailType != TrailType.None) { var hasTrail = false; var isShort = false; var showAltitude = false; var showSpeed = false; switch (args.TrailType) { case TrailType.Short: isShort = true; hasTrail = aircraftSnapshot.ShortCoordinates.Count > 0; break; case TrailType.ShortAltitude: showAltitude = true; aircraftJson.TrailType = "a"; goto case TrailType.Short; case TrailType.ShortSpeed: showSpeed = true; aircraftJson.TrailType = "s"; goto case TrailType.Short; case TrailType.Full: hasTrail = aircraftSnapshot.FullCoordinates.Count > 0; break; case TrailType.FullAltitude: showAltitude = true; aircraftJson.TrailType = "a"; goto case TrailType.Full; case TrailType.FullSpeed: showSpeed = true; aircraftJson.TrailType = "s"; goto case TrailType.Full; } if (hasTrail) { BuildCoordinatesList(isShort, firstTimeSeen, aircraftJson, aircraftSnapshot, args, showAltitude, showSpeed); } } aircraftListJson.Aircraft.Add(aircraftJson); } }
/// <summary> /// Returns a filtered list of aircraft and at the same time calculates the distances from the browser location to each aircraft. /// </summary> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> /// <returns></returns> /// <remarks>Distance calculations can be expensive, hence the reason why we try to minimise the number of times that they are performed.</remarks> private List <IAircraft> FilterAircraft(List <IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary <int, double?> distances) { List <IAircraft> result = new List <IAircraft>(); foreach (var aircraft in aircraftListSnapshot) { if (PassesFilter(aircraft, args, distances)) { result.Add(aircraft); } } return(result); }
/// <summary> /// Returns a fully-formed <see cref="AircraftListJson"/> from the aircraft list passed across. /// </summary> /// <param name="args"></param> /// <returns></returns> public AircraftListJson Build(AircraftListJsonBuilderArgs args) { if (args == null) { throw new ArgumentNullException("args"); } RefreshConfigurationSettings(); var feedId = args.SourceFeedId == -1 ? _DefaultAircraftListFeedId : args.SourceFeedId; IAircraftList aircraftList = null; if (args.IsFlightSimulatorList) { aircraftList = args.AircraftList; } else { var selectedFeed = _FeedManager.GetByUniqueId(feedId, ignoreInvisibleFeeds: true); if (selectedFeed == null) { feedId = _DefaultAircraftListFeedId; selectedFeed = _FeedManager.GetByUniqueId(feedId, ignoreInvisibleFeeds: true); } aircraftList = selectedFeed == null ? null : selectedFeed.AircraftList; } if (aircraftList == null) { aircraftList = _EmptyAircraftList; feedId = args.SourceFeedId; } var result = new AircraftListJson() { FlagHeight = 20, FlagWidth = 85, ShowFlags = _ShowFlags && !args.IsFlightSimulatorList, ShowPictures = _ShowPictures && (!args.IsInternetClient || _ShowPicturesToInternetClients) && !args.IsFlightSimulatorList, ShowSilhouettes = _ShowSilhouettes && !args.IsFlightSimulatorList, ShortTrailLengthSeconds = _ShortTrailLength, Source = (int)aircraftList.Source, SourceFeedId = feedId, }; if (!args.FeedsNotRequired) { foreach (var feed in _FeedManager.VisibleFeeds) { result.Feeds.Add(new FeedJson() { UniqueId = feed.UniqueId, Name = feed.Name, HasPolarPlot = feed.AircraftList != null && feed.AircraftList.PolarPlotter != null }); } } long timestamp, dataVersion; var aircraft = aircraftList.TakeSnapshot(out timestamp, out dataVersion); result.AvailableAircraft = aircraft.Count; if (args.IgnoreUnchanged) { aircraft = aircraft.Where(r => r.DataVersion > args.PreviousDataVersion).ToList(); } result.LastDataVersion = dataVersion.ToString(); result.ServerTime = JavascriptHelper.ToJavascriptTicks(timestamp); Dictionary <int, double?> distances = new Dictionary <int, double?>(); aircraft = FilterAircraft(aircraft, args, distances); SortAircraft(aircraft, args, distances); CopyAircraft(result, aircraft, args, distances); return(result); }
/// <summary> /// Builds the full or short coordinates list and attaches it to the aircraft JSON object. /// </summary> /// <param name="shortCoordinates"></param> /// <param name="firstTimeSeen"></param> /// <param name="aircraftJson"></param> /// <param name="aircraftSnapshot"></param> /// <param name="args"></param> private void BuildCoordinatesList(bool shortCoordinates, bool firstTimeSeen, AircraftJson aircraftJson, IAircraft aircraftSnapshot, AircraftListJsonBuilderArgs args) { aircraftJson.ResetTrail = firstTimeSeen || args.ResendTrails || aircraftSnapshot.FirstCoordinateChanged > args.PreviousDataVersion; List <double?> list = new List <double?>(); Coordinate lastCoordinate = null; foreach (var coordindate in shortCoordinates ? aircraftSnapshot.ShortCoordinates : aircraftSnapshot.FullCoordinates) { if (aircraftJson.ResetTrail || coordindate.DataVersion > args.PreviousDataVersion) { list.Add(Round.Coordinate(coordindate.Latitude)); list.Add(Round.Coordinate(coordindate.Longitude)); if (shortCoordinates) { list.Add(JavascriptHelper.ToJavascriptTicks(coordindate.Tick)); } else { list.Add(Round.Track(coordindate.Heading)); } } lastCoordinate = coordindate; } if (aircraftSnapshot.Latitude != null && aircraftSnapshot.Longitude != null && (lastCoordinate.Latitude != aircraftSnapshot.Latitude || lastCoordinate.Longitude != aircraftSnapshot.Longitude) && aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) { list.Add(Round.Coordinate(aircraftSnapshot.Latitude)); list.Add(Round.Coordinate(aircraftSnapshot.Longitude)); if (shortCoordinates) { list.Add(JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value)); } else { list.Add(Round.Track(aircraftSnapshot.Track)); } } if (list.Count != 0) { if (shortCoordinates) { aircraftJson.ShortCoordinates = list; } else { aircraftJson.FullCoordinates = list; } } }
/// <summary> /// Copies the aircraft from the snapshot to the JSON object. /// </summary> /// <param name="aircraftListJson"></param> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> private void CopyAircraft(AircraftListJson aircraftListJson, List <IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary <int, double?> distances) { var now = _Provider.UtcNow; foreach (var aircraftSnapshot in aircraftListSnapshot) { double?distance; if (!distances.TryGetValue(aircraftSnapshot.UniqueId, out distance)) { distance = null; } var aircraftJson = new AircraftJson() { BearingFromHere = GreatCircleMaths.Bearing(args.BrowserLatitude, args.BrowserLongitude, aircraftSnapshot.Latitude, aircraftSnapshot.Longitude, null, false, true), DistanceFromHere = distance == null ? (double?)null : Math.Round(distance.Value, 2), UniqueId = aircraftSnapshot.UniqueId, }; if (aircraftJson.BearingFromHere != null) { aircraftJson.BearingFromHere = Math.Round(aircraftJson.BearingFromHere.Value, 1); } bool firstTimeSeen = !args.PreviousAircraft.Contains(aircraftSnapshot.UniqueId); if (firstTimeSeen || aircraftSnapshot.AltitudeChanged > args.PreviousDataVersion) { aircraftJson.Altitude = aircraftSnapshot.Altitude; } if (firstTimeSeen || aircraftSnapshot.CallsignChanged > args.PreviousDataVersion) { aircraftJson.Callsign = aircraftSnapshot.Callsign; } if (firstTimeSeen || aircraftSnapshot.CallsignIsSuspectChanged > args.PreviousDataVersion) { aircraftJson.CallsignIsSuspect = aircraftSnapshot.CallsignIsSuspect; } if (firstTimeSeen || aircraftSnapshot.ConstructionNumberChanged > args.PreviousDataVersion) { aircraftJson.ConstructionNumber = aircraftSnapshot.ConstructionNumber; } if (firstTimeSeen || aircraftSnapshot.CountMessagesReceivedChanged > args.PreviousDataVersion) { aircraftJson.CountMessagesReceived = aircraftSnapshot.CountMessagesReceived; } if (firstTimeSeen || aircraftSnapshot.DestinationChanged > args.PreviousDataVersion) { aircraftJson.Destination = aircraftSnapshot.Destination; } if (firstTimeSeen || aircraftSnapshot.GroundSpeedChanged > args.PreviousDataVersion) { aircraftJson.GroundSpeed = Round.GroundSpeed(aircraftSnapshot.GroundSpeed); } if (firstTimeSeen || aircraftSnapshot.EmergencyChanged > args.PreviousDataVersion) { aircraftJson.Emergency = aircraftSnapshot.Emergency; } if (firstTimeSeen || aircraftSnapshot.EngineTypeChanged > args.PreviousDataVersion) { aircraftJson.EngineType = (int)aircraftSnapshot.EngineType; } if (firstTimeSeen || aircraftSnapshot.FirstSeenChanged > args.PreviousDataVersion) { aircraftJson.FirstSeen = aircraftSnapshot.FirstSeen; } if (firstTimeSeen || aircraftSnapshot.FlightsCountChanged > args.PreviousDataVersion) { aircraftJson.FlightsCount = aircraftSnapshot.FlightsCount; } if (firstTimeSeen || aircraftSnapshot.PictureFileNameChanged > args.PreviousDataVersion) { aircraftJson.HasPicture = !String.IsNullOrEmpty(aircraftSnapshot.PictureFileName); } if (firstTimeSeen || aircraftSnapshot.Icao24Changed > args.PreviousDataVersion) { aircraftJson.Icao24 = aircraftSnapshot.Icao24; } if (firstTimeSeen || aircraftSnapshot.Icao24CountryChanged > args.PreviousDataVersion) { aircraftJson.Icao24Country = aircraftSnapshot.Icao24Country; } if (firstTimeSeen || aircraftSnapshot.Icao24InvalidChanged > args.PreviousDataVersion) { aircraftJson.Icao24Invalid = aircraftSnapshot.Icao24Invalid; } if (firstTimeSeen || aircraftSnapshot.IsMilitaryChanged > args.PreviousDataVersion) { aircraftJson.IsMilitary = aircraftSnapshot.IsMilitary; } if (firstTimeSeen || aircraftSnapshot.IsInterestingChanged > args.PreviousDataVersion) { aircraftJson.IsInteresting = aircraftSnapshot.IsInteresting; } if (firstTimeSeen || aircraftSnapshot.LatitudeChanged > args.PreviousDataVersion) { aircraftJson.Latitude = Round.Coordinate(aircraftSnapshot.Latitude); } if (firstTimeSeen || aircraftSnapshot.LongitudeChanged > args.PreviousDataVersion) { aircraftJson.Longitude = Round.Coordinate(aircraftSnapshot.Longitude); } if (firstTimeSeen || aircraftSnapshot.ModelChanged > args.PreviousDataVersion) { aircraftJson.Model = aircraftSnapshot.Model; } if (firstTimeSeen || aircraftSnapshot.NumberOfEnginesChanged > args.PreviousDataVersion) { aircraftJson.NumberOfEngines = aircraftSnapshot.NumberOfEngines; } if (firstTimeSeen || aircraftSnapshot.OnGroundChanged > args.PreviousDataVersion) { aircraftJson.OnGround = aircraftSnapshot.OnGround; } if (firstTimeSeen || aircraftSnapshot.OperatorChanged > args.PreviousDataVersion) { aircraftJson.Operator = aircraftSnapshot.Operator; } if (firstTimeSeen || aircraftSnapshot.OperatorIcaoChanged > args.PreviousDataVersion) { aircraftJson.OperatorIcao = aircraftSnapshot.OperatorIcao; } if (firstTimeSeen || aircraftSnapshot.OriginChanged > args.PreviousDataVersion) { aircraftJson.Origin = aircraftSnapshot.Origin; } if (firstTimeSeen || aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) { aircraftJson.PositionTime = aircraftSnapshot.PositionTime == null ? (long?)null : JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value); } if (firstTimeSeen || aircraftSnapshot.RegistrationChanged > args.PreviousDataVersion) { aircraftJson.Registration = aircraftSnapshot.Registration; } if (firstTimeSeen || aircraftSnapshot.SpeciesChanged > args.PreviousDataVersion) { aircraftJson.Species = (int)aircraftSnapshot.Species; } if (firstTimeSeen || aircraftSnapshot.SpeedTypeChanged > args.PreviousDataVersion) { aircraftJson.SpeedType = (int)aircraftSnapshot.SpeedType; } if (firstTimeSeen || aircraftSnapshot.SquawkChanged > args.PreviousDataVersion) { aircraftJson.Squawk = String.Format("{0:0000}", aircraftSnapshot.Squawk); } if (firstTimeSeen || aircraftSnapshot.TrackChanged > args.PreviousDataVersion) { aircraftJson.Track = Round.Track(aircraftSnapshot.Track); } if (firstTimeSeen || aircraftSnapshot.TypeChanged > args.PreviousDataVersion) { aircraftJson.Type = aircraftSnapshot.Type; } if (firstTimeSeen || aircraftSnapshot.UserTagChanged > args.PreviousDataVersion) { aircraftJson.UserTag = aircraftSnapshot.UserTag; } if (firstTimeSeen || aircraftSnapshot.VerticalRateChanged > args.PreviousDataVersion) { aircraftJson.VerticalRate = aircraftSnapshot.VerticalRate; } if (firstTimeSeen || aircraftSnapshot.WakeTurbulenceCategoryChanged > args.PreviousDataVersion) { aircraftJson.WakeTurbulenceCategory = (int)aircraftSnapshot.WakeTurbulenceCategory; } if (aircraftSnapshot.Stopovers.Count > 0 && (firstTimeSeen || aircraftSnapshot.StopoversChanged > args.PreviousDataVersion)) { aircraftJson.Stopovers = new List <string>(); aircraftJson.Stopovers.AddRange(aircraftSnapshot.Stopovers); } aircraftJson.SecondsTracked = (long)((now - aircraftSnapshot.FirstSeen).TotalSeconds); if (args.ShowShortTrail) { if (aircraftSnapshot.ShortCoordinates.Count > 0) { BuildCoordinatesList(true, firstTimeSeen, aircraftJson, aircraftSnapshot, args); } } else { if (aircraftSnapshot.FullCoordinates.Count > 0) { BuildCoordinatesList(false, firstTimeSeen, aircraftJson, aircraftSnapshot, args); } } aircraftListJson.Aircraft.Add(aircraftJson); } }
/// <summary> /// Copies the aircraft from the snapshot to the JSON object. /// </summary> /// <param name="aircraftListJson"></param> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> private void CopyAircraft(AircraftListJson aircraftListJson, List<IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary<int, double?> distances) { var now = _Provider.UtcNow; foreach(var aircraftSnapshot in aircraftListSnapshot) { double? distance; if(!distances.TryGetValue(aircraftSnapshot.UniqueId, out distance)) distance = null; var aircraftJson = new AircraftJson() { BearingFromHere = GreatCircleMaths.Bearing(args.BrowserLatitude, args.BrowserLongitude, aircraftSnapshot.Latitude, aircraftSnapshot.Longitude, null, false, true), DistanceFromHere = distance == null ? (double?)null : Math.Round(distance.Value, 2), UniqueId = aircraftSnapshot.UniqueId, }; if(aircraftJson.BearingFromHere != null) aircraftJson.BearingFromHere = Math.Round(aircraftJson.BearingFromHere.Value, 1); bool firstTimeSeen = !args.PreviousAircraft.Contains(aircraftSnapshot.UniqueId); if(firstTimeSeen || aircraftSnapshot.AltitudeChanged > args.PreviousDataVersion) aircraftJson.Altitude = aircraftSnapshot.Altitude; if(firstTimeSeen || aircraftSnapshot.CallsignChanged > args.PreviousDataVersion) aircraftJson.Callsign = aircraftSnapshot.Callsign; if(firstTimeSeen || aircraftSnapshot.CallsignIsSuspectChanged > args.PreviousDataVersion) aircraftJson.CallsignIsSuspect = aircraftSnapshot.CallsignIsSuspect; if(firstTimeSeen || aircraftSnapshot.ConstructionNumberChanged > args.PreviousDataVersion) aircraftJson.ConstructionNumber = aircraftSnapshot.ConstructionNumber; if(firstTimeSeen || aircraftSnapshot.CountMessagesReceivedChanged > args.PreviousDataVersion) aircraftJson.CountMessagesReceived = aircraftSnapshot.CountMessagesReceived; if(firstTimeSeen || aircraftSnapshot.DestinationChanged > args.PreviousDataVersion) aircraftJson.Destination = aircraftSnapshot.Destination; if(firstTimeSeen || aircraftSnapshot.GroundSpeedChanged > args.PreviousDataVersion) aircraftJson.GroundSpeed = Round.GroundSpeed(aircraftSnapshot.GroundSpeed); if(firstTimeSeen || aircraftSnapshot.EmergencyChanged > args.PreviousDataVersion) aircraftJson.Emergency = aircraftSnapshot.Emergency; if(firstTimeSeen || aircraftSnapshot.EngineTypeChanged > args.PreviousDataVersion) aircraftJson.EngineType = (int)aircraftSnapshot.EngineType; if(firstTimeSeen || aircraftSnapshot.FirstSeenChanged > args.PreviousDataVersion) aircraftJson.FirstSeen = aircraftSnapshot.FirstSeen; if(firstTimeSeen || aircraftSnapshot.FlightsCountChanged > args.PreviousDataVersion) aircraftJson.FlightsCount = aircraftSnapshot.FlightsCount; if(firstTimeSeen || aircraftSnapshot.PictureFileNameChanged > args.PreviousDataVersion) aircraftJson.HasPicture = !String.IsNullOrEmpty(aircraftSnapshot.PictureFileName); if(firstTimeSeen || aircraftSnapshot.Icao24Changed > args.PreviousDataVersion) aircraftJson.Icao24 = aircraftSnapshot.Icao24; if(firstTimeSeen || aircraftSnapshot.Icao24CountryChanged > args.PreviousDataVersion) aircraftJson.Icao24Country = aircraftSnapshot.Icao24Country; if(firstTimeSeen || aircraftSnapshot.Icao24InvalidChanged > args.PreviousDataVersion) aircraftJson.Icao24Invalid = aircraftSnapshot.Icao24Invalid; if(firstTimeSeen || aircraftSnapshot.IsMilitaryChanged > args.PreviousDataVersion) aircraftJson.IsMilitary = aircraftSnapshot.IsMilitary; if(firstTimeSeen || aircraftSnapshot.IsInterestingChanged > args.PreviousDataVersion) aircraftJson.IsInteresting = aircraftSnapshot.IsInteresting; if(firstTimeSeen || aircraftSnapshot.LatitudeChanged > args.PreviousDataVersion) aircraftJson.Latitude = Round.Coordinate(aircraftSnapshot.Latitude); if(firstTimeSeen || aircraftSnapshot.LongitudeChanged > args.PreviousDataVersion) aircraftJson.Longitude = Round.Coordinate(aircraftSnapshot.Longitude); if(firstTimeSeen || aircraftSnapshot.ModelChanged > args.PreviousDataVersion) aircraftJson.Model = aircraftSnapshot.Model; if(firstTimeSeen || aircraftSnapshot.NumberOfEnginesChanged > args.PreviousDataVersion) aircraftJson.NumberOfEngines = aircraftSnapshot.NumberOfEngines; if(firstTimeSeen || aircraftSnapshot.OnGroundChanged > args.PreviousDataVersion) aircraftJson.OnGround = aircraftSnapshot.OnGround; if(firstTimeSeen || aircraftSnapshot.OperatorChanged > args.PreviousDataVersion) aircraftJson.Operator = aircraftSnapshot.Operator; if(firstTimeSeen || aircraftSnapshot.OperatorIcaoChanged > args.PreviousDataVersion) aircraftJson.OperatorIcao = aircraftSnapshot.OperatorIcao; if(firstTimeSeen || aircraftSnapshot.OriginChanged > args.PreviousDataVersion) aircraftJson.Origin = aircraftSnapshot.Origin; if(firstTimeSeen || aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) aircraftJson.PositionTime = aircraftSnapshot.PositionTime == null ? (long?)null : JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value); if(firstTimeSeen || aircraftSnapshot.RegistrationChanged > args.PreviousDataVersion) aircraftJson.Registration = aircraftSnapshot.Registration; if(firstTimeSeen || aircraftSnapshot.SpeciesChanged > args.PreviousDataVersion) aircraftJson.Species = (int)aircraftSnapshot.Species; if(firstTimeSeen || aircraftSnapshot.SpeedTypeChanged > args.PreviousDataVersion) aircraftJson.SpeedType = (int)aircraftSnapshot.SpeedType; if(firstTimeSeen || aircraftSnapshot.SquawkChanged > args.PreviousDataVersion) aircraftJson.Squawk = String.Format("{0:0000}", aircraftSnapshot.Squawk); if(firstTimeSeen || aircraftSnapshot.TrackChanged > args.PreviousDataVersion) aircraftJson.Track = Round.Track(aircraftSnapshot.Track); if(firstTimeSeen || aircraftSnapshot.TypeChanged > args.PreviousDataVersion) aircraftJson.Type = aircraftSnapshot.Type; if(firstTimeSeen || aircraftSnapshot.UserTagChanged > args.PreviousDataVersion) aircraftJson.UserTag = aircraftSnapshot.UserTag; if(firstTimeSeen || aircraftSnapshot.VerticalRateChanged > args.PreviousDataVersion) aircraftJson.VerticalRate = aircraftSnapshot.VerticalRate; if(firstTimeSeen || aircraftSnapshot.WakeTurbulenceCategoryChanged > args.PreviousDataVersion) aircraftJson.WakeTurbulenceCategory = (int)aircraftSnapshot.WakeTurbulenceCategory; if(aircraftSnapshot.Stopovers.Count > 0 && (firstTimeSeen || aircraftSnapshot.StopoversChanged > args.PreviousDataVersion)) { aircraftJson.Stopovers = new List<string>(); aircraftJson.Stopovers.AddRange(aircraftSnapshot.Stopovers); } aircraftJson.SecondsTracked = (long)((now - aircraftSnapshot.FirstSeen).TotalSeconds); if(args.ShowShortTrail) { if(aircraftSnapshot.ShortCoordinates.Count > 0) { BuildCoordinatesList(true, firstTimeSeen, aircraftJson, aircraftSnapshot, args); } } else { if(aircraftSnapshot.FullCoordinates.Count > 0) { BuildCoordinatesList(false, firstTimeSeen, aircraftJson, aircraftSnapshot, args); } } aircraftListJson.Aircraft.Add(aircraftJson); } }
/// <summary> /// Returns a filtered list of aircraft and at the same time calculates the distances from the browser location to each aircraft. /// </summary> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> /// <returns></returns> /// <remarks>Distance calculations can be expensive, hence the reason why we try to minimise the number of times that they are performed.</remarks> private List <IAircraft> FilterAircraft(List <IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, ref Dictionary <int, double?> distances) { List <IAircraft> result = new List <IAircraft>(); foreach (var aircraft in aircraftListSnapshot) { if (!PassesFilter(aircraft, args.Filter)) { continue; } var distance = args.IsFlightSimulatorList ? null : GreatCircleMaths.Distance(args.BrowserLatitude, args.BrowserLongitude, aircraft.Latitude, aircraft.Longitude); if (args.Filter != null) { if (args.Filter.DistanceLower != null && (distance == null || distance < args.Filter.DistanceLower)) { continue; } if (args.Filter.DistanceUpper != null && (distance == null || distance > args.Filter.DistanceUpper)) { continue; } } result.Add(aircraft); distances.Add(aircraft.UniqueId, distance); } return(result); }
/// <summary> /// Creates an object that holds all of the aircraft list arguments that were extracted from the request. /// </summary> /// <param name="args"></param> /// <param name="aircraftList"></param> /// <param name="isFlightSimulator"></param> /// <returns></returns> private AircraftListJsonBuilderArgs ConstructBuildArgs(RequestReceivedEventArgs args, IAircraftList aircraftList, bool isFlightSimulator) { var result = new AircraftListJsonBuilderArgs() { AircraftList = aircraftList, BrowserLatitude = QueryNDouble(args, "lat"), BrowserLongitude = QueryNDouble(args, "lng"), Filter = isFlightSimulator ? null : ConstructFilter(args), IsFlightSimulatorList = isFlightSimulator, IsInternetClient = args.IsInternetRequest, PreviousDataVersion = QueryLong(args, "ldv", -1), ResendTrails = QueryString(args, "refreshTrails", false) == "1", ShowShortTrail = QueryString(args, "trFmt", true) == "S", }; for(int sortColumnCount = 0;sortColumnCount < 2;++sortColumnCount) { var sortColumn = QueryString(args, String.Format("sortBy{0}", sortColumnCount + 1), true); var sortOrder = QueryString(args, String.Format("sortOrder{0}", sortColumnCount + 1), true); if(String.IsNullOrEmpty(sortColumn) || String.IsNullOrEmpty(sortOrder)) break; result.SortBy.Add(new KeyValuePair<string,bool>(sortColumn, sortOrder == "ASC")); } if(result.SortBy.Count == 0) result.SortBy.Add(new KeyValuePair<string,bool>(AircraftComparerColumn.FirstSeen, false)); var previousAircraftIds = args.Request.Headers["X-VirtualRadarServer-AircraftIds"]; if(!String.IsNullOrEmpty(previousAircraftIds)) { var decodedPreviousAircraftIds = HttpUtility.UrlDecode(previousAircraftIds); foreach(var chunk in decodedPreviousAircraftIds.Split(',')) { int id; if(int.TryParse(chunk, out id)) result.PreviousAircraft.Add(id); } } return result; }
/// <summary> /// Returns a fully-formed <see cref="AircraftListJson"/> from the aircraft list passed across. /// </summary> /// <param name="args"></param> /// <returns></returns> public AircraftListJson Build(AircraftListJsonBuilderArgs args) { if(args == null) throw new ArgumentNullException("aircraftList"); if(args.AircraftList == null) throw new InvalidOperationException("The AircraftList must be supplied"); var result = new AircraftListJson() { FlagHeight = 20, FlagWidth = 85, ShowFlags = _ShowFlags && !args.IsFlightSimulatorList, ShowPictures = _ShowPictures && (!args.IsInternetClient || _ShowPicturesToInternetClients) && !args.IsFlightSimulatorList, ShowSilhouettes = _ShowSilhouettes && !args.IsFlightSimulatorList, ShortTrailLengthSeconds = _ShortTrailLength, Source = (int)args.AircraftList.Source, }; long timestamp, dataVersion; var aircraft = args.AircraftList.TakeSnapshot(out timestamp, out dataVersion); result.AvailableAircraft = aircraft.Count; result.LastDataVersion = dataVersion.ToString(); result.ServerTime = JavascriptHelper.ToJavascriptTicks(timestamp); Dictionary<int, double?> distances = new Dictionary<int,double?>(); aircraft = FilterAircraft(aircraft, args, ref distances); SortAircraft(aircraft, args, distances); CopyAircraft(result, aircraft, args, distances); return result; }
/// <summary> /// Sorts the aircraft list using the parameters in the args object. /// </summary> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param>] /// <param name="distances"></param> private void SortAircraft(List<IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, Dictionary<int, double?> distances) { IAircraftComparer comparer = Factory.Singleton.Resolve<IAircraftComparer>(); comparer.BrowserLocation = args.BrowserLatitude == null || args.BrowserLongitude == null ? null : new Coordinate((float)args.BrowserLatitude, (float)args.BrowserLongitude); foreach(var sortBy in args.SortBy) { comparer.SortBy.Add(sortBy); } foreach(var distance in distances) { comparer.PrecalculatedDistances.Add(distance.Key, distance.Value); } aircraftListSnapshot.Sort(comparer); }
/// <summary> /// Returns a filtered list of aircraft and at the same time calculates the distances from the browser location to each aircraft. /// </summary> /// <param name="aircraftListSnapshot"></param> /// <param name="args"></param> /// <param name="distances"></param> /// <returns></returns> /// <remarks>Distance calculations can be expensive, hence the reason why we try to minimise the number of times that they are performed.</remarks> private List<IAircraft> FilterAircraft(List<IAircraft> aircraftListSnapshot, AircraftListJsonBuilderArgs args, ref Dictionary<int, double?> distances) { List<IAircraft> result = new List<IAircraft>(); foreach(var aircraft in aircraftListSnapshot) { if(!PassesFilter(aircraft, args.Filter)) continue; var distance = args.IsFlightSimulatorList ? null : GreatCircleMaths.Distance(args.BrowserLatitude, args.BrowserLongitude, aircraft.Latitude, aircraft.Longitude); if(args.Filter != null) { if(args.Filter.DistanceLower != null && (distance == null || distance < args.Filter.DistanceLower)) continue; if(args.Filter.DistanceUpper != null && (distance == null || distance > args.Filter.DistanceUpper)) continue; } result.Add(aircraft); distances.Add(aircraft.UniqueId, distance); } return result; }
/// <summary> /// Returns true if the aircraft passes the filter criteria passed across. /// </summary> /// <param name="aircraft"></param> /// <param name="args"></param> /// <param name="distances"></param> /// <returns></returns> private bool PassesFilter(IAircraft aircraft, AircraftListJsonBuilderArgs args, Dictionary <int, double?> distances) { var filter = args.Filter; bool result = filter == null; var distance = args.IsFlightSimulatorList ? null : GreatCircleMaths.Distance(args.BrowserLatitude, args.BrowserLongitude, aircraft.Latitude, aircraft.Longitude); if (!result) { result = true; if (result && filter.Altitude != null) { result = filter.Altitude.Passes(aircraft.Altitude); } if (result && filter.Callsign != null) { result = filter.Callsign.Passes(aircraft.Callsign); } if (result && filter.EngineType != null) { result = filter.EngineType.Passes(aircraft.EngineType); } if (result && filter.Icao24 != null) { result = filter.Icao24.Passes(aircraft.Icao24); } if (result && filter.Icao24Country != null) { result = filter.Icao24Country.Passes(aircraft.Icao24Country); } if (result && filter.IsInteresting != null) { result = filter.IsInteresting.Passes(aircraft.IsInteresting); } if (result && filter.IsMilitary != null) { result = filter.IsMilitary.Passes(aircraft.IsMilitary); } if (result && filter.MustTransmitPosition != null) { result = filter.MustTransmitPosition.Passes(aircraft.Latitude != null && aircraft.Longitude != null); } if (result && filter.Operator != null) { result = filter.Operator.Passes(aircraft.Operator); } if (result && filter.OperatorIcao != null) { result = filter.OperatorIcao.Passes(aircraft.OperatorIcao); } if (result && filter.PositionWithin != null) { result = args.SelectedAircraftId == aircraft.UniqueId || IsWithinBounds(aircraft.Latitude, aircraft.Longitude, filter.PositionWithin); } if (result && filter.Registration != null) { result = filter.Registration.Passes(aircraft.Registration); } if (result && filter.Species != null) { result = filter.Species.Passes(aircraft.Species); } if (result && filter.Squawk != null) { result = filter.Squawk.Passes(aircraft.Squawk); } if (result && filter.Type != null) { result = filter.Type.Passes(aircraft.Type); } if (result && filter.UserTag != null) { result = filter.UserTag.Passes(aircraft.UserTag); } if (result && filter.WakeTurbulenceCategory != null) { result = filter.WakeTurbulenceCategory.Passes(aircraft.WakeTurbulenceCategory); } if (result && filter.Airport != null) { result = PassesAirportFilter(filter.Airport, aircraft); } if (result && filter.Distance != null) { if (distance == null && filter.Distance.IsValid) { result = false; } else { result = filter.Distance.Passes(distance); } } } if (result) { distances.Add(aircraft.UniqueId, distance); } return(result); }
/// <summary> /// Creates an object that holds all of the aircraft list arguments that were extracted from the request. /// </summary> /// <param name="args"></param> /// <param name="feedId"></param> /// <param name="aircraftList"></param> /// <param name="isFlightSimulator"></param> /// <returns></returns> private AircraftListJsonBuilderArgs ConstructBuildArgs(RequestReceivedEventArgs args, int feedId, IAircraftList aircraftList, bool isFlightSimulator) { var result = new AircraftListJsonBuilderArgs() { AircraftList = aircraftList, BrowserLatitude = QueryNDouble(args, "lat"), BrowserLongitude = QueryNDouble(args, "lng"), Filter = isFlightSimulator ? null : ConstructFilter(args), IsFlightSimulatorList = isFlightSimulator, IsInternetClient = args.IsInternetRequest, PreviousDataVersion = QueryLong(args, "ldv", -1), ServerTimeTicks = QueryLong(args, "stm", -1), ResendTrails = QueryString(args, "refreshTrails", false) == "1", SelectedAircraftId = QueryInt(args, "selAc", -1), SourceFeedId = feedId, }; var trFmt = QueryString(args, "trFmt", true); if (!String.IsNullOrEmpty(trFmt)) { switch (trFmt) { case "F": result.TrailType = TrailType.Full; break; case "FA": result.TrailType = TrailType.FullAltitude; break; case "FS": result.TrailType = TrailType.FullSpeed; break; case "S": result.TrailType = TrailType.Short; break; case "SA": result.TrailType = TrailType.ShortAltitude; break; case "SS": result.TrailType = TrailType.ShortSpeed; break; } } for (int sortColumnCount = 0; sortColumnCount < 2; ++sortColumnCount) { var sortColumn = QueryString(args, String.Format("sortBy{0}", sortColumnCount + 1), true); var sortOrder = QueryString(args, String.Format("sortOrder{0}", sortColumnCount + 1), true); if (String.IsNullOrEmpty(sortColumn) || String.IsNullOrEmpty(sortOrder)) { break; } result.SortBy.Add(new KeyValuePair <string, bool>(sortColumn, sortOrder == "ASC")); } if (result.SortBy.Count == 0) { result.SortBy.Add(new KeyValuePair <string, bool>(AircraftComparerColumn.FirstSeen, false)); } if ((args.Request.HttpMethod ?? "").ToUpper() == "POST") { ExtractPreviousAircraftIdsFromPostBody(args.Request, result.PreviousAircraft); } else { ExtractPreviousAircraftIdsFromHeader(args.Request, result.PreviousAircraft); } return(result); }
/// <summary> /// Builds the full or short coordinates list and attaches it to the aircraft JSON object. /// </summary> /// <param name="shortCoordinates"></param> /// <param name="firstTimeSeen"></param> /// <param name="aircraftJson"></param> /// <param name="aircraftSnapshot"></param> /// <param name="args"></param> private void BuildCoordinatesList(bool shortCoordinates, bool firstTimeSeen, AircraftJson aircraftJson, IAircraft aircraftSnapshot, AircraftListJsonBuilderArgs args) { aircraftJson.ResetTrail = firstTimeSeen || args.ResendTrails || aircraftSnapshot.FirstCoordinateChanged > args.PreviousDataVersion; List<double?> list = new List<double?>(); Coordinate lastCoordinate = null; foreach(var coordindate in shortCoordinates ? aircraftSnapshot.ShortCoordinates : aircraftSnapshot.FullCoordinates) { if(aircraftJson.ResetTrail || coordindate.DataVersion > args.PreviousDataVersion) { list.Add(Round.Coordinate(coordindate.Latitude)); list.Add(Round.Coordinate(coordindate.Longitude)); if(shortCoordinates) list.Add(JavascriptHelper.ToJavascriptTicks(coordindate.Tick)); else list.Add(Round.Track(coordindate.Heading)); } lastCoordinate = coordindate; } if(aircraftSnapshot.Latitude != null && aircraftSnapshot.Longitude != null && (lastCoordinate.Latitude != aircraftSnapshot.Latitude || lastCoordinate.Longitude != aircraftSnapshot.Longitude) && aircraftSnapshot.PositionTimeChanged > args.PreviousDataVersion) { list.Add(Round.Coordinate(aircraftSnapshot.Latitude)); list.Add(Round.Coordinate(aircraftSnapshot.Longitude)); if(shortCoordinates) list.Add(JavascriptHelper.ToJavascriptTicks(aircraftSnapshot.PositionTime.Value)); else list.Add(Round.Track(aircraftSnapshot.Track)); } if(list.Count != 0) { if(shortCoordinates) aircraftJson.ShortCoordinates = list; else aircraftJson.FullCoordinates = list; } }