113 lines
3.9 KiB
Python
113 lines
3.9 KiB
Python
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) :
|
|
|
|
corrected_width = (180*width)/(6371000*pi)
|
|
|
|
path = create_linestring(landmarks)
|
|
obj = buffer(path, corrected_width, join_style="mitre", cap_style="square", mitre_limit=2)
|
|
|
|
return obj
|
|
|
|
|
|
def create_linestring(landmarks: List[Landmark])->List[Point] :
|
|
|
|
points = []
|
|
|
|
for landmark in landmarks :
|
|
points.append(Point(landmark.location))
|
|
|
|
return LineString(points)
|
|
|
|
|
|
def is_in_area(area: Polygon, coordinates) -> bool :
|
|
|
|
point = Point(coordinates)
|
|
return point.within(area)
|
|
|
|
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.name not in visited_names:
|
|
second_order_landmarks.append(landmark)
|
|
|
|
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
|