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
00050
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
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);
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
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;
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
00137 cv::Point p(arrow_start), q(arrow_end);
00138
00139
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
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) {
00254 v_edges.push_back(t);
00255
00256 }
00257 }
00258 edges.push_back(v_edges);
00259 }
00260 fin.close();
00261
00262
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;
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
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
00389 path_from_goal.clear();
00390
00391
00392 Graph::vertex_descriptor g = boost::vertex(goal_idx, graph_copy);
00393
00394 while (indexmap[p[g]] != start_idx) {
00395
00396 path_from_goal.push_back(indexmap[p[g]]);
00397 g = p[g];
00398 }
00399 path_from_goal.push_back(start_idx);
00400
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 }