Files
Extern/C3d/Include/mb_cube_tree.h
T
SaraP b38b0825ee Extern :
- C3d aggiornamento delle librerie ( 114902).
2021-09-28 17:11:24 +02:00

1660 lines
73 KiB
C++

////////////////////////////////////////////////////////////////////////////////
/**
\file
\brief \ru Дерево габаритных кубов.
\en Bounding boxes tree. \~
*/
////////////////////////////////////////////////////////////////////////////////
#ifndef __MB_CUBE_TREE_H
#define __MB_CUBE_TREE_H
#include <system_cpp_standard.h>
#include <vector>
#include <utility>
#include <iterator>
#include <algorithm>
#include <limits>
//------------------------------------------------------------------------------
/** \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", "double Type::DistanceToCube( const Cube & cube, double eps )". \~
\ingroup Base_Items
*/
// ---
template <class Type, class Cube, class Point, class Vector>
class MbCubeTree {
public:
typedef std::pair<const Type *,size_t> ItemIndex;
typedef std::pair<const Type *,const Type *> ItemItem;
typedef std::vector<ItemIndex> ItemIndexVector;
typedef std::pair<const Type *,double> ItemDistance;
typedef std::pair<size_t,double> IndexDistance;
typedef MbCubeTree<Type,Cube,Point,Vector> 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_anyDir = 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_newDir = 4, ///< \ru Нужен выбор оси в зависимости от битового флага. \en Have to select axis by bit flags of branching.
};
// Selected coordinate axis for branching
// ^
// | maximum +-------------+
// | | upperBranch |
// | | |
// | upper +---|-------------|---+
// | | | | |
// | midst --------midstBranch-------- or leafObjects for terminal branch content
// | | | | |
// | lower +---|-------------|---+
// | | |
// | | lowerBranch |
// | minimum +-------------+
// |
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.
Cube branchCube; ///< \ru Габарит ветви. \en Branch bounding box.
ItemIndexVector leafObjects; ///< \ru Объекты c габаритами в конечной ветви (листе). \en Objects (with indices in initial array) in terminal 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.
static size_t treeDepth; ///< \ru Глубина дерева. \en Tree depth.
static size_t leafMinCount; ///< \ru Минимальное количество элементов в конечной ветви. \en The minimum number of elements in the leaf branch.
static const double minDoubleValue; ///< \ru Минимальное значение double. \en Min double value.
static const double maxDoubleValue; ///< \ru Максимальное значение double. \en Max double value.
static const double defaultEpsilon; ///< \ru Точность по умолчанию. \en Default accuracy.
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( 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( 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. \~
*/
bool InitTree( std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm = edm_MaxCoord );
/**
\brief \ru Копировать дерево.
\en Copy the tree. \~
\details \ru Копировать дерево. \n
\en Copy the tree. \n \~
\param[in] srcTree - \ru Исходное дерево.
\en Initial tree. \~
\param[in] copiedObjects - \ru Копии объектов дерева.
\en Copies of tree objects. \~
*/
bool InitTree( const MbCubeTree & srcTree,
const std::vector<ItemIndex> & srcObjects,
const std::vector<ItemIndex> & dstObjects );
/// \ru Очистить дерево. \en Clear the tree.
void Clear();
/// \ru Сдвинуть дерево. \en Move the tree.
void Move( const Vector & );
public:
// функции настроек и состояния дерева / settings and tree state functions
/// \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 depth (shared variable).
size_t GetTreeDepth() const { return treeDepth; };
/// \ru Установить глубину дерева (общая переменная). \en Set tree depth (shared variable).
void SetTreeDepth( size_t k ) { treeDepth = (std::min)( k, (size_t)64 ); }
/// \ru Сбросить глубину дерева (общая переменная). \en Reset tree depth (shared variable).
void ResetTreeDepth() { treeDepth = 64; }
/// \ru Получить минимальное количество элементов в конечной ветви (общая переменная). \en Get a minimum number of elements in the leaf branch (shared variable).
size_t GetLeafMinElementsCount() const { return leafMinCount; }
/// \ru Установить минимальное количество элементов в конечной ветви (общая переменная). \en Set a minimum number of elements in the leaf branch (shared variable).
void SetLeafMinElementsCount( size_t k ) { leafMinCount = (std::max)( k, (size_t)1 ); }
/// \ru Сбросить минимальное количество элементов в конечной ветви (общая переменная). \en Reset the minimum number of elements in the leaf branch (shared variable).
void ResetLeafMinElementsCount() { leafMinCount = 1; }
public:
// функции работы с деревом объектов / public functions for work with objects tree
/// \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,
std::vector<size_t> & 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,
std::vector<size_t> & indices,
bool skipOwnself = false ) const;
/// \ru Выдать пересекающиеся с отрезком луча кубом объекты дерева. \en Get objects of the tree intersecting with the ray segment.
void GetIntersectObjects( const Point & rayPnt1, const Point & rayPnt2, double epsilon,
std::vector<size_t> & indices ) const;
/// \ru Найти ближайший к кубу объект дерева. \en Find the nearest tree object to a bounding box.
void FindNearestObject ( const Cube & gabarit, double & distance,
const Type *& object,
double eps = MbCubeTree::defaultEpsilon ) 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 = MbCubeTree::defaultEpsilon ) const;
/// \ru Найти ближайший к точке объект дерева. \en Find the nearest tree object to a point.
void FindNearestObject ( const Point & pnt, double & distance,
const Type *& object,
double eps = MbCubeTree::defaultEpsilon ) 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 = MbCubeTree::defaultEpsilon ) 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 = MbCubeTree::defaultEpsilon ) 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 = MbCubeTree::defaultEpsilon ) 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 = MbCubeTree::defaultEpsilon ) 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<size_t> & indices,
double eps = MbCubeTree::defaultEpsilon ) const;
private:
// функции инициализация и заполнение ветвей дерева / internal functions for initialization, filling branches
/// \ru Копировать дерево. \en Copy the tree.
bool InitTree( const MbCubeTree & srcTree, const std::vector<ItemItem> & objPair );
/// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
bool InitTree ( std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, unsigned char flag );
/// \ru Заполнение ветвей дерева. \en Fill (set) tree branches.
void SetBranches( std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, unsigned char & flag );
/// \ru Заполнение конечной ветви дерева. \en Fill terminal tree branch.
void FillLeaf( std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a );
/// \ru Установка битового флага flag в зависимости от направления direction. \en Set direction bit flag.
void SetFlag( unsigned char & flag );
/// \ru Получить компонент точки в зависимости от направления direction. \en Get point component by branching direction.
double GetPointComponent( const Point & pnt ) const;
/// \ru Получить компонент точки в зависимости от направления direction. \en Get point component by branching direction.
void GetCubeMinMaxComponents( const Cube & cube, double epsExt, double & wMin, double & wMax ) const;
/// \ru Измерить расстояние по выбранной в мере. \en Measure distance using selected measure type.
double GetDistance( const Type & object, const Point & pnt, bool signedDistance ) const;
/// \ru Функция сравнения - меньше. \en Compare function "Less".
static bool LessPairByFirstItem( const ItemItem & e1, const ItemItem & e2 ) { return (e1.first < e2.first) ? true : false; }
};
//-------------------------------------------------------------------------------
// \ru Глубина дерева. \en Tree depth.
// ---
template <class Type, class Cube, class Point, class Vector>
size_t MbCubeTree<Type, Cube, Point, Vector>::treeDepth( 64 );
//-------------------------------------------------------------------------------
// \ru Минимальное количество элементов в конечной ветви. \en The minimum number of elements in the leaf branch.
// ---
template <class Type, class Cube, class Point, class Vector>
size_t MbCubeTree<Type, Cube, Point, Vector>::leafMinCount( 1 );
//-------------------------------------------------------------------------------
// \ru Минимальное значение double. \en Min double value.
// ---
template <class Type, class Cube, class Point, class Vector>
#ifdef C3D_STANDARD_CXX_11
const double MbCubeTree<Type, Cube, Point, Vector>::minDoubleValue( (std::numeric_limits<double>::lowest)() );
#else
const double MbCubeTree<Type, Cube, Point, Vector>::minDoubleValue( -MB_MAXDOUBLE );
#endif
//-------------------------------------------------------------------------------
// \ru Максимальное значение double. \en Max double value.
// ---
template <class Type, class Cube, class Point, class Vector>
#ifdef C3D_STANDARD_CXX_11
const double MbCubeTree<Type, Cube, Point, Vector>::maxDoubleValue( (std::numeric_limits<double>::max)() );
#else
const double MbCubeTree<Type, Cube, Point, Vector>::maxDoubleValue( MB_MAXDOUBLE );
#endif
//-------------------------------------------------------------------------------
// \ru Точность по умолчанию. \en Default accuracy.
// ---
template <class Type, class Cube, class Point, class Vector>
const double MbCubeTree<Type, Cube, Point, Vector>::defaultEpsilon( 1E-7 );
//-------------------------------------------------------------------------------
// \ru Конструктор дерева по объектам. \en Tree constructor by objects.
// ---
template <class Type, class Cube, class Point, class Vector>
inline MbCubeTree<Type, Cube, Point, Vector>::MbCubeTree( std::vector<ItemIndex> & objects, DistanceMeasure dm )
: midst ( 0.0 )
, minimum ( 0.0 )
, maximum ( 0.0 )
, lower ( 0.0 )
, upper ( 0.0 )
, direction ( eda_anyDir )
, dmType ( dm )
, leafObjects( )
, branchCube ( )
, midstBranch( nullptr )
, lowerBranch( nullptr )
, upperBranch( nullptr )
{
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 != nullptr )
gabarit |= objects[i].first->GetCube();
}
branchCube = gabarit;
InitTree( objects, gabarit, eda_anyDir, 0, 0 );
ResetLeafMinElementsCount();
ResetTreeDepth();
}
}
//-------------------------------------------------------------------------------
// \ru Конструктор дерева по объектам. \en Tree constructor by objects.
// ---
template <class Type, class Cube, class Point, class Vector>
inline MbCubeTree<Type, Cube, Point, Vector>::MbCubeTree( 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_anyDir )
, dmType ( dm )
, leafObjects( )
, branchCube ( gabarit )
, midstBranch( nullptr )
, lowerBranch( nullptr )
, upperBranch( nullptr )
{
C3D_ASSERT( Cube::GetDimension() == Point::GetDimension() );
InitTree( objects, gabarit, eda_anyDir, 0, 0 );
ResetLeafMinElementsCount();
ResetTreeDepth();
}
//-------------------------------------------------------------------------------
// \ru Конструктор дерева. \en Tree constructor.
// ---
template <class Type, class Cube, class Point, class Vector>
inline MbCubeTree<Type, Cube, Point, Vector>::MbCubeTree( DistanceMeasure dm )
: midst ( 0.0 )
, minimum ( 0.0 )
, maximum ( 0.0 )
, lower ( 0.0 )
, upper ( 0.0 )
, direction ( eda_anyDir )
, dmType ( dm )
, leafObjects( )
, branchCube ( )
, midstBranch( nullptr )
, lowerBranch( nullptr )
, upperBranch( nullptr )
{
}
//-------------------------------------------------------------------------------
// \ru Очистить дерево. \en Clear the tree.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::Clear()
{
delete midstBranch;
delete lowerBranch;
delete upperBranch;
midstBranch = lowerBranch = upperBranch = nullptr;
midst = minimum = maximum = lower = upper = 0.0;
direction = eda_anyDir;
branchCube.SetEmpty();
leafObjects.clear();
}
//-------------------------------------------------------------------------------
// \ru Деструктор. \en Destructor.
// ---
template <class Type, class Cube, class Point, class Vector>
inline MbCubeTree<Type, Cube, Point, Vector>::~MbCubeTree()
{
delete midstBranch;
delete lowerBranch;
delete upperBranch;
}
//-------------------------------------------------------------------------------
// \ru Сдвинуть дерево. \en Move the tree.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::Move( const Vector & to )
{
if ( to.MaxFactor() > 0.0 ) {
if ( midstBranch != nullptr )
midstBranch->Move( to );
if ( lowerBranch != nullptr )
lowerBranch->Move( to );
if ( upperBranch != nullptr )
upperBranch->Move( to );
Point pto;
pto.Move( to );
double toValue = GetPointComponent( pto );
midst += toValue;
minimum += toValue;
maximum += toValue;
lower += toValue;
upper += toValue;
branchCube.Move( to );
}
}
//-------------------------------------------------------------------------------
// \ru Копировать дерево. \en Copy the tree.
// ---
template <class Type, class Cube, class Point, class Vector>
inline bool MbCubeTree<Type, Cube, Point, Vector>::InitTree( const MbCubeTree<Type, Cube, Point, Vector> & srcTree, const std::vector<ItemItem> & itemPairs )
{
bool res = true;
midst = srcTree.midst;
minimum = srcTree.minimum;
maximum = srcTree.maximum;
lower = srcTree.lower;
upper = srcTree.upper;
direction = srcTree.direction;
dmType = srcTree.dmType;
branchCube = srcTree.branchCube;
size_t cnt = srcTree.leafObjects.size();
leafObjects.resize( cnt );
typename std::vector<ItemItem>::const_iterator it;
ItemItem itemPair( nullptr, nullptr );
for ( size_t k = 0; k < cnt && res; ++k ) {
res = false;
leafObjects[k].second = srcTree.leafObjects[k].second;
itemPair.first = srcTree.leafObjects[k].first;
it = std::lower_bound( itemPairs.begin(), itemPairs.end(), itemPair, MbCubeTree<Type, Cube, Point, Vector>::LessPairByFirstItem );
if ( it != itemPairs.end() ) {
if ( !MbCubeTree<Type, Cube, Point, Vector>::LessPairByFirstItem( itemPair, *it ) ) {
leafObjects[k].first = it->second;
res = true;
}
}
}
if ( res && (srcTree.midstBranch != nullptr) ) {
C3D_ASSERT( midstBranch == nullptr );
if ( midstBranch == nullptr )
midstBranch = new MbCubeTree<Type, Cube, Point, Vector>( srcTree.midstBranch->dmType );
else
midstBranch->Clear();
res &= midstBranch->InitTree( *srcTree.midstBranch, itemPairs );
}
if ( res && (srcTree.lowerBranch != nullptr) ) {
C3D_ASSERT( lowerBranch == nullptr );
if ( lowerBranch == nullptr )
lowerBranch = new MbCubeTree<Type, Cube, Point, Vector>( srcTree.lowerBranch->dmType );
else
lowerBranch->Clear();
res &= lowerBranch->InitTree( *srcTree.lowerBranch, itemPairs );
}
if ( res && (srcTree.upperBranch != nullptr) ) {
C3D_ASSERT( upperBranch == nullptr );
if ( upperBranch == nullptr )
upperBranch = new MbCubeTree<Type, Cube, Point, Vector>( srcTree.upperBranch->dmType );
else
upperBranch->Clear();
res &= upperBranch->InitTree( *srcTree.upperBranch, itemPairs );
}
return res;
}
//-------------------------------------------------------------------------------
// \ru Копировать дерево. \en Copy the tree.
// ---
template <class Type, class Cube, class Point, class Vector>
inline bool MbCubeTree<Type, Cube, Point, Vector>::InitTree( const MbCubeTree<Type, Cube, Point, Vector> & srcTree,
const std::vector<ItemIndex> & srcItems,
const std::vector<ItemIndex> & dstItems )
{
bool res = false;
Clear();
const size_t itemCnt = srcItems.size();
if ( (itemCnt > 0) && (itemCnt == dstItems.size()) && srcTree.IsReady() && (srcTree.Count() == itemCnt) ) {
res = true;
std::vector< std::pair<const Type *, const Type *> > itemPairs;
itemPairs.resize( itemCnt );
double eps = defaultEpsilon;
size_t k;
for ( k = 0; k < itemCnt; ++k ) {
res = false;
if ( srcItems[k].second == dstItems[k].second ) {
const Type * srcItem = srcItems[k].first;
const Type * dstItem = dstItems[k].first;
if ( (srcItem != dstItem) && (srcItem != nullptr) && (dstItem != nullptr) ) {
if ( srcItem->IsSame( *dstItem, eps ) ) {
itemPairs[k].first = srcItem;
itemPairs[k].second = dstItem;
res = true;
}
}
}
}
if ( res ) {
res = true;
if ( itemPairs.size() > 1 ) {
std::sort( itemPairs.begin(), itemPairs.end() );
itemPairs.erase( std::unique( itemPairs.begin(), itemPairs.end() ), itemPairs.end() );
if ( itemPairs.size() != itemCnt )
res = false;
}
}
if ( res ) {
res = InitTree( srcTree, itemPairs );
}
}
return res;
}
//-------------------------------------------------------------------------------
// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
// ---
template <class Type, class Cube, class Point, class Vector>
inline bool MbCubeTree<Type, Cube, Point, Vector>::InitTree( std::vector<ItemIndex> & objects, const Cube & gabarit, DistanceMeasure dm )
{
bool res = false;
Clear();
dmType = dm;
size_t cnt = objects.size();
C3D_ASSERT( Cube::GetDimension() == Point::GetDimension() );
if ( cnt > 0 ) { // Инициализация дерева
res = InitTree( objects, gabarit, eda_anyDir, 0, 0 );
ResetLeafMinElementsCount();
ResetTreeDepth();
}
return res;
}
//-------------------------------------------------------------------------------
// \ru Инициализация дерева по объектам. \en Initialize tree by objects.
// ---
template <class Type, class Cube, class Point, class Vector>
inline bool MbCubeTree<Type, Cube, Point, Vector>::InitTree( std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, unsigned char flag )
{
bool res = false;
size_t iCount = objects.size();
if ( iCount > 0 ) { // Инициализация дерева / Initialize tree
const double eps = defaultEpsilon;
const size_t gabDim = gabarit.GetDimension();
// slow : memory reallocation
//std::vector< std::pair<double,double> > 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 ) {
res = true;
branchCube = gabarit;
if ( (tier < treeDepth) && (iCount > leafMinCount) ) {
// если ось указана, то следующее разделение должно выполниться по другой оси
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_newDir : { // разделение на ветви по ещё не использованному направлению
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_anyDir) || (a == eda_newDir) ) {
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 );
}
}
}
return res;
}
//-------------------------------------------------------------------------------
// установка ветвей
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::SetBranches( std::vector<ItemIndex> & objects, const Cube & gabarit,
DirectionAxis a, int tier, unsigned char & flag )
{
direction = a;
const size_t iCount = objects.size();
double eps = defaultEpsilon;
GetCubeMinMaxComponents( gabarit, eps, minimum, maximum );
midst = 0.5 * (minimum + maximum); // центральное значение
lower = midst;
upper = midst;
size_t lowerCount = 0;
size_t upperCount = 0;
size_t midstCount = 0;
Cube lowerGabarit;
Cube upperGabarit;
Cube midstGabarit;
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = objects[i];
if ( obj.first != nullptr ) {
const Cube & cube = obj.first->GetCube();
double pMin, pMax;
GetCubeMinMaxComponents( cube, 0.0, pMin, pMax );
if ( pMax < midst - eps ) {
lowerCount++;
lowerGabarit |= cube;
}
else if ( pMin > midst + eps ) {
upperCount++;
upperGabarit |= cube;
}
else {
lower = std_min( lower, pMin );
upper = std_max( upper, pMax );
midstCount++;
midstGabarit |= cube;
}
}
}
std::vector<ItemIndex> lowerArray;
std::vector<ItemIndex> upperArray;
std::vector<ItemIndex> midstArray;
lowerArray.reserve( lowerCount );
upperArray.reserve( upperCount );
midstArray.reserve( midstCount );
// KOMPAS-46058
//size_t iDelta = std_max( (size_t)1, iCount / 8 );
//lowerArray.reserve( iDelta );
//upperArray.reserve( iDelta );
//midstArray.reserve( iDelta );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = objects[i];
if ( obj.first != nullptr ) {
const Cube & cube = obj.first->GetCube();
double pMin, pMax;
GetCubeMinMaxComponents( cube, 0.0, pMin, pMax );
if ( pMax < midst - eps ) { // объект расположен ниже центрального значения
lowerArray.emplace_back( obj );
}
else if ( pMin > midst + eps ) { // объект расположен выше центрального значения
upperArray.emplace_back( obj );
}
else { // объект содержит центральное значение
lower = std_min( lower, pMin );
upper = std_max( upper, pMax );
midstArray.emplace_back( obj );
}
}
}
lower -= eps; // верхний размер центральной ветви, расширенный на погрешность
upper += eps; // нижний размер центральной ветви, расширенный на погрешность
lowerCount = lowerArray.size();
upperCount = upperArray.size();
midstCount = midstArray.size();
if ( (lowerCount > 0) || (upperCount > 0) ) {
if ( lowerCount > 0 ) { // нижняя ветвь / lower branch
C3D_ASSERT ( lowerBranch == nullptr );
if ( lowerBranch == nullptr )
lowerBranch = new MbCubeTree<Type,Cube,Point,Vector>( dmType );
lowerBranch->InitTree( lowerArray, lowerGabarit, eda_anyDir, tier+1, 0 );
lowerArray.clear();
}
if ( upperCount > 0 ) { // верхняя ветвь / upper branch
C3D_ASSERT( upperBranch == nullptr );
if ( upperBranch == nullptr )
upperBranch = new MbCubeTree<Type,Cube,Point,Vector>( dmType );
upperBranch->InitTree( upperArray, upperGabarit, eda_anyDir, tier+1, 0 );
upperArray.clear();
}
if ( midstCount > 0 ) { // центральная ветвь / central branch
C3D_ASSERT( midstBranch == nullptr );
if ( midstBranch == nullptr )
midstBranch = new MbCubeTree<Type,Cube,Point,Vector>( 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 > leafMinCount && freeDir ) {
// установка битового флага flag в зависимости от направления direction
SetFlag( flag );
InitTree( midstArray, midstGabarit, eda_newDir, tier, flag );
midstArray.clear();
}
else { // разделение на ветви не произошло ни по одному направлению
branchCube = gabarit;
leafObjects = std::move( objects );
}
}
}
//-------------------------------------------------------------------------------
// установка битового флага flag в зависимости от направления direction
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::SetFlag( unsigned char & 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 Получить компонент точки в зависимости от направления direction. \en Get point component by branching direction.
// ---
template <class Type, class Cube, class Point, class Vector>
inline double MbCubeTree<Type, Cube, Point, Vector>::GetPointComponent( const Point & pnt ) const
{
double w = minDoubleValue;
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_anyDir : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_newDir : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
return w;
}
//-------------------------------------------------------------------------------
// \ru Получить компонент точки в зависимости от направления direction. \en Get point component by branching direction.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetCubeMinMaxComponents( const Cube & cube, double eps, double & wMin, double & wMax ) const
{
wMin = maxDoubleValue;
wMax = minDoubleValue;
switch ( direction ) {
case eda_axisX: { wMin = cube.GetMin( 0 ) - eps; wMax = cube.GetMax( 0 ) + eps; } break;
case eda_axisY: { wMin = cube.GetMin( 1 ) - eps; wMax = cube.GetMax( 1 ) + eps; } break;
case eda_axisZ: { wMin = cube.GetMin( 2 ) - eps; wMax = cube.GetMax( 2 ) + eps; } break;
case eda_anyDir: { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_newDir: { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
}
//-------------------------------------------------------------------------------
// \ru Заполнение конечной ветви дерева (установка конечной ветви). \en Fill (set) terminal tree branch.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::FillLeaf( std::vector<ItemIndex> & objects, const Cube & gabarit, DirectionAxis a )
{
direction = a;
const double eps = defaultEpsilon;
GetCubeMinMaxComponents( gabarit, eps, minimum, maximum );
midst = 0.5 * (minimum + maximum); // центральное значение
lower = minimum;
upper = maximum;
branchCube = gabarit;
leafObjects = std::move( objects );
}
//-------------------------------------------------------------------------------
// \ru Готово ли дерево. \en Whether tree is ready.
// ---
template <class Type, class Cube, class Point, class Vector>
inline bool MbCubeTree<Type, Cube, Point, Vector>::IsReady() const
{
return ( (midstBranch != nullptr) ||
(lowerBranch != nullptr) ||
(upperBranch != nullptr) ||
(leafObjects.size() > 0) );
}
//-------------------------------------------------------------------------------
// \ru Количество объектов в дереве. \en Number of objects in the tree.
// ---
template <class Type, class Cube, class Point, class Vector>
inline size_t MbCubeTree<Type, Cube, Point, Vector>::Count() const
{
size_t cnt = leafObjects.size();
if ( midstBranch != nullptr )
cnt += midstBranch->Count();
if ( lowerBranch != nullptr )
cnt += lowerBranch->Count();
if ( upperBranch != nullptr )
cnt += upperBranch->Count();
return cnt;
}
//-------------------------------------------------------------------------------
// \ru Выдать содержащие точку объекты дерева. \en Get tree objects containing a point.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetContainsObjects( const Point & pnt, double epsilon,
std::vector<const Type *> & items ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum - epsilon)) || ((maximum + epsilon) < w) )
return; // вне области / out of region
if ( (w < (midst + epsilon)) && (lowerBranch != nullptr) ) {
lowerBranch->GetContainsObjects( pnt, epsilon, items );
}
if ( ((midst - epsilon) < w) && (upperBranch != nullptr) ) {
upperBranch->GetContainsObjects( pnt, epsilon, items );
}
if ( ((lower - epsilon) < w) && (w < (upper + epsilon)) && (midstBranch != nullptr) ) {
midstBranch->GetContainsObjects( pnt, epsilon, items );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetContainsObjects( const Point & pnt, double epsilon,
std::vector<size_t> & indices ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum - epsilon)) || ((maximum + epsilon) < w) )
return; // вне области / out of region
if ( (w < (midst + epsilon)) && (lowerBranch != nullptr) ) {
lowerBranch->GetContainsObjects( pnt, epsilon, indices );
}
if ( ((midst - epsilon) < w) && (upperBranch != nullptr) ) {
upperBranch->GetContainsObjects( pnt, epsilon, indices );
}
if ( ((lower - epsilon) < w) && (w < (upper + epsilon)) && (midstBranch != nullptr) ) {
midstBranch->GetContainsObjects( pnt, epsilon, indices );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetIntersectObjects( const Cube & gabarit, double epsilon,
std::vector<const Type *> & items,
bool skipOwnself ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double wMin, wMax;
GetCubeMinMaxComponents( gabarit, 0.0, wMin, wMax );
if ( (wMax < minimum) || (maximum < wMin) )
return; // вне области / out of region
if ( (wMin < midst) && (lowerBranch != nullptr) ) {
lowerBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (midst < wMax) && (upperBranch != nullptr) ) {
upperBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (lower < wMax) && (wMin < upper) && (midstBranch != nullptr) ) {
midstBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetIntersectObjects( const Cube & gabarit, double epsilon,
std::vector<size_t> & items,
bool skipOwnself ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double wMin, wMax;
GetCubeMinMaxComponents( gabarit, 0.0, wMin, wMax );
if ( (wMax < minimum) || (maximum < wMin) )
return; // вне области / out of region
if ( (wMin < midst) && (lowerBranch != nullptr) ) {
lowerBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (midst < wMax) && (upperBranch != nullptr) ) {
upperBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
if ( (lower < wMax) && (wMin < upper) && (midstBranch != nullptr) ) {
midstBranch->GetIntersectObjects( gabarit, epsilon, items, skipOwnself );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
if ( !skipOwnself || (&gabarit != &static_cast<const Cube &>(obj.first->GetCube()) ) ) { // KOMPAS-20871
if ( obj.first->GetCube().Intersect( gabarit, epsilon ) )
items.push_back( obj.second );
}
}
}
}
}
//-------------------------------------------------------------------------------
// \ru Выдать пересекающиеся с отрезком луча кубом объекты дерева. \en Get objects of the tree intersecting with the ray segment.
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetIntersectObjects( const Point & rayPnt1, const Point & rayPnt2, double eps,
std::vector<size_t> & itemIndices ) const
{
bool isBranch = (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr);
bool isLeaf = !leafObjects.empty();
Point segmPnt1( rayPnt1 ), segmPnt2( rayPnt2 );
double segmLen = segmPnt1.DistanceToPoint( segmPnt2 );
C3D_ASSERT( !branchCube.IsEmpty() );
C3D_ASSERT( !rayPnt1.IsSame( rayPnt2, eps ) );
if ( isBranch || isLeaf ) {
if ( !branchCube.IsEmpty() && !rayPnt1.IsSame( rayPnt2, eps ) ) {
Vector rayVect( rayPnt1, rayPnt2 );
{
double rayLen = rayVect.Length();
rayVect /= rayLen;
}
double minParam = maxDoubleValue;
double maxParam = minDoubleValue;
Point vertPnt;
Vector vertVect;
size_t vertCnt = branchCube.GetVerticesCount();
for ( size_t vertInd = 0; vertInd < vertCnt; ++vertInd ) {
branchCube.GetVertex( vertInd, vertPnt );
vertVect.Init( rayPnt1, vertPnt );
double vt = (rayVect * vertVect);
if ( vt < minParam )
minParam = vt;
if ( vt > maxParam )
maxParam = vt;
}
segmPnt1.Set( rayPnt1, rayVect, minParam );
segmPnt2.Set( rayPnt1, rayVect, maxParam );
segmLen = segmPnt1.DistanceToPoint( segmPnt2 );
}
}
if ( isBranch ) {
double w1 = minDoubleValue;
double w2 = minDoubleValue;
switch ( direction ) {
case eda_axisX : { w1 = segmPnt1[0]; w2 = segmPnt2[0]; } break;
case eda_axisY : { w1 = segmPnt1[1]; w2 = segmPnt2[1]; } break;
case eda_axisZ : { w1 = segmPnt1[2]; w2 = segmPnt2[2]; } break;
case eda_anyDir : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
case eda_newDir : { C3D_ASSERT_UNCONDITIONAL( false ); } break;
default: break;
}
double wMin = std_min( w1, w2 );
double wMax = std_max( w1, w2 );
if ( (wMax < (minimum - eps)) || ((maximum + eps) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst + eps)) && (lowerBranch != nullptr) ) {
lowerBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
}
if ( (wMax > (midst - eps)) && (upperBranch != nullptr) ) {
upperBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
}
if ( (wMax > (lower - eps)) && (wMin < (upper + eps)) && (midstBranch != nullptr) ) {
midstBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
}
}
else if ( isLeaf ) { // содержимое конечной ветви // terminal branch content
const Cube segmCube( segmPnt1, segmPnt2, true );
Point objPnt, segmPnt;
segmPnt.Set( segmPnt1, 0.5, segmPnt2, 0.5 );
Vector vect1, vect2;
size_t iCount = leafObjects.size();
itemIndices.reserve( itemIndices.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
bool add = false;
const Cube & objCube = obj.first->GetCube();
if ( objCube.Contains( segmPnt, eps ) )
add = true;
else if ( objCube.Intersect( segmCube, eps ) ) {
add = true;
if ( segmLen > eps ) {
objCube.GetCenter( objPnt );
double objDist = 0.5 * objCube.GetDiagonal();
vect1.Init( segmPnt1, objPnt );
vect2.Init( segmPnt1, segmPnt2 );
vect2 /= segmLen;
vect2 = (vect1 * vect2) * vect2;
vect1 -= vect2;
double d = ::sqrt( vect1 * vect1 );
if ( d > objDist + eps )
add = false;
}
}
if ( add )
itemIndices.push_back( obj.second );
}
}
}
}
//-------------------------------------------------------------------------------
// Измерить расстояние по выбранной в мере
// ---
template <class Type, class Cube, class Point, class Vector>
inline double MbCubeTree<Type, Cube, Point, Vector>::GetDistance( const Type & object, const Point & pnt, bool signedDistance ) const
{
double d = maxDoubleValue;
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::FindNearestObject( const Cube & gabarit, double & distance, const Type *& item, double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double wMin, wMax;
GetCubeMinMaxComponents( gabarit, 0.0, wMin, wMax );
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->FindNearestObject( gabarit, distance, item, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != nullptr) ) {
upperBranch->FindNearestObject( gabarit, distance, item, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->FindNearestObject( gabarit, distance, item, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::FindNearestObject( const Cube & gabarit, double & distance, size_t & index, double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double wMin, wMax;
GetCubeMinMaxComponents( gabarit, 0.0, wMin, wMax );
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->FindNearestObject( gabarit, distance, index, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != nullptr) ) {
upperBranch->FindNearestObject( gabarit, distance, index, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->FindNearestObject( gabarit, distance, index, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetNearestObjects( const Cube & gabarit, const double distance,
std::vector<IndexDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double wMin, wMax;
GetCubeMinMaxComponents( gabarit, 0.0, wMin, wMax );
if ( (wMax < (minimum-distance)) || ((maximum+distance) < wMin) )
return; // вне области / out of region
if ( (wMin < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
if ( ((midst-distance) < wMax) && (upperBranch != nullptr) ) {
upperBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
if ( ((lower-distance) < wMax) && (wMin < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->GetNearestObjects( gabarit, distance, itemDistances, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::FindNearestObject( const Point & pnt, double & distance, const Type *& item, double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->FindNearestObject( pnt, distance, item, eps );
}
if ( ((midst-distance) < w) && (upperBranch != nullptr) ) {
upperBranch->FindNearestObject( pnt, distance, item, eps );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->FindNearestObject( pnt, distance, item, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
double d = GetDistance( *obj.first, pnt, false );
if ( distance > d - eps ) {
item = obj.first;
distance = d;
}
}
}
}
}
//-------------------------------------------------------------------------------
// Выдать ближайший к точке объект дерева
// ---
template <class Type, class Cube, class Point, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::FindNearestObject( const Point & pnt, double & distance, size_t & index, double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->FindNearestObject( pnt, distance, index, eps );
}
if ( ((midst-distance) < w) && (upperBranch != nullptr) ) {
upperBranch->FindNearestObject( pnt, distance, index, eps );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->FindNearestObject( pnt, distance, index, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
for ( size_t i = 0, iCount = leafObjects.size(); i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetNearestObjects( const Point & pnt, const double distance,
std::vector<ItemDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
if ( ((midst-distance) < w) && (upperBranch != nullptr) ) {
upperBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetNearestObjects( const Point & pnt, const double distance,
std::vector<IndexDistance> & itemDistances,
double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
if ( ((midst-distance) < w) && (upperBranch != nullptr) ) {
upperBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->GetNearestObjects( pnt, distance, itemDistances, eps );
}
}
else { // содержимое конечной ветви // terminal 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 != nullptr ) {
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, class Vector>
inline void MbCubeTree<Type, Cube, Point, Vector>::GetNearestObjects( const Point & pnt, const double distance,
std::vector<size_t> & itemIndices,
double eps ) const
{
if ( (lowerBranch != nullptr) || (upperBranch != nullptr) || (midstBranch != nullptr) ) {
double w = GetPointComponent( pnt );
if ( (w < (minimum-distance)) || ((maximum+distance) < w) )
return; // вне области / out of region
if ( (w < (midst+distance)) && (lowerBranch != nullptr) ) {
lowerBranch->GetNearestObjects( pnt, distance, itemIndices, eps );
}
if ( ((midst-distance) < w) && (upperBranch != nullptr) ) {
upperBranch->GetNearestObjects( pnt, distance, itemIndices, eps );
}
if ( ((lower-distance) < w) && (w < (upper+distance)) && (midstBranch != nullptr) ) {
midstBranch->GetNearestObjects( pnt, distance, itemIndices, eps );
}
}
else { // содержимое конечной ветви // terminal branch content
size_t iCount = leafObjects.size();
itemIndices.reserve( itemIndices.size() + iCount );
for ( size_t i = 0; i < iCount; ++i ) {
const ItemIndex & obj = leafObjects[i];
if ( obj.first != nullptr ) {
double d = GetDistance( *obj.first, pnt, true );
if ( distance > d - eps ) {
itemIndices.push_back( obj.second );
}
}
}
}
}
#endif