OpenLibrary
base.hpp
1 
2 /***************************************
3  * Base for A* routing algorithm *
4  * Author: MichaƂ Walenciak *
5  * Creation date: 14.08.2012 *
6  ***************************************/
7 
8 #ifndef OPENLIBRARY_A_START_ROUTER_HPP
9 #define OPENLIBRARY_A_START_ROUTER_HPP
10 
11 #include <assert.h>
12 #include <cmath>
13 #include <vector>
14 #include <iostream>
15 
16 #define DEBUG_DISABLE_OUTPUT
17 #include <common/debug.hpp>
18 
19 #include "traits.hpp"
20 
21 
22 namespace ol
23 {
24  namespace Router
25  {
26 
27  namespace
28  {
29  template<class T, class U, bool>
30  struct _H
31  {
32  static void insert(T &, const U &) {}
33  };
34 
35  template<class T, class U>
36  struct _H<T, U, true>
37  {
38  static void insert(T &container, const U &element)
39  {
40  container.push_front(element);
41  }
42  };
43 
44  template<class T, class U>
45  struct _H<T, U, false>
46  {
47  static void insert(T &container, const U &element)
48  {
49  container.push_back(element);
50  }
51  };
52  }
53 
83  typedef unsigned int FlagsT;
84 
85  template<class PointT, class OpenSetT, class ClosedSetT, FlagsT flags = 0>
86  class AStar
87  {
88  public:
89  AStar(): m_openSet(), m_closedSet() {}
90  virtual ~AStar() {}
91 
103  template<class PathT, class CoordinateT>
104  PathT route(CoordinateT startPoint, CoordinateT endPoint)
105  {
106  if (Container<PathT>::prependable == false) //if containter is not prependable - switch start and end points
107  std::swap(startPoint, endPoint);
108 
109  PointT firstPoint(startPoint.x, startPoint.y);
110  PointT lastPoint(endPoint.x, endPoint.y);
111 
112  //prepare sets
113  init(&firstPoint, &lastPoint);
114 
115  //find path
116  const bool status = findPath(&lastPoint);
117 
118  PathT path;
119  if (status)
120  path = reconstruct_path<PathT>(&lastPoint);
121 
122  return std::move(path);
123  }
124 
125  protected:
126  typedef decltype(PointT::f_score) FScoreT;
127  typedef decltype(PointT::g_score) GScoreT;
128 
129  OpenSetT m_openSet;
130  ClosedSetT m_closedSet;
131 
132  virtual void init(PointT *startPoint, PointT *endPoint)
133  {
134  startPoint->f_score = heuristic_cost_estimate(startPoint, endPoint);
135 
136  m_openSet.clear();
137  m_closedSet.clear();
138  m_openSet.insert(startPoint);
139  }
140 
141  //main loop of algorithm
142  virtual bool findPath(PointT *endPoint)
143  {
144  bool status = false;
145 
146  while (m_openSet.isEmpty() == false)
147  {
148  ol_debug(DebugLevel::Debug) << "\nopen set: " << m_openSet;
149  ol_debug(DebugLevel::Debug) << "closed set: " << m_closedSet;
150  PointT *currentPoint = m_openSet.getBest();
151 
152  ol_debug(DebugLevel::Debug) << "current point: " << *currentPoint;
153 
154  if ( *currentPoint == *endPoint )
155  {
156  ol_debug(DebugLevel::Debug) << "\t== end point";
157  endPoint->origin = currentPoint->origin;
158  endPoint->f_score = currentPoint->f_score;
159  endPoint->g_score = currentPoint->g_score;
160  status = true;
161  break;
162  }
163 
164  m_closedSet.insert(currentPoint);
165 
166  const std::vector<PointT *> neighbours = get_neighbours(currentPoint);
167  ol_debug(DebugLevel::Debug) << "\tneighbours: " << neighbours;
168 
169  for (PointT *neighbour: neighbours)
170  {
171  bool saved = false;
172  ol_debug(DebugLevel::Debug) << "\tprocessing neigbhbour " << *neighbour;
173 
174  //check if neigbhbour is already processed
175  if (m_closedSet.exists(neighbour))
176  ol_debug(DebugLevel::Debug) << "\t\tin closed set";
177  else
178  {
179  const GScoreT neighbour_g_score = currentPoint->g_score + distance(currentPoint, neighbour);
180 
181  static PointT dummy(0 ,0);
182  PointT *existing = &dummy;
183 
184  //check if in open set
185  if (m_openSet.exists(neighbour, existing) == false || neighbour_g_score < existing->g_score)
186  {
187  if (existing != &dummy) //just update existing point
188  {
189  ol_debug(DebugLevel::Debug) << "\t\tbetter than point already existing in open set. Updating";
190  existing->origin = neighbour->origin;
191  existing->g_score = neighbour_g_score;
192 
193  //due to potencial complexity of heuristic_cost_estimate function, recalculate f_score
194  existing->f_score = heuristic_cost_estimate(existing, endPoint);
195  }
196  else
197  {
198  ol_debug(DebugLevel::Debug) << "\t\tnot in open set. Adding";
199  neighbour->g_score = neighbour_g_score;
200  neighbour->f_score = heuristic_cost_estimate(neighbour, endPoint);
201  //neighbour->origin already set
202 
203  //add new point or update existing one
204  m_openSet.insert(neighbour);
205  saved = true;
206  }
207  }
208  else
209  ol_debug(DebugLevel::Debug) << "\t\talready in open set";
210  }
211 
212  if (saved == false)
213  delete neighbour;
214  }
215  }
216 
217  return status;
218  }
219 
220  virtual FScoreT heuristic_cost_estimate(const PointT *p1, const PointT *p2) const = 0;
221  virtual std::vector<PointT *> get_neighbours(PointT *p) = 0;
222 
223  template<class PathT>
224  PathT reconstruct_path(PointT *last)
225  {
226  assert(last->origin != nullptr);
227 
228  PathT result;
229  PointT *p = last;
230 
231  while (p != nullptr)
232  _H<PathT, PointT, Container<PathT>::prependable>::insert(result, *p), p = p->origin;
233 
234  return std::move(result);
235  }
236 
237  long double distance(const PointT *p1, const PointT *p2) const
238  {
239  const auto pow2 = [](long double x) -> long double { return x * x; };
240  const long double dist = sqrt( pow2(p1->x - p2->x) + pow2(p1->y - p2->y) );
241  return dist;
242  }
243  };
244  }
245 }
246 
247 #endif
PathT route(CoordinateT startPoint, CoordinateT endPoint)
function for finding path
Definition: base.hpp:104
Definition: base.hpp:86
Definition: debug.hpp:45
Definition: traits.hpp:24