/* * This file is part of the CoverageControl library * * Author: Saurav Agarwal * Contact: sauravag@seas.upenn.edu, agr.saurav1@gmail.com * Repository: https://github.com/KumarRobotics/CoverageControl * * Copyright (c) 2024, Saurav Agarwal * * The CoverageControl library is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or (at your * option) any later version. * * The CoverageControl library is distributed in the hope that it will be * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General * Public License for more details. * * You should have received a copy of the GNU General Public License along with * CoverageControl library. If not, see . */ /*! * \file plotter.cpp * \brief Helper function to plot maps */ #include #include #include "CoverageControl/extern/gnuplot/gnuplot-iostream.h" #include "CoverageControl/plotter.h" namespace CoverageControl { [[nodiscard]] bool Plotter::GnuplotCommands(Gnuplot &gp) { std::filesystem::path map_filename{ std::filesystem::weakly_canonical(dir + "/" + plot_name)}; std::filesystem::path dir_path{map_filename.parent_path()}; if (!std::filesystem::exists(dir_path)) { std::cerr << "Directory does not exist: " << dir_path << std::endl; return 1; } gp << "set o '" << map_filename.string() << "'\n"; gp << "set terminal pngcairo enhanced font 'Times," << font_sz << "' size " << image_sz << "," << image_sz << "\n"; gp << "set palette defined (-5 'black', -1 '" << color_unknown << "', 0 'white', 1 '" << color_idf << "')\n"; gp << "set cbrange [-5:1]\n"; gp << "set size ratio -1\n"; gp << "set xrange [0:" << range_max << "]\n"; gp << "set yrange [0:" << range_max << "]\n"; gp << "set border linewidth 1.5\n"; if (unset_colorbox) gp << "unset colorbox\n"; return 0; } void Plotter::StreamMap(Gnuplot &gp, MapType const &map) { for (int i = 0; i < map.rows(); ++i) { for (int j = 0; j < map.cols(); ++j) { gp << map(i, j) << " "; } gp << "\n"; } gp << "e" << std::endl; } void Plotter::PlotMap(Gnuplot &gp, bool begin) { if (begin == true) gp << "plot "; else gp << ", "; gp << "'-' matrix using ($2*" << resolution << "):($1*" << resolution << "):3 with image notitle "; } void Plotter::PlotLine(Gnuplot &gp, int marker_size, std::string color, bool begin) { if (begin == true) gp << "plot "; else gp << ", "; gp << "'-' with line lw " << marker_size << " lc rgb '" << color << "' notitle"; } void Plotter::PlotPoints(Gnuplot &gp, int point_type, int marker_size, std::string color, bool begin) { if (begin == true) gp << "plot "; else gp << ", "; gp << "'-' with points pt " << point_type << " ps " << marker_size << " lc rgb '" << color << "' notitle"; } void Plotter::PlotMap(MapType const &map) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); gp << "\n"; StreamMap(gp, map); } void Plotter::PlotMap(MapType const &map, PointVector const &positions) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); PlotPoints(gp, 7, marker_sz, color_robot); gp << "\n"; StreamMap(gp, map); for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; } void Plotter::PlotMap(MapType const &map, PointVector const &positions, std::vector> const &trajectories, std::vector const &robot_status) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); for (size_t i = 0; i < positions.size(); ++i) { if (robot_status[i] == 0) { PlotLine(gp, marker_sz, color_robot, false); } else { PlotLine(gp, marker_sz, color_robot_alt, false); } } for (size_t i = 0; i < positions.size(); ++i) { if (robot_status[i] == 0) { PlotPoints(gp, 7, marker_sz, color_robot, false); } else { PlotPoints(gp, 7, marker_sz, color_robot_alt, false); } } gp << "\n"; StreamMap(gp, map); for (auto const &trajectory : trajectories) { for (auto const &pos : trajectory) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; } for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << std::endl; gp << "e" << std::endl; } } void Plotter::PlotMap(MapType const &map, PointVector const &positions, std::vector> const &trajectories, std::vector const &robot_status, double const &communication_range) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); for (size_t i = 0; i < positions.size(); ++i) { if (robot_status[i] == 0) { PlotLine(gp, marker_sz, color_robot, false); } else { PlotLine(gp, marker_sz, color_robot_alt, false); } } PlotLine(gp, half_marker_sz, color_communication_links, false); for (size_t i = 0; i < positions.size(); ++i) { if (robot_status[i] == 0) { PlotPoints(gp, 7, marker_sz, color_robot, false); } else { PlotPoints(gp, 7, marker_sz, color_robot_alt, false); } } gp << "\n"; StreamMap(gp, map); for (auto const &trajectory : trajectories) { for (auto const &pos : trajectory) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; } for (size_t i = 0; i < positions.size(); ++i) { for (size_t j = i + 1; j < positions.size(); ++j) { if ((positions[i] - positions[j]).norm() < communication_range) { gp << positions[i][0] << " " << positions[i][1] << "\n"; gp << positions[j][0] << " " << positions[j][1] << "\n"; gp << "\n"; } } } gp << "e" << std::endl; for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << std::endl; gp << "e" << std::endl; } } void Plotter::PlotMap(MapType const &map, PointVector const &positions, std::vector> const &voronoi, std::vector> const &trajectories) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); PlotLine(gp, marker_sz, color_robot, false); PlotLine(gp, half_marker_sz, color_voronoi, false); // voronoi PlotPoints(gp, 7, marker_sz, color_robot, false); // robots gp << "\n"; StreamMap(gp, map); for (auto const &trajectory : trajectories) { for (auto const &pos : trajectory) { gp << pos[0] << " " << pos[1] << "\n"; } gp << "\n"; } gp << "e" << std::endl; for (auto const &vcell : voronoi) { for (auto const &pos : vcell) { gp << pos[0] << " " << pos[1] << "\n"; } gp << "\n"; } gp << "e" << std::endl; for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << "\n"; } gp << "e" << std::endl; } void Plotter::PlotMap(MapType const &map, PointVector const &positions, Voronoi const &voronoi, std::vector> const &trajectories) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); PlotLine(gp, marker_sz, color_robot, false); PlotLine(gp, half_marker_sz, color_voronoi, false); // voronoi PlotPoints(gp, 7, marker_sz, color_robot, false); // robots gp << "\n"; StreamMap(gp, map); for (auto const &trajectory : trajectories) { for (auto const &pos : trajectory) { gp << pos[0] << " " << pos[1] << "\n"; } gp << "\n"; } gp << "e" << std::endl; auto voronoi_cells = voronoi.GetVoronoiCells(); for (auto const &vcell : voronoi_cells) { for (auto const &pos : vcell.cell) { gp << pos[0] << " " << pos[1] << "\n"; } auto const &pos = vcell.cell.front(); gp << pos[0] << " " << pos[1] << "\n"; gp << "\n"; } gp << "e" << std::endl; for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << "\n"; } gp << "e" << std::endl; } void Plotter::PlotMap(MapType const &map, PointVector const &positions, PointVector const &goals, Voronoi const &voronoi) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); PlotLine(gp, half_marker_sz, color_voronoi, false); // voronoi PlotLine(gp, half_marker_sz, color_robot, false); // goals path PlotPoints(gp, 28, marker_sz, color_robot, false); // goals PlotPoints(gp, 7, marker_sz, color_robot, false); // robots gp << "\n"; StreamMap(gp, map); auto voronoi_cells = voronoi.GetVoronoiCells(); for (auto const &vcell : voronoi_cells) { for (auto const &pos : vcell.cell) { gp << pos[0] << " " << pos[1] << std::endl; } auto const &pos = vcell.cell.front(); gp << pos[0] << " " << pos[1] << std::endl; gp << "\n"; } gp << "e" << std::endl; for (size_t i = 0; i < positions.size(); ++i) { auto const &pos = positions[i]; auto const &goal = goals[i]; gp << pos[0] << " " << pos[1] << std::endl; gp << goal[0] << " " << goal[1] << std::endl; gp << "\n"; } gp << "e" << std::endl; for (auto const &pos : goals) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; } void Plotter::PlotMap(MapType const &map, PointVector const &positions, std::vector> const &trajectories, PointVector const &frontiers) { Gnuplot gp; if (GnuplotCommands(gp)) { std::cerr << "Error in GnuplotCommands" << std::endl; return; } PlotMap(gp); PlotLine(gp, marker_sz, color_robot); PlotPoints(gp, 7, marker_sz, color_robot); PlotPoints(gp, 1, half_marker_sz, color_robot); gp << "\n"; StreamMap(gp, map); for (auto const &trajectory : trajectories) { for (auto const &pos : trajectory) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "\n"; } gp << "e" << std::endl; for (auto const &pos : positions) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; for (auto const &pos : frontiers) { gp << pos[0] << " " << pos[1] << std::endl; } gp << "e" << std::endl; } } // namespace CoverageControl