2016-06-28 19:00:44 -04:00
/*
2016-07-17 21:57:10 -04:00
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
2016-06-28 19:00:44 -04:00
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
2023-12-17 22:44:11 -08:00
#include <rtabmap/core/global_map/OctoMap.h>
2016-06-28 19:00:44 -04:00
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UStl.h>
2018-02-08 21:40:17 -05:00
#include <rtabmap/utilite/UTimer.h>
2016-06-28 19:00:44 -04:00
#include <rtabmap/core/util3d_transforms.h>
#include <rtabmap/core/util3d_filtering.h>
#include <rtabmap/core/util3d_mapping.h>
2020-11-30 12:33:08 -05:00
#include <rtabmap/core/util2d.h>
2016-08-21 19:33:01 -04:00
#include <pcl/common/transforms.h>
2021-05-30 10:12:07 -04:00
2016-06-28 19:00:44 -04:00
namespace rtabmap {
2018-02-08 21:40:17 -05:00
//////////////////////////////////////
// RtabmapColorOcTree
//////////////////////////////////////
2018-02-09 11:02:01 -05:00
RtabmapColorOcTreeNode * RtabmapColorOcTreeNode :: getChild ( unsigned int i ) {
#ifdef OCTOMAP_PRE_18
return static_cast < RtabmapColorOcTreeNode *> ( OcTreeNode :: getChild ( i ));
#else
UFATAL ( "This function should not be used with octomap >= 1.8" );
return 0 ;
#endif
}
const RtabmapColorOcTreeNode * RtabmapColorOcTreeNode :: getChild ( unsigned int i ) const {
#ifdef OCTOMAP_PRE_18
return static_cast < const RtabmapColorOcTreeNode *> ( OcTreeNode :: getChild ( i ));
#else
UFATAL ( "This function should not be used with octomap >= 1.8" );
return 0 ;
#endif
}
2018-02-09 10:53:39 -05:00
//octomap <1.8
bool RtabmapColorOcTreeNode :: pruneNode () {
#ifdef OCTOMAP_PRE_18
// checks for equal occupancy only, color ignored
if ( ! this -> collapsible ()) return false ;
// set occupancy value
setLogOdds ( getChild ( 0 ) -> getLogOdds ());
// set color to average color
if ( isColorSet ()) color = getAverageChildColor ();
// delete children
for ( unsigned int i = 0 ; i < 8 ; i ++ ) {
delete children [ i ];
}
delete [] children ;
children = NULL ;
return true ;
#else
UFATAL ( "This function should not be used with octomap >= 1.8" );
return false ;
#endif
}
//octomap <1.8
void RtabmapColorOcTreeNode :: expandNode () {
#ifdef OCTOMAP_PRE_18
assert ( ! hasChildren ());
for ( unsigned int k = 0 ; k < 8 ; k ++ ) {
createChild ( k );
children [ k ] -> setValue ( value );
getChild ( k ) -> setColor ( color );
}
#else
UFATAL ( "This function should not be used with octomap >= 1.8" );
#endif
}
2018-02-09 11:02:01 -05:00
//octomap <1.8
bool RtabmapColorOcTreeNode :: createChild ( unsigned int i ) {
#ifdef OCTOMAP_PRE_18
if ( children == NULL ) allocChildren ();
children [ i ] = new RtabmapColorOcTreeNode ();
return true ;
#else
UFATAL ( "This function should not be used with octomap >= 1.8" );
return false ;
#endif
}
2021-11-30 20:34:51 -05:00
void RtabmapColorOcTreeNode :: updateOccupancyTypeChildren ()
{
if ( children != NULL ){
int type = kTypeUnknown ;
for ( int i = 0 ; i < 8 && type != kTypeObstacle ; i ++ ) {
RtabmapColorOcTreeNode * child = static_cast < RtabmapColorOcTreeNode *> ( children [ i ]);
if ( child != NULL && child -> getOccupancyType () >= kTypeEmpty ) {
if ( type == kTypeUnknown ) {
type = child -> getOccupancyType ();
}
}
}
type_ = type ;
}
}
2018-02-08 21:40:17 -05:00
RtabmapColorOcTree :: RtabmapColorOcTree ( double resolution )
: OccupancyOcTreeBase < RtabmapColorOcTreeNode > ( resolution ) {
RtabmapColorOcTreeMemberInit . ensureLinking ();
};
RtabmapColorOcTreeNode * RtabmapColorOcTree :: setNodeColor ( const octomap :: OcTreeKey & key ,
uint8_t r ,
uint8_t g ,
uint8_t b ) {
RtabmapColorOcTreeNode * n = search ( key );
if ( n != 0 ) {
n -> setColor ( r , g , b );
}
return n ;
}
bool RtabmapColorOcTree :: pruneNode ( RtabmapColorOcTreeNode * node ) {
2018-02-09 10:53:39 -05:00
#ifndef OCTOMAP_PRE_18
2018-02-08 21:40:17 -05:00
if ( ! isNodeCollapsible ( node ))
return false ;
// set value to children's values (all assumed equal)
node -> copyData ( * ( getNodeChild ( node , 0 )));
if ( node -> isColorSet ()) // TODO check
node -> setColor ( node -> getAverageChildColor ());
// delete children
for ( unsigned int i = 0 ; i < 8 ; i ++ ) {
deleteNodeChild ( node , i );
}
delete [] node -> children ;
node -> children = NULL ;
return true ;
2018-02-09 10:53:39 -05:00
#else
UFATAL ( "This function should not be used with octomap < 1.8" );
return false ;
#endif
2018-02-08 21:40:17 -05:00
}
bool RtabmapColorOcTree :: isNodeCollapsible ( const RtabmapColorOcTreeNode * node ) const {
2018-02-09 10:53:39 -05:00
#ifndef OCTOMAP_PRE_18
2018-02-08 21:40:17 -05:00
// all children must exist, must not have children of
// their own and have the same occupancy probability
if ( ! nodeChildExists ( node , 0 ))
return false ;
const RtabmapColorOcTreeNode * firstChild = getNodeChild ( node , 0 );
if ( nodeHasChildren ( firstChild ))
return false ;
for ( unsigned int i = 1 ; i < 8 ; i ++ ) {
// compare nodes only using their occupancy, ignoring color for pruning
if ( ! nodeChildExists ( node , i ) || nodeHasChildren ( getNodeChild ( node , i )) || ! ( getNodeChild ( node , i ) -> getValue () == firstChild -> getValue ()))
return false ;
}
return true ;
2018-02-09 10:53:39 -05:00
#else
UFATAL ( "This function should not be used with octomap < 1.8" );
return false ;
#endif
2018-02-08 21:40:17 -05:00
}
RtabmapColorOcTreeNode * RtabmapColorOcTree :: averageNodeColor ( const octomap :: OcTreeKey & key ,
uint8_t r ,
uint8_t g ,
uint8_t b ) {
RtabmapColorOcTreeNode * n = search ( key );
if ( n != 0 ) {
if ( n -> isColorSet ()) {
RtabmapColorOcTreeNode :: Color prev_color = n -> getColor ();
n -> setColor (( prev_color . r + r ) / 2 , ( prev_color . g + g ) / 2 , ( prev_color . b + b ) / 2 );
}
else {
n -> setColor ( r , g , b );
}
}
return n ;
}
RtabmapColorOcTreeNode * RtabmapColorOcTree :: integrateNodeColor ( const octomap :: OcTreeKey & key ,
uint8_t r ,
uint8_t g ,
uint8_t b ) {
RtabmapColorOcTreeNode * n = search ( key );
if ( n != 0 ) {
if ( n -> isColorSet ()) {
RtabmapColorOcTreeNode :: Color prev_color = n -> getColor ();
double node_prob = n -> getOccupancy ();
uint8_t new_r = ( uint8_t ) (( double ) prev_color . r * node_prob
+ ( double ) r * ( 0.99 - node_prob ));
uint8_t new_g = ( uint8_t ) (( double ) prev_color . g * node_prob
+ ( double ) g * ( 0.99 - node_prob ));
uint8_t new_b = ( uint8_t ) (( double ) prev_color . b * node_prob
+ ( double ) b * ( 0.99 - node_prob ));
n -> setColor ( new_r , new_g , new_b );
}
else {
n -> setColor ( r , g , b );
}
}
return n ;
}
void RtabmapColorOcTree :: updateInnerOccupancy () {
this -> updateInnerOccupancyRecurs ( this -> root , 0 );
}
void RtabmapColorOcTree :: updateInnerOccupancyRecurs ( RtabmapColorOcTreeNode * node , unsigned int depth ) {
2018-02-09 10:53:39 -05:00
#ifndef OCTOMAP_PRE_18
2018-02-08 21:40:17 -05:00
// only recurse and update for inner nodes:
if ( nodeHasChildren ( node )){
// return early for last level:
if ( depth < this -> tree_depth ){
for ( unsigned int i = 0 ; i < 8 ; i ++ ) {
if ( nodeChildExists ( node , i )) {
updateInnerOccupancyRecurs ( getNodeChild ( node , i ), depth + 1 );
}
}
}
node -> updateOccupancyChildren ();
node -> updateColorChildren ();
2021-11-30 20:34:51 -05:00
node -> updateOccupancyTypeChildren ();
2018-02-08 21:40:17 -05:00
}
2018-02-09 10:53:39 -05:00
#else
// only recurse and update for inner nodes:
if ( node -> hasChildren ()){
// return early for last level:
if ( depth < this -> tree_depth ){
for ( unsigned int i = 0 ; i < 8 ; i ++ ) {
if ( node -> childExists ( i )) {
updateInnerOccupancyRecurs ( node -> getChild ( i ), depth + 1 );
}
}
}
node -> updateOccupancyChildren ();
node -> updateColorChildren ();
2021-11-30 20:34:51 -05:00
node -> updateOccupancyTypeChildren ();
2018-02-09 10:53:39 -05:00
}
#endif
2018-02-08 21:40:17 -05:00
}
2018-02-09 10:53:39 -05:00
RtabmapColorOcTree :: StaticMemberInitializer :: StaticMemberInitializer () {
RtabmapColorOcTree * tree = new RtabmapColorOcTree ( 0.1 );
#ifndef OCTOMAP_PRE_18
tree -> clearKeyRays ();
#endif
AbstractOcTree :: registerTreeType ( tree );
}
2018-11-29 18:21:12 -05:00
#ifndef _WIN32
// On Windows, the app freezes on start if the following is defined
2018-11-21 14:47:15 -05:00
RtabmapColorOcTree :: StaticMemberInitializer RtabmapColorOcTree :: RtabmapColorOcTreeMemberInit ;
2018-11-29 18:21:12 -05:00
#endif
2018-11-21 14:47:15 -05:00
2018-02-08 21:40:17 -05:00
//////////////////////////////////////
// OctoMap
//////////////////////////////////////
2023-12-17 22:44:11 -08:00
OctoMap :: OctoMap ( const LocalGridCache * cache , const ParametersMap & parameters ) :
GlobalMap ( cache , parameters ),
2018-02-01 22:17:46 -05:00
hasColor_ ( false ),
2018-02-18 15:10:25 -05:00
rangeMax_ ( Parameters :: defaultGridRangeMax ()),
2021-05-30 10:12:07 -04:00
rayTracing_ ( Parameters :: defaultGridRayTracing ()),
emptyFloodFillDepth_ ( Parameters :: defaultGridGlobalFloodFillDepth ())
2018-02-01 22:17:46 -05:00
{
2023-12-17 22:44:11 -08:00
octree_ = new RtabmapColorOcTree ( cellSize_ );
if ( occupancyThr_ <= 0.0f )
2018-08-16 14:42:05 -04:00
{
UWARN ( "Cannot set %s to null for OctoMap, using default value %f instead." ,
Parameters :: kGridGlobalOccupancyThr (). c_str (),
Parameters :: defaultGridGlobalOccupancyThr ());
2023-12-17 22:44:11 -08:00
occupancyThr_ = Parameters :: defaultGridGlobalOccupancyThr ();
2018-08-16 14:42:05 -04:00
}
2023-12-17 22:44:11 -08:00
UDEBUG ( "occupancyThr_=%f" , occupancyThr_ );
UDEBUG ( "probHit_=%f" , probability ( logOddsHit_ ));
UDEBUG ( "probMiss_=%f" , probability ( logOddsMiss_ ));
UDEBUG ( "probClampingMin_=%f" , probability ( logOddsClampingMin_ ));
UDEBUG ( "probClampingMax_=%f" , probability ( logOddsClampingMax_ ));
octree_ -> setOccupancyThres ( occupancyThr_ );
octree_ -> setProbHit ( probability ( logOddsHit_ ));
octree_ -> setProbMiss ( probability ( logOddsMiss_ ));
octree_ -> setClampingThresMin ( probability ( logOddsClampingMin_ ));
octree_ -> setClampingThresMax ( probability ( logOddsClampingMax_ ));
2018-02-18 15:10:25 -05:00
Parameters :: parse ( parameters , Parameters :: kGridRangeMax (), rangeMax_ );
Parameters :: parse ( parameters , Parameters :: kGridRayTracing (), rayTracing_ );
2023-12-17 22:44:11 -08:00
2021-05-30 10:12:07 -04:00
Parameters :: parse ( parameters , Parameters :: kGridGlobalFloodFillDepth (), emptyFloodFillDepth_ );
2024-11-15 14:13:13 -08:00
UASSERT ( emptyFloodFillDepth_ <= 16 );
2018-02-01 22:17:46 -05:00
2021-05-30 10:12:07 -04:00
UDEBUG ( "rangeMax_ =%f" , rangeMax_ );
UDEBUG ( "rayTracing_ =%s" , rayTracing_ ? "true" : "false" );
UDEBUG ( "emptyFloodFillDepth_=%d" , emptyFloodFillDepth_ );
2016-06-28 19:00:44 -04:00
}
OctoMap ::~ OctoMap ()
{
this -> clear ();
delete octree_ ;
}
void OctoMap :: clear ()
{
octree_ -> clear ();
2016-08-21 19:33:01 -04:00
hasColor_ = false ;
2023-12-17 22:44:11 -08:00
GlobalMap :: clear ();
2016-06-28 19:00:44 -04:00
}
2023-12-17 22:44:11 -08:00
unsigned long OctoMap :: getMemoryUsed () const
2016-06-28 19:00:44 -04:00
{
2023-12-17 22:44:11 -08:00
unsigned long memoryUsage = GlobalMap :: getMemoryUsed ();
// Note: size of OctoMap object is missing.
return memoryUsage ;
2016-06-28 19:00:44 -04:00
}
2021-05-30 10:12:07 -04:00
bool OctoMap :: isValidEmpty ( RtabmapColorOcTree * octree_ , unsigned int treeDepth , octomap :: point3d startPosition )
{
auto nodePtr = octree_ -> search ( startPosition . x (), startPosition . y (), startPosition . z (), treeDepth );
if ( nodePtr != NULL )
{
if ( ! octree_ -> isNodeOccupied ( * nodePtr ))
{
return true ;
}
}
return false ;
}
octomap :: point3d OctoMap :: findCloseEmpty ( RtabmapColorOcTree * octree_ , unsigned int treeDepth , octomap :: point3d startPosition )
{
//try current position
if ( isValidEmpty ( octree_ , treeDepth , startPosition ))
{
return startPosition ;
}
//x pos
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x () + octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ())))
{
return octomap :: point3d ( startPosition . x () + octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ());
}
//x neg
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x () - octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ())))
{
return octomap :: point3d ( startPosition . x () - octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ());
}
//y pos
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x (), startPosition . y () + octree_ -> getNodeSize ( treeDepth ), startPosition . z ())))
{
return octomap :: point3d ( startPosition . x (), startPosition . y () + octree_ -> getNodeSize ( treeDepth ), startPosition . z ());
}
//y neg
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x () - octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ())))
{
return octomap :: point3d ( startPosition . x (), startPosition . y () - octree_ -> getNodeSize ( treeDepth ), startPosition . z ());
}
//z pos
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () + octree_ -> getNodeSize ( treeDepth ))))
{
return octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () + octree_ -> getNodeSize ( treeDepth ));
}
//z neg
if ( isValidEmpty ( octree_ , treeDepth , octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () - octree_ -> getNodeSize ( treeDepth ))))
{
return octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () - octree_ -> getNodeSize ( treeDepth ));
}
//no valid position
return startPosition ;
}
bool OctoMap :: isNodeVisited ( std :: unordered_set < octomap :: OcTreeKey , octomap :: OcTreeKey :: KeyHash > const & EmptyNodes , octomap :: OcTreeKey const key )
{
for ( auto it = EmptyNodes . find ( key ); it != EmptyNodes . end (); it ++ )
{
if ( * it == key )
{
return true ;
}
}
return false ;
}
void OctoMap :: floodFill ( RtabmapColorOcTree * octree_ , unsigned int treeDepth , octomap :: point3d startPosition , std :: unordered_set < octomap :: OcTreeKey , octomap :: OcTreeKey :: KeyHash > & EmptyNodes , std :: queue < octomap :: point3d >& positionToExplore )
{
auto key = octree_ -> coordToKey ( startPosition , treeDepth );
if ( ! isNodeVisited ( EmptyNodes , key ))
{
if ( isValidEmpty ( octree_ , treeDepth , startPosition ))
{
EmptyNodes . insert ( key );
positionToExplore . push ( octomap :: point3d ( startPosition . x () + octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ()));
positionToExplore . push ( octomap :: point3d ( startPosition . x () - octree_ -> getNodeSize ( treeDepth ), startPosition . y (), startPosition . z ()));
positionToExplore . push ( octomap :: point3d ( startPosition . x (), startPosition . y () + octree_ -> getNodeSize ( treeDepth ), startPosition . z ()));
positionToExplore . push ( octomap :: point3d ( startPosition . x (), startPosition . y () - octree_ -> getNodeSize ( treeDepth ), startPosition . z ()));
positionToExplore . push ( octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () + octree_ -> getNodeSize ( treeDepth )));
positionToExplore . push ( octomap :: point3d ( startPosition . x (), startPosition . y (), startPosition . z () - octree_ -> getNodeSize ( treeDepth )));
}
}
}
std :: unordered_set < octomap :: OcTreeKey , octomap :: OcTreeKey :: KeyHash > OctoMap :: findEmptyNode ( RtabmapColorOcTree * octree_ , unsigned int treeDepth , octomap :: point3d startPosition )
{
std :: unordered_set < octomap :: OcTreeKey , octomap :: OcTreeKey :: KeyHash > exploreNode ;
std :: queue < octomap :: point3d > positionToExplore ;
startPosition = findCloseEmpty ( octree_ , treeDepth , startPosition );
floodFill ( octree_ , treeDepth , startPosition , exploreNode , positionToExplore );
while ( ! positionToExplore . empty ())
{
floodFill ( octree_ , treeDepth , positionToExplore . front (), exploreNode , positionToExplore );
positionToExplore . pop ();
}
return exploreNode ;
}
2023-12-17 22:44:11 -08:00
void OctoMap :: assemble ( const std :: list < std :: pair < int , Transform > > & newPoses )
2016-06-28 19:00:44 -04:00
{
// Original version from A. Hornung:
// https://github.com/OctoMap/octomap_mapping/blob/jade-devel/octomap_server/src/OctomapServer.cpp#L356
//
2018-02-01 22:17:46 -05:00
2023-12-17 22:44:11 -08:00
int lastId = assembledNodes (). size () ? assembledNodes (). rbegin () -> first : 0 ;
2016-06-28 19:00:44 -04:00
UDEBUG ( "Last id = %d" , lastId );
2018-02-01 22:17:46 -05:00
2023-12-17 22:44:11 -08:00
UDEBUG ( "newPoses = %d" , ( int ) newPoses . size ());
2018-02-01 22:17:46 -05:00
2023-12-17 22:44:11 -08:00
if ( ! newPoses . empty ())
2017-04-07 18:31:11 -04:00
{
2019-03-19 14:10:30 -04:00
float rangeMaxSqrd = rangeMax_ * rangeMax_ ;
float cellSize = octree_ -> getResolution ();
2026-09-09 10:42:46 -07:00
int not3DCount = 0 ;
int not3DFirstId = 0 ;
int not3DGroundType = 0 ;
int not3DObstaclesType = 0 ;
int not3DEmptyType = 0 ;
2023-12-17 22:44:11 -08:00
for ( std :: list < std :: pair < int , Transform > >:: const_iterator iter = newPoses . begin (); iter != newPoses . end (); ++ iter )
2016-06-28 19:00:44 -04:00
{
2023-12-17 22:44:11 -08:00
std :: map < int , LocalGrid >:: const_iterator localGridIter ;
localGridIter = cache (). find ( iter -> first );
if ( localGridIter != cache (). end ())
2016-06-28 19:00:44 -04:00
{
2023-12-17 22:44:11 -08:00
cv :: Mat ground = localGridIter -> second . groundCells ;
cv :: Mat obstacles = localGridIter -> second . obstacleCells ;
cv :: Mat emptyCells = localGridIter -> second . emptyCells ;
if ( ! localGridIter -> second . is3D ())
{
2026-09-09 10:42:46 -07:00
if ( ++ not3DCount == 1 )
{
not3DFirstId = iter -> first ;
not3DGroundType = ground . type ();
not3DObstaclesType = obstacles . type ();
not3DEmptyType = emptyCells . type ();
}
2023-12-17 22:44:11 -08:00
continue ;
}
2019-03-19 14:10:30 -04:00
UDEBUG ( "Adding %d to octomap (resolution=%f)" , iter -> first , octree_ -> getResolution ());
2017-04-07 18:31:11 -04:00
2019-03-19 14:10:30 -04:00
octomap :: point3d sensorOrigin ( iter -> second . x (), iter -> second . y (), iter -> second . z ());
2023-12-17 22:44:11 -08:00
sensorOrigin += octomap :: point3d ( localGridIter -> second . viewPoint . x , localGridIter -> second . viewPoint . y , localGridIter -> second . viewPoint . z );
2018-02-08 21:40:17 -05:00
2019-03-19 14:10:30 -04:00
updateMinMax ( sensorOrigin );
octomap :: OcTreeKey tmpKey ;
2023-12-17 22:44:11 -08:00
if ( ! octree_ -> coordToKeyChecked ( sensorOrigin , tmpKey ))
2019-03-19 14:10:30 -04:00
{
2026-08-06 13:32:20 -07:00
UERROR ( "Could not generate Key for origin (%f,%f,%f)" , sensorOrigin . x (), sensorOrigin . y (), sensorOrigin . z ());
2019-03-19 14:10:30 -04:00
}
2023-12-17 22:44:11 -08:00
bool computeRays = rayTracing_ && emptyCells . empty ();
2019-03-19 14:10:30 -04:00
// instead of direct scan insertion, compute update to filter ground:
octomap :: KeySet free_cells ;
// insert ground points only as free:
2023-12-17 22:44:11 -08:00
unsigned int maxGroundPts = ground . cols ;
2019-03-19 14:10:30 -04:00
UDEBUG ( "%d: compute free cells (from %d ground points)" , iter -> first , ( int ) maxGroundPts );
Eigen :: Affine3f t = iter -> second . toEigen3f ();
2023-12-17 22:44:11 -08:00
LaserScan tmpGround = LaserScan :: backwardCompatibility ( ground );
UASSERT ( tmpGround . size () == ( int ) maxGroundPts );
2019-03-19 14:10:30 -04:00
for ( unsigned int i = 0 ; i < maxGroundPts ; ++ i )
2017-04-07 18:31:11 -04:00
{
2019-03-19 14:10:30 -04:00
pcl :: PointXYZRGB pt ;
2023-12-17 22:44:11 -08:00
pt = util3d :: laserScanToPointRGB ( tmpGround , i );
pt = pcl :: transformPoint ( pt , t );
2018-02-08 21:40:17 -05:00
octomap :: point3d point ( pt . x , pt . y , pt . z );
2019-03-19 14:10:30 -04:00
bool ignoreOccupiedCell = false ;
2018-02-18 15:10:25 -05:00
if ( rangeMaxSqrd > 0.0f )
2017-04-07 18:31:11 -04:00
{
2019-03-19 14:10:30 -04:00
octomap :: point3d v ( pt . x - cellSize - sensorOrigin . x (), pt . y - cellSize - sensorOrigin . y (), pt . z - cellSize - sensorOrigin . z ());
2018-02-18 15:10:25 -05:00
if ( v . norm_sq () > rangeMaxSqrd )
2017-04-07 18:31:11 -04:00
{
2019-03-19 14:10:30 -04:00
// compute new point to max range
v . normalize ();
v *= rangeMax_ ;
point = sensorOrigin + v ;
ignoreOccupiedCell = true ;
2018-02-08 21:40:17 -05:00
}
2018-02-18 15:10:25 -05:00
}
2018-02-08 21:40:17 -05:00
2019-03-19 14:10:30 -04:00
if ( ! ignoreOccupiedCell )
2018-02-18 15:10:25 -05:00
{
2019-03-19 14:10:30 -04:00
// occupied endpoint
2018-02-18 15:10:25 -05:00
octomap :: OcTreeKey key ;
if ( octree_ -> coordToKeyChecked ( point , key ))
2018-02-08 21:40:17 -05:00
{
2019-03-19 14:10:30 -04:00
if ( iter -> first > 0 && iter -> first < lastId )
2018-02-13 10:16:48 -05:00
{
2018-02-18 15:10:25 -05:00
RtabmapColorOcTreeNode * n = octree_ -> search ( key );
2019-03-19 14:10:30 -04:00
if ( n && n -> getNodeRefId () > 0 && n -> getNodeRefId () > iter -> first )
2018-02-18 15:10:25 -05:00
{
2019-03-19 14:10:30 -04:00
// The cell has been updated from more recent node, don't update the cell
continue ;
}
}
updateMinMax ( point );
RtabmapColorOcTreeNode * n = octree_ -> updateNode ( key , true );
if ( n )
{
if ( ! hasColor_ && ! ( pt . r == 0 && pt . g == 0 && pt . b == 0 ) && ! ( pt . r == 255 && pt . g == 255 && pt . b == 255 ))
{
hasColor_ = true ;
}
octree_ -> averageNodeColor ( key , pt . r , pt . g , pt . b );
if ( iter -> first > 0 )
{
n -> setNodeRefId ( iter -> first );
n -> setPointRef ( point );
}
n -> setOccupancyType ( RtabmapColorOcTreeNode :: kTypeGround );
}
}
}
// only clear space (ground points)
octomap :: KeyRay keyRay ;
if ( computeRays &&
( iter -> first < 0 || iter -> first > lastId ) &&
octree_ -> computeRayKeys ( sensorOrigin , point , keyRay ))
{
free_cells . insert ( keyRay . begin (), keyRay . end ());
}
}
UDEBUG ( "%d: ground cells=%d free cells=%d" , iter -> first , ( int ) maxGroundPts , ( int ) free_cells . size ());
// all other points: free on ray, occupied on endpoint:
2023-12-17 22:44:11 -08:00
unsigned int maxObstaclePts = obstacles . cols ;
2019-03-19 14:10:30 -04:00
UDEBUG ( "%d: compute occupied cells (from %d obstacle points)" , iter -> first , ( int ) maxObstaclePts );
2023-12-17 22:44:11 -08:00
LaserScan tmpObstacle = LaserScan :: backwardCompatibility ( obstacles );
UASSERT ( tmpObstacle . size () == ( int ) maxObstaclePts );
2019-03-19 14:10:30 -04:00
for ( unsigned int i = 0 ; i < maxObstaclePts ; ++ i )
{
pcl :: PointXYZRGB pt ;
2023-12-17 22:44:11 -08:00
pt = util3d :: laserScanToPointRGB ( tmpObstacle , i );
pt = pcl :: transformPoint ( pt , t );
2019-03-19 14:10:30 -04:00
octomap :: point3d point ( pt . x , pt . y , pt . z );
bool ignoreOccupiedCell = false ;
if ( rangeMaxSqrd > 0.0f )
{
octomap :: point3d v ( pt . x - cellSize - sensorOrigin . x (), pt . y - cellSize - sensorOrigin . y (), pt . z - cellSize - sensorOrigin . z ());
if ( v . norm_sq () > rangeMaxSqrd )
{
// compute new point to max range
v . normalize ();
v *= rangeMax_ ;
point = sensorOrigin + v ;
ignoreOccupiedCell = true ;
}
}
if ( ! ignoreOccupiedCell )
{
// occupied endpoint
octomap :: OcTreeKey key ;
if ( octree_ -> coordToKeyChecked ( point , key ))
{
if ( iter -> first > 0 && iter -> first < lastId )
{
RtabmapColorOcTreeNode * n = octree_ -> search ( key );
if ( n && n -> getNodeRefId () > 0 && n -> getNodeRefId () > iter -> first )
{
// The cell has been updated from more recent node, don't update the cell
2018-02-18 15:10:25 -05:00
continue ;
}
}
updateMinMax ( point );
2019-03-19 14:10:30 -04:00
RtabmapColorOcTreeNode * n = octree_ -> updateNode ( key , true );
if ( n )
2018-02-18 15:10:25 -05:00
{
2019-03-19 14:10:30 -04:00
if ( ! hasColor_ && ! ( pt . r == 0 && pt . g == 0 && pt . b == 0 ) && ! ( pt . r == 255 && pt . g == 255 && pt . b == 255 ))
{
hasColor_ = true ;
}
octree_ -> averageNodeColor ( key , pt . r , pt . g , pt . b );
2018-02-18 15:10:25 -05:00
if ( iter -> first > 0 )
{
n -> setNodeRefId ( iter -> first );
2019-03-19 14:10:30 -04:00
n -> setPointRef ( point );
}
n -> setOccupancyType ( RtabmapColorOcTreeNode :: kTypeObstacle );
}
}
}
// free cells
octomap :: KeyRay keyRay ;
if ( computeRays &&
( iter -> first < 0 || iter -> first > lastId ) &&
octree_ -> computeRayKeys ( sensorOrigin , point , keyRay ))
{
free_cells . insert ( keyRay . begin (), keyRay . end ());
}
}
UDEBUG ( "%d: occupied cells=%d free cells=%d" , iter -> first , ( int ) maxObstaclePts , ( int ) free_cells . size ());
// mark free cells only if not seen occupied in this cloud
for ( octomap :: KeySet :: iterator it = free_cells . begin (), end = free_cells . end (); it != end ; ++ it )
{
if ( iter -> first > 0 )
{
RtabmapColorOcTreeNode * n = octree_ -> search ( * it );
if ( n && n -> getNodeRefId () > 0 && n -> getNodeRefId () >= iter -> first )
{
// The cell has been updated from current node or more recent node, don't update the cell
continue ;
}
}
2022-01-23 16:29:11 -05:00
RtabmapColorOcTreeNode * n = octree_ -> updateNode ( * it , false , true );
2019-03-19 14:10:30 -04:00
if ( n && n -> getOccupancyType () == RtabmapColorOcTreeNode :: kTypeUnknown )
{
n -> setOccupancyType ( RtabmapColorOcTreeNode :: kTypeEmpty );
if ( iter -> first > 0 )
{
n -> setNodeRefId ( iter -> first );
}
}
}
// all empty cells
2023-12-17 22:44:11 -08:00
if ( emptyCells . cols )
2019-03-19 14:10:30 -04:00
{
2023-12-17 22:44:11 -08:00
unsigned int maxEmptyPts = emptyCells . cols ;
2019-03-19 14:10:30 -04:00
UDEBUG ( "%d: compute free cells (from %d empty points)" , iter -> first , ( int ) maxEmptyPts );
2023-12-17 22:44:11 -08:00
LaserScan tmpEmpty = LaserScan :: backwardCompatibility ( emptyCells );
2019-03-19 14:10:30 -04:00
UASSERT ( tmpEmpty . size () == ( int ) maxEmptyPts );
for ( unsigned int i = 0 ; i < maxEmptyPts ; ++ i )
{
pcl :: PointXYZ pt ;
pt = util3d :: laserScanToPoint ( tmpEmpty , i );
pt = pcl :: transformPoint ( pt , t );
octomap :: point3d point ( pt . x , pt . y , pt . z );
bool ignoreCell = false ;
if ( rangeMaxSqrd > 0.0f )
{
octomap :: point3d v ( pt . x - sensorOrigin . x (), pt . y - sensorOrigin . y (), pt . z - sensorOrigin . z ());
if ( v . norm_sq () > rangeMaxSqrd )
{
ignoreCell = true ;
}
}
if ( ! ignoreCell )
{
octomap :: OcTreeKey key ;
if ( octree_ -> coordToKeyChecked ( point , key ))
{
if ( iter -> first > 0 )
{
RtabmapColorOcTreeNode * n = octree_ -> search ( key );
if ( n && n -> getNodeRefId () > 0 && n -> getNodeRefId () >= iter -> first )
{
// The cell has been updated from current node or more recent node, don't update the cell
continue ;
}
}
updateMinMax ( point );
2021-05-26 16:27:49 -04:00
RtabmapColorOcTreeNode * n = octree_ -> updateNode ( key , false , true );
2019-03-19 14:10:30 -04:00
if ( n && n -> getOccupancyType () == RtabmapColorOcTreeNode :: kTypeUnknown )
{
n -> setOccupancyType ( RtabmapColorOcTreeNode :: kTypeEmpty );
if ( iter -> first > 0 )
{
n -> setNodeRefId ( iter -> first );
}
2018-02-18 15:10:25 -05:00
}
2018-02-13 10:16:48 -05:00
}
2017-04-07 18:31:11 -04:00
}
}
2022-01-23 16:29:11 -05:00
}
2023-12-17 22:44:11 -08:00
if ( emptyCells . cols || ! free_cells . empty ())
2022-01-23 16:29:11 -05:00
{
2021-05-26 16:27:49 -04:00
octree_ -> updateInnerOccupancy ();
2017-04-07 18:31:11 -04:00
}
2019-03-19 14:10:30 -04:00
// compress map
2023-12-17 22:44:11 -08:00
//if(newPoses.size() > 1)
2019-03-19 14:10:30 -04:00
//{
// octree_->prune();
//}
2023-12-17 22:44:11 -08:00
addAssembledNode ( iter -> first , iter -> second );
2019-03-19 14:10:30 -04:00
UDEBUG ( "%d: end" , iter -> first );
2017-04-07 18:31:11 -04:00
}
2019-03-19 14:10:30 -04:00
else
2017-04-07 18:31:11 -04:00
{
2019-03-19 14:10:30 -04:00
UDEBUG ( "Did not find %d in cache" , iter -> first );
2017-04-07 18:31:11 -04:00
}
2016-06-28 19:00:44 -04:00
}
2026-09-09 10:42:46 -07:00
if ( not3DCount )
{
UWARN ( "It seems the local occupancy grids are not 3d, cannot update OctoMap! "
"(%d local grid(s) ignored, first one (id=%d) had ground type=%d, obstacles type=%d, empty type=%d)" ,
not3DCount , not3DFirstId , not3DGroundType , not3DObstaclesType , not3DEmptyType );
}
2016-06-28 19:00:44 -04:00
}
2018-02-08 21:40:17 -05:00
2021-05-30 10:12:07 -04:00
if ( emptyFloodFillDepth_ > 0 )
{
UTimer t ;
auto key = octree_ -> coordToKey ( 0 , 0 , 0 , emptyFloodFillDepth_ );
auto pos = octree_ -> keyToCoord ( key );
std :: unordered_set < octomap :: OcTreeKey , octomap :: OcTreeKey :: KeyHash > EmptyNodes = findEmptyNode ( octree_ , emptyFloodFillDepth_ , pos );
std :: vector < octomap :: OcTreeKey > nodeToDelete ;
for ( RtabmapColorOcTree :: iterator it = octree_ -> begin_leafs ( emptyFloodFillDepth_ ); it != octree_ -> end_leafs (); ++ it )
{
if ( ! octree_ -> isNodeOccupied ( * it ))
{
if ( ! isNodeVisited ( EmptyNodes , it . getKey ()))
{
nodeToDelete . push_back ( it . getKey ());
}
}
}
for ( unsigned int y = 0 ; y < nodeToDelete . size (); y ++ )
{
octree_ -> deleteNode ( nodeToDelete [ y ], emptyFloodFillDepth_ );
}
UDEBUG ( "Flood Fill: deleted %d empty cells (%fs)" , ( int ) nodeToDelete . size (), t . ticks ());
}
2016-06-28 19:00:44 -04:00
}
2018-02-08 21:40:17 -05:00
void OctoMap :: updateMinMax ( const octomap :: point3d & point )
{
if ( point . x () < minValues_ [ 0 ])
{
minValues_ [ 0 ] = point . x ();
}
if ( point . y () < minValues_ [ 1 ])
{
minValues_ [ 1 ] = point . y ();
}
if ( point . z () < minValues_ [ 2 ])
{
minValues_ [ 2 ] = point . z ();
}
if ( point . x () > maxValues_ [ 0 ])
{
maxValues_ [ 0 ] = point . x ();
}
if ( point . y () > maxValues_ [ 1 ])
{
maxValues_ [ 1 ] = point . y ();
}
if ( point . z () > maxValues_ [ 2 ])
{
maxValues_ [ 2 ] = point . z ();
}
}
2021-05-07 17:05:01 -04:00
2016-07-15 17:46:13 -04:00
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr OctoMap :: createCloud (
unsigned int treeDepth ,
std :: vector < int > * obstacleIndices ,
2018-02-08 21:40:17 -05:00
std :: vector < int > * emptyIndices ,
std :: vector < int > * groundIndices ,
2019-12-17 17:31:37 -05:00
bool originalRefPoints ,
2020-01-22 10:34:21 -05:00
std :: vector < int > * frontierIndices ,
2021-05-30 10:12:07 -04:00
std :: vector < double > * cloudProb ) const
2016-07-15 17:46:13 -04:00
{
UASSERT ( treeDepth <= octree_ -> getTreeDepth ());
2016-06-28 19:00:44 -04:00
pcl :: PointCloud < pcl :: PointXYZRGB >:: Ptr cloud ( new pcl :: PointCloud < pcl :: PointXYZRGB > );
2020-01-22 10:34:21 -05:00
if ( cloudProb )
{
cloudProb -> resize ( octree_ -> size ());
}
2016-07-15 17:46:13 -04:00
UDEBUG ( "depth=%d (maxDepth=%d) octree = %d" ,
( int ) treeDepth , ( int ) octree_ -> getTreeDepth (), ( int ) octree_ -> size ());
cloud -> resize ( octree_ -> size ());
2016-06-28 19:00:44 -04:00
if ( obstacleIndices )
{
2016-07-15 17:46:13 -04:00
obstacleIndices -> resize ( octree_ -> size ());
2016-06-28 19:00:44 -04:00
}
2016-07-15 17:46:13 -04:00
if ( emptyIndices )
2016-06-28 19:00:44 -04:00
{
2016-07-15 17:46:13 -04:00
emptyIndices -> resize ( octree_ -> size ());
2016-06-28 19:00:44 -04:00
}
2019-12-17 17:31:37 -05:00
if ( frontierIndices )
{
frontierIndices -> resize ( octree_ -> size ());
}
2018-02-08 21:40:17 -05:00
if ( groundIndices )
{
groundIndices -> resize ( octree_ -> size ());
}
2016-07-15 17:46:13 -04:00
if ( treeDepth == 0 )
{
treeDepth = octree_ -> getTreeDepth ();
}
2018-02-08 21:40:17 -05:00
double minZ = minValues_ [ 2 ];
double maxZ = maxValues_ [ 2 ];
2016-07-15 17:46:13 -04:00
2018-02-08 21:40:17 -05:00
bool addAllPoints = obstacleIndices == 0 && groundIndices == 0 && emptyIndices == 0 ;
2016-06-28 19:00:44 -04:00
int oi = 0 ;
int si = 0 ;
2018-02-08 21:40:17 -05:00
int ei = 0 ;
2019-12-17 17:31:37 -05:00
int fi = 0 ;
2016-06-28 19:00:44 -04:00
int gi = 0 ;
2018-02-08 21:40:17 -05:00
float halfCellSize = octree_ -> getNodeSize ( treeDepth ) / 2.0f ;
2021-05-07 17:05:01 -04:00
2018-02-08 21:40:17 -05:00
for ( RtabmapColorOcTree :: iterator it = octree_ -> begin ( treeDepth ); it != octree_ -> end (); ++ it )
2016-06-28 19:00:44 -04:00
{
2018-02-13 10:16:48 -05:00
if ( octree_ -> isNodeOccupied ( * it ) && ( obstacleIndices != 0 || groundIndices != 0 || addAllPoints ))
2016-06-28 19:00:44 -04:00
{
2016-07-15 17:46:13 -04:00
octomap :: point3d pt = octree_ -> keyToCoord ( it . getKey ());
2020-01-22 10:34:21 -05:00
if ( cloudProb )
{
( * cloudProb )[ oi ] = it -> getOccupancy ();
}
2016-08-21 19:33:01 -04:00
if ( octree_ -> getTreeDepth () == it . getDepth () && hasColor_ )
2016-07-15 17:46:13 -04:00
{
( * cloud )[ oi ] = pcl :: PointXYZRGB ( it -> getColor (). r , it -> getColor (). g , it -> getColor (). b );
}
else
{
// Gradiant color on z axis
float H = ( maxZ - pt . z ()) * 299.0f / ( maxZ - minZ );
float r , g , b ;
2020-11-30 12:33:08 -05:00
util2d :: HSVtoRGB ( & r , & g , & b , H , 1 , 1 );
2016-07-15 17:46:13 -04:00
( * cloud )[ oi ]. r = r * 255.0f ;
( * cloud )[ oi ]. g = g * 255.0f ;
( * cloud )[ oi ]. b = b * 255.0f ;
}
2018-02-08 21:40:17 -05:00
if ( originalRefPoints && it -> getOccupancyType () > 0 )
{
const octomap :: point3d & p = it -> getPointRef ();
( * cloud )[ oi ]. x = p . x ();
( * cloud )[ oi ]. y = p . y ();
( * cloud )[ oi ]. z = p . z ();
}
else
{
( * cloud )[ oi ]. x = pt . x () - halfCellSize ;
( * cloud )[ oi ]. y = pt . y () - halfCellSize ;
( * cloud )[ oi ]. z = pt . z ();
}
if ( it -> getOccupancyType () == RtabmapColorOcTreeNode :: kTypeGround )
2016-06-28 19:00:44 -04:00
{
2018-02-08 21:40:17 -05:00
if ( groundIndices )
{
groundIndices -> at ( gi ++ ) = oi ;
}
}
2018-02-13 10:16:48 -05:00
else if ( obstacleIndices )
{
obstacleIndices -> at ( si ++ ) = oi ;
}
++ oi ;
}
2019-12-17 17:31:37 -05:00
else if ( ! octree_ -> isNodeOccupied ( * it ) && ( emptyIndices != 0 || addAllPoints || frontierIndices != 0 ))
2018-02-13 10:16:48 -05:00
{
octomap :: point3d pt = octree_ -> keyToCoord ( it . getKey ());
2020-01-22 10:34:21 -05:00
if ( cloudProb )
{
( * cloudProb )[ oi ] = it -> getOccupancy ();
}
2021-05-30 10:12:07 -04:00
if ( frontierIndices != 0 &&
( ! octree_ -> search ( pt . x () + octree_ -> getNodeSize ( treeDepth ), pt . y (), pt . z (), treeDepth ) || ! octree_ -> search ( pt . x () - octree_ -> getNodeSize ( treeDepth ), pt . y (), pt . z (), treeDepth ) ||
! octree_ -> search ( pt . x (), pt . y () + octree_ -> getNodeSize ( treeDepth ), pt . z (), treeDepth ) || ! octree_ -> search ( pt . x (), pt . y () - octree_ -> getNodeSize ( treeDepth ), pt . z (), treeDepth ) ||
! octree_ -> search ( pt . x (), pt . y (), pt . z () + octree_ -> getNodeSize ( treeDepth ), treeDepth ) || ! octree_ -> search ( pt . x (), pt . y (), pt . z () - octree_ -> getNodeSize ( treeDepth ), treeDepth ) )) //ajouter 1 au key ?
2021-05-07 17:05:01 -04:00
{
2021-05-30 10:12:07 -04:00
//unknown neighbor FACE cell
frontierIndices -> at ( fi ++ ) = oi ;
}
2021-05-07 17:05:01 -04:00
2021-05-30 10:12:07 -04:00
( * cloud )[ oi ] = pcl :: PointXYZRGB ( it -> getColor (). r , it -> getColor (). g , it -> getColor (). b );
( * cloud )[ oi ]. x = pt . x () - halfCellSize ;
( * cloud )[ oi ]. y = pt . y () - halfCellSize ;
( * cloud )[ oi ]. z = pt . z ();
2021-05-07 17:05:01 -04:00
2021-05-30 10:12:07 -04:00
if ( emptyIndices )
{
emptyIndices -> at ( ei ++ ) = oi ;
2021-05-07 17:05:01 -04:00
}
2021-05-30 10:12:07 -04:00
2016-06-28 19:00:44 -04:00
++ oi ;
2019-12-17 17:31:37 -05:00
}
2016-06-28 19:00:44 -04:00
}
2016-07-15 17:46:13 -04:00
2016-06-28 19:00:44 -04:00
cloud -> resize ( oi );
2020-01-22 10:34:21 -05:00
if ( cloudProb )
{
cloudProb -> resize ( oi );
}
2016-06-28 19:00:44 -04:00
if ( obstacleIndices )
{
obstacleIndices -> resize ( si );
2018-02-08 21:40:17 -05:00
UDEBUG ( "obstacle=%d" , si );
2016-06-28 19:00:44 -04:00
}
2016-07-15 17:46:13 -04:00
if ( emptyIndices )
2016-06-28 19:00:44 -04:00
{
2018-02-08 21:40:17 -05:00
emptyIndices -> resize ( ei );
UDEBUG ( "empty=%d" , ei );
}
2019-12-17 17:31:37 -05:00
if ( frontierIndices )
{
frontierIndices -> resize ( fi );
UDEBUG ( "frontier=%d" , fi );
}
2018-02-08 21:40:17 -05:00
if ( groundIndices )
{
groundIndices -> resize ( gi );
UDEBUG ( "ground=%d" , gi );
2016-06-28 19:00:44 -04:00
}
UDEBUG ( "" );
return cloud ;
}
2017-04-07 18:31:11 -04:00
cv :: Mat OctoMap :: createProjectionMap ( float & xMin , float & yMin , float & gridCellSize , float minGridSize , unsigned int treeDepth )
2016-06-28 19:00:44 -04:00
{
2018-02-19 16:25:55 -05:00
UDEBUG ( "minGridSize=%f, treeDepth=%d" , minGridSize , ( int ) treeDepth );
2017-04-07 18:31:11 -04:00
UASSERT ( treeDepth <= octree_ -> getTreeDepth ());
if ( treeDepth == 0 )
{
treeDepth = octree_ -> getTreeDepth ();
}
gridCellSize = octree_ -> getNodeSize ( treeDepth );
2016-06-28 19:00:44 -04:00
2018-02-19 16:25:55 -05:00
cv :: Mat obstaclesMat = cv :: Mat ( 1 , ( int ) octree_ -> size (), CV_32FC2 );
cv :: Mat groundMat = cv :: Mat ( 1 , ( int ) octree_ -> size (), CV_32FC2 );
2016-06-28 19:00:44 -04:00
int gi = 0 ;
int oi = 0 ;
2018-02-19 16:25:55 -05:00
cv :: Vec2f * oPtr = obstaclesMat . ptr < cv :: Vec2f > ( 0 , 0 );
cv :: Vec2f * gPtr = groundMat . ptr < cv :: Vec2f > ( 0 , 0 );
2021-11-30 20:34:51 -05:00
float halfCellSize = octree_ -> getNodeSize ( treeDepth ) / 2.0f ;
2018-02-08 21:40:17 -05:00
for ( RtabmapColorOcTree :: iterator it = octree_ -> begin ( treeDepth ); it != octree_ -> end (); ++ it )
2016-06-28 19:00:44 -04:00
{
2017-04-07 18:31:11 -04:00
octomap :: point3d pt = octree_ -> keyToCoord ( it . getKey ());
2021-11-30 20:34:51 -05:00
if ( octree_ -> isNodeOccupied ( * it ) &&
it -> getOccupancyType () == RtabmapColorOcTreeNode :: kTypeObstacle )
2016-06-28 19:00:44 -04:00
{
2018-02-19 16:25:55 -05:00
// projected on ground
2021-11-30 20:34:51 -05:00
oPtr [ oi ][ 0 ] = pt . x () - halfCellSize ;
oPtr [ oi ][ 1 ] = pt . y () - halfCellSize ;
2018-02-19 16:25:55 -05:00
++ oi ;
2016-06-28 19:00:44 -04:00
}
2017-03-21 21:51:39 -04:00
else
2016-06-28 19:00:44 -04:00
{
2018-02-19 16:25:55 -05:00
// projected on ground
2021-11-30 20:34:51 -05:00
gPtr [ gi ][ 0 ] = pt . x () - halfCellSize ;
gPtr [ gi ][ 1 ] = pt . y () - halfCellSize ;
2018-02-19 16:25:55 -05:00
++ gi ;
2016-06-28 19:00:44 -04:00
}
}
2018-02-19 16:25:55 -05:00
obstaclesMat = obstaclesMat ( cv :: Range :: all (), cv :: Range ( 0 , oi ));
groundMat = groundMat ( cv :: Range :: all (), cv :: Range ( 0 , gi ));
2016-06-28 19:00:44 -04:00
std :: map < int , Transform > poses ;
poses . insert ( std :: make_pair ( 1 , Transform :: getIdentity ()));
std :: map < int , std :: pair < cv :: Mat , cv :: Mat > > maps ;
maps . insert ( std :: make_pair ( 1 , std :: make_pair ( groundMat , obstaclesMat )));
2018-02-19 16:25:55 -05:00
cv :: Mat map = util3d :: create2DMapFromOccupancyLocalMaps (
2016-06-28 19:00:44 -04:00
poses ,
maps ,
gridCellSize ,
xMin , yMin ,
minGridSize ,
false );
2018-02-19 16:25:55 -05:00
UDEBUG ( "" );
return map ;
2016-06-28 19:00:44 -04:00
}
2016-07-15 17:46:13 -04:00
bool OctoMap :: writeBinary ( const std :: string & path )
{
return octree_ -> writeBinary ( path );
}
2016-06-28 19:00:44 -04:00
} /* namespace rtabmap */