route_planner_base.cpp
Go to the documentation of this file.
1 //=============================================================================
2 // Copyright (C) 2021-2024 Wageningen University - All Rights Reserved
3 // Author: Gonzalo Mier
4 // BSD-3 License
5 //=============================================================================
6 
7 #include <ortools/constraint_solver/routing.h>
8 #include <ortools/constraint_solver/routing_enums.pb.h>
9 #include <ortools/constraint_solver/routing_index_manager.h>
10 #include <ortools/constraint_solver/routing_parameters.h>
11 #include <math.h>
12 #include <utility>
13 #include <vector>
14 #include <limits>
16 
17 namespace f2c::rp {
18 
19 namespace ortools = operations_research;
20 
22  const F2CCells& cells, const F2CSwathsByCells& swaths,
23  bool show_log, double d_tol, bool redirect_swaths,
24  long int time_limit_seconds, bool search_for_optimum) {
25  F2CGraph2D shortest_graph = createShortestGraph(cells, swaths, d_tol);
26 
27  F2CGraph2D cov_graph = createCoverageGraph(
28  cells, swaths, shortest_graph, d_tol, redirect_swaths);
29 
30  std::vector<long long int> v_route = computeBestRoute(
31  cov_graph, show_log, time_limit_seconds, search_for_optimum);
33  v_route, swaths, cov_graph, shortest_graph);
34 }
35 
37  this->r_start_end = p;
38 }
39 
41  const F2CCells& cells, const F2CSwathsByCells& swaths_by_cells,
42  double d_tol) const {
43  F2CGraph2D g;
44  // Add points from swaths that touches border
45  for (auto&& swaths : swaths_by_cells) {
46  for (auto&& s : swaths) {
47  g.addEdge(s.startPoint(), cells.closestPointOnBorderTo(s.startPoint()));
48  g.addEdge(s.endPoint(), cells.closestPointOnBorderTo(s.endPoint()));
49  }
50  }
51 
52  // Add points in the border
53  for (auto&& cell : cells) {
54  for (auto&& ring : cell) {
55  for (size_t i = 0; i < ring.size()-1; ++i) {
56  g.addEdge(ring.getGeometry(i), ring.getGeometry(i+1));
57  }
58  }
59  }
60 
61  // Add start and end point if they exists
62  if (this->r_start_end) {
63  g.addEdge(*r_start_end, cells.closestPointOnBorderTo(*r_start_end));
64  }
65 
66  std::vector<F2CPoint> nodes = g.getNodes();
67 
68  // Connect nodes that are near other edges.
69  for (int i = 0; i < 2; ++i) {
70  auto edges = g.getEdges();
71  for (auto&& edge : edges) {
72  size_t from = edge.first;
73  for (auto&& e : edge.second) {
74  size_t to = e.first;
75 
76  F2CLineString border {g.indexToNode(from), g.indexToNode(to)};
77  for (auto&& n : nodes) {
78  if (n != border[0] && n != border[1] && n.distance(border) < d_tol) {
79  g.addEdge(border[0], n);
80  g.addEdge(n, border[1]);
81  g.removeEdge(border[0], border[1]);
82  }
83  }
84  }
85  }
86  }
87  return g;
88 }
89 
90 
92  const F2CCells& cells, const F2CSwathsByCells& swaths_by_cells,
93  F2CGraph2D& shortest_graph,
94  double d_tol, bool redirect_swaths) const {
95  F2CGraph2D g;
96  for (auto&& swaths : swaths_by_cells) {
97  for (auto&& s : swaths) {
98  F2CPoint mid_p {(s.startPoint() + s.endPoint()) * 0.5};
99  if (redirect_swaths) {
100  g.addEdge(s.startPoint(), mid_p, 0);
101  g.addEdge(s.endPoint(), mid_p, 0);
102  } else {
103  g.addDirectedEdge(s.startPoint(), mid_p, 0);
104  g.addDirectedEdge(mid_p, s.endPoint(), 0);
105  }
106  }
107  }
108 
109  for (const auto& swaths1 : swaths_by_cells) {
110  for (const auto& s1 : swaths1) {
111  auto s1_s = s1.startPoint();
112  auto s1_e = s1.endPoint();
113  for (const auto& swaths2 : swaths_by_cells) {
114  for (const auto& s2 : swaths2) {
115  auto s2_s = s2.startPoint();
116  auto s2_e = s2.endPoint();
117  if (redirect_swaths) {
118  g.addEdge(s1_s, s2_s, shortest_graph);
119  g.addEdge(s1_e, s2_e, shortest_graph);
120  g.addEdge(s1_s, s2_e, shortest_graph);
121  g.addEdge(s1_e, s2_s, shortest_graph);
122  } else {
123  g.addDirectedEdge(s1_e, s2_s, shortest_graph);
124  }
125  }
126  }
127  }
128  }
129 
130  F2CPoint deposit(-1e8, -1e8); // Arbitrary point
131  if (this->r_start_end) {
132  deposit = *this->r_start_end;
133  }
134 
135  for (auto&& swaths : swaths_by_cells) {
136  for (auto&& s : swaths) {
137  if (this->r_start_end) {
138  g.addEdge(s.startPoint(), deposit, shortest_graph);
139  g.addEdge(s.endPoint(), deposit, shortest_graph);
140  } else {
141  g.addEdge(s.startPoint(), deposit, 0);
142  g.addEdge(s.endPoint(), deposit, 0);
143  }
144  }
145  }
146  return g;
147 }
148 
149 std::vector<long long int> RoutePlannerBase::computeBestRoute(
150  const F2CGraph2D& cov_graph, bool show_log, long int time_limit_seconds,
151  bool use_guided_local_search) const {
152  int depot_id = static_cast<int>(cov_graph.numNodes()-1);
153  const ortools::RoutingIndexManager::NodeIndex depot{depot_id};
154  ortools::RoutingIndexManager manager(cov_graph.numNodes(), 1, depot);
155  ortools::RoutingModel routing(manager);
156 
157  const int transit_callback_index = routing.RegisterTransitCallback(
158  [&cov_graph, &manager] (long long int from, long long int to) -> long long int {
159  auto from_node = manager.IndexToNode(from).value();
160  auto to_node = manager.IndexToNode(to).value();
161  return cov_graph.getCostFromEdge(from_node, to_node);
162  });
163  routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index);
164  ortools::RoutingSearchParameters searchParameters =
165  ortools::DefaultRoutingSearchParameters();
166  searchParameters.set_use_full_propagation(false);
167  searchParameters.set_first_solution_strategy(
168  ortools::FirstSolutionStrategy::AUTOMATIC);
169  if (use_guided_local_search) {
170  searchParameters.set_local_search_metaheuristic(
171  ortools::LocalSearchMetaheuristic::GUIDED_LOCAL_SEARCH);
172  } else {
173  searchParameters.set_local_search_metaheuristic(
174  ortools::LocalSearchMetaheuristic::AUTOMATIC);
175  }
176  searchParameters.mutable_time_limit()->set_seconds(time_limit_seconds);
177  searchParameters.set_log_search(show_log);
178  const ortools::Assignment* solution =
179  routing.SolveWithParameters(searchParameters);
180 
181  long long int index = routing.Start(0);
182  std::vector<long long int> v_id;
183 
184  index = solution->Value(routing.NextVar(index));
185 
186  while (!routing.IsEnd(index)) {
187  v_id.emplace_back(manager.IndexToNode(index).value());
188  index = solution->Value(routing.NextVar(index));
189  }
190  return v_id;
191 }
192 
194  const std::vector<long long int>& route_ids,
195  const F2CSwathsByCells& swaths_by_cells,
196  const F2CGraph2D& coverage_graph,
197  F2CGraph2D& shortest_graph) const {
198  F2CRoute route;
199  F2CSwath swath;
200  const size_t NS = swaths_by_cells.sizeTotal();
201  for (int i = 0; i < route_ids.size()-2; ++i) {
202  F2CPoint p_s = coverage_graph.indexToNode(route_ids[i]);
203  F2CPoint p_e = coverage_graph.indexToNode(route_ids[i+2]);
204  for (int j = 0; j < NS; ++j) {
205  F2CSwath swath = swaths_by_cells.getSwath(j).clone();
206  if (p_s == swath.startPoint() && p_e == swath.endPoint()) {
207  if (route.isEmpty() && r_start_end) {
208  route.addConnection(shortest_graph.shortestPath(
209  *r_start_end, swath.startPoint()));
210  }
211  route.addSwath(swath, shortest_graph);
212  break;
213  } else if (p_e == swath.startPoint() && p_s == swath.endPoint()) {
214  swath.reverse();
215  if (route.isEmpty() && r_start_end) {
216  route.addConnection(shortest_graph.shortestPath(
217  *r_start_end, swath.startPoint()));
218  }
219  route.addSwath(swath, shortest_graph);
220  break;
221  }
222  }
223  }
224  if (r_start_end) {
225  route.addConnection(shortest_graph.shortestPath(
226  route.endPoint(), *r_start_end));
227  }
228  return route;
229 }
230 
231 } // namespace f2c::rp
232 
233 
f2c::types::Graph2D
Definition: Graph2D.h:18
f2c::types::Swath::clone
Swath clone() const
Definition: Swath.cpp:117
f2c::types::Graph2D::addEdge
Graph2D & addEdge(const Point &i, const Point &j, int64_t cost)
Definition: Graph2D.cpp:23
5_route_planning.swaths
swaths
Definition: 5_route_planning.py:58
1_basic_types.cells
cells
Definition: 1_basic_types.py:93
f2c::rp::RoutePlannerBase::createCoverageGraph
virtual F2CGraph2D createCoverageGraph(const F2CCells &cells, const F2CSwathsByCells &swaths_by_cells, F2CGraph2D &shortest_graph, double d_tol, bool redirect_swaths=true) const
Definition: route_planner_base.cpp:91
f2c::rp::RoutePlannerBase::createShortestGraph
virtual F2CGraph2D createShortestGraph(const F2CCells &cells, const F2CSwathsByCells &swaths_by_cells, double d_tol) const
Definition: route_planner_base.cpp:40
f2c::rp::RoutePlannerBase::transformSolutionToRoute
virtual F2CRoute transformSolutionToRoute(const std::vector< long long int > &route_ids, const F2CSwathsByCells &swaths_by_cells, const F2CGraph2D &coverage_graph, F2CGraph2D &shortest_graph) const
Tranform index of points to an actual Route.
Definition: route_planner_base.cpp:193
1_basic_types.cell
cell
Definition: 1_basic_types.py:88
f2c::types::Swath
Definition: Swath.h:23
f2c::types::SwathsByCells::sizeTotal
size_t sizeTotal() const
Definition: SwathsByCells.cpp:100
f2c::types::Graph::getEdges
map_to_map_to_int getEdges() const
Definition: Graph.cpp:46
f2c::types::Swath::reverse
void reverse()
Definition: Swath.cpp:72
f2c::types::Graph2D::numNodes
size_t numNodes() const
Definition: Graph2D.cpp:57
2_objective_functions.swaths1
swaths1
Definition: 2_objective_functions.py:37
f2c::types::Graph::getCostFromEdge
int64_t getCostFromEdge(size_t from, size_t to, int64_t INF=1e15) const
Definition: Graph.cpp:61
5_route_planning.route
route
Definition: 5_route_planning.py:29
f2c::rp::RoutePlannerBase::r_start_end
std::optional< F2CPoint > r_start_end
Definition: route_planner_base.h:92
f2c::rp::RoutePlannerBase::setStartAndEndPoint
void setStartAndEndPoint(const F2CPoint &p)
Set the start and the end of the route.
Definition: route_planner_base.cpp:36
f2c::rp::RoutePlannerBase::computeBestRoute
virtual std::vector< long long int > computeBestRoute(const F2CGraph2D &cov_graph, bool show_log, long int time_limit_seconds, bool use_guided_local_search=true) const
Definition: route_planner_base.cpp:149
f2c::types::Graph2D::indexToNode
Point indexToNode(size_t id) const
Definition: Graph2D.cpp:73
f2c::types::Graph2D::addDirectedEdge
Graph2D & addDirectedEdge(const Point &from, const Point &to, int64_t cost)
Definition: Graph2D.cpp:12
1_basic_types.ring
ring
Definition: 1_basic_types.py:68
f2c::types::Swath::endPoint
Point endPoint() const
Definition: Swath.cpp:99
f2c::types::Graph2D::getNodes
std::vector< Point > getNodes() const
Definition: Graph2D.cpp:61
f2c::rp::RoutePlannerBase::genRoute
virtual F2CRoute genRoute(const F2CCells &cells, const F2CSwathsByCells &swaths_by_cells, bool show_log=false, double d_tol=1e-4, bool redirect_swaths=true, long int time_limit_seconds=1, bool search_for_optimum=false)
Definition: route_planner_base.cpp:21
f2c::types::LineString
Definition: LineString.h:19
f2c::rp
Route planning algorithms' namespace.
Definition: boustrophedon_order.h:14
f2c::types::SwathsByCells::getSwath
Swath & getSwath(size_t i)
Definition: SwathsByCells.cpp:74
f2c::types::Swath::startPoint
Point startPoint() const
Definition: Swath.cpp:92
f2c::types::Cells
Definition: Cells.h:21
f2c::types::Route
Definition: Route.h:23
f2c::types::Graph2D::shortestPath
std::vector< Point > shortestPath(const Point &from, const Point &to, int64_t INF=1<< 30)
Definition: Graph2D.cpp:91
route_planner_base.h
f2c::types::Point
Definition: Point.h:21
f2c::types::Graph2D::removeEdge
Graph2D & removeEdge(const Point &i, const Point &j)
Definition: Graph2D.cpp:53
f2c::types::SwathsByCells
Definition: SwathsByCells.h:17


fields2cover
Author(s):
autogenerated on Fri Apr 25 2025 02:18:31