// return "arr" or "x min" of bus reaching next stop // to show on bus on road public static string GetArrivalTiming(string vehiclePlate) { BusOnRoad bor = ActiveBuses [vehiclePlate]; BusSvc svc = BusSvcs [bor.routeName]; string busStopCode = (string)bor.nextStopEnumerator.Current; // get diff of distance travelled by bus and distance between stops for the service var diffDist = svc.distanceBetweenStops [bor.stopCounter] - bor.distanceTravelled; var time = (int)((diffDist / bor.avgSpeed) / 60); // in min // if arrived bus stop if (diffDist < MARGIN_OF_ERROR && ((string)bor.nextStopEnumerator.Current).Equals(busStopCode)) { // shift next stop indicator // if no more stop, finish service // else, keep counting if (!bor.nextStopEnumerator.MoveNext()) { bor.finished = true; } else { bor.stopCounter++; } } // generate display string (give +- 1 allowance) return((time == 0 || time == -1) ? "Arr" : ((time > 60 || time < -1) ? "--" : time + " min")); }
private static async void DispatchBasedOnTime(BusSvc bs) { while (BusHelper.IsWithinServiceTiming(bs.routeName)) { BusHelper.AddBusOnRoad(bs.routeName + "-" + BusHelper.ActiveBuses.Count, bs.routeName); // dispatch again after freq await Task.Delay(TimeSpan.FromMinutes(bs.freq [BusHelper.GetTimeOfDay(bs.routeName)])); } }
// have a stopwatch to keep track of time since bus service last dispatched // in order to estimate bus arrival timing for first stop private static void StartTimerDispatch(BusSvc bs) { // init/reset stopwatch if (bs.timerSinceLastDispatch == null) { bs.timerSinceLastDispatch = new Stopwatch(); bs.timerSinceLastDispatch.Start(); } else { bs.timerSinceLastDispatch.Restart(); } }
// return true if current time between first bus and last bus timing public static bool IsWithinServiceTiming(string routeName) { TimeSpan currTimeSpan = DateTime.Now.TimeOfDay; BusSvc svc = BusSvcs [routeName]; int day = GetDayOfWeek(); // case not operating throughout the day if (svc.firstBusTime.Count <= day) { return(false); } return(currTimeSpan.CompareTo(TimeSpan.Parse(svc.firstBusTime[day])) > 0 && currTimeSpan.CompareTo(TimeSpan.Parse(svc.lastBusTime[day])) < 0); }
// simulate bus moving along the route (via checkpoints on route) public static void GoToNextCheckpoint(BusOnRoad bor) { // init if needed BusSvc svc = BusHelper.BusSvcs [bor.routeName]; if (bor.nextCheckpointEnumerator == null) { bor.nextCheckpointEnumerator = svc.checkpoints.GetEnumerator(); } else if (bor.nextDistanceEnumerator == null) { bor.nextDistanceEnumerator = svc.distanceBetweenCheckpoints.GetEnumerator(); } // default position at first stop double longitude = BusHelper.BusStops [svc.firstStop].longitude; double latitude = BusHelper.BusStops [svc.firstStop].latitude; // update position and distance based on checkpoint if (bor.nextCheckpointEnumerator.MoveNext()) { longitude = (double)bor.nextCheckpointEnumerator.Current; } if (bor.nextCheckpointEnumerator.MoveNext()) { latitude = (double)bor.nextCheckpointEnumerator.Current; } if (bor.nextDistanceEnumerator != null && bor.nextDistanceEnumerator.MoveNext()) { bor.distanceTravelled += (double)bor.nextDistanceEnumerator.Current; } // update bus position bor.longitude = longitude; bor.latitude = latitude; }
// return "arr" or "x min" or "not operating" of next and subsequent bus timing // of each bus service serving the bus stop // to show on bus stop // for NUS buses public static string GetArrivalTiming(string busStopCode, string routeName, string loop = "" /* optional, "BEFORE" or "AFTER" if repeatedService*/) { BusSvc svc = BusSvcs [routeName]; // case not operating if (!IsWithinServiceTiming(routeName)) { return("not operating"); } // calculate arrival timing (next and subsequent) based on bus stop and route int nextTiming = Int16.MaxValue; int subsequentTiming = Int16.MaxValue; foreach (BusOnRoad bor in ActiveBuses.Values.Where(b => b.routeName.Equals(routeName))) { // ignore buses of wrong direction for repeated services case if ((loop.Equals("BEFORE") && bor.stopCounter > svc.stops.IndexOf(svc.loopStop)) || (loop.Equals("AFTER") && bor.stopCounter < svc.stops.IndexOf(svc.loopStop))) { continue; } // first bus stop case if (busStopCode.Equals(bor.firstStop)) { if (bor.stopCounter == 0 && svc.timerSinceLastDispatch != null) { // get time by freq for the first stop (ignore negative) var timeOfDay = GetTimeOfDay(routeName); var timeDiff = svc.freq [timeOfDay] - (int)(svc.timerSinceLastDispatch.ElapsedMilliseconds / (1000 * 60)); if (timeDiff >= 0) { nextTiming = timeDiff; } if (timeDiff + svc.freq [timeOfDay] >= 0) { subsequentTiming = timeDiff + svc.freq [timeOfDay]; } } } else { // get diff of distance travelled by bus and distance between stops for the service // count from back for case after loop (repeated service) or last stop var index = (loop.Equals("AFTER") || bor.stopCounter >= svc.stops.Count - 2) ? svc.stops.LastIndexOf(busStopCode) - 1 : svc.stops.IndexOf(busStopCode) - 1; // bounds check if (index < 0 || index >= svc.distanceBetweenStops.Count) { continue; } var diffDist = svc.distanceBetweenStops [index] - bor.distanceTravelled; // ignore getting time if bus passed stop if (diffDist < 0) { continue; } var time = (int)((diffDist / bor.avgSpeed) / 60); // in min // store the next and subsequent time if lesser if (nextTiming > time) { subsequentTiming = nextTiming; nextTiming = time; } else if (subsequentTiming > time) { subsequentTiming = time; } } } // generate display string of next and subsequent timings (ignore if more than 30 min) string display = ""; display += (nextTiming == 0) ? "Arr" : ((nextTiming > 60) ? "--" : nextTiming + " min"); display += " / "; display += (subsequentTiming == 0) ? "Arr" : (subsequentTiming > 60) ? "--" : subsequentTiming + " min"; return(display); }