339 lines
11 KiB
C++
339 lines
11 KiB
C++
/**
|
|
* dynamicEDT3D:
|
|
* A library for incrementally updatable Euclidean distance transforms in 3D.
|
|
* @author C. Sprunk, B. Lau, W. Burgard, University of Freiburg, Copyright (C) 2011.
|
|
* @see http://octomap.sourceforge.net/
|
|
* License: New BSD License
|
|
*/
|
|
|
|
/*
|
|
* Copyright (c) 2011-2012, C. Sprunk, B. Lau, W. Burgard, University of Freiburg
|
|
* 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 University of Freiburg 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 OWNER 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.
|
|
*/
|
|
|
|
template <class TREE>
|
|
float DynamicEDTOctomapBase<TREE>::distanceValue_Error = -1.0;
|
|
|
|
template <class TREE>
|
|
int DynamicEDTOctomapBase<TREE>::distanceInCellsValue_Error = -1;
|
|
|
|
template <class TREE>
|
|
DynamicEDTOctomapBase<TREE>::DynamicEDTOctomapBase(float maxdist, TREE* _octree, octomap::point3d bbxMin, octomap::point3d bbxMax, bool treatUnknownAsOccupied)
|
|
: DynamicEDT3D(((int) (maxdist/_octree->getResolution()+1)*((int) (maxdist/_octree->getResolution()+1)))), octree(_octree), unknownOccupied(treatUnknownAsOccupied)
|
|
{
|
|
treeDepth = octree->getTreeDepth();
|
|
treeResolution = octree->getResolution();
|
|
initializeOcTree(bbxMin, bbxMax);
|
|
octree->enableChangeDetection(true);
|
|
}
|
|
|
|
template <class TREE>
|
|
DynamicEDTOctomapBase<TREE>::~DynamicEDTOctomapBase() {
|
|
|
|
}
|
|
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::update(bool updateRealDist){
|
|
|
|
for(octomap::KeyBoolMap::const_iterator it = octree->changedKeysBegin(), end=octree->changedKeysEnd(); it!=end; ++it){
|
|
//the keys in this list all go down to the lowest level!
|
|
|
|
octomap::OcTreeKey key = it->first;
|
|
|
|
//ignore changes outside of bounding box
|
|
if(key[0] < boundingBoxMinKey[0] || key[1] < boundingBoxMinKey[1] || key[2] < boundingBoxMinKey[2])
|
|
continue;
|
|
if(key[0] > boundingBoxMaxKey[0] || key[1] > boundingBoxMaxKey[1] || key[2] > boundingBoxMaxKey[2])
|
|
continue;
|
|
|
|
typename TREE::NodeType* node = octree->search(key);
|
|
assert(node);
|
|
//"node" is not necessarily at lowest level, BUT: the occupancy value of this node
|
|
//has to be the same as of the node indexed by the key *it
|
|
|
|
updateMaxDepthLeaf(key, octree->isNodeOccupied(node));
|
|
}
|
|
octree->resetChangeDetection();
|
|
|
|
DynamicEDT3D::update(updateRealDist);
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::initializeOcTree(octomap::point3d bbxMin, octomap::point3d bbxMax){
|
|
|
|
boundingBoxMinKey = octree->coordToKey(bbxMin);
|
|
boundingBoxMaxKey = octree->coordToKey(bbxMax);
|
|
|
|
offsetX = -boundingBoxMinKey[0];
|
|
offsetY = -boundingBoxMinKey[1];
|
|
offsetZ = -boundingBoxMinKey[2];
|
|
|
|
int _sizeX = boundingBoxMaxKey[0] - boundingBoxMinKey[0] + 1;
|
|
int _sizeY = boundingBoxMaxKey[1] - boundingBoxMinKey[1] + 1;
|
|
int _sizeZ = boundingBoxMaxKey[2] - boundingBoxMinKey[2] + 1;
|
|
|
|
initializeEmpty(_sizeX, _sizeY, _sizeZ, false);
|
|
|
|
|
|
if(unknownOccupied == false){
|
|
for(typename TREE::leaf_bbx_iterator it = octree->begin_leafs_bbx(bbxMin,bbxMax), end=octree->end_leafs_bbx(); it!= end; ++it){
|
|
if(octree->isNodeOccupied(*it)){
|
|
int nodeDepth = it.getDepth();
|
|
if( nodeDepth == treeDepth){
|
|
insertMaxDepthLeafAtInitialize(it.getKey());
|
|
} else {
|
|
int cubeSize = 1 << (treeDepth - nodeDepth);
|
|
octomap::OcTreeKey key=it.getIndexKey();
|
|
for(int dx = 0; dx < cubeSize; dx++)
|
|
for(int dy = 0; dy < cubeSize; dy++)
|
|
for(int dz = 0; dz < cubeSize; dz++){
|
|
unsigned short int tmpx = key[0]+dx;
|
|
unsigned short int tmpy = key[1]+dy;
|
|
unsigned short int tmpz = key[2]+dz;
|
|
|
|
if(boundingBoxMinKey[0] > tmpx || boundingBoxMinKey[1] > tmpy || boundingBoxMinKey[2] > tmpz)
|
|
continue;
|
|
if(boundingBoxMaxKey[0] < tmpx || boundingBoxMaxKey[1] < tmpy || boundingBoxMaxKey[2] < tmpz)
|
|
continue;
|
|
|
|
insertMaxDepthLeafAtInitialize(octomap::OcTreeKey(tmpx, tmpy, tmpz));
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
octomap::OcTreeKey key;
|
|
for(int dx=0; dx<sizeX; dx++){
|
|
key[0] = boundingBoxMinKey[0] + dx;
|
|
for(int dy=0; dy<sizeY; dy++){
|
|
key[1] = boundingBoxMinKey[1] + dy;
|
|
for(int dz=0; dz<sizeZ; dz++){
|
|
key[2] = boundingBoxMinKey[2] + dz;
|
|
|
|
typename TREE::NodeType* node = octree->search(key);
|
|
if(!node || octree->isNodeOccupied(node)){
|
|
insertMaxDepthLeafAtInitialize(key);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::insertMaxDepthLeafAtInitialize(octomap::OcTreeKey key){
|
|
bool isSurrounded = true;
|
|
|
|
|
|
for(int dx=-1; dx<=1; dx++)
|
|
for(int dy=-1; dy<=1; dy++)
|
|
for(int dz=-1; dz<=1; dz++){
|
|
if(dx==0 && dy==0 && dz==0)
|
|
continue;
|
|
typename TREE::NodeType* node = octree->search(octomap::OcTreeKey(key[0]+dx, key[1]+dy, key[2]+dz));
|
|
if((!unknownOccupied && node==NULL) || ((node!=NULL) && (octree->isNodeOccupied(node)==false))){
|
|
isSurrounded = false;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(isSurrounded){
|
|
//obstacles that are surrounded by obstacles do not need to be put in the queues,
|
|
//hence this initialization
|
|
dataCell c;
|
|
int x = key[0]+offsetX;
|
|
int y = key[1]+offsetY;
|
|
int z = key[2]+offsetZ;
|
|
c.obstX = x;
|
|
c.obstY = y;
|
|
c.obstZ = z;
|
|
c.sqdist = 0;
|
|
c.dist = 0.0;
|
|
c.queueing = fwProcessed;
|
|
c.needsRaise = false;
|
|
data[x][y][z] = c;
|
|
} else {
|
|
setObstacle(key[0]+offsetX, key[1]+offsetY, key[2]+offsetZ);
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::updateMaxDepthLeaf(octomap::OcTreeKey& key, bool occupied){
|
|
if(occupied)
|
|
setObstacle(key[0]+offsetX, key[1]+offsetY, key[2]+offsetZ);
|
|
else
|
|
removeObstacle(key[0]+offsetX, key[1]+offsetY, key[2]+offsetZ);
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::worldToMap(const octomap::point3d &p, int &x, int &y, int &z) const {
|
|
octomap::OcTreeKey key = octree->coordToKey(p);
|
|
x = key[0] + offsetX;
|
|
y = key[1] + offsetY;
|
|
z = key[2] + offsetZ;
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::mapToWorld(int x, int y, int z, octomap::point3d &p) const {
|
|
p = octree->keyToCoord(octomap::OcTreeKey(x-offsetX, y-offsetY, z-offsetZ));
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::mapToWorld(int x, int y, int z, octomap::OcTreeKey &key) const {
|
|
key = octomap::OcTreeKey(x-offsetX, y-offsetY, z-offsetZ);
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::getDistanceAndClosestObstacle(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
if(x>=0 && x<sizeX && y>=0 && y<sizeY && z>=0 && z<sizeZ){
|
|
dataCell c= data[x][y][z];
|
|
|
|
distance = c.dist*treeResolution;
|
|
if(c.obstX != invalidObstData){
|
|
mapToWorld(c.obstX, c.obstY, c.obstZ, closestObstacle);
|
|
} else {
|
|
//If we are at maxDist, it can very well be that there is no valid closest obstacle data for this cell, this is not an error.
|
|
}
|
|
} else {
|
|
distance = distanceValue_Error;
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
void DynamicEDTOctomapBase<TREE>::getDistanceAndClosestObstacle_unsafe(const octomap::point3d& p, float &distance, octomap::point3d& closestObstacle) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
|
|
dataCell c= data[x][y][z];
|
|
|
|
distance = c.dist*treeResolution;
|
|
if(c.obstX != invalidObstData){
|
|
mapToWorld(c.obstX, c.obstY, c.obstZ, closestObstacle);
|
|
} else {
|
|
//If we are at maxDist, it can very well be that there is no valid closest obstacle data for this cell, this is not an error.
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
float DynamicEDTOctomapBase<TREE>::getDistance(const octomap::point3d& p) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
if(x>=0 && x<sizeX && y>=0 && y<sizeY && z>=0 && z<sizeZ){
|
|
return data[x][y][z].dist*treeResolution;
|
|
} else {
|
|
return distanceValue_Error;
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
float DynamicEDTOctomapBase<TREE>::getDistance_unsafe(const octomap::point3d& p) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
return data[x][y][z].dist*treeResolution;
|
|
}
|
|
|
|
template <class TREE>
|
|
float DynamicEDTOctomapBase<TREE>::getDistance(const octomap::OcTreeKey& k) const {
|
|
int x = k[0] + offsetX;
|
|
int y = k[1] + offsetY;
|
|
int z = k[2] + offsetZ;
|
|
|
|
if(x>=0 && x<sizeX && y>=0 && y<sizeY && z>=0 && z<sizeZ){
|
|
return data[x][y][z].dist*treeResolution;
|
|
} else {
|
|
return distanceValue_Error;
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
float DynamicEDTOctomapBase<TREE>::getDistance_unsafe(const octomap::OcTreeKey& k) const {
|
|
int x = k[0] + offsetX;
|
|
int y = k[1] + offsetY;
|
|
int z = k[2] + offsetZ;
|
|
|
|
return data[x][y][z].dist*treeResolution;
|
|
}
|
|
|
|
template <class TREE>
|
|
int DynamicEDTOctomapBase<TREE>::getSquaredDistanceInCells(const octomap::point3d& p) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
if(x>=0 && x<sizeX && y>=0 && y<sizeY && z>=0 && z<sizeZ){
|
|
return data[x][y][z].sqdist;
|
|
} else {
|
|
return distanceInCellsValue_Error;
|
|
}
|
|
}
|
|
|
|
template <class TREE>
|
|
int DynamicEDTOctomapBase<TREE>::getSquaredDistanceInCells_unsafe(const octomap::point3d& p) const {
|
|
int x,y,z;
|
|
worldToMap(p, x, y, z);
|
|
return data[x][y][z].sqdist;
|
|
}
|
|
|
|
template <class TREE>
|
|
bool DynamicEDTOctomapBase<TREE>::checkConsistency() const {
|
|
|
|
for(octomap::KeyBoolMap::const_iterator it = octree->changedKeysBegin(), end=octree->changedKeysEnd(); it!=end; ++it){
|
|
//std::cerr<<"Cannot check consistency, you must execute the update() method first."<<std::endl;
|
|
return false;
|
|
}
|
|
|
|
for(int x=0; x<sizeX; x++){
|
|
for(int y=0; y<sizeY; y++){
|
|
for(int z=0; z<sizeZ; z++){
|
|
|
|
octomap::point3d point;
|
|
mapToWorld(x,y,z,point);
|
|
typename TREE::NodeType* node = octree->search(point);
|
|
|
|
bool mapOccupied = isOccupied(x,y,z);
|
|
bool treeOccupied = false;
|
|
if(node){
|
|
treeOccupied = octree->isNodeOccupied(node);
|
|
} else {
|
|
if(unknownOccupied)
|
|
treeOccupied = true;
|
|
}
|
|
|
|
if(mapOccupied != treeOccupied){
|
|
//std::cerr<<"OCCUPANCY MISMATCH BETWEEN TREE AND MAP at "<<x<<","<<y<<","<<z<<std::endl;
|
|
//std::cerr<<"Tree "<<treeOccupied<<std::endl;
|
|
//std::cerr<<"Map "<<mapOccupied<<std::endl;
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|