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 <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); }