rtree_graph_planner.hpp
Go to the documentation of this file.
1 /// Copyright (c) 2014-2016 Andrew Hundt, Johns Hopkins University
2 ///
3 /// @author Andrew Hundt <ATHundt@gmail.com>
4 ///
5 /// Dual licensed under the BSD or Apache License, Version 2.0
6 /// (the "Licenses") licenses at users option. Contributions shall be made such
7 /// that users can continue to choose between the Licenses.
8 /// You may not use this project except in compliance with the Licenses.
9 ///
10 /// BSD license:
11 /// ------------
12 ///
13 /// Redistribution and use in source and binary forms, with or without
14 /// modification, are permitted provided that the following conditions are met:
15 ///
16 /// 1. Redistributions of source code must retain the above copyright notice, this
17 /// list of conditions and the following disclaimer.
18 /// 2. Redistributions in binary form must reproduce the above copyright notice,
19 /// this list of conditions and the following disclaimer in the documentation
20 /// and/or other materials provided with the distribution.
21 ///
22 /// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
23 /// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
24 /// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
25 /// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
26 /// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
27 /// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 /// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
29 /// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 /// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
31 /// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 ///
33 /// The views and conclusions contained in the software and documentation are those
34 /// of the authors and should not be interpreted as representing official policies,
35 /// either expressed or implied, of the grl Project.
36 ///
37 /// Apache v2 license:
38 /// ------------------
39 ///
40 /// You may obtain a copy of the Apache License, Version 2.0 (the "License") at
41 ///
42 /// http://www.apache.org/licenses/LICENSE-2.0
43 ///
44 /// Unless required by applicable law or agreed to in writing, software
45 /// distributed under the License is distributed on an "AS IS" BASIS,
46 /// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
47 /// See the License for the specific language governing permissions and
48 /// limitations under the License.
49 
50 #ifndef RTREE_PLANNER_HPP_
51 #define RTREE_PLANNER_HPP_
52 
53 #include <vector>
54 
55 #include <boost/random/mersenne_twister.hpp>
56 
57 #include <boost/graph/adjacency_list.hpp>
58 #include <boost/graph/breadth_first_search.hpp>
59 #include <boost/graph/adjacency_list.hpp>
60 #include <boost/graph/dijkstra_shortest_paths.hpp>
61 
62 #include <boost/pending/indirect_cmp.hpp>
63 #include <boost/range/irange.hpp>
64 #include <boost/range/numeric.hpp>
65 #include <boost/range/algorithm/transform.hpp>
66 #include <boost/range/algorithm/fill.hpp>
67 
68 
69 #include <boost/geometry.hpp>
70 #include <boost/geometry/algorithms/distance.hpp>
71 #include <boost/geometry/geometries/register/point.hpp>
72 #include <boost/geometry/geometries/point.hpp>
73 #include <boost/geometry/geometries/box.hpp>
74 #include <boost/geometry/geometries/polygon.hpp>
75 #include <boost/geometry/algorithms/correct.hpp>
76 #include <boost/geometry/geometries/adapted/boost_array.hpp>
77 #include <boost/geometry/geometries/register/linestring.hpp>
78 #include <boost/geometry/index/rtree.hpp>
79 
80 #include <boost/math/special_functions/fpclassify.hpp>
81 #include <boost/math/constants/constants.hpp>
82 #include <boost/math/special_functions/sign.hpp>
83 
84 namespace bg = boost::geometry;
85 namespace bgi = boost::geometry::index;
86 
87 BOOST_GEOMETRY_REGISTER_BOOST_ARRAY_CS(cs::cartesian)
88 
89 
90 
91 namespace plan {
92 
93 // Define properties for vertex
94 // source boost geometry graph example: https://github.com/boostorg/geometry/blob/bd9455207bb0012237c1853c3281ea95f146f91c/example/07_b_graph_route_example.cpp
95 template <typename Point>
97 {
99  {
100  boost::geometry::assign_zero(location);
101  }
102  bg_vertex_property(Point const& loc)
103  : location(loc)
104  {
105  }
106 
107  Point location;
108 };
109 
110 // Define properties for edge
111 // source boost geometry graph example: https://github.com/boostorg/geometry/blob/bd9455207bb0012237c1853c3281ea95f146f91c/example/07_b_graph_route_example.cpp
112 template <typename Line>
114 {
115  bg_edge_property(Line const& line)
116  : length(boost::geometry::length(line))
117  , m_line(line)
118  {
119  }
120 
121  inline Line const& line() const
122  {
123  return m_line;
124  }
125 
126  double length;
127 private :
128  Line m_line;
129 };
130 
131 
132  //typedef bg::model::point<double, 3, bg::cs::cartesian> point;
133  typedef boost::array<double,6> ArmPos;
134  typedef ArmPos point_type;
135  typedef bg::model::box<point_type> box;
136  //typedef bg::model::referring_segment<point_type> line_type; /// @todo maybe better to use refs?
137  typedef bg::model::segment<point_type> line_type;
138  typedef line_type edge_type;
139  //typedef bg::model::polygon<point, false, false> polygon; // ccw, open polygon
140 
141  typedef boost::adjacency_list
142  <
143  boost::vecS, boost::vecS, boost::undirectedS
144  , bg_vertex_property<point_type> // bundled
147 
148  typedef boost::graph_traits<graph_type>::vertex_descriptor vertex_descriptor_type;
149  typedef bg_vertex_property<point_type> vertex_property_type;
151 
152  typedef std::pair<point_type, vertex_descriptor_type> rtree_value;
153  typedef boost::geometry::index::rtree<rtree_value,bgi::rstar<16, 4> > knn_rtree_type;
154 
155 } // namespace plan
156 
157 
158 BOOST_GEOMETRY_REGISTER_LINESTRING(std::vector<plan::ArmPos>)
159 
160 
161 template<typename T>
163 {
164  // copy the sign of the value in radians to the value of pi
165  T signedPI = boost::math::copysign(boost::math::constants::pi<T>(),rad);
166  // set the value of rad to the appropriate signed value between pi and -pi
167  rad = std::fmod(rad+signedPI,(boost::math::constants::two_pi<T>())) - signedPI;
168 
169  return rad;
170 }
171 
172 
173 // functor for getting sum of previous result and square of current element
174 // source: http://stackoverflow.com/questions/1326118/sum-of-square-of-each-elements-in-the-vector-using-for-each
175 template<typename T>
176 struct square
177 {
178  T operator()(const T& Left, const T& Right) const
179  {
180  return (Left + Right*Right);
181  }
182 };
183 
184 namespace boost { namespace geometry {
185 
186 
187 /// distance on an n-torus, so any dimensions offset by 2pi are equal and distances wrap
188 /// @example comparable_distance(pi-.01,-pi+.01) == .02 radians
189 double comparable_distance(plan::ArmPos const& p1, plan::ArmPos const& p2 ) {
190  plan::ArmPos diff;
191  boost::transform(p1,p2,diff.begin(),std::minus<plan::ArmPos::value_type>());
192  boost::transform(diff,diff.begin(),&normalizeRadiansPiToMinusPi<plan::ArmPos::value_type>);
193  return boost::accumulate(diff,0,square<plan::ArmPos::value_type>());
194 }
195 
196 
197 
198 /// distance between a a point and an axis aligned "box" on the surface of an n-torus
199 // so any dimensions offset by 2pi are equal and distances wrap
200 template<typename Box>
201 double comparable_distance(plan::ArmPos const& armpos, Box const& box ){
202  namespace bg = boost::geometry;
203  plan::ArmPos normAP = normalizeRadiansPiToMinusPi(armpos);
204  plan::ArmPos mindiff;
205  boost::transform(normAP,bg::get<bg::min_corner>(box),mindiff.begin(),std::minus<plan::ArmPos::value_type>());
206  boost::transform(mindiff,mindiff.begin(),&normalizeRadiansPiToMinusPi<plan::ArmPos::value_type>);
207  plan::ArmPos maxdiff;
208  boost::transform(normAP,bg::get<bg::max_corner>(box),maxdiff.begin(),std::minus<plan::ArmPos::value_type>());
209  boost::transform(maxdiff,maxdiff.begin(),&normalizeRadiansPiToMinusPi<plan::ArmPos::value_type>);
210 
211  plan::ArmPos::value_type final_distance = 0.0;
212  for(int i = 0; i < armpos.size(); ++i){
213  if(mindiff[i] >= 0.0 && maxdiff[i] <= 0.0) continue; // between the min and max means "in the box" for this dimension
214  plan::ArmPos::value_type min_dist = std::min(std::abs(mindiff[i]),std::abs(maxdiff[i]));
215  final_distance+=min_dist*min_dist;
216  }
217 
218  return final_distance;
219 // diff (min<D> - p<D>), (p<D> - max<D>)
220 }
221 
222 }} // namespace boost::geometry
223 
224 
225 ///
226 /// source boost geometry graph example: https://github.com/boostorg/geometry/blob/bd9455207bb0012237c1853c3281ea95f146f91c/example/07_b_graph_route_example.cpp
227 template <typename Graph, typename Route>
228 inline void add_edge_to_route(Graph const& graph,
229  typename boost::graph_traits<Graph>::vertex_descriptor vertex1,
230  typename boost::graph_traits<Graph>::vertex_descriptor vertex2,
231  Route& route)
232 {
233  std::pair
234  <
235  typename boost::graph_traits<Graph>::edge_descriptor,
236  bool
237  > opt_edge = boost::edge(vertex1, vertex2, graph);
238  if (opt_edge.second)
239  {
240  // Get properties of edge and of vertex
241  plan::edge_property_type const& edge_prop = graph[opt_edge.first];
243  <
244  typename boost::geometry::point_type<plan::edge_type>::type
245  > const& vertex_prop = graph[vertex2];
246 
247  // Depending on how edge connects to vertex, copy it forward or backward
248  if (boost::geometry::equals(*bg::segment_view<plan::edge_type>(edge_prop.line()).begin(), vertex_prop.location))
249  {
250  std::copy(bg::segment_view<plan::edge_type>(edge_prop.line()).begin(), bg::segment_view<plan::edge_type>(edge_prop.line()).end(),
251  std::back_inserter(route));
252  }
253  else
254  {
255  std::reverse_copy(bg::segment_view<plan::edge_type>(edge_prop.line()).begin(), bg::segment_view<plan::edge_type>(edge_prop.line()).end(),
256  std::back_inserter(route));
257  }
258  }
259 }
260 
261 /// After running dijkstra's algorithm build list of shortest path steps between start and end position.
262 /// @note there will be duplicate positions that should be removed.
263 /// source boost geometry graph example: https://github.com/boostorg/geometry/blob/bd9455207bb0012237c1853c3281ea95f146f91c/example/07_b_graph_route_example.cpp
264 template <typename Graph, typename Route>
265 inline void build_route(Graph const& graph,
266  std::vector<typename boost::graph_traits<Graph>::vertex_descriptor> const& predecessors,
267  typename boost::graph_traits<Graph>::vertex_descriptor vertex1,
268  typename boost::graph_traits<Graph>::vertex_descriptor vertex2,
269  Route& route)
270 {
271  typedef typename boost::graph_traits<Graph>::vertex_descriptor vertex_type;
272  vertex_type pred = predecessors[vertex2];
273 
274  add_edge_to_route(graph, pred, vertex2, route);
275  while (pred != vertex1)
276  {
277  add_edge_to_route(graph, predecessors[pred], pred, route);
278  pred = predecessors[pred];
279  }
280 }
281 
282 #endif
boost::array< double, 6 > ArmPos
bg::model::box< point_type > box
bg_vertex_property< point_type > vertex_property_type
T operator()(const T &Left, const T &Right) const
OutputIterator copy(std::string model, OutputIterator it, grl::revolute_joint_velocity_open_chain_state_constraint_tag)
copy vector of joint velocity limits in radians/s
Definition: Kuka.hpp:131
boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, bg_vertex_property< point_type >, bg_edge_property< line_type > > graph_type
T normalizeRadiansPiToMinusPi(T rad)
bg_vertex_property(Point const &loc)
boost::geometry::index::rtree< rtree_value, bgi::rstar< 16, 4 > > knn_rtree_type
void add_edge_to_route(Graph const &graph, typename boost::graph_traits< Graph >::vertex_descriptor vertex1, typename boost::graph_traits< Graph >::vertex_descriptor vertex2, Route &route)
bg_edge_property< edge_type > edge_property_type
ArmPos point_type
line_type edge_type
std::pair< point_type, vertex_descriptor_type > rtree_value
double comparable_distance(plan::ArmPos const &armpos, Box const &box)
distance between a a point and an axis aligned "box" on the surface of an n-torus ...
Line const & line() const
bg_edge_property(Line const &line)
bg::model::segment< point_type > line_type
void build_route(Graph const &graph, std::vector< typename boost::graph_traits< Graph >::vertex_descriptor > const &predecessors, typename boost::graph_traits< Graph >::vertex_descriptor vertex1, typename boost::graph_traits< Graph >::vertex_descriptor vertex2, Route &route)
boost::graph_traits< graph_type >::vertex_descriptor vertex_descriptor_type