47 #include "boost/algorithm/string.hpp" 
   48 #include "boost/filesystem.hpp" 
   49 #include "boost/filesystem/path.hpp" 
   50 #include "boost/filesystem/operations.hpp" 
   51 #include "boost/lexical_cast.hpp" 
   52 #include "boost/foreach.hpp" 
   55 #define strtok_r strtok_s 
   62         const bool isBigEndian = *
reinterpret_cast<const unsigned char*
>(&one) == 
static_cast<unsigned char>(0);
 
   73         std::vector<string> parsedLine;
 
   74         char delimiters[] = 
" \t,;";
 
   78         strcpy(tmpLine, line);
 
   79         token = strtok_r(tmpLine, delimiters, &brkt);
 
   84                         parsedLine.push_back(
string(token));
 
   85                         token = strtok_r(NULL, delimiters, &brkt);
 
   97         ifstream is(fileName.c_str());
 
   99         unsigned elementCount=0;
 
  100         std::map<string, unsigned> keywordCols;
 
  103         bool firstLine(
true);
 
  104         unsigned lineCount=0;
 
  114                         elementCount = 
header.size();
 
  115                         for(
unsigned int i = 0; i < elementCount; i++)
 
  117                                 keywordCols[
header[i]] = i;
 
  125                         if(parsedLine.size() != elementCount && parsedLine.size() !=0)
 
  127                                 stringstream errorMsg;
 
  128                                 errorMsg << 
"Error at line " << lineCount+1 << 
": expecting " << elementCount << 
" columns but read " << parsedLine.size() << 
" elements.";
 
  129                                 throw runtime_error(errorMsg.str());    
 
  132                         for(
unsigned int i = 0; i < parsedLine.size(); i++)
 
  134                                 for(BOOST_AUTO(it,keywordCols.begin()); it!=keywordCols.end(); it++)
 
  136                                         if(i == (*it).second)
 
  138                                                 data[(*it).first].push_back(parsedLine[i]);     
 
  167         readingFileName(readingFileName),
 
  168         referenceFileName(referenceFileName),
 
  169         configFileName(configFileName),
 
  170         initialTransformation(initialTransformation),
 
  171         groundTruthTransformation(groundTruthTransformation),
 
  203                 #if BOOST_FILESYSTEM_VERSION >= 3 
  204                 dataPath = boost::filesystem::path(fileName).parent_path().string();
 
  206                 dataPath = boost::filesystem::path(fileName).parent_path().file_string();
 
  209         if (configPath.empty())
 
  211                 #if BOOST_FILESYSTEM_VERSION >= 3 
  212                 configPath = boost::filesystem::path(fileName).parent_path().string();
 
  214                 configPath = boost::filesystem::path(fileName).parent_path().file_string();
 
  221         const bool found3dInitialTrans(findTransform(data, 
"iT", 3));
 
  222         bool found2dInitialTrans(findTransform(data, 
"iT", 2));
 
  223         const bool found3dGroundTruthTrans(findTransform(data, 
"gT", 3));
 
  224         bool found2dGroundTruthTrans(findTransform(data, 
"gT", 2));
 
  225         if (found3dInitialTrans)
 
  226                 found2dInitialTrans = 
false;
 
  227         if (found3dGroundTruthTrans)
 
  228                 found2dGroundTruthTrans = 
false;
 
  231         if (found3dInitialTrans && found2dGroundTruthTrans)
 
  232                 throw runtime_error(
"Initial transformation is in 3D but ground-truth is in 2D");
 
  233         if (found2dInitialTrans && found3dGroundTruthTrans)
 
  234                 throw runtime_error(
"Initial transformation is in 2D but ground-truth is in 3D");
 
  235         CsvElements::const_iterator readingIt(data.find(
"reading"));
 
  236         if (readingIt == data.end())
 
  237                 throw runtime_error(
"Error transfering CSV to structure: The header should at least contain \"reading\".");
 
  238         CsvElements::const_iterator referenceIt(data.find(
"reference"));
 
  239         CsvElements::const_iterator configIt(data.find(
"config"));
 
  242         const std::vector<string>& readingFileNames = readingIt->second;
 
  243         const unsigned lineCount = readingFileNames.size();
 
  244         boost::optional<std::vector<string> > referenceFileNames;
 
  245         boost::optional<std::vector<string> > configFileNames;
 
  246         if (referenceIt != data.end())
 
  248                 referenceFileNames = referenceIt->second;
 
  249                 assert (referenceFileNames->size() == lineCount);
 
  251         if (configIt != data.end())
 
  253                 configFileNames = configIt->second;
 
  254                 assert (configFileNames->size() == lineCount);
 
  258         for(
unsigned line=0; line<lineCount; line++)
 
  264                 if (referenceFileNames)
 
  267                         info.
