00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #include "PointMatcher.h"
00037 #include "PointMatcherPrivate.h"
00038 #include <iostream>
00039
00040 using namespace std;
00041
00043 template<typename T>
00044 PointMatcher<T>::DataPoints::Label::Label(const std::string& text, const size_t span):
00045 text(text),
00046 span(span)
00047 {}
00048
00050 template<typename T>
00051 PointMatcher<T>::DataPoints::InvalidField::InvalidField(const std::string& reason):
00052 runtime_error(reason)
00053 {}
00054
00056 template<typename T>
00057 bool PointMatcher<T>::DataPoints::Label::operator ==(const Label& that) const
00058 {
00059 return (this->text == that.text) && (this->span == that.span);
00060 }
00061
00063 template<typename T>
00064 PointMatcher<T>::DataPoints::Labels::Labels()
00065 {}
00066
00068 template<typename T>
00069 PointMatcher<T>::DataPoints::Labels::Labels(const Label& label):
00070 std::vector<Label>(1, label)
00071 {}
00072
00074 template<typename T>
00075 bool PointMatcher<T>::DataPoints::Labels::contains(const std::string& text) const
00076 {
00077 for (const_iterator it(this->begin()); it != this->end(); ++it)
00078 {
00079 if (it->text == text)
00080 return true;
00081 }
00082 return false;
00083 }
00084
00086 template<typename T>
00087 size_t PointMatcher<T>::DataPoints::Labels::totalDim() const
00088 {
00089 size_t dim(0);
00090 for (const_iterator it(this->begin()); it != this->end(); ++it)
00091 dim += it->span;
00092 return dim;
00093 }
00094
00096 template<typename T>
00097 PointMatcher<T>::DataPoints::DataPoints()
00098 {}
00099
00101 template<typename T>
00102 PointMatcher<T>::DataPoints::DataPoints(const Labels& featureLabels, const Labels& descriptorLabels, const size_t pointCount):
00103 featureLabels(featureLabels),
00104 descriptorLabels(descriptorLabels)
00105 {
00106 features.resize(featureLabels.totalDim(), pointCount);
00107 if(descriptorLabels.totalDim())
00108 descriptors.resize(descriptorLabels.totalDim(), pointCount);
00109 }
00110
00112 template<typename T>
00113 PointMatcher<T>::DataPoints::DataPoints(const Matrix& features, const Labels& featureLabels):
00114 features(features),
00115 featureLabels(featureLabels)
00116 {}
00117
00119 template<typename T>
00120 PointMatcher<T>::DataPoints::DataPoints(const Matrix& features, const Labels& featureLabels, const Matrix& descriptors, const Labels& descriptorLabels):
00121 features(features),
00122 featureLabels(featureLabels),
00123 descriptors(descriptors),
00124 descriptorLabels(descriptorLabels)
00125 {}
00126
00128 template<typename T>
00129 bool PointMatcher<T>::DataPoints::operator ==(const DataPoints& that) const
00130 {
00131 return
00132 (features == that.features) &&
00133 (featureLabels == that.featureLabels) &&
00134 (descriptors == that.descriptors) &&
00135 (featureLabels == that.featureLabels);
00136 }
00137
00139 template<typename T>
00140 void PointMatcher<T>::DataPoints::concatenate(const DataPoints& dp)
00141 {
00142 const int nbPoints1 = this->features.cols();
00143 const int nbPoints2 = dp.features.cols();
00144 const int nbPointsTotal = nbPoints1 + nbPoints2;
00145
00146 const int dimFeat = this->features.rows();
00147 if(dimFeat != dp.features.rows())
00148 {
00149 stringstream errorMsg;
00150 errorMsg << "Cannot concatenate DataPoints because the dimension of the features are not the same. Actual dimension: " << dimFeat << " New dimension: " << dp.features.rows();
00151 throw InvalidField(errorMsg.str());
00152 }
00153
00154
00155 this->features.conservativeResize(Eigen::NoChange, nbPointsTotal);
00156 this->features.rightCols(nbPoints2) = dp.features;
00157
00158
00159 if (this->descriptorLabels == dp.descriptorLabels)
00160 {
00161 if (this->descriptorLabels.size() > 0)
00162 {
00163
00164 this->descriptors.conservativeResize(Eigen::NoChange, nbPointsTotal);
00165 this->descriptors.rightCols(nbPoints2) = dp.descriptors;
00166 }
00167 }
00168 else
00169 {
00170
00171
00172
00173 Labels newDescLabels;
00174 for(BOOST_AUTO(it, this->descriptorLabels.begin()); it != this->descriptorLabels.end(); ++it)
00175 {
00176 for(BOOST_AUTO(jt, dp.descriptorLabels.begin()); jt != dp.descriptorLabels.end(); ++jt)
00177 {
00178 if (it->text == jt->text)
00179 {
00180 if (it->span != jt->span)
00181 throw InvalidField(
00182 (boost::format("The field %1% has dimension %2% in this, different than dimension %3% in that") % it->text % it->span % jt->span).str()
00183 );
00184 newDescLabels.push_back(*it);
00185 break;
00186 }
00187 }
00188 }
00189
00190
00191 if (newDescLabels.size() > 0)
00192 {
00193 Matrix newDescriptors;
00194 Labels filledLabels;
00195 this->allocateFields(newDescLabels, filledLabels, newDescriptors);
00196 assert(newDescLabels == filledLabels);
00197
00198
00199 unsigned row(0);
00200 for(BOOST_AUTO(it, newDescLabels.begin()); it != newDescLabels.end(); ++it)
00201 {
00202 View view(newDescriptors.block(row, 0, it->span, newDescriptors.cols()));
00203 view.leftCols(nbPoints1) = this->getDescriptorViewByName(it->text);
00204 view.rightCols(nbPoints2) = dp.getDescriptorViewByName(it->text);
00205 row += it->span;
00206 }
00207
00208
00209 this->descriptors.swap(newDescriptors);
00210 this->descriptorLabels = newDescLabels;
00211 }
00212 else
00213 {
00214 this->descriptors = Matrix();
00215 this->descriptorLabels = Labels();
00216 }
00217 }
00218 assertDescriptorConsistency();
00219 }
00220
00222 template<typename T>
00223 void PointMatcher<T>::DataPoints::conservativeResize(Index pointCount)
00224 {
00225 features.conservativeResize(Eigen::NoChange, pointCount);
00226 if (descriptors.cols() > 0)
00227 descriptors.conservativeResize(Eigen::NoChange, pointCount);
00228 }
00229
00231 template<typename T>
00232 typename PointMatcher<T>::DataPoints PointMatcher<T>::DataPoints::createSimilarEmpty() const
00233 {
00234 const int nbPoints(features.cols());
00235 DataPoints output(
00236 Matrix(features.rows(), nbPoints),
00237 featureLabels
00238 );
00239 if (descriptors.cols() > 0)
00240 {
00241 assert(descriptors.cols() == nbPoints);
00242 output.descriptors = Matrix(descriptors.rows(), nbPoints);
00243 output.descriptorLabels = descriptorLabels;
00244 }
00245 else
00246 {
00247 assert(descriptors.rows() == 0);
00248 }
00249 return output;
00250 }
00251
00253 template<typename T>
00254 typename PointMatcher<T>::DataPoints PointMatcher<T>::DataPoints::createSimilarEmpty(Index pointCount) const
00255 {
00256 DataPoints output(
00257 Matrix(features.rows(), pointCount),
00258 featureLabels
00259 );
00260 if (descriptors.cols() > 0)
00261 {
00262 output.descriptors = Matrix(descriptors.rows(), pointCount);
00263 output.descriptorLabels = descriptorLabels;
00264 }
00265 else
00266 {
00267 assert(descriptors.rows() == 0);
00268 }
00269 return output;
00270 }
00271
00273 template<typename T>
00274 void PointMatcher<T>::DataPoints::setColFrom(Index thisCol, const DataPoints& that, Index thatCol)
00275 {
00276 features.col(thisCol) = that.features.col(thatCol);
00277 if (descriptors.cols() > 0)
00278 descriptors.col(thisCol) = that.descriptors.col(thatCol);
00279 }
00280
00281
00283 template<typename T>
00284 void PointMatcher<T>::DataPoints::allocateFeature(const std::string& name, const unsigned dim)
00285 {
00286 allocateField(name, dim, featureLabels, features);
00287 }
00288
00290 template<typename T>
00291 void PointMatcher<T>::DataPoints::allocateFeatures(const Labels& newLabels)
00292 {
00293 allocateFields(newLabels, featureLabels, features);
00294 }
00295
00297 template<typename T>
00298 void PointMatcher<T>::DataPoints::addFeature(const std::string& name, const Matrix& newFeature)
00299 {
00300 addField(name, newFeature, featureLabels, features);
00301 }
00302
00304 template<typename T>
00305 typename PointMatcher<T>::Matrix PointMatcher<T>::DataPoints::getFeatureCopyByName(const std::string& name) const
00306 {
00307 return Matrix(getFeatureViewByName(name));
00308 }
00309
00311 template<typename T>
00312 const typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getFeatureViewByName(const std::string& name) const
00313 {
00314 return getConstViewByName(name, featureLabels, features);
00315 }
00316
00318 template<typename T>
00319 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getFeatureViewByName(const std::string& name)
00320 {
00321 return getViewByName(name, featureLabels, features);
00322 }
00323
00325 template<typename T>
00326 const typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getFeatureRowViewByName(const std::string& name, const unsigned row) const
00327 {
00328 return getConstViewByName(name, featureLabels, features, int(row));
00329 }
00330
00332 template<typename T>
00333 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getFeatureRowViewByName(const std::string& name, const unsigned row)
00334 {
00335 return getViewByName(name, featureLabels, features, int(row));
00336 }
00337
00339 template<typename T>
00340 bool PointMatcher<T>::DataPoints::featureExists(const std::string& name) const
00341 {
00342 return fieldExists(name, 0, featureLabels);
00343 }
00344
00346 template<typename T>
00347 bool PointMatcher<T>::DataPoints::featureExists(const std::string& name, const unsigned dim) const
00348 {
00349 return fieldExists(name, dim, featureLabels);
00350 }
00351
00353 template<typename T>
00354 unsigned PointMatcher<T>::DataPoints::getFeatureDimension(const std::string& name) const
00355 {
00356 return getFieldDimension(name, featureLabels);
00357 }
00358
00360 template<typename T>
00361 unsigned PointMatcher<T>::DataPoints::getFeatureStartingRow(const std::string& name) const
00362 {
00363 return getFieldStartingRow(name, featureLabels);
00364 }
00365
00367 template<typename T>
00368 void PointMatcher<T>::DataPoints::allocateDescriptor(const std::string& name, const unsigned dim)
00369 {
00370 allocateField(name, dim, descriptorLabels, descriptors);
00371 }
00372
00374 template<typename T>
00375 void PointMatcher<T>::DataPoints::allocateDescriptors(const Labels& newLabels)
00376 {
00377 allocateFields(newLabels, descriptorLabels, descriptors);
00378 }
00379
00381 template<typename T>
00382 void PointMatcher<T>::DataPoints::addDescriptor(const std::string& name, const Matrix& newDescriptor)
00383 {
00384 addField(name, newDescriptor, descriptorLabels, descriptors);
00385 }
00386
00388 template<typename T>
00389 typename PointMatcher<T>::Matrix PointMatcher<T>::DataPoints::getDescriptorCopyByName(const std::string& name) const
00390 {
00391 return Matrix(getDescriptorViewByName(name));
00392 }
00393
00395 template<typename T>
00396 const typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getDescriptorViewByName(const std::string& name) const
00397 {
00398 return getConstViewByName(name, descriptorLabels, descriptors);
00399 }
00400
00402 template<typename T>
00403 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getDescriptorViewByName(const std::string& name)
00404 {
00405 return getViewByName(name, descriptorLabels, descriptors);
00406 }
00407
00409 template<typename T>
00410 const typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getDescriptorRowViewByName(const std::string& name, const unsigned row) const
00411 {
00412 return getConstViewByName(name, descriptorLabels, descriptors, int(row));
00413 }
00414
00416 template<typename T>
00417 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getDescriptorRowViewByName(const std::string& name, const unsigned row)
00418 {
00419 return getViewByName(name, descriptorLabels, descriptors, int(row));
00420 }
00421
00423 template<typename T>
00424 bool PointMatcher<T>::DataPoints::descriptorExists(const std::string& name) const
00425 {
00426 return fieldExists(name, 0, descriptorLabels);
00427 }
00428
00430 template<typename T>
00431 bool PointMatcher<T>::DataPoints::descriptorExists(const std::string& name, const unsigned dim) const
00432 {
00433 return fieldExists(name, dim, descriptorLabels);
00434 }
00435
00437 template<typename T>
00438 unsigned PointMatcher<T>::DataPoints::getDescriptorDimension(const std::string& name) const
00439 {
00440 return getFieldDimension(name, descriptorLabels);
00441 }
00442
00444 template<typename T>
00445 unsigned PointMatcher<T>::DataPoints::getDescriptorStartingRow(const std::string& name) const
00446 {
00447 return getFieldStartingRow(name, descriptorLabels);
00448 }
00449
00451 template<typename T>
00452 void PointMatcher<T>::DataPoints::assertDescriptorConsistency() const
00453 {
00454 if (descriptors.rows() == 0)
00455 {
00456 if (descriptors.cols() != 0)
00457 throw std::runtime_error(
00458 (boost::format("Point cloud has degenerate descriptor dimensions of rows=0, cols=%1%") % descriptors.cols()).str()
00459 );
00460 if (descriptorLabels.size() > 0)
00461 throw std::runtime_error(
00462 (boost::format("Point cloud has no descriptor data but %1% descriptor labels") % descriptorLabels.size()).str()
00463 );
00464 }
00465 else
00466 {
00467 if (descriptors.cols() != features.cols())
00468 throw std::runtime_error(
00469 (boost::format("Point cloud has %1% points in features but %2% points in descriptors") % features.cols() % descriptors.cols()).str()
00470 );
00471 int descDim(0);
00472 for (BOOST_AUTO(it, descriptorLabels.begin()); it != descriptorLabels.end(); ++it)
00473 descDim += it->span;
00474 if (descriptors.rows() != descDim)
00475 throw std::runtime_error(
00476 (boost::format("Descriptor labels return %1% total dimensions but there are %2% in the descriptors matrix") % descDim % descriptors.rows()).str()
00477 );
00478 }
00479 }
00480
00482 template<typename T>
00483 void PointMatcher<T>::DataPoints::allocateField(const std::string& name, const unsigned dim, Labels& labels, Matrix& data) const
00484 {
00485 if (fieldExists(name, 0, labels))
00486 {
00487 const unsigned descDim(getFieldDimension(name, labels));
00488 if (descDim != dim)
00489 {
00490 throw InvalidField(
00491 (boost::format("The existing field %1% has dimension %2%, different than requested dimension %3%") % name % descDim % dim).str()
00492 );
00493 }
00494 }
00495 else
00496 {
00497 const int oldDim(data.rows());
00498 const int totalDim(oldDim + dim);
00499 const int pointCount(features.cols());
00500 data.conservativeResize(totalDim, pointCount);
00501 labels.push_back(Label(name, dim));
00502 }
00503 }
00504
00506 template<typename T>
00507 void PointMatcher<T>::DataPoints::allocateFields(const Labels& newLabels, Labels& labels, Matrix& data) const
00508 {
00509 typedef vector<bool> BoolVector;
00510 BoolVector present(newLabels.size(), false);
00511
00512
00513 size_t additionalDim(0);
00514 for (size_t i = 0; i < newLabels.size(); ++i)
00515 {
00516 const string& newName(newLabels[i].text);
00517 const size_t newSpan(newLabels[i].span);
00518 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00519 {
00520 if (it->text == newName)
00521 {
00522 if (it->span != newSpan)
00523 throw InvalidField(
00524 (boost::format("The existing field %1% has dimension %2%, different than requested dimension %3%") % newName % it->span % newSpan).str()
00525 );
00526 present[i] = true;
00527 break;
00528 }
00529 }
00530 if (!present[i])
00531 additionalDim += newSpan;
00532 }
00533
00534
00535 const int oldDim(data.rows());
00536 const int totalDim(oldDim + additionalDim);
00537 const int pointCount(features.cols());
00538 data.conservativeResize(totalDim, pointCount);
00539 for (size_t i = 0; i < newLabels.size(); ++i)
00540 {
00541 if (!present[i])
00542 labels.push_back(newLabels[i]);
00543 }
00544 }
00545
00547 template<typename T>
00548 void PointMatcher<T>::DataPoints::addField(const std::string& name, const Matrix& newField, Labels& labels, Matrix& data) const
00549 {
00550 const int newFieldDim = newField.rows();
00551 const int newPointCount = newField.cols();
00552 const int pointCount = features.cols();
00553
00554 if (newField.rows() == 0)
00555 return;
00556
00557
00558 if (fieldExists(name, 0, labels))
00559 {
00560 const int fieldDim = getFieldDimension(name, labels);
00561
00562 if(fieldDim == newFieldDim)
00563 {
00564
00565 if(pointCount == newPointCount)
00566 {
00567 const int row = getFieldStartingRow(name, labels);
00568 data.block(row, 0, fieldDim, pointCount) = newField;
00569 }
00570 else
00571 {
00572 stringstream errorMsg;
00573 errorMsg << "The field " << name << " cannot be added because the number of points is not the same. Old point count: " << pointCount << "new: " << newPointCount;
00574 throw InvalidField(errorMsg.str());
00575 }
00576 }
00577 else
00578 {
00579 stringstream errorMsg;
00580 errorMsg << "The field " << name << " already exists but could not be added because the dimension is not the same. Old dim: " << fieldDim << " new: " << newFieldDim;
00581 throw InvalidField(errorMsg.str());
00582 }
00583 }
00584 else
00585 {
00586 if(pointCount == newPointCount || pointCount == 0)
00587 {
00588 const int oldFieldDim(data.rows());
00589 const int totalDim = oldFieldDim + newFieldDim;
00590 data.conservativeResize(totalDim, newPointCount);
00591 data.bottomRows(newFieldDim) = newField;
00592 labels.push_back(Label(name, newFieldDim));
00593 }
00594 else
00595 {
00596 stringstream errorMsg;
00597 errorMsg << "The field " << name << " cannot be added because the number of points is not the same. Old point count: " << pointCount << " new: " << newPointCount;
00598 throw InvalidField(errorMsg.str());
00599 }
00600 }
00601 }
00602
00605 template<typename T>
00606 const typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getConstViewByName(const std::string& name, const Labels& labels, const Matrix& data, const int viewRow) const
00607 {
00608 unsigned row(0);
00609 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00610 {
00611 if (it->text == name)
00612 {
00613 if (viewRow >= 0)
00614 {
00615 if (viewRow >= int(it->span))
00616 throw InvalidField(
00617 (boost::format("Requesting row %1% of field %2% that only has %3% rows") % viewRow % name % it->span).str()
00618 );
00619 return data.block(row + viewRow, 0, 1, data.cols());
00620 }
00621 else
00622 return data.block(row, 0, it->span, data.cols());
00623 }
00624 row += it->span;
00625 }
00626 throw InvalidField("Field " + name + " not found");
00627 }
00628
00631 template<typename T>
00632 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getViewByName(const std::string& name, const Labels& labels, Matrix& data, const int viewRow) const
00633 {
00634 unsigned row(0);
00635 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00636 {
00637 if (it->text == name)
00638 {
00639 if (viewRow >= 0)
00640 {
00641 if (viewRow >= int(it->span))
00642 throw InvalidField(
00643 (boost::format("Requesting row %1% of field %2% that only has %3% rows") % viewRow % name % it->span).str()
00644 );
00645 return data.block(row + viewRow, 0, 1, data.cols());
00646 }
00647 else
00648 return data.block(row, 0, it->span, data.cols());
00649 }
00650 row += it->span;
00651 }
00652 throw InvalidField("Field " + name + " not found");
00653 }
00654
00656 template<typename T>
00657 bool PointMatcher<T>::DataPoints::fieldExists(const std::string& name, const unsigned dim, const Labels& labels) const
00658 {
00659 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00660 {
00661 if (it->text == name)
00662 {
00663 if (dim == 0 || it->span == dim)
00664 return true;
00665 else
00666 return false;
00667 }
00668 }
00669 return false;
00670 }
00671
00672
00674 template<typename T>
00675 unsigned PointMatcher<T>::DataPoints::getFieldDimension(const std::string& name, const Labels& labels) const
00676 {
00677 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00678 {
00679 if (it->text == name)
00680 return it->span;
00681 }
00682 return 0;
00683 }
00684
00685
00687 template<typename T>
00688 unsigned PointMatcher<T>::DataPoints::getFieldStartingRow(const std::string& name, const Labels& labels) const
00689 {
00690 unsigned row(0);
00691 for(BOOST_AUTO(it, labels.begin()); it != labels.end(); ++it)
00692 {
00693 if (it->text == name)
00694 return row;
00695 row += it->span;
00696 }
00697 return 0;
00698 }
00699
00700 template struct PointMatcher<float>::DataPoints;
00701 template struct PointMatcher<double>::DataPoints;
00702
00703
00705 template<typename T>
00706 void PointMatcher<T>::swapDataPoints(DataPoints& a, DataPoints& b)
00707 {
00708 a.features.swap(b.features);
00709 swap(a.featureLabels, b.featureLabels);
00710 a.descriptors.swap(b.descriptors);
00711 swap(a.descriptorLabels, b.descriptorLabels);
00712 }
00713
00714 template
00715 void PointMatcher<float>::swapDataPoints(DataPoints& a, DataPoints& b);
00716 template
00717 void PointMatcher<double>::swapDataPoints(DataPoints& a, DataPoints& b);