anyway/backend/src/refiner.py
2024-06-26 11:01:23 +02:00

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