private static void CalculateTravelTime(esriNetworkTimeUsage timeUsage, double secondsSinceMidnight, trip_instance instance, ref double final_travel_time) { // Going forward in time if (timeUsage == esriNetworkTimeUsage.esriNTUBeforeTraversal) { // Select only those trips with a start time after the query time. // Use a half-second for padding to avoid small rounding errors that come out of core Network Analyst if (instance.start_time >= secondsSinceMidnight - 0.5) { double travel_time = instance.end_time - secondsSinceMidnight; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } // Going backward in time else //esriNetworkTimeUsage.esriNTUAfterTraversal { // Select only those trips with an end time before the query time. if (instance.end_time <= secondsSinceMidnight + 0.5) { // How long between the query time and the time you ended your trip at that stop. double travel_time = secondsSinceMidnight - instance.start_time; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } }
private static void CalculateTravelTime(esriNetworkTimeUsage timeUsage, double secondsSinceMidnight, trip_instance instance, ref double final_travel_time) { // Going forward in time if (timeUsage == esriNetworkTimeUsage.esriNTUBeforeTraversal) { // Select only those trips with a start time after the query time. // Use a half-second for padding to avoid small rounding errors that come out of core Network Analyst if (instance.start_time >= secondsSinceMidnight-0.5) { double travel_time = instance.end_time - secondsSinceMidnight; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } // Going backward in time else //esriNetworkTimeUsage.esriNTUAfterTraversal { // Select only those trips with an end time before the query time. if (instance.end_time <= secondsSinceMidnight+0.5) { // How long between the query time and the time you ended your trip at that stop. double travel_time = secondsSinceMidnight - instance.start_time; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } }
public object QueryValueAtTime(INetworkElement element, DateTime queryTime, esriNetworkTimeUsage timeUsage) { if (m_VerboseLogging) ++m_queryValueAtTime_Count; int eid = element.EID; // Note that all query times are local times in the time zone of the network element. DateTime queryDate = queryTime.Date; DayOfWeek queryDayOfWeek = queryTime.DayOfWeek; List<trip_instance> trip_instances; // Get the trip instances associated with the EID if (m_eids.TryGetValue(eid, out trip_instances)) { // This is the query time in seconds since midnight. double seconds_since_midnight = queryTime.TimeOfDay.TotalSeconds; // This will be the final answer. // Initialize it to infinity. double final_travel_time = double.PositiveInfinity; // Initialize a variable showing the max start time of trip on this EID (which is sometimes after midnight because trips run into the next day) long max_trip_start_time = 0; ///////////////////////////////////////////////////// // Each network edge has a set of instances when a trip uses it. Each trip instance // contains a trip_id (unique), a start time, and an end time. We want to loop through all the // possible trips and find the one that minimizes overall travle time (wait time until the trip begins and // travel time to traverse the edge) and return that as the impedance of the edge. // Iterate through all trips with this EID. foreach (trip_instance instance in trip_instances) { // Get the trip object for this trip instance so we can determine if this trip should be considered. Trip tr; // PATRICK: Is there a way to get the trip without this boolean thing? bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // service_id is needed to determine calendar information // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // Figure out what the latest start time for trips on this element is. // We use this later when we consider trips running early in the day which // might have carryover from the previous day's trips. if (instance.start_time > max_trip_start_time) { max_trip_start_time = instance.start_time; } // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary<DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Three reasons to calculate a travel time on this trip: // 1) Solving against a general day of the week, and this trip runs on that day of the week // 2) Solving against a specific date of the year, and this trip has an added exception that day // 3) Specific day, falls within calendar date range, has trip that day // 1 bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripToday(queryDayOfWeek, cal)); // 2 // Consider the schedule date ranges and exceptions // Comparing dates for the key should be fine as long as the datetimes are created only using year, month, and day bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(queryDate)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[queryDate] == CalendarExceptionType.added); // 3 bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(queryDate, cal.start_date, cal.end_date) && HasTripToday(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[queryDate] == CalendarExceptionType.removed); // The one reason to be sure NOT to use this trip for this element if (isSpecificDayWithRemovedException) { continue; } // All of the reasons to figure out the traversal time for this element and this trip else if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { CalculateTravelTime(timeUsage, seconds_since_midnight, instance, ref final_travel_time); } } // Special conditions to check if our trip is occurring late in the day. // If our query time and min travel time pushes us past midnight, look at trips from the next day as well. // This only matters if we're going forward in time. if (timeUsage == esriNetworkTimeUsage.esriNTUBeforeTraversal && (seconds_since_midnight + final_travel_time) > SECONDS_IN_A_DAY) { // Find the date for the day after the query day. DateTime DayAfterQuery = queryDate.AddDays(1); foreach (trip_instance instance in trip_instances) { Trip tr; bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // How many seconds are left in the current day. double secondsLeftInDay = SECONDS_IN_A_DAY - seconds_since_midnight; // Ignore this trip if it starts after our current shortest travel time double seconds_since_midnight_tomorrow = (final_travel_time - secondsLeftInDay); bool tripStartsTooLate = (instance.start_time >= seconds_since_midnight_tomorrow-0.5); // Pad by half a second to avoid rounding errors if (tripStartsTooLate) continue; // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary<DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Reasons to calculate the travel time: // 1) Generic day of the week, has trip tomorrow bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripTomorrow(queryDayOfWeek, cal)); // 2) Specific date, has added exception bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(DayAfterQuery)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[DayAfterQuery] == CalendarExceptionType.added); // 3) Specific date, falls within date range, has trip tomorrow bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(DayAfterQuery, cal.start_date, cal.end_date) && HasTripTomorrow(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[DayAfterQuery] == CalendarExceptionType.removed); // All of the reasons to figure out the traversal time for this element and this trip if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { // Select only those trips starting before our current min travel time. if (instance.start_time <= seconds_since_midnight_tomorrow-0.5) { double travel_time = SECONDS_IN_A_DAY + instance.end_time - seconds_since_midnight; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } // The one reason to be sure NOT to use this trip for this element else if (isSpecificDayWithRemovedException) { continue; } } } // Special conditions if our trip is occurring early in the day // Only do this part if our trip is occurring before trips from the previous day have stopped running if (seconds_since_midnight-0.5 <= max_trip_start_time - SECONDS_IN_A_DAY) { // Figure out the query time in seconds since the previous day's midnight double secondsSinceMidnightYesterday = SECONDS_IN_A_DAY + seconds_since_midnight; // Find the date for the day prior to the query day. DateTime DayBeforeQuery = queryDate.AddDays(-1); foreach (trip_instance instance in trip_instances) { Trip tr; bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary<DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Reasons to calculate the travel time: // 1) Generic day of the week, has trip yesterday bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripYesterday(queryDayOfWeek, cal)); // 2) Specific date, has added exception bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(DayBeforeQuery)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[DayBeforeQuery] == CalendarExceptionType.added); // 3) Specific date, falls within date range, has trip tomorrow bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(DayBeforeQuery, cal.start_date, cal.end_date) && HasTripTomorrow(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[DayBeforeQuery] == CalendarExceptionType.removed); // All of the reasons to figure out the traversal time for this element and this trip if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { CalculateTravelTime(timeUsage, secondsSinceMidnightYesterday, instance, ref final_travel_time); } // The one reason to be sure NOT to use this trip for this element else if (isSpecificDayWithRemovedException) { continue; } } } // If we didn't find any valid trips at all, set it equal to -1 so it's not traversable. if (final_travel_time == double.PositiveInfinity) { return -1; } else { // Return the final minimum travel time across the element. // Divide by 60 to convert to minutes. return final_travel_time / 60.0; } } // If the EID wasn't even in our list, return -1. This should never happen. else { return -1; } }
public object QueryValueAtTime(INetworkElement element, DateTime queryTime, esriNetworkTimeUsage timeUsage) { // Grab the correct cache for this network Dictionary <string, Trip> m_trips = m_caches[m_workspace_path_name].m_trips; Dictionary <long, long> m_linefeatures = m_caches[m_workspace_path_name].m_linefeatures; Dictionary <string, Calendar> m_calendars = m_caches[m_workspace_path_name].m_calendars; Dictionary <string, Dictionary <DateTime, CalendarExceptionType> > m_calExceptions = m_caches[m_workspace_path_name].m_calExceptions; Dictionary <long, List <trip_instance> > m_eids = m_caches[m_workspace_path_name].m_eids; if (m_VerboseLogging) { ++m_queryValueAtTime_Count; } int eid = element.EID; // Note that all query times are local times in the time zone of the network element. DateTime queryDate = queryTime.Date; DayOfWeek queryDayOfWeek = queryTime.DayOfWeek; List <trip_instance> trip_instances; // Get the trip instances associated with the EID if (m_eids.TryGetValue(eid, out trip_instances)) { // This is the query time in seconds since midnight. double seconds_since_midnight = queryTime.TimeOfDay.TotalSeconds; // This will be the final answer. // Initialize it to infinity. double final_travel_time = double.PositiveInfinity; // Initialize a variable showing the max start time of trip on this EID (which is sometimes after midnight because trips run into the next day) long max_trip_start_time = 0; ///////////////////////////////////////////////////// // Each network edge has a set of instances when a trip uses it. Each trip instance // contains a trip_id (unique), a start time, and an end time. We want to loop through all the // possible trips and find the one that minimizes overall travle time (wait time until the trip begins and // travel time to traverse the edge) and return that as the impedance of the edge. // Iterate through all trips with this EID. foreach (trip_instance instance in trip_instances) { // Get the trip object for this trip instance so we can determine if this trip should be considered. Trip tr; // PATRICK: Is there a way to get the trip without this boolean thing? bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // service_id is needed to determine calendar information // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // Figure out what the latest start time for trips on this element is. // We use this later when we consider trips running early in the day which // might have carryover from the previous day's trips. if (instance.start_time > max_trip_start_time) { max_trip_start_time = instance.start_time; } // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary <DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Three reasons to calculate a travel time on this trip: // 1) Solving against a general day of the week, and this trip runs on that day of the week // 2) Solving against a specific date of the year, and this trip has an added exception that day // 3) Specific day, falls within calendar date range, has trip that day // 1 bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripToday(queryDayOfWeek, cal)); // 2 // Consider the schedule date ranges and exceptions // Comparing dates for the key should be fine as long as the datetimes are created only using year, month, and day bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(queryDate)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[queryDate] == CalendarExceptionType.added); // 3 bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(queryDate, cal.start_date, cal.end_date) && HasTripToday(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[queryDate] == CalendarExceptionType.removed); // The one reason to be sure NOT to use this trip for this element if (isSpecificDayWithRemovedException) { continue; } // All of the reasons to figure out the traversal time for this element and this trip else if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { CalculateTravelTime(timeUsage, seconds_since_midnight, instance, ref final_travel_time); } } // Special conditions to check if our trip is occurring late in the day. // If our query time and min travel time pushes us past midnight, look at trips from the next day as well. // This only matters if we're going forward in time. if (timeUsage == esriNetworkTimeUsage.esriNTUBeforeTraversal && (seconds_since_midnight + final_travel_time) > SECONDS_IN_A_DAY) { // Find the date for the day after the query day. DateTime DayAfterQuery = queryDate.AddDays(1); foreach (trip_instance instance in trip_instances) { Trip tr; bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // How many seconds are left in the current day. double secondsLeftInDay = SECONDS_IN_A_DAY - seconds_since_midnight; // Ignore this trip if it starts after our current shortest travel time double seconds_since_midnight_tomorrow = (final_travel_time - secondsLeftInDay); bool tripStartsTooLate = (instance.start_time >= seconds_since_midnight_tomorrow - 0.5); // Pad by half a second to avoid rounding errors if (tripStartsTooLate) { continue; } // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary <DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Reasons to calculate the travel time: // 1) Generic day of the week, has trip tomorrow bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripTomorrow(queryDayOfWeek, cal)); // 2) Specific date, has added exception bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(DayAfterQuery)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[DayAfterQuery] == CalendarExceptionType.added); // 3) Specific date, falls within date range, has trip tomorrow bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(DayAfterQuery, cal.start_date, cal.end_date) && HasTripTomorrow(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[DayAfterQuery] == CalendarExceptionType.removed); // All of the reasons to figure out the traversal time for this element and this trip if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { // Select only those trips starting before our current min travel time. if (instance.start_time <= seconds_since_midnight_tomorrow - 0.5) { double travel_time = SECONDS_IN_A_DAY + instance.end_time - seconds_since_midnight; if (travel_time < final_travel_time) { // If the travel time we just calculated is less than our current minimum, // update the current minimum. final_travel_time = travel_time; } } } // The one reason to be sure NOT to use this trip for this element else if (isSpecificDayWithRemovedException) { continue; } } } // Special conditions if our trip is occurring early in the day // Only do this part if our trip is occurring before trips from the previous day have stopped running if (seconds_since_midnight - 0.5 <= max_trip_start_time - SECONDS_IN_A_DAY) { // Figure out the query time in seconds since the previous day's midnight double secondsSinceMidnightYesterday = SECONDS_IN_A_DAY + seconds_since_midnight; // Find the date for the day prior to the query day. DateTime DayBeforeQuery = queryDate.AddDays(-1); foreach (trip_instance instance in trip_instances) { Trip tr; bool hasTripInfo = m_trips.TryGetValue(instance.trip_id, out tr); if (!hasTripInfo) // Something is messed up in their GTFS data - a trip value in stop_times isn't in trips.txt. Just ignore it. { continue; } string service_id = tr.service_id; // This trip is restricted, so skip it if (IsTripRestricted(instance.trip_id, tr)) { continue; } // Get the date range and days of the week that this trip run Calendar cal = null; bool hasCalendar = m_calendars.TryGetValue(service_id, out cal); // Get added and removed dates for this trip Dictionary <DateTime, CalendarExceptionType> calExceptions = null; bool hasCalendarExceptions = m_calExceptions.TryGetValue(service_id, out calExceptions); // Reasons to calculate the travel time: // 1) Generic day of the week, has trip yesterday bool isGeneralDayWithTrip = (!m_UseSpecificDates && hasCalendar && HasTripYesterday(queryDayOfWeek, cal)); // 2) Specific date, has added exception bool isSpecificDayWithException = (m_UseSpecificDates && hasCalendarExceptions && calExceptions.ContainsKey(DayBeforeQuery)); bool isSpecificDayWithAddedException = (isSpecificDayWithException && calExceptions[DayBeforeQuery] == CalendarExceptionType.added); // 3) Specific date, falls within date range, has trip tomorrow bool isSpecificDayInTripRange = (m_UseSpecificDates && hasCalendar && DateFallsBetween(DayBeforeQuery, cal.start_date, cal.end_date) && HasTripTomorrow(queryDayOfWeek, cal)); // Do not calculate travel time for this trip if the specific date is a removed exception bool isSpecificDayWithRemovedException = (isSpecificDayWithException && calExceptions[DayBeforeQuery] == CalendarExceptionType.removed); // All of the reasons to figure out the traversal time for this element and this trip if (isGeneralDayWithTrip || isSpecificDayWithAddedException || isSpecificDayInTripRange) { CalculateTravelTime(timeUsage, secondsSinceMidnightYesterday, instance, ref final_travel_time); } // The one reason to be sure NOT to use this trip for this element else if (isSpecificDayWithRemovedException) { continue; } } } // If we didn't find any valid trips at all, set it equal to -1 so it's not traversable. if (final_travel_time == double.PositiveInfinity) { return(-1); } else { // Return the final minimum travel time across the element. // Divide by 60 to convert to minutes. return(final_travel_time / 60.0); } } // If the EID wasn't even in our list, return -1. This should never happen. else { return(-1); } }