42 cout <<
"Reading XML file: " << filename <<
"..." << flush;
53 pugi::xml_document xmldoc;
57 std::string resolved_filename = resolved_path.string();
60 pugi::xml_parse_result result = xmldoc.load_file(resolved_filename.c_str());
64 cout <<
"failed." << endl;
65 cerr <<
"XML file " << filename <<
" parsed with errors, attribute value: [" << xmldoc.child(
"node").attribute(
"attr").value() <<
"]\n";
66 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): Errors were found while parsing XML file. Error description: " + std::string(result.description()));
69 pugi::xml_node helios = xmldoc.child(
"helios");
72 std::cout <<
"failed." << std::endl;
73 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): XML file must have tag '<helios> ... </helios>' bounding all other tags.");
79 size_t total_hits = 0;
81 if (load_grid_only ==
false) {
84 for (pugi::xml_node s = helios.child(
"scan"); s; s = s.next_sibling(
"scan")) {
87 const char *origin_str = s.child_value(
"origin");
89 if (strlen(origin_str) == 0) {
91 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): An origin was not specified for scan #" + std::to_string(scan_count));
97 const char *size_str = s.child_value(
"size");
100 if (strlen(size_str) == 0) {
102 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): A size was not specified for scan #" + std::to_string(scan_count));
106 if (size.
x <= 0 || size.
y <= 0) {
108 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): The scan size must be positive (check scan #" + std::to_string(scan_count) +
").");
112 const char *offset_str = s.child_value(
"translation");
115 if (strlen(offset_str) > 0) {
120 const char *rotation_str = s.child_value(
"rotation");
123 if (strlen(rotation_str) > 0) {
125 rotation = rotation *
M_PI / 180.f;
130 const char *thetaMin_str = s.child_value(
"thetaMin");
133 if (strlen(thetaMin_str) == 0) {
137 thetaMin = atof(thetaMin_str) *
M_PI / 180.f;
145 const char *thetaMax_str = s.child_value(
"thetaMax");
148 if (strlen(thetaMax_str) == 0) {
151 thetaMax = atof(thetaMax_str) *
M_PI / 180.f;
154 if (thetaMax - 1e-5 >
M_PI) {
155 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): thetaMax cannot be greater than 180 degrees.");
159 const char *phiMin_str = s.child_value(
"phiMin");
162 if (strlen(phiMin_str) == 0) {
165 phiMin = atof(phiMin_str) *
M_PI / 180.f;
173 const char *phiMax_str = s.child_value(
"phiMax");
176 if (strlen(phiMax_str) == 0) {
179 phiMax = atof(phiMax_str) *
M_PI / 180.f;
182 if (phiMax - 1e-5 > 4.f *
M_PI) {
183 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): phiMax cannot be greater than 720 degrees.");
187 const char *exitDiameter_str_uc = s.child_value(
"exitDiameter");
188 const char *exitDiameter_str_lc = s.child_value(
"exitdiameter");
191 if (strlen(exitDiameter_str_uc) == 0 && strlen(exitDiameter_str_lc) == 0) {
193 }
else if (strlen(exitDiameter_str_uc) > 0) {
194 exitDiameter = fmax(0, atof(exitDiameter_str_uc));
196 exitDiameter = fmax(0, atof(exitDiameter_str_lc));
200 const char *beamDivergence_str_uc = s.child_value(
"beamDivergence");
201 const char *beamDivergence_str_lc = s.child_value(
"beamdivergence");
203 float beamDivergence;
204 if (strlen(beamDivergence_str_uc) == 0 && strlen(beamDivergence_str_lc) == 0) {
206 }
else if (strlen(beamDivergence_str_uc) > 0) {
207 beamDivergence = fmax(0, atof(beamDivergence_str_uc));
209 beamDivergence = fmax(0, atof(beamDivergence_str_lc));
213 const char *dFilter_str = s.child_value(
"distanceFilter");
216 if (strlen(dFilter_str) > 0) {
222 const char *data_format = s.child_value(
"ASCII_format");
224 std::vector<std::string> column_format;
225 if (strlen(data_format) != 0) {
229 std::istringstream stream(data_format);
230 while (stream >> tmp) {
231 column_format.push_back(tmp);
236 ScanMetadata scan(origin, size.
x, thetaMin, thetaMax, size.
y, phiMin, phiMax, exitDiameter, beamDivergence, column_format);
243 std::string data_filename =
deblank(s.child_value(
"filename"));
245 if (!data_filename.empty()) {
248 strcpy(str,
"input/");
249 strcat(str, data_filename.c_str());
254 strcpy(str, data_filename.c_str());
259 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): Data file `" + std::string(str) +
"' given for scan #" + std::to_string(scan_count) +
" does not exist.");
287 for (pugi::xml_node s = helios.child(
"grid"); s; s = s.next_sibling(
"grid")) {
290 const char *center_str = s.child_value(
"center");
292 if (strlen(center_str) == 0) {
294 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): A center was not specified for grid #" + std::to_string(cell_count));
300 const char *gsize_str = s.child_value(
"size");
302 if (strlen(gsize_str) == 0) {
304 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): A size was not specified for grid cell #" + std::to_string(cell_count));
309 if (gsize.
x <= 0 || gsize.
y <= 0 || gsize.
z <= 0) {
316 const char *grot_str = s.child_value(
"rotation");
318 if (strlen(grot_str) == 0) {
321 rotation = atof(grot_str);
327 const char *Nx_str = s.child_value(
"Nx");
329 if (strlen(Nx_str) == 0) {
336 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): The number of grid cells must be positive.");
339 const char *Ny_str = s.child_value(
"Ny");
341 if (strlen(Ny_str) == 0) {
348 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): The number of grid cells must be positive.");
351 const char *Nz_str = s.child_value(
"Nz");
353 if (strlen(Nz_str) == 0) {
360 helios_runtime_error(
"ERROR (LiDARcloud::loadXML): The number of grid cells must be positive.");
367 vec3 gsubsize =
make_vec3(
float(gsize.
x) /
float(Nx),
float(gsize.
y) /
float(Ny),
float(gsize.
z) /
float(Nz));
371 for (
int k = 0; k < Nz; k++) {
372 z = -0.5f * float(gsize.
z) + (float(k) + 0.5f) *
float(gsubsize.
z);
373 for (
int j = 0; j < Ny; j++) {
374 y = -0.5f * float(gsize.
y) + (float(j) + 0.5f) *
float(gsubsize.
y);
375 for (
int i = 0; i < Nx; i++) {
376 x = -0.5f * float(gsize.
x) + (float(i) + 0.5f) *
float(gsubsize.
x);
383 cout <<
"Adding grid cell #" << count <<
" with center " << subcenter_rot.
x + center.
x <<
"," << subcenter_rot.
y + center.
y <<
"," << subcenter.
z + center.
z <<
" and size " << gsubsize.
x <<
" x " << gsubsize.
y <<
" x "
384 << gsubsize.
z << endl;
387 addGridCell(subcenter + center, center, gsubsize, gsize, rotation *
M_PI / 180.f,
make_int3(i, j, k),
make_int3(Nx, Ny, Nz));
397 cout <<
"done." << endl;
399 cout <<
"Successfully read " <<
getScanCount() <<
" scan(s), which contain " << total_hits <<
" total hit points." << endl;
407 std::string resolved_filename = resolved_path.string();
409 ifstream datafile(resolved_filename);
411 if (!datafile.is_open()) {
412 helios_runtime_error(
"ERROR (LiDARcloud::loadASCIIFile): ASCII data file '" + ASCII_data_file +
"' does not exist.");
416 helios_runtime_error(
"ERROR (LiDARcloud::loadASCIIFile): Scan #" + std::to_string(scanID) +
" does not exist.");
421 float temp_zenith, temp_azimuth;
423 float temp_row, temp_column;
425 std::map<std::string, double> data;
427 vector<unsigned int> row, column;
428 std::size_t hit_count = 0;
429 while (datafile.good()) {
431 temp_xyz =
make_vec3(-9999, -9999, -9999);
436 temp_azimuth = -9999;
440 datafile >> temp_row;
442 datafile >> temp_column;
444 datafile >> temp_zenith;
445 temp_zenith =
deg2rad(temp_zenith);
447 datafile >> temp_azimuth;
448 temp_azimuth =
deg2rad(temp_azimuth);
449 }
else if (scan_data.
columnFormat.at(i) ==
"zenith_rad") {
450 datafile >> temp_zenith;
451 }
else if (scan_data.
columnFormat.at(i) ==
"azimuth_rad") {
452 datafile >> temp_azimuth;
454 datafile >> temp_xyz.
x;
456 datafile >> temp_xyz.
y;
458 datafile >> temp_xyz.
z;
460 datafile >> temp_rgb.
r;
462 datafile >> temp_rgb.
g;
464 datafile >> temp_rgb.
b;
466 datafile >> temp_rgb.
r;
469 datafile >> temp_rgb.
g;
472 datafile >> temp_rgb.
b;
475 datafile >> temp_data;
480 if (!datafile.good()) {
481 if (hit_count == 0) {
482 std::cerr <<
"WARNING: Something is likely wrong with the data file " << ASCII_data_file <<
". Check that the format is consistent with that specified in the XML metadata file." << std::endl;
490 if (temp_xyz.
x == -9999) {
491 helios_runtime_error(
"ERROR (LiDARcloud::loadASCIIFile): x-coordinate not specified for hit point #" + std::to_string(hit_count) +
" of scan #" + std::to_string(scanID));
492 }
else if (temp_xyz.
y == -9999) {
493 helios_runtime_error(
"ERROR (LiDARcloud::loadASCIIFile): y-coordinate not specified for hit point #" + std::to_string(hit_count) +
" of scan #" + std::to_string(scanID));
494 }
else if (temp_xyz.
z == -9999) {
495 helios_runtime_error(
"ERROR (LiDARcloud::loadASCIIFile): z-coordinate not specified for hit point #" + std::to_string(hit_count) +
" of scan #" + std::to_string(scanID));
505 addHitPoint(scanID, temp_xyz, temp_direction, temp_rgb, data);
841 ensureOutputDirectoryExists(filename);
844 std::cerr <<
"ERROR (LiDARcloud::exportPointCloud): Cannot export scan " << scanID <<
" because this scan does not exist." << std::endl;
852 if (!file.is_open()) {
853 helios_runtime_error(
"ERROR (LiDARcloud::exportPointCloud): Could not open file '" + std::string(filename) +
"' for writing.");
856 std::vector<std::string> hit_data;
858 std::map<std::string, double> data = hits.at(r).data;
859 for (std::map<std::string, double>::iterator iter = data.begin(); iter != data.end(); ++iter) {
860 std::vector<std::string>::iterator it = find(hit_data.begin(), hit_data.end(), iter->first);
861 if (it == hit_data.end()) {
862 hit_data.push_back(iter->first);
869 if (ASCII_format.size() == 0) {
870 ASCII_format.push_back(
"x");
871 ASCII_format.push_back(
"y");
872 ASCII_format.push_back(
"z");
884 for (
int c = 0; c < ASCII_format.size(); c++) {
886 if (ASCII_format.at(c).compare(
"x") == 0) {
888 }
else if (ASCII_format.at(c).compare(
"y") == 0) {
890 }
else if (ASCII_format.at(c).compare(
"z") == 0) {
892 }
else if (ASCII_format.at(c).compare(
"r") == 0) {
894 }
else if (ASCII_format.at(c).compare(
"g") == 0) {
896 }
else if (ASCII_format.at(c).compare(
"b") == 0) {
898 }
else if (ASCII_format.at(c).compare(
"r255") == 0) {
899 file << round(color.
r * 255);
900 }
else if (ASCII_format.at(c).compare(
"g255") == 0) {
901 file << round(color.
g * 255);
902 }
else if (ASCII_format.at(c).compare(
"b255") == 0) {
903 file << round(color.
b * 255);
904 }
else if (ASCII_format.at(c).compare(
"zenith") == 0) {
906 }
else if (ASCII_format.at(c).compare(
"azimuth") == 0) {
908 }
else if (hits.at(r).data.find(ASCII_format.at(c)) != hits.at(r).data.end()) {
909 file <<
getHitData(r, ASCII_format.at(c).c_str());
914 if (c < ASCII_format.size() - 1) {