Пример #1
0
        // Пользователь запросил генерацию листов по введенным данным
        // TODO: обработать правильность заполнения и контроль ошибок
        private void BtnPOIGenerate_Click(object sender, RoutedEventArgs e)
        {
            // Создаем новый лист
            TripTicket tripTicket = new TripTicket();

            // Создаем хранилище листов
            tripLists = new List <TripTicket>();

            // Помещаем новый лист в хранилище
            tripLists.Add(tripTicket);
            // Генерируем с сохранением выходных данных в ntt
            NextTripTicket ntt = tripTicket.Generate();
            // Записываем количество пройденных км в рамках этого листа
            int realDistance = tripTicket.TotalRealDistance;

            // ИНТЕРФЕЙС:
            // Отображаем расчетное количество км, которое можно пройти на введенном количестве топлива
            tbMustDistance.Text = tripTicket.TotalDistance.ToString();

            // Будем продолжать генерацию новых листов пока она требуется (ntt не равно null)
            while (ntt != null)
            {
                tripTicket = new TripTicket(ntt.Liters, ntt.Date, ntt.NextIndex, ntt.OdometerEndDay);
                ntt        = tripTicket.Generate();
                // Суммируем пройденный путь
                realDistance += tripTicket.TotalRealDistance;
                tripLists.Add(tripTicket);
            }

            // Показывать первый лист из хранилища
            currentSheet = 0;
            // Вызвать обновление интерфейса
            ShowTrackListSheet();

            // ИНТЕРФЕЙС:
            // Отобразисть суммарное количество пройденного пути
            tbFullDistance.Text = realDistance.ToString();

            // Показания дометра на конец чека
            // с добавлением пройденного пути от дома и обратно
            tbOdometerEnd.Text = (int.Parse(tbOdometerStart.Text) + realDistance +
                                  ((tripLists.Count - 1) * CurrentOptions.Vehicles[CurrentOptions.SelectedVehicle].HomeWay * 2)).ToString();
        }
Пример #2
0
        private NextTripTicket GenerateTimeAndDate(List <POI> poi)
        {
            int i = 1;

            NextTripTicket ntt = null;

            BusinessDaysCalculator businessDays = MainWindow.Instance.GlobalBusinessDaysCalculator;

            // Стартовая дата в чеке
            DateTime startTime = receiptDate;

            //Определяем конец рабочего дня (попросту добавляем к указанной дате время)
            DateTime endDT = new DateTime(startTime.Year, startTime.Month, startTime.Day, endOfWorkDay.Hours, endOfWorkDay.Minutes, 0);

            foreach (POI p in poi)
            {
                if (i > 1)
                {
                    startTime = startTime.AddMinutes(p.prev.toNextPOI.TotalMinutes);
                }
                if (p.next == null)
                {
                    break;
                }

                //ПРЕДСТАВЛЕНИЕ ДАТЫ
                //Конвертация даты в строку и запись в объект. (Можно делать это уже при выгрузки в XLSX
                p.Date     = startTime.ToShortDateString();
                p.FullDate = startTime;

                startTime = startTime.AddMinutes(random.Next(0, pause + 1)); //Добавляем задержку в точке назначения

                p.timeDeparture = startTime;
                p.timeArrive    = startTime.Add(p.toNextPOI);

                //Проверяем укладываемся ли в рабочий день
                if (p.next != null)
                {
                    //Если ехать в следующую точку, то надо проверить а хватит ли потом времени в рамках рабочего дня

                    if ((startTime.AddMinutes(p.next.toNextPOI.TotalMinutes * 2) > endDT) && !p.address.IsBase)
                    {
                        DateTime checkDay;
                        //Если не хватит то переключаем день на следующий
                        do
                        { //Меняем день до тех пор пока он не станет следующим РАБОЧИМ днем
                            startTime = startTime.AddDays(1);
                            checkDay  = new DateTime(startTime.Year, startTime.Month, startTime.Day);
                        } while (((startTime.DayOfWeek == DayOfWeek.Saturday || startTime.DayOfWeek == DayOfWeek.Sunday) && (businessDays.IsBusinessDay(checkDay) != 1)) || // если это выходной и не является принудительно рабочим
                                 businessDays.IsBusinessDay(checkDay) == 2);                                                                                                // если это любой другой день, но он объявлен нерабочим

                        //Переводим стартовое время на начало рабочего дня
                        startTime = new DateTime(startTime.Year, startTime.Month, startTime.Day, startOfWorkDay.Hours, startOfWorkDay.Minutes, 0);
                        //Определяем конец рабочего дня
                        endDT = new DateTime(startTime.Year, startTime.Month, startTime.Day, endOfWorkDay.Hours, endOfWorkDay.Minutes, 0);
                        //startTime = startOfWorkDay;

                        FuelResidude = Math.Round(p.FuelResidude);
                        // Если нужно создавать новый трип лист каждый раз когда закончился день
                        // и еще достаточно топлива, то
                        if (MainWindow.DIVIDE_TRIPTICKETS && FuelResidude > fuelLost)
                        {
                            // Записываем данные для переноса на след день
                            ntt = new NextTripTicket()
                            {
                                NextIndex = Id + 1,         // Id следующего путевого листа
                                Date      = startTime,      //Дата с которой начнется след лист
                                Liters    = p.FuelResidude, //Остаток топлива с которым начнется день
                                NumberPOI = i               //Количество уже пройденных точек (нужно для удаление лишних)
                            };

                            return(ntt);
                        }

                        i = 0;
                    }
                    i++;
                }
            }

            return(null);
        }
