public async Task <Plan> CreateAsync(PlanForm planForm)
        {
            await EventBus.TriggerAsync(new EventSearchPlace(planForm)); //update SearchedPlaces DB

            await _planFormRepository.InsertAsync(planForm);

            var plan = await _planProvider.GenerateAsync(planForm);

            await _planRepository.InsertAsync(plan);

            plan.Photo = await _placePhotoManager.GetPhotos(plan.PlanForm.PlaceId);

            //foreach(var element in plan.Elements)
            //{
            //    await _planElementRepository.InsertAsync(element);

            //    if(element.EndingRoute != null)
            //    {
            //        await _planRouteRepository.InsertAsync(element.EndingRoute);

            //        foreach(var step in element.EndingRoute.Steps)
            //        {
            //            await _planRouteStepRepository.InsertAsync(step);
            //        }
            //    }
            //}

            return(plan);
        }
Exemple #2
0
        // Co sprawdzić
        // -> różnica dat -> 2 tygodnie?
        // -> Timespan must be?


        public async Task CheckFormValidAsync(PlanForm planForm)
        {
            if (!planForm.IsDatesCorrect())
            {
                throw new UserFriendlyException("Trip start or end data are incorrect!");
            }
            //if (!(await _planDataProvider.IsPlaceIdValid(planForm.PlaceId)))
            //{
            //    throw new UserFriendlyException("PlaceId is incorrect!");
            //}
        }
        public async Task <Plan> GenerateAsync(PlanForm planForm)
        {
            // 1. Create decision array
            var DecisionArray = new DecisionArray();

            // 2. Create plan object. Validate desitnation and accomodation.
            var destinationInfo = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(planForm.PlaceId));

            var plan = new Plan(destinationInfo.Result.name, destinationInfo.Result.geometry.location.lat, destinationInfo.Result.geometry.location.lng,
                                (decimal?)destinationInfo.Result.rating, (decimal?)destinationInfo.Result.user_ratings_total, destinationInfo.Result.formatted_address);

            if (planForm.HasAccomodationBooked)
            {
                var accomodationInfo = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(planForm.AccomodationId));

                plan.PlanAccomodation = new PlanAccomodation(accomodationInfo.Result.geometry.location.lat, accomodationInfo.Result.geometry.location.lng, planForm.AccomodationId,
                                                             accomodationInfo.Result.name, accomodationInfo.Result.formatted_address, (decimal?)accomodationInfo.Result.rating, (decimal?)accomodationInfo.Result.user_ratings_total);

                var distance = CalculateDistance(plan.Latitude, plan.Longitude, plan.PlanAccomodation.Lat, plan.PlanAccomodation.Lng);

                if (distance > MaximumDistanceToAccomodation) //more than 15km
                {
                    throw new UserFriendlyException($"Odległość między celem podróży a miejscem zakwaterowania nie może być większa nić {(int)(MaximumDistanceToAccomodation/1000)} km");
                }
            }

            plan.PlanForm    = planForm;
            plan.Assumptions = new PlanAssumptions(planForm);

            // 3. Generate weight vector based on user preferences
            DecisionArray.WeightVector = _weightVectorProvider.Generate(planForm);
            plan.PlanFormWeightVector  = PlanFormWeightVector.Create(DecisionArray.WeightVector);

            // 4. Get plan candidates
            var candidates = await _planElementCandidateFactory.GetCandidates(plan, DecisionArray.WeightVector);

            //5. Create decision row with values based on candidates
            int init = 1;

            foreach (var candidate in candidates)
            {
                DecisionArray.DecisionRows.Add(_decisionRowFactory.Create(candidate, init, plan.StartLocation));
                ++init;
            }

            // 6. SCORE FUNCTION -> SAW Normalization (3 types - chosen first) and then calculate Score
            var minVector = DecisionArray.GetMinVector();
            var maxVector = DecisionArray.GetMaxVector();

            foreach (var decisionRow in DecisionArray.DecisionRows)
            {
                decisionRow.NormalizedScore = _sawMethod.CalculateNormalizedScore(SawNormalizationMethod.LinearFirstType, DecisionArray.WeightVector, decisionRow.DecisionValues, minVector, maxVector);
            }

            // 7. Clasification
            DecisionArray.DecisionRows = DecisionArray.DecisionRows.OrderByDescending(x => x.NormalizedScore).ToList();
            int newPos = 1;

            foreach (var row in DecisionArray.DecisionRows)
            {
                row.ScorePosition = newPos;
                ++newPos;
            }

            // 8. Create Plan based on decision rows and optimize routes with travel salesman problem
            plan.Elements = await _planElementsProvider.GenerateAsync(DecisionArray, plan);

            return(plan);
        }
