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