Files
opennurbs/opennurbs_rtree.cpp
2018-09-10 17:39:40 -07:00

3911 lines
112 KiB
C++

/* $NoKeywords: $ */
/*
//
// Copyright (c) 1993-2012 Robert McNeel & Associates. All rights reserved.
// OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert
// McNeel & Associates.
//
// THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.
// ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF
// MERCHANTABILITY ARE HEREBY DISCLAIMED.
//
// For complete openNURBS copyright information see <http://www.opennurbs.org>.
//
////////////////////////////////////////////////////////////////
*/
#include "opennurbs.h"
#if !defined(ON_COMPILING_OPENNURBS)
// This check is included in all opennurbs source .c and .cpp files to insure
// ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled.
// When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined
// and the opennurbs .h files alter what is declared and how it is declared.
#error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs
#endif
// Dimension of tree bounding boxes
#define ON_RTree_NODE_DIM 3
/// A link list of nodes for reinsertion after a delete operation
struct ON_RTreeListNode
{
struct ON_RTreeListNode* m_next; ///< Next in list
struct ON_RTreeNode* m_node; ///< ON_RTreeNode
};
/// Variables for finding a split partition
struct ON_RTreePartitionVars
{
int m_partition[ON_RTree_MAX_NODE_COUNT+1];
int m_total;
int m_minFill;
int m_taken[ON_RTree_MAX_NODE_COUNT+1];
int m_count[2];
ON_RTreeBBox m_cover[2];
double m_area[2];
ON_RTreeBranch m_branchBuf[ON_RTree_MAX_NODE_COUNT+1];
int m_branchCount;
ON_RTreeBBox m_coverSplit;
double m_coverSplitArea;
};
typedef bool (*ON_RTreeSearchCallback)(void* a_context, ON__INT_PTR a_id );
struct ON_RTreeSearchResultCallback
{
void* m_context;
ON_RTreeSearchCallback m_resultCallback;
};
static void ChoosePartition(ON_RTreePartitionVars* a_parVars, int a_minFill);
static void CountRec(ON_RTreeNode* a_node, int& a_count);
static void PickSeeds(ON_RTreePartitionVars* a_parVars);
static void InitParVars(ON_RTreePartitionVars* a_parVars, int a_maxRects, int a_minFill);
static void GetBranches(ON_RTreeNode* a_node, ON_RTreeBranch* a_branch, ON_RTreePartitionVars* a_parVars);
static int PickBranch(ON_RTreeBBox* a_rect, ON_RTreeNode* a_node);
static void DisconnectBranch(ON_RTreeNode* a_node, int a_index);
static ON_RTreeBBox NodeCover(ON_RTreeNode* a_node);
static void InitRect(ON_RTreeBBox* a_rect);
static ON_RTreeBBox CombineRectHelper(const ON_RTreeBBox* a_rectA, const ON_RTreeBBox* a_rectB);
static double CalcRectVolumeHelper(const ON_RTreeBBox* a_rect);
static bool OverlapHelper(const ON_RTreeBBox* a_rectA, const ON_RTreeBBox* a_rectB);
static double DistanceToCapsuleAxisHelper(const struct ON_RTreeCapsule* a_capsule, const ON_RTreeBBox* a_rect);
static void ClassifyHelper(int a_index, int a_group, struct ON_RTreePartitionVars* a_parVars);
static bool SearchHelper(const ON_RTreeNode* a_node, ON_RTreeBBox* a_rect, ON_RTreeSearchResultCallback& a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_RTreeSearchResult& a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<ON_RTreeLeaf> &a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<int> &a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<void*> &a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, struct ON_RTreeSphere* a_sphere, ON_RTreeSearchResultCallback& a_result );
static bool SearchHelper(const ON_RTreeNode* a_node, struct ON_RTreeCapsule* a_capsule, ON_RTreeSearchResultCallback& a_result );
////////////////////////////////////////////////////////////////
//
// ON_RTreeMemPool
//
size_t ON_MemoryPageSize()
{
#if defined(ON_COMPILER_MSC)
static size_t pagesize = 0;
if ( 0 == pagesize )
{
SYSTEM_INFO system_info;
memset(&system_info,0,sizeof(system_info));
::GetSystemInfo(&system_info);
pagesize = system_info.dwPageSize;
if ( pagesize <= 0 )
pagesize = 4096;
}
return pagesize;
#else
return 4096;
#endif
}
static size_t SizeofBlkLink()
{
// Room to reserve for struct ON_RTreeMemPool::Blk.
// This number should be >= sizeof(struct ON_RTreeMemPool::Blk)
// and a multiple of 16 to insure proper alignment on all CPUs.
return 16;
}
static size_t MemPoolBlkSize( size_t leaf_count )
{
// sizeof_blklink = number of bytes to reserve for the
// struct ON_RTreeMemPool::Blk header used to keep track
// of our allocations.
const size_t sizeof_blklink = SizeofBlkLink();
// pagesize = OS memory manager page size. We want the
// allocated blocks to be some smallish mulitples of pagesize
// to the active sections of the tree will end up in CPU cache
// when the tree is being repeatedly searched.
size_t pagesize = ON_MemoryPageSize();
if ( pagesize <= sizeof_blklink )
pagesize = 4096;
size_t node_count = 32;
if ( leaf_count > 0 )
{
// When the user can estimate the number of leaves,
// node_count is an estimate of the number of nodes needed
// to build the tree. When node_count is small, we avoid
// allocating too much memory for a tiny tree. The goal
// is to avoid wasting lots of memory when there are thousands
// of individual trees, most with a less than six leaves.
// If there are only a few trees, or most of the trees have
// lots of leaves, then hard coding node_count = 32 works
// just fine.
if ( 5*leaf_count < 4*ON_RTree_MAX_NODE_COUNT )
node_count = 3;
else if ( 5*leaf_count < 4*ON_RTree_MAX_NODE_COUNT*ON_RTree_MAX_NODE_COUNT )
node_count = ON_RTree_MAX_NODE_COUNT+1;
}
// Set "sz" to an multiple of pagesize that is big enough
// to hold node_count nodes.
const size_t sizeof_node = sizeof(ON_RTreeNode);
size_t sz = pagesize;
size_t nodes_per_blk = ( node_count < 32 )
? node_count
: (sz-sizeof_blklink)/sizeof_node;
while ( nodes_per_blk < node_count )
{
sz += pagesize;
nodes_per_blk = (sz-sizeof_blklink)/sizeof_node;
}
// Some lame allocators pad each allocation request and use the extra space
// to store allocation bookkeeping information. The "+ 2*sizeof(void*) allows
// for up to two pointers of "lame" system overhead per allocation. The goal
// is to prevent the "real" allocation from being just a hair bigger that a
// multiple of pagesize.
if ( sz < sizeof_blklink + nodes_per_blk*sizeof_node + 2*sizeof(void*) )
nodes_per_blk--; // prevent memory manager overhead from allocating another page
// Return the minimum number of bytes we need for each block. An decent
// OS should assign this allocation an efficient set of pages.
return (sizeof_blklink + nodes_per_blk*sizeof_node);
}
ON_RTreeMemPool::ON_RTreeMemPool( size_t leaf_count )
: m_nodes(0)
, m_list_nodes(0)
, m_buffer(0)
, m_buffer_capacity(0)
, m_blk_list(0)
, m_sizeof_blk(0)
, m_sizeof_heap(0)
{
m_sizeof_blk = MemPoolBlkSize(leaf_count);
}
ON_RTreeMemPool::~ON_RTreeMemPool()
{
DeallocateAll();
}
void ON_RTreeMemPool::GrowBuffer()
{
if ( (0 == m_sizeof_blk) || (0 != m_blk_list && 0 == m_blk_list->m_next) )
{
// Setting m_sizeof_blk happens twice per ON_RTreeMemPool.
// The first time is typically at construction and not here.
// The (0 == m_sizeof_blk) check is here to support cases
// where the ON_RTreeMemPool class is initialized by a "memset(...,0)
// instead of calling its constructor. The first block can be small
// if the caller passed in a leaf_count estimate. For the second
// (0 != m_blk_list && 0 == m_blk_list->m_next) and subsequent calls
// to GrowBuffer(), we use the default block size.
m_sizeof_blk = MemPoolBlkSize(0);
}
struct Blk* blk = (struct Blk*)onmalloc(m_sizeof_blk);
if ( blk )
{
m_sizeof_heap += m_sizeof_blk;
blk->m_next = m_blk_list;
m_blk_list = blk;
const size_t sizeof_blklink = SizeofBlkLink();
m_buffer = ((unsigned char*)m_blk_list) + sizeof_blklink;
m_buffer_capacity = m_sizeof_blk - sizeof_blklink;
}
else
{
m_buffer = 0;
m_buffer_capacity = 0;
ON_ERROR("ON_RTreeMemPool::GrowBuffer - out of memory");
}
}
ON_RTreeNode* ON_RTreeMemPool::AllocNode()
{
ON_RTreeNode* node = (ON_RTreeNode*)m_nodes;
if ( node )
{
m_nodes = m_nodes->m_next;
}
else
{
const size_t node_sz = sizeof(*node);
if ( m_buffer_capacity < node_sz )
GrowBuffer();
if ( 0 == (node = (ON_RTreeNode*)m_buffer) )
{
ON_ERROR("ON_RTreeMemPool::AllocNode() - out of memory");
return 0;
}
m_buffer += node_sz;
m_buffer_capacity -= node_sz;
}
// initialize node
node->m_count = 0;
node->m_level = -1;
return node;
}
void ON_RTreeMemPool::FreeNode(ON_RTreeNode* node)
{
if ( node )
{
struct Blk* blk = (struct Blk*)node;
blk->m_next = m_nodes;
m_nodes = blk;
}
}
struct ON_RTreeListNode* ON_RTreeMemPool::AllocListNode()
{
struct ON_RTreeListNode* list_node = (struct ON_RTreeListNode*)m_list_nodes;
if ( list_node )
{
m_list_nodes = m_list_nodes->m_next;
}
else
{
size_t list_node_sz = sizeof(*list_node);
if ( m_buffer_capacity < list_node_sz )
{
GrowBuffer();
}
list_node = (struct ON_RTreeListNode*)m_buffer;
if ( list_node )
{
m_buffer += list_node_sz;
m_buffer_capacity -= list_node_sz;
}
}
return list_node;
}
void ON_RTreeMemPool::FreeListNode(struct ON_RTreeListNode* list_node)
{
if ( list_node )
{
struct Blk* blk = (struct Blk*)list_node;
blk->m_next = m_list_nodes;
m_list_nodes = blk;
}
}
size_t ON_RTreeMemPool::SizeOf() const
{
return m_sizeof_heap;
}
size_t ON_RTreeMemPool::SizeOfUnusedBuffer() const
{
const struct Blk* blk;
size_t sz = m_buffer_capacity;
for ( blk = m_nodes; blk; blk = blk->m_next )
{
sz += sizeof(struct ON_RTreeNode);
}
for ( blk = m_list_nodes; blk; blk = blk->m_next )
{
sz += sizeof(struct ON_RTreeListNode);
}
return sz;
}
void ON_RTreeMemPool::DeallocateAll()
{
struct Blk* p = m_blk_list;
if (nullptr != p)
{
m_nodes = nullptr;
m_list_nodes = nullptr;
m_buffer = nullptr;
m_buffer_capacity = 0;
m_blk_list = nullptr;
m_sizeof_blk = 0;
m_sizeof_heap = 0;
while (p)
{
struct Blk* next = p->m_next;
onfree(p);
p = next;
}
}
}
////////////////////////////////////////////////////////////////
//
// ON_RTreeIterator
//
ON_RTreeIterator::ON_RTreeIterator()
{
Initialize(0);
}
ON_RTreeIterator::ON_RTreeIterator(const class ON_RTree& rtree)
{
Initialize(rtree);
}
ON_RTreeIterator::~ON_RTreeIterator()
{
}
const ON_RTreeBranch* ON_RTreeIterator::Value() const
{
return ( 0 != m_sp )
? &m_sp->m_node->m_branch[m_sp->m_branchIndex]
: 0;
}
bool ON_RTreeIterator::Initialize(const ON_RTree& a_rtree)
{
return Initialize(a_rtree.Root());
}
bool ON_RTreeIterator::Initialize(const ON_RTreeNode* a_node)
{
m_sp = 0;
m_root = ( 0 != a_node && a_node->m_count > 0 ) ? a_node : 0;
return First();
}
bool ON_RTreeIterator::PushChildren(StackElement* sp, bool bFirstChild )
{
StackElement* spmax = &m_stack[0] + MAX_STACK;
const ON_RTreeNode* node = sp->m_node;
m_sp = 0;
// push first leaf coverted by this node onto the stack
while( 0 != node && node->m_level >= 0 && node->m_count > 0 )
{
if ( 0 == node->m_level )
{
m_sp = sp;
return true;
}
node = node->m_branch[sp->m_branchIndex].m_child;
if( ++sp == spmax )
{
// Either this is a GIGANTIC R-tree, or, more likely, there is
// a bug in the code that creates the R-tree and this R-tree
// is horribly unbalanced. If the case is valid, then we must
// increase MAX_STACK and ship a service release.
ON_ERROR("ON_RTreeIterator::PushFirstChild - stack overflow");
return false;
}
sp->m_node = node;
sp->m_branchIndex = bFirstChild ? 0 : node->m_count-1; // 0 for first child
}
return false;
}
bool ON_RTreeIterator::First()
{
m_sp = 0;
if ( 0 == m_root || m_root->m_level < 0 || m_root->m_count <= 0 )
return false;
m_stack[0].m_node = m_root;
m_stack[0].m_branchIndex = 0;
return PushChildren(&m_stack[0],true);
}
bool ON_RTreeIterator::Last()
{
m_sp = 0;
if ( 0 == m_root || m_root->m_level < 0 || m_root->m_count <= 0 )
return false;
m_stack[0].m_node = m_root;
m_stack[0].m_branchIndex = m_root->m_count - 1;
return PushChildren(&m_stack[0],false);
}
bool ON_RTreeIterator::Next()
{
if ( 0 == m_sp )
return false; // invalid iterator
if ( ++(m_sp->m_branchIndex) < m_sp->m_node->m_count )
return true; // m_sp->m_node is always at leaf level
// pop the stack until we find an element with room to move over.
StackElement* sp0 = &m_stack[0];
StackElement* sp = m_sp;
m_sp = 0;
while ( sp > sp0 )
{
sp--; // pop the stack
// ++(sp->m_branchIndex) moves to the next element in sp->m_node.
if ( ++(sp->m_branchIndex) >= sp->m_node->m_count )
continue; // this element is used up
// Since we've popped the stack, we cannot be at the leaf level.
// PushFirst() pushes the first child onto the stack until
// it reaches the leaf level.
return PushChildren(sp,true);
}
return false; // we were at the last element and now there are no more.
}
bool ON_RTreeIterator::Prev()
{
if ( 0 == m_sp )
return false; // invalid iterator
if ( --(m_sp->m_branchIndex) >= 0 )
return true; // m_sp->m_node is always at leaf level
// pop the stack until we find an element with room to move over.
StackElement* sp0 = &m_stack[0];
StackElement* sp = m_sp;
m_sp = 0;
while ( sp > sp0 )
{
sp--; // pop the stack
// --(sp->m_branchIndex) moves to the previous element in sp->m_node.
if ( --(sp->m_branchIndex) < 0 )
continue; // this element is used up
// Since we've popped the stack, we cannot be at the leaf level.
// PushFirst() pushes the first child onto the stack until
// it reaches the leaf level.
return PushChildren(sp,false);
}
return false; // we were at the last element and now there are no more.
}
////////////////////////////////////////////////////////////////
//
// ON_RTree
//
ON_RTree::ON_RTree( size_t leaf_count )
: m_root(0)
, m_reserved(0)
, m_mem_pool(leaf_count)
{
}
ON_RTree::~ON_RTree()
{
RemoveAll();
}
bool ON_RTree::CreateMeshFaceTree( const ON_Mesh* mesh )
{
double fmin[3], fmax[3];
ON_3dPoint V;
unsigned int fi, fcount;
const int* fvi;
const ON_MeshFace* meshF;
const ON_3fPoint* meshfV;
const ON_3dPoint* meshdV;
RemoveAll();
if ( 0 == mesh )
return false;
fcount = mesh->m_F.UnsignedCount();
if ( fcount <= 0 )
return false;
meshF = mesh->m_F.Array();
if ( 0 == meshF )
return false;
meshfV = mesh->m_V.Array();
meshdV = mesh->HasDoublePrecisionVertices()
? mesh->DoublePrecisionVertices().Array()
: 0;
if ( 0 != meshfV )
{
if ( 0 != meshdV )
{
for ( fi = 0; fi < fcount; fi++ )
{
fvi = meshF[fi].vi;
V = meshfV[fvi[0]];
fmin[0] = fmax[0] = V.x;
fmin[1] = fmax[1] = V.y;
fmin[2] = fmax[2] = V.z;
V = meshdV[fvi[0]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshfV[fvi[1]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshdV[fvi[1]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshfV[fvi[2]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshdV[fvi[2]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
if ( fvi[2] != fvi[3] )
{
V = meshfV[fvi[3]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshdV[fvi[3]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
}
if ( !Insert(fmin,fmax,fi) )
{
RemoveAll();
return false;
}
}
}
else
{
for ( fi = 0; fi < fcount; fi++ )
{
fvi = meshF[fi].vi;
V = meshfV[fvi[0]];
fmin[0] = fmax[0] = V.x;
fmin[1] = fmax[1] = V.y;
fmin[2] = fmax[2] = V.z;
V = meshfV[fvi[1]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshfV[fvi[2]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
if ( fvi[2] != fvi[3] )
{
V = meshfV[fvi[3]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
}
if ( !Insert(fmin,fmax,fi) )
{
RemoveAll();
return false;
}
}
}
}
else if ( 0 != meshdV )
{
for ( fi = 0; fi < fcount; fi++ )
{
fvi = meshF[fi].vi;
V = meshdV[fvi[0]];
fmin[0] = fmax[0] = V.x;
fmin[1] = fmax[1] = V.y;
fmin[2] = fmax[2] = V.z;
V = meshdV[fvi[1]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
V = meshdV[fvi[2]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
if ( fvi[2] != fvi[3] )
{
V = meshdV[fvi[3]];
if ( V.x < fmin[0] ) fmin[0] = V.x; else if ( V.x > fmax[0] ) fmax[0] = V.x;
if ( V.y < fmin[1] ) fmin[1] = V.y; else if ( V.y > fmax[1] ) fmax[1] = V.y;
if ( V.z < fmin[2] ) fmin[2] = V.z; else if ( V.z > fmax[2] ) fmax[2] = V.z;
}
if ( !Insert(fmin,fmax,fi) )
{
RemoveAll();
return false;
}
}
}
else
{
// no vertices
return false;
}
return (0 != m_root);
}
bool ON_RTree::Insert2d(const double a_min[2], const double a_max[2], int a_element_id)
{
const double min3d[3] = {a_min[0],a_min[1],0.0};
const double max3d[3] = {a_max[0],a_max[1],0.0};
return Insert(min3d,max3d,a_element_id);
}
bool ON_RTree::Insert(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM], int a_element_id)
{
bool rc;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
if ( rect.m_min[0] <= rect.m_max[0] && rect.m_min[1] <= rect.m_max[1] && rect.m_min[2] <= rect.m_max[2] )
{
if ( 0 == m_root )
{
m_root = m_mem_pool.AllocNode();
m_root->m_level = 0;
}
InsertRect(&rect, a_element_id, &m_root, 0);
rc = true;
}
else
{
// invalid bounding box - don't let this corrupt the tree
rc = false;
ON_ERROR("ON_RTree::Insert - invalid a_min[] or a_max[] input.");
}
return rc;
}
bool ON_RTree::Insert2d(const double a_min[2], const double a_max[2], void* a_element_id)
{
const double min3d[3] = {a_min[0],a_min[1],0.0};
const double max3d[3] = {a_max[0],a_max[1],0.0};
return Insert(min3d,max3d,a_element_id);
}
bool ON_RTree::Insert(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM], void* a_element_id)
{
bool rc;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
if ( rect.m_min[0] <= rect.m_max[0] && rect.m_min[1] <= rect.m_max[1] && rect.m_min[2] <= rect.m_max[2] )
{
if ( 0 == m_root )
{
m_root = m_mem_pool.AllocNode();
m_root->m_level = 0;
}
// The ON__INT_PTR cast is safe because ON__INT_PTR == sizeof(void*)
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_PUSH
// Disable warning C4311: 'type cast' : pointer truncation from 'void *' to 'ON__INT_PTR'
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4311 )
#endif
InsertRect(&rect, (ON__INT_PTR)a_element_id, &m_root, 0);
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_POP
#endif
rc = true;
}
else
{
// invalid bounding box - don't let this corrupt the tree
rc = false;
ON_ERROR("ON_RTree::Insert - invalid a_min[] or a_max[] input.");
}
return rc;
}
bool ON_RTree::Remove2d(const double a_min[2], const double a_max[2], int a_dataId)
{
const double min3d[3] = {a_min[0],a_min[1],0.0};
const double max3d[3] = {a_max[0],a_max[1],0.0};
return Remove(min3d,max3d,a_dataId);
}
bool ON_RTree::Remove(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM], int a_dataId)
{
bool rc = false;
if ( 0 != m_root )
{
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
if ( rect.m_min[0] <= rect.m_max[0] && rect.m_min[1] <= rect.m_max[1] && rect.m_min[2] <= rect.m_max[2] )
{
// RemoveRect() returns 0 on success
rc = (0 == RemoveRect(&rect, a_dataId, &m_root));
}
else
{
// invalid bounding box - don't let this corrupt the tree
ON_ERROR("ON_RTree::Remove - invalid a_min[] or a_max[] input.");
}
}
return rc;
}
bool ON_RTree::Remove2d(const double a_min[2], const double a_max[2], void* a_dataId)
{
const double min3d[3] = {a_min[0],a_min[1],0.0};
const double max3d[3] = {a_max[0],a_max[1],0.0};
return Remove(min3d,max3d,a_dataId);
}
bool ON_RTree::Remove(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM], void* a_dataId)
{
bool rc = false;
if ( 0 != m_root )
{
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
if ( rect.m_min[0] <= rect.m_max[0] && rect.m_min[1] <= rect.m_max[1] && rect.m_min[2] <= rect.m_max[2] )
{
// RemoveRect() returns 0 on success
// The ON__INT_PTR cast is save because ON__INT_PTR == sizeof(void*)
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_PUSH
// Disable warning C4311: 'type cast' : pointer truncation from 'void *' to 'ON__INT_PTR'
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4311 )
#endif
rc = (0 == RemoveRect(&rect, (ON__INT_PTR)a_dataId, &m_root));
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_POP
#endif
}
else
{
// invalid bounding box - don't let this corrupt the tree
ON_ERROR("ON_RTree::Remove - invalid a_min[] or a_max[] input.");
}
}
return rc;
}
bool ON_RTree::Search2d(
const double a_min[2], const double a_max[2],
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_data),
void* a_context
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,2*sizeof(a_min[0]));
rect.m_min[2] = 0.0;
memcpy(rect.m_max,a_max,2*sizeof(a_max[0]));
rect.m_max[2] = 0.0;
ON_RTreeSearchResultCallback result;
result.m_context = a_context;
result.m_resultCallback = a_resultCallback;
return SearchHelper(m_root, &rect, result);
}
bool ON_RTree::Search(
const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM],
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_data),
void* a_context
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
return Search( &rect, a_resultCallback, a_context );
}
bool ON_RTree::Search(
ON_RTreeBBox* a_rect,
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_data),
void* a_context
) const
{
if ( 0 == m_root || 0 == a_rect )
return false;
ON_RTreeSearchResultCallback result;
result.m_context = a_context;
result.m_resultCallback = a_resultCallback;
return SearchHelper(m_root, a_rect, result);
}
bool ON_RTree::Search(
struct ON_RTreeSphere* a_sphere,
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_id),
void* a_context
) const
{
if ( 0 == m_root || 0 == a_sphere )
return false;
ON_RTreeSearchResultCallback result;
result.m_context = a_context;
result.m_resultCallback = a_resultCallback;
return SearchHelper(m_root, a_sphere, result);
}
bool ON_RTree::Search(
struct ON_RTreeCapsule* a_capsule,
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_id),
void* a_context
) const
{
if ( 0 == m_root || 0 == a_capsule )
return false;
ON_RTreeSearchResultCallback result;
result.m_context = a_context;
result.m_resultCallback = a_resultCallback;
return SearchHelper(m_root, a_capsule, result);
}
bool ON_RTree::Search2d(const double a_min[2], const double a_max[2],
ON_SimpleArray<ON_RTreeLeaf>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,2*sizeof(a_min[0]));
rect.m_min[2] = 0.0;
memcpy(rect.m_max,a_max,2*sizeof(a_max[0]));
rect.m_max[2] = 0.0;
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM],
ON_SimpleArray<ON_RTreeLeaf>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search2d(const double a_min[2], const double a_max[2],
ON_SimpleArray<void*>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,2*sizeof(a_min[0]));
rect.m_min[2] = 0.0;
memcpy(rect.m_max,a_max,2*sizeof(a_max[0]));
rect.m_max[2] = 0.0;
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM],
ON_SimpleArray<void*>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search2d(const double a_min[2], const double a_max[2],
ON_SimpleArray<int>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,2*sizeof(a_min[0]));
rect.m_min[2] = 0.0;
memcpy(rect.m_max,a_max,2*sizeof(a_max[0]));
rect.m_max[2] = 0.0;
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM],
ON_SimpleArray<int>& a_result
) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search2d(const double a_min[2], const double a_max[2],
ON_RTreeSearchResult& a_result ) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,2*sizeof(a_min[0]));
rect.m_min[2] = 0.0;
memcpy(rect.m_max,a_max,2*sizeof(a_max[0]));
rect.m_max[2] = 0.0;
return SearchHelper(m_root, &rect, a_result);
}
bool ON_RTree::Search(const double a_min[ON_RTree_NODE_DIM], const double a_max[ON_RTree_NODE_DIM],
ON_RTreeSearchResult& a_result ) const
{
if ( 0 == m_root )
return false;
ON_RTreeBBox rect;
memcpy(rect.m_min,a_min,sizeof(rect.m_min));
memcpy(rect.m_max,a_max,sizeof(rect.m_max));
return SearchHelper(m_root, &rect, a_result);
}
struct ON_RTreePairSearchResult
{
double m_tolerance;
ON_SimpleArray<ON_2dex>* m_result;
};
static bool PairSearchOverlapHelper( const ON_RTreeBBox* a_rectA, const ON_RTreeBBox* a_rectB, double tolerance )
{
double dx,dy,dz,d;
const double* mn;
const double* mx;
mx = a_rectA->m_max;
mn = a_rectB->m_min;
dx = *mn++ - *mx++;
if ( dx > tolerance ) return false;
dy = *mn++ - *mx++;
if ( dy > tolerance ) return false;
dz = *mn - *mx;
if ( dz > tolerance ) return false;
mx = a_rectB->m_max;
mn = a_rectA->m_min;
d = *mn++ - *mx++;
if ( d > tolerance ) return false;
if ( d > dx ) dx = d;
d = *mn++ - *mx++;
if ( d > tolerance ) return false;
if ( d > dy ) dy = d;
d = *mn++ - *mx++;
if ( d > tolerance ) return false;
if ( d > dz ) dz = d;
d = (dx > 0.0) ? dx*dx : 0.0;
d += (dy > 0.0) ? dy*dy : 0.0;
d += (dz > 0.0) ? dz*dz : 0.0;
return (d <= tolerance*tolerance);
}
static void PairSearchHelper( const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
while(branchB < branchBmax)
{
if ( PairSearchOverlapHelper( &a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeB->m_level > 0 )
{
PairSearchHelper(a_branchA,branchB->m_child,a_result);
}
else
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)a_branchA->m_id;
r.j = (int)branchB->m_id;
}
}
branchB++;
}
}
static void PairSearchHelper( const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
while(branchA < branchAmax)
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
PairSearchHelper(branchA->m_child,a_branchB,a_result);
}
else
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)branchA->m_id;
r.j = (int)a_branchB->m_id;
}
}
branchA++;
}
}
static void PairSearchHelper( const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
while(branchA < branchAmax)
{
for ( branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++ )
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
if ( a_nodeB->m_level > 0 )
PairSearchHelper(branchA->m_child,branchB->m_child,a_result);
else
PairSearchHelper(branchA->m_child,branchB,a_result);
}
else if ( a_nodeB->m_level > 0 )
{
PairSearchHelper(branchA,branchB->m_child,a_result);
}
else
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)branchA->m_id;
r.j = (int)branchB->m_id;
}
}
}
branchA++;
}
}
bool ON_RTree::Search(
const ON_RTree& a_rtreeA,
const ON_RTree& a_rtreeB,
double tolerance,
ON_SimpleArray<ON_2dex>& a_result
)
{
if ( 0 == a_rtreeA.m_root )
return false;
if ( 0 == a_rtreeB.m_root )
return false;
ON_RTreePairSearchResult r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_result = &a_result;
PairSearchHelper(a_rtreeA.m_root,a_rtreeB.m_root,&r);
return true;
}
typedef void (*ON_RTreePairSearchCallback)(void*, ON__INT_PTR, ON__INT_PTR);
struct ON_RTreePairSearchCallbackResult
{
double m_tolerance;
void* m_context;
ON_RTreePairSearchCallback m_resultCallback;
};
typedef bool (*ON_RTreePairSearchCallbackBool)(void*, ON__INT_PTR, ON__INT_PTR);
struct ON_RTreePairSearchCallbackResultBool
{
double m_tolerance;
void* m_context;
ON_RTreePairSearchCallbackBool m_resultCallbackBool;
};
typedef bool(*ON_RTreePairSearchCallbackBoolTolerance)(void*, ON__INT_PTR, ON__INT_PTR, double*);
struct ON_RTreePairSearchCallbackResultBoolTolerance
{
double m_tolerance;
void* m_context;
ON_RTreePairSearchCallbackBoolTolerance m_resultCallbackBoolTolerance;
};
static void PairSearchHelper( const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
while(branchB < branchBmax)
{
if ( PairSearchOverlapHelper( &a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeB->m_level > 0 )
{
PairSearchHelper(a_branchA,branchB->m_child,a_result);
}
else
{
a_result->m_resultCallback(a_result->m_context,a_branchA->m_id,branchB->m_id);
}
}
branchB++;
}
}
static bool PairSearchHelperBool( const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBool* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
while(branchB < branchBmax)
{
if ( PairSearchOverlapHelper( &a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeB->m_level > 0 )
{
if ( !PairSearchHelperBool(a_branchA,branchB->m_child,a_result) )
return false;
}
else
{
if ( !a_result->m_resultCallbackBool(a_result->m_context,a_branchA->m_id,branchB->m_id) )
return false;
}
}
branchB++;
}
return true;
}
static bool PairSearchHelperBoolTolerance(const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
while (branchB < branchBmax)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeB->m_level > 0)
{
if (!PairSearchHelperBoolTolerance(a_branchA, branchB->m_child, a_result))
return false;
}
else
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, a_branchA->m_id, branchB->m_id, &a_result->m_tolerance))
return false;
}
}
branchB++;
}
return true;
}
static void PairSearchHelper( const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
while(branchA < branchAmax)
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
PairSearchHelper(branchA->m_child,a_branchB,a_result);
}
else
{
a_result->m_resultCallback(a_result->m_context,branchA->m_id,a_branchB->m_id);
}
}
branchA++;
}
}
static bool PairSearchHelperBool( const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResultBool* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
while(branchA < branchAmax)
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
if ( !PairSearchHelperBool(branchA->m_child,a_branchB,a_result) )
return false;
}
else
{
if ( !a_result->m_resultCallbackBool(a_result->m_context,branchA->m_id,a_branchB->m_id) )
return false;
}
}
branchA++;
}
return true;
}
static bool PairSearchHelperBoolTolerance(const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
while (branchA < branchAmax)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (!PairSearchHelperBoolTolerance(branchA->m_child, a_branchB, a_result))
return false;
}
else
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, branchA->m_id, a_branchB->m_id, &a_result->m_tolerance))
return false;
}
}
branchA++;
}
return true;
}
static void PairSearchHelper( const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResult* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
while(branchA < branchAmax)
{
for ( branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++ )
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
if ( a_nodeB->m_level > 0 )
PairSearchHelper(branchA->m_child,branchB->m_child,a_result);
else
PairSearchHelper(branchA->m_child,branchB,a_result);
}
else if ( a_nodeB->m_level > 0 )
{
PairSearchHelper(branchA,branchB->m_child,a_result);
}
else
{
a_result->m_resultCallback(a_result->m_context,branchA->m_id,branchB->m_id);
}
}
}
branchA++;
}
}
static bool PairSearchHelperBool( const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBool* a_result )
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
while(branchA < branchAmax)
{
for ( branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++ )
{
if ( PairSearchOverlapHelper( &branchA->m_rect, &branchB->m_rect, a_result->m_tolerance ) )
{
if ( a_nodeA->m_level > 0 )
{
if ( a_nodeB->m_level > 0 )
{
if ( !PairSearchHelperBool(branchA->m_child,branchB->m_child,a_result) )
return false;
}
else
{
if ( !PairSearchHelperBool(branchA->m_child,branchB,a_result) )
return false;
}
}
else if ( a_nodeB->m_level > 0 )
{
if ( !PairSearchHelperBool(branchA,branchB->m_child,a_result) )
return false;
}
else
{
if ( !a_result->m_resultCallbackBool(a_result->m_context,branchA->m_id,branchB->m_id) )
return false;
}
}
}
branchA++;
}
return true;
}
static bool PairSearchHelperBoolTolerance(const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
{
// neither branchA nor branchB are leaf nodes
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!PairSearchHelperBoolTolerance(branchA->m_child, branchB->m_child, a_result))
return false;
}
}
branchA++;
}
}
else
{
// branchB nodes are leaves and branchA nodes are not
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!PairSearchHelperBoolTolerance(branchA->m_child, branchB, a_result))
return false;
}
}
branchA++;
}
}
}
else if (a_nodeB->m_level > 0)
{
// branchA nodes are leaves and branchB nodes are not
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!PairSearchHelperBoolTolerance(branchA, branchB->m_child, a_result))
return false;
}
}
branchA++;
}
}
else
{
// branchA and branchB are leaf nodes
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, branchA->m_id, branchB->m_id, &a_result->m_tolerance))
return false;
}
}
branchA++;
}
}
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
{
if (!PairSearchHelperBoolTolerance(branchA->m_child, branchB->m_child, a_result))
return false;
}
else
{
if (!PairSearchHelperBoolTolerance(branchA->m_child, branchB, a_result))
return false;
}
}
else if (a_nodeB->m_level > 0)
{
if (!PairSearchHelperBoolTolerance(branchA, branchB->m_child, a_result))
return false;
}
else
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, branchA->m_id, branchB->m_id, &a_result->m_tolerance))
return false;
}
}
}
branchA++;
}
return true;
}
bool ON_RTree::Search(
const ON_RTree& a_rtreeA,
const ON_RTree& a_rtreeB,
double tolerance,
void ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB),
void* a_context
)
{
if ( 0 == a_rtreeA.m_root )
return false;
if ( 0 == a_rtreeB.m_root )
return false;
ON_RTreePairSearchCallbackResult r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallback = resultCallback;
PairSearchHelper(a_rtreeA.m_root,a_rtreeB.m_root,&r);
return true;
}
bool ON_RTree::Search(
const ON_RTree& a_rtreeA,
const ON_RTree& a_rtreeB,
double tolerance,
bool ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB),
void* a_context
)
{
if ( 0 == a_rtreeA.m_root )
return false;
if ( 0 == a_rtreeB.m_root )
return false;
ON_RTreePairSearchCallbackResultBool r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallbackBool = resultCallback;
// Do not return false if PairSearchHelperBool() returns false. The only reason
// PairSearchHelperBool() returns false is that the user specified resultCallback()
// terminated the search. This way a programmer with the ability to reason can
// distinguish between a terminiation and a failure to start because input is
// missing.
PairSearchHelperBool(a_rtreeA.m_root,a_rtreeB.m_root,&r);
return true;
}
bool ON_RTree::Search(
const ON_RTree& a_rtreeA,
const ON_RTree& a_rtreeB,
double tolerance,
bool ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB, double* tolerance),
void* a_context
)
{
if (0 == a_rtreeA.m_root)
return false;
if (0 == a_rtreeB.m_root)
return false;
ON_RTreePairSearchCallbackResultBoolTolerance r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallbackBoolTolerance = resultCallback;
// Do not return false if PairSearchHelperBoolTolerance() returns false.
// The only reason PairSearchHelperBoolTolerance() returns false is that
// the user specified resultCallback() terminated the search.
// This way a programmer with the ability to reason can distinguish between
// a terminiation and a failure to start because input is missing.
PairSearchHelperBoolTolerance(a_rtreeA.m_root, a_rtreeB.m_root, &r);
return true;
}
#if 1
static void SingleTreeSearchHelper(const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
if (a_nodeB->m_level > 0)
{
// branchB's have children nodes and a_branchA is a leaf
while (branchB < branchBmax)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
SingleTreeSearchHelper(a_branchA, branchB->m_child, a_result);
}
branchB++;
}
}
else
{
// branchB's are leaves and a_branchA is a leaf
while (branchB < branchBmax)
{
if (a_branchA < branchB)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)a_branchA->m_id;
r.j = (int)branchB->m_id;
}
}
branchB++;
}
}
}
static void SingleTreeSearchHelper(const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
if (a_nodeA->m_level > 0)
{
// branchA's have children nodes and a_branchB is a leaf
while (branchA < branchAmax)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
SingleTreeSearchHelper(branchA->m_child, a_branchB, a_result);
}
branchA++;
}
}
else
{
// branchA's are leaves and a_branchB is a leaf
while (branchA < branchAmax)
{
if (branchA < a_branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)branchA->m_id;
r.j = (int)a_branchB->m_id;
}
}
branchA++;
}
}
}
static void SingleTreeSearchHelper(const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
if (a_nodeA->m_level > 0 || a_nodeB->m_level > 0)
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
SingleTreeSearchHelper(branchA->m_child, branchB->m_child, a_result);
else
SingleTreeSearchHelper(branchA->m_child, branchB, a_result);
}
else // a_nodeB->m_level > 0
{
SingleTreeSearchHelper(branchA, branchB->m_child, a_result);
}
}
}
branchA++;
}
}
else
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
// branchA and branchB are leaf nodes in the same same tree.
// Don't test pairs twice and don't test a node against itself.
if (branchA < branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
ON_2dex& r = a_result->m_result->AppendNew();
r.i = (int)branchA->m_id;
r.j = (int)branchB->m_id;
}
}
}
branchA++;
}
}
}
bool ON_RTree::Search(
double tolerance,
ON_SimpleArray<ON_2dex>& a_result
) const
{
if (0 == this->m_root)
return false;
ON_RTreePairSearchResult r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_result = &a_result;
SingleTreeSearchHelper(this->m_root, this->m_root, &r);
return true;
}
static void SingleTreeSearchHelper(const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
if (a_nodeB->m_level > 0)
{
// branchB's have children nodes and a_branchA is a leaf
while (branchB < branchBmax)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
SingleTreeSearchHelper(a_branchA, branchB->m_child, a_result);
}
branchB++;
}
}
else
{
// branchB's are all leaves
while (branchB < branchBmax)
{
if (a_branchA < branchB)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
a_result->m_resultCallback(a_result->m_context, a_branchA->m_id, branchB->m_id);
}
}
branchB++;
}
}
}
static bool SingleTreeSearchHelperBool(const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBool* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
if (a_nodeB->m_level > 0)
{
// branchB's have children nodes and a_branchA is a leaf
while (branchB < branchBmax)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!SingleTreeSearchHelperBool(a_branchA, branchB->m_child, a_result))
return false;
}
branchB++;
}
}
else
{
// branchB's are all leaves
while (branchB < branchBmax)
{
if (a_branchA < branchB)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBool(a_result->m_context, a_branchA->m_id, branchB->m_id))
return false;
}
}
branchB++;
}
}
return true;
}
static bool SingleTreeSearchHelperBoolTolerance(const ON_RTreeBranch* a_branchA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchB, *branchBmax;
branchB = a_nodeB->m_branch;
branchBmax = branchB + a_nodeB->m_count;
if (a_nodeB->m_level > 0)
{
// branchB's have children nodes and a_branchA is a leaf
while (branchB < branchBmax)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!SingleTreeSearchHelperBoolTolerance(a_branchA, branchB->m_child, a_result))
return false;
}
branchB++;
}
}
else
{
// branchB's are all leaves
while (branchB < branchBmax)
{
if (a_branchA < branchB)
{
if (PairSearchOverlapHelper(&a_branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, a_branchA->m_id, branchB->m_id, &a_result->m_tolerance))
return false;
}
}
branchB++;
}
}
return true;
}
static void SingleTreeSearchHelper(const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
if (a_nodeA->m_level > 0)
{
// branchA's have children nodes and a_branchB is a leaf
while (branchA < branchAmax)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
SingleTreeSearchHelper(branchA->m_child, a_branchB, a_result);
}
branchA++;
}
}
else
{
// branchA's are all leaves
while (branchA < branchAmax)
{
if (branchA < a_branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
a_result->m_resultCallback(a_result->m_context, branchA->m_id, a_branchB->m_id);
}
}
branchA++;
}
}
}
static bool SingleTreeSearchHelperBool(const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResultBool* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
if (a_nodeA->m_level > 0)
{
// branchA's have children nodes and a_branchB is a leaf
while (branchA < branchAmax)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
if (!SingleTreeSearchHelperBool(branchA->m_child, a_branchB, a_result))
return false;
}
branchA++;
}
}
else
{
// branchA's are all leaves
while (branchA < branchAmax)
{
if (branchA < a_branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBool(a_result->m_context, branchA->m_id, a_branchB->m_id))
return false;
}
}
branchA++;
}
}
return true;
}
static bool SingleTreeSearchHelperBoolTolerance(const ON_RTreeNode* a_nodeA, const ON_RTreeBranch* a_branchB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
if (a_nodeA->m_level > 0)
{
// branchA's have children nodes and a_branchB is a leaf
while (branchA < branchAmax)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
if (!SingleTreeSearchHelperBoolTolerance(branchA->m_child, a_branchB, a_result))
return false;
}
branchA++;
}
}
else
{
// branchA's are all leaves
while (branchA < branchAmax)
{
if (branchA < a_branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &a_branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, branchA->m_id, a_branchB->m_id, &a_result->m_tolerance))
return false;
}
}
branchA++;
}
}
return true;
}
static void SingleTreeSearchHelper(const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResult* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
if (a_nodeA->m_level > 0 || a_nodeB->m_level > 0)
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
SingleTreeSearchHelper(branchA->m_child, branchB->m_child, a_result);
else
SingleTreeSearchHelper(branchA->m_child, branchB, a_result);
}
else // a_nodeB->m_level > 0
{
SingleTreeSearchHelper(branchA, branchB->m_child, a_result);
}
}
}
branchA++;
}
}
else
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
// branchA and branchB are leaf nodes in the same same tree.
// Don't test pairs twice and don't test a node against itself.
if (branchA < branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
a_result->m_resultCallback(a_result->m_context, branchA->m_id, branchB->m_id);
}
}
}
branchA++;
}
}
}
static bool SingleTreeSearchHelperBool(const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBool* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
if (a_nodeA->m_level > 0 || a_nodeB->m_level > 0)
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
{
if (!SingleTreeSearchHelperBool(branchA->m_child, branchB->m_child, a_result))
return false;
}
else
{
if (!SingleTreeSearchHelperBool(branchA->m_child, branchB, a_result))
return false;
}
}
else // a_nodeB->m_level > 0
{
if (!SingleTreeSearchHelperBool(branchA, branchB->m_child, a_result))
return false;
}
}
}
branchA++;
}
}
else
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
// branchA and branchB are leaf nodes in the same same tree.
// Don't test pairs twice and don't test a node against itself.
if (branchA < branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBool(a_result->m_context, branchA->m_id, branchB->m_id))
return false;
}
}
}
branchA++;
}
}
return true;
}
static bool SingleTreeSearchHelperBoolTolerance(const ON_RTreeNode* a_nodeA, const ON_RTreeNode* a_nodeB, ON_RTreePairSearchCallbackResultBoolTolerance* a_result)
{
// DO NOT ADD ANYTHING TO THIS FUNCTION
const ON_RTreeBranch *branchA, *branchAmax, *branchB, *branchBmax;
branchA = a_nodeA->m_branch;
branchAmax = branchA + a_nodeA->m_count;
branchBmax = a_nodeB->m_branch + a_nodeB->m_count;
if (a_nodeA->m_level > 0 || a_nodeB->m_level > 0)
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (a_nodeA->m_level > 0)
{
if (a_nodeB->m_level > 0)
{
if (!SingleTreeSearchHelperBoolTolerance(branchA->m_child, branchB->m_child, a_result))
return false;
}
else
{
if (!SingleTreeSearchHelperBoolTolerance(branchA->m_child, branchB, a_result))
return false;
}
}
else // a_nodeB->m_level > 0
{
if (!SingleTreeSearchHelperBoolTolerance(branchA, branchB->m_child, a_result))
return false;
}
}
}
branchA++;
}
}
else
{
while (branchA < branchAmax)
{
for (branchB = a_nodeB->m_branch; branchB < branchBmax; branchB++)
{
// branchA and branchB are leaf nodes in the same same tree.
// Don't test pairs twice and don't test a node against itself.
if (branchA < branchB)
{
if (PairSearchOverlapHelper(&branchA->m_rect, &branchB->m_rect, a_result->m_tolerance))
{
if (!a_result->m_resultCallbackBoolTolerance(a_result->m_context, branchA->m_id, branchB->m_id, &a_result->m_tolerance))
return false;
}
}
}
branchA++;
}
}
return true;
}
bool ON_RTree::Search(
double tolerance,
void ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB),
void* a_context
) const
{
if (0 == this->m_root)
return false;
ON_RTreePairSearchCallbackResult r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallback = resultCallback;
SingleTreeSearchHelper(this->m_root, this->m_root, &r);
return true;
}
bool ON_RTree::Search(
double tolerance,
bool ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB),
void* a_context
) const
{
if (0 == this->m_root)
return false;
ON_RTreePairSearchCallbackResultBool r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallbackBool = resultCallback;
// Do not return false if PairSearchHelperBool() returns false. The only reason
// PairSearchHelperBool() returns false is that the user specified resultCallback()
// terminated the search. This way a programmer with the ability to reason can
// distinguish between a terminiation and a failure to start because input is
// missing.
SingleTreeSearchHelperBool(this->m_root, this->m_root, &r);
return true;
}
bool ON_RTree::Search(
double tolerance,
bool ON_CALLBACK_CDECL resultCallback(void* a_context, ON__INT_PTR a_idA, ON__INT_PTR a_idB, double* tolerance),
void* a_context
) const
{
if (0 == this->m_root)
return false;
ON_RTreePairSearchCallbackResultBoolTolerance r;
r.m_tolerance = (ON_IsValid(tolerance) && tolerance > 0.0) ? tolerance : 0.0;
r.m_context = a_context;
r.m_resultCallbackBoolTolerance = resultCallback;
// Do not return false if PairSearchHelperBool() returns false. The only reason
// PairSearchHelperBool() returns false is that the user specified resultCallback()
// terminated the search. This way a programmer with the ability to reason can
// distinguish between a terminiation and a failure to start because input is
// missing.
SingleTreeSearchHelperBoolTolerance(this->m_root, this->m_root, &r);
return true;
}
#endif
int ON_RTree::ElementCount()
{
int count = 0;
if ( 0 != m_root )
CountRec(m_root, count);
return count;
}
const ON_RTreeNode* ON_RTree::Root() const
{
return m_root;
}
ON_BoundingBox ON_RTree::BoundingBox() const
{
ON_BoundingBox bbox;
if ( 0 != m_root && m_root->m_count > 0 )
{
bbox.m_min = m_root->m_branch[0].m_rect.m_min;
bbox.m_max = m_root->m_branch[0].m_rect.m_max;
for ( int i = 1; i < m_root->m_count; i++ )
{
if ( m_root->m_branch[i].m_rect.m_min[0] < bbox.m_min.x )
bbox.m_min.x = m_root->m_branch[i].m_rect.m_min[0];
if ( m_root->m_branch[i].m_rect.m_min[1] < bbox.m_min.y )
bbox.m_min.y = m_root->m_branch[i].m_rect.m_min[1];
if ( m_root->m_branch[i].m_rect.m_min[2] < bbox.m_min.z )
bbox.m_min.z = m_root->m_branch[i].m_rect.m_min[2];
if ( m_root->m_branch[i].m_rect.m_max[0] > bbox.m_max.x )
bbox.m_max.x = m_root->m_branch[i].m_rect.m_max[0];
if ( m_root->m_branch[i].m_rect.m_max[1] > bbox.m_max.y )
bbox.m_max.y = m_root->m_branch[i].m_rect.m_max[1];
if ( m_root->m_branch[i].m_rect.m_max[2] > bbox.m_max.z )
bbox.m_max.z = m_root->m_branch[i].m_rect.m_max[2];
}
}
return bbox;
}
static void CountRec(ON_RTreeNode* a_node, int& a_count)
{
if(a_node->IsInternalNode()) // not a leaf node
{
for(int index = 0; index < a_node->m_count; ++index)
{
CountRec(a_node->m_branch[index].m_child, a_count);
}
}
else // A leaf node
{
a_count += a_node->m_count;
}
}
size_t ON_RTree::SizeOf() const
{
return m_mem_pool.SizeOf();
}
#if defined (ON_RUNTIME_WIN)
// never used
static void NodeCountHelper( const ON_RTreeNode* node, size_t& node_count, size_t& wasted_branch_count, size_t& leaf_count )
{
if ( 0 == node )
return;
node_count++;
wasted_branch_count += (ON_RTree_MAX_NODE_COUNT - node->m_count);
if ( node->m_level > 0 )
{
for ( int i = 0; i < node->m_count; i++ )
{
NodeCountHelper(node->m_branch[i].m_child,node_count,wasted_branch_count,leaf_count);
}
}
else
leaf_count += node->m_count;
}
#endif
void ON_RTree::RemoveAll()
{
m_root = 0;
m_mem_pool.DeallocateAll();
}
void ON_RTree::RemoveAllRec(ON_RTreeNode* a_node)
{
if(a_node->IsInternalNode()) // This is an internal node in the tree
{
for(int index=0; index < a_node->m_count; ++index)
{
RemoveAllRec(a_node->m_branch[index].m_child);
}
}
m_mem_pool.FreeNode(a_node);
}
static void InitRect(ON_RTreeBBox* a_rect)
{
for(int index = 0; index < ON_RTree_NODE_DIM; ++index)
{
a_rect->m_min[index] = (double)0;
a_rect->m_max[index] = (double)0;
}
}
// Inserts a new data rectangle into the index structure.
// Recursively descends tree, propagates splits back up.
// Returns 0 if node was not split. Old node updated.
// If node was split, returns 1 and sets the pointer pointed to by
// new_node to point to the new node. Old node updated to become one of two.
// The level argument specifies the number of steps up from the leaf
// level to insert; e.g. a data rectangle goes in at level = 0.
bool ON_RTree::InsertRectRec(ON_RTreeBBox* a_rect, ON__INT_PTR a_id, ON_RTreeNode* a_node, ON_RTreeNode** a_newNode, int a_level)
{
int index;
ON_RTreeBranch branch;
ON_RTreeNode* otherNode;
// Still above level for insertion, go down tree recursively
if(a_node->m_level > a_level)
{
index = PickBranch(a_rect, a_node);
if ( index < 0 )
{
return false;
}
if (!InsertRectRec(a_rect, a_id, a_node->m_branch[index].m_child, &otherNode, a_level))
{
// Child was not split
a_node->m_branch[index].m_rect = CombineRectHelper(a_rect, &(a_node->m_branch[index].m_rect));
return false;
}
else // Child was split
{
a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child);
branch.m_child = otherNode;
branch.m_rect = NodeCover(otherNode);
return AddBranch(&branch, a_node, a_newNode);
}
}
else if(a_node->m_level == a_level) // Have reached level for insertion. Add rect, split if necessary
{
branch.m_rect = *a_rect;
// The (ON_RTreeNode*) cast is safe because ON__INT_PTR == sizeof(void*)
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_PUSH
// Disable warning C4312: 'type cast' : conversion from 'ON__INT_PTR' to 'ON_RTreeNode *' of greater size
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4312 )
#endif
branch.m_child = (ON_RTreeNode*)a_id;
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_POP
#endif
// Child field of leaves contains id of data record
return AddBranch(&branch, a_node, a_newNode);
}
// We should never get here
ON_ERROR("ON_RTree::InsertRectRec - bug in algorithm");
return false;
}
// Insert a data rectangle into an index structure.
// InsertRect provides for splitting the root;
// returns 1 if root was split, 0 if it was not.
// The level argument specifies the number of steps up from the leaf
// level to insert; e.g. a data rectangle goes in at level = 0.
// InsertRect2 does the recursion.
//
bool ON_RTree::InsertRect(ON_RTreeBBox* a_rect, ON__INT_PTR a_id, ON_RTreeNode** a_root, int a_level)
{
ON_RTreeNode* newRoot;
ON_RTreeNode* newNode;
ON_RTreeBranch branch;
if(InsertRectRec(a_rect, a_id, *a_root, &newNode, a_level)) // Root split
{
newRoot = m_mem_pool.AllocNode(); // Grow tree taller and new root
newRoot->m_level = (*a_root)->m_level + 1;
branch.m_rect = NodeCover(*a_root);
branch.m_child = *a_root;
AddBranch(&branch, newRoot, nullptr);
branch.m_rect = NodeCover(newNode);
branch.m_child = newNode;
AddBranch(&branch, newRoot, nullptr);
*a_root = newRoot;
return true;
}
return false;
}
// Find the smallest rectangle that includes all rectangles in branches of a node.
static ON_RTreeBBox NodeCover(ON_RTreeNode* a_node)
{
int i;
const ON_RTreeBranch* branch;
ON_RTreeBBox rect;
if ( (i = a_node->m_count) > 0 )
{
rect = a_node->m_branch[--i].m_rect;
for ( branch = a_node->m_branch; i; i--, branch++ )
{
#if (3 == ON_RTree_NODE_DIM)
if ( rect.m_min[0] > branch->m_rect.m_min[0] )
rect.m_min[0] = branch->m_rect.m_min[0];
if ( rect.m_min[1] > branch->m_rect.m_min[1] )
rect.m_min[1] = branch->m_rect.m_min[1];
if ( rect.m_min[2] > branch->m_rect.m_min[2] )
rect.m_min[2] = branch->m_rect.m_min[2];
if ( rect.m_max[0] < branch->m_rect.m_max[0] )
rect.m_max[0] = branch->m_rect.m_max[0];
if ( rect.m_max[1] < branch->m_rect.m_max[1] )
rect.m_max[1] = branch->m_rect.m_max[1];
if ( rect.m_max[2] < branch->m_rect.m_max[2] )
rect.m_max[2] = branch->m_rect.m_max[2];
#else
for( int j = 0; j < ON_RTree_NODE_DIM; j++ )
{
if ( rect.m_min[j] > branch->m_rect.m_min[j] )
rect.m_min[j] = branch->m_rect.m_min[j];
if ( rect.m_max[j] < branch->m_rect.m_max[j] )
rect.m_max[j] = branch->m_rect.m_max[j];
}
#endif
}
}
else
{
InitRect(&rect);
}
return rect;
}
// Add a branch to a node. Split the node if necessary.
// Returns 0 if node not split. Old node updated.
// Returns 1 if node split, sets *new_node to address of new node.
// Old node updated, becomes one of two.
bool ON_RTree::AddBranch(ON_RTreeBranch* a_branch, ON_RTreeNode* a_node, ON_RTreeNode** a_newNode)
{
if(a_node->m_count < ON_RTree_MAX_NODE_COUNT) // Split won't be necessary
{
a_node->m_branch[a_node->m_count] = *a_branch;
++a_node->m_count;
return false;
}
else
{
SplitNode(a_node, a_branch, a_newNode);
return true;
}
}
// Disconnect a dependent node.
// Caller must return (or stop using iteration index) after this as count has changed
static void DisconnectBranch(ON_RTreeNode* a_node, int a_index)
{
// Remove element by swapping with the last element to prevent gaps in array
a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1];
--a_node->m_count;
}
// Pick a branch. Pick the one that will need the smallest increase
// in area to accomodate the new rectangle. This will result in the
// least total area for the covering rectangles in the current node.
// In case of a tie, pick the one which was smaller before, to get
// the best resolution when searching.
static int PickBranch(ON_RTreeBBox* a_rect, ON_RTreeNode* a_node)
{
bool firstTime = true;
double increase;
double bestIncr = -1.0;
double area;
double bestArea;
int best;
ON_RTreeBBox tempRect;
best = -1;
bestArea = -1.0;
for(int index=0; index < a_node->m_count; ++index)
{
ON_RTreeBBox* curRect = &a_node->m_branch[index].m_rect;
area = CalcRectVolumeHelper(curRect);
tempRect = CombineRectHelper(a_rect, curRect);
increase = CalcRectVolumeHelper(&tempRect) - area;
if((increase < bestIncr) || firstTime)
{
best = index;
bestArea = area;
bestIncr = increase;
firstTime = false;
}
else if((increase == bestIncr) && (area <=bestArea))
{
best = index;
bestArea = area;
bestIncr = increase;
}
}
return best;
}
// Combine two rectangles into larger one containing both
ON_RTreeBBox CombineRectHelper(const ON_RTreeBBox* a_rectA, const ON_RTreeBBox* a_rectB)
{
ON_RTreeBBox rect = *a_rectA;
#if (3 == ON_RTree_NODE_DIM)
if ( rect.m_min[0] > a_rectB->m_min[0] )
rect.m_min[0] = a_rectB->m_min[0];
if ( rect.m_min[1] > a_rectB->m_min[1] )
rect.m_min[1] = a_rectB->m_min[1];
if ( rect.m_min[2] > a_rectB->m_min[2] )
rect.m_min[2] = a_rectB->m_min[2];
if ( rect.m_max[0] < a_rectB->m_max[0] )
rect.m_max[0] = a_rectB->m_max[0];
if ( rect.m_max[1] < a_rectB->m_max[1] )
rect.m_max[1] = a_rectB->m_max[1];
if ( rect.m_max[2] < a_rectB->m_max[2] )
rect.m_max[2] = a_rectB->m_max[2];
#else
for( int j = 0; j < ON_RTree_NODE_DIM; j++ )
{
if ( rect.m_min[j] > a_rectB->m_min[j] )
rect.m_min[j] = a_rectB->m_min[j];
if ( rect.m_max[j] < a_rectB->m_max[j] )
rect.m_max[j] = a_rectB->m_max[j];
}
#endif
return rect;
}
// Split a node.
// Divides the nodes branches and the extra one between two nodes.
// Old node is one of the new ones, and one really new one is created.
// Tries more than one method for choosing a partition, uses best result.
void ON_RTree::SplitNode(ON_RTreeNode* a_node, ON_RTreeBranch* a_branch, ON_RTreeNode** a_newNode)
{
ON_RTreePartitionVars localVars;
int level;
// Load all the branches into a buffer, initialize a_node to be empty
level = a_node->m_level; // save m_level (The InitNode() call in GetBranches will set it to -1)
GetBranches(a_node, a_branch, &localVars);
// Find partition
ChoosePartition(&localVars, ON_RTree_MIN_NODE_COUNT);
// Put branches from buffer into 2 nodes according to chosen partition
*a_newNode = m_mem_pool.AllocNode();
(*a_newNode)->m_level = a_node->m_level = level; // restore m_level
LoadNodes(a_node, *a_newNode, &localVars);
}
double CalcRectVolumeHelper(const ON_RTreeBBox* a_rect)
{
double d, r;
// Bounding sphere volume calculation is slower, but helps certain merge cases
#if ( 3 == ON_RTree_NODE_DIM)
// 3d bounding sphere volume
d = (a_rect->m_max[0] - a_rect->m_min[0]);
r = d * d;
d = (a_rect->m_max[1] - a_rect->m_min[1]);
r += d * d;
d = (a_rect->m_max[2] - a_rect->m_min[2]);
r += d * d;
r = sqrt(r*0.5); // r = sqrt((dx^2 + dy^2 + dz^2)/2);
return (r * r * r * 4.1887902047863909846168578443727); // 4/3 pi r^3
#elif ( 2 == ON_RTree_NODE_DIM )
// 2d bounding circle volume
d = (a_rect->m_max[0] - a_rect->m_min[0]);
r = d * d;
d = (a_rect->m_max[1] - a_rect->m_min[1]);
r += d * d;
r = sqrt(r*0.5); // r = sqrt((dx^2 + dy^2)/2);
return (r * r * ON_PI);
#else
// n-dim unit sphere volumes
// 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2
// 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5
// 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8
// 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11
// 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14
// 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17
// 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20
//return (unit_sphere_volume * radius^ON_RTree_NODE_DIM);
// Faster rectangle volume calculation, but can cause poor merges
d = a_rect->m_max[0] - a_rect->m_min[0];
for(int i = 1; i < ON_RTree_NODE_DIM; ++i)
{
d *= a_rect->m_max[i] - a_rect->m_min[i];
}
return d;
#endif
}
// Load branch buffer with branches from full node plus the extra branch.
static void GetBranches(ON_RTreeNode* a_node, ON_RTreeBranch* a_branch, ON_RTreePartitionVars* a_parVars)
{
// Load the branch buffer
for(int index=0; index < ON_RTree_MAX_NODE_COUNT; ++index)
{
a_parVars->m_branchBuf[index] = a_node->m_branch[index];
}
a_parVars->m_branchBuf[ON_RTree_MAX_NODE_COUNT] = *a_branch;
a_parVars->m_branchCount = ON_RTree_MAX_NODE_COUNT + 1;
// Calculate rect containing all in the set
a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect;
for(int index=1; index < ON_RTree_MAX_NODE_COUNT+1; ++index)
{
a_parVars->m_coverSplit = CombineRectHelper(&a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect);
}
a_parVars->m_coverSplitArea = CalcRectVolumeHelper(&a_parVars->m_coverSplit);
a_node->m_count = 0;
a_node->m_level = -1;
}
// Method #0 for choosing a partition:
// As the seeds for the two groups, pick the two rects that would waste the
// most area if covered by a single rectangle, i.e. evidently the worst pair
// to have in the same group.
// Of the remaining, one at a time is chosen to be put in one of the two groups.
// The one chosen is the one with the greatest difference in area expansion
// depending on which group - the rect most strongly attracted to one group
// and repelled from the other.
// If one group gets too full (more would force other group to violate min
// fill requirement) then other group gets the rest.
// These last are the ones that can go in either group most easily.
static void ChoosePartition(ON_RTreePartitionVars* a_parVars, int a_minFill)
{
double biggestDiff;
int group, chosen, betterGroup;
InitParVars(a_parVars, a_parVars->m_branchCount, a_minFill);
PickSeeds(a_parVars);
while (((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total)
&& (a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill))
&& (a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill)))
{
biggestDiff = -1.0;
chosen = 0;
betterGroup = 0;
for(int index=0; index<a_parVars->m_total; ++index)
{
if(!a_parVars->m_taken[index])
{
ON_RTreeBBox* curRect = &a_parVars->m_branchBuf[index].m_rect;
ON_RTreeBBox rect0 = CombineRectHelper(curRect, &a_parVars->m_cover[0]);
ON_RTreeBBox rect1 = CombineRectHelper(curRect, &a_parVars->m_cover[1]);
double growth0 = CalcRectVolumeHelper(&rect0) - a_parVars->m_area[0];
double growth1 = CalcRectVolumeHelper(&rect1) - a_parVars->m_area[1];
double diff = growth1 - growth0;
if(diff >= 0)
{
group = 0;
}
else
{
group = 1;
diff = -diff;
}
if(diff > biggestDiff)
{
biggestDiff = diff;
chosen = index;
betterGroup = group;
}
else if((diff == biggestDiff) && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup]))
{
chosen = index;
betterGroup = group;
}
}
}
ClassifyHelper(chosen, betterGroup, a_parVars);
}
// If one group too full, put remaining rects in the other
if((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total)
{
if(a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill)
{
group = 1;
}
else
{
group = 0;
}
for(int index=0; index<a_parVars->m_total; ++index)
{
if(!a_parVars->m_taken[index])
{
ClassifyHelper(index, group, a_parVars);
}
}
}
}
// Copy branches from the buffer into two nodes according to the partition.
void ON_RTree::LoadNodes(ON_RTreeNode* a_nodeA, ON_RTreeNode* a_nodeB, ON_RTreePartitionVars* a_parVars)
{
for(int index=0; index < a_parVars->m_total; ++index)
{
if(a_parVars->m_partition[index] == 0)
{
AddBranch(&a_parVars->m_branchBuf[index], a_nodeA, nullptr);
}
else if(a_parVars->m_partition[index] == 1)
{
AddBranch(&a_parVars->m_branchBuf[index], a_nodeB, nullptr);
}
}
}
// Initialize a ON_RTreePartitionVars structure.
static void InitParVars(ON_RTreePartitionVars* a_parVars, int a_maxRects, int a_minFill)
{
a_parVars->m_count[0] = a_parVars->m_count[1] = 0;
a_parVars->m_area[0] = a_parVars->m_area[1] = (double)0;
a_parVars->m_total = a_maxRects;
a_parVars->m_minFill = a_minFill;
for(int index=0; index < a_maxRects; ++index)
{
a_parVars->m_taken[index] = false;
a_parVars->m_partition[index] = -1;
}
}
static void PickSeeds(ON_RTreePartitionVars* a_parVars)
{
int seed0 = 0, seed1 = 1;
double worst, waste;
double area[ON_RTree_MAX_NODE_COUNT+1];
for(int index=0; index<a_parVars->m_total; ++index)
{
area[index] = CalcRectVolumeHelper(&a_parVars->m_branchBuf[index].m_rect);
}
worst = -a_parVars->m_coverSplitArea - 1;
for(int indexA=0; indexA < a_parVars->m_total-1; ++indexA)
{
for(int indexB = indexA+1; indexB < a_parVars->m_total; ++indexB)
{
ON_RTreeBBox oneRect = CombineRectHelper(&a_parVars->m_branchBuf[indexA].m_rect, &a_parVars->m_branchBuf[indexB].m_rect);
waste = CalcRectVolumeHelper(&oneRect) - area[indexA] - area[indexB];
if(waste > worst)
{
worst = waste;
seed0 = indexA;
seed1 = indexB;
}
}
}
ClassifyHelper(seed0, 0, a_parVars);
ClassifyHelper(seed1, 1, a_parVars);
}
// Put a branch in one of the groups.
void ClassifyHelper(int a_index, int a_group, ON_RTreePartitionVars* a_parVars)
{
a_parVars->m_partition[a_index] = a_group;
a_parVars->m_taken[a_index] = true;
if (a_parVars->m_count[a_group] == 0)
{
a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect;
}
else
{
a_parVars->m_cover[a_group] = CombineRectHelper(&a_parVars->m_branchBuf[a_index].m_rect, &a_parVars->m_cover[a_group]);
}
a_parVars->m_area[a_group] = CalcRectVolumeHelper(&a_parVars->m_cover[a_group]);
++a_parVars->m_count[a_group];
}
// Delete a data rectangle from an index structure.
// Pass in a pointer to a ON_RTreeBBox, the tid of the record, ptr to ptr to root node.
// Returns 1 if record not found, 0 if success.
// RemoveRect provides for eliminating the root.
bool ON_RTree::RemoveRect(ON_RTreeBBox* a_rect, ON__INT_PTR a_id, ON_RTreeNode** a_root)
{
ON_RTreeNode* tempNode;
ON_RTreeListNode* reInsertList = nullptr;
if(!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList))
{
// Found and deleted a data item
// Reinsert any branches from eliminated nodes
while(reInsertList)
{
tempNode = reInsertList->m_node;
for(int index = 0; index < tempNode->m_count; ++index)
{
InsertRect(&(tempNode->m_branch[index].m_rect),
tempNode->m_branch[index].m_id,
a_root,
tempNode->m_level);
}
ON_RTreeListNode* remLNode = reInsertList;
reInsertList = reInsertList->m_next;
m_mem_pool.FreeNode(remLNode->m_node);
m_mem_pool.FreeListNode(remLNode);
}
// Check for redundant root (not leaf, 1 child) and eliminate
if((*a_root)->m_count == 1 && (*a_root)->IsInternalNode())
{
tempNode = (*a_root)->m_branch[0].m_child;
m_mem_pool.FreeNode(*a_root);
*a_root = tempNode;
}
return false;
}
else
{
return true;
}
}
// Delete a rectangle from non-root part of an index structure.
// Called by RemoveRect. Descends tree recursively,
// merges branches on the way back up.
// Returns 1 if record not found, 0 if success.
bool ON_RTree::RemoveRectRec(ON_RTreeBBox* a_rect, ON__INT_PTR a_id, ON_RTreeNode* a_node, ON_RTreeListNode** a_listNode)
{
if(a_node->IsInternalNode()) // not a leaf node
{
for(int index = 0; index < a_node->m_count; ++index)
{
if(OverlapHelper(a_rect, &(a_node->m_branch[index].m_rect)))
{
if(!RemoveRectRec(a_rect, a_id, a_node->m_branch[index].m_child, a_listNode))
{
if(a_node->m_branch[index].m_child->m_count >= ON_RTree_MIN_NODE_COUNT)
{
// child removed, just resize parent rect
a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child);
}
else
{
// child removed, not enough entries in node, eliminate node
ReInsert(a_node->m_branch[index].m_child, a_listNode);
DisconnectBranch(a_node, index); // Must return after this call as count has changed
}
return false;
}
}
}
return true;
}
else // A leaf node
{
for(int index = 0; index < a_node->m_count; ++index)
{
if(a_node->m_branch[index].m_id == a_id)
{
DisconnectBranch(a_node, index); // Must return after this call as count has changed
return false;
}
}
return true;
}
}
// Decide whether two rectangles overlap.
bool OverlapHelper(const ON_RTreeBBox* a_rectA, const ON_RTreeBBox* a_rectB)
{
const double* mn;
const double* mx;
mx = a_rectA->m_max;
mn = a_rectB->m_min;
if ( *mx++ < *mn++ ) return false;
if ( *mx++ < *mn++ ) return false;
if ( *mx < *mn ) return false;
mx = a_rectB->m_max;
mn = a_rectA->m_min;
if ( *mx++ < *mn++ ) return false;
if ( *mx++ < *mn++ ) return false;
if ( *mx < *mn ) return false;
return true;
}
//static bool OverlapHelper(const struct ON_RTreeSphere* a_sphere, const ON_RTreeBBox* a_rect)
//{
// double d[3], t, r;
// const double* mn;
// const double* mx;
// const double* pt;
//
// pt = a_sphere->m_point;
// r = a_sphere->m_radius;
// mn = a_rect->m_min;
// mx = a_rect->m_max;
//
// if ( *pt < *mn )
// {
// d[0] = *mn - *pt;
// if ( d[0] > r )
// return false;
// }
// else if ( *pt > *mx )
// {
// d[0] = *pt - *mx;
// if ( d[0] > r )
// return false;
// }
// else
// {
// d[0] = 0.0;
// }
//
// mn++;
// mx++;
// pt++;
// if ( *pt < *mn )
// {
// d[1] = *mn - *pt;
// if ( d[1] > r )
// return false;
// if ( d[1] > d[0] )
// {
// t = d[0]; d[0] = d[1]; d[1] = t;
// }
// }
// else if ( *pt > *mx )
// {
// d[1] = *pt - *mx;
// if ( d[1] > r )
// return false;
// if ( d[1] > d[0] )
// {
// t = d[0]; d[0] = d[1]; d[1] = t;
// }
// }
// else
// {
// d[1] = 0.0;
// }
//
// mn++;
// mx++;
// pt++;
// if ( *pt < *mn )
// {
// d[2] = *mn - *pt;
// if ( d[2] > r )
// return false;
// if ( d[2] > d[0] )
// {
// t = d[0]; d[0] = d[2]; d[2] = t;
// }
// }
// else if ( *pt > *mx )
// {
// d[2] = *pt - *mx;
// if ( d[2] > r )
// return false;
// if ( d[2] > d[0] )
// {
// t = d[0]; d[0] = d[2]; d[2] = t;
// }
// }
// else
// {
// d[2] = 0.0;
// }
//
// if ( d[0] > 0.0 )
// {
// d[1] /= d[0];
// d[2] /= d[0];
// d[0] *= sqrt(1.0 + d[1]*d[1] + d[2]*d[2]);
// return (d[0] <= r);
// }
//
// return true;
//}
static double DistanceToBoxHelper(
const double* pt,
double r,
const ON_RTreeBBox* a_rect
)
{
// If the sphere with center at pt and radius r intersects a_rect, then
// the distance from pt to a_rect is returned. A value of 0.0 indicates
// that pt is inside a_rect. If the distance from pt to a_rect is
// greater than r, then some number > r and <= actual distance from
// pt to a_rect is returned as quickly as possible.
double d[3], t;
const double* mn;
const double* mx;
mn = a_rect->m_min;
mx = a_rect->m_max;
if ( *pt < *mn )
{
d[0] = *mn - *pt;
if ( d[0] > r )
return d[0];
}
else if ( *pt > *mx )
{
d[0] = *pt - *mx;
if ( d[0] > r )
return d[0];
}
else
{
d[0] = 0.0;
}
mn++;
mx++;
pt++;
if ( *pt < *mn )
{
d[1] = *mn - *pt;
if ( d[1] > r )
return d[1];
if ( d[1] > d[0] )
{
t = d[0]; d[0] = d[1]; d[1] = t;
}
}
else if ( *pt > *mx )
{
d[1] = *pt - *mx;
if ( d[1] > r )
return d[1];
if ( d[1] > d[0] )
{
t = d[0]; d[0] = d[1]; d[1] = t;
}
}
else
{
d[1] = 0.0;
}
mn++;
mx++;
pt++;
if ( *pt < *mn )
{
d[2] = *mn - *pt;
if ( d[2] > r )
return d[2];
if ( d[2] > d[0] )
{
t = d[0]; d[0] = d[2]; d[2] = t;
}
}
else if ( *pt > *mx )
{
d[2] = *pt - *mx;
if ( d[2] > r )
return d[2];
if ( d[2] > d[0] )
{
t = d[0]; d[0] = d[2]; d[2] = t;
}
}
else
{
d[2] = 0.0;
}
if ( d[0] > 0.0 )
{
d[1] /= d[0];
d[2] /= d[0];
d[0] *= sqrt(1.0 + d[1]*d[1] + d[2]*d[2]);
}
return d[0];
}
static double DistanceToCapsuleAxisHelper(const struct ON_RTreeCapsule* a_capsule, const ON_RTreeBBox* a_rect)
{
double L[2][3], s[2];
if ( 0.0 == a_capsule->m_domain[0] && 1.0 == a_capsule->m_domain[1] )
return ((const ON_BoundingBox*)a_rect->m_min)->MinimumDistanceTo( *((const ON_Line*)a_capsule->m_point[0]) );
if ( 0.0 == a_capsule->m_domain[0] )
{
L[0][0] = a_capsule->m_point[0][0];
L[0][1] = a_capsule->m_point[0][1];
L[0][2] = a_capsule->m_point[0][2];
}
else
{
s[0] = 1.0 - a_capsule->m_domain[0];
s[1] = a_capsule->m_domain[0];
L[0][0] = s[0]*a_capsule->m_point[0][0] + s[1]*a_capsule->m_point[1][0];
L[0][1] = s[0]*a_capsule->m_point[0][1] + s[1]*a_capsule->m_point[1][1];
L[0][2] = s[0]*a_capsule->m_point[0][2] + s[1]*a_capsule->m_point[1][2];
}
if ( 0.0 == a_capsule->m_domain[1] )
{
L[1][0] = a_capsule->m_point[1][0];
L[1][1] = a_capsule->m_point[1][1];
L[1][2] = a_capsule->m_point[1][2];
}
else
{
s[0] = 1.0 - a_capsule->m_domain[1];
s[1] = a_capsule->m_domain[1];
L[1][0] = s[0]*a_capsule->m_point[0][0] + s[1]*a_capsule->m_point[1][0];
L[1][1] = s[0]*a_capsule->m_point[0][1] + s[1]*a_capsule->m_point[1][1];
L[1][2] = s[0]*a_capsule->m_point[0][2] + s[1]*a_capsule->m_point[1][2];
}
return ((const ON_BoundingBox*)a_rect->m_min)->MinimumDistanceTo( *((const ON_Line*)L[0]) );
}
// Add a node to the reinsertion list. All its branches will later
// be reinserted into the index structure.
void ON_RTree::ReInsert(ON_RTreeNode* a_node, ON_RTreeListNode** a_listNode)
{
ON_RTreeListNode* newListNode;
newListNode = m_mem_pool.AllocListNode();
newListNode->m_node = a_node;
newListNode->m_next = *a_listNode;
*a_listNode = newListNode;
}
static
bool OverlapBoundedPlaneXYZHelper( const double* a_bounded_plane, const ON_RTreeBBox* a_rect )
{
unsigned char flag = 0;
double x, y, z, d, v;
// check the 8 corners of the box minimizing the number of evaluations
// and unrolling the loop for speed
// corner = (min, min, min)
x = a_bounded_plane[0]*a_rect->m_min[0];
y = a_bounded_plane[1]*a_rect->m_min[1];
z = a_bounded_plane[2]*a_rect->m_min[2];
d = a_bounded_plane[3];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
flag = 1;
else if ( v > a_bounded_plane[5] )
flag = 2;
else
return true;
// corner = (max, min, min)
x = a_bounded_plane[0]*a_rect->m_max[0];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (max, max, min)
y = a_bounded_plane[1]*a_rect->m_max[1];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (max, max, max)
z = a_bounded_plane[2]*a_rect->m_max[2];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (min, max, max)
x = a_bounded_plane[0]*a_rect->m_min[0];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (min, min, max)
y = a_bounded_plane[1]*a_rect->m_min[1];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (max, min, max)
x = a_bounded_plane[0]*a_rect->m_max[0];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// corner = (min, max, min)
x = a_bounded_plane[0]*a_rect->m_min[0];
y = a_bounded_plane[1]*a_rect->m_max[1];
z = a_bounded_plane[2]*a_rect->m_min[2];
v = x + y + z + d;
if ( v < a_bounded_plane[4] )
{
flag |= 1;
if ( 3 == flag )
return true;
}
else if ( v > a_bounded_plane[5] )
{
flag |= 2;
if ( 3 == flag )
return true;
}
else
return true;
// Either all 8 box corners
// are below the min plane (flag=1)
// or above the max plane (flag=2).
return false;
}
static
bool SearchBoundedPlaneXYZHelper(const ON_RTreeNode* a_node, const double* a_bounded_plane, ON_RTreeSearchResultCallback& a_result )
{
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapBoundedPlaneXYZHelper(a_bounded_plane, &branch[i].m_rect))
{
if(!SearchBoundedPlaneXYZHelper(branch[i].m_child, a_bounded_plane, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
for(i=0; i < count; ++i)
{
if(OverlapBoundedPlaneXYZHelper(a_bounded_plane, &branch[i].m_rect))
{
if ( !a_result.m_resultCallback( a_result.m_context, branch[i].m_id ) )
{
// callback canceled search
return false;
}
}
}
}
}
return true; // Continue searching
}
bool ON_RTree::Search(
const class ON_PlaneEquation& a_plane_eqn,
double a_min,
double a_max,
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_id),
void* a_context
) const
{
return Search(&a_plane_eqn.x, a_min, a_max, a_resultCallback, a_context);
}
bool ON_RTree::Search(
const double a_plane_eqn[4],
double a_min,
double a_max,
bool ON_CALLBACK_CDECL a_resultCallback(void* a_context, ON__INT_PTR a_id),
void* a_context
) const
{
if ( 0 == m_root
|| 0 == a_plane_eqn
|| !(a_min <= a_max)
|| (0.0 == a_plane_eqn[0] && 0.0 == a_plane_eqn[1] && 0.0 == a_plane_eqn[2])
)
return false;
double bounded_plane[6];
bounded_plane[0] = a_plane_eqn[0];
bounded_plane[1] = a_plane_eqn[1];
bounded_plane[2] = a_plane_eqn[2];
bounded_plane[3] = a_plane_eqn[3];
bounded_plane[4] = a_min;
bounded_plane[5] = a_max;
ON_RTreeSearchResultCallback result;
result.m_context = a_context;
result.m_resultCallback = a_resultCallback;
return SearchBoundedPlaneXYZHelper(m_root, bounded_plane, result);
}
// Search in an index tree or subtree for all data retangles that overlap the argument rectangle.
static
bool SearchHelper(const ON_RTreeNode* a_node, ON_RTreeBBox* a_rect, ON_RTreeSearchResultCallback& a_result )
{
// NOTE:
// Some versions of ON_RTree::Search shrink a_rect as the search progresses.
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if(!SearchHelper(branch[i].m_child, a_rect, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
for(i=0; i < count; ++i)
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if ( !a_result.m_resultCallback( a_result.m_context, branch[i].m_id ) )
{
// callback canceled search
return false;
}
}
}
}
}
return true; // Continue searching
}
static
bool SearchHelper(const ON_RTreeNode* a_node, struct ON_RTreeSphere* a_sphere, ON_RTreeSearchResultCallback& a_result )
{
// NOTE:
// Some versions of ON_RTree::Search shrink a_sphere as the search progresses.
int i, closest_i, count;
const double* sphere_center;
const ON_RTreeBranch* branch;
double r[ON_RTree_MAX_NODE_COUNT], sphere_radius, closest_d;
if ( (count = a_node->m_count) > 0 )
{
branch = a_node->m_branch;
sphere_center = a_sphere->m_point;
sphere_radius = a_sphere->m_radius;
closest_i = -1;
closest_d = sphere_radius;
for( i = 0; i < count; ++i )
{
// The radius parameter passed to DistanceToBoxHelper()
// needs to be sphere_radius and not closest_d in order
// for the for() loops below to work correctly.
r[i] = DistanceToBoxHelper( sphere_center, sphere_radius, &branch[i].m_rect );
if ( r[i] <= closest_d )
{
closest_d = r[i];
closest_i = i;
}
}
// If all of the branches rectangles do not intersect the sphere,
// then closest_i = -1.
if ( closest_i >= 0 )
{
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed.
// Search a closer node first to avoid worst case search times
// in calculations where the calls to a_result.m_resultCallback()
// reduce a_sphere->m_radius as results are found. Closest point
// calculations are an example.
if ( !SearchHelper(branch[closest_i].m_child, a_sphere, a_result) )
{
// callback canceled search
return false;
}
for( i = 0; i < count; ++i )
{
// Note that the calls to SearchHelper() can reduce the
// value of a_sphere->m_radius.
if( i != closest_i && r[i] <= a_sphere->m_radius )
{
if(!SearchHelper(branch[i].m_child, a_sphere, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
// Search a closer node first to avoid worst case search times
// in calculations where the calls to a_result.m_resultCallback()
// reduce a_sphere->m_radius as results are found. Closest point
// calculations are an example.
if ( !a_result.m_resultCallback( a_result.m_context, branch[closest_i].m_id ) )
{
// callback canceled search
return false;
}
for( i = 0; i < count; ++i)
{
// Note that the calls to a_result.m_resultCallback() can reduce
// the value of a_sphere->m_radius.
if( i != closest_i && r[i] <= a_sphere->m_radius )
{
if ( !a_result.m_resultCallback( a_result.m_context, branch[i].m_id ) )
{
// callback canceled search
return false;
}
}
}
}
}
}
return true; // Continue searching
}
static
bool SearchHelper(const ON_RTreeNode* a_node, struct ON_RTreeCapsule* a_capsule, ON_RTreeSearchResultCallback& a_result )
{
// NOTE:
// Some versions of ON_RTree::Search shrink a_sphere as the search progresses.
int i, count;
double r[2];
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
if ( count > 1 )
{
// search a closer node first to avoid worst case search times
// in closest point style calculations
r[0] = DistanceToCapsuleAxisHelper( a_capsule, &branch[0].m_rect );
r[1] = DistanceToCapsuleAxisHelper( a_capsule, &branch[count-1].m_rect );
i = ( r[0] <= r[1] ) ? 0 : count-1;
if ( (r[i?1:0] <= a_capsule->m_radius && !SearchHelper(branch[i].m_child, a_capsule, a_result))
|| (r[i?0:1] <= a_capsule->m_radius && !SearchHelper(branch[count-1 - i].m_child, a_capsule, a_result))
)
{
// callback canceled search
return false;
}
count -= 2;
branch++;
}
r[1] = a_capsule->m_radius;
for( i = 0; i < count; ++i )
{
r[0] = DistanceToCapsuleAxisHelper(a_capsule, &branch[i].m_rect);
if(r[0] <= r[1])
{
if(!SearchHelper(branch[i].m_child, a_capsule, a_result) )
{
return false; // Don't continue searching
}
// a_result.m_resultCallback can shrink the capsule
r[1] = a_capsule->m_radius;
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
if ( count > 1 )
{
// search a closer node first to avoid worst case search times
// in closest point style calculations
r[0] = DistanceToCapsuleAxisHelper( a_capsule, &branch[0].m_rect );
r[1] = DistanceToCapsuleAxisHelper( a_capsule, &branch[count-1].m_rect );
i = ( r[0] <= r[1] ) ? 0 : count-1;
if ( (r[i?1:0] <= a_capsule->m_radius && !a_result.m_resultCallback( a_result.m_context, branch[i].m_id ))
|| (r[i?0:1] <= a_capsule->m_radius && !a_result.m_resultCallback( a_result.m_context, branch[count-1 - i].m_id ))
)
{
// callback canceled search
return false;
}
count -= 2;
branch++;
}
r[1] = a_capsule->m_radius;
for( i = 0; i < count; ++i)
{
r[0] = DistanceToCapsuleAxisHelper(a_capsule, &branch[i].m_rect);
if(r[0] <= r[1])
{
if ( !a_result.m_resultCallback( a_result.m_context, branch[i].m_id ) )
{
// callback canceled search
return false;
}
// a_result.m_resultCallback can shrink the capsule
r[1] = a_capsule->m_radius;
}
}
}
}
return true; // Continue searching
}
// Search in an index tree or subtree for all data retangles that overlap the argument rectangle.
static bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<ON_RTreeLeaf> &a_result)
{
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if(!SearchHelper(branch[i].m_child, a_rect, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return point to the branch
for(i=0; i < count; ++i)
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
ON_RTreeLeaf& leaf = a_result.AppendNew();
leaf.m_rect = branch[i].m_rect;
leaf.m_id = branch[i].m_id;
}
}
}
}
return true; // Continue searching
}
static
bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<void*> &a_result)
{
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if(!SearchHelper(branch[i].m_child, a_rect, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
for(i=0; i < count; ++i)
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
// The (void*) cast is safe because branch[i].m_id is an ON__INT_PTR
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_PUSH
// Disable warning C4312: 'type cast' : conversion from 'const ON__INT_PTR' to 'void *' of greater size
#pragma ON_PRAGMA_WARNING_DISABLE_MSC( 4312 )
#endif
a_result.Append( (void*)branch[i].m_id );
#if defined(ON_COMPILER_MSC) && 4 == ON_SIZEOF_POINTER
#pragma ON_PRAGMA_WARNING_POP
#endif
}
}
}
}
return true; // Continue searching
}
static
bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_SimpleArray<int> &a_result)
{
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if(!SearchHelper(branch[i].m_child, a_rect, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
for(i=0; i < count; ++i)
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
a_result.Append( (int)branch[i].m_id );
}
}
}
}
return true; // Continue searching
}
static
bool SearchHelper(const ON_RTreeNode* a_node, const ON_RTreeBBox* a_rect, ON_RTreeSearchResult& a_result)
{
int i, count;
if ( (count = a_node->m_count) > 0 )
{
const ON_RTreeBranch* branch = a_node->m_branch;
if(a_node->IsInternalNode())
{
// a_node is an internal node - search m_branch[].m_child as needed
for( i=0; i < count; ++i )
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if(!SearchHelper(branch[i].m_child, a_rect, a_result) )
{
return false; // Don't continue searching
}
}
}
}
else
{
// a_node is a leaf node - return m_branch[].m_id values
for(i=0; i < count; ++i)
{
if(OverlapHelper(a_rect, &branch[i].m_rect))
{
if ( a_result.m_count >= a_result.m_capacity )
return false; // No more space for results
a_result.m_id[a_result.m_count++] = branch[i].m_id;
}
}
}
}
return true; // Continue searching
}