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); }
public async Task <string> UpdatePhotos(string placeId, int count = 2) { var details = await _googlePlaceDetailsApiClient.GetAsync(_googlePlaceDetailsInputFactory.CreatePhotoReference(placeId)); if (InterpreteGoogleStatus.IsStatusOk(details.status)) { var maxPhotoNum = 1; var photo = String.Empty; foreach (var item in details.Result.photos) { photo = await _googlePlacePhotosApiCaller.GetPhotoAsync(item.photo_reference, 600, null); if (!String.IsNullOrWhiteSpace(photo)) { await _placePhotoRepository.InsertAsync(new PlacePhoto(placeId, item.photo_reference, photo)); } maxPhotoNum += 1; if (maxPhotoNum >= count) { break; } } return(photo); } else { return(String.Empty); } }
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); }