905577a744
- C3d aggiornamento delle librerie.
1343 lines
61 KiB
C++
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
|