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(auto it(this->descriptorLabels.begin()); it != this->descriptorLabels.end(); ++it)
00175 {
00176 for(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(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 assert(descriptors.cols() == pointCount);
00263 output.descriptors = Matrix(descriptors.rows(), pointCount);
00264 output.descriptorLabels = descriptorLabels;
00265 }
00266 else
00267 {
00268 assert(descriptors.rows() == 0);
00269 }
00270 return output;
00271 }
00272
00274 template<typename T>
00275 void PointMatcher<T>::DataPoints::setColFrom(Index thisCol, const DataPoints& that, Index thatCol)
00276 {
00277 features.col(thisCol) = that.features.col(thatCol);
00278 if (descriptors.cols() > 0)
00279 descriptors.col(thisCol) = that.descriptors.col(thatCol);
00280 }
00281
00282
00284 template<typename T>
00285 void PointMatcher<T>::DataPoints::allocateFeature(const std::string& name, const unsigned dim)
00286 {
00287 allocateField(name, dim, featureLabels, features);
00288 }
00289
00291 template<typename T>
00292 void PointMatcher<T>::DataPoints::allocateFeatures(const Labels& newLabels)
00293 {
00294 allocateFields(newLabels, featureLabels, features);
00295 }
00296
00298 template<typename T>
00299 void PointMatcher<T>::DataPoints::addFeature(const std::string& name, const Matrix& newFeature)
00300 {
00301 addField(name, newFeature, featureLabels, features);
00302 }
00303
00305 template<typename T>
00306 typename PointMatcher<T>::Matrix PointMatcher<T>::DataPoints::getFeatureCopyByName(const std::string& name) const
00307 {
00308 return Matrix(getFeatureViewByName(name));
00309 }
00310
00312 template<typename T>
00313 typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getFeatureViewByName(const std::string& name) const
00314 {
00315 return getConstViewByName(name, featureLabels, features);
00316 }
00317
00319 template<typename T>
00320 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getFeatureViewByName(const std::string& name)
00321 {
00322 return getViewByName(name, featureLabels, features);
00323 }
00324
00326 template<typename T>
00327 typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getFeatureRowViewByName(const std::string& name, const unsigned row) const
00328 {
00329 return getConstViewByName(name, featureLabels, features, int(row));
00330 }
00331
00333 template<typename T>
00334 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getFeatureRowViewByName(const std::string& name, const unsigned row)
00335 {
00336 return getViewByName(name, featureLabels, features, int(row));
00337 }
00338
00340 template<typename T>
00341 bool PointMatcher<T>::DataPoints::featureExists(const std::string& name) const
00342 {
00343 return fieldExists(name, 0, featureLabels);
00344 }
00345
00347 template<typename T>
00348 bool PointMatcher<T>::DataPoints::featureExists(const std::string& name, const unsigned dim) const
00349 {
00350 return fieldExists(name, dim, featureLabels);
00351 }
00352
00354 template<typename T>
00355 unsigned PointMatcher<T>::DataPoints::getFeatureDimension(const std::string& name) const
00356 {
00357 return getFieldDimension(name, featureLabels);
00358 }
00359
00361 template<typename T>
00362 unsigned PointMatcher<T>::DataPoints::getFeatureStartingRow(const std::string& name) const
00363 {
00364 return getFieldStartingRow(name, featureLabels);
00365 }
00366
00368 template<typename T>
00369 void PointMatcher<T>::DataPoints::allocateDescriptor(const std::string& name, const unsigned dim)
00370 {
00371 allocateField(name, dim, descriptorLabels, descriptors);
00372 }
00373
00375 template<typename T>
00376 void PointMatcher<T>::DataPoints::allocateDescriptors(const Labels& newLabels)
00377 {
00378 allocateFields(newLabels, descriptorLabels, descriptors);
00379 }
00380
00382 template<typename T>
00383 void PointMatcher<T>::DataPoints::addDescriptor(const std::string& name, const Matrix& newDescriptor)
00384 {
00385 addField(name, newDescriptor, descriptorLabels, descriptors);
00386 }
00387
00389 template<typename T>
00390 typename PointMatcher<T>::Matrix PointMatcher<T>::DataPoints::getDescriptorCopyByName(const std::string& name) const
00391 {
00392 return Matrix(getDescriptorViewByName(name));
00393 }
00394
00396 template<typename T>
00397 typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getDescriptorViewByName(const std::string& name) const
00398 {
00399 return getConstViewByName(name, descriptorLabels, descriptors);
00400 }
00401
00403 template<typename T>
00404 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getDescriptorViewByName(const std::string& name)
00405 {
00406 return getViewByName(name, descriptorLabels, descriptors);
00407 }
00408
00410 template<typename T>
00411 typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getDescriptorRowViewByName(const std::string& name, const unsigned row) const
00412 {
00413 return getConstViewByName(name, descriptorLabels, descriptors, int(row));
00414 }
00415
00417 template<typename T>
00418 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getDescriptorRowViewByName(const std::string& name, const unsigned row)
00419 {
00420 return getViewByName(name, descriptorLabels, descriptors, int(row));
00421 }
00422
00424 template<typename T>
00425 bool PointMatcher<T>::DataPoints::descriptorExists(const std::string& name) const
00426 {
00427 return fieldExists(name, 0, descriptorLabels);
00428 }
00429
00431 template<typename T>
00432 bool PointMatcher<T>::DataPoints::descriptorExists(const std::string& name, const unsigned dim) const
00433 {
00434 return fieldExists(name, dim, descriptorLabels);
00435 }
00436
00438 template<typename T>
00439 unsigned PointMatcher<T>::DataPoints::getDescriptorDimension(const std::string& name) const
00440 {
00441 return getFieldDimension(name, descriptorLabels);
00442 }
00443
00445 template<typename T>
00446 unsigned PointMatcher<T>::DataPoints::getDescriptorStartingRow(const std::string& name) const
00447 {
00448 return getFieldStartingRow(name, descriptorLabels);
00449 }
00450
00452 template<typename T>
00453 void PointMatcher<T>::DataPoints::assertDescriptorConsistency() const
00454 {
00455 if (descriptors.rows() == 0)
00456 {
00457 if (descriptors.cols() != 0)
00458 throw std::runtime_error(
00459 (boost::format("Point cloud has degenerate descriptor dimensions of rows=0, cols=%1%") % descriptors.cols()).str()
00460 );
00461 if (descriptorLabels.size() > 0)
00462 throw std::runtime_error(
00463 (boost::format("Point cloud has no descriptor data but %1% descriptor labels") % descriptorLabels.size()).str()
00464 );
00465 }
00466 else
00467 {
00468 if (descriptors.cols() != features.cols())
00469 throw std::runtime_error(
00470 (boost::format("Point cloud has %1% points in features but %2% points in descriptors") % features.cols() % descriptors.cols()).str()
00471 );
00472 int descDim(0);
00473 for (auto it(descriptorLabels.begin()); it != descriptorLabels.end(); ++it)
00474 descDim += it->span;
00475 if (descriptors.rows() != descDim)
00476 throw std::runtime_error(
00477 (boost::format("Descriptor labels return %1% total dimensions but there are %2% in the descriptors matrix") % descDim % descriptors.rows()).str()
00478 );
00479 }
00480 }
00481
00483 template<typename T>
00484 void PointMatcher<T>::DataPoints::allocateField(const std::string& name, const unsigned dim, Labels& labels, Matrix& data) const
00485 {
00486 if (fieldExists(name, 0, labels))
00487 {
00488 const unsigned descDim(getFieldDimension(name, labels));
00489 if (descDim != dim)
00490 {
00491 throw InvalidField(
00492 (boost::format("The existing field %1% has dimension %2%, different than requested dimension %3%") % name % descDim % dim).str()
00493 );
00494 }
00495 }
00496 else
00497 {
00498 const int oldDim(data.rows());
00499 const int totalDim(oldDim + dim);
00500 const int pointCount(features.cols());
00501 data.conservativeResize(totalDim, pointCount);
00502 labels.push_back(Label(name, dim));
00503 }
00504 }
00505
00507 template<typename T>
00508 void PointMatcher<T>::DataPoints::allocateFields(const Labels& newLabels, Labels& labels, Matrix& data) const
00509 {
00510 typedef vector<bool> BoolVector;
00511 BoolVector present(newLabels.size(), false);
00512
00513
00514 size_t additionalDim(0);
00515 for (size_t i = 0; i < newLabels.size(); ++i)
00516 {
00517 const string& newName(newLabels[i].text);
00518 const size_t newSpan(newLabels[i].span);
00519 for(auto it(labels.begin()); it != labels.end(); ++it)
00520 {
00521 if (it->text == newName)
00522 {
00523 if (it->span != newSpan)
00524 throw InvalidField(
00525 (boost::format("The existing field %1% has dimension %2%, different than requested dimension %3%") % newName % it->span % newSpan).str()
00526 );
00527 present[i] = true;
00528 break;
00529 }
00530 }
00531 if (!present[i])
00532 additionalDim += newSpan;
00533 }
00534
00535
00536 const int oldDim(data.rows());
00537 const int totalDim(oldDim + additionalDim);
00538 const int pointCount(features.cols());
00539 data.conservativeResize(totalDim, pointCount);
00540 for (size_t i = 0; i < newLabels.size(); ++i)
00541 {
00542 if (!present[i])
00543 labels.push_back(newLabels[i]);
00544 }
00545 }
00546
00548 template<typename T>
00549 void PointMatcher<T>::DataPoints::addField(const std::string& name, const Matrix& newField, Labels& labels, Matrix& data) const
00550 {
00551 const int newFieldDim = newField.rows();
00552 const int newPointCount = newField.cols();
00553 const int pointCount = features.cols();
00554
00555 if (newField.rows() == 0)
00556 return;
00557
00558
00559 if (fieldExists(name, 0, labels))
00560 {
00561 const int fieldDim = getFieldDimension(name, labels);
00562
00563 if(fieldDim == newFieldDim)
00564 {
00565
00566 if(pointCount == newPointCount)
00567 {
00568 const int row = getFieldStartingRow(name, labels);
00569 data.block(row, 0, fieldDim, pointCount) = newField;
00570 }
00571 else
00572 {
00573 stringstream errorMsg;
00574 errorMsg << "The field " << name << " cannot be added because the number of points is not the same. Old point count: " << pointCount << "new: " << newPointCount;
00575 throw InvalidField(errorMsg.str());
00576 }
00577 }
00578 else
00579 {
00580 stringstream errorMsg;
00581 errorMsg << "The field " << name << " already exists but could not be added because the dimension is not the same. Old dim: " << fieldDim << " new: " << newFieldDim;
00582 throw InvalidField(errorMsg.str());
00583 }
00584 }
00585 else
00586 {
00587 if(pointCount == newPointCount || pointCount == 0)
00588 {
00589 const int oldFieldDim(data.rows());
00590 const int totalDim = oldFieldDim + newFieldDim;
00591 data.conservativeResize(totalDim, newPointCount);
00592 data.bottomRows(newFieldDim) = newField;
00593 labels.push_back(Label(name, newFieldDim));
00594 }
00595 else
00596 {
00597 stringstream errorMsg;
00598 errorMsg << "The field " << name << " cannot be added because the number of points is not the same. Old point count: " << pointCount << " new: " << newPointCount;
00599 throw InvalidField(errorMsg.str());
00600 }
00601 }
00602 }
00603
00606 template<typename T>
00607 typename PointMatcher<T>::DataPoints::ConstView PointMatcher<T>::DataPoints::getConstViewByName(const std::string& name, const Labels& labels, const Matrix& data, const int viewRow) const
00608 {
00609 unsigned row(0);
00610 for(auto it(labels.begin()); it != labels.end(); ++it)
00611 {
00612 if (it->text == name)
00613 {
00614 if (viewRow >= 0)
00615 {
00616 if (viewRow >= int(it->span))
00617 throw InvalidField(
00618 (boost::format("Requesting row %1% of field %2% that only has %3% rows") % viewRow % name % it->span).str()
00619 );
00620 return data.block(row + viewRow, 0, 1, data.cols());
00621 }
00622 else
00623 return data.block(row, 0, it->span, data.cols());
00624 }
00625 row += it->span;
00626 }
00627 throw InvalidField("Field " + name + " not found");
00628 }
00629
00632 template<typename T>
00633 typename PointMatcher<T>::DataPoints::View PointMatcher<T>::DataPoints::getViewByName(const std::string& name, const Labels& labels, Matrix& data, const int viewRow) const
00634 {
00635 unsigned row(0);
00636 for(auto it(labels.begin()); it != labels.end(); ++it)
00637 {
00638 if (it->text == name)
00639 {
00640 if (viewRow >= 0)
00641 {
00642 if (viewRow >= int(it->span))
00643 throw InvalidField(
00644 (boost::format("Requesting row %1% of field %2% that only has %3% rows") % viewRow % name % it->span).str()
00645 );
00646 return data.block(row + viewRow, 0, 1, data.cols());
00647 }
00648 else
00649 return data.block(row, 0, it->span, data.cols());
00650 }
00651 row += it->span;
00652 }
00653 throw InvalidField("Field " + name + " not found");
00654 }
00655
00657 template<typename T>
00658 bool PointMatcher<T>::DataPoints::fieldExists(const std::string& name, const unsigned dim, const Labels& labels) const
00659 {
00660 for(auto it(labels.begin()); it != labels.end(); ++it)
00661 {
00662 if (it->text == name)
00663 {
00664 if (dim == 0 || it->span == dim)
00665 return true;
00666 else
00667 return false;
00668 }
00669 }
00670 return false;
00671 }
00672
00673
00675 template<typename T>
00676 unsigned PointMatcher<T>::DataPoints::getFieldDimension(const std::string& name, const Labels& labels) const
00677 {
00678 for(auto it(labels.begin()); it != labels.end(); ++it)
00679 {
00680 if (it->text == name)
00681 return it->span;
00682 }
00683 return 0;
00684 }
00685
00686
00688 template<typename T>
00689 unsigned PointMatcher<T>::DataPoints::getFieldStartingRow(const std::string& name, const Labels& labels) const
00690 {
00691 unsigned row(0);
00692 for(auto it(labels.begin()); it != labels.end(); ++it)
00693 {
00694 if (it->text == name)
00695 return row;
00696 row += it->span;
00697 }
00698 return 0;
00699 }
00700
00701 template struct PointMatcher<float>::DataPoints;
00702 template struct PointMatcher<double>::DataPoints;
00703
00704
00706 template<typename T>
00707 void PointMatcher<T>::swapDataPoints(DataPoints& a, DataPoints& b)
00708 {
00709 a.features.swap(b.features);
00710 swap(a.featureLabels, b.featureLabels);
00711 a.descriptors.swap(b.descriptors);
00712 swap(a.descriptorLabels, b.descriptorLabels);
00713 }
00714
00715 template
00716 void PointMatcher<float>::swapDataPoints(DataPoints& a, DataPoints& b);
00717 template
00718 void PointMatcher<double>::swapDataPoints(DataPoints& a, DataPoints& b);