Upgraded refiner
All checks were successful
Build and push docker image / Build (pull_request) Successful in 3m8s
Build and release APK / Build APK (pull_request) Successful in 5m0s
Build web / Build Web (pull_request) Successful in 1m41s

This commit is contained in:
Helldragon67 2024-06-24 11:06:01 +02:00
parent 813c83a81d
commit 8d068c80a7
8 changed files with 1126 additions and 1135 deletions

View File

@ -15,7 +15,33 @@ SHOPPING = LandmarkType(landmark_type='shopping')
# Include the json here
# Create a list of all things to visit given some preferences and a city. Ready for the optimizer
def generate_landmarks(preferences: Preferences, city_country: str = None, coordinates: Tuple[float, float] = None) -> Tuple[List[Landmark], List[Landmark]] :
def generate_landmarks(preferences: Preferences, coordinates: Tuple[float, float]) :
l_sights, l_nature, l_shop = get_amenities()
L = []
# List for sightseeing
if preferences.sightseeing.score != 0 :
L1 = get_landmarks(l_sights, SIGHTSEEING, coordinates=coordinates)
correct_score(L1, preferences.sightseeing)
L += L1
# List for nature
if preferences.nature.score != 0 :
L2 = get_landmarks(l_nature, NATURE, coordinates=coordinates)
correct_score(L2, preferences.nature)
L += L2
# List for shopping
if preferences.shopping.score != 0 :
L3 = get_landmarks(l_shop, SHOPPING, coordinates=coordinates)
correct_score(L3, preferences.shopping)
L += L3
return remove_duplicates(L), take_most_important(L)
"""def generate_landmarks(preferences: Preferences, city_country: str = None, coordinates: Tuple[float, float] = None) -> Tuple[List[Landmark], List[Landmark]] :
l_sights, l_nature, l_shop = get_amenities()
L = []
@ -39,8 +65,7 @@ def generate_landmarks(preferences: Preferences, city_country: str = None, coord
L += L3
return remove_duplicates(L), take_most_important(L)
"""
# Helper function to gather the amenities list
def get_amenities() -> List[List[str]] :
@ -199,7 +224,71 @@ def create_bbox(coordinates: Tuple[float, float], side_length: int) -> Tuple[flo
return min_lat, min_lon, max_lat, max_lon
def get_landmarks(list_amenity: list, landmarktype: LandmarkType, city_country: str = None, coordinates: Tuple[float, float] = None) -> List[Landmark] :
def get_landmarks(list_amenity: list, landmarktype: LandmarkType, coordinates: Tuple[float, float]) -> List[Landmark] :
# Read the parameters from the file
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/landmarks_manager.params', "r") as f :
parameters = json.loads(f.read())
tag_coeff = parameters['tag coeff']
park_coeff = parameters['park coeff']
church_coeff = parameters['church coeff']
radius = parameters['radius close to']
bbox_side = parameters['city bbox side']
# Create bbox around start location
bbox = create_bbox(coordinates, bbox_side)
# Initialize some variables
N = 0
L = []
overpass = Overpass()
for amenity in list_amenity :
query = overpassQueryBuilder(bbox=bbox, elementType=['way', 'relation'], selector=amenity, includeCenter=True, out='body')
result = overpass.query(query)
N += result.countElements()
for elem in result.elements():
name = elem.tag('name') # Add name
location = (elem.centerLat(), elem.centerLon()) # Add coordinates (lat, lon)
# 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
# skip if part of another building
if 'building:part' in elem.tags().keys() and elem.tag('building:part') == 'yes':
continue
else :
osm_type = elem.type() # Add type : 'way' or 'relation'
osm_id = elem.id() # Add OSM id
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. Penalty for churches as there are A LOT
if amenity == "'amenity'='place_of_worship'" :
score = int((count_elements_within_radius(location, radius) + n_tags*tag_coeff )*church_coeff)
elif amenity == "'leisure'='park'" :
score = int((count_elements_within_radius(location, radius) + n_tags*tag_coeff )*park_coeff)
else :
score = count_elements_within_radius(location, radius) + n_tags*tag_coeff
if score is not None :
# Generate the landmark and append it to the list
landmark = Landmark(name=name, type=elem_type, location=location, osm_type=osm_type, osm_id=osm_id, attractiveness=score, must_do=False, n_tags=n_tags)
L.append(landmark)
return L
"""def get_landmarks(list_amenity: list, landmarktype: LandmarkType, city_country: str = None, coordinates: Tuple[float, float] = None) -> List[Landmark] :
if city_country is None and coordinates is None :
raise ValueError("Either one of 'city_country' and 'coordinates' arguments must be specified")
@ -277,3 +366,4 @@ def get_landmarks(list_amenity: list, landmarktype: LandmarkType, city_country:
L.append(landmark)
return L
"""

View File

@ -1,6 +1,6 @@
from optimizer import solve_optimization
from refiner import refine_optimization
from landmarks_manager import generate_landmarks
from structs.landmarks import LandmarkTest
from structs.landmarks import Landmark
from structs.landmarktype import LandmarkType
from structs.preferences import Preferences, Preference
@ -12,35 +12,45 @@ app = FastAPI()
# Assuming frontend is calling like this :
#"http://127.0.0.1:8000/process?param1={param1}&param2={param2}"
@app.post("/optimizer_coords/{latitude}/{longitude}/{city_country}")
def main1(preferences: Preferences = Body(...), latitude: float = None, longitude: float = None, city_country: str = None) -> List[Landmark]:
@app.post("/optimizer_coords/{start_lat}/{start_lon}/{finish_lat}/{finish_lon}")
def main1(start_lat: float, start_lon: float, preferences: Preferences = Body(...), finish_lat: float = None, finish_lon: float = None) -> List[Landmark]:
if preferences is None :
raise ValueError("Please provide preferences in the form of a 'Preference' BaseModel class.")
elif latitude is None and longitude is None and city_country is None :
raise ValueError("Please provide GPS coordinates or a 'city_country' string.")
elif latitude is not None and longitude is not None and city_country is not None :
raise ValueError("Please provide EITHER GPS coordinates or a 'city_country' string.")
if bool(start_lat) ^ bool(start_lon) :
raise ValueError("Please provide both latitude and longitude for the starting point")
if bool(finish_lat) ^ bool(finish_lon) :
raise ValueError("Please provide both latitude and longitude for the finish point")
# From frontend get longitude, latitude and prefence list
if city_country is None :
coordinates = tuple((latitude, longitude))
start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(start_lat, start_lon), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
if bool(finish_lat) and bool(finish_lon) :
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(finish_lat, finish_lon), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
else :
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(start_lat, start_lon), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
[], landmarks_short = generate_landmarks(preferences=preferences, city_country=city_country, coordinates=coordinates)
start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(48.8375946, 2.2949904), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.8375946, 2.2949904), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
# Generate the landmarks from the start location
landmarks, landmarks_short = generate_landmarks(preferences=preferences, coordinates=start.location)
# insert start and finish to the landmarks list
landmarks_short.insert(0, start)
landmarks_short.append(finish)
max_walking_time = 4 # hours
# TODO use these parameters in another way
max_walking_time = 4 # hours
detour = 30 # minutes
visiting_list = solve_optimization(landmarks_short, max_walking_time*60, True)
return visiting_list
# First stage optimization
base_tour = solve_optimization(landmarks_short, max_walking_time*60, True)
# Second stage optimization
refined_tour = refine_optimization(landmarks, base_tour, max_walking_time*60+detour, True)
return refined_tour