Пример #3
0
        public NextTripTicket Generate()
        {
            //Вычисление какой расход. Зимний или Летний
            double gasRate = gasRateWinter;

            if ((receiptDate.Month >= 4 && receiptDate.Month <= 9) || (receiptDate.Month == 3 && receiptDate.Month >= 15))
            {
                gasRate = gasRateSummer;
            }

            TotalDistance = GetDistance(gasRate, gasLiters);

            int distance = 0; //счетчик пройденного пути
            int index    = 0;

            POI start = new POI()
            {
                address = pool[0]
            };                                           //TODO: подразумевается, что база имеет индекс 0, а что если это не так!?

            index++;
            start.Id = index;
            poi.Add(start);      //<--------------------------------------------------------------------------------------------- Добавляем первую точку. Это база!

            POI prev = start;    //предыдущая точка для следующей найденной
            POI curr;            //текущая точка. сюда будт получено значение в цикле (раз за разом)

            bool nowBase = true; //изначально мы на базе

            //цикл генерирует первичный маршрут, случайным образом
            //пока пройденный путь меньше общего пройденного пути по расходу/чеку, цикл будет добавлять точки и прибавлять
            //дистанцию до точек в счетчик пройденного пути
            while (distance <= TotalDistance - inaccuracy)
            {                //с учетом погрешности
                int min = 0;
                if (nowBase) // Это чтобы находясь на базе случайно не поехать опять на базу
                {
                    min++;
                }
                int r = random.Next(min, pool.Count()); //случайный индекс в диапазоне листа адресов (пула)

                //Если мы не на базе, а нам нужно каждый раз возвращаться на базу, то след адрес у нас БАЗА
                if (!nowBase && backToBase)
                {
                    r = 0; //TODO: тут я подразумеваю, что база имеет у нас индекс 0 в листе адресов
                           //TODO: а что если это не так?
                }

                Address adr         = pool[r]; //получаем адрес по индексу
                int     poiDistance = adr.Distance;

                //Если мы не на базе, а нам туда нужно каждый раз возвращаться, то дистанция будет равной
                //пройденной перед этим
                if (!nowBase && backToBase)
                {
                    poiDistance = prev.address.Distance;
                    //System.out.println("Предыдущий адрес: " + prev.address.getName());
                }

                //System.out.println("Добавляем: "+poiDistance);

                //проверяем не выйдим ли мы за рамки
                // необходимого пути с учетом допустимой погрешности
                // либо мы не на базе, а нам туда каждый раз надо возвращаться, тогда у нас просто нет выбора
                if ((poiDistance + distance <= TotalDistance + inaccuracy) || (!nowBase && backToBase))
                {
                    distance += poiDistance; //добавляем пройденную дистанцию

                    //Создаем точку для листа с найденным адресом, предыдущей точкой, а следующая точка пока null
                    //Если - это не последняя точка то она будет присвоена в след витке.
                    curr = new POI {
                        address = adr, prev = prev
                    };                                               //(adr, prev, null);
                    index++;
                    curr.Id = index;
                    poi.Add(curr);

                    if (backToBase)
                    {                       //Если мы каждый раз возвращаемся на базу, то
                        nowBase = !nowBase; //меняем значение база ли это на противоположное
                    }

                    //Если текущая точка не является первой (есть предыдущая), то
                    //говорим предыдущей точке, что следующая для нее - это текущая
                    int prevDist = 0;

                    if (prev != null)
                    {
                        //В предыдущую точку добавляем дистанцию до текущей точки
                        if (curr.address.IsBase)
                        { //Если теущая точка база, то дистанцию до нее такаяже как и в предыдущую
                            prevDist = prev.address.Distance;
                        }
                        else
                        {
                            prevDist = curr.address.Distance;
                        }

                        //Присвиваем в прыдущую точку дистанцию до текущей
                        prev.distToNext = prevDist;

                        //Записываем остаток топлива
                        gasLiters         = gasLiters - (gasRate * prevDist / 100);
                        prev.FuelResidude = gasLiters;
                        //Console.WriteLine("Осталось топилва: "+gasLiters);

                        //Рассчитываем время из предыдущей точки в текущую, на основе дистанции <-----------------------------ВРЕМЯ!!!!!
                        //TimeSpan timeInMinutes = GetTravelTime(averageSpeed, prevDist);
                        prev.toNextPOI = GetTravelTime(averageSpeed, prevDist); //.setMinutesFromMidnight(timeInMinutes); //записываем в предыдущую точку время затраченной для
                                                                                //достижения текущей точки


                        //В прыдыдущей точке делаем ссылку на текущую в переменную следующая.
                        prev.next = curr;
                        //System.out.println("Предыдущая: "+prev.address.getName());
                    }

                    //TODO: Где то тут надо сгенерировать дату в точку и время

                    //Для следующего витка цикла в предыдущую точку присваиваем ссылку на текущую
                    prev = curr;

                    usedPOI.Add(adr); //добавляем использованный адрес в соотв лист
                }

                //TODO: не совсем уверен нужно ли так делать: Я удаляю провернную точку из пула даже если она не подошла,
                //чтобы не зациклиться до бесконечности
                if (r != 0)
                { //Если адрес не база, то удаляем
                    pool.Remove(pool[r]);
                }

                //После удаления я проверяю есть ли в пуле еще точки и если их нет, то цикл я прерываю,
                //т.к. не хватает точек достроить маршрутный лист
                if (pool.Count <= 1)
                { //1 - потому, что в конечном итоге база то останется
                    //System.out.println("Перебрали все значение, но подходящего нет! Маршрутный лист недостроен.");
                    break;
                }
            } //КОНЕЦ ЦИКЛА

            TotalRealDistance = distance;

            // По уже созданному маршруту генерируются даты-время пути.
            // Если требуется создавать один маршрутный на один день,
            // И если в один день уложиться не удалось, то
            // ntt веренется не null
            // А это значит что по данным ntt будет сгенерирован следующий лист на след день
            // Поэтому:
            NextTripTicket ntt = GenerateTimeAndDate(poi);

            // В пробег начального дня прибавляется путь до дома
            // ПЛЮС путь ОТ дома (чтоб туда обратно получилось)
            if (Id != 0)
            {
                OdometerStartDay = lastListOdo + homeWay * 2;
            }

            if (ntt != null)
            {
                TotalRealDistance = 0;                                     // Обнуляем пройденный путь в рамках одного листа
                poi.RemoveRange(ntt.NumberPOI, poi.Count - ntt.NumberPOI); // Удаляем точки которые не будут использоваться данным листом

                // Пробегаемся по всем точкам чтобы...
                foreach (POI p in poi)
                {
                    // ... суммировать весь пройденный путь только по этим точкам
                    TotalRealDistance += p.distToNext;
                }

                ntt.OdometerEndDay = OdometerStartDay + TotalRealDistance;

                //return ntt; <Возвращаем ниже>// вернем данные для генерации след листа
                // таким образом, код который вызвал генерацию будет знать что
                // генерация была ограничена одинм днем и весь бензин еще не использован
                // и генерация должна быть продолжена с использованием выходных данных ntt
            }

            OdometerEndDay = OdometerStartDay + TotalRealDistance;

            TimeSpan randTime = new TimeSpan(0, random.Next(2, 15), 0);

            // Время Выезда по путевому
            StartTime = poi[0].timeDeparture - randTime;

            randTime = new TimeSpan(0, random.Next(2, 15), 0);
            int k = poi.Count - 1;

            // TODO: Это костыль:
            //       Иногда последняя точка путая и время у нее равно нулю. Поэтому вернем индекс предпоследней
            if (poi[k].timeArrive == new DateTime(1, 1, 1, 0, 0, 0))
            {
                k--;
            }
            // Время приезда по путевому
            EndTime = poi[k].timeArrive + randTime;

            return(ntt); // если ntt вернулось null то генерация след листа не требуется.
        }