diff --git a/backend/src/landmarks_manager.py b/backend/src/landmarks_manager.py index 8592e00..da04088 100644 --- a/backend/src/landmarks_manager.py +++ b/backend/src/landmarks_manager.py @@ -9,9 +9,12 @@ from typing import Tuple BBOX_SIDE = 10 # size of bbox in *km* for general area, 10km -RADIUS_CLOSE_TO = 25 # size of area in *m* for close features, 5àm radius -MIN_SCORE = 30 # discard elements with score < 100 -MIN_TAGS = 5 # discard elements withs less than 5 tags +RADIUS_CLOSE_TO = 25 # size of area in *m* for close features, 25m radius +MIN_SCORE = 30 # DEPRECIATED. discard elements with score < 30 +MIN_TAGS = 5 # DEPRECIATED. discard elements withs less than 5 tags +CHURCH_PENALTY = 0.1 # penalty to reduce score of curches +PARK_COEFF = 10 # multiplier for parks +N_IMPORTANT = 30 # take the 30 most important landmarks SIGHTSEEING = LandmarkType(landmark_type='sightseeing') NATURE = LandmarkType(landmark_type='nature') @@ -71,7 +74,8 @@ def generate_landmarks(preferences: Preferences, city_country: str = None, coord L += L3 - return L, cleanup_list(L) + return L, take_most_important(L) + #return L, cleanup_list(L) # Determines if two locations are close to each other def is_close_to(loc1: Tuple[float, float], loc2: Tuple[float, float])->bool : @@ -82,6 +86,45 @@ def is_close_to(loc1: Tuple[float, float], loc2: Tuple[float, float])->bool : else : return False + +def take_most_important(L: List[Landmark])->List[Landmark] : + L_copy = [] + L_clean = [] + scores = [0]*len(L) + names = [] + name_id = {} + + for i, elem in enumerate(L) : + if elem.name not in names : + names.append(elem.name) + name_id[elem.name] = [i] + L_copy.append(elem) + else : + name_id[elem.name] += [i] + scores = [] + for j in name_id[elem.name] : + scores.append(L[j].attractiveness) + best_id = max(range(len(scores)), key=scores.__getitem__) + t = name_id[elem.name][best_id] + if t == i : + for old in L_copy : + if old.name == elem.name : + old.attractiveness = L[t].attractiveness + + continue + + for i, elem in enumerate(L_copy) : + scores[i] = elem.attractiveness + + res = sorted(range(len(scores)), key = lambda sub: scores[sub])[-N_IMPORTANT:] + + for i, elem in enumerate(L_copy) : + if i in res : + L_clean.append(elem) + + return L_clean + + # Remove duplicate elements and elements with low score def cleanup_list(L: List[Landmark])->List[Landmark] : L_clean = [] @@ -207,6 +250,11 @@ def get_landmarks_coords(coordinates: Tuple[float, float], l: List[Landmark], la # skip if unprecise location if name is None or location[0] is None: continue + + # skip if unused + if 'disused:leisure' in elem.tags().keys(): + continue + else : osm_type = elem.type() # Add type : 'way' or 'relation' @@ -214,8 +262,16 @@ def get_landmarks_coords(coordinates: Tuple[float, float], l: List[Landmark], la elem_type = landmarktype # Add the landmark type as 'sightseeing n_tags = len(elem.tags().keys()) # Add number of tags - # Add score of given landmark based on the number of surrounding elements - score = count_elements_within_radius(location) + # Add score of given landmark based on the number of surrounding elements. Penalty for churches as there are A LOT + if amenity == "'amenity'='place_of_worship'" : + score = int(count_elements_within_radius(location)*CHURCH_PENALTY) + elif amenity == "'leisure'='park'" : + score = int(count_elements_within_radius(location)*PARK_COEFF) + else : + score = count_elements_within_radius(location) + + if name == "Jardin du Luxembourg" : + continue if score is not None : # Generate the landmark and append it to the list @@ -247,6 +303,11 @@ def get_landmarks_nominatim(city_country: str, l: List[Landmark], landmarktype: # skip if unprecise location if name is None or location[0] is None: continue + + # skip if unused + if 'disused:leisure' in elem.tags().keys(): + continue + else : osm_type = elem.type() # Add type : 'way' or 'relation' @@ -255,7 +316,11 @@ def get_landmarks_nominatim(city_country: str, l: List[Landmark], landmarktype: n_tags = len(elem.tags().keys()) # Add number of tags # Add score of given landmark based on the number of surrounding elements - score = count_elements_within_radius(location) + if amenity == "'amenity'='place_of_worship'" : + score = int(count_elements_within_radius(location)*CHURCH_PENALTY) + else : + score = count_elements_within_radius(location) + if score is not None : # Generate the landmark and append it to the list diff --git a/backend/src/optimizer.py b/backend/src/optimizer.py index 6b6f192..a5f0fc3 100644 --- a/backend/src/optimizer.py +++ b/backend/src/optimizer.py @@ -498,14 +498,15 @@ def solve_optimization (landmarks, max_steps, printing_details) : print(i) i += 1 + t, order, [] = is_connected(res.x, landmarks) + if printing_details is True : if i != 0 : print(f"Neded to recompute paths {i} times because of unconnected loops...") - t, order, [] = is_connected(res.x, landmarks) - X = print_res(res, order, landmarks, P) - return X - else : - return untangle(res.x) + + print_res(res, order, landmarks, P) + + return order diff --git a/backend/src/structs/landmarks.py b/backend/src/structs/landmarks.py index 61715bf..a474c0b 100644 --- a/backend/src/structs/landmarks.py +++ b/backend/src/structs/landmarks.py @@ -1,3 +1,4 @@ +from typing import Optional from pydantic import BaseModel from OSMPythonTools.api import Api from .landmarktype import LandmarkType @@ -18,5 +19,6 @@ class Landmark(BaseModel) : attractiveness : int must_do : bool n_tags : int + time_to_reach : Optional[int] = 0 diff --git a/backend/src/tester.py b/backend/src/tester.py index 45a3b7c..18a28c5 100644 --- a/backend/src/tester.py +++ b/backend/src/tester.py @@ -82,6 +82,7 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]: test.append(finish) test.insert(0, start) + max_walking_time = 4 # hours visiting_order = solve_optimization(test, max_walking_time*60, True)