configFileName = localToGlobalFileName(configPath, (*configFileNames)[line]);
 
  270                 if(found3dInitialTrans)
 
  272                 if(found2dInitialTrans)
 
  274                 if(found3dGroundTruthTrans)
 
  276                 if(found2dGroundTruthTrans)
 
  280                 this->push_back(info);
 
  302         if (!boost::filesystem::exists(globalFileName))
 
  304                 const boost::filesystem::path globalFilePath(boost::filesystem::path(parentPath) /  boost::filesystem::path(fileName));
 
  305                 #if BOOST_FILESYSTEM_VERSION >= 3 
  306                 globalFileName = globalFilePath.string();
 
  308                 globalFileName = globalFilePath.file_string();
 
  312         return globalFileName;
 
  320         for(
unsigned i=0; i<dim+1; i++)
 
  322                 for(
unsigned j=0; j<dim+1; j++)
 
  324                         stringstream transName;
 
  325                         transName << prefix << i << j;
 
  326                         found = found && (data.find(transName.str()) != data.end());
 
  337         for(
unsigned i=0; i<dim+1; i++)
 
  339                 for(
unsigned j=0; j<dim+1; j++)
 
  341                         stringstream transName;
 
  342                         transName << prefix << i << j;
 
  343                         CsvElements::const_iterator colIt(data.find(transName.str()));
 
  344                         const T value = boost::lexical_cast<T> (colIt->second[line]);
 
  345                         transformation(i,j) = value;
 
  348         return transformation;
 
  357         boost::filesystem::path fullPath(fileName);
 
  359         ifstream ifs(fileName.c_str());
 
  360         if (!ifs.good() || !boost::filesystem::is_regular_file(fullPath))
 
  361         #if BOOST_FILESYSTEM_VERSION >= 3 
  362                 #if BOOST_VERSION >= 105000 
  363                                 throw runtime_error(
string(
"Cannot open file ") + boost::filesystem::complete(fullPath).generic_string());
 
  365                                 throw runtime_error(
string(
"Cannot open file ") + boost::filesystem3::complete(fullPath).generic_string());
 
  368                 throw runtime_error(
string(
"Cannot open file ") + boost::filesystem::complete(fullPath).native_file_string());
 
  377         const boost::filesystem::path path(fileName);
 
  378         const string& ext(boost::filesystem::extension(path));
 
  379         if (boost::iequals(ext, 
".vtk"))
 
  381         else if (boost::iequals(ext, 
".csv"))
 
  383         else if (boost::iequals(ext, 
".ply"))
 
  385         else if (boost::iequals(ext, 
".pcd"))
 
  388                 throw runtime_error(
"loadAnyFormat(): Unknown extension \"" + ext + 
"\" for file \"" + fileName + 
"\", extension must be either \".vtk\" or \".csv\"");
 
  410         ifstream ifs(fileName.c_str());
 
  419         internalName(internalName),
 
  420         externalName(externalName),
 
  430         bool findLabel = 
false;
 
  431         for(
size_t i=0; i<labels.size(); ++i)
 
  433                 if(internalName == labels[i].text)
 
  444                 labels.push_back(
Label(internalName,1));
 
  451                 labels.push_back(
Label(internalName, dim));
 
  466 template <
typename T>
 
  472         if (label.
text == 
"normals")
 
  487         else if (label.
text == 
"color")
 
  491                         externalName = 
"red";
 
  495                         externalName = 
"green";
 
  499                         externalName = 
"blue";
 
  502                         externalName = 
"alpha";
 
  504         else if (label.
text == 
"eigValues")
 
  506                 externalName = 
"eigValues" + boost::lexical_cast<string>(row);
 
  508         else if (label.
text == 
"eigVectors")
 
  511                 externalName = 
"eigVectors" + boost::lexical_cast<string>(row/3);
 
  513                 int row_mod = row % 3;
 
  516                 else if (row_mod == 1)
 
  518                 else if (row_mod == 2)
 
  521         else if (label.
span  == 1)
 
  523                 externalName = label.
text;
 
  526                 externalName = label.
