DataPoints.cpp
Go to the documentation of this file.
00001 // kate: replace-tabs off; indent-width 4; indent-mode normal
00002 // vim: ts=4:sw=4:noexpandtab
00003 /*
00004 
00005 Copyright (c) 2010--2012,
00006 François Pomerleau and Stephane Magnenat, ASL, ETHZ, Switzerland
00007 You can contact the authors at <f dot pomerleau at gmail dot com> and
00008 <stephane at magnenat dot net>
00009 
00010 All rights reserved.
00011 
00012 Redistribution and use in source and binary forms, with or without
00013 modification, are permitted provided that the following conditions are met:
00014     * Redistributions of source code must retain the above copyright
00015       notice, this list of conditions and the following disclaimer.
00016     * Redistributions in binary form must reproduce the above copyright
00017       notice, this list of conditions and the following disclaimer in the
00018       documentation and/or other materials provided with the distribution.
00019     * Neither the name of the <organization> nor the
00020       names of its contributors may be used to endorse or promote products
00021       derived from this software without specific prior written permission.
00022 
00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
00026 DISCLAIMED. IN NO EVENT SHALL ETH-ASL BE LIABLE FOR ANY
00027 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
00028 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
00029 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
00030 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
00031 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00032 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
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     // concatenate features
00155     this->features.conservativeResize(Eigen::NoChange, nbPointsTotal);
00156     this->features.rightCols(nbPoints2) = dp.features;
00157     
00158     // concatenate descriptors
00159     if (this->descriptorLabels == dp.descriptorLabels)
00160     {
00161         if (this->descriptorLabels.size() > 0)
00162         {
00163             // same descriptors, fast merge
00164             this->descriptors.conservativeResize(Eigen::NoChange, nbPointsTotal);
00165             this->descriptors.rightCols(nbPoints2) = dp.descriptors;
00166         }
00167     }
00168     else
00169     {
00170         // different descriptors, slow merge
00171         
00172         // collect labels to be kept
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         // allocate new descriptors
00191         if (newDescLabels.size() > 0)
00192         {
00193             Matrix newDescriptors;
00194             Labels filledLabels;
00195             this->allocateFields(newDescLabels, filledLabels, newDescriptors);
00196             assert(newDescLabels == filledLabels);
00197             
00198             // fill
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             // swap descriptors
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     // for fields that exist, take note and check dimension
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     // for new fields allocate
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     // Replace if the field exists
00559     if (fieldExists(name, 0, labels))
00560     {
00561         const int fieldDim = getFieldDimension(name, labels);
00562         
00563         if(fieldDim == newFieldDim)
00564         {
00565             // Ensure that the number of points in the point cloud and in the field are the same
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 // Add at the end if it is a new field
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);


libpointmatcher
Author(s): Stéphane Magnenat, François Pomerleau
autogenerated on Thu Jan 2 2014 11:16:06