00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014 #include "tango_ros_native/occupancy_grid_file_io.h"
00015
00016 #include <cmath>
00017 #include <fstream>
00018 #include <iostream>
00019 #include <sys/stat.h>
00020 #include <unistd.h>
00021
00022 #include <geometry_msgs/Quaternion.h>
00023 #include <tf/LinearMath/Matrix3x3.h>
00024
00025 #include <glog/logging.h>
00026
00027 #include <yaml-cpp/yaml.h>
00028
00029 namespace {
00030 void AddTrailingSlashToDirectoryPathIfNeeded(std::string* directory_path) {
00031 if (!directory_path->empty() && directory_path->back() != '/') {
00032 (*directory_path) += '/';
00033 }
00034 }
00035 bool DirectoryPathExists(const std::string& path) {
00036 struct stat st;
00037 return (stat(path.c_str(), &st) == 0 && (st.st_mode & S_IFDIR));
00038 }
00039 bool MakeDirectoryPath(const std::string& input_path, mode_t mode) {
00040 if (input_path.empty()) {
00041
00042 return 0;
00043 }
00044
00045 size_t previous_slash_pos = 0;
00046 size_t current_slash_pos;
00047 std::string dir;
00048 int make_dir_status = 0;
00049
00050 std::string path = input_path;
00051 AddTrailingSlashToDirectoryPathIfNeeded(&path);
00052
00053 while ((current_slash_pos = path.find_first_of('/', previous_slash_pos)) !=
00054 std::string::npos) {
00055 dir = path.substr(0, current_slash_pos++);
00056 previous_slash_pos = current_slash_pos;
00057 if (dir.empty() || dir == ".")
00058 continue;
00059
00060 if ((make_dir_status = mkdir(dir.c_str(), mode)) && errno != EEXIST) {
00061 return false;
00062 }
00063 }
00064 return true;
00065 }
00066 }
00067
00068 namespace occupancy_grid_file_io {
00069 bool SaveOccupancyGridToFiles(
00070 const std::string& map_name, const std::string& map_uuid,
00071 const std::string& map_directory, const nav_msgs::OccupancyGrid& occupancy_grid) {
00072 return SaveOccupancyGridDataToPgmFile(map_name, map_directory, occupancy_grid)
00073 && SaveOccupancyGridMetadataToYamlFile(map_name, map_uuid, map_directory, occupancy_grid.info);
00074 }
00075
00076 bool SaveOccupancyGridDataToPgmFile(
00077 const std::string& map_name, const std::string& map_directory,
00078 const nav_msgs::OccupancyGrid& occupancy_grid) {
00079 std::string map_directory_with_trailing_slash = map_directory;
00080 AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00081 if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
00082 LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
00083 if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
00084 LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
00085 return false;
00086 }
00087 }
00088
00089 std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
00090 FILE* pgm_file = fopen(map_pgm_file_path.c_str(), "w");
00091 if (!pgm_file) {
00092 LOG(ERROR) << "Could no open file " << map_pgm_file_path;
00093 return false;
00094 }
00095
00096 fprintf(pgm_file, "P5\n# CREATOR: TangoRosStreamer %.3f m/pix\n%d %d\n255\n",
00097 occupancy_grid.info.resolution,
00098 occupancy_grid.info.width, occupancy_grid.info.height);
00099 for (size_t i = 0; i < occupancy_grid.info.height; ++i) {
00100 for (size_t j = 0; j < occupancy_grid.info.width; ++j) {
00101
00102
00103 int value = occupancy_grid.data[j + (occupancy_grid.info.height - i - 1) * occupancy_grid.info.width];
00104 if (value == 0) {
00105 fputc(254, pgm_file);
00106 } else if (value == +100) {
00107 fputc(000, pgm_file);
00108 } else {
00109 fputc(205, pgm_file);
00110 }
00111 }
00112 }
00113 fclose(pgm_file);
00114 LOG(INFO) << "Map image successfully saved to " << map_pgm_file_path;
00115 return true;
00116 }
00117
00118 bool SaveOccupancyGridMetadataToYamlFile(
00119 const std::string& map_name, const std::string& map_uuid,
00120 const std::string& map_directory, const nav_msgs::MapMetaData& map_metadata) {
00121 std::string map_directory_with_trailing_slash = map_directory;
00122 AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00123 if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
00124 LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
00125 if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
00126 LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
00127 return false;
00128 }
00129 }
00130
00131 std::string image_name = map_name;
00132 if (image_name.empty())
00133 image_name = "\"\"";
00134 std::string uuid = map_uuid;
00135 if (uuid.empty())
00136 uuid = "\"\"";
00137
00138 std::string map_yaml_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
00139 FILE* yaml_file = fopen(map_yaml_file_path.c_str(), "w");
00140 if (!yaml_file) {
00141 LOG(ERROR) << "Could no open file " << map_yaml_file_path;
00142 return false;
00143 }
00144
00145 tf::Matrix3x3 mat(tf::Quaternion(map_metadata.origin.orientation.x,
00146 map_metadata.origin.orientation.y,
00147 map_metadata.origin.orientation.z,
00148 map_metadata.origin.orientation.w));
00149 double yaw, pitch, roll;
00150 mat.getEulerYPR(yaw, pitch, roll);
00151 if (std::isnan(yaw))
00152 yaw = 0.0;
00153
00154 fprintf(yaml_file, "image: %s.pgm\nresolution: %f\norigin: [%f, %f, %f]\nnegate: 0\n"
00155 "occupied_thresh: 0.65\nfree_thresh: 0.196\nuuid: %s\n\n",
00156 map_name.c_str(), map_metadata.resolution, map_metadata.origin.position.x,
00157 map_metadata.origin.position.y, yaw, uuid.c_str());
00158
00159 fclose(yaml_file);
00160 LOG(INFO) << "Map yaml file successfully saved to " << map_yaml_file_path;
00161 return true;
00162 }
00163
00164 bool LoadOccupancyGridFromFiles(
00165 const std::string& map_name, const std::string& map_directory,
00166 nav_msgs::OccupancyGrid* occupancy_grid, std::string* map_uuid) {
00167 int negate;
00168 double occupied_threshold;
00169 double free_threshold;
00170 bool result = LoadOccupancyGridMetadataFromYamlFile(
00171 map_name, map_directory, &(occupancy_grid->info), &negate,
00172 &occupied_threshold, &free_threshold, map_uuid);
00173 return result && LoadOccupancyGridDataFromPgmFile(
00174 map_name, map_directory, negate, occupied_threshold, free_threshold,
00175 occupancy_grid);
00176 }
00177
00178 bool LoadOccupancyGridDataFromPgmFile(
00179 const std::string& map_name, const std::string& map_directory,
00180 bool negate, double occupied_threshold, double free_threshold,
00181 nav_msgs::OccupancyGrid* occupancy_grid) {
00182 std::string map_directory_with_trailing_slash = map_directory;
00183 AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00184
00185 std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
00186 std::ifstream pgm_file(map_pgm_file_path, std::ios::binary);
00187 if (pgm_file.fail()) {
00188 LOG(ERROR) << "Could no open file " << map_pgm_file_path;
00189 return false;
00190 }
00191
00192
00193 std::string file_type;
00194 getline(pgm_file, file_type);
00195 LOG(INFO) << file_type;
00196 if (file_type.compare("P5") != 0) {
00197 LOG(ERROR) << "Pgm file type error. Type is " << file_type
00198 << " while supported type is P5.";
00199 return false;
00200 }
00201
00202 std::string comment;
00203 getline(pgm_file, comment);
00204 LOG(INFO) << comment;
00205
00206 std::string image_size;
00207 getline(pgm_file, image_size);
00208 std::stringstream size_stream(image_size);
00209 size_stream >> occupancy_grid->info.width >> occupancy_grid->info.height;
00210 LOG(INFO) << "Image size is " << occupancy_grid->info.width << "x" << occupancy_grid->info.height;
00211
00212 std::string max_value_string;
00213 getline(pgm_file, max_value_string);
00214 std::stringstream max_val_stream(max_value_string);
00215 int max_value = 0;
00216 max_val_stream >> max_value;
00217
00218 int pixel_array[occupancy_grid->info.height * occupancy_grid->info.width];
00219 for (size_t i = 0; i < occupancy_grid->info.height * occupancy_grid->info.width; ++i) {
00220 char pixel = pgm_file.get();
00221 pixel_array[i] = static_cast<int>(pixel);
00222 }
00223
00224
00225 occupancy_grid->data.reserve(occupancy_grid->info.height * occupancy_grid->info.width);
00226 for (size_t i = 0; i < occupancy_grid->info.height; ++i) {
00227 for (size_t j = 0; j < occupancy_grid->info.width; ++j) {
00228 int value = pixel_array[j + (occupancy_grid->info.height - i - 1) * occupancy_grid->info.width];
00229 if (negate)
00230 value = max_value - value;
00231 double occupancy = (max_value - value) / static_cast<double>(max_value);
00232 if (occupancy < free_threshold) {
00233 occupancy_grid->data.push_back(0);
00234 } else if (occupancy > occupied_threshold) {
00235 occupancy_grid->data.push_back(100);
00236 } else {
00237 occupancy_grid->data.push_back(-1);
00238 }
00239 }
00240 }
00241 pgm_file.close();
00242 LOG(INFO) << "Map image successfully loaded from " << map_pgm_file_path;
00243 return true;
00244 }
00245
00246 bool LoadOccupancyGridMetadataFromYamlFile(
00247 const std::string& map_name, const std::string& map_directory,
00248 nav_msgs::MapMetaData* map_metadata, int* negate,
00249 double* occupied_threshold, double* free_threshold, std::string* map_uuid) {
00250 std::string map_directory_with_trailing_slash = map_directory;
00251 AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
00252
00253 std::string map_yam_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
00254 std::ifstream yaml_file(map_yam_file_path.c_str());
00255 if (yaml_file.fail()) {
00256 LOG(ERROR) << "Could no open file " << map_yam_file_path;
00257 return false;
00258 }
00259
00260 YAML::Node node = YAML::Load(yaml_file);
00261 try {
00262 map_metadata->resolution = node["resolution"].as<double>();
00263 } catch (YAML::RepresentationException& e) {
00264 LOG(ERROR) << "The map does not contain a resolution tag or it is invalid. " << e.msg;
00265 return false;
00266 }
00267 try {
00268 *negate = node["negate"].as<int>();
00269 } catch (YAML::RepresentationException& e) {
00270 LOG(ERROR) << "The map does not contain a negate tag or it is invalid. " << e.msg;
00271 return false;
00272 }
00273 try {
00274 *occupied_threshold = node["occupied_thresh"].as<double>();
00275 } catch (YAML::RepresentationException& e) {
00276 LOG(ERROR) << "The map does not contain an occupied_thresh tag or it is invalid. " << e.msg;
00277 return false;
00278 }
00279 try {
00280 *free_threshold = node["free_thresh"].as<double>();
00281 } catch (YAML::RepresentationException& e) {
00282 LOG(ERROR) << "The map does not contain a free_thresh tag or it is invalid. " << e.msg;
00283 return false;
00284 }
00285 try {
00286 map_metadata->origin.position.x = node["origin"][0].as<double>();
00287 map_metadata->origin.position.y = node["origin"][1].as<double>();
00288 map_metadata->origin.position.z = 0.0;
00289 tf::Quaternion quaternion;
00290 double yaw = node["origin"][2].as<double>();
00291 quaternion.setRPY(0., 0., yaw);
00292 map_metadata->origin.orientation.x = quaternion.x();
00293 map_metadata->origin.orientation.y = quaternion.y();
00294 map_metadata->origin.orientation.z = quaternion.z();
00295 map_metadata->origin.orientation.w = quaternion.w();
00296 } catch (YAML::RepresentationException& e) {
00297 LOG(ERROR) << "The map does not contain an origin tag or it is invalid. " << e.msg;
00298 return false;
00299 }
00300 try {
00301 *map_uuid = node["uuid"].as<std::string>();
00302 } catch (YAML::RepresentationException& e) {
00303 LOG(WARNING) << "The map does not contain a uuid tag or it is invalid. " << e.msg;
00304 }
00305 yaml_file.close();
00306 LOG(INFO) << "Map yaml file successfully loaded from " << map_yam_file_path;
00307 return true;
00308 }
00309 }