text + boost::lexical_cast<std::string>(row);
 
  537         vector<GenericInputHeader> csvHeader;
 
  542         unsigned int csvCol = 0;
 
  543         unsigned int csvRow = 0;
 
  545         bool firstLine(
true);
 
  549         is.unsetf(std::ios_base::skipws);
 
  550         unsigned int line_count = std::count(
 
  551                 std::istream_iterator<char>(is),
 
  552                         std::istream_iterator<char>(), 
 
  556         is.seekg(0, ios::beg);
 
  558         char delimiters[] = 
" \t,;";
 
  569                 unsigned int len = strspn(line.c_str(), 
" ,+-.1234567890Ee");
 
  570                 if(len != line.length())
 
  583                         unsigned int dim = 0;
 
  585                         strcpy(tmpLine, line.c_str());
 
  587                         token = strtok_r(tmpLine, delimiters, &brkt);
 
  598                                 token = strtok_r(NULL, delimiters, &brkt);
 
  604                                 if (!(dim == 2 || dim == 3))
 
  606                                         int idX=0, idY=0, idZ=0;
 
  608                                         cout << 
"WARNING: " << dim << 
" columns detected. Not obvious which columns to load for x, y or z." << endl;
 
  609                                         cout << endl << 
"Enter column ID (starting from 0) for x: ";
 
  611                                         cout << 
"Enter column ID (starting from 0) for y: ";
 
  613                                         cout << 
"Enter column ID (starting from 0, -1 if 2D data) for z: ";
 
  617                                         for(
unsigned int i=0; i<dim; i++)
 
  619                                                 std::ostringstream os;
 
  646                         int rowIdFeatures = 0;
 
  647                         int rowIdDescriptors = 0;
 
  652                         for(
size_t i=0; i<externalLabels.size(); i++)
 
  656                                 for(
size_t j=0; j < csvHeader.size(); j++)
 
  660                                                 csvHeader[j].matrixType = supLabel.
type;
 
  662                                                 switch (supLabel.
type)
 
  665                                                                 csvHeader[j].matrixRowId = rowIdFeatures;
 
  670                                                                 csvHeader[j].matrixRowId = rowIdDescriptors;
 
  675                                                                 csvHeader[j].matrixRowId = rowIdTime;
 
  680                                                                 throw runtime_error(
string(
"CSV parse error: encounter a type different from FEATURE, DESCRIPTOR and TIME. Implementation not supported. See the definition of 'enum PMPropTypes'"));
 
  691                         for(
unsigned int i=0; i<csvHeader.size(); i++)
 
  696                                         csvHeader[i].matrixRowId = rowIdDescriptors;
 
  697                                         descLabelGen.
add(csvHeader[i].name); 
 
  710                         const unsigned int nbPoints = line_count;
 
  712                         features = 
Matrix(featDim, nbPoints);
 
  713                         descriptors = 
Matrix(descDim, nbPoints);
 
  721                 strcpy(line_c,line.c_str());
 
  722                 token = strtok_r(line_c, delimiters, &brkt);
 
  730                                 if(csvCol > (csvHeader.size() - 1))
 
  734                                         (boost::format(
"CSV parse error: at line %1%, too many elements to parse compare to the header number of columns (col=%2%).") % csvRow % csvHeader.size()).str());
 
  738                                 const int matrixRow = csvHeader[csvCol].matrixRowId;
 
  739                                 const int matrixCol = csvRow;
 
  741                                 switch (csvHeader[csvCol].matrixType)
 
  744                                                 features(matrixRow, matrixCol) = lexical_cast_scalar_to_string<T>(
string(token));
 
  747                                                 descriptors(matrixRow, matrixCol) = lexical_cast_scalar_to_string<T>(token);
 
  750                                                 times(matrixRow, matrixCol) = lexical_cast_scalar_to_string<std::int64_t>(token);
 
  753                                                 throw runtime_error(
string(
"CSV parse error: encounter a type different from FEATURE, DESCRIPTOR and TIME. Implementation not supported. See the definition of 'enum PMPropTypes'"));
 
  759                                 token = strtok_r(NULL, delimiters, &brkt);
 
  765                         if(csvCol != (csvHeader.size()))
 
  768                                 (boost::format(
"CSV parse error: at line %1%, not enough elements to parse compare to the header number of columns (col=%2%).") % csvRow % csvHeader.size()).str());
 
  781         if (descriptors.rows() > 0)
 
  789                 loadedPoints.
times = times;
 
  796                 loadedPoints.
