Files
Extern/C3d/Include/mb_cube_tree.h
T
Dario Sassi 905577a744 Extern :
- C3d aggiornamento delle librerie.
2020-11-21 18:27:05 +00:00

1343 lines
61 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Дерево габаритных кубов.
\en Bounding boxes tree. \~
*/
////////////////////////////////////////////////////////////////////////////////
#ifndef __MB_CUBE_TREE_H
#define __MB_CUBE_TREE_H
#include <templ_rp_array.h>
#include <templ_s_array.h>
#include <system_dependency.h>
#include <vector>
#include <utility>
//------------------------------------------------------------------------------
/** \brief \ru Дерево объектов с габаритными кубами.
\en Tree of objects with bounding boxes. \~
\details \ru Дерево объектов с габаритными кубами.\n
Oбъекты дерева должны иметь функцию "const Cube & Type::GetCube() const"
и функцию "double Type::DistanceToCube( const Cube & cube, double eps )".
\en Tree of objects with bounding boxes.\n
Tree objects must have functions : "const Cube & Type::GetCube() const"
and "double Type::DistanceToCube( const Cube & cube, double eps )". \~
\ingroup Base_Items
*/
// ---
template <class Type, class Cube, class Point>
class MbCubeTree {
public:
typedef std::pair<const Type *,size_t> ItemIndex;
typedef std::vector<ItemIndex> ItemIndexVector;
typedef std::pair<const Type *,double> ItemDistance;
typedef c3d::IndexDouble IndexDistance;
typedef MbCubeTree<Type,Cube,Point> TypeTree;
/// \ru Тип алгоритма вычисления расстояния от точки до габарита. \en Algorithm type that is used to measure distance between point and bounding box.
enum DistanceMeasure {
edm_MaxCoord = 0, ///< \ru Максимальное расстояние вдоль одной из координатных осей. \en Distance maximum along one of coordinate axes.
edm_CubeCenter, ///< \ru Расстояние до центра габарита объекта. \en Distance to central point of bounding box.
};
/// \ru Битовые флаги направлений ветвления. \en Bit flags of branching directions.
enum BranchingDirections {
ebd_WasDirX = 0x01, ///< \ru Была попытка ветвления по оси Ox. \en An attempt was made to branch along the Ox axis.
ebd_WasDirY = 0x02, ///< \ru Была попытка ветвления по оси Oy. \en An attempt was made to branch along the Oy axis.
ebd_WasDirZ = 0x04, ///< \ru Была попытка ветвления по оси Oz. \en An attempt was made to branch along the Oz axis.
};
private:
/// \ru Координатная ось деления на ветви. \en Selected coordinate axis for branching.
enum DirectionAxis {
eda_anyDirection = 0, ///< \ru Произвольная координатная ось. \en Arbitrarily coordinate axis.
eda_axisX = 1, ///< \ru Координатная ось X. \en Coordinate axis X.
eda_axisY = 2, ///< \ru Координатная ось Y. \en Coordinate axis Y.
eda_axisZ = 3, ///< \ru Координатная ось Z. \en Coordinate axis Z.
eda_needNewDirection = 4, ///< \ru Нужен выбор оси в зависимости от битового флага. \en Have to select axis by bit flags of branching.
};
private:
double midst; ///< \ru Центральное значение по оси direction. \en Central value along "direction" axis.
double minimum; ///< \ru Минимальное значение по оси direction. \en Minimal value along "direction" axis.
double maximum; ///< \ru Максимальное значение по оси direction. \en Maximal value along "direction" axis.
double lower; ///< \ru Размер центральной ветви в сторону увеличения от midst. \en Size of the central branch upward relative to the value of midst.
double upper; ///< \ru Размер центральной ветви в сторону уменьшения от midst. \en Size of the central branch downward relative to the value of midst.
DirectionAxis direction; ///< \ru Направление деления на ветви. \en Branching direction.
DistanceMeasure dmType; ///< \ru Тип расчета расстояния от точки до габарита объекта. \en Distance measurement type between point and bounding box.
ItemIndexVector leafObjects; ///< \ru Объекты c габаритами в конечной ветви (листе). \en Objects (with indices in initial array) in final branch of tree.
TypeTree * midstBranch; ///< \ru Ветвь, элементы которой пересекают центральное значение. \en A branch, whose elements cross the central value.
TypeTree * lowerBranch; ///< \ru Ветвь, элементы которой меньше центрального значения. \en A branch whose elements are smaller than the central value.
TypeTree * upperBranch; ///< \ru Ветвь, элементы которой больше центрального значения. \en A branch whose elements are larger than the central value.
// Selected coordinate axis for branching
// ^
// |
// | maximum +-------------+
// | | upperBranch |
// | | |
// | upper +---|-------------|---+
// | | | | |
// | midst --------midstBranch-------- or leafObjects for final branch content
// | | | | |
// | lower +---|-------------|---+
// | | |
// | | lowerBranch |
// | minimum +-------------+
// |
public:
/**
\brief \ru Конструктор дерева по объектам.
\en Tree constructor by objects. \~
\details \ru Конструктор дерева по объектам. \n
\en Tree constructor by objects. \n \~
\param[in] objects - \ru Объекты дерева.
\en Tree objects. \~
\param[in] dm - \ru Тип вычисления расстояния от точки до габарита.
\en Distance measure type between point and bounding box. \~
*/
MbCubeTree( const std::vector<ItemIndex> & objects, DistanceMeasure dm = edm_MaxCoord );
/**
\brief \ru Конструктор дерева по объектам.
\en Tree constructor by objects. \~
\details \ru Конструктор дерева по объектам. \n
\en Tree constructor by objects. \n \~
\param[in] objects - \ru Объекты дерева.
\en Tree objects. \~
\param[in] gabarit - \ru Общий габарит всех объектов дерева, должен быть не пустым.
\en The total bounding box of all objects in the tree, it must not be empty. \~
\param[in] dm - \ru Тип вычисления расстояния от точки до габарита.
\en Distance measure type between point and bounding box. \~
*/
MbCubeTree( const std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm = edm_MaxCoord );
/**
\brief \ru Конструктор пустого дерева.
\en Constructor of empty tree. \~
\details \ru Конструктор пустого дерева. \n
\en Constructor of empty tree. \n \~
\param[in] dm - \ru Тип вычисления расстояния от точки до габарита.
\en Distance measure type between point and bounding box. \~
*/
MbCubeTree( DistanceMeasure dm = edm_MaxCoord );
private:
MbCubeTree( const MbCubeTree & ); // не реализовано / not implemented
MbCubeTree & operator = ( const MbCubeTree & ); // не реализовано / not implemented
public:
/// \ru Деструктор. \en Destuctror.
~MbCubeTree();
public:
/**
\brief \ru Инициализация дерева по объектам.
\en Initialize tree by objects. \~
\details \ru Инициализация дерева по объектам. \n
\en Initialize tree by objects. \n \~
\param[in] objects - \ru Объекты дерева.
\en Tree objects. \~
\param[in] gabarit - \ru Общий габарит всех объектов дерева, должен быть не пустым.
\en The total bounding box of all objects in the tree, it must not be empty. \~
\param[in] dm - \ru Тип вычисления расстояния от точки до габарита.
\en Distance measure type between point and bounding box. \~
*/
void InitTree( const std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm = edm_MaxCoord );
/// \ru Очистить дерево. \en Clear the tree.
void Clear();
public:
// функции работы с деревом объектов / public functions for work with objects tree
/// \ru Получить тип алгоритма вычисления расстояния от точки до габарита. \en Get algorithm type that is used to measure distance between point and bounding box.
DistanceMeasure GetDistanceMeasure() const { return dmType; }
/// \ru Количество объектов в дереве (не хранит, считает обходом дерева). \en Number of objects in the tree (does not store, tree calculates it by traversing tree nodes).
size_t Count() const;
/// \ru Готово ли дерево. \en Whether tree is ready.
bool IsReady() const;
/// \ru Выдать содержащие точку объекты дерева. \en Get tree objects containing a point.
void GetContainsObjects ( const Point & pnt, double epsilon,
std::vector<const Type *> & objects ) const;
/// \ru Выдать содержащие точку объекты дерева. \en Get tree objects containing a point.
void GetContainsObjects( const Point & pnt, double epsilon,
c3d::IndicesVector & indices ) const;
/// \ru Выдать пересекающиеся с габаритным кубом объекты дерева. \en Get objects of the tree intersecting with the bounding box.
void GetIntersectObjects( const Cube & gabarit, double epsilon,
std::vector<const Type *> & objects,
bool skipOwnself = false ) const;
/// \ru Выдать пересекающиеся с габаритным кубом объекты дерева. \en Get objects of the tree intersecting with the bounding box.
void GetIntersectObjects( const Cube & gabarit, double epsilon,
c3d::IndicesVector & indices,
bool skipOwnself = false ) const;
/// \ru Найти ближайший к кубу объект дерева. \en Find the nearest tree object to a bounding box.
void FindNearestObject ( const Cube & gabarit, double & distance,
const Type *& object,
double eps = METRIC_REGION ) const;
/// \ru Найти ближайший к кубу объект дерева в виде индекса в исходном массиве. \en Find the nearest tree object to a bounding box (as an index in initial array of objects).
void FindNearestObject ( const Cube & gabarit, double & distance,
size_t & index,
double eps = METRIC_REGION ) const;
/// \ru Найти ближайший к точке объект дерева. \en Find the nearest tree object to a point.
void FindNearestObject ( const Point & pnt, double & distance,
const Type *& object,
double eps = PARAM_REGION ) const;
/// \ru Найти ближайший к точке объект дерева в виде индекса в исходном массиве. \en Find the nearest tree object to a point (as an index in initial array of objects).
void FindNearestObject ( const Point & pnt, double & distance,
size_t & index,
double eps = PARAM_REGION ) const;
/// \ru Выдать объекты дерева, расположенные к кубу ближе заданного расстояния. \en Get tree objects that are closer to the cube than the specified distance.
void GetNearestObjects ( const Cube & gabarit, const double distance,
std::vector<IndexDistance> & itemDistances,
double eps = PARAM_REGION ) const;
/// \ru Выдать объекты дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects that are closer to the point than the specified distance.
void GetNearestObjects ( const Point & pnt, const double distance,
std::vector<ItemDistance> & itemDistances,
double eps = PARAM_REGION ) const;
/// \ru Выдать индексы объектов дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects indices that are closer to the point than the specified distance.
void GetNearestObjects ( const Point & pnt, const double distance,
std::vector<IndexDistance> & indexDistances,
double eps = PARAM_REGION ) const;
/// \ru Выдать индексы объектов дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects indices that are closer to the point than the specified distance.
void GetNearestObjects ( const Point & pnt, const double distance,
c3d::IndicesVector & indices,
double eps = PARAM_REGION ) const;
private:
// функции инициализация и заполнение ветвей дерева / internal functions for initialization, filling branches
/// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
void InitTree ( const std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, uint8 flag );
/// \ru Заполнение ветвей дерева. \en Fill (set) tree branches.
void SetBranches( const std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, uint8 & flag );
/// \ru Установка битового флага flag в зависимости от направления direction. \en Set direction bit flag.
void SetFlag( uint8 & flag );
/// \ru Измерить расстояние по выбранной в мере. \en Measure distance using selected measure type.
double GetDistance( const Type & object, const Point & pnt, bool signedDistance ) const;
/// \ru Заполнение конечной ветви дерева. \en Fill final tree branch.
void FillLeaf ( const std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a );
};
//-------------------------------------------------------------------------------
// \ru Конструктор дерева по объектам. \en Tree constructor by objects.
// ---
template <class Type, class Cube, class Point>
inline MbCubeTree<Type, Cube, Point>::MbCubeTree( const std::vector<ItemIndex> & objects, DistanceMeasure dm )
: midst ( 0.0 )
, minimum ( 0.0 )
, maximum ( 0.0 )
, lower ( 0.0 )
, upper ( 0.0 )
, direction ( eda_anyDirection )
, dmType ( dm )
, leafObjects( )
, midstBranch( NULL )
, lowerBranch( NULL )
, upperBranch( NULL )
{
size_t cnt = objects.size();
C3D_ASSERT( Cube::GetDimension() == Point::GetDimension() );
if ( cnt > 0 ) { // Инициализация дерева
Cube gabarit;
for ( size_t i = 0; i < cnt; ++i ) {
if ( objects[i].first != NULL )
gabarit |= objects[i].first->GetCube();
}
InitTree( objects, gabarit, eda_anyDirection, 0, 0 );
}
}
//-------------------------------------------------------------------------------
// \ru Конструктор дерева по объектам. \en Tree constructor by objects.
// ---
template <class Type, class Cube, class Point>
inline MbCubeTree<Type, Cube, Point>::MbCubeTree( const std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm )
: midst ( 0.0 )
, minimum ( 0.0 )
, maximum ( 0.0 )
, lower ( 0.0 )
, upper ( 0.0 )
, direction ( eda_anyDirection )
, dmType ( dm )
, leafObjects( )
, midstBranch( NULL )
, lowerBranch( NULL )
, upperBranch( NULL )
{
C3D_ASSERT( Cube::GetDimension() == Point::GetDimension() );
InitTree( objects, gabarit, eda_anyDirection, 0, 0 );
}
//-------------------------------------------------------------------------------
// \ru Конструктор дерева. \en Tree constructor.
// ---
template <class Type, class Cube, class Point>
inline MbCubeTree<Type, Cube, Point>::MbCubeTree( DistanceMeasure dm )
: midst ( 0.0 )
, minimum ( 0.0 )
, maximum ( 0.0 )
, lower ( 0.0 )
, upper ( 0.0 )
, direction ( eda_anyDirection )
, dmType ( dm )
, leafObjects( )
, midstBranch( NULL )
, lowerBranch( NULL )
, upperBranch( NULL )
{
}
//-------------------------------------------------------------------------------
// \ru Очистить дерево. \en Clear the tree.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::Clear()
{
delete midstBranch;
delete lowerBranch;
delete upperBranch;
midstBranch = lowerBranch = upperBranch = NULL;
midst = minimum = maximum = lower = upper = 0.0;
direction = eda_anyDirection;
leafObjects.clear();
}
//-------------------------------------------------------------------------------
// \ru Деструктор. \en Destructor.
// ---
template <class Type, class Cube, class Point>
inline MbCubeTree<Type, Cube, Point>::~MbCubeTree() {
delete midstBranch;
delete lowerBranch;
delete upperBranch;
}
//-------------------------------------------------------------------------------
// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::InitTree( const std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm )
{
Clear();
dmType = dm;
size_t cnt = objects.size();
C3D_ASSERT( Cube::GetDimension() == Point::GetDimension() );
if ( cnt > 0 ) { // Инициализация дерева
InitTree( objects, gabarit, eda_anyDirection, 0, 0 );
}
}
//-------------------------------------------------------------------------------
// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::InitTree( const std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, uint8 flag )
{
size_t iCount = objects.size();
if ( iCount > 0 ) { // Инициализация дерева / Initialize tree
const double eps = PARAM_REGION;
const size_t gabDim = gabarit.GetDimension();
// slow : memory reallocation
//std::vector<c3d::DoublePair> gabLimits;
//std::vector<double> gabLens;
//gabLimits.reserve( gabDim );
//gabLens.reserve( gabDim );
double gabLens[3];
C3D_ASSERT( gabDim < 4 );
bool validLimits = true;
{
double gabMin, gabMax, gabLen;
for ( size_t i = 0; i < gabDim; ++i ) {
gabMin = gabarit.GetMin(i);
gabMax = gabarit.GetMax(i);
gabLen = gabMax - gabMin;
// slow : memory reallocation
//gabLimits.push_back( std::make_pair( gabMin, gabMax ) );
//gabLens.push_back( gabLen );
//gabLimits[i] = std::make_pair( gabMin, gabMax );
gabLens[i] = gabLen;
validLimits &= (gabLen > -eps);
}
}
if ( validLimits ) {
if ( (tier < c3d::COUNT_BIN) && (iCount > 1) ) {
// если ось указана, то следующее разделение должно выполниться по другой оси
switch ( a ) {
case eda_axisX : { // разделение на ветви по по наиболее вытянутой оси Y или Z
if ( gabDim == 3 ) {
if ( gabLens[1] - eps > gabLens[2] )
SetBranches( objects, gabarit, eda_axisY, tier, flag );
else
SetBranches( objects, gabarit, eda_axisZ, tier, flag );
}
else if ( gabDim == 2 ) {
SetBranches( objects, gabarit, eda_axisY, tier, flag );
}
} break;
case eda_axisY : { // разделение на ветви по по наиболее вытянутой оси Z или X
if ( gabDim == 3 ) {
if ( gabLens[2] - eps > gabLens[0] )
SetBranches( objects, gabarit, eda_axisZ, tier, flag );
else
SetBranches( objects, gabarit, eda_axisX, tier, flag );
}
else if ( gabDim == 2 ) {
SetBranches( objects, gabarit, eda_axisX, tier, flag );
}
} break;
case eda_axisZ : { // разделение на ветви по по наиболее вытянутой оси X или Y
if ( gabDim == 3 ) {
if ( gabLens[0] - eps > gabLens[1] )
SetBranches( objects, gabarit, eda_axisX, tier, flag );
else
SetBranches( objects, gabarit, eda_axisY, tier, flag );
}
else {
C3D_ASSERT_UNCONDITIONAL( false );
}
} break;
case eda_needNewDirection : { // разделение на ветви по ещё не использованному направлению
if ( gabDim == 3 ) {
if ( flag & ebd_WasDirX ) { // попытка разделения по оси X не удалась
if ( gabLens[1] + eps > gabLens[2] && !(flag & ebd_WasDirY) )
SetBranches( objects, gabarit, eda_axisY, tier, flag );
else {
if ( !(flag & ebd_WasDirZ) )
SetBranches( objects, gabarit, eda_axisZ, tier, flag );
else { // исчерпаны все возможности разделения
FillLeaf( objects, gabarit, eda_axisZ );
}
}
}
else if ( flag & ebd_WasDirY ) { // попытка разделения по оси Y не удалась
if ( gabLens[2] - eps > gabLens[0] && !(flag & ebd_WasDirZ) )
SetBranches( objects, gabarit, eda_axisZ, tier, flag );
else
SetBranches( objects, gabarit, eda_axisX, tier, flag );
}
else { // попытка разделения по оси Z не удалась
if ( gabLens[0] + eps > gabLens[1] )
SetBranches( objects, gabarit, eda_axisX, tier, flag );
else
SetBranches( objects, gabarit, eda_axisY, tier, flag );
}
}
else if ( gabDim == 2 ) {
if ( flag & ebd_WasDirX ) { // попытка разделения по оси X не удалась
if ( !(flag & ebd_WasDirY) )
SetBranches( objects, gabarit, eda_axisY, tier, flag );
else { // исчерпаны все возможности разделения
FillLeaf( objects, gabarit, eda_axisY );
}
}
else if ( flag & ebd_WasDirY ) { // попытка разделения по оси Y не удалась
if ( !(flag & ebd_WasDirX) )
SetBranches( objects, gabarit, eda_axisX, tier, flag );
else { // исчерпаны все возможности разделения
FillLeaf( objects, gabarit, eda_axisX );
}
}
}
else {
C3D_ASSERT_UNCONDITIONAL( false );
}
} break;
default : { // разделение на ветви по наиболее вытянутой оси
if ( gabDim == 3 ) {
if ( (gabLens[0] + eps > gabLens[1]) && (gabLens[0] + eps > gabLens[2]) )
SetBranches( objects, gabarit, eda_axisX, tier, flag );
else if ( gabLens[1] + eps > gabLens[2] )
SetBranches( objects, gabarit, eda_axisY, tier, flag );
else
SetBranches( objects, gabarit, eda_axisZ, tier, flag );
}
else if ( gabDim == 2 ) {
if ( gabLens[0] + eps > gabLens[1] )
SetBranches( objects, gabarit, eda_axisX, tier, flag );
else
SetBranches( objects, gabarit, eda_axisY, tier, flag );
}
} break;
}
}
else { // один объект или достигнут максимальный уровень вложенности
if ( (a == eda_anyDirection) || (a == eda_needNewDirection) ) {
if ( gabDim == 3 ) {
if ( (gabLens[0] + eps > gabLens[1]) && (gabLens[0] + eps > gabLens[2]) )
a = eda_axisX;
else if ( gabLens[1] + eps > gabLens[2] )
a = eda_axisY;
else
a = eda_axisZ;
}
else if ( gabDim == 2 ) {
if ( gabLens[0] + eps > gabLens[1] )
a = eda_axisX;
else
a = eda_axisY;
}
}
FillLeaf( objects, gabarit, a );
}
}
}
}
//-------------------------------------------------------------------------------
// установка ветвей
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::SetBranches( const std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, uint8 & flag )
{
direction = a;
const size_t iCount = objects.size();
double eps = PARAM_REGION;
switch ( direction ) {
case eda_axisX : {
minimum = gabarit.GetMin(0) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(0) + eps; // расширение нижней границы на погрешность
} break;
case eda_axisY : {
minimum = gabarit.GetMin(1) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(1) + eps; // расширение нижней границы на погрешность
} break;
case eda_axisZ : {
minimum = gabarit.GetMin(2) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(2) + eps; // расширение нижней границы на погрешность
} break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
midst = 0.5 * (minimum + maximum); // центральное значение
lower = midst;
upper = midst;
size_t iDelta = std_max( (size_t)1, iCount / 8 );
std::vector<ItemIndex> lowerArray;
std::vector<ItemIndex> upperArray;
std::vector<ItemIndex> midstArray;
lowerArray.reserve( iDelta );
upperArray.reserve( iDelta );
midstArray.reserve( iDelta );
Cube lowerGabarit;
Cube upperGabarit;
Cube midstGabarit;
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = objects[i];
if ( obj.first != NULL ) {
const Cube & cube = obj.first->GetCube();
double pMin = UNDEFINED_DBL;
double pMax = UNDEFINED_DBL;
switch ( direction ) {
case eda_axisX : { pMin = cube.GetMin(0); pMax = cube.GetMax(0); } break;
case eda_axisY : { pMin = cube.GetMin(1); pMax = cube.GetMax(1); } break;
case eda_axisZ : { pMin = cube.GetMin(2); pMax = cube.GetMax(2); } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( pMax < midst - eps ) {
lowerArray.push_back( obj ); // объект располагается ниже центрального значения
lowerGabarit |= cube;
}
else if ( pMin > midst + eps ) {
upperArray.push_back( obj ); // объект располагается выше центрального значения
upperGabarit |= cube;
}
else {
lower = std_min( lower, pMin );
upper = std_max( upper, pMax );
midstArray.push_back( obj ); // объект содержит центральное значение
midstGabarit |= cube;
}
}
}
lower -= eps; // верхний размер центральной ветви, расширенный на погрешность
upper += eps; // нижний размер центральной ветви, расширенный на погрешность
size_t lowerCount = lowerArray.size();
size_t upperCount = upperArray.size();
size_t midstCount = midstArray.size();
if ( (lowerCount > 0) || (upperCount > 0) ) {
if ( lowerCount > 0 ) { // нижняя ветвь / lower branch
C3D_ASSERT ( lowerBranch == NULL );
if ( lowerBranch == NULL )
lowerBranch = new MbCubeTree<Type,Cube,Point>( dmType );
lowerBranch->InitTree( lowerArray, lowerGabarit, eda_anyDirection, tier+1, 0 );
lowerArray.clear();
}
if ( upperCount > 0 ) { // верхняя ветвь / upper branch
C3D_ASSERT( upperBranch == NULL );
if ( upperBranch == NULL )
upperBranch = new MbCubeTree<Type,Cube,Point>( dmType );
upperBranch->InitTree( upperArray, upperGabarit, eda_anyDirection, tier+1, 0 );
upperArray.clear();
}
if ( midstCount > 0 ) { // центральная ветвь / central branch
C3D_ASSERT( midstBranch == NULL );
if ( midstBranch == NULL )
midstBranch = new MbCubeTree<Type,Cube,Point>( dmType );
midstBranch->InitTree( midstArray, midstGabarit, direction, tier+1, 0 );
midstArray.clear();
}
}
else { // попытка разделить на ветви по-другому, ещё не использованному направлению
bool freeDir = false;
const size_t gabDim = gabarit.GetDimension();
if ( gabDim == 3 ) {
freeDir = !((flag & ebd_WasDirX) &&
(flag & ebd_WasDirY) &&
(flag & ebd_WasDirZ));
}
else if ( gabDim == 2 ) {
freeDir = !((flag & ebd_WasDirX) &&
(flag & ebd_WasDirY));
}
if ( midstCount > 1 && freeDir ) {
// установка битового флага flag в зависимости от направления direction
SetFlag( flag );
InitTree( midstArray, midstGabarit, eda_needNewDirection, tier, flag );
midstArray.clear();
}
else { // разделение на ветви не произошло ни по одному направлению
leafObjects.reserve( leafObjects.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
if ( objects[i].first != NULL )
leafObjects.push_back( objects[i] );
}
}
}
}
//-------------------------------------------------------------------------------
// установка битового флага flag в зависимости от направления direction
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::SetFlag( uint8 & flag )
{
if ( direction == eda_axisX )
flag |= ebd_WasDirX;
else if ( direction == eda_axisY )
flag |= ebd_WasDirY;
else if ( direction == eda_axisZ )
flag |= ebd_WasDirZ;
}
//-------------------------------------------------------------------------------
// \ru Заполнение конечной ветви дерева (установка конечной ветви). \en Fill (set) final tree branch.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::FillLeaf( const std::vector<ItemIndex> & objects, const Cube & gabarit, DirectionAxis a )
{
direction = a;
const double eps = PARAM_REGION;
switch ( direction ) {
case eda_axisX : {
minimum = gabarit.GetMin(0) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(0) + eps; // расширение нижней границы на погрешность
} break;
case eda_axisY : {
minimum = gabarit.GetMin(1) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(1) + eps; // расширение нижней границы на погрешность
} break;
case eda_axisZ : {
minimum = gabarit.GetMin(2) - eps; // расширение верхней границы на погрешность
maximum = gabarit.GetMax(2) + eps; // расширение нижней границы на погрешность
} break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
midst = 0.5 * (minimum + maximum); // центральное значение
lower = minimum;
upper = maximum;
size_t iCount = objects.size();
leafObjects.reserve( leafObjects.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
if ( objects[i].first != NULL )
leafObjects.push_back( objects[i] );
}
}
//-------------------------------------------------------------------------------
// \ru Готово ли дерево. \en Whether tree is ready.
// ---
template <class Type, class Cube, class Point>
inline bool MbCubeTree<Type, Cube, Point>::IsReady() const
{
return ( (midstBranch != NULL) ||
(lowerBranch != NULL) ||
(upperBranch != NULL) ||
(leafObjects.size() > 0) );
}
//-------------------------------------------------------------------------------
// \ru Количество объектов в дереве. \en Number of objects in the tree.
// ---
template <class Type, class Cube, class Point>
inline size_t MbCubeTree<Type, Cube, Point>::Count() const
{
size_t cnt = leafObjects.size();
if ( midstBranch != NULL )
cnt += midstBranch->Count();
if ( lowerBranch != NULL )
cnt += lowerBranch->Count();
if ( upperBranch != NULL )
cnt += upperBranch->Count();
return cnt;
}
//-------------------------------------------------------------------------------
// \ru Выдать содержащие точку объекты дерева. \en Get tree objects containing a point.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetContainsObjects( const Point & pnt, double epsilon,
std::vector<const Type *> & items ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum - epsilon)) || ((maximum + epsilon) < w) )
return; // вне области / out of region
if ( (w < (midst + epsilon)) && (lowerBranch != NULL) ) {
lowerBranch->GetContainsObjects( pnt, epsilon, items );
}
if ( ((midst - epsilon) < w) && (upperBranch != NULL) ) {
upperBranch->GetContainsObjects( pnt, epsilon, items );
}
if ( ((lower - epsilon) < w) && (w < (upper + epsilon)) && (midstBranch != NULL) ) {
midstBranch->GetContainsObjects( pnt, epsilon, items );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
items.reserve( items.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
if ( obj.first->GetCube().Contains( pnt, epsilon ) )
items.push_back( obj.first );
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать содержащие точку объекты дерева. \en Get tree objects containing a point.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetContainsObjects( const Point & pnt, double epsilon,
c3d::IndicesVector & indices ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX: { w = pnt[0]; } break;
case eda_axisY: { w = pnt[1]; } break;
case eda_axisZ: { w = pnt[2]; } break;
case eda_anyDirection: { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection: { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum - epsilon)) || ((maximum + epsilon) < w) )
return; // вне области / out of region
if ( (w < (midst + epsilon)) && (lowerBranch != NULL) ) {
lowerBranch->GetContainsObjects( pnt, epsilon, indices );
}
if ( ((midst - epsilon) < w) && (upperBranch != NULL) ) {
upperBranch->GetContainsObjects( pnt, epsilon, indices );
}
if ( ((lower - epsilon) < w) && (w < (upper + epsilon)) && (midstBranch != NULL) ) {
midstBranch->GetContainsObjects( pnt, epsilon, indices );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
indices.reserve( indices.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
if ( obj.first->GetCube().Contains( pnt, epsilon ) )
indices.push_back( obj.second );
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать пересекающиеся с габаритным кубом объекты дерева. \en Get objects of the tree intersecting with the bounding box.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetIntersectObjects( const Cube & gabarit, double epsilon,
std::vector<const Type *> & items,
bool skipOwnself ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double wMin = MB_MAXDOUBLE;
double wMax = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { wMin = gabarit.GetMin(0); wMax = gabarit.GetMax(0); } break;
case eda_axisY : { wMin = gabarit.GetMin(1); wMax = gabarit.GetMax(1); } break;
case eda_axisZ : { wMin = gabarit.GetMin(2); wMax = gabarit.GetMax(2); } break;
}
if ( (wMax < minimum) || (maximum < wMin) )
return; // вне области / out of region
if ( (wMin < midst) && (lowerBranch != NULL) ) {
lowerBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (midst < wMax) && (upperBranch != NULL) ) {
upperBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (lower < wMax) && (wMin < upper) && (midstBranch != NULL) ) {
midstBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
items.reserve( items.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
if ( !skipOwnself || (&gabarit != &static_cast<const Cube &>(obj.first->GetCube()) ) ) { // KOMPAS-20871
if ( obj.first->GetCube().Intersect( gabarit, epsilon ) )
items.push_back( obj.first );
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать пересекающиеся с габаритным кубом объекты дерева. \en Get objects of the tree intersecting with the bounding box.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetIntersectObjects( const Cube & gabarit, double epsilon,
c3d::IndicesVector & items,
bool skipOwnself ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double wMin = MB_MAXDOUBLE;
double wMax = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { wMin = gabarit.GetMin(0); wMax = gabarit.GetMax(0); } break;
case eda_axisY : { wMin = gabarit.GetMin(1); wMax = gabarit.GetMax(1); } break;
case eda_axisZ : { wMin = gabarit.GetMin(2); wMax = gabarit.GetMax(2); } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (wMax < minimum) || (maximum < wMin) )
return; // вне области / out of region
if ( (wMin < midst) && (lowerBranch != NULL) ) {
lowerBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (midst < wMax) && (upperBranch != NULL) ) {
upperBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (lower < wMax) && (wMin < upper) && (midstBranch != NULL) ) {
midstBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
items.reserve( items.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
if ( !skipOwnself || (&gabarit != &static_cast<const Cube &>(obj.first->GetCube()) ) ) { // KOMPAS-20871
if ( obj.first->GetCube().Intersect( gabarit, epsilon ) )
items.push_back( obj.second );
}
}
}
}
}
//-------------------------------------------------------------------------------
// Измерить расстояние по выбранной в мере
// ---
template <class Type, class Cube, class Point>
inline double MbCubeTree<Type, Cube, Point>::GetDistance( const Type & object, const Point & pnt, bool signedDistance ) const
{
double d = MB_MAXDOUBLE;
if ( dmType == edm_MaxCoord )
d = object.GetCube().DistanceToPoint( pnt );
else if ( dmType == edm_CubeCenter ) {
Point pnt0;
object.GetCube().GetCenter( pnt0 );
d = pnt0.DistanceToPoint( pnt );
}
if ( !signedDistance )
d = ::fabs(d);
return d;
}
//-------------------------------------------------------------------------------
// \ru Найти ближайший к кубу объект дерева. \en Find the nearest tree object to a bounding box.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::FindNearestObject( const Cube & gabarit, double & distance, const Type *& item, double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double wMin = MB_MAXDOUBLE;
double wMax = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { wMin = gabarit.GetMin(0); wMax = gabarit.GetMax(0); } break;
case eda_axisY : { wMin = gabarit.GetMin(1); wMax = gabarit.GetMax(1); } break;
case eda_axisZ : { wMin = gabarit.GetMin(2); wMax = gabarit.GetMax(2); } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->FindNearestObject( gabarit, distance, item, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != NULL) ) {
upperBranch->FindNearestObject( gabarit, distance, item, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->FindNearestObject( gabarit, distance, item, eps );
}
}
else { // содержимое конечной ветви / final branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = obj.first->GetCube().DistanceToCube( gabarit, eps );
if ( distance > d - eps ) {
item = obj.first;
distance = d;
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Найти ближайший к кубу объект дерева в виде индекса в исходном массиве. \en Find the nearest tree object to a bounding box (as an index in initial array of objects).
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::FindNearestObject( const Cube & gabarit, double & distance, size_t & index, double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double wMin = MB_MAXDOUBLE;
double wMax = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { wMin = gabarit.GetMin(0); wMax = gabarit.GetMax(0); } break;
case eda_axisY : { wMin = gabarit.GetMin(1); wMax = gabarit.GetMax(1); } break;
case eda_axisZ : { wMin = gabarit.GetMin(2); wMax = gabarit.GetMax(2); } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->FindNearestObject( gabarit, distance, index, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != NULL) ) {
upperBranch->FindNearestObject( gabarit, distance, index, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->FindNearestObject( gabarit, distance, index, eps );
}
}
else { // содержимое конечной ветви / final branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = obj.first->GetCube().DistanceToCube( gabarit, eps );
if ( distance > d - eps ) {
index = obj.second;
distance = d;
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать объекты дерева, расположенные к кубу ближе заданного расстояния. \en Get tree objects that are closer to the cube than the specified distance.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetNearestObjects( const Cube & gabarit, const double distance,
std::vector<IndexDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double wMin = MB_MAXDOUBLE;
double wMax = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { wMin = gabarit.GetMin(0); wMax = gabarit.GetMax(0); } break;
case eda_axisY : { wMin = gabarit.GetMin(1); wMax = gabarit.GetMax(1); } break;
case eda_axisZ : { wMin = gabarit.GetMin(2); wMax = gabarit.GetMax(2); } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != NULL) ) {
upperBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
}
else { // содержимое конечной ветви / final branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = obj.first->GetCube().DistanceToCube( gabarit, eps );
if ( distance > d - eps ) {
IndexDistance itemDistance( obj.second, d );
itemDistances.push_back( itemDistance );
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Найти ближайший к точке объект дерева. \en Find the nearest tree object to a point.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::FindNearestObject( const Point & pnt, double & distance, const Type *& item, double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->FindNearestObject( pnt, distance, item );
}
if ( ((midst-distance) < w) && (upperBranch != NULL) ) {
upperBranch->FindNearestObject( pnt, distance, item );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->FindNearestObject( pnt, distance, item );
}
}
else { // содержимое конечной ветви / final branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = GetDistance( *obj.first, pnt, false );
if ( distance > d - eps ) {
item = obj.first;
distance = d;
}
}
}
}
}
//-------------------------------------------------------------------------------
// Выдать ближайший к точке объект дерева
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::FindNearestObject( const Point & pnt, double & distance, size_t & index, double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->FindNearestObject( pnt, distance, index );
}
if ( ((midst-distance) < w) && (upperBranch != NULL) ) {
upperBranch->FindNearestObject( pnt, distance, index );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->FindNearestObject( pnt, distance, index );
}
}
else { // содержимое конечной ветви / final branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = GetDistance( *obj.first, pnt, false );
if ( distance > d - eps ) {
index = obj.second;
distance = d;
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать объекты дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects that are closer to the point than the specified distance.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetNearestObjects( const Point & pnt, const double distance,
std::vector<ItemDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((midst-distance) < w) && (upperBranch != NULL) ) {
upperBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->GetNearestObjects( pnt, distance, itemDistances );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
itemDistances.reserve( itemDistances.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = GetDistance( *obj.first, pnt, true );
if ( distance > d - eps ) {
ItemDistance itemDistance( obj.first, d );
itemDistances.push_back( itemDistance );
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать индексы объектов дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects indices that are closer to the point than the specified distance.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetNearestObjects( const Point & pnt, const double distance,
std::vector<IndexDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((midst-distance) < w) && (upperBranch != NULL) ) {
upperBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->GetNearestObjects( pnt, distance, itemDistances );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
itemDistances.reserve( itemDistances.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = GetDistance( *obj.first, pnt, true );
if ( distance > d - eps ) {
IndexDistance itemDistance( obj.second, d );
itemDistances.push_back( itemDistance );
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать индексы объектов дерева, расположенные к точке ближе заданного расстояния. \en Get tree objects indices that are closer to the point than the specified distance.
// ---
template <class Type, class Cube, class Point>
inline void MbCubeTree<Type, Cube, Point>::GetNearestObjects( const Point & pnt, const double distance,
c3d::IndicesVector & itemDistances,
double eps ) const
{
if ( (lowerBranch != NULL) || (upperBranch != NULL) || (midstBranch != NULL) ) {
double w = -MB_MAXDOUBLE;
switch ( direction ) {
case eda_axisX : { w = pnt[0]; } break;
case eda_axisY : { w = pnt[1]; } break;
case eda_axisZ : { w = pnt[2]; } break;
case eda_anyDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_needNewDirection : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != NULL) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((midst-distance) < w) && (upperBranch != NULL) ) {
upperBranch->GetNearestObjects( pnt, distance, itemDistances );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != NULL) ) {
midstBranch->GetNearestObjects( pnt, distance, itemDistances );
}
}
else { // содержимое конечной ветви / final branch content
size_t iCount = leafObjects.size();
itemDistances.reserve( itemDistances.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != NULL ) {
double d = GetDistance( *obj.first, pnt, true );
if ( distance > d - eps ) {
itemDistances.push_back( obj.second );
}
}
}
}
}
#endif