graph.cpp
Go to the documentation of this file.
00001 
00038 #include <yaml-cpp/yaml.h>
00039 #include <fstream>
00040 #include <boost/graph/dijkstra_shortest_paths.hpp>
00041 #include <boost/foreach.hpp>
00042 
00043 #include <bwi_mapper/graph.h>
00044 #include <bwi_mapper/map_utils.h>
00045 #include <bwi_mapper/point_utils.h>
00046 
00047 #ifdef HAVE_NEW_YAMLCPP
00048 namespace YAML {
00049   // The >> operator disappeared in yaml-cpp 0.5, so this function is
00050   // added to provide support for code written under the yaml-cpp 0.3 API.
00051   template<typename T>
00052   void operator >> (const YAML::Node& node, T& i)
00053   {
00054     i = node.as<T>();
00055   }
00056 }
00057 #endif
00058 
00059 namespace bwi_mapper {
00060 
00065   void drawGraph(cv::Mat &image, const Graph& graph,
00066       uint32_t orig_x, uint32_t orig_y, bool put_text, bool put_all_edges,
00067       std::vector<std::pair<size_t, size_t> > specific_edges) {
00068 
00069     Graph::vertex_iterator vi, vend;
00070     size_t count = 0;
00071     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; 
00072         ++vi, ++count) {
00073       Point2f location = graph[*vi].location;
00074       // Draw the edges from this vertex
00075       std::vector<size_t> adj_vertices;
00076       getAdjacentNodes(count, graph, adj_vertices);
00077       BOOST_FOREACH(size_t adj_vtx, adj_vertices) {
00078         if (adj_vtx > count) {
00079           bool allow_edge = put_all_edges;
00080           allow_edge = allow_edge || 
00081             std::find(specific_edges.begin(), specific_edges.end(), 
00082                 std::make_pair(count, adj_vtx)) != specific_edges.end();
00083           allow_edge = allow_edge || 
00084             std::find(specific_edges.begin(), specific_edges.end(), 
00085                 std::make_pair(adj_vtx, count)) != specific_edges.end();
00086           if (allow_edge) {
00087             Point2f location2 = getLocationFromGraphId(adj_vtx, graph);
00088             cv::Point start_pt = 
00089               cv::Point(orig_x + location.x, orig_y + location.y);
00090             cv::Point end_pt = 
00091               cv::Point(orig_x + location2.x, orig_y + location2.y);
00092             float shift_ratio = 15.0f / cv::norm(start_pt - end_pt);
00093             cv::Point start_shift = start_pt + shift_ratio * (end_pt - start_pt); 
00094             cv::Point end_shift = end_pt + shift_ratio * (start_pt - end_pt); 
00095             cv::line(image, start_shift, end_shift, 
00096                 cv::Scalar(160, 160, 255),
00097                 4, CV_AA); // draw an anti aliased line
00098           }
00099         }
00100       }
00101     }
00102 
00103     count = 0;
00104     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; ++vi) {
00105       Point2f location = graph[*vi].location;
00106       // Draw this vertex
00107       cv::Point vertex_loc(orig_x + (uint32_t)location.x, 
00108           orig_y + (uint32_t)location.y);
00109       if (put_text) {
00110         cv::Point text_loc = vertex_loc + cv::Point(-7,7);
00111         if (count >= 10) {
00112           text_loc = text_loc + cv::Point(-7,0);
00113         }
00114         cv::putText(image, boost::lexical_cast<std::string>(count), text_loc,
00115             cv::FONT_HERSHEY_SIMPLEX, 0.7, cvScalar(0,0,255), 2, CV_AA);
00116       } else {
00117         size_t vertex_size = 13; // + graph[*vi].pixels / 10;
00118         cv::circle(image, vertex_loc, vertex_size, cv::Scalar(0,0,255), -1, CV_AA);
00119       }
00120       count++;
00121     }
00122   }
00123 
00124   void drawArrowOnImage(cv::Mat &image, const cv::Point2f &arrow_center, float orientation, 
00125                         const cv::Scalar &color, int size, int thickness) {
00126 
00127     cv::Point arrow_start = arrow_center +
00128       cv::Point2f(size * cosf(orientation + M_PI/2), 
00129                   size * sinf(orientation + M_PI/2));
00130     cv::Point arrow_end = arrow_center -
00131       cv::Point2f(size * cosf(orientation + M_PI/2), 
00132                   size * sinf(orientation + M_PI/2));
00133 
00134     cv::line(image, arrow_start, arrow_end, color, thickness, CV_AA);
00135 
00136     // http://mlikihazar.blogspot.com/2013/02/draw-arrow-opencv.html
00137     cv::Point p(arrow_start), q(arrow_end);
00138 
00139     //Draw the first segment
00140     float angle = atan2f(p.y - q.y, p.x - q.x);
00141     p.x = (int) (q.x + (size/2 - 1) * cos(angle + M_PI/4));
00142     p.y = (int) (q.y + (size/2 - 1) * sin(angle + M_PI/4));
00143     cv::line(image, p, q, color, thickness, CV_AA);
00144 
00145     //Draw the second segment
00146     p.x = (int) (q.x + (size/2 + 1) * cos(angle - M_PI/4));
00147     p.y = (int) (q.y + (size/2 + 1) * sin(angle - M_PI/4));
00148     cv::line(image, p, q, color, thickness, CV_AA);
00149 
00150   }
00151 
00152   void drawArrowOnGraph(cv::Mat &image, const Graph& graph, 
00153       std::pair<size_t, float> arrow, uint32_t map_width, uint32_t map_height,
00154       cv::Scalar color, uint32_t orig_x, uint32_t orig_y) {
00155 
00156     float orientation = arrow.second;
00157     Point2f loc = getLocationFromGraphId(arrow.first, graph);
00158     cv::Point node_loc(loc.x + orig_x, loc.y + orig_y); 
00159     cv::Point map_center(orig_x + map_width / 2, orig_y + map_height / 2);
00160     
00161     cv::Point arrow_center_1 = node_loc + 
00162       cv::Point(25 * cosf(orientation), 25 * sinf(orientation));
00163     cv::Point arrow_center_2 = node_loc - 
00164       cv::Point(25 * cosf(orientation), 25 * sinf(orientation));
00165     cv::Point arrow_center = (cv::norm(arrow_center_2 - map_center) <
00166         cv::norm(arrow_center_1 - map_center)) ? arrow_center_2 :
00167       arrow_center_1;
00168 
00169     drawArrowOnImage(image, arrow_center, orientation, color, 20, 3);
00170 
00171   }
00172 
00173   void drawCircleOnGraph(cv::Mat &image, const Graph& graph, 
00174       size_t node, cv::Scalar color,
00175       uint32_t orig_x, uint32_t orig_y) {
00176     Point2f loc = getLocationFromGraphId(node, graph);
00177     cv::Point circle_loc(loc.x + orig_x, loc.y + orig_y); 
00178     cv::circle(image, circle_loc, 15, color, 2, CV_AA); 
00179   }
00180 
00181   void drawSquareOnGraph(cv::Mat &image, const Graph& graph, 
00182       size_t node, cv::Scalar color,
00183       uint32_t orig_x, uint32_t orig_y, int size, int thickness) {
00184     Point2f loc = getLocationFromGraphId(node, graph);
00185     cv::Point square_loc(loc.x + orig_x, loc.y + orig_y); 
00186     cv::Rect rect(square_loc.x - size/2, square_loc.y - size/2, size, size);
00187     cv::rectangle(image, rect, color, thickness, CV_AA); 
00188   }
00189 
00190   void writeGraphToFile(const std::string &filename, 
00191       const Graph& graph, const nav_msgs::MapMetaData& info) {
00192 
00193     std::map<Graph::vertex_descriptor, size_t> vertex_map;
00194     size_t count = 0;
00195     Graph::vertex_iterator vi, vend;
00196     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; ++vi) {
00197       vertex_map[*vi] = count;
00198       count++;
00199     }
00200 
00201     count = 0;
00202     YAML::Emitter out;
00203     out << YAML::BeginSeq;
00204     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; ++vi) {
00205       out << YAML::BeginMap;
00206       Point2f pxl_loc = graph[*vi].location;
00207       Point2f real_loc = toMap(pxl_loc, info);
00208       out << YAML::Key << "id" << YAML::Value << count;
00209       out << YAML::Key << "x" << YAML::Value << real_loc.x;
00210       out << YAML::Key << "y" << YAML::Value << real_loc.y;
00211       out << YAML::Key << "edges" << YAML::Value << YAML::BeginSeq;
00212       Graph::adjacency_iterator ai, aend;
00213       for (boost::tie(ai, aend) = boost::adjacent_vertices(
00214             (Graph::vertex_descriptor)*vi, graph); 
00215           ai != aend; ++ai) {
00216         out << vertex_map[*ai];
00217       }
00218       out << YAML::EndSeq;
00219       out << YAML::EndMap;
00220       count++;
00221     }
00222     out << YAML::EndSeq;
00223 
00224     std::ofstream fout(filename.c_str());
00225     fout << out.c_str();
00226     fout.close();
00227   }
00228 
00229   void readGraphFromFile(const std::string &filename, 
00230       const nav_msgs::MapMetaData& info, Graph& graph) {
00231 
00232     std::vector<std::pair<float, float> > vertices;
00233     std::vector<std::vector<size_t> > edges;
00234 
00235     std::ifstream fin(filename.c_str());
00236     YAML::Node doc;
00237 #ifdef HAVE_NEW_YAMLCPP
00238     doc = YAML::Load(fin);
00239 #else
00240     YAML::Parser parser(fin);
00241     parser.GetNextDocument(doc);
00242 #endif
00243     for (size_t i = 0; i < doc.size(); ++i) {
00244       float x, y;
00245       doc[i]["x"] >> x;
00246       doc[i]["y"] >> y;
00247       vertices.push_back(std::make_pair(x, y));
00248       std::vector<size_t> v_edges;
00249       const YAML::Node& edges_node = doc[i]["edges"];
00250       for (size_t j = 0; j < edges_node.size(); ++j) {
00251         size_t t;
00252         edges_node[j] >> t;
00253         if (t > i) { // Only add edge one way
00254           v_edges.push_back(t);
00255           // std::cout << "Add edge: " << i << " -> " << t << std::endl;
00256         }
00257       }
00258       edges.push_back(v_edges);
00259     }
00260     fin.close();
00261 
00262     // Construct the graph object
00263     for (size_t i = 0; i < vertices.size(); ++i) {
00264       Graph::vertex_descriptor vi = boost::add_vertex(graph);
00265       Point2f real_loc (vertices[i].first, vertices[i].second);
00266       Point2f pxl_loc (toGrid(real_loc, info));
00267       graph[vi].location = pxl_loc;
00268       graph[vi].pixels = 0; // Not saved to file as of yet
00269     }
00270 
00271     for (size_t i = 0; i < edges.size(); ++i) {
00272       for (size_t j = 0; j < edges[i].size(); ++j) {
00273         Graph::vertex_descriptor vi,vj;
00274         vi = boost::vertex(i, graph);
00275         vj = boost::vertex(edges[i][j], graph);
00276         Graph::edge_descriptor e; bool b;
00277         boost::tie(e,b) = boost::add_edge(vi, vj, graph);
00278         graph[e].weight = 
00279           bwi_mapper::getMagnitude(graph[vi].location - graph[vj].location);
00280       }
00281     }
00282 
00283     std::cout << "Read graph with " << vertices.size() << " vertices." << std::endl;
00284   }
00285 
00286   Point2f getLocationFromGraphId(int idx, const Graph& graph) {
00287     Graph::vertex_descriptor i = boost::vertex(idx, graph);
00288     return graph[i].location;
00289   }
00290 
00291   size_t getClosestIdOnGraph(const Point2f &point, 
00292       const Graph &graph, double threshold) {
00293     Graph::vertex_iterator vi, vend;
00294     size_t count = 0, min_idx = -1;
00295     float min_distance = std::numeric_limits<float>::max(); 
00296     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; ++vi) {
00297       Point2f location = graph[*vi].location;
00298       if (bwi_mapper::getMagnitude(point - location) <= min_distance) {
00299         min_distance =
00300           bwi_mapper::getMagnitude(point - location);
00301         min_idx = count;
00302       }
00303       count++;
00304     }
00305     if (min_distance < threshold || threshold == 0.0) {
00306       return min_idx;
00307     } else {
00308       return -1;
00309     }
00310   }
00311 
00312   size_t getClosestIdOnGraphFromEdge(const Point2f& point, 
00313       const Graph &graph, size_t prev_graph_id) {
00314 
00315     boost::property_map<Graph, boost::vertex_index_t>::type 
00316         indexmap = boost::get(boost::vertex_index, graph);
00317 
00318     Graph::vertex_descriptor prev_vertex = boost::vertex(prev_graph_id, graph);
00319     Point2f location = graph[prev_vertex].location;
00320 
00321     size_t min_idx = -1;
00322     float min_distance = std::numeric_limits<float>::max();
00323     Point2f other_location;
00324 
00325     Graph::adjacency_iterator ai, aend;
00326     for (boost::tie(ai, aend) = boost::adjacent_vertices(prev_vertex, graph); 
00327         ai != aend; ++ai) {
00328       Point2f location2 = graph[*ai].location;
00329 
00330       float distance = bwi_mapper::minimumDistanceToLineSegment(
00331            location, location2, point);
00332       if (distance < min_distance) {
00333         other_location = location2;
00334         min_distance = distance;
00335         min_idx = indexmap[*ai]; 
00336       }
00337     }
00338 
00339     if (getMagnitude(point - location) < getMagnitude(point - other_location)) {
00340       return prev_graph_id;
00341     } else {
00342       return min_idx;
00343     }
00344   }
00345 
00346   bool isVisible(size_t u, size_t v, const Graph &graph, 
00347       const nav_msgs::OccupancyGrid& map) {
00348     Point2f loc_u = getLocationFromGraphId(u, graph);
00349     Point2f loc_v = getLocationFromGraphId(v, graph);
00350     return locationsInDirectLineOfSight(loc_u, loc_v, map);
00351   }
00352 
00353   float getNodeAngle(size_t u, size_t v, const Graph & graph) {
00354     Graph::vertex_descriptor vd_u = boost::vertex(u, graph);
00355     Graph::vertex_descriptor vd_v = boost::vertex(v, graph);
00356     return atan2f(graph[vd_v].location.y - graph[vd_u].location.y,
00357         graph[vd_v].location.x - graph[vd_u].location.x);
00358   }
00359 
00360   float getEuclideanDistance(size_t u, size_t v, const Graph& graph) {
00361     Graph::vertex_descriptor vd_u = boost::vertex(u, graph);
00362     Graph::vertex_descriptor vd_v = boost::vertex(v, graph);
00363     return getMagnitude(graph[vd_v].location - graph[vd_u].location);
00364   }
00365 
00366   float getShortestPathWithDistance(size_t start_idx, size_t goal_idx,
00367       std::vector<size_t> &path_from_goal, const Graph &graph) {
00368 
00369     bwi_mapper::Graph graph_copy(graph);
00370     // Perform Dijakstra from start_idx
00371     std::vector<Graph::vertex_descriptor> 
00372       p(boost::num_vertices(graph_copy));
00373     std::vector<double> d(boost::num_vertices(graph_copy));
00374     Graph::vertex_descriptor s = 
00375       boost::vertex(start_idx, graph_copy);
00376 
00377     boost::property_map<Graph, boost::vertex_index_t>::type 
00378         indexmap = boost::get(boost::vertex_index, graph_copy);
00379     boost::property_map<
00380       Graph, 
00381       double Edge::*
00382     >::type weightmap = boost::get(&Edge::weight, graph_copy);
00383     boost::dijkstra_shortest_paths(graph_copy, s, &p[0], &d[0], weightmap,
00384         indexmap, std::less<double>(), boost::closed_plus<double>(),
00385         (std::numeric_limits<double>::max)(), 0,
00386         boost::default_dijkstra_visitor());
00387 
00388     // Look up the parent chain from the goal vertex to the start vertex
00389     path_from_goal.clear();
00390 
00391     /* std::cout << "path from goal: " << goal_idx << " to start: " << start_idx << std::endl; */
00392     Graph::vertex_descriptor g = boost::vertex(goal_idx, graph_copy);
00393     /* float shortest_distance = std::numeric_limits<float>::quiet_NaN(); */
00394     while (indexmap[p[g]] != start_idx) {
00395       /* std::cout << " - " << indexmap[p[g]] << "(" << d[g] << ")" << std::endl; */
00396       path_from_goal.push_back(indexmap[p[g]]);
00397       g = p[g];
00398     }
00399     path_from_goal.push_back(start_idx);
00400     /* std::cout << " - goal Distance: " << d[goal_idx] << std::endl; */
00401 
00402     return d[goal_idx];
00403 
00404   }
00405 
00406   float getShortestPathDistance(size_t start_idx, size_t goal_idx,
00407       const Graph &graph) {
00408     std::vector<size_t> temp_path;
00409     return getShortestPathWithDistance(start_idx, goal_idx, temp_path, graph);
00410   }
00411 
00412   void getAdjacentNodes(size_t graph_id, const Graph& graph,
00413       std::vector<size_t>& adjacent_vertices) {
00414 
00415     adjacent_vertices.clear();
00416 
00417     boost::property_map<Graph, boost::vertex_index_t>::type 
00418         indexmap = boost::get(boost::vertex_index, graph);
00419 
00420     Graph::vertex_descriptor vertex = boost::vertex(graph_id, graph);
00421     Graph::adjacency_iterator ai, aend;
00422     for (boost::tie(ai, aend) = boost::adjacent_vertices(vertex, graph); 
00423         ai != aend; ++ai) {
00424       adjacent_vertices.push_back(indexmap[*ai]);
00425     }
00426 
00427   }
00428 
00429   void getVisibleNodes(size_t v, const Graph& graph, 
00430       const nav_msgs::OccupancyGrid& grid,
00431       std::vector<size_t>& visible_vertices, float visibility_range) {
00432 
00433     visible_vertices.clear();
00434 
00435     Point2f loc_v = getLocationFromGraphId(v, graph);
00436     size_t count = 0;
00437     Graph::vertex_iterator vi, vend;
00438     for (boost::tie(vi, vend) = boost::vertices(graph); vi != vend; 
00439         ++vi, ++count) {
00440       bool is_visible = isVisible(v, count, graph, grid);
00441       if (is_visible && visibility_range != 0.0f) {
00442         is_visible = is_visible && 
00443           (getEuclideanDistance(v, count, graph) < visibility_range);
00444       }
00445       if (is_visible) {
00446         visible_vertices.push_back(count);
00447       }
00448     }
00449   }
00450   
00451 } /* bwi_mapper */


bwi_mapper
Author(s): Piyush Khandelwal
autogenerated on Fri Aug 28 2015 10:14:35