View File

@ -141,19 +141,19 @@ def get_distance(p1: Tuple[float, float], p2: Tuple[float, float], detour: float
else:
dist = 6371.01 * acos(sin(radians(p1[0]))*sin(radians(p2[0])) + cos(radians(p1[0]))*cos(radians(p2[0]))*cos(radians(p1[1]) - radians(p2[1])))
# Consider the detour factor for average city
wdist = dist*detour
# Consider the detour factor for average cityto deterline walking distance (in km)
walk_dist = dist*detour
# Time to walk this distance (in minutes)
wtime = wdist/speed*60
walk_time = walk_dist/speed*60
if wtime > 15 :
wtime = 5*round(wtime/5)
if walk_time > 15 :
walk_time = 5*round(walk_time/5)
else :
wtime = round(wtime)
walk_time = round(walk_time)
return round(wdist, 1), wtime
return round(walk_dist, 1), walk_time
# Initialize A and c. Compute the distances from all landmarks to each other and store attractiveness
@ -291,27 +291,47 @@ def respect_order(N: int, A_eq, b_eq):
# Computes the path length given path matrix (dist_table) and a result
def add_time_to_reach(order: List[Landmark], landmarks: List[Landmark])->List[Landmark] :
j = 0
L = []
def add_time_to_reach(order: List[int], landmarks: List[Landmark])->List[Landmark] :
# Read the parameters from the file
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/optimizer.params', "r") as f :
parameters = json.loads(f.read())
detour = parameters['detour factor']
detour_factor = parameters['detour factor']
speed = parameters['average walking speed']
j = 0
L = []
prev = landmarks[0]
while(len(L) != len(order)) :
elem = landmarks[order[j]]
if elem != prev :
elem.time_to_reach = get_distance(elem.location, prev.location, detour, speed)[1]
elem.time_to_reach = get_distance(elem.location, prev.location, detour_factor, speed)[1]
elem.must_do = True
L.append(elem)
prev = elem
j += 1
return L
def add_time_to_reach_simple(ordered_visit: List[Landmark])-> List[Landmark] :
# Read the parameters from the file
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/optimizer.params', "r") as f :
parameters = json.loads(f.read())
detour_factor = parameters['detour factor']
speed = parameters['average walking speed']
L = []
prev = ordered_visit[0]
L.append(prev)
for elem in ordered_visit[1:] :
elem.time_to_reach = get_distance(elem.location, prev.location, detour_factor, speed)[1]
elem.must_do = True
L.append(elem)
prev = elem
return L
@ -356,7 +376,7 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
# Add the times to reach and stop optimizing
L = add_time_to_reach(order, landmarks)
break
print(i)
#print(i)
i += 1
if i == timeout :

View File

@ -1,4 +1,4 @@
{
"detour factor" : 10,
"average walking speed" : 27.5
"detour factor" : 1.4,
"average walking speed" : 4.8
}

View File

@ -1,9 +1,10 @@
from shapely import buffer, LineString, Point, Polygon
from shapely import buffer, LineString, Point, Polygon, MultiPoint, convex_hull, concave_hull, LinearRing
from typing import List
from math import pi
from structs.landmarks import Landmark
from landmarks_manager import take_most_important
from optimizer import solve_optimization, add_time_to_reach_simple, print_res
def create_corridor(landmarks: List[Landmark], width: float) :
@ -34,10 +35,78 @@ def is_in_area(area: Polygon, coordinates) -> bool :
def get_minor_landmarks(all_landmarks: List[Landmark], visited_landmarks: List[Landmark], width: float) -> List[Landmark] :
second_order_landmarks = []
visited_names = []
area = create_corridor(visited_landmarks, width)
for visited in visited_landmarks :
visited_names.append(visited.name)
for landmark in all_landmarks :
if is_in_area(area, landmark.location) and landmark not in visited_landmarks:
if is_in_area(area, landmark.location) and landmark.name not in visited_names:
second_order_landmarks.append(landmark)
return take_most_important(second_order_landmarks)
return take_most_important(second_order_landmarks)
"""def refine_optimization(landmarks: List[Landmark], base_tour: List[Landmark], max_time: int, print_infos: bool) -> List[Landmark] :
minor_landmarks = get_minor_landmarks(landmarks, base_tour, 200)
if print_infos : print("There are " + str(len(minor_landmarks)) + " minor landmarks around the predicted path")
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
full_set.append(base_tour[-1]) # add finish back
new_route = solve_optimization(full_set, max_time, print_infos)
return new_route"""
def refine_optimization(landmarks: List[Landmark], base_tour: List[Landmark], max_time: int, print_infos: bool) -> List[Landmark] :
minor_landmarks = get_minor_landmarks(landmarks, base_tour, 200)
if print_infos : print("There are " + str(len(minor_landmarks)) + " minor landmarks around the predicted path")
# full set of visitable landmarks
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
full_set.append(base_tour[-1]) # add finish back
# get a new route
new_route = solve_optimization(full_set, max_time, False)
coords = [] # Coordinates of the new route
coords_dict = {} # maps the location of an element to the element itself. Used to access the elements back once we get the geometry
# Iterate through the new route without finish
for elem in new_route[:-1] :
coords.append(Point(elem.location))
coords_dict[elem.location] = elem # if start = goal, only finish remains
# Create a concave polygon using the coordinates
better_route_poly = concave_hull(MultiPoint(coords)) # Create concave hull with "core" of route leaving out start and finish
xs, ys = better_route_poly.exterior.xy
better_route = [] # List of ordered visit
name_index = {} # Maps the name of a landmark to its index in the concave polygon
# Loop through the polygon and generate the better (ordered) route
for i,x in enumerate(xs[:-1]) :
better_route.append(coords_dict[tuple((x,ys[i]))])
name_index[coords_dict[tuple((x,ys[i]))].name] = i
# Scroll the list to have start in front again
start_index = name_index['start']
better_route = better_route[start_index:] + better_route[:start_index]
# Append the finish back and correct the time to reach
better_route.append(new_route[-1])
better_route = add_time_to_reach_simple(better_route)
if print_infos :
print("\nRefined tour (result of second stage optimization): ")
print_res(better_route, len(better_route))
return better_route

View File

@ -5,7 +5,7 @@ from landmarks_manager import generate_landmarks
from fastapi.encoders import jsonable_encoder
from optimizer import solve_optimization
from refiner import get_minor_landmarks
from refiner import refine_optimization
from structs.landmarks import Landmark
from structs.landmarktype import LandmarkType
from structs.preferences import Preferences, Preference
@ -80,38 +80,32 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
type=LandmarkType(landmark_type='shopping'),
score = 5))
city_country = None
landmarks, landmarks_short = generate_landmarks(preferences=preferences, city_country=city_country, coordinates=coordinates)
# Create start and finish
start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=coordinates, osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=coordinates, osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
# Generate the landmarks from the start location
landmarks, landmarks_short = generate_landmarks(preferences=preferences, coordinates=start.location)
#write_data(landmarks, "landmarks.txt")
# Insert start and finish to the landmarks list
landmarks_short.insert(0, start)
landmarks_short.append(finish)
start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(48.8375946, 2.2949904), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.8375946, 2.2949904), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
test = landmarks_short
test.insert(0, start)
test.append(finish)
# TODO use these parameters in another way
max_walking_time = 4 # hours
detour = 30 # minutes
visited_list = solve_optimization(test, max_walking_time*60, True)
#visited_list = [Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(48.8375946, 2.2949904), osm_type='start', osm_id=0, attractiveness=0, must_do=True, n_tags=0, time_to_reach=0), Landmark(name='Palais du Louvre', type=LandmarkType(landmark_type='sightseeing'), location=(48.8614768, 2.3351677), osm_type='relation', osm_id=3262297, attractiveness=32, must_do=False, n_tags=32, time_to_reach=85), Landmark(name='Musée du Louvre', type=LandmarkType(landmark_type='sightseeing'), location=(48.8611474, 2.3358637), osm_type='relation', osm_id=7515426, attractiveness=34, must_do=False, n_tags=33, time_to_reach=1), Landmark(name='Bourse de Commerce — Pinault Collection', type=LandmarkType(landmark_type='sightseeing'), location=(48.8628167, 2.3428183), osm_type='way', osm_id=19856722, attractiveness=32, must_do=False, n_tags=32, time_to_reach=12), Landmark(name='Centre Georges Pompidou', type=LandmarkType(landmark_type='sightseeing'), location=(48.8605235, 2.3524395), osm_type='way', osm_id=55503397, attractiveness=43, must_do=False, n_tags=43, time_to_reach=15), Landmark(name='Tour Saint-Jacques', type=LandmarkType(landmark_type='sightseeing'), location=(48.8579983, 2.3489178), osm_type='way', osm_id=20326709, attractiveness=33, must_do=False, n_tags=31, time_to_reach=8), Landmark(name='Hôtel de Ville', type=LandmarkType(landmark_type='sightseeing'), location=(48.8564265, 2.352527), osm_type='relation', osm_id=284089, attractiveness=34, must_do=False, n_tags=32, time_to_reach=7), Landmark(name='Cathédrale Notre-Dame de Paris', type=LandmarkType(landmark_type='sightseeing'), location=(48.8529372, 2.3498701), osm_type='way', osm_id=201611261, attractiveness=55, must_do=False, n_tags=54, time_to_reach=9), Landmark(name='Sainte-Chapelle', type=LandmarkType(landmark_type='sightseeing'), location=(48.8553966, 2.3450136), osm_type='relation', osm_id=3344870, attractiveness=57, must_do=False, n_tags=54, time_to_reach=10), Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.8375946, 2.2949904), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags=0, time_to_reach=90)]
minor_landmarks = get_minor_landmarks(landmarks, visited_list, 200)
#write_data(minor_landmarks, 'minor_landmarks.txt')
print("There are " + str(len(minor_landmarks)) + " minor landmarks around the predicted path")
full_set = visited_list[:-1] + minor_landmarks[:30]
full_set.append(finish)
new_route = solve_optimization(full_set, max_walking_time*60+detour, True)
# First stage optimization
base_tour = solve_optimization(landmarks_short, max_walking_time*60, True)
return new_route
# Second stage optimization
refined_tour = refine_optimization(landmarks, base_tour, max_walking_time*60+detour, True)
return refined_tour
test4(tuple((48.8795156, 2.3660204)))
#test4(tuple((48.8344400, 2.3220540))) # Café Chez César
test4(tuple((48.8375946, 2.2949904))) # Point random
#test3('Vienna, Austria')

