00001 /* +---------------------------------------------------------------------------+ 00002 | The Mobile Robot Programming Toolkit (MRPT) C++ library | 00003 | | 00004 | http://www.mrpt.org/ | 00005 | | 00006 | Copyright (C) 2005-2011 University of Malaga | 00007 | | 00008 | This software was written by the Machine Perception and Intelligent | 00009 | Robotics Lab, University of Malaga (Spain). | 00010 | Contact: Jose-Luis Blanco <jlblanco@ctima.uma.es> | 00011 | | 00012 | This file is part of the MRPT project. | 00013 | | 00014 | MRPT is free software: you can redistribute it and/or modify | 00015 | it under the terms of the GNU General Public License as published by | 00016 | the Free Software Foundation, either version 3 of the License, or | 00017 | (at your option) any later version. | 00018 | | 00019 | MRPT is distributed in the hope that it will be useful, | 00020 | but WITHOUT ANY WARRANTY; without even the implied warranty of | 00021 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 00022 | GNU General Public License for more details. | 00023 | | 00024 | You should have received a copy of the GNU General Public License | 00025 | along with MRPT. If not, see <http://www.gnu.org/licenses/>. | 00026 | | 00027 +---------------------------------------------------------------------------+ */ 00028 #ifndef CPOINTSMAP_H 00029 #define CPOINTSMAP_H 00030 00031 #include <mrpt/slam/CMetricMap.h> 00032 #include <mrpt/utils/CSerializable.h> 00033 #include <mrpt/math/CMatrix.h> 00034 #include <mrpt/utils/CLoadableOptions.h> 00035 #include <mrpt/utils/safe_pointers.h> 00036 #include <mrpt/math/KDTreeCapable.h> 00037 #include <mrpt/slam/CSinCosLookUpTableFor2DScans.h> 00038 #include <mrpt/poses/CPoint2D.h> 00039 #include <mrpt/math/lightweight_geom_data.h> 00040 #include <mrpt/utils/PLY_import_export.h> 00041 00042 #include <mrpt/maps/link_pragmas.h> 00043 00044 namespace mrpt 00045 { 00046 /** \ingroup mrpt_maps_grp */ 00047 namespace slam 00048 { 00049 // Fordward declarations: 00050 class CSimplePointsMap; 00051 class CObservation2DRangeScan; 00052 class CObservation3DRangeScan; 00053 00054 using namespace mrpt::poses; 00055 using namespace mrpt::math; 00056 00057 DEFINE_SERIALIZABLE_PRE_CUSTOM_BASE_LINKAGE( CPointsMap , CMetricMap, MAPS_IMPEXP ) 00058 00059 // Forward decls. needed to make its static methods friends of CPointsMap 00060 namespace detail { 00061 template <class Derived> struct loadFromRangeImpl; 00062 template <class Derived> struct pointmap_traits; 00063 } 00064 00065 00066 /** A cloud of points in 2D or 3D, which can be built from a sequence of laser scans or other sensors. 00067 * This is a virtual class, thus only a derived class can be instantiated by the user. The user most usually wants to use CSimplePointsMap. 00068 * 00069 * This class implements generic version of mrpt::slam::CMetric::insertObservation() accepting these types of sensory data: 00070 * - mrpt::slam::CObservation2DRangeScan: 2D range scans 00071 * - mrpt::slam::CObservation3DRangeScan: 3D range scans (Kinect, etc...) 00072 * - mrpt::slam::CObservationRange: IRs, Sonars, etc. 00073 * 00074 * \sa CMetricMap, CPoint, mrpt::utils::CSerializable 00075 * \ingroup mrpt_maps_grp 00076 */ 00077 class MAPS_IMPEXP CPointsMap : 00078 public CMetricMap, 00079 public mrpt::utils::KDTreeCapable<CPointsMap>, 00080 public mrpt::utils::PLY_Importer, 00081 public mrpt::utils::PLY_Exporter 00082 { 00083 // This must be added to any CSerializable derived class: 00084 DEFINE_VIRTUAL_SERIALIZABLE( CPointsMap ) 00085 00086 protected: 00087 /** Helper struct used for \a internal_loadFromRangeScan2D_prepareOneRange() */ 00088 struct MAPS_IMPEXP TLaserRange2DInsertContext { 00089 TLaserRange2DInsertContext(const CObservation2DRangeScan &_rangeScan) : HM(UNINITIALIZED_MATRIX), rangeScan(_rangeScan) 00090 { } 00091 CMatrixDouble44 HM; //!< Homog matrix of the local sensor pose within the robot 00092 const CObservation2DRangeScan &rangeScan; 00093 std::vector<float> fVars; //!< Extra variables to be used as desired by the derived class. 00094 std::vector<unsigned int> uVars; 00095 std::vector<uint8_t> bVars; 00096 }; 00097 00098 /** Helper struct used for \a internal_loadFromRangeScan3D_prepareOneRange() */ 00099 struct MAPS_IMPEXP TLaserRange3DInsertContext { 00100 TLaserRange3DInsertContext(const CObservation3DRangeScan &_rangeScan) : HM(UNINITIALIZED_MATRIX), rangeScan(_rangeScan) 00101 { } 00102 CMatrixDouble44 HM; //!< Homog matrix of the local sensor pose within the robot 00103 const CObservation3DRangeScan &rangeScan; 00104 float scan_x, scan_y,scan_z; //!< In \a internal_loadFromRangeScan3D_prepareOneRange, these are the local coordinates of the scan points being inserted right now. 00105 std::vector<float> fVars; //!< Extra variables to be used as desired by the derived class. 00106 std::vector<unsigned int> uVars; 00107 std::vector<uint8_t> bVars; 00108 }; 00109 00110 public: 00111 CPointsMap(); //!< Ctor 00112 virtual ~CPointsMap(); //!< Virtual destructor. 00113 00114 00115 // -------------------------------------------- 00116 /** @name Pure virtual interfaces to be implemented by any class derived from CPointsMap 00117 @{ */ 00118 00119 /** Reserves memory for a given number of points: the size of the map does not change, it only reserves the memory. 00120 * This is useful for situations where it is approximately known the final size of the map. This method is more 00121 * efficient than constantly increasing the size of the buffers. Refer to the STL C++ library's "reserve" methods. 00122 */ 00123 virtual void reserve(size_t newLength) = 0; 00124 00125 /** Resizes all point buffers so they can hold the given number of points: newly created points are set to default values, 00126 * and old contents are not changed. 00127 * \sa reserve, setPoint, setPointFast, setSize 00128 */ 00129 virtual void resize(size_t newLength) = 0; 00130 00131 /** Resizes all point buffers so they can hold the given number of points, *erasing* all previous contents 00132 * and leaving all points to default values. 00133 * \sa reserve, setPoint, setPointFast, setSize 00134 */ 00135 virtual void setSize(size_t newLength) = 0; 00136 00137 /** Changes the coordinates of the given point (0-based index), *without* checking for out-of-bounds and *without* calling mark_as_modified() \sa setPoint */ 00138 virtual void setPointFast(size_t index,float x, float y, float z)=0; 00139 00140 /** The virtual method for \a insertPoint() *without* calling mark_as_modified() */ 00141 virtual void insertPointFast( float x, float y, float z = 0 ) = 0; 00142 00143 /** Virtual assignment operator, copies as much common data (XYZ, color,...) as possible from the source map into this one. */ 00144 virtual void copyFrom(const CPointsMap &obj) = 0; 00145 00146 /** Get all the data fields for one point as a vector: depending on the implementation class this can be [X Y Z] or [X Y Z R G B], etc... 00147 * Unlike getPointAllFields(), this method does not check for index out of bounds 00148 * \sa getPointAllFields, setPointAllFields, setPointAllFieldsFast 00149 */ 00150 virtual void getPointAllFieldsFast( const size_t index, std::vector<float> & point_data ) const = 0; 00151 00152 /** Set all the data fields for one point as a vector: depending on the implementation class this can be [X Y Z] or [X Y Z R G B], etc... 00153 * Unlike setPointAllFields(), this method does not check for index out of bounds 00154 * \sa setPointAllFields, getPointAllFields, getPointAllFieldsFast 00155 */ 00156 virtual void setPointAllFieldsFast( const size_t index, const std::vector<float> & point_data ) = 0; 00157 00158 protected: 00159 00160 /** Auxiliary method called from within \a addFrom() automatically, to finish the copying of class-specific data */ 00161 virtual void addFrom_classSpecific(const CPointsMap &anotherMap, const size_t nPreviousPoints) = 0; 00162 00163 public: 00164 00165 /** @} */ 00166 // -------------------------------------------- 00167 00168 00169 /** Returns the square distance from the 2D point (x0,y0) to the closest correspondence in the map. 00170 */ 00171 virtual float squareDistanceToClosestCorrespondence( 00172 float x0, 00173 float y0 ) const; 00174 00175 inline float squareDistanceToClosestCorrespondenceT(const TPoint2D &p0) const { 00176 return squareDistanceToClosestCorrespondence(static_cast<float>(p0.x),static_cast<float>(p0.y)); 00177 } 00178 00179 00180 /** With this struct options are provided to the observation insertion process. 00181 * \sa CObservation::insertIntoPointsMap 00182 */ 00183 struct MAPS_IMPEXP TInsertionOptions : public utils::CLoadableOptions 00184 { 00185 /** Initilization of default parameters */ 00186 TInsertionOptions( ); 00187 /** See utils::CLoadableOptions */ 00188 void loadFromConfigFile(const mrpt::utils::CConfigFileBase &source,const std::string §ion); 00189 /** See utils::CLoadableOptions */ 00190 void dumpToTextStream(CStream &out) const; 00191 00192 float minDistBetweenLaserPoints; //!< The minimum distance between points (in 3D): If two points are too close, one of them is not inserted into the map. Default is 0.02 meters. 00193 bool addToExistingPointsMap; //!< Applicable to "loadFromRangeScan" only! If set to false, the points from the scan are loaded, clearing all previous content. Default is false. 00194 bool also_interpolate; //!< If set to true, far points (<1m) are interpolated with samples at "minDistSqrBetweenLaserPoints" intervals (Default is false). 00195 bool disableDeletion; //!< If set to false (default=true) points in the same plane as the inserted scan and inside the free space, are erased: i.e. they don't exist yet. 00196 bool fuseWithExisting; //!< If set to true (default=false), inserted points are "fused" with previously existent ones. This shrink the size of the points map, but its slower. 00197 bool isPlanarMap; //!< If set to true, only HORIZONTAL (in the XY plane) measurements will be inserted in the map (Default value is false, thus 3D maps are generated). \sa horizontalTolerance 00198 float horizontalTolerance; //!< The tolerance in rads in pitch & roll for a laser scan to be considered horizontal, considered only when isPlanarMap=true (default=0). 00199 float maxDistForInterpolatePoints; //!< The maximum distance between two points to interpolate between them (ONLY when also_interpolate=true) 00200 00201 }; 00202 00203 TInsertionOptions insertionOptions; //!< The options used when inserting observations in the map 00204 00205 /** Options used when evaluating "computeObservationLikelihood" in the derived classes. 00206 * \sa CObservation::computeObservationLikelihood 00207 */ 00208 struct MAPS_IMPEXP TLikelihoodOptions: public utils::CLoadableOptions 00209 { 00210 /** Initilization of default parameters 00211 */ 00212 TLikelihoodOptions( ); 00213 virtual ~TLikelihoodOptions() {} 00214 00215 /** See utils::CLoadableOptions */ 00216 void loadFromConfigFile( 00217 const mrpt::utils::CConfigFileBase &source, 00218 const std::string §ion); 00219 00220 /** See utils::CLoadableOptions */ 00221 void dumpToTextStream(CStream &out) const; 00222 00223 void writeToStream(CStream &out) const; //!< Binary dump to stream - for usage in derived classes' serialization 00224 void readFromStream(CStream &in); //!< Binary dump to stream - for usage in derived classes' serialization 00225 00226 double sigma_dist; //!< Sigma (standard deviation, in meters) of the exponential used to model the likelihood (default= 0.5meters) 00227 double max_corr_distance; //!< Maximum distance in meters to consider for the numerator divided by "sigma_dist", so that each point has a minimum (but very small) likelihood to avoid underflows (default=1.0 meters) 00228 uint32_t decimation; //!< Speed up the likelihood computation by considering only one out of N rays (default=10) 00229 }; 00230 00231 TLikelihoodOptions likelihoodOptions; 00232 00233 00234 /** Adds all the points from \a anotherMap to this map, without fusing. 00235 * This operation can be also invoked via the "+=" operator, for example: 00236 * \code 00237 * CSimplePointsMap m1, m2; 00238 * ... 00239 * m1.addFrom( m2 ); // Add all points of m2 to m1 00240 * m1 += m2; // Exactly the same than above 00241 * \endcode 00242 * \note The method in CPointsMap is generic but derived classes may redefine this virtual method to another one more optimized. 00243 */ 00244 virtual void addFrom(const CPointsMap &anotherMap); 00245 00246 /** This operator is synonymous with \a addFrom. \sa addFrom */ 00247 inline void operator +=(const CPointsMap &anotherMap) 00248 { 00249 this->addFrom(anotherMap); 00250 } 00251 00252 /** Insert the contents of another map into this one with some geometric transformation, without fusing close points. 00253 * \param otherMap The other map whose points are to be inserted into this one. 00254 * \param otherPose The pose of the other map in the coordinates of THIS map 00255 * \sa fuseWith, addFrom 00256 */ 00257 void insertAnotherMap( 00258 const CPointsMap *otherMap, 00259 const CPose3D &otherPose); 00260 00261 // -------------------------------------------------- 00262 /** @name File input/output methods 00263 @{ */ 00264 00265 /** Load from a text file. Each line should contain an "X Y" coordinate pair, separated by whitespaces. 00266 * Returns false if any error occured, true elsewere. 00267 */ 00268 inline bool load2D_from_text_file(const std::string &file) { return load2Dor3D_from_text_file(file,false); } 00269 00270 /** Load from a text file. Each line should contain an "X Y Z" coordinate tuple, separated by whitespaces. 00271 * Returns false if any error occured, true elsewere. 00272 */ 00273 inline bool load3D_from_text_file(const std::string &file) { return load2Dor3D_from_text_file(file,true); } 00274 00275 /** 2D or 3D generic implementation of \a load2D_from_text_file and load3D_from_text_file */ 00276 bool load2Dor3D_from_text_file(const std::string &file, const bool is_3D); 00277 00278 /** Save to a text file. Each line will contain "X Y" point coordinates. 00279 * Returns false if any error occured, true elsewere. 00280 */ 00281 bool save2D_to_text_file(const std::string &file) const; 00282 00283 /** Save to a text file. Each line will contain "X Y Z" point coordinates. 00284 * Returns false if any error occured, true elsewere. 00285 */ 00286 bool save3D_to_text_file(const std::string &file)const; 00287 00288 /** This virtual method saves the map to a file "filNamePrefix"+< some_file_extension >, as an image or in any other applicable way (Notice that other methods to save the map may be implemented in classes implementing this virtual interface). 00289 */ 00290 void saveMetricMapRepresentationToFile( 00291 const std::string &filNamePrefix 00292 )const 00293 { 00294 std::string fil( filNamePrefix + std::string(".txt") ); 00295 save3D_to_text_file( fil ); 00296 } 00297 00298 /** Save the point cloud as a PCL PCD file, in either ASCII or binary format (requires MRPT built against PCL) \return false on any error */ 00299 virtual bool savePCDFile(const std::string &filename, bool save_as_binary) const; 00300 00301 /** @} */ // End of: File input/output methods 00302 // -------------------------------------------------- 00303 00304 /** Returns the number of stored points in the map. 00305 */ 00306 inline size_t size() const { return x.size(); } 00307 00308 /** Returns the number of stored points in the map (DEPRECATED, use "size()" instead better) 00309 */ 00310 inline size_t getPointsCount() const { return size(); } 00311 00312 /** Access to a given point from map, as a 2D point. First index is 0. 00313 * \return The return value is the weight of the point (the times it has been fused), or 1 if weights are not used. 00314 * \exception Throws std::exception on index out of bound. 00315 * \sa setPoint, getPointFast 00316 */ 00317 unsigned long getPoint(size_t index,float &x,float &y,float &z) const; 00318 /// \overload 00319 unsigned long getPoint(size_t index,float &x,float &y) const; 00320 /// \overload 00321 unsigned long getPoint(size_t index,double &x,double &y,double &z) const; 00322 /// \overload 00323 unsigned long getPoint(size_t index,double &x,double &y) const; 00324 /// \overload 00325 inline unsigned long getPoint(size_t index,CPoint2D &p) const { return getPoint(index,p.x(),p.y()); } 00326 /// \overload 00327 inline unsigned long getPoint(size_t index,CPoint3D &p) const { return getPoint(index,p.x(),p.y(),p.z()); } 00328 /// \overload 00329 inline unsigned long getPoint(size_t index,mrpt::math::TPoint2D &p) const { return getPoint(index,p.x,p.y); } 00330 /// \overload 00331 inline unsigned long getPoint(size_t index,mrpt::math::TPoint3D &p) const { return getPoint(index,p.x,p.y,p.z); } 00332 00333 /** Access to a given point from map, and its colors, if the map defines them (othersise, R=G=B=1.0). First index is 0. 00334 * \return The return value is the weight of the point (the times it has been fused) 00335 * \exception Throws std::exception on index out of bound. 00336 */ 00337 virtual void getPoint( size_t index, float &x, float &y, float &z, float &R, float &G, float &B ) const 00338 { 00339 getPoint(index,x,y,z); 00340 R=G=B=1; 00341 } 00342 00343 /** Just like \a getPoint() but without checking out-of-bound index and without returning the point weight, just XYZ. 00344 */ 00345 inline void getPointFast(size_t index,float &x,float &y,float &z) const { x=this->x[index]; y=this->y[index]; z=this->z[index]; } 00346 00347 /** Returns true if the point map has a color field for each point */ 00348 virtual bool hasColorPoints() const { return false; } 00349 00350 /** Changes a given point from map, with Z defaulting to 0 if not provided. 00351 * \exception Throws std::exception on index out of bound. 00352 */ 00353 inline void setPoint(size_t index,float x, float y, float z) { 00354 ASSERT_BELOW_(index,this->size()) 00355 setPointFast(index,x,y,z); 00356 mark_as_modified(); 00357 } 00358 /// \overload 00359 inline void setPoint(size_t index,CPoint2D &p) { setPoint(index,p.x(),p.y(),0); } 00360 /// \overload 00361 inline void setPoint(size_t index,CPoint3D &p) { setPoint(index,p.x(),p.y(),p.z()); } 00362 /// \overload 00363 inline void setPoint(size_t index,float x, float y) { setPoint(index,x,y,0); } 00364 /// \overload (RGB data is ignored in classes without color information) 00365 virtual void setPoint(size_t index,float x, float y, float z, float R, float G, float B) { setPoint(index,x,y,z); } 00366 00367 /// Sets the point weight, which is ignored in all classes but those which actually store that field (Note: No checks are done for out-of-bounds index). \sa getPointWeight 00368 virtual void setPointWeight(size_t index,unsigned long w) { } 00369 /// Gets the point weight, which is ignored in all classes (defaults to 1) but in those which actually store that field (Note: No checks are done for out-of-bounds index). \sa setPointWeight 00370 virtual unsigned int getPointWeight(size_t index) const { return 1; } 00371 00372 00373 /** Provides a direct access to points buffer, or NULL if there is no points in the map. 00374 */ 00375 void getPointsBuffer( size_t &outPointsCount, const float *&xs, const float *&ys, const float *&zs ) const; 00376 00377 /** Provides a direct access to a read-only reference of the internal point buffer. \sa getAllPoints */ 00378 inline const std::vector<float> & getPointsBufferRef_x() const { return x; } 00379 /** Provides a direct access to a read-only reference of the internal point buffer. \sa getAllPoints */ 00380 inline const std::vector<float> & getPointsBufferRef_y() const { return y; } 00381 /** Provides a direct access to a read-only reference of the internal point buffer. \sa getAllPoints */ 00382 inline const std::vector<float> & getPointsBufferRef_z() const { return z; } 00383 00384 /** Returns a copy of the 2D/3D points as a std::vector of float coordinates. 00385 * If decimation is greater than 1, only 1 point out of that number will be saved in the output, effectively performing a subsampling of the points. 00386 * \sa getPointsBufferRef_x, getPointsBufferRef_y, getPointsBufferRef_z 00387 * \tparam VECTOR can be std::vector<float or double> or any row/column Eigen::Array or Eigen::Matrix (this includes mrpt::vector_float and mrpt::vector_double). 00388 */ 00389 template <class VECTOR> 00390 void getAllPoints( VECTOR &xs, VECTOR &ys, VECTOR &zs, size_t decimation = 1 ) const 00391 { 00392 MRPT_START 00393 ASSERT_(decimation>0) 00394 const size_t Nout = x.size() / decimation; 00395 xs.resize(Nout); 00396 ys.resize(Nout); 00397 zs.resize(Nout); 00398 size_t idx_in, idx_out; 00399 for (idx_in=0,idx_out=0;idx_out<Nout;idx_in+=decimation,++idx_out) 00400 { 00401 xs[idx_out]=x[idx_in]; 00402 ys[idx_out]=y[idx_in]; 00403 zs[idx_out]=z[idx_in]; 00404 } 00405 MRPT_END 00406 } 00407 00408 inline void getAllPoints(std::vector<TPoint3D> &ps,size_t decimation=1) const { 00409 std::vector<float> dmy1,dmy2,dmy3; 00410 getAllPoints(dmy1,dmy2,dmy3,decimation); 00411 ps.resize(dmy1.size()); 00412 for (size_t i=0;i<dmy1.size();i++) { 00413 ps[i].x=static_cast<double>(dmy1[i]); 00414 ps[i].y=static_cast<double>(dmy2[i]); 00415 ps[i].z=static_cast<double>(dmy3[i]); 00416 } 00417 } 00418 00419 /** Returns a copy of the 2D/3D points as a std::vector of float coordinates. 00420 * If decimation is greater than 1, only 1 point out of that number will be saved in the output, effectively performing a subsampling of the points. 00421 * \sa setAllPoints 00422 */ 00423 void getAllPoints( std::vector<float> &xs, std::vector<float> &ys, size_t decimation = 1 ) const; 00424 00425 inline void getAllPoints(std::vector<TPoint2D> &ps,size_t decimation=1) const { 00426 std::vector<float> dmy1,dmy2; 00427 getAllPoints(dmy1,dmy2,decimation); 00428 ps.resize(dmy1.size()); 00429 for (size_t i=0;i<dmy1.size();i++) { 00430 ps[i].x=static_cast<double>(dmy1[i]); 00431 ps[i].y=static_cast<double>(dmy2[i]); 00432 } 00433 } 00434 00435 /** Provides a way to insert (append) individual points into the map: the missing fields of child 00436 * classes (color, weight, etc) are left to their default values 00437 */ 00438 inline void insertPoint( float x, float y, float z=0 ) { insertPointFast(x,y,z); mark_as_modified(); } 00439 /// \overload of \a insertPoint() 00440 inline void insertPoint( const CPoint3D &p ) { insertPoint(p.x(),p.y(),p.z()); } 00441 /// \overload 00442 inline void insertPoint( const mrpt::math::TPoint3D &p ) { insertPoint(p.x,p.y,p.z); } 00443 /// \overload (RGB data is ignored in classes without color information) 00444 virtual void insertPoint( float x, float y, float z, float R, float G, float B ) { insertPoint(x,y,z); } 00445 00446 /** Set all the points at once from vectors with X,Y and Z coordinates (if Z is not provided, it will be set to all zeros). 00447 * \tparam VECTOR can be mrpt::vector_float or std::vector<float> or any other column or row Eigen::Matrix. 00448 */ 00449 template <typename VECTOR> 00450 inline void setAllPointsTemplate(const VECTOR &X,const VECTOR &Y,const VECTOR &Z = VECTOR()) 00451 { 00452 const size_t N = X.size(); 00453 ASSERT_EQUAL_(X.size(),Y.size()) 00454 ASSERT_(Z.size()==0 || Z.size()==X.size()) 00455 this->setSize(N); 00456 const bool z_valid = !Z.empty(); 00457 if (z_valid) for (size_t i=0;i<N;i++) { this->setPointFast(i,X[i],Y[i],Z[i]); } 00458 else for (size_t i=0;i<N;i++) { this->setPointFast(i,X[i],Y[i],0); } 00459 mark_as_modified(); 00460 } 00461 00462 /** Set all the points at once from vectors with X,Y and Z coordinates. \sa getAllPoints */ 00463 inline void setAllPoints(const std::vector<float> &X,const std::vector<float> &Y,const std::vector<float> &Z) { 00464 setAllPointsTemplate(X,Y,Z); 00465 } 00466 00467 /** Set all the points at once from vectors with X and Y coordinates (Z=0). \sa getAllPoints */ 00468 inline void setAllPoints(const std::vector<float> &X,const std::vector<float> &Y) { 00469 setAllPointsTemplate(X,Y); 00470 } 00471 00472 /** Get all the data fields for one point as a vector: depending on the implementation class this can be [X Y Z] or [X Y Z R G B], etc... 00473 * \sa getPointAllFieldsFast, setPointAllFields, setPointAllFieldsFast 00474 */ 00475 void getPointAllFields( const size_t index, std::vector<float> & point_data ) const { 00476 ASSERT_BELOW_(index,this->size()) 00477 getPointAllFieldsFast(index,point_data); 00478 } 00479 00480 /** Set all the data fields for one point as a vector: depending on the implementation class this can be [X Y Z] or [X Y Z R G B], etc... 00481 * Unlike setPointAllFields(), this method does not check for index out of bounds 00482 * \sa setPointAllFields, getPointAllFields, getPointAllFieldsFast 00483 */ 00484 void setPointAllFields( const size_t index, const std::vector<float> & point_data ){ 00485 ASSERT_BELOW_(index,this->size()) 00486 setPointAllFieldsFast(index,point_data); 00487 } 00488 00489 00490 /** Delete points out of the given "z" axis range have been removed. 00491 */ 00492 void clipOutOfRangeInZ(float zMin, float zMax); 00493 00494 /** Delete points which are more far than "maxRange" away from the given "point". 00495 */ 00496 void clipOutOfRange(const CPoint2D &point, float maxRange); 00497 00498 /** Remove from the map the points marked in a bool's array as "true". 00499 * \exception std::exception If mask size is not equal to points count. 00500 */ 00501 void applyDeletionMask( const std::vector<bool> &mask ); 00502 00503 /** Computes the matchings between this and another 2D/3D points map. 00504 This includes finding: 00505 - The set of points pairs in each map 00506 - The mean squared distance between corresponding pairs. 00507 This method is the most time critical one into the ICP algorithm. 00508 00509 * \param otherMap [IN] The other map to compute the matching with. 00510 * \param otherMapPose [IN] The pose of the other map as seen from "this". 00511 * \param maxDistForCorrespondence [IN] Maximum 2D distance between two points to be matched. 00512 * \param maxAngularDistForCorrespondence [IN] Maximum angular distance in radians to allow far points to be matched. 00513 * \param angularDistPivotPoint [IN] The point from which to measure the "angular distances" 00514 * \param correspondences [OUT] The detected matchings pairs. 00515 * \param correspondencesRatio [OUT] The number of correct correspondences. 00516 * \param sumSqrDist [OUT] The sum of all matched points squared distances.If undesired, set to NULL, as default. 00517 * \param covariance [OUT] The resulting matching covariance 3x3 matrix, or NULL if undesired. 00518 * \param onlyKeepTheClosest [OUT] Returns only the closest correspondence (default=false) 00519 * 00520 * \sa computeMatching3DWith 00521 */ 00522 void computeMatchingWith2D( 00523 const CMetricMap *otherMap, 00524 const CPose2D &otherMapPose, 00525 float maxDistForCorrespondence, 00526 float maxAngularDistForCorrespondence, 00527 const CPose2D &angularDistPivotPoint, 00528 TMatchingPairList &correspondences, 00529 float &correspondencesRatio, 00530 float *sumSqrDist = NULL, 00531 bool onlyKeepTheClosest = false, 00532 bool onlyUniqueRobust = false, 00533 const size_t decimation_other_map_points = 1, 00534 const size_t offset_other_map_points = 0 ) const; 00535 00536 /** Computes the matchings between this and another 3D points map - method used in 3D-ICP. 00537 This method finds the set of point pairs in each map. 00538 00539 The method is the most time critical one into the ICP algorithm. 00540 00541 * \param otherMap [IN] The other map to compute the matching with. 00542 * \param otherMapPose [IN] The pose of the other map as seen from "this". 00543 * \param maxDistForCorrespondence [IN] Maximum 2D linear distance between two points to be matched. 00544 * \param maxAngularDistForCorrespondence [IN] In radians: The aim is to allow larger distances to more distant correspondences. 00545 * \param angularDistPivotPoint [IN] The point used to calculate distances from in both maps. 00546 * \param correspondences [OUT] The detected matchings pairs. 00547 * \param correspondencesRatio [OUT] The ratio [0,1] of points in otherMap with at least one correspondence. 00548 * \param sumSqrDist [OUT] The sum of all matched points squared distances.If undesired, set to NULL, as default. 00549 * \param onlyKeepTheClosest [IN] If set to true, only the closest correspondence will be returned. If false (default) all are returned. 00550 * 00551 * \sa compute3DMatchingRatio 00552 */ 00553 void computeMatchingWith3D( 00554 const CMetricMap *otherMap, 00555 const CPose3D &otherMapPose, 00556 float maxDistForCorrespondence, 00557 float maxAngularDistForCorrespondence, 00558 const CPoint3D &angularDistPivotPoint, 00559 TMatchingPairList &correspondences, 00560 float &correspondencesRatio, 00561 float *sumSqrDist = NULL, 00562 bool onlyKeepTheClosest = true, 00563 bool onlyUniqueRobust = false, 00564 const size_t decimation_other_map_points = 1, 00565 const size_t offset_other_map_points = 0 ) const; 00566 00567 /** Computes the ratio in [0,1] of correspondences between "this" and the "otherMap" map, whose 6D pose relative to "this" is "otherMapPose" 00568 * In the case of a multi-metric map, this returns the average between the maps. This method always return 0 for grid maps. 00569 * \param otherMap [IN] The other map to compute the matching with. 00570 * \param otherMapPose [IN] The 6D pose of the other map as seen from "this". 00571 * \param minDistForCorr [IN] The minimum distance between 2 non-probabilistic map elements for counting them as a correspondence. 00572 * \param minMahaDistForCorr [IN] The minimum Mahalanobis distance between 2 probabilistic map elements for counting them as a correspondence. 00573 * 00574 * \return The matching ratio [0,1] 00575 * \sa computeMatchingWith2D 00576 */ 00577 float compute3DMatchingRatio( 00578 const CMetricMap *otherMap, 00579 const CPose3D &otherMapPose, 00580 float minDistForCorr = 0.10f, 00581 float minMahaDistForCorr = 2.0f 00582 ) const; 00583 00584 /** Transform the range scan into a set of cartessian coordinated 00585 * points. The options in "insertionOptions" are considered in this method. 00586 * \param rangeScan The scan to be inserted into this map 00587 * \param robotPose The robot 3D pose, default to (0,0,0|0deg,0deg,0deg). It is used to compute the sensor pose relative to the robot actual pose. Recall sensor pose is embeded in the observation class. 00588 * 00589 * Only ranges marked as "valid=true" in the observation will be inserted 00590 * 00591 * \note Each derived class may enrich points in different ways (color, weight, etc..), so please refer to the description of the specific 00592 * implementation of mrpt::slam::CPointsMap you are using. 00593 * \note The actual generic implementation of this file lives in <src>/CPointsMap_crtp_common.h, but specific instantiations are generated at each derived class. 00594 * 00595 * \sa CObservation2DRangeScan, CObservation3DRangeScan 00596 */ 00597 virtual void loadFromRangeScan( 00598 const CObservation2DRangeScan &rangeScan, 00599 const CPose3D *robotPose = NULL ) = 0; 00600 00601 /** Overload of \a loadFromRangeScan() for 3D range scans (for example, Kinect observations). 00602 * 00603 * \param rangeScan The scan to be inserted into this map 00604 * \param robotPose The robot 3D pose, default to (0,0,0|0deg,0deg,0deg). It is used to compute the sensor pose relative to the robot actual pose. Recall sensor pose is embeded in the observation class. 00605 * 00606 * \note Each derived class may enrich points in different ways (color, weight, etc..), so please refer to the description of the specific 00607 * implementation of mrpt::slam::CPointsMap you are using. 00608 * \note The actual generic implementation of this file lives in <src>/CPointsMap_crtp_common.h, but specific instantiations are generated at each derived class. 00609 */ 00610 virtual void loadFromRangeScan( 00611 const CObservation3DRangeScan &rangeScan, 00612 const CPose3D *robotPose = NULL ) = 0; 00613 00614 /** Insert the contents of another map into this one, fusing the previous content with the new one. 00615 * This means that points very close to existing ones will be "fused", rather than "added". This prevents 00616 * the unbounded increase in size of these class of maps. 00617 * NOTICE that "otherMap" is neither translated nor rotated here, so if this is desired it must done 00618 * before calling this method. 00619 * \param otherMap The other map whose points are to be inserted into this one. 00620 * \param minDistForFuse Minimum distance (in meters) between two points, each one in a map, to be considered the same one and be fused rather than added. 00621 * \param notFusedPoints If a pointer is supplied, this list will contain at output a list with a "bool" value per point in "this" map. This will be false/true according to that point having been fused or not. 00622 * \sa loadFromRangeScan, addFrom 00623 */ 00624 void fuseWith( 00625 CPointsMap *anotherMap, 00626 float minDistForFuse = 0.02f, 00627 std::vector<bool> *notFusedPoints = NULL); 00628 00629 /** Replace each point \f$ p_i \f$ by \f$ p'_i = b \oplus p_i \f$ (pose compounding operator). 00630 */ 00631 void changeCoordinatesReference(const CPose2D &b); 00632 00633 /** Replace each point \f$ p_i \f$ by \f$ p'_i = b \oplus p_i \f$ (pose compounding operator). 00634 */ 00635 void changeCoordinatesReference(const CPose3D &b); 00636 00637 /** Copy all the points from "other" map to "this", replacing each point \f$ p_i \f$ by \f$ p'_i = b \oplus p_i \f$ (pose compounding operator). 00638 */ 00639 void changeCoordinatesReference(const CPointsMap &other, const CPose3D &b); 00640 00641 /** Returns true if the map is empty/no observation has been inserted. 00642 */ 00643 virtual bool isEmpty() const; 00644 00645 /** STL-like method to check whether the map is empty: */ 00646 inline bool empty() const { return isEmpty(); } 00647 00648 /** Returns a 3D object representing the map. 00649 * The color of the points is given by the static variables: COLOR_3DSCENE_R,COLOR_3DSCENE_G,COLOR_3DSCENE_B 00650 * \sa mrpt::global_settings::POINTSMAPS_3DOBJECT_POINTSIZE 00651 */ 00652 virtual void getAs3DObject ( mrpt::opengl::CSetOfObjectsPtr &outObj ) const; 00653 00654 /** If the map is a simple points map or it's a multi-metric map that contains EXACTLY one simple points map, return it. 00655 * Otherwise, return NULL 00656 */ 00657 virtual const CSimplePointsMap * getAsSimplePointsMap() const { return NULL; } 00658 virtual CSimplePointsMap * getAsSimplePointsMap() { return NULL; } 00659 00660 00661 /** This method returns the largest distance from the origin to any of the points, such as a sphere centered at the origin with this radius cover ALL the points in the map (the results are buffered, such as, if the map is not modified, the second call will be much faster than the first one). */ 00662 float getLargestDistanceFromOrigin() const; 00663 00664 /** Like \a getLargestDistanceFromOrigin() but returns in \a output_is_valid = false if the distance was not already computed, skipping its computation then, unlike getLargestDistanceFromOrigin() */ 00665 float getLargestDistanceFromOriginNoRecompute(bool &output_is_valid) const { 00666 output_is_valid = m_largestDistanceFromOriginIsUpdated; 00667 return m_largestDistanceFromOrigin; 00668 } 00669 00670 /** Computes the bounding box of all the points, or (0,0 ,0,0, 0,0) if there are no points. 00671 * Results are cached unless the map is somehow modified to avoid repeated calculations. 00672 */ 00673 void boundingBox( float &min_x,float &max_x,float &min_y,float &max_y,float &min_z,float &max_z ) const; 00674 00675 inline void boundingBox(TPoint3D &pMin,TPoint3D &pMax) const { 00676 float dmy1,dmy2,dmy3,dmy4,dmy5,dmy6; 00677 boundingBox(dmy1,dmy2,dmy3,dmy4,dmy5,dmy6); 00678 pMin.x=dmy1; 00679 pMin.y=dmy2; 00680 pMin.z=dmy3; 00681 pMax.x=dmy4; 00682 pMax.y=dmy5; 00683 pMax.z=dmy6; 00684 } 00685 00686 void extractCylinder( const CPoint2D ¢er, const double radius, const double zmin, const double zmax, CPointsMap *outMap ); 00687 00688 /** @name Filter-by-height stuff 00689 @{ */ 00690 00691 /** Enable/disable the filter-by-height functionality \sa setHeightFilterLevels \note Default upon construction is disabled. */ 00692 inline void enableFilterByHeight(bool enable=true) { m_heightfilter_enabled=enable; } 00693 /** Return whether filter-by-height is enabled \sa enableFilterByHeight */ 00694 inline bool isFilterByHeightEnabled() const { return m_heightfilter_enabled; } 00695 00696 /** Set the min/max Z levels for points to be actually inserted in the map (only if \a enableFilterByHeight() was called before). */ 00697 inline void setHeightFilterLevels(const double _z_min, const double _z_max) { m_heightfilter_z_min=_z_min; m_heightfilter_z_max=_z_max; } 00698 /** Get the min/max Z levels for points to be actually inserted in the map \sa enableFilterByHeight, setHeightFilterLevels */ 00699 inline void getHeightFilterLevels(double &_z_min, double &_z_max) const { _z_min=m_heightfilter_z_min; _z_max=m_heightfilter_z_max; } 00700 00701 /** @} */ 00702 00703 /** The color [0,1] of points when extracted from getAs3DObject (default=blue) */ 00704 static float COLOR_3DSCENE_R; 00705 static float COLOR_3DSCENE_G; 00706 static float COLOR_3DSCENE_B; 00707 00708 00709 /** Computes the likelihood of taking a given observation from a given pose in the world being modeled with this map. 00710 * \param takenFrom The robot's pose the observation is supposed to be taken from. 00711 * \param obs The observation. 00712 * \return This method returns a likelihood in the range [0,1]. 00713 * 00714 * \sa Used in particle filter algorithms, see: CMultiMetricMapPDF 00715 * \note In CPointsMap this method is virtual so it can be redefined in derived classes, if desired. 00716 */ 00717 virtual double computeObservationLikelihood( const CObservation *obs, const CPose3D &takenFrom ); 00718 00719 /** @name PCL library support 00720 @{ */ 00721 00722 00723 /** Use to convert this MRPT point cloud object into a PCL point cloud object. 00724 * Usage example: 00725 * \code 00726 * mrpt::slam::CPointsCloud pc; 00727 * pcl::PointCloud<pcl::PointXYZ> cloud; 00728 * 00729 * pc.getPCLPointCloud(cloud); 00730 * \endcode 00731 */ 00732 template <class POINTCLOUD> 00733 void getPCLPointCloud(POINTCLOUD &cloud) const 00734 { 00735 const size_t nThis = this->size(); 00736 // Fill in the cloud data 00737 cloud.width = nThis; 00738 cloud.height = 1; 00739 cloud.is_dense = false; 00740 cloud.points.resize(cloud.width * cloud.height); 00741 for (size_t i = 0; i < nThis; ++i) { 00742 cloud.points[i].x =this->x[i]; 00743 cloud.points[i].y =this->y[i]; 00744 cloud.points[i].z =this->z[i]; 00745 } 00746 } 00747 00748 /** @} */ 00749 00750 /** @name Methods that MUST be implemented by children classes of KDTreeCapable 00751 @{ */ 00752 00753 /// Must return the number of data points 00754 inline size_t kdtree_get_point_count() const { return this->size(); } 00755 00756 /// Returns the dim'th component of the idx'th point in the class: 00757 inline float kdtree_get_pt(const size_t idx, int dim) const { 00758 if (dim==0) return this->x[idx]; 00759 else if (dim==1) return this->y[idx]; 00760 else if (dim==2) return this->z[idx]; else return 0; 00761 } 00762 00763 /// Returns the distance between the vector "p1[0:size-1]" and the data point with index "idx_p2" stored in the class: 00764 inline float kdtree_distance(const float *p1, const size_t idx_p2,size_t size) const 00765 { 00766 if (size==2) 00767 { 00768 const float d0 = p1[0]-x[idx_p2]; 00769 const float d1 = p1[1]-y[idx_p2]; 00770 return d0*d0+d1*d1; 00771 } 00772 else 00773 { 00774 const float d0 = p1[0]-x[idx_p2]; 00775 const float d1 = p1[1]-y[idx_p2]; 00776 const float d2 = p1[2]-z[idx_p2]; 00777 return d0*d0+d1*d1+d2*d2; 00778 } 00779 } 00780 00781 // Optional bounding-box computation: return false to default to a standard bbox computation loop. 00782 // Return true if the BBOX was already computed by the class and returned in "bb" so it can be avoided to redo it again. 00783 // Look at bb.size() to find out the expected dimensionality (e.g. 2 or 3 for point clouds) 00784 template <typename BBOX> 00785 bool kdtree_get_bbox(BBOX &bb) const 00786 { 00787 float min_z,max_z; 00788 this->boundingBox( 00789 bb[0].low, bb[0].high, 00790 bb[1].low, bb[1].high, 00791 min_z,max_z); 00792 if (bb.size()==3) { 00793 bb[2].low = min_z; bb[2].high = max_z; 00794 } 00795 return true; 00796 } 00797 00798 00799 /** @} */ 00800 00801 protected: 00802 std::vector<float> x,y,z; //!< The point coordinates 00803 00804 CSinCosLookUpTableFor2DScans m_scans_sincos_cache; //!< Cache of sin/cos values for the latest 2D scan geometries. 00805 00806 /** Auxiliary variables used in "getLargestDistanceFromOrigin" 00807 * \sa getLargestDistanceFromOrigin 00808 */ 00809 mutable float m_largestDistanceFromOrigin; 00810 00811 /** Auxiliary variables used in "getLargestDistanceFromOrigin" 00812 * \sa getLargestDistanceFromOrigin 00813 */ 00814 mutable bool m_largestDistanceFromOriginIsUpdated; 00815 00816 mutable bool m_boundingBoxIsUpdated; 00817 mutable float m_bb_min_x,m_bb_max_x, m_bb_min_y,m_bb_max_y, m_bb_min_z,m_bb_max_z; 00818 00819 00820 /** Called only by this class or children classes, set m_largestDistanceFromOriginIsUpdated=false and such. */ 00821 inline void mark_as_modified() const 00822 { 00823 m_largestDistanceFromOriginIsUpdated=false; 00824 m_boundingBoxIsUpdated = false; 00825 kdtree_mark_as_outdated(); 00826 } 00827 00828 /** This is a common version of CMetricMap::insertObservation() for point maps (actually, CMetricMap::internal_insertObservation), 00829 * so derived classes don't need to worry implementing that method unless something special is really necesary. 00830 * See mrpt::slam::CPointsMap for the enumeration of types of observations which are accepted. 00831 */ 00832 bool internal_insertObservation( 00833 const CObservation *obs, 00834 const CPose3D *robotPose); 00835 00836 /** Helper method for ::copyFrom() */ 00837 void base_copyFrom(const CPointsMap &obj); 00838 00839 00840 /** @name PLY Import virtual methods to implement in base classes 00841 @{ */ 00842 /** In a base class, reserve memory to prepare subsequent calls to PLY_import_set_face */ 00843 virtual void PLY_import_set_face_count(const size_t N) { } 00844 00845 /** In a base class, will be called after PLY_import_set_vertex_count() once for each loaded point. 00846 * \param pt_color Will be NULL if the loaded file does not provide color info. 00847 */ 00848 virtual void PLY_import_set_vertex(const size_t idx, const mrpt::math::TPoint3Df &pt, const mrpt::utils::TColorf *pt_color = NULL); 00849 /** @} */ 00850 00851 /** @name PLY Export virtual methods to implement in base classes 00852 @{ */ 00853 00854 /** In a base class, return the number of vertices */ 00855 virtual size_t PLY_export_get_vertex_count() const; 00856 00857 /** In a base class, return the number of faces */ 00858 virtual size_t PLY_export_get_face_count() const { return 0; } 00859 00860 /** In a base class, will be called after PLY_export_get_vertex_count() once for each exported point. 00861 * \param pt_color Will be NULL if the loaded file does not provide color info. 00862 */ 00863 virtual void PLY_export_get_vertex( 00864 const size_t idx, 00865 mrpt::math::TPoint3Df &pt, 00866 bool &pt_has_color, 00867 mrpt::utils::TColorf &pt_color) const; 00868 00869 /** @} */ 00870 00871 /** The minimum and maximum height for a certain laser scan to be inserted into this map 00872 * \sa m_heightfilter_enabled */ 00873 double m_heightfilter_z_min, m_heightfilter_z_max; 00874 00875 /** Whether or not (default=not) filter the input points by height 00876 * \sa m_heightfilter_z_min, m_heightfilter_z_max */ 00877 bool m_heightfilter_enabled; 00878 00879 00880 // Friend methods: 00881 template <class Derived> friend struct detail::loadFromRangeImpl; 00882 template <class Derived> friend struct detail::pointmap_traits; 00883 00884 00885 }; // End of class def. 00886 00887 } // End of namespace 00888 00889 namespace global_settings 00890 { 00891 /** The size of points when exporting with getAs3DObject() (default=3.0) 00892 * Affects to: 00893 * - mrpt::slam::CPointsMap and all its children classes. 00894 */ 00895 extern MAPS_IMPEXP float POINTSMAPS_3DOBJECT_POINTSIZE; 00896 } 00897 } // End of namespace 00898 00899 #endif
| Page generated by Doxygen 1.7.5 for MRPT 0.9.5 SVN: at Thu Oct 13 21:25:36 UTC 2011 |