occupancy_grid_file_io.cpp
Go to the documentation of this file.
1 // Copyright 2017 Intermodalics All Rights Reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
15 
16 #include <cmath>
17 #include <fstream>
18 #include <iostream>
19 #include <sys/stat.h>
20 #include <unistd.h>
21 
22 #include <geometry_msgs/Quaternion.h>
24 
25 #include <glog/logging.h>
26 
27 #include <yaml-cpp/yaml.h>
28 
29 namespace {
30 void AddTrailingSlashToDirectoryPathIfNeeded(std::string* directory_path) {
31  if (!directory_path->empty() && directory_path->back() != '/') {
32  (*directory_path) += '/';
33  }
34 }
35 bool DirectoryPathExists(const std::string& path) {
36  struct stat st;
37  return (stat(path.c_str(), &st) == 0 && (st.st_mode & S_IFDIR));
38 }
39 bool MakeDirectoryPath(const std::string& input_path, mode_t mode) {
40  if (input_path.empty()) {
41  // Path is empty, there is nothing to create so we return success.
42  return 0;
43  }
44 
45  size_t previous_slash_pos = 0;
46  size_t current_slash_pos;
47  std::string dir;
48  int make_dir_status = 0;
49 
50  std::string path = input_path;
51  AddTrailingSlashToDirectoryPathIfNeeded(&path);
52 
53  while ((current_slash_pos = path.find_first_of('/', previous_slash_pos)) !=
54  std::string::npos) {
55  dir = path.substr(0, current_slash_pos++);
56  previous_slash_pos = current_slash_pos;
57  if (dir.empty() || dir == ".")
58  continue; // If leading / first time is 0 length.
59 
60  if ((make_dir_status = mkdir(dir.c_str(), mode)) && errno != EEXIST) {
61  return false;
62  }
63  }
64  return true;
65 }
66 } // namespace
67 
68 namespace occupancy_grid_file_io {
70  const std::string& map_name, const std::string& map_uuid,
71  const std::string& map_directory, const nav_msgs::OccupancyGrid& occupancy_grid) {
72  return SaveOccupancyGridDataToPgmFile(map_name, map_directory, occupancy_grid)
73  && SaveOccupancyGridMetadataToYamlFile(map_name, map_uuid, map_directory, occupancy_grid.info);
74 }
75 
77  const std::string& map_name, const std::string& map_directory,
78  const nav_msgs::OccupancyGrid& occupancy_grid) {
79  std::string map_directory_with_trailing_slash = map_directory;
80  AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
81  if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
82  LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
83  if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
84  LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
85  return false;
86  }
87  }
88 
89  std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
90  FILE* pgm_file = fopen(map_pgm_file_path.c_str(), "w");
91  if (!pgm_file) {
92  LOG(ERROR) << "Could no open file " << map_pgm_file_path;
93  return false;
94  }
95 
96  fprintf(pgm_file, "P5\n# CREATOR: TangoRosStreamer %.3f m/pix\n%d %d\n255\n",
97  occupancy_grid.info.resolution,
98  occupancy_grid.info.width, occupancy_grid.info.height);
99  for (size_t i = 0; i < occupancy_grid.info.height; ++i) {
100  for (size_t j = 0; j < occupancy_grid.info.width; ++j) {
101  // Need to invert the ordering of the cells to
102  // produce an image with pixel (0,0) in the top-left corner.
103  int value = occupancy_grid.data[j + (occupancy_grid.info.height - i - 1) * occupancy_grid.info.width];
104  if (value == 0) {
105  fputc(254, pgm_file);
106  } else if (value == +100) {
107  fputc(000, pgm_file);
108  } else {
109  fputc(205, pgm_file);
110  }
111  }
112  }
113  fclose(pgm_file);
114  LOG(INFO) << "Map image successfully saved to " << map_pgm_file_path;
115  return true;
116 }
117 
119  const std::string& map_name, const std::string& map_uuid,
120  const std::string& map_directory, const nav_msgs::MapMetaData& map_metadata) {
121  std::string map_directory_with_trailing_slash = map_directory;
122  AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
123  if (!DirectoryPathExists(map_directory_with_trailing_slash)) {
124  LOG(INFO) << "Directory " << map_directory_with_trailing_slash << " does not exist, creating it now.";
125  if (!MakeDirectoryPath(map_directory_with_trailing_slash, S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH)) {
126  LOG(ERROR) << "Could not create directory: " << map_directory_with_trailing_slash;
127  return false;
128  }
129  }
130 
131  std::string image_name = map_name;
132  if (image_name.empty())
133  image_name = "\"\"";
134  std::string uuid = map_uuid;
135  if (uuid.empty())
136  uuid = "\"\"";
137 
138  std::string map_yaml_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
139  FILE* yaml_file = fopen(map_yaml_file_path.c_str(), "w");
140  if (!yaml_file) {
141  LOG(ERROR) << "Could no open file " << map_yaml_file_path;
142  return false;
143  }
144 
145  tf::Matrix3x3 mat(tf::Quaternion(map_metadata.origin.orientation.x,
146  map_metadata.origin.orientation.y,
147  map_metadata.origin.orientation.z,
148  map_metadata.origin.orientation.w));
149  double yaw, pitch, roll;
150  mat.getEulerYPR(yaw, pitch, roll);
151  if (std::isnan(yaw))
152  yaw = 0.0;
153 
154  fprintf(yaml_file, "image: %s.pgm\nresolution: %f\norigin: [%f, %f, %f]\nnegate: 0\n"
155  "occupied_thresh: 0.65\nfree_thresh: 0.196\nuuid: %s\n\n",
156  map_name.c_str(), map_metadata.resolution, map_metadata.origin.position.x,
157  map_metadata.origin.position.y, yaw, uuid.c_str());
158 
159  fclose(yaml_file);
160  LOG(INFO) << "Map yaml file successfully saved to " << map_yaml_file_path;
161  return true;
162 }
163 
165  const std::string& map_name, const std::string& map_directory,
166  nav_msgs::OccupancyGrid* occupancy_grid, std::string* map_uuid) {
167  int negate;
168  double occupied_threshold;
169  double free_threshold;
171  map_name, map_directory, &(occupancy_grid->info), &negate,
172  &occupied_threshold, &free_threshold, map_uuid);
173  return result && LoadOccupancyGridDataFromPgmFile(
174  map_name, map_directory, negate, occupied_threshold, free_threshold,
175  occupancy_grid);
176 }
177 
179  const std::string& map_name, const std::string& map_directory,
180  bool negate, double occupied_threshold, double free_threshold,
181  nav_msgs::OccupancyGrid* occupancy_grid) {
182  std::string map_directory_with_trailing_slash = map_directory;
183  AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
184 
185  std::string map_pgm_file_path = map_directory_with_trailing_slash + map_name + ".pgm";
186  std::ifstream pgm_file(map_pgm_file_path, std::ios::binary);
187  if (pgm_file.fail()) {
188  LOG(ERROR) << "Could no open file " << map_pgm_file_path;
189  return false;
190  }
191 
192  // First line contains file type.
193  std::string file_type;
194  getline(pgm_file, file_type);
195  LOG(INFO) << file_type;
196  if (file_type.compare("P5") != 0) {
197  LOG(ERROR) << "Pgm file type error. Type is " << file_type
198  << " while supported type is P5.";
199  return false;
200  }
201  // Second line contains comment.
202  std::string comment;
203  getline(pgm_file, comment);
204  LOG(INFO) << comment;
205  // Third line contains size.
206  std::string image_size;
207  getline(pgm_file, image_size);
208  std::stringstream size_stream(image_size);
209  size_stream >> occupancy_grid->info.width >> occupancy_grid->info.height;
210  LOG(INFO) << "Image size is " << occupancy_grid->info.width << "x" << occupancy_grid->info.height;
211  // Fourth line contains max value.
212  std::string max_value_string;
213  getline(pgm_file, max_value_string);
214  std::stringstream max_val_stream(max_value_string);
215  int max_value = 0;
216  max_val_stream >> max_value;
217  // Following lines contain binary data.
218  int pixel_array[occupancy_grid->info.height * occupancy_grid->info.width];
219  for (size_t i = 0; i < occupancy_grid->info.height * occupancy_grid->info.width; ++i) {
220  char pixel = pgm_file.get();
221  pixel_array[i] = static_cast<int>(pixel);
222  }
223  // Need to invert the ordering of the pixels to
224  // produce a map with cell (0,0) in the lower-left corner.
225  occupancy_grid->data.reserve(occupancy_grid->info.height * occupancy_grid->info.width);
226  for (size_t i = 0; i < occupancy_grid->info.height; ++i) {
227  for (size_t j = 0; j < occupancy_grid->info.width; ++j) {
228  int value = pixel_array[j + (occupancy_grid->info.height - i - 1) * occupancy_grid->info.width];
229  if (negate)
230  value = max_value - value;
231  double occupancy = (max_value - value) / static_cast<double>(max_value);
232  if (occupancy < free_threshold) {
233  occupancy_grid->data.push_back(0);
234  } else if (occupancy > occupied_threshold) {
235  occupancy_grid->data.push_back(100);
236  } else {
237  occupancy_grid->data.push_back(-1);
238  }
239  }
240  }
241  pgm_file.close();
242  LOG(INFO) << "Map image successfully loaded from " << map_pgm_file_path;
243  return true;
244 }
245 
247  const std::string& map_name, const std::string& map_directory,
248  nav_msgs::MapMetaData* map_metadata, int* negate,
249  double* occupied_threshold, double* free_threshold, std::string* map_uuid) {
250  std::string map_directory_with_trailing_slash = map_directory;
251  AddTrailingSlashToDirectoryPathIfNeeded(&map_directory_with_trailing_slash);
252 
253  std::string map_yam_file_path = map_directory_with_trailing_slash + map_name + ".yaml";
254  std::ifstream yaml_file(map_yam_file_path.c_str());
255  if (yaml_file.fail()) {
256  LOG(ERROR) << "Could no open file " << map_yam_file_path;
257  return false;
258  }
259 
260  YAML::Node node = YAML::Load(yaml_file);
261  try {
262  map_metadata->resolution = node["resolution"].as<double>();
263  } catch (YAML::RepresentationException& e) {
264  LOG(ERROR) << "The map does not contain a resolution tag or it is invalid. " << e.msg;
265  return false;
266  }
267  try {
268  *negate = node["negate"].as<int>();
269  } catch (YAML::RepresentationException& e) {
270  LOG(ERROR) << "The map does not contain a negate tag or it is invalid. " << e.msg;
271  return false;
272  }
273  try {
274  *occupied_threshold = node["occupied_thresh"].as<double>();
275  } catch (YAML::RepresentationException& e) {
276  LOG(ERROR) << "The map does not contain an occupied_thresh tag or it is invalid. " << e.msg;
277  return false;
278  }
279  try {
280  *free_threshold = node["free_thresh"].as<double>();
281  } catch (YAML::RepresentationException& e) {
282  LOG(ERROR) << "The map does not contain a free_thresh tag or it is invalid. " << e.msg;
283  return false;
284  }
285  try {
286  map_metadata->origin.position.x = node["origin"][0].as<double>();
287  map_metadata->origin.position.y = node["origin"][1].as<double>();
288  map_metadata->origin.position.z = 0.0;
289  tf::Quaternion quaternion;
290  double yaw = node["origin"][2].as<double>();
291  quaternion.setRPY(0., 0., yaw);
292  map_metadata->origin.orientation.x = quaternion.x();
293  map_metadata->origin.orientation.y = quaternion.y();
294  map_metadata->origin.orientation.z = quaternion.z();
295  map_metadata->origin.orientation.w = quaternion.w();
296  } catch (YAML::RepresentationException& e) {
297  LOG(ERROR) << "The map does not contain an origin tag or it is invalid. " << e.msg;
298  return false;
299  }
300  try {
301  *map_uuid = node["uuid"].as<std::string>();
302  } catch (YAML::RepresentationException& e) {
303  LOG(WARNING) << "The map does not contain a uuid tag or it is invalid. " << e.msg;
304  }
305  yaml_file.close();
306  LOG(INFO) << "Map yaml file successfully loaded from " << map_yam_file_path;
307  return true;
308 }
309 } // namespace occupancy_grid_file_io
bool SaveOccupancyGridDataToPgmFile(const std::string &map_name, const std::string &map_directory, const nav_msgs::OccupancyGrid &occupancy_grid)
bool LoadOccupancyGridFromFiles(const std::string &map_name, const std::string &map_directory, nav_msgs::OccupancyGrid *occupancy_grid, std::string *map_uuid)
bool SaveOccupancyGridToFiles(const std::string &map_name, const std::string &map_uuid, const std::string &map_directory, const nav_msgs::OccupancyGrid &occupancy_grid)
void getEulerYPR(tfScalar &yaw, tfScalar &pitch, tfScalar &roll, unsigned int solution_number=1) const
bool LoadOccupancyGridMetadataFromYamlFile(const std::string &map_name, const std::string &map_directory, nav_msgs::MapMetaData *map_metadata, int *negate, double *occupied_threshold, double *free_threshold, std::string *map_uuid)
bool LoadOccupancyGridDataFromPgmFile(const std::string &map_name, const std::string &map_directory, bool negate, double occupied_threshold, double free_threshold, nav_msgs::OccupancyGrid *occupancy_grid)
bool SaveOccupancyGridMetadataToYamlFile(const std::string &map_name, const std::string &map_uuid, const std::string &map_directory, const nav_msgs::MapMetaData &map_metadata)
void setRPY(const tfScalar &roll, const tfScalar &pitch, const tfScalar &yaw)


tango_ros_native
Author(s):
autogenerated on Mon Jun 10 2019 15:37:51