Merge pull request 'fixed cluster names' (#57) from backend/fix/missing-cluster-names into main
Reviewed-on: #57
This commit is contained in:
commit
84e5902436
File diff suppressed because one or more lines are too long
@ -130,11 +130,12 @@ def new_trip(preferences: Preferences,
|
|||||||
logger.debug(f'First stage optimization\t: {round(t_first_stage,3)} seconds')
|
logger.debug(f'First stage optimization\t: {round(t_first_stage,3)} seconds')
|
||||||
logger.debug(f'Second stage optimization\t: {round(t_second_stage,3)} seconds')
|
logger.debug(f'Second stage optimization\t: {round(t_second_stage,3)} seconds')
|
||||||
logger.info(f'Total computation time\t: {round(t_first_stage + t_second_stage,3)} seconds')
|
logger.info(f'Total computation time\t: {round(t_first_stage + t_second_stage,3)} seconds')
|
||||||
|
|
||||||
linked_tour = LinkedLandmarks(refined_tour)
|
linked_tour = LinkedLandmarks(refined_tour)
|
||||||
|
|
||||||
# upon creation of the trip, persistence of both the trip and its landmarks is ensured.
|
# upon creation of the trip, persistence of both the trip and its landmarks is ensured.
|
||||||
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
|
trip = Trip.from_linked_landmarks(linked_tour, cache_client)
|
||||||
logger.info(f'Generated a trip of {trip.total_time} minutes with {len(refined_tour)} landmarks in {round(t_generate_landmarks + t_first_stage + t_second_stage,3)} seconds.')
|
logger.info(f'Generated a trip of {trip.total_time} minutes with {len(refined_tour)} landmarks in {round(t_generate_landmarks + t_first_stage + t_second_stage,3)} seconds.')
|
||||||
|
logger.debug('Detailed trip :\n\t' + '\n\t'.join(f'{landmark}' for landmark in refined_tour))
|
||||||
|
|
||||||
background_tasks.add_task(fill_cache)
|
background_tasks.add_task(fill_cache)
|
||||||
|
|
||||||
|
@ -594,7 +594,7 @@ class Optimizer:
|
|||||||
status = pl.LpStatus[prob.status]
|
status = pl.LpStatus[prob.status]
|
||||||
solution = [pl.value(var) for var in x] # The values of the decision variables (will be 0 or 1)
|
solution = [pl.value(var) for var in x] # The values of the decision variables (will be 0 or 1)
|
||||||
|
|
||||||
self.logger.debug("First results are out. Looking out for circles and correcting.")
|
self.logger.debug("First results are out. Looking out for circles and correcting...")
|
||||||
|
|
||||||
# Raise error if no solution is found. FIXME: for now this throws the internal server error
|
# Raise error if no solution is found. FIXME: for now this throws the internal server error
|
||||||
if status != 'Optimal' :
|
if status != 'Optimal' :
|
||||||
|
@ -52,7 +52,7 @@ class Overpass :
|
|||||||
# Retrieve cached data and identify missing cache entries
|
# Retrieve cached data and identify missing cache entries
|
||||||
cached_responses, non_cached_cells = self._retrieve_cached_data(overlapping_cells, osm_types, selector, conditions, out)
|
cached_responses, non_cached_cells = self._retrieve_cached_data(overlapping_cells, osm_types, selector, conditions, out)
|
||||||
|
|
||||||
self.logger.info(f'Cache hit for {len(overlapping_cells)-len(non_cached_cells)}/{len(overlapping_cells)} quadrants.')
|
self.logger.debug(f'Cache hit for {len(overlapping_cells)-len(non_cached_cells)}/{len(overlapping_cells)} quadrants.')
|
||||||
|
|
||||||
# If there is no missing data, return the cached responses after filtering.
|
# If there is no missing data, return the cached responses after filtering.
|
||||||
if not non_cached_cells :
|
if not non_cached_cells :
|
||||||
@ -61,6 +61,7 @@ class Overpass :
|
|||||||
# If there is no cached data, fetch all from Overpass.
|
# If there is no cached data, fetch all from Overpass.
|
||||||
elif not cached_responses :
|
elif not cached_responses :
|
||||||
query_str = Overpass.build_query(bbox, osm_types, selector, conditions, out)
|
query_str = Overpass.build_query(bbox, osm_types, selector, conditions, out)
|
||||||
|
self.logger.debug(f'Query string: {query_str}')
|
||||||
return self.fetch_data_from_api(query_str)
|
return self.fetch_data_from_api(query_str)
|
||||||
|
|
||||||
# Hybrid cache: some data from Overpass, some data from cache.
|
# Hybrid cache: some data from Overpass, some data from cache.
|
||||||
@ -68,6 +69,7 @@ class Overpass :
|
|||||||
# Resize the bbox for smaller search area and build new query string.
|
# Resize the bbox for smaller search area and build new query string.
|
||||||
non_cached_bbox = Overpass._get_non_cached_bbox(non_cached_cells, bbox)
|
non_cached_bbox = Overpass._get_non_cached_bbox(non_cached_cells, bbox)
|
||||||
query_str = Overpass.build_query(non_cached_bbox, osm_types, selector, conditions, out)
|
query_str = Overpass.build_query(non_cached_bbox, osm_types, selector, conditions, out)
|
||||||
|
self.logger.debug(f'Query string: {query_str}')
|
||||||
non_cached_responses = self.fetch_data_from_api(query_str)
|
non_cached_responses = self.fetch_data_from_api(query_str)
|
||||||
return Overpass._filter_landmarks(cached_responses, bbox) + non_cached_responses
|
return Overpass._filter_landmarks(cached_responses, bbox) + non_cached_responses
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
max_bbox_side: 4000 #m
|
max_bbox_side: 4000 #m
|
||||||
radius_close_to: 50
|
radius_close_to: 50
|
||||||
church_coeff: 0.55
|
church_coeff: 0.75
|
||||||
nature_coeff: 1.4
|
nature_coeff: 1.6
|
||||||
overall_coeff: 10
|
overall_coeff: 10
|
||||||
tag_exponent: 1.15
|
tag_exponent: 1.15
|
||||||
image_bonus: 1.1
|
image_bonus: 1.1
|
||||||
viewpoint_bonus: 5
|
viewpoint_bonus: 10
|
||||||
wikipedia_bonus: 1.25
|
wikipedia_bonus: 1.25
|
||||||
name_bonus: 3
|
|
||||||
N_important: 60
|
N_important: 60
|
||||||
pay_bonus: -1
|
pay_bonus: -1
|
||||||
|
@ -5,5 +5,5 @@ max_landmarks: 10
|
|||||||
max_landmarks_refiner: 20
|
max_landmarks_refiner: 20
|
||||||
overshoot: 0.0016
|
overshoot: 0.0016
|
||||||
time_limit: 1
|
time_limit: 1
|
||||||
gap_rel: 0.05
|
gap_rel: 0.025
|
||||||
max_iter: 40
|
max_iter: 40
|
@ -31,9 +31,9 @@ def test_turckheim(client, request): # pylint: disable=redefined-outer-name
|
|||||||
"shopping": {"type": "shopping", "score": 0},
|
"shopping": {"type": "shopping", "score": 0},
|
||||||
"max_time_minute": duration_minutes,
|
"max_time_minute": duration_minutes,
|
||||||
"detour_tolerance_minute": 0},
|
"detour_tolerance_minute": 0},
|
||||||
# "start": [48.084588, 7.280405]
|
"start": [48.084588, 7.280405]
|
||||||
# "start": [45.74445023349939, 4.8222687890538865]
|
# "start": [45.74445023349939, 4.8222687890538865]
|
||||||
"start": [45.75156398104873, 4.827154464827647]
|
# "start": [45.75156398104873, 4.827154464827647]
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
result = response.json()
|
result = response.json()
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
"""Find clusters of interest to add more general areas of visit to the tour."""
|
"""Find clusters of interest to add more general areas of visit to the tour."""
|
||||||
import logging
|
import logging
|
||||||
from typing import Literal
|
from typing import Literal, Tuple
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from sklearn.cluster import DBSCAN
|
from sklearn.cluster import DBSCAN
|
||||||
@ -33,7 +33,7 @@ class Cluster(BaseModel):
|
|||||||
"""
|
"""
|
||||||
type: Literal['street', 'area']
|
type: Literal['street', 'area']
|
||||||
importance: int
|
importance: int
|
||||||
centroid: tuple
|
centroid: Tuple[float, float]
|
||||||
# start: Optional[list] = None # for later use if we want to have streets as well
|
# start: Optional[list] = None # for later use if we want to have streets as well
|
||||||
# end: Optional[list] = None
|
# end: Optional[list] = None
|
||||||
|
|
||||||
@ -178,11 +178,12 @@ class ClusterManager:
|
|||||||
|
|
||||||
# Calculate the centroid as the mean of the points
|
# Calculate the centroid as the mean of the points
|
||||||
centroid = np.mean(current_cluster, axis=0)
|
centroid = np.mean(current_cluster, axis=0)
|
||||||
|
centroid = tuple((round(centroid[0], 7), round(centroid[1], 7)))
|
||||||
|
|
||||||
if self.cluster_type == 'shopping' :
|
if self.cluster_type == 'shopping' :
|
||||||
score = len(current_cluster)*2
|
score = len(current_cluster)*3
|
||||||
else :
|
else :
|
||||||
score = len(current_cluster)*8
|
score = len(current_cluster)*15
|
||||||
locations.append(Cluster(
|
locations.append(Cluster(
|
||||||
type='area',
|
type='area',
|
||||||
centroid=centroid,
|
centroid=centroid,
|
||||||
@ -215,7 +216,7 @@ class ClusterManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
# Define the bounding box for a given radius around the coordinates
|
# Define the bounding box for a given radius around the coordinates
|
||||||
bbox = create_bbox(cluster.centroid, 1000)
|
bbox = create_bbox(cluster.centroid, 300)
|
||||||
|
|
||||||
# Query neighborhoods and shopping malls
|
# Query neighborhoods and shopping malls
|
||||||
selectors = ['"place"~"^(suburb|neighborhood|neighbourhood|quarter|city_block)$"']
|
selectors = ['"place"~"^(suburb|neighborhood|neighbourhood|quarter|city_block)$"']
|
||||||
@ -223,10 +224,10 @@ class ClusterManager:
|
|||||||
if self.cluster_type == 'shopping' :
|
if self.cluster_type == 'shopping' :
|
||||||
selectors.append('"shop"="mall"')
|
selectors.append('"shop"="mall"')
|
||||||
new_name = 'Shopping Area'
|
new_name = 'Shopping Area'
|
||||||
t = 40
|
t = 30
|
||||||
else :
|
else :
|
||||||
new_name = 'Neighborhood'
|
new_name = 'Neighborhood'
|
||||||
t = 15
|
t = 20
|
||||||
|
|
||||||
min_dist = float('inf')
|
min_dist = float('inf')
|
||||||
osm_id = 0
|
osm_id = 0
|
||||||
@ -238,7 +239,7 @@ class ClusterManager:
|
|||||||
result = self.overpass.send_query(bbox = bbox,
|
result = self.overpass.send_query(bbox = bbox,
|
||||||
osm_types = osm_types,
|
osm_types = osm_types,
|
||||||
selector = sel,
|
selector = sel,
|
||||||
out = 'ids center'
|
out = 'ids center tags'
|
||||||
)
|
)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
self.logger.error(f"Error fetching clusters: {e}")
|
self.logger.error(f"Error fetching clusters: {e}")
|
||||||
@ -259,9 +260,9 @@ class ClusterManager:
|
|||||||
d = get_distance(cluster.centroid, coords)
|
d = get_distance(cluster.centroid, coords)
|
||||||
if d < min_dist :
|
if d < min_dist :
|
||||||
min_dist = d
|
min_dist = d
|
||||||
new_name = name
|
new_name = name # add name
|
||||||
osm_type = osm_type # Add type: 'way' or 'relation'
|
osm_type = osm_type # add type: 'way' or 'relation'
|
||||||
osm_id = id # Add OSM id
|
osm_id = id # add OSM id
|
||||||
|
|
||||||
return Landmark(
|
return Landmark(
|
||||||
name=new_name,
|
name=new_name,
|
||||||
|
@ -39,7 +39,6 @@ class LandmarkManager:
|
|||||||
self.overall_coeff = parameters['overall_coeff']
|
self.overall_coeff = parameters['overall_coeff']
|
||||||
self.tag_exponent = parameters['tag_exponent']
|
self.tag_exponent = parameters['tag_exponent']
|
||||||
self.image_bonus = parameters['image_bonus']
|
self.image_bonus = parameters['image_bonus']
|
||||||
self.name_bonus = parameters['name_bonus']
|
|
||||||
self.wikipedia_bonus = parameters['wikipedia_bonus']
|
self.wikipedia_bonus = parameters['wikipedia_bonus']
|
||||||
self.viewpoint_bonus = parameters['viewpoint_bonus']
|
self.viewpoint_bonus = parameters['viewpoint_bonus']
|
||||||
self.pay_bonus = parameters['pay_bonus']
|
self.pay_bonus = parameters['pay_bonus']
|
||||||
@ -147,6 +146,8 @@ class LandmarkManager:
|
|||||||
score *= self.wikipedia_bonus
|
score *= self.wikipedia_bonus
|
||||||
if landmark.is_place_of_worship :
|
if landmark.is_place_of_worship :
|
||||||
score *= self.church_coeff
|
score *= self.church_coeff
|
||||||
|
if landmark.is_viewpoint :
|
||||||
|
score *= self.viewpoint_bonus
|
||||||
if landmarktype == 'nature' :
|
if landmarktype == 'nature' :
|
||||||
score *= self.nature_coeff
|
score *= self.nature_coeff
|
||||||
|
|
||||||
@ -201,7 +202,7 @@ class LandmarkManager:
|
|||||||
|
|
||||||
return_list += self._to_landmarks(result, landmarktype, preference_level)
|
return_list += self._to_landmarks(result, landmarktype, preference_level)
|
||||||
|
|
||||||
self.logger.debug(f"Fetched {len(return_list)} landmarks of type {landmarktype} in {bbox}")
|
# self.logger.debug(f"Fetched {len(return_list)} landmarks of type {landmarktype} in {bbox}")
|
||||||
|
|
||||||
return return_list
|
return return_list
|
||||||
|
|
||||||
@ -267,7 +268,7 @@ class LandmarkManager:
|
|||||||
landmark.image_url = value
|
landmark.image_url = value
|
||||||
if key == 'website' :
|
if key == 'website' :
|
||||||
landmark.website_url = value
|
landmark.website_url = value
|
||||||
if key == 'place_of_worship' :
|
if value == 'place_of_worship' :
|
||||||
landmark.is_place_of_worship = True
|
landmark.is_place_of_worship = True
|
||||||
if key == 'wikipedia' :
|
if key == 'wikipedia' :
|
||||||
landmark.wiki_url = value
|
landmark.wiki_url = value
|
||||||
|
Loading…
x
Reference in New Issue
Block a user