updated refiner
This commit is contained in:
parent
8d068c80a7
commit
fdcaaf8c16
@ -1,8 +1,8 @@
|
|||||||
import math as m
|
import math as m
|
||||||
import json, os
|
import json, os
|
||||||
|
|
||||||
from typing import List, Tuple
|
from typing import List, Tuple, Optional
|
||||||
from OSMPythonTools.overpass import Overpass, overpassQueryBuilder, Nominatim
|
from OSMPythonTools.overpass import Overpass, overpassQueryBuilder
|
||||||
|
|
||||||
from structs.landmarks import Landmark, LandmarkType
|
from structs.landmarks import Landmark, LandmarkType
|
||||||
from structs.preferences import Preferences, Preference
|
from structs.preferences import Preferences, Preference
|
||||||
@ -38,7 +38,9 @@ def generate_landmarks(preferences: Preferences, coordinates: Tuple[float, float
|
|||||||
correct_score(L3, preferences.shopping)
|
correct_score(L3, preferences.shopping)
|
||||||
L += L3
|
L += L3
|
||||||
|
|
||||||
return remove_duplicates(L), take_most_important(L)
|
L = remove_duplicates(L)
|
||||||
|
|
||||||
|
return L, take_most_important(L)
|
||||||
|
|
||||||
|
|
||||||
"""def generate_landmarks(preferences: Preferences, city_country: str = None, coordinates: Tuple[float, float] = None) -> Tuple[List[Landmark], List[Landmark]] :
|
"""def generate_landmarks(preferences: Preferences, city_country: str = None, coordinates: Tuple[float, float] = None) -> Tuple[List[Landmark], List[Landmark]] :
|
||||||
@ -91,7 +93,7 @@ def get_list(path: str) -> List[str] :
|
|||||||
|
|
||||||
|
|
||||||
# Take the most important landmarks from the list
|
# Take the most important landmarks from the list
|
||||||
def take_most_important(L: List[Landmark]) -> List[Landmark] :
|
def take_most_important(L: List[Landmark], N = 0) -> List[Landmark] :
|
||||||
|
|
||||||
# Read the parameters from the file
|
# Read the parameters from the file
|
||||||
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/landmarks_manager.params', "r") as f :
|
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/landmarks_manager.params', "r") as f :
|
||||||
@ -125,7 +127,7 @@ def take_most_important(L: List[Landmark]) -> List[Landmark] :
|
|||||||
for i, elem in enumerate(L_copy) :
|
for i, elem in enumerate(L_copy) :
|
||||||
scores[i] = elem.attractiveness
|
scores[i] = elem.attractiveness
|
||||||
|
|
||||||
res = sorted(range(len(scores)), key = lambda sub: scores[sub])[-N_important:]
|
res = sorted(range(len(scores)), key = lambda sub: scores[sub])[-(N_important-N):]
|
||||||
|
|
||||||
for i, elem in enumerate(L_copy) :
|
for i, elem in enumerate(L_copy) :
|
||||||
if i in res :
|
if i in res :
|
||||||
@ -148,21 +150,15 @@ def remove_duplicates(L: List[Landmark]) -> List[Landmark] :
|
|||||||
|
|
||||||
L_clean = []
|
L_clean = []
|
||||||
names = []
|
names = []
|
||||||
coords = []
|
|
||||||
|
|
||||||
for landmark in L :
|
for landmark in L :
|
||||||
if landmark.name in names and landmark.location in coords:
|
if landmark.name in names:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
approx_coords = tuple((round(landmark.location[0], 4), round(landmark.location[0], 4)))
|
|
||||||
|
|
||||||
if approx_coords in coords :
|
|
||||||
continue
|
|
||||||
|
|
||||||
else :
|
else :
|
||||||
names.append(landmark.name)
|
names.append(landmark.name)
|
||||||
L_clean.append(landmark)
|
L_clean.append(landmark)
|
||||||
coords.append(approx_coords)
|
|
||||||
|
|
||||||
return L_clean
|
return L_clean
|
||||||
|
|
||||||
|
@ -4,12 +4,13 @@ import json, os
|
|||||||
from typing import List, Tuple
|
from typing import List, Tuple
|
||||||
from scipy.optimize import linprog
|
from scipy.optimize import linprog
|
||||||
from math import radians, sin, cos, acos
|
from math import radians, sin, cos, acos
|
||||||
|
from shapely import Polygon
|
||||||
|
|
||||||
from structs.landmarks import Landmark
|
from structs.landmarks import Landmark
|
||||||
|
|
||||||
|
|
||||||
# Function to print the result
|
# Function to print the result
|
||||||
def print_res(L: List[Landmark], L_tot) -> list:
|
def print_res(L: List[Landmark], L_tot):
|
||||||
|
|
||||||
if len(L) == L_tot:
|
if len(L) == L_tot:
|
||||||
print('\nAll landmarks can be visited within max_steps, the following order is suggested : ')
|
print('\nAll landmarks can be visited within max_steps, the following order is suggested : ')
|
||||||
@ -25,10 +26,10 @@ def print_res(L: List[Landmark], L_tot) -> list:
|
|||||||
print('- ' + elem.name)
|
print('- ' + elem.name)
|
||||||
|
|
||||||
print("\nMinutes walked : " + str(dist))
|
print("\nMinutes walked : " + str(dist))
|
||||||
print(f"Visited {len(L)} out of {L_tot} landmarks")
|
print(f"Visited {len(L)-2} out of {L_tot-2} landmarks")
|
||||||
|
|
||||||
|
|
||||||
# Prevent the use of a particular set of nodes
|
# Prevent the use of a particular solution
|
||||||
def prevent_config(resx, A_ub, b_ub) -> bool:
|
def prevent_config(resx, A_ub, b_ub) -> bool:
|
||||||
|
|
||||||
for i, elem in enumerate(resx):
|
for i, elem in enumerate(resx):
|
||||||
@ -56,7 +57,7 @@ def prevent_config(resx, A_ub, b_ub) -> bool:
|
|||||||
return A_ub, b_ub
|
return A_ub, b_ub
|
||||||
|
|
||||||
|
|
||||||
# Prevent the possibility of a given set of vertices
|
# Prevent the possibility of a given solution bit
|
||||||
def break_cricle(circle_vertices: list, L: int, A_ub: list, b_ub: list) -> bool:
|
def break_cricle(circle_vertices: list, L: int, A_ub: list, b_ub: list) -> bool:
|
||||||
|
|
||||||
if L-1 in circle_vertices :
|
if L-1 in circle_vertices :
|
||||||
@ -73,7 +74,7 @@ def break_cricle(circle_vertices: list, L: int, A_ub: list, b_ub: list) -> bool:
|
|||||||
return A_ub, b_ub
|
return A_ub, b_ub
|
||||||
|
|
||||||
|
|
||||||
# Checks if the path is connected, returns a circle if it finds one
|
# Checks if the path is connected, returns a circle if it finds one and the RESULT
|
||||||
def is_connected(resx) -> bool:
|
def is_connected(resx) -> bool:
|
||||||
|
|
||||||
# first round the results to have only 0-1 values
|
# first round the results to have only 0-1 values
|
||||||
@ -182,8 +183,8 @@ def init_ub_dist(landmarks: List[Landmark], max_steps: int):
|
|||||||
return c, A_ub, [max_steps]
|
return c, A_ub, [max_steps]
|
||||||
|
|
||||||
|
|
||||||
# Constraint to respect max number of travels
|
# Constraint to respect only one travel per landmark. Also caps the total number of visited landmarks
|
||||||
def respect_number(L, A_ub, b_ub):
|
def respect_number(L:int, A_ub, b_ub):
|
||||||
|
|
||||||
ones = [1]*L
|
ones = [1]*L
|
||||||
zeros = [0]*L
|
zeros = [0]*L
|
||||||
@ -192,6 +193,14 @@ def respect_number(L, A_ub, b_ub):
|
|||||||
A_ub = np.vstack((A_ub, h))
|
A_ub = np.vstack((A_ub, h))
|
||||||
b_ub.append(1)
|
b_ub.append(1)
|
||||||
|
|
||||||
|
# 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())
|
||||||
|
max_landmarks = parameters['max landmarks']
|
||||||
|
|
||||||
|
A_ub = np.vstack((A_ub, ones*L))
|
||||||
|
b_ub.append(max_landmarks+1)
|
||||||
|
|
||||||
return A_ub, b_ub
|
return A_ub, b_ub
|
||||||
|
|
||||||
|
|
||||||
@ -290,7 +299,7 @@ def respect_order(N: int, A_eq, b_eq):
|
|||||||
return A_eq, b_eq
|
return A_eq, b_eq
|
||||||
|
|
||||||
|
|
||||||
# Computes the path length given path matrix (dist_table) and a result
|
# Computes the time to reach from each landmark to the next
|
||||||
def add_time_to_reach(order: List[int], landmarks: List[Landmark])->List[Landmark] :
|
def add_time_to_reach(order: List[int], landmarks: List[Landmark])->List[Landmark] :
|
||||||
|
|
||||||
# Read the parameters from the file
|
# Read the parameters from the file
|
||||||
@ -315,6 +324,7 @@ def add_time_to_reach(order: List[int], landmarks: List[Landmark])->List[Landmar
|
|||||||
|
|
||||||
return L
|
return L
|
||||||
|
|
||||||
|
|
||||||
def add_time_to_reach_simple(ordered_visit: List[Landmark])-> List[Landmark] :
|
def add_time_to_reach_simple(ordered_visit: List[Landmark])-> List[Landmark] :
|
||||||
|
|
||||||
# Read the parameters from the file
|
# Read the parameters from the file
|
||||||
@ -326,14 +336,17 @@ def add_time_to_reach_simple(ordered_visit: List[Landmark])-> List[Landmark] :
|
|||||||
L = []
|
L = []
|
||||||
prev = ordered_visit[0]
|
prev = ordered_visit[0]
|
||||||
L.append(prev)
|
L.append(prev)
|
||||||
|
total_dist = 0
|
||||||
|
|
||||||
for elem in ordered_visit[1:] :
|
for elem in ordered_visit[1:] :
|
||||||
elem.time_to_reach = get_distance(elem.location, prev.location, detour_factor, speed)[1]
|
elem.time_to_reach = get_distance(elem.location, prev.location, detour_factor, speed)[1]
|
||||||
elem.must_do = True
|
elem.must_do = True
|
||||||
L.append(elem)
|
L.append(elem)
|
||||||
prev = elem
|
prev = elem
|
||||||
|
total_dist += get_distance(elem.location, prev.location, detour_factor, speed)[1]
|
||||||
|
|
||||||
return L
|
|
||||||
|
return L, total_dist
|
||||||
|
|
||||||
|
|
||||||
# Main optimization pipeline
|
# Main optimization pipeline
|
||||||
@ -366,22 +379,23 @@ def solve_optimization (landmarks :List[Landmark], max_steps: int, printing_deta
|
|||||||
else :
|
else :
|
||||||
order, circle = is_connected(res.x)
|
order, circle = is_connected(res.x)
|
||||||
i = 0
|
i = 0
|
||||||
timeout = 300
|
timeout = 80
|
||||||
while len(circle) != 0 and i < timeout:
|
while len(circle) != 0 and i < timeout:
|
||||||
A_ub, b_ub = prevent_config(res.x, A_ub, b_ub)
|
A_ub, b_ub = prevent_config(res.x, A_ub, b_ub)
|
||||||
A_ub, b_ub = break_cricle(order, len(landmarks), A_ub, b_ub)
|
A_ub, b_ub = break_cricle(order, len(landmarks), A_ub, b_ub)
|
||||||
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq = b_eq, bounds=x_bounds, method='highs', integrality=3)
|
res = linprog(c, A_ub=A_ub, b_ub=b_ub, A_eq=A_eq, b_eq = b_eq, bounds=x_bounds, method='highs', integrality=3)
|
||||||
order, circle = is_connected(res.x)
|
order, circle = is_connected(res.x)
|
||||||
if len(circle) == 0 :
|
if len(circle) == 0 :
|
||||||
# Add the times to reach and stop optimizing
|
|
||||||
L = add_time_to_reach(order, landmarks)
|
|
||||||
break
|
break
|
||||||
#print(i)
|
print(i)
|
||||||
i += 1
|
i += 1
|
||||||
|
|
||||||
if i == timeout :
|
if i == timeout :
|
||||||
raise TimeoutError(f"Optimization took too long. No solution found after {timeout} iterations.")
|
raise TimeoutError(f"Optimization took too long. No solution found after {timeout} iterations.")
|
||||||
|
|
||||||
|
# Add the times to reach and stop optimizing
|
||||||
|
L = add_time_to_reach(order, landmarks)
|
||||||
|
|
||||||
if printing_details is True :
|
if printing_details is True :
|
||||||
if i != 0 :
|
if i != 0 :
|
||||||
print(f"Neded to recompute paths {i} times because of unconnected loops...")
|
print(f"Neded to recompute paths {i} times because of unconnected loops...")
|
||||||
|
@ -4,5 +4,5 @@
|
|||||||
"church coeff" : 0.6,
|
"church coeff" : 0.6,
|
||||||
"park coeff" : 1.5,
|
"park coeff" : 1.5,
|
||||||
"tag coeff" : 100,
|
"tag coeff" : 100,
|
||||||
"N important" : 30
|
"N important" : 40
|
||||||
}
|
}
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
"detour factor" : 1.4,
|
"detour factor" : 1.4,
|
||||||
"average walking speed" : 4.8
|
"average walking speed" : 4.8,
|
||||||
|
"max landmarks" : 10
|
||||||
}
|
}
|
@ -1,10 +1,15 @@
|
|||||||
|
from collections import defaultdict
|
||||||
|
from heapq import heappop, heappush
|
||||||
|
from itertools import permutations
|
||||||
|
import os, json
|
||||||
|
|
||||||
from shapely import buffer, LineString, Point, Polygon, MultiPoint, convex_hull, concave_hull, LinearRing
|
from shapely import buffer, LineString, Point, Polygon, MultiPoint, convex_hull, concave_hull, LinearRing
|
||||||
from typing import List
|
from typing import List, Tuple
|
||||||
from math import pi
|
from math import pi
|
||||||
|
|
||||||
from structs.landmarks import Landmark
|
from structs.landmarks import Landmark
|
||||||
from landmarks_manager import take_most_important
|
from landmarks_manager import take_most_important
|
||||||
from optimizer import solve_optimization, add_time_to_reach_simple, print_res
|
from optimizer import solve_optimization, add_time_to_reach_simple, print_res, get_distance
|
||||||
|
|
||||||
|
|
||||||
def create_corridor(landmarks: List[Landmark], width: float) :
|
def create_corridor(landmarks: List[Landmark], width: float) :
|
||||||
@ -28,10 +33,135 @@ def create_linestring(landmarks: List[Landmark])->List[Point] :
|
|||||||
|
|
||||||
|
|
||||||
def is_in_area(area: Polygon, coordinates) -> bool :
|
def is_in_area(area: Polygon, coordinates) -> bool :
|
||||||
|
|
||||||
point = Point(coordinates)
|
point = Point(coordinates)
|
||||||
return point.within(area)
|
return point.within(area)
|
||||||
|
|
||||||
|
|
||||||
|
def is_close_to(location1: Tuple[float], location2: Tuple[float]):
|
||||||
|
"""Determine if two locations are close by rounding their coordinates to 3 decimals."""
|
||||||
|
absx = abs(location1[0] - location2[0])
|
||||||
|
absy = abs(location1[1] - location2[1])
|
||||||
|
|
||||||
|
return absx < 0.001 and absy < 0.001
|
||||||
|
#return (round(location1[0], 3), round(location1[1], 3)) == (round(location2[0], 3), round(location2[1], 3))
|
||||||
|
|
||||||
|
|
||||||
|
def rearrange(landmarks: List[Landmark]) -> List[Landmark]:
|
||||||
|
|
||||||
|
i = 1
|
||||||
|
while i < len(landmarks):
|
||||||
|
j = i+1
|
||||||
|
while j < len(landmarks):
|
||||||
|
if is_close_to(landmarks[i].location, landmarks[j].location) and landmarks[i].name not in ['start', 'finish'] and landmarks[j].name not in ['start', 'finish']:
|
||||||
|
# If they are not adjacent, move the j-th element to be adjacent to the i-th element
|
||||||
|
if j != i + 1:
|
||||||
|
landmarks.insert(i + 1, landmarks.pop(j))
|
||||||
|
break # Move to the next i-th element after rearrangement
|
||||||
|
j += 1
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return landmarks
|
||||||
|
|
||||||
|
"""
|
||||||
|
def find_shortest_path(landmarks: List[Landmark]) -> List[Landmark]:
|
||||||
|
|
||||||
|
# Read from data
|
||||||
|
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/optimizer.params', "r") as f :
|
||||||
|
parameters = json.loads(f.read())
|
||||||
|
detour = parameters['detour factor']
|
||||||
|
speed = parameters['average walking speed']
|
||||||
|
|
||||||
|
# Step 1: Build the graph
|
||||||
|
graph = defaultdict(list)
|
||||||
|
for i in range(len(landmarks)):
|
||||||
|
for j in range(len(landmarks)):
|
||||||
|
if i != j:
|
||||||
|
distance = get_distance(landmarks[i].location, landmarks[j].location, detour, speed)[1]
|
||||||
|
graph[i].append((distance, j))
|
||||||
|
|
||||||
|
# Step 2: Dijkstra's algorithm to find the shortest path from start to finish
|
||||||
|
start_idx = next(i for i, lm in enumerate(landmarks) if lm.name == 'start')
|
||||||
|
finish_idx = next(i for i, lm in enumerate(landmarks) if lm.name == 'finish')
|
||||||
|
|
||||||
|
distances = {i: float('inf') for i in range(len(landmarks))}
|
||||||
|
previous_nodes = {i: None for i in range(len(landmarks))}
|
||||||
|
distances[start_idx] = 0
|
||||||
|
priority_queue = [(0, start_idx)]
|
||||||
|
|
||||||
|
while priority_queue:
|
||||||
|
current_distance, current_index = heappop(priority_queue)
|
||||||
|
|
||||||
|
if current_distance > distances[current_index]:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for neighbor_distance, neighbor_index in graph[current_index]:
|
||||||
|
distance = current_distance + neighbor_distance
|
||||||
|
|
||||||
|
if distance < distances[neighbor_index]:
|
||||||
|
distances[neighbor_index] = distance
|
||||||
|
previous_nodes[neighbor_index] = current_index
|
||||||
|
heappush(priority_queue, (distance, neighbor_index))
|
||||||
|
|
||||||
|
# Step 3: Backtrack from finish to start to find the path
|
||||||
|
path = []
|
||||||
|
current_index = finish_idx
|
||||||
|
while current_index is not None:
|
||||||
|
path.append(landmarks[current_index])
|
||||||
|
current_index = previous_nodes[current_index]
|
||||||
|
path.reverse()
|
||||||
|
|
||||||
|
return path
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
def total_path_distance(path: List[Landmark], detour, speed) -> float:
|
||||||
|
total_distance = 0
|
||||||
|
for i in range(len(path) - 1):
|
||||||
|
total_distance += get_distance(path[i].location, path[i + 1].location, detour, speed)[1]
|
||||||
|
return total_distance
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def find_shortest_path_through_all_landmarks(landmarks: List[Landmark]) -> List[Landmark]:
|
||||||
|
|
||||||
|
# Read from data
|
||||||
|
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/optimizer.params', "r") as f :
|
||||||
|
parameters = json.loads(f.read())
|
||||||
|
detour = parameters['detour factor']
|
||||||
|
speed = parameters['average walking speed']
|
||||||
|
|
||||||
|
# Step 1: Find 'start' and 'finish' landmarks
|
||||||
|
start_idx = next(i for i, lm in enumerate(landmarks) if lm.name == 'start')
|
||||||
|
finish_idx = next(i for i, lm in enumerate(landmarks) if lm.name == 'finish')
|
||||||
|
|
||||||
|
start_landmark = landmarks[start_idx]
|
||||||
|
finish_landmark = landmarks[finish_idx]
|
||||||
|
|
||||||
|
|
||||||
|
# Step 2: Create a list of unvisited landmarks excluding 'start' and 'finish'
|
||||||
|
unvisited_landmarks = [lm for i, lm in enumerate(landmarks) if i not in [start_idx, finish_idx]]
|
||||||
|
|
||||||
|
# Step 3: Initialize the path with the 'start' landmark
|
||||||
|
path = [start_landmark]
|
||||||
|
coordinates = [landmarks[start_idx].location]
|
||||||
|
|
||||||
|
current_landmark = start_landmark
|
||||||
|
|
||||||
|
# Step 4: Use nearest neighbor heuristic to visit all landmarks
|
||||||
|
while unvisited_landmarks:
|
||||||
|
nearest_landmark = min(unvisited_landmarks, key=lambda lm: get_distance(current_landmark.location, lm.location, detour, speed)[1])
|
||||||
|
path.append(nearest_landmark)
|
||||||
|
coordinates.append(nearest_landmark.location)
|
||||||
|
current_landmark = nearest_landmark
|
||||||
|
unvisited_landmarks.remove(nearest_landmark)
|
||||||
|
|
||||||
|
# Step 5: Finally add the 'finish' landmark to the path
|
||||||
|
path.append(finish_landmark)
|
||||||
|
coordinates.append(landmarks[finish_idx].location)
|
||||||
|
|
||||||
|
path_poly = Polygon(coordinates)
|
||||||
|
|
||||||
|
return path, path_poly
|
||||||
|
|
||||||
def get_minor_landmarks(all_landmarks: List[Landmark], visited_landmarks: List[Landmark], width: float) -> List[Landmark] :
|
def get_minor_landmarks(all_landmarks: List[Landmark], visited_landmarks: List[Landmark], width: float) -> List[Landmark] :
|
||||||
|
|
||||||
second_order_landmarks = []
|
second_order_landmarks = []
|
||||||
@ -45,7 +175,7 @@ def get_minor_landmarks(all_landmarks: List[Landmark], visited_landmarks: List[L
|
|||||||
if is_in_area(area, landmark.location) and landmark.name not in visited_names:
|
if is_in_area(area, landmark.location) and landmark.name not in visited_names:
|
||||||
second_order_landmarks.append(landmark)
|
second_order_landmarks.append(landmark)
|
||||||
|
|
||||||
return take_most_important(second_order_landmarks)
|
return take_most_important(second_order_landmarks, len(visited_landmarks))
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -58,55 +188,106 @@ def get_minor_landmarks(all_landmarks: List[Landmark], visited_landmarks: List[L
|
|||||||
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
|
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
|
||||||
full_set.append(base_tour[-1]) # add finish back
|
full_set.append(base_tour[-1]) # add finish back
|
||||||
|
|
||||||
new_route = solve_optimization(full_set, max_time, print_infos)
|
new_tour = solve_optimization(full_set, max_time, print_infos)
|
||||||
|
|
||||||
return new_route"""
|
return new_tour"""
|
||||||
|
|
||||||
|
|
||||||
def refine_optimization(landmarks: List[Landmark], base_tour: List[Landmark], max_time: int, print_infos: bool) -> List[Landmark] :
|
def refine_optimization(landmarks: List[Landmark], base_tour: List[Landmark], max_time: int, print_infos: bool) -> List[Landmark] :
|
||||||
|
|
||||||
|
# Read from the file
|
||||||
|
with open (os.path.dirname(os.path.abspath(__file__)) + '/parameters/optimizer.params', "r") as f :
|
||||||
|
parameters = json.loads(f.read())
|
||||||
|
max_landmarks = parameters['max landmarks']
|
||||||
|
|
||||||
|
if len(base_tour)-2 >= max_landmarks :
|
||||||
|
return base_tour
|
||||||
|
|
||||||
|
|
||||||
minor_landmarks = get_minor_landmarks(landmarks, base_tour, 200)
|
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")
|
if print_infos : print("Using " + str(len(minor_landmarks)) + " minor landmarks around the predicted path")
|
||||||
|
|
||||||
# full set of visitable landmarks
|
# full set of visitable landmarks
|
||||||
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
|
full_set = base_tour[:-1] + minor_landmarks # create full set of possible landmarks (without finish)
|
||||||
full_set.append(base_tour[-1]) # add finish back
|
full_set.append(base_tour[-1]) # add finish back
|
||||||
|
|
||||||
# get a new route
|
# get a new tour
|
||||||
new_route = solve_optimization(full_set, max_time, False)
|
new_tour = solve_optimization(full_set, max_time, False)
|
||||||
|
new_tour, new_dist = add_time_to_reach_simple(new_tour)
|
||||||
|
|
||||||
coords = [] # Coordinates of the new route
|
"""#if base_tour[0].location == base_tour[-1].location :
|
||||||
coords_dict = {} # maps the location of an element to the element itself. Used to access the elements back once we get the geometry
|
if False :
|
||||||
|
coords = [] # Coordinates of the new tour
|
||||||
|
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
|
# Iterate through the new tour without finish
|
||||||
for elem in new_route[:-1] :
|
for elem in new_tour[:-1] :
|
||||||
coords.append(Point(elem.location))
|
coords.append(Point(elem.location))
|
||||||
coords_dict[elem.location] = elem # if start = goal, only finish remains
|
coords_dict[elem.location] = elem # if start = goal, only finish remains
|
||||||
|
|
||||||
# Create a concave polygon using the coordinates
|
# 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
|
better_tour_poly = concave_hull(MultiPoint(coords)) # Create concave hull with "core" of tour leaving out start and finish
|
||||||
xs, ys = better_route_poly.exterior.xy
|
xs, ys = better_tour_poly.exterior.xy
|
||||||
|
|
||||||
better_route = [] # List of ordered visit
|
# reverse the xs and ys
|
||||||
name_index = {} # Maps the name of a landmark to its index in the concave polygon
|
xs.reverse()
|
||||||
|
ys.reverse()
|
||||||
|
|
||||||
# Loop through the polygon and generate the better (ordered) route
|
better_tour = [] # List of ordered visit
|
||||||
for i,x in enumerate(xs[:-1]) :
|
name_index = {} # Maps the name of a landmark to its index in the concave polygon
|
||||||
better_route.append(coords_dict[tuple((x,ys[i]))])
|
|
||||||
name_index[coords_dict[tuple((x,ys[i]))].name] = i
|
# Loop through the polygon and generate the better (ordered) tour
|
||||||
|
for i,x in enumerate(xs[:-1]) :
|
||||||
|
better_tour.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
|
# Scroll the list to have start in front again
|
||||||
start_index = name_index['start']
|
start_index = name_index['start']
|
||||||
better_route = better_route[start_index:] + better_route[:start_index]
|
better_tour = better_tour[start_index:] + better_tour[:start_index]
|
||||||
|
|
||||||
# Append the finish back and correct the time to reach
|
# Append the finish back and correct the time to reach
|
||||||
better_route.append(new_route[-1])
|
better_tour.append(new_tour[-1])
|
||||||
better_route = add_time_to_reach_simple(better_route)
|
|
||||||
|
# Rearrange only if polygon
|
||||||
|
better_tour = rearrange(better_tour)
|
||||||
|
|
||||||
|
# Add the time to reach
|
||||||
|
better_tour = add_time_to_reach_simple(better_tour)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
if not better_poly.is_simple :
|
||||||
|
|
||||||
|
coords_dict = {}
|
||||||
|
better_tour2 = []
|
||||||
|
for elem in better_tour :
|
||||||
|
coords_dict[elem.location] = elem
|
||||||
|
|
||||||
|
better_poly2 = better_poly.buffer(0)
|
||||||
|
new_coords = better_poly2.exterior.coords[:]
|
||||||
|
start_coords = base_tour[0].location
|
||||||
|
start_index = new_coords.
|
||||||
|
|
||||||
|
#for point in new_coords :
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
better_tour, better_poly = find_shortest_path_through_all_landmarks(new_tour)
|
||||||
|
better_tour, better_dist = add_time_to_reach_simple(better_tour)
|
||||||
|
|
||||||
|
if new_dist < better_dist :
|
||||||
|
final_tour = new_tour
|
||||||
|
else :
|
||||||
|
final_tour = better_tour
|
||||||
|
|
||||||
if print_infos :
|
if print_infos :
|
||||||
|
print("\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n")
|
||||||
print("\nRefined tour (result of second stage optimization): ")
|
print("\nRefined tour (result of second stage optimization): ")
|
||||||
print_res(better_route, len(better_route))
|
print_res(final_tour, len(full_set))
|
||||||
|
|
||||||
return better_route
|
|
||||||
|
|
||||||
|
return final_tour
|
||||||
|
@ -84,6 +84,10 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
|||||||
# Create start and finish
|
# 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)
|
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)
|
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)
|
||||||
|
#finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.8777055, 2.3640967), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||||
|
#start = Landmark(name='start', type=LandmarkType(landmark_type='start'), location=(48.847132, 2.312359), 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.843185, 2.344533), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||||
|
#finish = Landmark(name='finish', type=LandmarkType(landmark_type='finish'), location=(48.847132, 2.312359), osm_type='finish', osm_id=0, attractiveness=0, must_do=True, n_tags = 0)
|
||||||
|
|
||||||
# Generate the landmarks from the start location
|
# Generate the landmarks from the start location
|
||||||
landmarks, landmarks_short = generate_landmarks(preferences=preferences, coordinates=start.location)
|
landmarks, landmarks_short = generate_landmarks(preferences=preferences, coordinates=start.location)
|
||||||
@ -94,7 +98,7 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
|||||||
landmarks_short.append(finish)
|
landmarks_short.append(finish)
|
||||||
|
|
||||||
# TODO use these parameters in another way
|
# TODO use these parameters in another way
|
||||||
max_walking_time = 4 # hours
|
max_walking_time = 2 # hours
|
||||||
detour = 30 # minutes
|
detour = 30 # minutes
|
||||||
|
|
||||||
# First stage optimization
|
# First stage optimization
|
||||||
@ -107,5 +111,6 @@ def test4(coordinates: tuple[float, float]) -> List[Landmark]:
|
|||||||
|
|
||||||
|
|
||||||
#test4(tuple((48.8344400, 2.3220540))) # Café Chez César
|
#test4(tuple((48.8344400, 2.3220540))) # Café Chez César
|
||||||
test4(tuple((48.8375946, 2.2949904))) # Point random
|
#test4(tuple((48.8375946, 2.2949904))) # Point random
|
||||||
|
test4(tuple((47.377859, 8.540585))) # Zurich HB
|
||||||
#test3('Vienna, Austria')
|
#test3('Vienna, Austria')
|
Loading…
x
Reference in New Issue
Block a user