public static OptimalRoutesCollection FindOptimalRoutes(GeoCoords nowPos, GeoCoords needPos, DateTime time, Dictionary <Priority, double> priorities, IEnumerable <RouteType> types = null, double speed = 5, double dopTimeMinutes = 2, double percentTotalTime = 1, double percentTotalGoingTime = 1, double percentTotalTransportChangingCount = 1) { int n1 = 1, n2 = 1; if (priorities == null || priorities.Count == 0) { throw new Exception("Не заданы приоритеты."); } OptimalRoutesCollection findedOptimalRoutes = new OptimalRoutesCollection(); //DateTime ttt1 = DateTime.Now; findedOptimalRoutes.Add(new OptimalRoute(nowPos, needPos, time, types, speed, dopTimeMinutes)); //MessageBox.Show((DateTime.Now - ttt1).TotalMilliseconds.ToString()); //return findedOptimalRoutes;//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!1 List <Route> ignoringRoutes = new List <Route>(); Stack <Priority> myPriorities = new Stack <Priority>(priorities.Keys); //for (Priority currentPriority = myPriorities.Pop(); myPriorities.Count != 0; currentPriority = myPriorities.Pop()) //{ Priority currentPriority = myPriorities.Pop(); //double ddd = priorities[currentPriority]; double ddd = 0.25;// 0.95;// 0.85; // Порог эффективности маршрута по выбранному критерию. if (ddd > 1 || ddd < 0.25) { throw new Exception("Priority must been from [0.25; 1]"); } //List<IgnoringFragment> globalIgnoringFragments = new List<IgnoringFragment>(); IgnoringFragments ignoringFragments = new IgnoringFragments();//!!!!!!!!!!!!!! //List<IgnoringFragment> currentIgnoringFragments; //Point myStartPoint = findedOptimalRoutes[0].startPoint; for (OptimalRoute selectedOptimalRoute = findedOptimalRoutes[0]; selectedOptimalRoute != null; selectedOptimalRoute.Visited(), selectedOptimalRoute = SelectOptimalRouteWithMinimalMark(findedOptimalRoutes, Priority.MinimalTime)) { ignoringRoutes = new List <Route>();//!!!!!!!!!!!1111111111 // Проходим по всем ребрам выбранного пути и строим новые маршруты при удалении ребер: for (Points.Point tmpP = selectedOptimalRoute.myPoints.finalPoint; tmpP.Previous != null; tmpP = tmpP.Previous) { if (tmpP.Route != null && !ignoringRoutes.Contains(tmpP.Route)) { ignoringRoutes.Add(tmpP.Route); } ////// Игнорируемое "ребро": ////IgnoringFragment tmpIgnFragm = new IgnoringFragment(tmpP.StationCode, tmpP.RouteCode, tmpP.PreviousStationCode); //////!!!!!!!!!!!!!!!!!// ////ignoringFragments = new IgnoringFragments(selectedOptimalRoute.myIgnoringFragments);//!!!! ////if (ignoringFragments.Contains(tmpIgnFragm)) continue; ////ignoringFragments.Add(tmpIgnFragm); ////Points myPoints = null; //////Point myFinishPoint = null; ////OptimalRoute tmpOptimalRoute = null; //////myPoints = selectedOptimalRoute.MyPoints.Downgrade(ignoringFragments); //////myFinishPoint = selectedOptimalRoute.finalPoint.Downgrade(ignoringFragments); //////myPoints = tmpP.Previous.CurrentGraph; ////// Строим новый маршрут, избегая указанные ребра: ////tmpOptimalRoute = new OptimalRoute(nowPos, needPos, time, types, speed, dopTimeMinutes, ignoringList: ignoringFragments/*,/*myStartPoint,*/ /*myPoints*//*, myFinishPoint*/); ////n2++; ////if (tmpOptimalRoute.TotalTime.TotalSeconds <= findedOptimalRoutes[0].TotalTime.TotalSeconds / ddd) ////{ //// string tmpJSON = JsonConvert.SerializeObject(tmpOptimalRoute.points); //// bool ok = false; //// foreach (OptimalRoute opt in findedOptimalRoutes) //// { //// if (JsonConvert.SerializeObject(opt.points) == tmpJSON) //// { //// ok = true; //// break; //// } //// } //// if (ok) continue; //// findedOptimalRoutes.Add(tmpOptimalRoute); //// n1++; ////} } foreach (Route r in ignoringRoutes) { if (selectedOptimalRoute.ignoringRoutes.Contains(r)) { continue; } List <Route> ignoringRoutesAdd = new List <Route>(selectedOptimalRoute.ignoringRoutes); ignoringRoutesAdd.Add(r); OptimalRoute tmpOptimalRoute = new OptimalRoute(nowPos, needPos, time, types, speed, dopTimeMinutes, ignoringRoutesAdd: ignoringRoutesAdd); n2++; if (tmpOptimalRoute.TotalTime.TotalSeconds <= findedOptimalRoutes[0].TotalTime.TotalSeconds / ddd) { string tmpJSON = JsonConvert.SerializeObject(tmpOptimalRoute.points); bool ok = false; foreach (OptimalRoute opt in findedOptimalRoutes) { if (JsonConvert.SerializeObject(opt.points) == tmpJSON) { ok = true; break; } } if (ok) { continue; } findedOptimalRoutes.Add(tmpOptimalRoute); n1++; } } } //MessageBox.Show(n1 + " from " + n2); return(findedOptimalRoutes); }
/* * /// <summary> * /// Откатывает вершины до момента, когда они еще не содержали блокируемые фрагменты пути. * /// </summary> * /// <param name="ignoringFragments">Блокируемые фрагменты пути.</param> * /// <returns>Возвращает ближайшую версию, не содержащую блокируемые фрагменты пути.</returns> * public Points Downgrade(IgnoringFragments ignoringFragments) * { * Points newP = new Points(startPoint, finalPoint); * foreach (Point p in this) newP.Add(p.Downgrade(ignoringFragments)); * return newP; * }*/ /// <summary> /// Находит кратчайший путь. /// </summary> /// <param name="myStartPoint"></param> /// <param name="myFinishPoint"></param> /// <param name="myIgnoringFragments"></param> /// <param name="time"></param> /// <param name="types"></param> /// <param name="speed"></param> /// <param name="reservedTime"></param> /// <param name="databaseMysqlConnection"></param> public void CountShortWay(/*Point myStartPoint, Point myFinishPoint,*/ List <Route> ignoringRoutes, IgnoringFragments myIgnoringFragments, DateTime time, IEnumerable <RouteType> types, double speed, TimeSpan reservedTime, MySql.Data.MySqlClient.MySqlConnection databaseMysqlConnection) { //TimeSpan overLimitResedvedTime = TimeSpan.FromMinutes(20); DEBUG_timeToCreateNext = new TimeSpan(); DateTime t0 = DateTime.Now, t1; TimeSpan /*t_total = new TimeSpan(),*/ t_giversin = new TimeSpan(), t_finding_time = new TimeSpan() /*, t_upd_in_stations = new TimeSpan()*/; TimeSpan /*t_updating_total = new TimeSpan(),*/ t_going_check_total = new TimeSpan(), t_stations = new TimeSpan(), t_without_finding_marks = new TimeSpan(); for (Point selectedPoint = Next(); selectedPoint != null; selectedPoint = Next()) { //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! if (selectedPoint.TotalTime > finalPoint.TotalTime /* + overLimitResedvedTime*/) //... Пропускаем и удаляем, если значение метки превышает минимальное время до пункта назначения. { //points.Remove(selectedPoint);// break; //continue;// } DateTime t4 = DateTime.Now; DateTime t3 = DateTime.Now; Station selectedPointStation = selectedPoint.Station; if (selectedPointStation != null) { // Момент, когда мы прибудем на остановку: DateTime momentWhenComingToStation = time + selectedPoint.TotalTime; //t1 = DateTime.Now; // Загружаем маршруты, проходящие через остановку: List <Route> routesOnStation;// = routesOnStation = Database.GetRoutesOnStation(selectedPointStation.hashcode, canReadDataFromLocalCopy: true); if (selectedPointStation.routes != null) { routesOnStation = selectedPointStation.routes; } else { continue; } //t_total += DateTime.Now - t1; foreach (Route selectedRoute in routesOnStation) { if (ignoringRoutes != null && ignoringRoutes.Contains(selectedRoute)) { continue; } if (types.Contains(RouteTypeConverter.FromString(selectedRoute.type))) { //t1 = DateTime.Now; // Следующая остановка у данного транспорта: Station nextStation = selectedRoute.getNextStation(selectedPointStation); /*// Код остановки, на которую попадем на данном транспорте: * string nextCode = selectedRoute.getNextStationCodeAfter(selectedPointStation.hashcode, canReadDataFromLocalCopy: true);*/ //t_total += DateTime.Now - t1; if (nextStation /*nextCode*/ != null) // Если остановка не является конечной, то: { //t1 = DateTime.Now; // Загружаем расписание: Timetable table = selectedRoute.GetTimetable(selectedPointStation);//Database.GetTimetable(selectedPointStation.hashcode, selectedRoute.hashcode, databaseMysqlConnection, canReadDataFromLocalCopy: true); //t_total += DateTime.Now - t1; // Блокируем попытку попасть указанным транспортом на указанную остановку: if (myIgnoringFragments.Contains(nextStation.hashcode /*nextCode*/, selectedRoute.hashcode, selectedPointStation.hashcode)) { continue; } if (table.type == TableType.table) // Если это точное расписание, то: { // Минимальный начальный момент, с который можно начинать ожидать посадку: DateTime momentWhenAskingForGoing = momentWhenComingToStation; // Резервируем дополнительное время, если будем пересаживаться на другой маршрут: //if (selectedPoint.RouteCode == null || selectedPoint.RouteCode != selectedRoute.hashcode) momentWhenAskingForGoing += reservedTime; if (selectedPoint.Route != null && selectedPoint.Route != selectedRoute) { momentWhenAskingForGoing += reservedTime; } t1 = DateTime.Now; // Подсчитываем, сколько будем ожидать этот транспорт на остановке: TimeSpan waitingTime = table.FindTimeAfter(momentWhenAskingForGoing); t_finding_time += DateTime.Now - t1; // Момент, когда мы сядем в транспорт: DateTime momentWhenSitInTransport = momentWhenAskingForGoing + waitingTime; //t1 = DateTime.Now; /*// Следующая остановка у данного транспорта: * Station nextStation = Database.GetStationByHashcode(nextCode, databaseMysqlConnection, canReadDataFromLocalCopy: true);*/ // И соответствующее расписание на этой остановке: Timetable tbl = selectedRoute.GetTimetable(nextStation);//Database.GetTimetable(nextStation.hashcode, selectedRoute.hashcode, databaseMysqlConnection, canReadDataFromLocalCopy: true); //t_total += DateTime.Now - t1; t1 = DateTime.Now; // (сколько будем ехать до следующей остановки): TimeSpan goingOnTransportTime = tbl.FindTimeAfter(momentWhenSitInTransport); t_finding_time += DateTime.Now - t1; // Метка времени: TimeSpan onNextPointTotalTime = momentWhenSitInTransport - momentWhenComingToStation + goingOnTransportTime + selectedPoint.TotalTime; //t1 = DateTime.Now; if (Find(nextStation).tryUpdate(onNextPointTotalTime, selectedPoint, selectedPointStation, selectedRoute)) { } //t_updating_total += DateTime.Now - t1; } else if (table.type == TableType.periodic) { throw new NotImplementedException(); } } } } } //t_upd_in_stations = TimeSpan.FromMilliseconds(t_updating_total.TotalMilliseconds); t_stations += DateTime.Now - t3; GeoCoords selectedPointCoords = selectedPoint.Coords; t_without_finding_marks += DateTime.Now - t4; // Нет смысла идти пешком "транзитом" через остановку: /*//11111111111111111111111111!!!!!!!!!!!!!!!!!*/ if (selectedPoint.Route == null) { continue; } t4 = DateTime.Now; DateTime t2 = DateTime.Now; // Попробуем пройти пешком до других "вершин": foreach (Point p in this /*!!!!!!!!!!!!points*/) { if (!p.IsVisited && p != selectedPoint) { // Блокируем попытку дойти пешком до указанной остановки: if (myIgnoringFragments.Contains(p.StationCode, null, selectedPointStation.hashcode)) { continue; } t1 = DateTime.Now; int distanceToSelectedPoint = GeoCoords.Distance(selectedPointCoords, p.Coords); t_giversin += DateTime.Now - t1; TimeSpan goingTime = GetTimeForGoingTo(distanceToSelectedPoint, speed /*, true, sp*/); TimeSpan newTime = selectedPoint.TotalTime + goingTime + reservedTime; /*if (p != myFinishPoint)*/ // newTime += reservedTime; //t1 = DateTime.Now; if (p.tryUpdate(newTime, selectedPoint, selectedPointStation)) { } //t_updating_total += DateTime.Now - t1; } } t_going_check_total += DateTime.Now - t2; t_without_finding_marks += DateTime.Now - t4; if (myIgnoringFragments.Contains(null, null, selectedPointStation.hashcode)) { continue; } //t1 = DateTime.Now; if (finalPoint.tryUpdate(selectedPoint.TotalTime + GetTimeForGoingTo(selectedPointCoords, finalPoint.Coords, speed), selectedPoint, selectedPointStation)) { } //t_updating_total += DateTime.Now - t1; } t1 = DateTime.Now; // Сокращаем время ходьбы пешком до минимума и избавляемся от "бессмысленных" пересадок, сохраняя общее время неизменным: Point currentPoint = finalPoint.Previous; while (currentPoint != startPoint) { Route r = currentPoint.Route; if (r != null) { Point previousPoint = currentPoint.Previous; if (previousPoint != startPoint && previousPoint.Route != r) // Если на предыдущую остановку мы добрались другим транспортом, то: { Station previousRouteStation = r.getPreviousStation(previousPoint.Station); if (previousRouteStation != null) { Point point = previousRouteStation.Point; if (point != null && point.IsVisited) { Timetable ttt = r.GetTimetable(previousRouteStation); if (ttt != null) { DateTime ddd = time + previousPoint.TotalTime; TimeSpan moment = r.GetTimetable(currentPoint.Station).FindTimeAfter(ddd); TimeSpan tmp_time = ttt.FindTimeBefore(ddd + moment); TimeSpan momentArriveOnCurrent = previousPoint.TotalTime + moment; TimeSpan momentSittingOnPrevious = momentArriveOnCurrent + tmp_time; /*bool bbb = point.Route != null && point.Route.GetTimetable(point.Station) != null && point.Route.GetTimetable(point.Station).FindTimeAfter(time + point.TotalTime) <= previousPoint.TotalTime + moment + tmp_time; * if (bbb) * { * previousPoint.Route = r; * previousPoint.Previous = point;////!bbb && point.TotalTime <= momentSittingOnPrevious && * } * else */ if (/*point.TotalGoingTime>=previousPoint.TotalGoingTime || */ point.TotalTime <= previousPoint.TotalTime /* && point.TotalGoingTime <= previousPoint.TotalGoingTime*/) { previousPoint.Route = r; previousPoint.Previous = point; } } } } } } currentPoint = currentPoint.Previous; } //MessageBox.Show("Total: " + (DateTime.Now - t0).TotalMilliseconds ///**///+ "\n\tWithout finding minimal marks: " + t_without_finding_marks.TotalMilliseconds //+ "\n\tFinding minimal marks: " + DEBUG_timeToCreateNext.TotalMilliseconds //+ "\n\tStations: " + t_stations.TotalMilliseconds //+ "\n\t\tFinding time: " + t_finding_time.TotalMilliseconds //+ "\n\tWalking checks: " + t_going_check_total.TotalMilliseconds //+ "\n\t\tGaversin: " + t_giversin.TotalMilliseconds/**/ //+ "\n\tRecount: " + (DateTime.Now - t1).TotalMilliseconds //); }
/// <summary> /// /// </summary> /// <param name="nowPos"></param> /// <param name="needPos"></param> /// <param name="time">Начальный момент времени.</param> /// <param name="types">Допустимые типы транспорта.</param> /// <param name="goingSpeed">Скорость движения пешком.</param> /// <param name="dopTimeMinutes">Резерв времени для ожидания транспорта.</param> public OptimalRoute(GeoCoords nowPos, GeoCoords needPos, DateTime time, IEnumerable <RouteType> types = null, double goingSpeed = 5, double dopTimeMinutes = 2, List <Route> ignoringRoutesAdd = null, IEnumerable <IgnoringFragment> ignoringList = null, /*Point myStartPoint = null,*/ Points myPoints = null /*, Point myFinishPoint = null*/) { if (ignoringRoutesAdd != null) { this.ignoringRoutes = ignoringRoutesAdd; } else { this.ignoringRoutes = new List <Route>(); } Database.TryInitialize(); MySql.Data.MySqlClient.MySqlConnection databaseMysqlConnection = Database.conn; this.needPos = needPos; this.nowPos = nowPos; this.goingSpeed = goingSpeed; this.time = time; TimeSpan reservedTime = TimeSpan.FromMinutes(dopTimeMinutes); if (types == null) { types = new RouteType[] { RouteType.bus, RouteType.trolleybus, /*RouteType.tram, RouteType.metro, RouteType.express_bus, RouteType.marsh*/ } } ; this.types = types;//{ RouteType.bus };// if (ignoringList != null) { myIgnoringFragments = new IgnoringFragments(ignoringList); } else { myIgnoringFragments = new IgnoringFragments(); } //if (myPoints == null) //{ Points.Point myStartPoint = new Points.Point(TimeSpan.FromSeconds(0), nowPos); Points.Point myFinishPoint = new Points.Point(TimeSpan.FromDays(25000), needPos); myFinishPoint.tryUpdate(GetTimeForGoingTo(nowPos, needPos, goingSpeed) + TimeSpan.FromMinutes(20), myStartPoint);//!!!!!!!!!!!!!!!!! //myFinishPoint.tryUpdate(GetTimeForGoingTo(GoogleApi.GetWalkingDistance(nowPos, needPos), goingSpeed), myStartPoint); myPoints = new Points(myStartPoint, myFinishPoint); // Получим "начальный" список станций: List <Station> stationsList = Database.GetStationsAround(myPoints.startPoint.Coords, GeoCoords.Distance(myPoints.startPoint.Coords, myPoints.finalPoint.Coords), canReadDataFromLocalCopy: true); myPoints.Fill(stationsList, goingSpeed, reservedTime, myIgnoringFragments); //} //else //{ // if (myFinishPoint == null || myStartPoint == null) // throw new Exception(); //} //DateTime ttt1 = DateTime.Now; // Находим кратчайшие пути до всех вершин: myPoints.CountShortWay(/*myStartPoint, myFinishPoint,*/ ignoringRoutes, myIgnoringFragments, time, types, goingSpeed, reservedTime, databaseMysqlConnection); //myFinishPoint.tryUpdate(GetTimeForGoingTo(nowPos, needPos, goingSpeed), myStartPoint);//!!!!!!!!!!!!!!!!! //MessageBox.Show((DateTime.Now - ttt1).TotalMilliseconds.ToString()); Points.Point tmpP = myPoints.finalPoint; this.points.Add(tmpP.ToString());//// while (tmpP.Previous != null) { tmpP = tmpP.Previous;// this.points.Add(tmpP.ToString()); if (tmpP.Previous == null && tmpP.Coords != myPoints.startPoint.Coords) { throw new Exception("Где-то удалилась часть маршрута..."); } } this.totalTime = myPoints.finalPoint.TotalTime; this.totalGoingTime = myPoints.finalPoint.TotalGoingTime; this.totalTransportChangingCount = myPoints.finalPoint.TotalTransportChangingCount; /*this.finalPoint = myFinishPoint; * this.startPoint = myStartPoint;*/ this.myPoints = myPoints; }
public void Fill(IEnumerable <Station> stationsList, double goingSpeed, TimeSpan reservedTime, IgnoringFragments myIgnoringFragments = null) { foreach (Station st in stationsList) { if (myIgnoringFragments != null && myIgnoringFragments.Contains(st.hashcode, null, null)) { continue; } Point add = new Point(TimeSpan.FromDays(25000), st); add.tryUpdate(GetTimeForGoingTo(this.startPoint.Coords, st.Coords, goingSpeed) + reservedTime, this.startPoint); this.Add(add); } }