public override void Configuration(IAppBuilder app) { var httpConfig = new HttpConfiguration(); // this now returns ContainerBuilder instead of the container var builder = AutofacSetup.Register(httpConfig) // register your mock, change this to whatever lifetime scope you need var moqAirportCollection = new AirportCollection(); moqAirportCollection.Airports = new List <Airport> { new Airport { IATA = "moq", Name = "moqName" } }; var mock = AutoMock.GetLoose() var moqObj = MockObj = mock.Mock <IAirportService>() .Setup(x => x.GetAirports()) .Returns(moqAirportCollection); builder.Register <IAirportService>(() => moqObj); container = builder.Build(); WebApiConfig.Register(httpConfig); appBuilder.UseAutofacMiddleware(container); appBuilder.UseAutofacWebApi(httpConfig); appBuilder.UseWebApi(httpConfig); }
/// <summary> /// Master constructor for the "top level" of our application /// TODO: create a factory method if initialization becomes complicated. Not needed now /// </summary> public FlightProcessor() { airports = AirportCollection.LoadFromFile(AirportsFilePath); ProcessingType = "file"; EventsQueue = new ConcurrentQueue <AdsbEvent>(); FlightsQueue = new ConcurrentQueue <Flight>(); MainEventProcessor = new EventProcessor(FlightsQueue, airports); }
/// <summary> /// Master constructor is used for unit tests. Clean it up later /// </summary> public FlightProcessor(string airportFile, string eventFile, string debugAirplane) { airports = AirportCollection.LoadFromFile(airportFile); ProcessingType = "file"; EventsQueue = new ConcurrentQueue <AdsbEvent>(); FlightsQueue = new ConcurrentQueue <Flight>(); MainEventProcessor = new EventProcessor(FlightsQueue, airports); AdsbEventsFilePath = eventFile; DEBUG_FLIGHT = debugAirplane; }
private static void Execute() { // Load the input data AirportCollection airports = AirportCollection.LoadFromFile(AirportsFilePath); AdsbEventCollection events = AdsbEventCollection.LoadFromFile(AdsbEventsFilePath); // Create collection of identifiable flights FlightCollection flights = CalculateFlights(airports, events); // Write the output data flights.WriteToFile(OutputFilePath); }
/// <summary> /// Cntsructor. sets all the appropriate variables /// </summary> public AirplaneEventProcessor(IndividualAirplane individualAirplane, ConcurrentQueue <Flight> outputQueue, AirportCollection airportDB) { AirplaneProcessed = individualAirplane; FlightsQueue = outputQueue; Airports = airportDB; LastEvent = null; CurrentStatus = AirplaneStatus.UNKNOWN; LastKnownPosition = null; LastGrounded = null; LastTakeoff = null; LastDeviceSpeed = null; LastDeviceSpeedTime = null; }
public AirportCollection GetAllAirports() { AirportCollection results = new AirportCollection(); IList list = AdoTemplate.QueryWithRowMapper(CommandType.Text, "SELECT * FROM airport", airportMapper); //TODO - add support to queries for supplying own collection implementation? // Why not using IResultSetExtrator ? foreach (Airport airport in list) { results.Add(airport); } return(results); }
private static void Execute() { // Load the airports AirportCollection airports = AirportCollection.LoadFromFile(AirportsFilePath); }
private static FlightCollection CalculateFlights(AirportCollection airports, AdsbEventCollection events) { // Organize all ADS-B events by aircraft ID FlightCollection flights = new FlightCollection(); Dictionary <string, List <AdsbEvent> > eventsByID = new Dictionary <string, List <AdsbEvent> >(); foreach (AdsbEvent adsbEvent in events.Events) { if (!eventsByID.ContainsKey(adsbEvent.Identifier)) { eventsByID.Add(adsbEvent.Identifier, new List <AdsbEvent>()); eventsByID[adsbEvent.Identifier].Add(adsbEvent); } else { // Remove events that are soon after the previous one to improve performance int eventCount = eventsByID[adsbEvent.Identifier].Count; AdsbEvent lastEvent = eventsByID[adsbEvent.Identifier][eventCount - 1]; TimeSpan timeDiff = adsbEvent.Timestamp - lastEvent.Timestamp; if (timeDiff.TotalSeconds >= TimeThreshold) { eventsByID[adsbEvent.Identifier].Add(adsbEvent); } } } // For each aircraft identifier, step through the logged events in sequence to identify flights foreach (string identifier in eventsByID.Keys) { List <AdsbEvent> eventLog = eventsByID[identifier]; FlightStatus flightStatus = FlightStatus.Unknown; Airport lastAirport = new Airport(); DateTime lastGroundTime = DateTime.MinValue; foreach (AdsbEvent adsbEvent in eventLog) { // Find closest airport to the logged coordinates, as long as the event has coordinate values GeoCoordinate eventLoc = new GeoCoordinate(adsbEvent.Latitude ?? double.NaN, adsbEvent.Longitude ?? double.NaN); if (eventLoc.HasLocation()) { Airport closestAirport = airports.GetClosestAirport(eventLoc); GeoCoordinate airportLoc = new GeoCoordinate(closestAirport.Latitude, closestAirport.Longitude); double airportDistance = eventLoc.GetDistanceTo(airportLoc); double altitudeDiff = adsbEvent.Altitude.HasValue ? Math.Abs(adsbEvent.Altitude.Value - closestAirport.Elevation) : 0f; double speed = adsbEvent.Speed ?? 0f; // If the event was logged close to an airport, assume the aircraft has landed at that airport if (airportDistance <= DistanceThreshold && altitudeDiff <= AltitudeThreshold && speed <= SpeedThreshold) { // If this is not the first event (status unknown) and the new closest airport is different, create a new completed flight record if (flightStatus != FlightStatus.Unknown && closestAirport.Identifier != lastAirport.Identifier) { flights.Flights.Add(new Flight { AircraftIdentifier = identifier, DepartureTime = lastGroundTime, DepartureAirport = lastAirport.Identifier, ArrivalTime = adsbEvent.Timestamp, ArrivalAirport = closestAirport.Identifier }); } // In any case, update the status for the new airport flightStatus = FlightStatus.Ground; lastAirport = closestAirport; lastGroundTime = adsbEvent.Timestamp; } // If the aircraft is not close to an airport and was not previously flying, set the status to airborne else if ((airportDistance > DistanceThreshold || altitudeDiff > AltitudeThreshold) && flightStatus != FlightStatus.Air) { flightStatus = FlightStatus.Air; } // Otherwise, assume no status change } } // If all events have been read and the aircraft was last known to be flying, record a final flight with no arrival if (flightStatus == FlightStatus.Air) { flights.Flights.Add(new Flight { AircraftIdentifier = identifier, DepartureTime = lastGroundTime, DepartureAirport = lastAirport.Identifier, ArrivalTime = DateTime.MaxValue, ArrivalAirport = null }); } } return(flights); }
private static void Execute() { // Load the airports AirportCollection airports = AirportCollection.LoadFromFile(AirportsFilePath); var fileLines = System.IO.File.ReadAllLines(AdsbEventsFilePath); Dictionary <string, List <AdsbEvent> > airplanes = new Dictionary <string, List <AdsbEvent> >(); foreach (var line in fileLines) { string airplaneId = Events.AdsbEvent.FromJson(line).Identifier; if (airplanes.ContainsKey(airplaneId)) { airplanes[airplaneId].Add(Events.AdsbEvent.FromJson(line)); } else { List <AdsbEvent> tmpEventList = new List <AdsbEvent>() { Events.AdsbEvent.FromJson(line) }; airplanes.Add(Events.AdsbEvent.FromJson(line).Identifier, tmpEventList); } } System.IO.StreamWriter outFile = new System.IO.StreamWriter(OutputFilePath); foreach (var key in airplanes.Keys) { // debug output // System.Console.WriteLine(key); // setting defaults DateTime prevTime = DateTime.Parse("1/01/2020 12:00:00 AM"); GeoCoordinate prevAirportLocation = null; Airport prevAirport = null; Flight flight = new Flight(); flight.AircraftIdentifier = key; foreach (var adsbEventEntry in airplanes[key]) { // create a geolocation based on airplane adsb event coords string latLong = adsbEventEntry.Latitude.ToString() + "," + adsbEventEntry.Longitude.ToString(); GeoCoordinate airplaneLocation = GeoCoordinate.FromLatitudeAndLongitudeString(latLong); // get closest airport based on current airplane location Airport tempAirport = airports.GetClosestAirport(airplaneLocation); // create airport geolocation string airportLatLong = tempAirport.Latitude.ToString() + "," + tempAirport.Longitude.ToString(); GeoCoordinate airportLocation = GeoCoordinate.FromLatitudeAndLongitudeString(airportLatLong); // In order for an event to be a landing/takeoff: // 1. geolocation within 5 miles of an airport (Flight safety, no unregistered aircraft within 5 miles of an airport) // 2. altitude diff within 500 feet (safety altitude) // 3. take off and landing speed < 200 mph // In order for an airport to have a takeoff for this airplane: // 1. The timestamp reads must have a difference > 30 mins // Airplane heading and speed is not always present in adsbevent data, which means we can't rely on it to determine landing vs takeoff double tempDist = airplaneLocation.GetDistanceTo(airportLocation); if (tempDist < 5) { if (adsbEventEntry.Altitude != null && (adsbEventEntry.Altitude - tempAirport.Elevation <= 500) && adsbEventEntry.Speed != null && adsbEventEntry.Speed <= 200) { //did some reasearch, it looks like it takes the crew around 30-60 mins to get the plane checked again for next flight if (adsbEventEntry.Timestamp - prevTime > TimeSpan.Parse("00:30:00")) { // logic for arrivals and departures if (prevAirportLocation != null && prevAirportLocation != airportLocation) { //only departure is added w/ previous timestamp flight.DepartureTime = prevTime; flight.DepartureAirport = prevAirport.Identifier; } else if (prevAirportLocation == airportLocation) { //arrival is added w/ previous timestamp flight.ArrivalTime = prevTime; flight.ArrivalAirport = prevAirport.Identifier; } } prevAirportLocation = airportLocation; prevTime = adsbEventEntry.Timestamp; prevAirport = tempAirport; } } //record flights if arrival time is populated if (flight.ArrivalAirport != null) { outFile.WriteLine(flight.ToString()); flight = new Flight(); flight.AircraftIdentifier = key; } } } outFile.Close(); }
private static void Execute() { // Process data files var airports = AirportCollection.LoadFromFile(AirportsFilePath); var adsbEvents = LoadFromFile(AdsbEventsFilePath); Console.WriteLine($"Loaded {airports.Count} airports and {adsbEvents.Count} events"); // Sort events by aircraft var allAircraft = new Dictionary <string, Aircraft>(); adsbEvents.ForEach((adsbEvent) => { if (allAircraft.TryGetValue(adsbEvent.Identifier, out Aircraft aircraft)) { aircraft.AdsbEvents.Add(adsbEvent); } else { allAircraft.Add(adsbEvent.Identifier, new Aircraft(adsbEvent.Identifier, new List <AdsbEvent>() { adsbEvent })); } }); Console.WriteLine($"Identified {allAircraft.Count} aircraft"); // Find potential flights var flights = new List <Flight>(); allAircraft.Select(kv => kv.Value).ToList().ForEach((aircraft) => { var flight = new Flight() { AircraftIdentifier = aircraft.AircraftIdentifier }; // Filter out events without coordinates var aircraftEvents = aircraft.AdsbEvents .Where(adsbEvent => adsbEvent.Latitude != null && adsbEvent.Longitude != null) .OrderBy(adsbEvent => adsbEvent.Timestamp); // Implement a sliding window by analyzing the altitude data // This could also be implemented by analyzing the speed data, but the altitude data is // more consistent var events = aircraftEvents.Where(adsbEvent => adsbEvent.Altitude != null); var step = 10; var sampleSize = 25; var previousTrend = Trend.Unknown; // Check the start events for departure var startSample = events.Take(sampleSize); if (startSample.First().Altitude < startSample.Last().Altitude) { flight.DepartureTime = events.First().Timestamp; flight.DepartureAirport = airports.GetClosestAirport(events.First().GeoCoordinate).Identifier; } // Check the middle events for additional flights for (var i = 0; i < events.Count() - sampleSize; i += step) { var sample = events.Skip(i).Take(sampleSize); var currentTrend = GuessTrend(sample.Select(adsbEvent => adsbEvent.Altitude.Value)); // If the aircraft's altitude trend changes from decreasing to increasing below the altitude threshold, // assume that it's started a new flight if (previousTrend == Trend.Decrease && currentTrend == Trend.Increase && sample.First().Altitude < MAX_ALTITUDE) { var airport = airports.GetClosestAirport(sample.First().GeoCoordinate); // If there isn't an airport nearby, the airplane may have made an unexpected descent and ascent if (airport == null) { continue; } // Check if the aircraft is flying over the airport if (Math.Abs(airport.Elevation - sample.First().Altitude.Value) >= GROUND_TOLERANCE) { continue; } flight.ArrivalTime = sample.First().Timestamp; flight.ArrivalAirport = airport.Identifier; flights.Add(flight); flight = new Flight { AircraftIdentifier = aircraft.AircraftIdentifier, DepartureTime = sample.Last().Timestamp, DepartureAirport = airports.GetClosestAirport(sample.Last().GeoCoordinate).Identifier }; } previousTrend = currentTrend; } // Check the end events for arrival var endSample = events.TakeLast(sampleSize); if (endSample.First().Altitude > endSample.Last().Altitude) { flight.ArrivalTime = events.Last().Timestamp; flight.ArrivalAirport = airports.GetClosestAirport(events.Last().GeoCoordinate).Identifier; } if (flight.DepartureAirport != null || flight.ArrivalAirport != null) { flights.Add(flight); } }); Console.WriteLine($"Identified {flights.Count} potential flights"); WriteResults(flights); }
public EventProcessor(ConcurrentQueue <Flight> outputQueue, AirportCollection airportDB) { IndividualPlaneProcessor = new Dictionary <string, AirplaneEventProcessor>(); FlightsQueue = outputQueue; Airports = airportDB; }