addFeature(
"pad", Matrix::Ones(1,features.cols()));
 
  811         const boost::filesystem::path path(fileName);
 
  812         const string& ext(boost::filesystem::extension(path));
 
  813         if (boost::iequals(ext, 
".vtk"))
 
  817                 throw runtime_error(
"save(): Binary writing is not supported together with extension \"" + ext + 
"\". Currently binary writing is only supported with \".vtk\".");
 
  819         if (boost::iequals(ext, 
".csv"))
 
  821         else if (boost::iequals(ext, 
".ply"))
 
  823         else if (boost::iequals(ext, 
".pcd"))
 
  826                 throw runtime_error(
"save(): Unknown extension \"" + ext + 
"\" for file \"" + fileName + 
"\", extension must be either \".vtk\", \".ply\", \".pcd\" or \".csv\"");
 
  838         ofstream ofs(fileName.c_str());
 
  840                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
  848         const int pointCount(data.
features.cols());
 
  849         const int dimCount(data.
features.rows());
 
  859         for (
int i = 0; i < dimCount - 1; i++)
 
  863                 if (!((i == (dimCount - 2)) && descDimCount == 0))
 
  871                 for (
size_t s = 0; 
s < lab.
span; 
s++)
 
  874                         if (n != (descDimCount - 1))
 
  883         for (
int p = 0; p < pointCount; ++p)
 
  885                 for (
int i = 0; i < dimCount-1; ++i)
 
  888                         if(!((i == (dimCount - 2)) && descDimCount == 0))
 
  892                 for (
int i = 0; i < descDimCount; i++)
 
  895                         if (i != (descDimCount - 1))
 
  912         ifstream ifs(fileName.c_str(), std::ios::binary);
 
  914                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
  918 void skipBlock(
bool binary, 
int binarySize, std::istream & is, 
bool hasSeparateSizeParameter = 
true){
 
  923                 throw std::runtime_error(
"File violates the VTK format : parameter 'n' is missing after a field name.");
 
  926         if(hasSeparateSizeParameter) {
 
  929                         throw std::runtime_error(
"File violates the VTK format : parameter 'size' is missing after a field name.");
 
  938                 is.seekg(size * binarySize, std::ios_base::cur);
 
  940                 for (
int p = 0; p < n; p++)
 
  951         std::map<std::string, SplitTime> labelledSplitTime;
 
  958         if (line.find(
"# vtk DataFile Version") != 0)
 
  959                 throw runtime_error(
string(
"Wrong magic header, found ") + line);
 
  963         const bool isBinary = (line == 
"BINARY");
 
  964         if (line != 
"ASCII"){
 
  966                         throw runtime_error(
string(
"Wrong file type, expecting ASCII or BINARY, found ") + line);
 
  972         if (line == 
"DATASET POLYDATA")
 
  974         else if (line == 
"DATASET UNSTRUCTURED_GRID")
 
  977                 throw runtime_error(
string(
"Wrong data type, expecting DATASET POLYDATA, found ") + line);
 
  987         while (is >> fieldName)
 
  990                 if(fieldName == 
"POINTS")
 
  996                         if(!(type == 
"float" || type == 
"double"))
 
  997                                         throw runtime_error(
string(
"Field POINTS can only be of type double or float"));
 
  999                         Matrix features(4, pointCount);
 
 1000                         for (
int p = 0; p < pointCount; ++p)
 
 1002                                 readVtkData(type, isBinary, features.template block<3, 1>(0, p), is);
 
 1003                                 features(3, p) = 1.0;
 
 1005                         loadedPoints.
addFeature(
"x", features.row(0));
 
 1006                         loadedPoints.
addFeature(
"y", features.row(1));
 
 1007                         loadedPoints.
addFeature(
"z", features.row(2));
 
 1008                         loadedPoints.
addFeature(
"pad", features.row(3));
 
 1014                 else if(dataType == 
POLYDATA && fieldName == 
"VERTICES")
 
 1019                 else if(dataType == 
POLYDATA && fieldName == 
"LINES")
 
 1024                 else if(dataType == 
POLYDATA && fieldName == 
"POLYGONS")
 
 1029                 else if(dataType == 
POLYDATA && fieldName == 
"TRIANGLE_STRIPS")
 
 1046                 else if(fieldName == 
"POINT_DATA")
 
 1048                         int descriptorCount;
 
 1049                         is >> descriptorCount;
 
 1050                         if(pointCount != descriptorCount)
 
 1051                                 throw runtime_error(
string(
"The size of POINTS is different than POINT_DATA"));
 
 1055                 else if (fieldName == 
"FIELD")
 
 1057                         string fieldDataName;
 
 1059                         is >> fieldDataName >> fieldDataCount;
 
 1061                         for (
int f = 0; 
f < fieldDataCount; 
f++)
 
 1064                                 is >> name >> dim >> numTuples >> type;
 
 1066                                 if(type == 
"vtkIdType") 
 
 1069                                                 is.seekg(dim * numTuples * 4, std::ios_base::cur);
 
 1072                                                 for (
int t = 0; 
t < dim * numTuples; 
t++ )
 
 1078                                 else if(!(type == 
"float" || type == 
"double"))
 
 1079                                                 throw runtime_error(
string(
"Field " + fieldName + 
" is " + type + 
" but can only be of type double or float"));
 
 1082                                 Matrix descriptor(dim, pointCount);
 
 1083                                 readVtkData(type, isBinary, descriptor.transpose(), is);
 
 1087                 else if(fieldName == 
"METADATA") 
 
 1091                         while(!line.empty())
 
 1102                         bool isTimeSec = 
false;
 
 1103                         bool isTimeNsec = 
false;
 
 1106                         if(boost::algorithm::ends_with(name, 
"_splitTime_high32"))
 
 1109                                 boost::algorithm::erase_last(name, 
"_splitTime_high32");
 
 1112                         if(boost::algorithm::ends_with(name, 
"_splitTime_low32"))
 
 1115                                 boost::algorithm::erase_last(name, 
"_splitTime_low32");
 
 1119                         bool skipLookupTable = 
false;
 
 1120                         bool isColorScalars = 
false;
 
 1121                         if(fieldName == 
"SCALARS")
 
 1125                                 skipLookupTable = 
true;
 
 1127                         else if(fieldName == 
"VECTORS")
 
 1132                         else if(fieldName == 
"TENSORS")
 
 1137                         else if(fieldName == 
"NORMALS")
 
 1142                         else if(fieldName == 
"COLOR_SCALARS")
 
 1146                                 isColorScalars = 
true;
 
 1149                                 throw runtime_error(
string(
"Unknown field name " + fieldName + 
", expecting SCALARS, VECTORS, TENSORS, NORMALS or COLOR_SCALARS."));
 
 1156                         if(isTimeSec || isTimeNsec)
 
 1164                                 typename std::map<std::string, SplitTime>::iterator it;
 
 1166                                 it = labelledSplitTime.find(name);
 
 1168                                 if(it == labelledSplitTime.end())
 
 1171                                         t.high32 = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic> (dim, pointCount);
 
 1173                                         labelledSplitTime[name] = 
t;
 
 1179                                         assert(labelledSplitTime[name].isHigh32Found == 
false);
 
 1180                                         readVtkData(type, isBinary, labelledSplitTime[name].high32.transpose(), is);
 
 1181                                         labelledSplitTime[name].isHigh32Found = 
true;
 
 1187                                         assert(labelledSplitTime[name].isLow32Found == 
false);
 
 1188                                         readVtkData(type, isBinary, labelledSplitTime[name].low32.transpose(), is);
 
 1189                                         labelledSplitTime[name].isLow32Found = 
true;
 
 1195                                 Matrix descriptorData(dim, pointCount);
 
 1197                                 if(isColorScalars && isBinary) 
 
 1199                                         std::vector<unsigned char> buffer(dim);
 
 1200                                         for (
int i = 0; i < pointCount; ++i){
 
 1201                                                 is.read(
reinterpret_cast<char *
>(&buffer.front()), dim);
 
 1202                                                 for(
int r=0; r < dim; ++r){
 
 1203                                                         descriptorData(r, i) = buffer[r] / 
static_cast<T
>(255.0);
 
 1209                                         if(!(type == 
"float" || type == 
"double"))
 
 1210                                                 throw runtime_error(
string(
"Field " + fieldName + 
" is " + type + 
" but can only be of type double or float."));
 
 1217                                         readVtkData(type, isBinary, descriptorData.transpose(), is);
 
 1225         typename std::map<std::string, SplitTime>::iterator it;
 
 1226         for(it=labelledSplitTime.begin(); it!=labelledSplitTime.end(); it++)
 
 1229                 if(it->second.isHigh32Found == 
false)
 
 1231                         throw runtime_error(
string(
"Missing time field representing the higher 32 bits. Expecting SCALARS with name " + it->first + 
"_splitTime_high32 in the VTK file."));
 
 1234                 if(it->second.isLow32Found == 
false)
 
 1236                         throw runtime_error(
string(
"Missing time field representing the lower 32 bits. Expecting SCALARS with name " + it->first + 
"_splitTime_low32 in the VTK file."));
 
 1241                 for(
int i=0; i<it->second.high32.cols(); i++)
 
 1244                         timeData(0,i) = (((std::int64_t) it->second.high32(0,i)) << 32) | ((std::int64_t) it->second.low32(0,i));
 
 1247                 loadedPoints.
addTime(it->first, timeData);
 
 1250         return loadedPoints;
 
 1260 template<
typename T>
 
 1266         boost::assign::insert(
param) (
"baseFileName", 
"");
 
 1267         boost::assign::insert(
param) (
"writeBinary", 
toParam(binary));
 
 1268         VTKInspector vtkInspector(
param);
 
 1269         vtkInspector.dumpDataPoints(data, fileName);
 
 1286 template<
typename T>
 
 1289         ifstream ifs(fileName.c_str());
 
 1291                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
 1302 template <
typename T>
 
 1305         class Elements : 
public vector<PLYElement*>{
 
 1308                         for (
typename vector<PLYElement*>::const_iterator it = this->begin(); it != this->end(); it++ )
 
 1337         bool format_defined = 
false;
 
 1338         bool header_processed = 
false;
 
 1343         bool skip_props = 
false; 
 
 1344         unsigned elem_offset = 0; 
 
 1348         if (line.find(
"ply") != 0) {
 
 1349                 throw runtime_error(
string(
"PLY parse error: wrong magic header, found <") + line + 
string(
">"));
 
 1352         while (!header_processed)
 
 1355                         throw runtime_error(
"PLY parse error: reached end of file before end of header definition");
 
 1360                 istringstream stringstream (line);
 
 1363                 stringstream >> keyword;
 
 1366                 if (keyword == 
"comment") {
 
 1371                 if (keyword == 
"format")
 
 1374                                 throw runtime_error(
"PLY parse error: format already defined");
 
 1376                         string format_str, version_str;
 
 1377                         stringstream >> format_str >> version_str;
 
 1379                         if (format_str != 
"ascii" && format_str != 
"binary_little_endian" && format_str != 
"binary_big_endian")
 
 1380                                 throw runtime_error(
string(
"PLY parse error: format <") + format_str + 
string(
"> is not supported"));
 
 1382                         if (format_str == 
"binary_little_endian" || format_str == 
"binary_big_endian")
 
 1383                                 throw runtime_error(
string(
"PLY parse error: binary PLY files are not supported"));
 
 1384                         if (version_str != 
"1.0")
 
 1386                                 throw runtime_error(
string(
"PLY parse error: version <") + version_str + 
string(
"> of ply is not supported"));
 
 1389                         format_defined = 
true;
 
 1392                 else if (keyword == 
"element")
 
 1396                         string elem_name, elem_num_s;
 
 1397                         stringstream >> elem_name >> elem_num_s;
 
 1402                                 elem_num = boost::lexical_cast<unsigned>(elem_num_s);
 
 1404                         catch (boost::bad_lexical_cast& e)
 
 1406                                 throw runtime_error(
string(
"PLY parse error: bad number of elements ") + elem_num_s + 
string(
" for element ") + elem_name);
 
 1413                                 current_element = elem;
 
 1416                                 for (
typename Elements::const_iterator it = elements.begin(); it != elements.end(); it++ )
 
 1418                                         if (**it == *elem) {
 
 1420                                                 throw runtime_error(
string(
"PLY parse error: element: ") + elem_name + 
string( 
"is already defined"));
 
 1423                                 elements.push_back(elem);
 
 1428                                 LOG_WARNING_STREAM(
"PLY parse warning: element " << elem_name << 
" not supported. Skipping.");
 
 1432                         elem_offset += elem_num;
 
 1434                 else if (keyword == 
"property")
 
 1436                         if (current_element == NULL)
 
 1438                                 throw runtime_error(
"PLY parse error: property listed without defining an element");
 
 1444                         string next, prop_type, prop_name;
 
 1445                         stringstream >> next;
 
 1450                                 string prop_idx_type;
 
 1451                                 stringstream >> prop_idx_type >> prop_type >> prop_name;
 
 1455                                 current_element->
properties.push_back(list_prop);
 
 1461                                 stringstream >> prop_name;
 
 1469                 else if (keyword == 
"end_header")
 
 1471                         if (!format_defined)
 
 1473                                 throw runtime_error(
string(
"PLY parse error: format not defined in header"));
 
 1476                         if (elements.size() == 0)
 
 1478                                 throw runtime_error(
string(
"PLY parse error: no elements defined in header"));
 
 1481                         header_processed = 
true;
 
 1491         if(vertex->
name != 
"vertex")
 
 1493                 throw runtime_error(
string(
"PLY parse error: vertex should be the first element defined."));
 
 1499         int rowIdFeatures = 0;
 
 1500         int rowIdDescriptors = 0;
 
 1507         for(
size_t i=0; i<externalLabels.size(); i++)
 
 1517                                 it->pmType = supLabel.
type;
 
 1520                                 switch (supLabel.
type)
 
 1523                                                 it->pmRowID = rowIdFeatures;
 
 1528                                                 it->pmRowID = rowIdDescriptors;
 
 1533                                                 it->pmRowID = rowIdTime;
 
 1537                                                 throw runtime_error(
string(
"PLY Implementation Error: encounter a type different from FEATURE, DESCRIPTOR and TIME. Implementation not supported. See the definition of 'enum PMPropTypes'"));
 
 1553                         it->pmRowID = rowIdDescriptors;
 
 1554                         descLabelGen.
add(it->name); 
 
 1565         const unsigned int nbPoints = vertex->
num;
 
 1575         const int nbValues = nbPoints*nbProp;
 
 1578         for(
int i=0; i<nbValues; i++)
 
 1583                         throw runtime_error(
 
 1584                         (boost::format(
"PLY parse error: expected %1% values (%2% points with %3% properties) but only found %4% values.") % nbValues % nbPoints % nbProp % i).str());
 
 1588                         const int row = vertex->
properties[propID].pmRowID;
 
 1600                                         features(row, col) = value;
 
 1603                                         descriptors(row, col) = value;
 
 1606                                         times(row, col) = value;
 
 1609                                         throw runtime_error(
"Implementation error in loadPLY(). This should not throw.");
 
 1615                         if(propID >= nbProp)
 
 1630         if (descriptors.rows() > 0)
 
 1636         if(times.rows() > 0)
 
 1638                 loadedPoints.
times = times;
 
 1645                 loadedPoints.
addFeature(
"pad", Matrix::Ones(1,features.cols()));
 
 1648         return loadedPoints;
 
 1652 template<
typename T>
 
 1658         ofstream ofs(fileName.c_str());
 
 1660                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
 1662         const int pointCount(data.
features.cols());
 
 1663         const int featCount(data.
features.rows());
 
 1667         if (pointCount == 0)
 
 1673         ofs << 
"ply\n" <<
"format ascii 1.0\n";
 
 1674         ofs << 
"element vertex " << pointCount << 
"\n";
 
 1675         for (
int f=0; 
f <(featCount-1); 
f++)
 
 1683                 for (
size_t s = 0; 
s < lab.
span; 
s++)
 
 1686                         ofs << 
"property float " << 
getColLabel(lab,
s) << 
"\n";
 
 1690         ofs << 
"end_header\n";
 
 1693         for (
int p = 0; p < pointCount; ++p)
 
 1695                 for (
int f = 0; 
f < featCount - 1; ++
f)
 
 1698                         if(!(
f == featCount-2 && descRows == 0))
 
 1705                 for (
int d = 0; 
d < descRows; ++
d)
 
 1707                         if (datawithColor && 
d >= colorStartingRow && 
d < colorEndRow) {
 
 1708                                 ofs << static_cast<unsigned>(data.
descriptors(
d, p) * 255.0);
 
 1727 template<
typename T>
 
 1740                 throw std::runtime_error(
 
 1752 template<
typename T>
 
 1766                 throw std::runtime_error(
 
 1788 template <
typename T>
 
 1791         string lc = elem_name;
 
 1792         boost::algorithm::to_lower(lc);
 
 1804 template <
typename T>
 
 1811 template<
typename T>
 
 1813                 const std::string& elem_name, 
const int elem_num, 
const unsigned offset) {
 
 1822 template<
typename T>
 
 1824         return (type == 
"char" || type == 
"uchar" || type == 
"short" 
 1825                         || type == 
"ushort" || type == 
"int" || type == 
"uint" 
 1826                         || type == 
"float" || type == 
"double");
 
 1830 template <
typename T>
 
 1833         return name == rhs.
name;
 
 1837 template <
typename T>
 
 1840         return name == rhs.
name && type == rhs.
type;
 
 1846 template<
typename T>
 
 1848         ifstream ifs(fileName.c_str());
 
 1850                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
 1863 template<
typename T>
 
 1909                 if (line.substr(0,1) == 
"#" || line == 
"")
 
 1915                 vector<string> tokens;
 
 1916                 boost::split(tokens, line, boost::is_any_of(
"\t\r "), boost::token_compress_on);
 
 1918                 string pcd_version_str;
 
 1919                 if (tokens[0] == 
"VERSION")
 
 1921                         header.version = tokens[1];
 
 1923                         if (tokens[1] != 
"0.7" && tokens[1] != 
".7")
 
 1924                                 throw runtime_error(
"PCD Parse Error: Only PCD Version 0.7 is supported");
 
 1927                 else if (tokens[0] == 
"FIELDS")
 
 1929                         header.properties.resize(tokens.size() - 1);
 
 1931                         for (
size_t i = 1; i < tokens.size(); i++)
 
 1933                                 header.properties[i-1].field = tokens[i];
 
 1938                 else if (tokens[0] == 
"SIZE")
 
 1940                         if((tokens.size() - 1) != 
header.properties.size())
 
 1941                                 throw runtime_error(
"PCD Parse Error: number of elements for SIZE must be the same as FIELDS");
 
 1943                         for (
size_t i = 1; i < tokens.size(); i++)
 
 1945                                 const unsigned int size = boost::lexical_cast<unsigned int >(tokens[i]);
 
 1946                                 header.properties[i-1].size = size;
 
 1951                 else if (tokens[0] == 
"TYPE")
 
 1953                         if((tokens.size() - 1) != 
header.properties.size())
 
 1954                                 throw runtime_error(
"PCD Parse Error: number of elements for TYPE must be the same as FIELDS");
 
 1956                         for (
size_t i = 1; i < tokens.size(); i++)
 
 1958                                 const char type = boost::lexical_cast<char>(tokens[i]);
 
 1959                                 header.properties[i-1].type = type;
 
 1960                                 if (type != 
'I' && type != 
'U' && type != 
'F')
 
 1961                                         throw runtime_error(
"PCD Parse Error: invalid TYPE, it must be 'I', 'U', or 'F'");
 
 1966                 else if (tokens[0] == 
"COUNT")
 
 1969                         if((tokens.size() - 1) != 
header.properties.size())
 
 1970                                 throw runtime_error(
"PCD Parse Error: number of elements for COUNT must be the same as FIELDS");
 
 1972                         for (
size_t i = 1; i < tokens.size(); i++)
 
 1974                                 const unsigned int count = boost::lexical_cast<unsigned int >(tokens[i]);
 
 1975                                 header.properties[i-1].count = count;
 
 1980                 else if (tokens[0] == 
"WIDTH")
 
 1984                                 header.width = boost::lexical_cast<unsigned int >(tokens[1]);
 
 1986                         catch (boost::bad_lexical_cast& e)
 
 1988                                 throw runtime_error(
"PCD Parse Error: invalid WIDTH");
 
 1993                 else if (tokens[0] == 
"HEIGHT")
 
 1997                                 header.height= boost::lexical_cast<unsigned int >(tokens[1]);
 
 1999                         catch (boost::bad_lexical_cast& e)
 
 2001                                 throw runtime_error(
"PCD Parse Error: invalid HEIGHT");
 
 2006                 else if (tokens[0] == 
"VIEWPOINT")
 
 2008                         if((tokens.size() - 1) != 7 )
 
 2009                                 throw runtime_error(
"PCD Parse Error: number of elements for VIEWPOINT must be 7");
 
 2011                         for (
size_t i = 1; i < tokens.size(); i++)
 
 2015                                         header.viewPoint(i-1, 0) = boost::lexical_cast<T>(tokens[i]);
 
 2017                                 catch (boost::bad_lexical_cast& e)
 
 2020                                         ss << 
"PCD Parse Error: invalid value(" << tokens[i] << 
") of VIEWPOINT";
 
 2021                                         throw runtime_error(ss.str());
 
 2027                 else if (tokens[0] == 
"POINTS")
 
 2031                                 header.nbPoints = boost::lexical_cast<unsigned int>(tokens[1]);
 
 2033                         catch (boost::bad_lexical_cast& e)
 
 2036                                 ss << 
"PCD Parse Error: the value in the element POINTS (" << tokens[1] << 
") could not be cast as unsigned int";
 
 2037                                 throw runtime_error(ss.str());
 
 2041                 else if (tokens[0] == 
"DATA")
 
 2043                         header.dataType= tokens[1];
 
 2045                         if (
header.dataType == 
"ascii")
 
 2050                         else if(
header.dataType == 
"binary")
 
 2052                                 throw runtime_error(
"PCD Implementation Error: the option for DATA binary is not implemented yet");
 
 2057                                 ss << 
"PCD Parse Error: the value in the element DATA (" << tokens[1] << 
") must be ascii or binary";
 
 2058                                 throw runtime_error(ss.str());
 
 2066         if (
header.properties.size() == 0)
 
 2067                 throw runtime_error(
"PCD Parse Error: no FIELDS were find in the header");
 
 2072                 throw runtime_error(
"PCD Parse Error: POINTS field does not match WIDTH and HEIGHT fields");
 
 2080         int rowIdFeatures = 0;
 
 2081         int rowIdDescriptors = 0;
 
 2087         for(
size_t i=0; i<externalLabels.size(); i++)
 
 2092                 for(
size_t i=0; i < 
header.properties.size(); i++)
 
 2103                                 switch (supLabel.
type)
 
 2106                                                 header.properties[i].pmRowID = rowIdFeatures;
 
 2112                                                         ss << 
"PCD Parse Error: the field " << prop.
field << 
" must have a count of 1";
 
 2113                                                         throw runtime_error(ss.str());
 
 2117                                                 header.properties[i].pmRowID = rowIdDescriptors;
 
 2119                                                 rowIdDescriptors += prop.
count;
 
 2122                                                 header.properties[i].pmRowID = rowIdTime;
 
 2124                                                 rowIdTime += prop.
count;
 
 2126                                                 throw runtime_error(
string(
"PCD Implementation Error: encounter a type different from FEATURE, DESCRIPTOR and TIME. Implementation not supported. See the definition of 'enum PMPropTypes'"));
 
 2137         for(
size_t i=0; i < 
header.properties.size(); i++)
 
 2143                         header.properties[i].pmRowID = rowIdDescriptors;
 
 2145                         rowIdDescriptors += prop.
count;
 
 2156         const unsigned int totalDim = featDim + descDim + timeDim;
 
 2157         const unsigned int nbPoints = 
header.nbPoints;
 
 2175                 if (line.substr(0,1) == 
"#" || line == 
"")
 
 2181                 vector<string> tokens;
 
 2182                 boost::split(tokens, line, boost::is_any_of(
"\t\r "), boost::token_compress_on);
 
 2185                 if (tokens.size() != totalDim)
 
 2186                         throw runtime_error(
string(
"PCD Parse Error: number of data columns does not match number of fields at line: ") + boost::lexical_cast<string>(lineNum));
 
 2188                 unsigned int fileCol = 0;
 
 2189                 for(
size_t i=0; i<
header.properties.size(); i++)
 
 2191                         const unsigned int count = 
header.properties[i].count;
 
 2192                         const unsigned int row = 
header.properties[i].pmRowID;
 
 2196                         for(
size_t j=0; j<count; j++)
 
 2201                                                 features(row+j, col) = boost::lexical_cast<T>(tokens[fileCol]);
 
 2204                                                 descriptors(row+j, col) = boost::lexical_cast<T>(tokens[fileCol]);
 
 2207                                                 times(row+j, col) = boost::lexical_cast<std::int64_t>(tokens[fileCol]);
 
 2210                                                 throw runtime_error(
"Implementation error in loadPCD(). This should not throw.");
 
 2223         if (col != nbPoints)
 
 2226                 ss << 
"PCD Parse Error: the number of points in the file (" << col << 
") is less than the specified number of points (" << nbPoints << 
")";
 
 2227                 throw runtime_error(ss.str());
 
 2235         if (descriptors.rows() > 0)
 
 2241         if(times.rows() > 0)
 
 2243                 loadedPoints.
times = times;
 
 2250                 loadedPoints.
addFeature(
"pad", Matrix::Ones(1,features.cols()));
 
 2253         return loadedPoints;
 
 2256 template<
typename T>
 
 2259         ofstream ofs(fileName.c_str());
 
 2261                 throw runtime_error(
string(
"Cannot open file ") + fileName);
 
 2263         const int pointCount(data.
features.cols());
 
 2264         const int featCount(data.
features.rows());
 
 2268         if (pointCount == 0)
 
 2274         ofs << 
"# .PCD v.7 - Point Cloud Data file format\n" <<
"VERSION .7\n";
 
 2277         for (
int f=0; 
f < (featCount - 1); 
f++)
 
 2286                 for (
int i = 0; i < descCount; i++)
 
 2294         for (
int i =0; i < featCount - 1 + descCount; i++)
 
 2301         for (
int i =0; i < featCount - 1 + descCount; i++)
 
 2308         for (
int f = 0; 
f < featCount - 1 ; 
f++ )
 
 2314                 for (
int i = 0; i < descCount; i++)
 
 2321         ofs << 
"WIDTH " << pointCount << 
"\n";
 
 2322         ofs << 
"HEIGHT 1\n";
 
 2323         ofs << 
"POINTS " << pointCount << 
"\n";
 
 2324         ofs << 
"DATA ascii\n";
 
 2327         for (
int p = 0; p < pointCount; ++p)
 
 2329                 for (
int f = 0; 
f < featCount - 1; ++
f)
 
 2332                         if(!(
f == featCount-2 && descRows == 0))
 
 2335                 for (
int d = 0; 
d < descRows; ++
d)