288 lines
8.3 KiB
Text
288 lines
8.3 KiB
Text
|
/*
|
||
|
* scan_io_rxp implementation
|
||
|
*
|
||
|
* Copyright (C) Thomas Escher, Kai Lingemann, Andreas Nuechter
|
||
|
*
|
||
|
* Released under the GPL version 3.
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
/**
|
||
|
* @file
|
||
|
* @brief Implementation of reading 3D scans
|
||
|
* @author Kai Lingemann. Institute of Computer Science, University of Osnabrueck, Germany.
|
||
|
* @author Andreas Nuechter. Institute of Computer Science, University of Osnabrueck, Germany.
|
||
|
* @author Thomas Escher
|
||
|
*/
|
||
|
|
||
|
#include "scanio/scan_io_rxp.h"
|
||
|
#include "riegl/scanlib.hpp"
|
||
|
|
||
|
#include <iostream>
|
||
|
using std::cout;
|
||
|
using std::cerr;
|
||
|
using std::endl;
|
||
|
#include <vector>
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
#include <windows.h>
|
||
|
#endif
|
||
|
|
||
|
#include <boost/filesystem/operations.hpp>
|
||
|
#include <boost/filesystem/fstream.hpp>
|
||
|
using namespace boost::filesystem;
|
||
|
|
||
|
#include "slam6d/globals.icc"
|
||
|
|
||
|
using namespace scanlib;
|
||
|
using namespace std;
|
||
|
using namespace std::tr1;
|
||
|
|
||
|
|
||
|
|
||
|
#define DATA_PATH_PREFIX "scan"
|
||
|
#define DATA_PATH_SUFFIX ".rxp"
|
||
|
#define POSE_PATH_PREFIX "scan"
|
||
|
#define POSE_PATH_SUFFIX ".pose"
|
||
|
|
||
|
/*
|
||
|
TODO: this file is still work in progress for change to the new scanserver workflow
|
||
|
this ScanIO has to distinguish a multi scan file and a directory of single scan files and is currently very messy handling these with the importer class
|
||
|
*/
|
||
|
|
||
|
|
||
|
|
||
|
std::list<std::string> ScanIO_rxp::readDirectory(const char* dir_path, unsigned int start, unsigned int end)
|
||
|
{
|
||
|
std::list<std::string> identifiers;
|
||
|
|
||
|
path pose(dir_path);
|
||
|
if(is_regular_file(pose)) {
|
||
|
// TODO: create identifiers for this case
|
||
|
// a) from start to end, requires sanity checks and goodwill of user
|
||
|
// b) iterate through the file and get last index
|
||
|
// c) check last index by other means through the riegl api?
|
||
|
// TEMP: implementing a) without sanity checks :)
|
||
|
for(unsigned int i = start; i < end; ++i) {
|
||
|
identifiers.push_back(to_string(i,3));
|
||
|
}
|
||
|
} else {
|
||
|
for(unsigned int i = start; i <= end; ++i) {
|
||
|
// identifier is /d/d/d (000-999)
|
||
|
std::string identifier(to_string(i,3));
|
||
|
// scan consists of data (.3d) and pose (.pose) files
|
||
|
path data(dir_path);
|
||
|
data /= path(std::string(DATA_PATH_PREFIX) + identifier + DATA_PATH_SUFFIX);
|
||
|
path pose(dir_path);
|
||
|
pose /= path(std::string(POSE_PATH_PREFIX) + identifier + POSE_PATH_SUFFIX);
|
||
|
// stop if part of a scan is missing or end by absence is detected
|
||
|
if(!exists(data) || !exists(pose))
|
||
|
break;
|
||
|
identifiers.push_back(identifier);
|
||
|
}
|
||
|
}
|
||
|
return identifiers;
|
||
|
}
|
||
|
|
||
|
void ScanIO_rxp::readPose(const char* dir_path, const char* identifier, double* pose)
|
||
|
{
|
||
|
unsigned int i;
|
||
|
|
||
|
path pose_path(dir_path);
|
||
|
|
||
|
// if the directory actually marks a (multi scan) file, return zero pose
|
||
|
// TODO: test if pose_path gets constructed correctly, see removal of trailing / in the old code
|
||
|
if(is_regular_file(pose_path.string())) {
|
||
|
for(i = 0; i < 6; ++i) pose[i] = 0.0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
pose_path /= path(std::string(POSE_PATH_PREFIX) + identifier + POSE_PATH_SUFFIX);
|
||
|
if(!exists(pose_path))
|
||
|
throw std::runtime_error(std::string("There is no pose file for [") + identifier + "] in [" + dir_path + "]");
|
||
|
|
||
|
// open pose file
|
||
|
boost::filesystem::ifstream pose_file(pose_path);
|
||
|
|
||
|
// if the file is open, read contents
|
||
|
if(pose_file.good()) {
|
||
|
// read 6 plain doubles
|
||
|
for(i = 0; i < 6; ++i) pose_file >> pose[i];
|
||
|
pose_file.close();
|
||
|
|
||
|
// convert angles from deg to rad
|
||
|
for(i = 3; i < 6; ++i) pose[i] = rad(pose[i]);
|
||
|
} else {
|
||
|
throw std::runtime_error(std::string("Pose file could not be opened for [") + identifier + "] in [" + dir_path + "]");
|
||
|
}
|
||
|
}
|
||
|
|
||
|
bool ScanIO_rxp::supports(IODataType type)
|
||
|
{
|
||
|
return !!(type & (DATA_XYZ | DATA_REFLECTANCE | DATA_AMPLITUDE | DATA_DEVIATION | DATA_TYPE));
|
||
|
}
|
||
|
|
||
|
void ScanIO_rxp::readScan(const char* dir_path, const char* identifier, PointFilter& filter, std::vector<double>* xyz, std::vector<unsigned char>* rgb, std::vector<float>* reflectance, std::vector<float>* temperature, std::vector<float>* amplitude, std::vector<int>* type, std::vector<float>* deviation)
|
||
|
{
|
||
|
|
||
|
path data_path(dir_path);
|
||
|
|
||
|
// distinguish file and directory
|
||
|
if(is_regular_file(data_path)) {
|
||
|
stringstream str(identifier);
|
||
|
int scan_index;
|
||
|
str >> scan_index;
|
||
|
// first clean up if they "directory" has changed
|
||
|
// second case of resetting: rewinding index in case of non-sequential index access
|
||
|
if(old_path != dir_path || (imp != 0 && imp->getCurrentScan() > scan_index)) {
|
||
|
// TODO: I'm assuming here that I can simply do this
|
||
|
if(rc != 0) { rc->close(); }
|
||
|
if(dec != 0) { delete dec; dec = 0; }
|
||
|
if(imp != 0) { delete imp; imp = 0; }
|
||
|
// TODO ^
|
||
|
}
|
||
|
// create directory-persistent decoder
|
||
|
if (!dec) {
|
||
|
// remember path
|
||
|
old_path = dir_path;
|
||
|
|
||
|
// create new connection
|
||
|
rc = basic_rconnection::create(data_path.string());
|
||
|
rc->open();
|
||
|
|
||
|
// decoder splits the binary file into readable chunks
|
||
|
dec = new decoder_rxpmarker(rc);
|
||
|
// importer interprets the chunks
|
||
|
// TODO: this won't really work because filter is gone and xyz too and everything breaks
|
||
|
// probably set new filter and xyz in the importer
|
||
|
imp = new importer(filter, scan_index, xyz, reflectance, amplitude, type, deviation);
|
||
|
}
|
||
|
|
||
|
// set new filter and vectors
|
||
|
imp->set(filter, xyz, reflectance, amplitude, type, deviation);
|
||
|
|
||
|
buffer buf;
|
||
|
|
||
|
// skip the first scans
|
||
|
if(imp->getCurrentScan() < scan_index) {
|
||
|
for(dec->get(buf); !dec->eoi(); dec->get(buf)) {
|
||
|
imp->dispatch(buf.begin(), buf.end());
|
||
|
if(imp->getCurrentScan() >= scan_index) break;
|
||
|
}
|
||
|
}
|
||
|
if(dec->eoi()) return;
|
||
|
int cscan = imp->getCurrentScan();
|
||
|
// iterate over chunks, until the next scan is reached
|
||
|
for(dec->get(buf); !dec->eoi(); dec->get(buf)) {
|
||
|
imp->dispatch(buf.begin(), buf.end());
|
||
|
if(imp->getCurrentScan() != cscan) break;
|
||
|
}
|
||
|
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// error handling
|
||
|
data_path /= path(std::string(DATA_PATH_PREFIX) + identifier + DATA_PATH_SUFFIX);
|
||
|
if(!exists(data_path))
|
||
|
throw std::runtime_error(std::string("There is no scan file for [") + identifier + "] in [" + dir_path + "]");
|
||
|
|
||
|
if(xyz != 0) {
|
||
|
string data_path_str;
|
||
|
data_path_str = "file://" + data_path.string();
|
||
|
rc = basic_rconnection::create(data_path_str);
|
||
|
rc->open();
|
||
|
|
||
|
// decoder splits the binary file into readable chunks
|
||
|
dec = new decoder_rxpmarker(rc);
|
||
|
// importer interprets the chunks
|
||
|
imp = new importer(filter, 0, xyz, reflectance, amplitude, type, deviation);
|
||
|
|
||
|
// iterate over chunks
|
||
|
buffer buf;
|
||
|
for(dec->get(buf); !dec->eoi(); dec->get(buf)) {
|
||
|
imp->dispatch(buf.begin(), buf.end());
|
||
|
}
|
||
|
|
||
|
//done
|
||
|
rc->close();
|
||
|
// TODO: clean up all these pointers, aren't they dangling?
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void importer::on_echo_transformed(echo_type echo)
|
||
|
{
|
||
|
// for multi scan files, ignore those before start
|
||
|
if (currentscan < start) return;
|
||
|
|
||
|
// targets is a member std::vector that contains all
|
||
|
// echoes seen so far, i.e. the current echo is always
|
||
|
// indexed by target_count-1.
|
||
|
target& t(targets[target_count - 1]);
|
||
|
|
||
|
double point[3];
|
||
|
point[0] = t.vertex[1]*-100.0;
|
||
|
point[1] = t.vertex[2]*100.0;
|
||
|
point[2] = t.vertex[0]*100.0;
|
||
|
|
||
|
if(filter->check(point)) {
|
||
|
if(xyz) {
|
||
|
for(unsigned int i = 0; i < 3; ++i) xyz->push_back(point[i]);
|
||
|
}
|
||
|
if(reflectance) reflectance->push_back(t.reflectance);
|
||
|
if(amplitude) amplitude->push_back(t.amplitude);
|
||
|
if(deviation) deviation->push_back(t.deviation);
|
||
|
if(type) {
|
||
|
if(pointcloud::first == echo) type->push_back(0);
|
||
|
else if(pointcloud::interior == echo) type->push_back(1);
|
||
|
else if(pointcloud::last == echo) type->push_back(10);
|
||
|
else if(pointcloud::single == echo) type->push_back(9);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
// target.reflectance
|
||
|
// target.amplitude
|
||
|
// target.deviation
|
||
|
// target.time
|
||
|
// target.vertex point coordinates
|
||
|
*/
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
/**
|
||
|
* class factory for object construction
|
||
|
*
|
||
|
* @return Pointer to new object
|
||
|
*/
|
||
|
#ifdef _MSC_VER
|
||
|
extern "C" __declspec(dllexport) ScanIO* create()
|
||
|
#else
|
||
|
extern "C" ScanIO* create()
|
||
|
#endif
|
||
|
{
|
||
|
return new ScanIO_rxp;
|
||
|
}
|
||
|
|
||
|
|
||
|
/**
|
||
|
* class factory for object construction
|
||
|
*
|
||
|
* @return Pointer to new object
|
||
|
*/
|
||
|
#ifdef _MSC_VER
|
||
|
extern "C" __declspec(dllexport) void destroy(ScanIO *sio)
|
||
|
#else
|
||
|
extern "C" void destroy(ScanIO *sio)
|
||
|
#endif
|
||
|
{
|
||
|
delete sio;
|
||
|
}
|
||
|
|
||
|
#ifdef _MSC_VER
|
||
|
BOOL APIENTRY DllMain(HANDLE hModule, DWORD dwReason, LPVOID lpReserved)
|
||
|
{
|
||
|
return TRUE;
|
||
|
}
|
||
|
#endif
|