Beispiel #1
0
        public async Task <PlanElementCandidate> GenerateAsync(DecisionArray decisionArray, Plan plan, int whichMeal, PlanElementIteratorParams iterParams)
        {
            var test = true;
            //choose type based on preferences
            var type                  = (plan.PlanForm.FoodPreference == FoodPreference.OnlyRestaurant || (plan.PlanForm.FoodPreference == FoodPreference.Mixed && whichMeal == 2)) ? GooglePlaceTypeCategory.Restaurant : GooglePlaceTypeCategory.Food;
            var candidates            = new List <PlanElementCandidate>();
            var decisionRows          = new List <DecisionRow>();
            var googleNearbyFoodInput = _googlePlaceNearbySearchInputFactory.Create(iterParams.CurrentLocation, type);
            var nearbyFoodResults     = await _googlePlaceNearbySearchApiClient.GetAsync(googleNearbyFoodInput);

            int counter = 1;

            foreach (var nr in nearbyFoodResults.results)
            {
                var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(nr.place_id));

                if (details.IsOk)
                {
                    var candidate = new PlanElementCandidate(details.Result.name, details.Result.place_id, details.Result.formatted_address, details.Result.geometry.location, details.Result.opening_hours, details.Result.types, details.Result.rating, details.Result.price_level, details.Result.user_ratings_total);
                    if (test)
                    {
                        return(candidate);
                    }

                    candidates.Add(candidate);
                }
                ++counter;
                if (counter > 10 && candidates.Count > 5)
                {
                    break;
                }
            }



            var iter = 1;

            foreach (var candidate in candidates)
            {
                decisionRows.Add(_decisionRowFactory.Create(candidate, iter, iterParams.CurrentLocation));
                ++iter;
            }

            var minVector = DecisionArray.GetMinVector(decisionRows);
            var maxVector = DecisionArray.GetMaxVector(decisionRows);

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

            var result = decisionRows.OrderByDescending(x => x.NormalizedScore).FirstOrDefault(x => x.Candidate.IsOpen(iterParams.CurrentDateTime));

            if (result == null)
            {
                throw new UserFriendlyException($"Nie udało się znaleźć żadnego miejsca, gdzie można zjeść w pobliżu o godz: {iterParams.CurrentDateTime}");
            }

            return(result.Candidate);
        }
Beispiel #2
0
        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);
        }
        public async Task <IList <PlanElementCandidate> > GetCandidates(Plan plan, WeightVector weightVector)
        {
            var test       = true;
            var candidates = new List <PlanElementCandidate>();

            PlanElementType[] planElementTypes = new PlanElementType[]
            {
                PlanElementType.Entertainment,
                PlanElementType.Relax,
                PlanElementType.Activity,
                PlanElementType.Culture,
                PlanElementType.Sightseeing,
                PlanElementType.Partying,
                PlanElementType.Shopping,
            };


            foreach (var planElementType in planElementTypes)
            {
                var googlePlaceTypes = GooglePlaceTypes.Table.Where(x => x.PlanElementType == planElementType).ToList();

                foreach (var type in googlePlaceTypes)
                {
                    var nearbySearchInput = _googlePlaceNearbySearchInputFactory.Create(plan.StartLocation, (int)MaximumDistanceToAccomodation, type);
                    var nearbyResults     = await _googlePlaceNearbySearchApiClient.GetAsync(nearbySearchInput);

                    int counter = 1;
                    foreach (var nr in nearbyResults.results)
                    {
                        var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(nr.place_id));

                        if (details.IsOk)
                        {
                            var candidate = new PlanElementCandidate(details.Result.name, details.Result.place_id, details.Result.formatted_address, details.Result.geometry.location, details.Result.opening_hours, details.Result.types, details.Result.rating, details.Result.price_level, details.Result.user_ratings_total);
                            if (!candidates.Any(x => x.PlaceId == candidate.PlaceId))
                            {
                                candidates.Add(candidate);
                            }
                        }
                        ++counter;
                    }

                    if (test && candidates.Count > 15)
                    {
                        return(candidates);
                    }

                    WeightVectorLabel weightVectorLabel = WeightVector.TranslateLabel(planElementType);

                    if ((plan.PlanForm.IsOverOneWeek || weightVector.GetLabelValue(weightVectorLabel) >= 0.1m) && nearbyResults.IsMoreResults)
                    {
                        var nearbyResults2 = await _googlePlaceNearbySearchApiClient.GetNextPageTokenAsync(nearbyResults.next_page_token);

                        foreach (var nr in nearbyResults2.results)
                        {
                            var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreateAllUseful(nr.place_id));

                            if (details.IsOk)
                            {
                                var candidate = new PlanElementCandidate(details.Result.name, details.Result.place_id, details.Result.formatted_address, details.Result.geometry.location, details.Result.opening_hours, details.Result.types, details.Result.rating, details.Result.price_level, details.Result.user_ratings_total);

                                if (!candidates.Any(x => x.PlaceId == candidate.PlaceId))
                                {
                                    candidates.Add(candidate);
                                }
                            }
                            ++counter;
                        }
                    }

                    if (test && candidates.Count > 15)
                    {
                        return(candidates);
                    }
                }

                if (test && candidates.Count > 15)
                {
                    break;
                }
            }

            if (candidates.Count == 0)
            {
                throw new UserFriendlyException($"Nie znaleziono żadnych potencjalnych kandydatów na elementy planu");
            }

            return(candidates);
        }