libcrn  3.9.5
A document image processing library
•All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CRNPathFinding.h
Go to the documentation of this file.
1 /* Copyright 2012-2016 CoReNum, INSA-Lyon, Université Paris Descartes, ENS-Lyon
2  *
3  * This file is part of libcrn.
4  *
5  * libcrn is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published by
7  * the Free Software Foundation, either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * libcrn is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public License
16  * along with libcrn. If not, see <http://www.gnu.org/licenses/>.
17  *
18  * file: CRNPathFinding.h
19  * \author Yann LEYDIER
20  */
21 
22 #ifndef CRNPathFinding_HEADER
23 #define CRNPathFinding_HEADER
24 
25 #include <CRNType.h>
26 #include <memory>
27 #include <vector>
28 #include <list>
29 
30 namespace crn
31 {
33  template<typename Node> struct AStarNode
34  {
37  Node node;
38  double cumulCost;
39  double distToEnd;
40  double totalCost;
41  std::weak_ptr<AStarNode> parent;
42  };
43 
60  template<
61  typename Node,
62  typename StepCostFunc,
63  typename DistanceEstimationFunc,
64  typename NeighborFunc,
65  typename std::enable_if<!traits::HasLT<Node>::value, int>::type = 0
66  >
67  std::vector<Node> AStar(const Node &first, const Node &last, const StepCostFunc &stepcost, const DistanceEstimationFunc &heuristic, const NeighborFunc &get_neighbors)
68  {
69  using NodePtr = std::shared_ptr<AStarNode<Node>>;
70  std::vector<NodePtr> openset;
71  std::vector<NodePtr> closeset;
72  // fist node
73  NodePtr n(std::make_shared<AStarNode<Node>>());
74  n->node = first;
75  n->distToEnd = heuristic(n->node, last);
76  n->totalCost = n->distToEnd;
77  openset.push_back(std::move(n));
78  while (!openset.empty())
79  {
80  // pick up the node with lowest cost
81  auto minit = std::min_element(openset.begin(), openset.end(), [](const NodePtr &n1, const NodePtr &n2){ return n1->cumulCost < n2->cumulCost; });
82  NodePtr currentnode = *minit;
83  //openset.erase(minit);
84  std::swap(*minit, openset.back()); openset.pop_back();
85  closeset.push_back(currentnode);
86  if (currentnode->node == last)
87  { // destination reached!
88  std::vector<Node> path;
89  // fill the path
90  while (currentnode)
91  {
92  path.push_back(currentnode->node);
93  currentnode = currentnode->parent.lock();
94  }
95  return std::vector<Node>(path.rbegin(), path.rend());
96  }
97  else
98  {
99  // compute neighbors
100  const std::vector<Node> neighbors(get_neighbors(currentnode->node));
101  for (const Node &neigh : neighbors)
102  { // for each neighbor
103  NodePtr nn(std::make_shared<AStarNode<Node>>());
104  nn->node = neigh;
105  const double newcost = currentnode->cumulCost + stepcost(currentnode->node, neigh);
106  // check if present in open set
107  auto openit = std::find_if(openset.begin(), openset.end(), [&neigh](const NodePtr &n){ return n->node == neigh; });
108  if (openit != openset.end())
109  { // found in open set
110  if ((*openit)->cumulCost <= newcost)
111  continue; // previous occurrence was better
112  else
113  { // update
114  nn = *openit;
115  //openset.erase(openit);
116  std::swap(*openit, openset.back()); openset.pop_back();
117  }
118  }
119  else
120  {
121  // check if present in close set
122  auto closeit = std::find_if(closeset.begin(), closeset.end(), [&neigh](const NodePtr &n){ return n->node == neigh; });
123  if (closeit != closeset.end())
124  { // found in close set
125  if ((*closeit)->cumulCost <= newcost)
126  continue; // previous pass was better
127  else
128  { // need to pass on it again
129  nn = *closeit;
130  closeset.erase(closeit);
131  }
132  }
133  }
134  // set the new candidate node
135  nn->cumulCost = newcost;
136  nn->distToEnd = heuristic(nn->node, last);
137  nn->totalCost = newcost + nn->distToEnd;
138  nn->parent = currentnode;
139  openset.push_back(std::move(nn));
140  } // for each neighbor
141  } // not end node
142  } // while there are candidate nodes left
143  throw ExceptionNotFound{"AStar(): No path found."};
144  }
145 
147  template<typename Node> struct AStarNodeC
148  {
151  Node node;
152  double cumulCost;
153  double distToEnd;
154  double totalCost;
155  std::weak_ptr<AStarNodeC<Node>> parent;
156  struct CMP
157  {
158  bool operator()(const std::shared_ptr<AStarNodeC> &n1, const std::shared_ptr<AStarNodeC> &n2) const { return n1->node < n2->node; }
159  };
160  };
161 
178  template<
179  typename Node,
180  typename StepCostFunc,
181  typename DistanceEstimationFunc,
182  typename NeighborFunc,
183  typename std::enable_if<traits::HasLT<Node>::value, int>::type = 0
184  >
185  std::vector<Node> AStar(const Node &first, const Node &last, const StepCostFunc &stepcost, const DistanceEstimationFunc &heuristic, const NeighborFunc &get_neighbors)
186  {
187  using NodePtr = std::shared_ptr<AStarNodeC<Node>>;
188  const auto comparer = typename AStarNodeC<Node>::CMP{};
189  auto openset = std::set<NodePtr, typename AStarNodeC<Node>::CMP>(comparer);
190  auto closeset = std::set<NodePtr, typename AStarNodeC<Node>::CMP>(comparer);
191  // fist node
192  auto n = std::make_shared<AStarNodeC<Node>>();
193  n->node = first;
194  n->distToEnd = heuristic(n->node, last);
195  n->totalCost = n->distToEnd;
196  openset.insert(std::move(n));
197  while (!openset.empty())
198  {
199  // pick up the node with lowest cost
200  auto minit = std::min_element(openset.begin(), openset.end(), [](const NodePtr &n1, const NodePtr &n2){ return n1->cumulCost < n2->cumulCost; });
201  auto currentnode = *minit;
202  openset.erase(minit);
203  closeset.insert(currentnode);
204  if (currentnode->node == last)
205  { // destination reached!
206  auto path = std::vector<Node>{};
207  // fill the path
208  while (currentnode)
209  {
210  path.push_back(currentnode->node);
211  currentnode = currentnode->parent.lock();
212  }
213  return std::vector<Node>(path.rbegin(), path.rend());
214  }
215  else
216  {
217  // compute neighbors
218  auto neighbors = get_neighbors(currentnode->node);
219  for (auto &&neigh : neighbors)
220  { // for each neighbor
221  auto nn = std::make_shared<AStarNodeC<Node>>();
222  nn->node = std::move(neigh);
223  const double newcost = currentnode->cumulCost + stepcost(currentnode->node, nn->node);
224  // check if present in open set
225  auto openit = openset.find(nn);
226  if (openit != openset.end())
227  { // found in open set
228  if ((*openit)->cumulCost <= newcost)
229  continue; // previous occurrence was better
230  else
231  { // update
232  nn = *openit;
233  openset.erase(openit);
234  }
235  }
236  else
237  {
238  // check if present in close set
239  auto closeit = closeset.find(nn);
240  if (closeit != closeset.end())
241  { // found in close set
242  if ((*closeit)->cumulCost <= newcost)
243  continue; // previous pass was better
244  else
245  { // need to pass on it again
246  nn = *closeit;
247  closeset.erase(closeit);
248  }
249  }
250  }
251  // set the new candidate node
252  nn->cumulCost = newcost;
253  nn->distToEnd = heuristic(nn->node, last);
254  nn->totalCost = newcost + nn->distToEnd;
255  nn->parent = currentnode;
256  openset.insert(std::move(nn));
257  } // for each neighbor
258  } // not end node
259  } // while there are candidate nodes left
260  throw ExceptionNotFound{"AStar(): No path found."};
261  }
262 
263 }
264 
265 #endif
266 
267 
AStarNode()
Constructor.
AStarNodeC()
Constructor.
A node in an A* graph.
A node in an A* graph.
std::vector< Node > AStar(const Node &first, const Node &last, const StepCostFunc &stepcost, const DistanceEstimationFunc &heuristic, const NeighborFunc &get_neighbors)
A* path finding.
std::weak_ptr< AStarNode > parent
bool operator()(const std::shared_ptr< AStarNodeC > &n1, const std::shared_ptr< AStarNodeC > &n2) const
std::weak_ptr< AStarNodeC< Node > > parent
An item was not found in a container.
Definition: CRNException.h:95