File diff suppressed because it is too large Load Diff

View File

@ -16,86 +16,198 @@
"time_to_reach":0
},
"1":{
"name":"Musée d'art et d'histoire du Judaïsme",
"name":"Musée de Cluny",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8612656,
2.355418
48.8506604,
2.3437398
],
"osm_type":"way",
"osm_id":56687783,
"attractiveness":9,
"must_do":false,
"n_tags":8,
"time_to_reach":0
},
"2":{
"name":"Musée Ernest-Hébert (en travaux)",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8473326,
2.3227159
],
"osm_type":"way",
"osm_id":64314872,
"attractiveness":10,
"must_do":false,
"n_tags":9,
"time_to_reach":0
},
"3":{
"name":"Crypte Archéologique du Parvis Notre-Dame",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8535851,
2.3480846
],
"osm_type":"way",
"osm_id":159896046,
"osm_id":56640163,
"attractiveness":18,
"must_do":false,
"n_tags":18,
"time_to_reach":0
},
"4":{
"name":"Jardin Catherine Labouré",
"2":{
"name":"Musée du Luxembourg",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8510562,
2.320532
48.8485965,
2.3340156
],
"osm_type":"way",
"osm_id":148481812,
"attractiveness":8,
"osm_id":170226810,
"attractiveness":15,
"must_do":false,
"n_tags":8,
"n_tags":15,
"time_to_reach":0
},
"3":{
"name":"Musée national Eugène Delacroix",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8546662,
2.3353836
],
"osm_type":"way",
"osm_id":395785603,
"attractiveness":15,
"must_do":false,
"n_tags":15,
"time_to_reach":0
},
"4":{
"name":"Hôtel de Sully",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.854635,
2.3638126
],
"osm_type":"relation",
"osm_id":403146,
"attractiveness":14,
"must_do":false,
"n_tags":13,
"time_to_reach":0
},
"5":{
"name":"Arc de Triomphe du Carrousel",
"name":"Hôtel de la Monnaie",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8617276,
2.3329082
48.856403,
2.3388625
],
"osm_type":"way",
"osm_id":227483542,
"attractiveness":16,
"osm_type":"relation",
"osm_id":967664,
"attractiveness":11,
"must_do":false,
"n_tags":11,
"time_to_reach":0
},
"6":{
"name":"Musée Bourdelle",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8432078,
2.3186583
],
"osm_type":"relation",
"osm_id":1212876,
"attractiveness":23,
"must_do":false,
"n_tags":23,
"time_to_reach":0
},
"7":{
"name":"Musée Carnavalet",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8576819,
2.3627147
],
"osm_type":"relation",
"osm_id":2405955,
"attractiveness":25,
"must_do":false,
"n_tags":25,
"time_to_reach":0
},
"8":{
"name":"Pont Neuf",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8565248,
2.3408132
],
"osm_type":"way",
"osm_id":53574149,
"attractiveness":16,
"must_do":false,
"n_tags":15,
"time_to_reach":0
},
"9":{
"name":"Jardin du Luxembourg",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8467137,
2.3363649
],
"osm_type":"way",
"osm_id":128206209,
"attractiveness":35,
"must_do":false,
"n_tags":23,
"time_to_reach":0
},
"10":{
"name":"Cathédrale Notre-Dame de Paris",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8529372,
2.3498701
],
"osm_type":"way",
"osm_id":201611261,
"attractiveness":55,
"must_do":false,
"n_tags":54,
"time_to_reach":0
},
"11":{
"name":"Maison à l'enseigne du Faucheur",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8558553,
2.3568266
],
"osm_type":"way",
"osm_id":1123456865,
"attractiveness":13,
"must_do":false,
"n_tags":11,
"time_to_reach":0
},
"12":{
"name":"Maison à l'enseigne du Mouton",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8558431,
2.3568914
],
"osm_type":"way",
"osm_id":1123456866,
"attractiveness":13,
"must_do":false,
"n_tags":11,
"time_to_reach":0
},
"13":{
"name":"Palais de Justice de Paris",
"type":{
"landmark_type":"sightseeing"
@ -111,7 +223,23 @@
"n_tags":24,
"time_to_reach":0
},
"7":{
"14":{
"name":"Mémorial des Martyrs de la Déportation",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8517365,
2.3524734
],
"osm_type":"relation",
"osm_id":9396191,
"attractiveness":21,
"must_do":false,
"n_tags":21,
"time_to_reach":0
},
"15":{
"name":"Fontaine des Innocents",
"type":{
"landmark_type":"sightseeing"
@ -127,7 +255,39 @@
"n_tags":15,
"time_to_reach":0
},
"8":{
"16":{
"name":"Hôtel de Sens",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8535257,
2.3588733
],
"osm_type":"way",
"osm_id":55541122,
"attractiveness":21,
"must_do":false,
"n_tags":20,
"time_to_reach":0
},
"17":{
"name":"Hôtel d'Ourscamp",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8555465,
2.3571206
],
"osm_type":"way",
"osm_id":55620201,
"attractiveness":10,
"must_do":false,
"n_tags":9,
"time_to_reach":0
},
"18":{
"name":"Hôtel de Choiseul-Praslin",
"type":{
"landmark_type":"sightseeing"
@ -143,23 +303,7 @@
"n_tags":12,
"time_to_reach":0
},
"9":{
"name":"Hôtel de Cassini",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8519819,
2.3209847
],
"osm_type":"way",
"osm_id":68571376,
"attractiveness":13,
"must_do":false,
"n_tags":13,
"time_to_reach":0
},
"10":{
"19":{
"name":"Chapelle Notre-Dame-des-Anges",
"type":{
"landmark_type":"sightseeing"
@ -175,7 +319,7 @@
"n_tags":16,
"time_to_reach":0
},
"11":{
"20":{
"name":"Fontaine du Palmier",
"type":{
"landmark_type":"sightseeing"
@ -191,103 +335,39 @@
"n_tags":14,
"time_to_reach":0
},
"12":{
"name":"Colonne Médicis",
"21":{
"name":"Église Saint-Séverin",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8625255,
2.3429926
48.8520913,
2.3457237
],
"osm_type":"way",
"osm_id":942543401,
"osm_id":19740659,
"attractiveness":15,
"must_do":false,
"n_tags":13,
"n_tags":25,
"time_to_reach":0
},
"13":{
"name":"Noviciat des Dominicains",
"22":{
"name":"Église Orthodoxe Roumaine des Saints Archanges",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8561352,
2.3284496
],
"osm_type":"relation",
"osm_id":1002118,
"attractiveness":8,
"must_do":false,
"n_tags":8,
"time_to_reach":0
},
"14":{
"name":"Hôtel de Matignon",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8544393,
2.320661
],
"osm_type":"relation",
"osm_id":1076880,
"attractiveness":13,
"must_do":false,
"n_tags":13,
"time_to_reach":0
},
"15":{
"name":"Ligne de Petite Ceinture",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8597838,
2.3341775
],
"osm_type":"relation",
"osm_id":1536589,
"attractiveness":8,
"must_do":false,
"n_tags":8,
"time_to_reach":0
},
"16":{
"name":"Bateau Daphné",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8520929,
2.3494633
48.849488,
2.3471975
],
"osm_type":"way",
"osm_id":618750321,
"attractiveness":6,
"osm_id":55366403,
"attractiveness":10,
"must_do":false,
"n_tags":6,
"n_tags":16,
"time_to_reach":0
},
"17":{
"name":"Église Saint-Leu - Saint-Gilles",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8628813,
2.3500683
],
"osm_type":"way",
"osm_id":53933240,
"attractiveness":14,
"must_do":false,
"n_tags":23,
"time_to_reach":0
},
"18":{
"23":{
"name":"Église Saint-Merri",
"type":{
"landmark_type":"sightseeing"
@ -303,87 +383,23 @@
"n_tags":26,
"time_to_reach":0
},
"19":{
"name":"Église Saint-Joseph des Carmes",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8485199,
2.3302805
],
"osm_type":"way",
"osm_id":63370983,
"attractiveness":7,
"must_do":false,
"n_tags":11,
"time_to_reach":0
},
"20":{
"name":"Église Orthodoxe Saint-Séraphin de Sarov",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8426176,
2.3045363
],
"osm_type":"way",
"osm_id":80237345,
"attractiveness":7,
"must_do":false,
"n_tags":11,
"time_to_reach":0
},
"21":{
"name":"Fontaine des quatre évêques",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.85087,
2.3332776
],
"osm_type":"way",
"osm_id":40068036,
"attractiveness":8,
"must_do":false,
"n_tags":8,
"time_to_reach":0
},
"22":{
"name":"La fontaine de la Vierge",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8525605,
2.3513841
],
"osm_type":"way",
"osm_id":948654101,
"attractiveness":6,
"must_do":false,
"n_tags":6,
"time_to_reach":0
},
"23":{
"name":"Square Jean Chérioux",
"type":{
"landmark_type":"nature"
},
"location":[
48.8401918,
2.3006179
],
"osm_type":"way",
"osm_id":14334838,
"attractiveness":9,
"must_do":false,
"n_tags":5,
"time_to_reach":0
},
"24":{
"name":"Église Saint-Germain des Prés",
"type":{
"landmark_type":"sightseeing"
},
"location":[
48.8539667,
2.334463
],
"osm_type":"way",
"osm_id":62287173,
"attractiveness":12,
"must_do":false,
"n_tags":21,
"time_to_reach":0
},
"25":{
"name":"Square de la Tour Saint-Jacques",
"type":{
"landmark_type":"nature"
@ -399,7 +415,7 @@
"n_tags":12,
"time_to_reach":0
},
"25":{
"26":{
"name":"Square Jean XXIII",
"type":{
"landmark_type":"nature"
@ -415,52 +431,36 @@
"n_tags":15,
"time_to_reach":0
},
"26":{
"name":"Jardinet place du lieutenant Henri-Karcher",
"type":{
"landmark_type":"nature"
},
"location":[
48.8632971,
2.3399434
],
"osm_type":"way",
"osm_id":53826866,
"attractiveness":8,
"must_do":false,
"n_tags":5,
"time_to_reach":0
},
"27":{
"name":"Square de l'Abbé Esquerré",
"name":"Square Félix Desruelles",
"type":{
"landmark_type":"nature"
},
"location":[
48.8503173,
2.3136601
48.8536974,
2.3345069
],
"osm_type":"way",
"osm_id":103344111,
"attractiveness":11,
"osm_id":62287123,
"attractiveness":12,
"must_do":false,
"n_tags":7,
"time_to_reach":0
},
"28":{
"name":"Jardin Nelson Mandela",
"name":"Jardin des Rosiers Joseph-Migneret",
"type":{
"landmark_type":"nature"
},
"location":[
48.8626235,
2.344487
48.8572946,
2.3602516
],
"osm_type":"way",
"osm_id":159103475,
"attractiveness":23,
"osm_id":365878540,
"attractiveness":14,
"must_do":false,
"n_tags":15,
"n_tags":8,
"time_to_reach":0
},
"29":{