예제 #1
0
        public static PlanElement Create(DecisionRow row, int orderNo, DateTime start, DateTime end)
        {
            var element = new PlanElement
            {
                PlaceName        = row.Candidate.PlaceName,
                PlaceId          = row.Candidate.PlaceId,
                FormattedAddress = row.Candidate.FormattedAddress,
                Lat             = row.Candidate.Location.lat,
                Lng             = row.Candidate.Location.lng,
                OrderNo         = orderNo,
                Rating          = row.Candidate.Rating,
                Price           = row.Candidate.Price,
                Popularity      = row.Candidate.Popularity,
                ScorePosition   = row.ScorePosition,
                NormalizedScore = row.NormalizedScore,
                Start           = start,
                End             = end
            };

            element.PlanElementTypes = new List <PlanElementyTypeEntity>(row.Candidate.ElementTypes.Count);
            foreach (var e in row.Candidate.ElementTypes)
            {
                element.PlanElementTypes.Add(new PlanElementyTypeEntity(e));
            }

            element.OpeningHours = new List <PlanElementOpeningHourEntity>(row.Candidate.OpeningHours.Count);
            foreach (var e in row.Candidate.OpeningHours)
            {
                element.OpeningHours.Add(new PlanElementOpeningHourEntity(e));
            }

            return(element);
        }
        public async Task <IList <PlanElement> > GenerateAsync(DecisionArray decisionArray, Plan plan)
        {
            var elements = new List <PlanElement>();

            var optimizedElementsOrder = await _optimizePlanElementsOrder.Optimize(decisionArray, plan, plan.Assumptions.AssumedNumberOfElement); //travel salesman problem optimization

            var optimizedPosition = 1;

            foreach (var optimizedIter in optimizedElementsOrder)
            {
                decisionArray.DecisionRows[optimizedIter].OptimizedPosition = optimizedPosition;
                ++optimizedPosition;
            }

            //Sort by optimized position
            decisionArray.DecisionRows = decisionArray.DecisionRows.OrderBy(x => x.OptimizedPosition).ToList();

            var iterParams = new PlanElementIteratorParams(plan.StartLocation, plan.PlanForm.StartDateTime, plan.Assumptions);

            while (DateTime.Compare(iterParams.CurrentDateTime, plan.PlanForm.EndDateTime) <= 0 || iterParams.OrderNo >= decisionArray.DecisionRows.Count)
            {
                try
                {
                    PlanElement planElement = null;
                    //EATING
                    if (iterParams.IsTimeForMeal())
                    {
                        var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.EatingDuration);
                        var candidate      = await _planElementEatingProvider.GenerateAsync(decisionArray, plan, iterParams.WhichMeal, iterParams);

                        iterParams.CheckNextMeal();
                        planElement = new PlanElement(candidate.PlaceName, candidate.PlaceId, candidate.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, candidate.Location.lat, candidate.Location.lng, iterParams.OrderNo, candidate.Rating, candidate.Price, candidate.Popularity, PlanElementType.Eating);
                    }
                    //SLEEPING
                    else if (iterParams.IsTimeForSleep())
                    {
                        iterParams.IsSleep = true;
                        var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.SleepDuration);
                        if (plan.PlanForm.HasAccomodationBooked)
                        {
                            planElement = new PlanElement(plan.PlanAccomodation.PlaceName, plan.PlanAccomodation.PlaceId, plan.PlanAccomodation.FormattedAddress, iterParams.CurrentDateTime, elementEndTime, plan.PlanAccomodation.Lat, plan.PlanAccomodation.Lng, iterParams.OrderNo, plan.PlanAccomodation.Rating, null, null, PlanElementType.Sleeping);
                        }
                        else
                        {
                            planElement = new PlanElement(plan.PlanForm.PlaceName, plan.PlanForm.PlaceId, String.Empty, iterParams.CurrentDateTime, elementEndTime, plan.Latitude, plan.Longitude, iterParams.OrderNo, plan.Rating, null, null, PlanElementType.Sleeping);
                        }
                    }
                    //OTHER PLAN ELEMENTS
                    else
                    {
                        var foundRow       = false;
                        var elementEndTime = iterParams.CreateEndDateTime(plan.Assumptions.PlanElementDuration);
                        while (!foundRow)
                        {
                            if (iterParams.LeftRows.Any(x => x.Candidate.IsOpen(iterParams.CurrentDateTime))) //first check lefted row which was temporary closed
                            {
                                var leftedRow = iterParams.LeftRows.First(x => x.Candidate.IsOpen(iterParams.CurrentDateTime));
                                if (!leftedRow.Candidate.IsOpen(elementEndTime)) //check close date
                                {
                                    elementEndTime = leftedRow.Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime);
                                }

                                planElement = PlanElement.Create(leftedRow, iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime);
                                iterParams.LeftRows.Remove(leftedRow);
                                foundRow = true;
                            }
                            else if (decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(iterParams.CurrentDateTime)) //decision row is open
                            {
                                if (!decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.IsOpen(elementEndTime))             //check close date
                                {
                                    elementEndTime = decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex].Candidate.GetCloseDateTime(iterParams.CurrentDateTime, elementEndTime);
                                }

                                planElement = PlanElement.Create(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex], iterParams.OrderNo, iterParams.CurrentDateTime, elementEndTime);
                                foundRow    = true;
                                iterParams.CurrentDecisionRowIndex += 1;
                            }
                            else //decision row is closed
                            {
                                iterParams.LeftRows.Add(decisionArray.DecisionRows[iterParams.CurrentDecisionRowIndex]);
                                iterParams.CurrentDecisionRowIndex += 1;
                            }
                        }
                    }
                    if (iterParams.CurrentDecisionRowIndex == decisionArray.DecisionRows.Count())
                    {
                        throw new UserFriendlyException($"Skończyły się dostępni kandydaci");
                    }

                    if (planElement == null)
                    {
                        continue;
                    }

                    iterParams.NextLocation = Location.Create(planElement.Lat, planElement.Lng);
                    //DIRECTIONS
                    var directionsApiInput  = _googleDirectionsInputFactory.Create(iterParams.CurrentLocation, iterParams.NextLocation, iterParams.travelMode, iterParams.CurrentDateTime);
                    var directionsApiResult = await _googleDirectionsApiClient.GetAsync(directionsApiInput);

                    if (directionsApiResult.IsOk)
                    {
                        if (directionsApiResult.routes.First().legs.Any())
                        {
                            var route     = directionsApiResult.routes.First().legs.First(); //only 1 leg if no waypoints
                            var planRoute = new PlanRoute(route.distance.value, route.duration.value, iterParams.travelMode);

                            foreach (var step in route.steps) //steps of route
                            {
                                planRoute.Steps.Add(new PlanRouteStep(step.distance.value, step.duration.value,
                                                                      step.start_location.lat, step.start_location.lng,
                                                                      step.end_location.lat, step.end_location.lng,
                                                                      InterpreteEnums.InterpreteTravelMode(step.travel_mode),
                                                                      step.html_instructions, step.maneuver));
                            }

                            //update plan element times
                            planElement.UpdateDateTimeWithRouteDuration(planRoute.TimeDuration);
                            planElement.EndingRoute = planRoute;
                        }
                    }

                    elements.Add(planElement);                                       //add to plan list
                    iterParams.SetCurrentLocation(planElement.Lat, planElement.Lng); // update currentLocation in iterParams
                    iterParams.CurrentDateTime = planElement.End;                    //update current time in iterParams
                    ++iterParams.OrderNo;                                            //increase iter)
                    iterParams.ClearIfEndOfCurrentDay();
                }
                catch (Exception e)
                {
                    var error = e.InnerException;
                    break;
                }
            }

            return(elements);
        }