91eb150ddb
- C3d aggiornamento delle librerie ( 117971).
1825 lines
79 KiB
C++
1825 lines
79 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>
|
|
#include <queue>
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** \brief \ru Базовый интерфейс для вычисления квадрата расстояния до объекта, которому
|
|
принадлежит габаритный куб дерева по указанному индексу.
|
|
\en The base interface for calculating of squared distance to the object from
|
|
the tree's bounding box with specified index. \~
|
|
\ingroup Base_Items
|
|
*/
|
|
// ---
|
|
template <class Point>
|
|
class MbTreeDistanceToElementBase
|
|
{
|
|
public:
|
|
/// \ru Конструктор. \en Constructor.
|
|
MbTreeDistanceToElementBase() {}
|
|
/// \ru Деструктор. \en Destructor.
|
|
virtual ~MbTreeDistanceToElementBase() {}
|
|
|
|
/// \ru Вычислить квадрат расстояния от точки до объекта из габаритного куба. \en Find the squared distance from the point to tree object from bounding box.
|
|
virtual double DistanceToElement2( const Point & pnt, size_t iElem ) const = 0;
|
|
};
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** \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 Number of branches in the tree.
|
|
size_t NodeCount() 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;
|
|
/// \ru Выдать индекс объекта дерева, ближайшего к точке, и квадрат расстояния до него. \en Get tree objects index that are closest to the point, and squared distance to object.
|
|
double FindNearestObject ( const Point & pnt, const MbTreeDistanceToElementBase<Point> & calc, size_t & index ) 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>
|
|
const double MbCubeTree<Type, Cube, Point, Vector>::minDoubleValue( (std::numeric_limits<double>::lowest)() );
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// \ru Максимальное значение double. \en Max double value.
|
|
// ---
|
|
template <class Type, class Cube, class Point, class Vector>
|
|
const double MbCubeTree<Type, Cube, Point, Vector>::maxDoubleValue( (std::numeric_limits<double>::max)() );
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// \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 Number of branches in the tree.
|
|
// ---
|
|
template <class Type, class Cube, class Point, class Vector>
|
|
inline size_t MbCubeTree<Type, Cube, Point, Vector>::NodeCount() const
|
|
{
|
|
size_t count = 0;
|
|
|
|
std::vector<const TypeTree *> stack;
|
|
stack.push_back( this );
|
|
|
|
while ( !stack.empty() ) {
|
|
const TypeTree * ptr = stack.back();
|
|
stack.pop_back();
|
|
++count;
|
|
|
|
if ( ptr->lowerBranch != nullptr )
|
|
stack.push_back( ptr->lowerBranch );
|
|
|
|
if ( ptr->upperBranch != nullptr )
|
|
stack.push_back( ptr->upperBranch );
|
|
|
|
if ( ptr->midstBranch != nullptr )
|
|
stack.push_back( ptr->midstBranch );
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// \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 );
|
|
|
|
double sameEps = std_min( eps, LENGTH_EPSILON );
|
|
sameEps = std_max( sameEps, EXTENT_EPSILON );
|
|
|
|
C3D_ASSERT( !branchCube.IsEmpty() );
|
|
// C3D_ASSERT( !rayPnt1.IsSame( rayPnt2, sameEps ) );
|
|
|
|
if ( isBranch || isLeaf ) {
|
|
if ( !branchCube.IsEmpty() && !rayPnt1.IsSame( rayPnt2, sameEps ) ) {
|
|
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 );
|
|
}
|
|
}
|
|
|
|
bool diffPnt = !segmPnt1.IsSame( segmPnt2, sameEps );
|
|
|
|
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) ) {
|
|
if ( diffPnt ) {
|
|
lowerBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
|
|
}else{
|
|
lowerBranch->GetContainsObjects( segmPnt1, eps, itemIndices );
|
|
}
|
|
}
|
|
if ( (wMax > (midst - eps)) && (upperBranch != nullptr) ) {
|
|
if ( diffPnt ) {
|
|
upperBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
|
|
}
|
|
else {
|
|
upperBranch->GetContainsObjects( segmPnt1, eps, itemIndices );
|
|
}
|
|
}
|
|
if ( (wMax > (lower - eps)) && (wMin < (upper + eps)) && (midstBranch != nullptr) ) {
|
|
if ( diffPnt ) {
|
|
midstBranch->GetIntersectObjects( segmPnt1, segmPnt2, eps, itemIndices );
|
|
}
|
|
else {
|
|
midstBranch->GetContainsObjects( segmPnt1, eps, itemIndices );
|
|
}
|
|
}
|
|
}
|
|
else if ( isLeaf ) { // содержимое конечной ветви // terminal branch content
|
|
|
|
if ( !diffPnt ) {
|
|
GetContainsObjects( segmPnt1, eps, itemIndices );
|
|
return;
|
|
}
|
|
|
|
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 );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//------------------------------------------------------------------------------
|
|
/** \brief \ru Вспомогательная структура для элемента приоритетной очереди.
|
|
\en Auxilliary structure for the priority queue element. \~
|
|
\ingroup Base_Items
|
|
*/
|
|
// ---
|
|
template <class Type>
|
|
struct NodeElem
|
|
{
|
|
const Type * _ptr; ///< \ru Указатель на узел дерева. \en Pointer to the tree node.
|
|
double _weight; ///< \ru Расстояние от куба узла до точки. \en Distance from the node bounding box to the point.
|
|
|
|
/// \ru Конструктор. \en Constructor.
|
|
NodeElem() : _ptr( nullptr ), _weight( MB_MAXDOUBLE ) {}
|
|
/// \ru Конструктор. \en Constructor.
|
|
NodeElem( const Type * ptr, double weigth ) : _ptr( ptr ), _weight( weigth ) {}
|
|
/// \ru Конструктор копирования. \en Copy constructor.
|
|
NodeElem( const NodeElem<Type> & that ) : _ptr( that._ptr ), _weight( that._weight ) {}
|
|
/// \ru Деструктор. \en Destructor.
|
|
~NodeElem() {}
|
|
/// \ru Оператор присваивания. \en An assignment operator.
|
|
NodeElem<Type> & operator = ( const NodeElem<Type> & that )
|
|
{
|
|
_ptr = that._ptr;
|
|
_weight = that._weight;
|
|
return *this;
|
|
}
|
|
/// \ru Оператор сравнения. \en Comparison operator.
|
|
bool operator < ( const NodeElem<Type> & that ) const
|
|
{
|
|
return _weight > that._weight;
|
|
}
|
|
};
|
|
|
|
|
|
//-------------------------------------------------------------------------------
|
|
// \ru Выдать индекс объекта дерева, ближайшего к точке. \en Get tree objects index that are closest to the point.
|
|
// ---
|
|
template <class Type, class Cube, class Point, class Vector>
|
|
double MbCubeTree<Type, Cube, Point, Vector>::FindNearestObject( const Point & pnt, const MbTreeDistanceToElementBase<Point> & calc, size_t & index ) const
|
|
{
|
|
double dist2( MB_MAXDOUBLE );
|
|
index = SYS_MAX_T;
|
|
|
|
std::priority_queue< NodeElem<TypeTree> > queue;
|
|
queue.push( NodeElem<TypeTree>(this, 0.) );
|
|
while ( !queue.empty() ) {
|
|
const NodeElem<TypeTree> node = queue.top(); // Первым рассматриваем узлы, наиболее близкие к точке.
|
|
queue.pop();
|
|
|
|
double d2 = node._ptr->branchCube.DistanceToPoint2( pnt );
|
|
if ( d2 > dist2 )
|
|
break; // Все оставшиеся узлы дальше уже найденного расстояния.
|
|
|
|
if ( ( node._ptr->lowerBranch != nullptr ) || ( node._ptr->upperBranch != nullptr ) || ( node._ptr->midstBranch != nullptr ) ) {
|
|
if ( node._ptr->lowerBranch != nullptr ) {
|
|
d2 = node._ptr->lowerBranch->branchCube.DistanceToPoint2( pnt );
|
|
if ( d2 < dist2 )
|
|
queue.push( NodeElem<TypeTree>( node._ptr->lowerBranch, d2 ) );
|
|
}
|
|
|
|
if ( node._ptr->upperBranch != nullptr ) {
|
|
d2 = node._ptr->upperBranch->branchCube.DistanceToPoint2( pnt );
|
|
if ( d2 < dist2 )
|
|
queue.push( NodeElem<TypeTree>( node._ptr->upperBranch, d2 ) );
|
|
}
|
|
|
|
if ( node._ptr->midstBranch != nullptr ) {
|
|
d2 = node._ptr->midstBranch->branchCube.DistanceToPoint2( pnt );
|
|
if ( d2 < dist2 )
|
|
queue.push( NodeElem<TypeTree>( node._ptr->midstBranch, d2 ) );
|
|
}
|
|
}
|
|
else { // содержимое конечной ветви // terminal branch content
|
|
for ( size_t i = 0, iCount = node._ptr->leafObjects.size(); i < iCount; ++i ) {
|
|
const ItemIndex & obj = node._ptr->leafObjects[i];
|
|
d2 = obj.first->DistanceToPoint2( pnt );
|
|
if ( d2 < dist2 ) {
|
|
d2 = calc.DistanceToElement2( pnt, obj.second );
|
|
if ( d2 < dist2 ) {
|
|
dist2 = d2;
|
|
index = obj.second;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return dist2;
|
|
}
|
|
|
|
#endif
|