Exemple #4
0
        //0. Price //1. Rating //2. Distance //3. Popularity
        //4.Entertainment //5. Relax //6. Activity //7. Culture //8. Sightseeing //9. Partying //10. Shopping

        public WeightVector Generate(PlanForm planForm)
        {
            var weightVector = new WeightVector();

            //-----------Dajemy na typy elementów planu 0.5m---------------
            var     allPreferedStep     = Math.Round(0.3m / (planForm.PreferedPlanElements.Count()), 2);//max 0.3/14
            decimal totalSecondCategory = 0.5m;

            //PreferedPlanElements moze mieć po maks. 2 elementy nalezace do typów od 4 do 10 -> licz.el * allPreferedStep
            weightVector.AddValue(WeightVectorLabel.Entertainment, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Entertainment));
            weightVector.AddValue(WeightVectorLabel.Sightseeing, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Sightseeing));
            weightVector.AddValue(WeightVectorLabel.Activity, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Activity));
            weightVector.AddValue(WeightVectorLabel.Culture, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Culture));
            weightVector.AddValue(WeightVectorLabel.Relax, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Relax));
            weightVector.AddValue(WeightVectorLabel.Partying, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Partying));
            weightVector.AddValue(WeightVectorLabel.Shopping, allPreferedStep * planForm.PreferedPlanElements.Count(x => x == PlanElementType.Shopping));

            var allSortedStep = Math.Round((totalSecondCategory - weightVector.GetTotalSum()) / 9, 2);
            var remainingRest = (totalSecondCategory - weightVector.GetTotalSum()) - 9 * allSortedStep;

            //SortedPlanElements - punkty za miejsca : 3,2,2,1,1,0,0
            for (int i = 0; i < planForm.SortedPlanElements.Count; i++)
            {
                decimal bonus = 0;
                switch (i)
                {
                case 0:
                    bonus = allSortedStep * 3 + remainingRest;
                    break;

                case 1:
                case 2:
                    bonus = allSortedStep * 2;
                    break;

                case 3:
                case 4:
                    bonus = allSortedStep * 1;
                    break;

                default:
                    break;
                }

                if (planForm.SortedPlanElements[i] == PlanElementType.Entertainment)
                {
                    weightVector.AddValue(WeightVectorLabel.Entertainment, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Sightseeing)
                {
                    weightVector.AddValue(WeightVectorLabel.Sightseeing, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Activity)
                {
                    weightVector.AddValue(WeightVectorLabel.Activity, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Culture)
                {
                    weightVector.AddValue(WeightVectorLabel.Culture, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Relax)
                {
                    weightVector.AddValue(WeightVectorLabel.Relax, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Partying)
                {
                    weightVector.AddValue(WeightVectorLabel.Partying, bonus);
                }
                else if (planForm.SortedPlanElements[i] == PlanElementType.Shopping)
                {
                    weightVector.AddValue(WeightVectorLabel.Shopping, bonus);
                }
            }



            //-----------Dajemy na te 0.5---------------
            decimal totalFirstCategory = 0.5m;

            weightVector.SetPriority(WeightVectorLabel.Rating, 0.2m);
            totalFirstCategory -= 0.2m;
            var partsToDivide = 1;

            //Price
            if (planForm.PricePreference == PricePreference.Cheapest)
            {
                weightVector.AddValue(WeightVectorLabel.Price, 0.1m);
                totalFirstCategory -= 0.1m;
                partsToDivide      += 2;
            }
            else if (planForm.PricePreference == PricePreference.MediumPrices)
            {
                weightVector.AddValue(WeightVectorLabel.Price, 0.05m);
                totalFirstCategory -= 0.05m;
                partsToDivide      += 1;
            }

            //Popularity
            if (planForm.AtractionPopularityPreference == AtractionPopularityPreference.MostPopular)
            {
                weightVector.AddValue(WeightVectorLabel.Popularity, 0.1m);
                totalFirstCategory -= 0.1m;
                partsToDivide      += 2;
            }
            else if (planForm.AtractionPopularityPreference == AtractionPopularityPreference.MixedPopular)
            {
                weightVector.AddValue(WeightVectorLabel.Popularity, 0.05m);
                totalFirstCategory -= 0.05m;
                partsToDivide      += 1;
            }
            else if (planForm.AtractionPopularityPreference == AtractionPopularityPreference.NotWellKnown)
            {
                weightVector.AddValue(WeightVectorLabel.Popularity, 0m);
                totalFirstCategory -= 0.00m;
            }

            //Distance - im blizej tym bardziej wazne
            if (planForm.DistanceTypePreference == DistanceTypePreference.OnlyClosest)
            {
                weightVector.AddValue(WeightVectorLabel.Distance, 0.1m);
                totalFirstCategory -= 0.1m;
                partsToDivide      += 2;
            }
            else if (planForm.DistanceTypePreference == DistanceTypePreference.MediumDistances)
            {
                weightVector.AddValue(WeightVectorLabel.Distance, 0.05m);
                totalFirstCategory -= 0.05m;
                partsToDivide      += 1;
            }
            else if (planForm.DistanceTypePreference == DistanceTypePreference.LongDistances)
            {
                weightVector.AddValue(WeightVectorLabel.Distance, 0m);
                totalFirstCategory -= 0.00m;
            }

            if (totalFirstCategory > 0)
            {
                var totalFirstCategoryStep = Math.Round(totalFirstCategory / partsToDivide, 2);

                if (planForm.PricePreference == PricePreference.Cheapest)
                {
                    weightVector.AddValue(WeightVectorLabel.Price, 2 * totalFirstCategoryStep);
                }
                else if (planForm.PricePreference == PricePreference.MediumPrices)
                {
                    weightVector.AddValue(WeightVectorLabel.Price, 1 * totalFirstCategoryStep);
                }

                if (planForm.AtractionPopularityPreference == AtractionPopularityPreference.MostPopular)
                {
                    weightVector.AddValue(WeightVectorLabel.Popularity, 2 * totalFirstCategoryStep);
                }
                else if (planForm.AtractionPopularityPreference == AtractionPopularityPreference.MixedPopular)
                {
                    weightVector.AddValue(WeightVectorLabel.Popularity, 1 * totalFirstCategoryStep);
                }

                if (planForm.DistanceTypePreference == DistanceTypePreference.OnlyClosest)
                {
                    weightVector.AddValue(WeightVectorLabel.Distance, 2 * totalFirstCategoryStep);
                }
                else if (planForm.DistanceTypePreference == DistanceTypePreference.MediumDistances)
                {
                    weightVector.AddValue(WeightVectorLabel.Distance, 1 * totalFirstCategoryStep);
                }

                weightVector.AddValue(WeightVectorLabel.Rating, 1.0m - weightVector.GetTotalSum());
            }
            var test = weightVector.Total;

            return(weightVector);
        }
        public PlanAssumptions(PlanForm planForm)
        {
            SleepDuration = new TimeSpan(planForm.AverageSleep, 0, 0);
            var numberOfPartyActivity = planForm.PreferedPlanElements.Count(x => x == Enums.PlanElementType.Partying) + (planForm.SortedPlanElements.IndexOf(Enums.PlanElementType.Partying) < 3 ? 1 : 0);

            switch (numberOfPartyActivity)
            {
            case 1:
                SleepingTime = new TimeSpan(0, 0, 0);
                break;

            case 2:
                SleepingTime = new TimeSpan(1, 0, 0);
                break;

            case 3:
                SleepingTime = new TimeSpan(2, 0, 0);
                break;

            default:
                SleepingTime = new TimeSpan(23, 0, 0);
                break;
            }

            LunchTime  = new TimeSpan(14, 0, 0);
            DinnerTime = new TimeSpan(19, 0, 0);

            if (planForm.AtractionDurationPreference == Enums.PlanFormEnums.AtractionDurationPreference.Fast)
            {
                EatingDuration      = new TimeSpan(1, 0, 0);
                PlanElementDuration = new TimeSpan(1, 30, 0);
            }
            else if (planForm.AtractionDurationPreference == Enums.PlanFormEnums.AtractionDurationPreference.Medium)
            {
                EatingDuration      = new TimeSpan(1, 30, 0);
                PlanElementDuration = new TimeSpan(2, 30, 0);
            }
            else if (planForm.AtractionDurationPreference == Enums.PlanFormEnums.AtractionDurationPreference.Slow)
            {
                EatingDuration      = new TimeSpan(2, 0, 0);
                PlanElementDuration = new TimeSpan(3, 30, 0);
            }

            //radius search
            var hasVehicleTransport = planForm.PreferedTravelModes.Contains(Enums.GoogleTravelMode.Driving) || planForm.PreferedTravelModes.Contains(Enums.GoogleTravelMode.Transit);

            if (hasVehicleTransport)
            {
                RadiusSearch = 15000;
            }
            else
            {
                RadiusSearch = 6000;
            }

            //numbersOfElements
            var subTimeSpan  = planForm.EndDateTime.Subtract(planForm.StartDateTime);
            var subHours     = subTimeSpan.Days * 24 + subTimeSpan.Hours;
            var numberOfDays = (planForm.EndDateTime.DayOfYear - planForm.StartDateTime.DayOfYear + 1);

            subHours -= (numberOfDays - 1) * planForm.AverageSleep; // odejmujemy czas na spanie
            var eatingHours = EatingDuration.Multiply(NumberOfMealsPerDay * numberOfDays).Days *24 + EatingDuration.Multiply(NumberOfMealsPerDay * numberOfDays).Hours;

            subHours -= eatingHours;                                 // odejmujemy czas na jedzenie
            decimal hoursPerPlanElement = PlanElementDuration.Hours; // ((decimal)PlanElementDuration.Minutes / 60);

            if (PlanElementDuration.Minutes > 0)
            {
                hoursPerPlanElement += 0.5m;
            }
            //Assume that moving is about 10% of plan
            subHours -= (int)(0.1m * (decimal)subHours);

            var assumedNumberOfElements = (int)((decimal)subHours / hoursPerPlanElement);

            AssumedNumberOfElement = assumedNumberOfElements;
        }