1 module rtree;
2 
3 /******************************************************************************
4  * class RTree
5  *
6  * Implementation of $(LINK2 https://en.wikipedia.org/wiki/R-tree, R-Tree), a multidimensional bounding rectangle tree.
7  *
8  * This is ported to D $(LINK2 https://github.com/nushoin/RTree, C++ version by Yariv Barkan).
9  *
10  * Params:
11  * DataType = Referenced data, should be int, void*, obj* etc. no larger than (void*).sizeof and simple type
12  * ElemType = Type of element such as int or float
13  * NumDims  = Number of dimensions such as 2 or 3
14  * ElemTypeReal = Type of element that allows fractional and large values such as float or double, for use in volume calcs
15  *
16  * Example:
17  * ---
18  *     // a 3-dimensional tree
19  *     alias MyTree = RTree!(StructPtr, float, 3);
20  *     auto my_tree = new MyTree();
21  * ---
22  *
23  * Notes: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle.
24  *        This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency.
25  *        Instead of using a callback function for returned results, I recommend use efficient pre-sized, grow-only memory
26  *        array similar to MFC CArray or STL Vector for returning search query result.
27  */
28 class RTree(DataType, ElemType, alias NumDims,
29 	ElemTypeReal, alias int MaxNodes = 8, alias int MinNodes = MaxNodes / 2)
30 {
31 public:
32 
33 	import std.container.array : Array;
34 
35 	// Precomputed volumes of the unit spheres for the first few dimensions
36 	enum float[] UnitSphereVolume = [
37 		0.000000f, 2.000000f, 3.141593f, // Dimension  0,1,2
38 		4.188790f, 4.934802f, 5.263789f, // Dimension  3,4,5
39 		5.167713f, 4.724766f, 4.058712f, // Dimension  6,7,8
40 		3.298509f, 2.550164f, 1.884104f, // Dimension  9,10,11
41 		1.335263f, 0.910629f, 0.599265f, // Dimension  12,13,14
42 		0.381443f, 0.235331f, 0.140981f, // Dimension  15,16,17
43 		0.082146f, 0.046622f, 0.025807f, // Dimension  18,19,20
44 	];
45 
46 	// Unit sphere constant for required number of dimensions
47 	enum unitSphereVolume = cast(ElemTypeReal) UnitSphereVolume[NumDims];
48 
49 	static assert(is(ElemTypeReal : float));
50 	static assert(NumDims >= 2 && NumDims <= 3);
51 	static assert(DataType.sizeof <= (void*).sizeof, "DataType should be no larger than (void*).sizeof");
52 
53 	this()
54 	{
55 		static assert(MaxNodes > MinNodes);
56 		static assert(MinNodes > 0);
57 
58 		m_root = AllocNode();
59 		m_root.m_level = 0;
60 	}
61 
62 	~this()
63 	{
64 		Reset(); // Free, or reset node memory
65 	}
66 
67 	/// Insert entry
68 	/// Params:
69 	///     a_min    = Min of bounding rect
70 	///     a_max    = Max of bounding rect
71 	///     a_dataId = Positive Id of data.  Maybe zero, but negative numbers not allowed.
72 	void insert()(auto ref const ElemType[NumDims] a_min, auto ref const ElemType[NumDims] a_max, DataType a_dataId)
73 	{
74 		debug
75 		{
76 			for(int index=0; index<NumDims; ++index)
77 			{
78 				assert(a_min[index] <= a_max[index]);
79 			}
80 		}
81 
82 		Branch branch;
83 		branch.m_data = a_dataId;
84 		branch.m_child = null;
85 
86 		for(int axis=0; axis<NumDims; ++axis)
87 		{
88 			branch.m_rect.m_min[axis] = a_min[axis];
89 			branch.m_rect.m_max[axis] = a_max[axis];
90 		}
91 
92 		InsertRect(branch, &m_root, 0);
93 	}
94 
95 	/// Remove entry
96 	/// Params:
97 	///     a_min = Min of bounding rect
98 	///     a_max = Max of bounding rect
99 	///     a_dataId = Positive Id of data.  Maybe zero, but negative numbers not allowed.
100 	void remove(const ElemType[NumDims] a_min, const ElemType[NumDims] a_max, DataType a_dataId)
101 	{
102 		debug
103 		{
104 			for(int index=0; index<NumDims; ++index)
105 			{
106 				assert(a_min[index] <= a_max[index]);
107 			}
108 		}
109 
110 		Rect rect;
111 
112 		for(int axis=0; axis<NumDims; ++axis)
113 		{
114 			rect.m_min[axis] = a_min[axis];
115 			rect.m_max[axis] = a_max[axis];
116 		}
117 
118 		RemoveRect(&rect, a_dataId, &m_root);
119 	}
120 
121 	/// Find all within query rectangle
122 	/// Params:
123 	///     a_min = Min of query bounding rect
124 	///     a_max = Max of query bounding rect
125 	/// Returns: Returns the array of entries found
126 	Array!DataType search(const ElemType[NumDims] a_min, const ElemType[NumDims] a_max)
127 	{
128 		debug
129 		{
130 			for(int index=0; index<NumDims; ++index)
131 			{
132 				assert(a_min[index] <= a_max[index]);
133 			}
134 		}
135 
136 		Rect rect;
137 
138 		for(int axis=0; axis<NumDims; ++axis)
139 		{
140 			rect.m_min[axis] = a_min[axis];
141 			rect.m_max[axis] = a_max[axis];
142 		}
143 
144 		// NOTE: May want to return search result another way, perhaps returning the number of found elements here.
145 
146 		Array!DataType result;
147 		Search(m_root, &rect, result);
148 
149 		return result;
150 	}
151 
152 
153 	/// Remove all entries from tree
154 	void removeAll()
155 	{
156 		// Delete all existing nodes
157 		Reset();
158 
159 		m_root = AllocNode();
160 		m_root.m_level = 0;
161 	}
162 
163 	/// Count the data elements in this container.  This is slow as no internal counter is maintained.
164 	int count()
165 	{
166 		int count = 0;
167 		CountRec(m_root, count);
168 
169 		return count;
170 	}
171 
172 protected:
173 
174 	// Minimal bounding rectangle (n-dimensional)
175 	struct Rect
176 	{
177 		ElemType[NumDims] m_min;                      ///< Min dimensions of bounding box
178 		ElemType[NumDims] m_max;                      ///< Max dimensions of bounding box
179 	}
180 
181 	// May be data or may be another subtree
182 	// The parents level determines this.
183 	// If the parents level is 0, then this is data
184 	struct Branch
185 	{
186 		Rect m_rect;                                  ///< Bounds
187 		Node* m_child;                                ///< Child node
188 		DataType m_data;                              ///< Data Id
189 	}
190 
191 	// Node for each branch level
192 	struct Node
193 	{
194 		bool IsInternalNode()                         { return (m_level > 0); } // Not a leaf, but a internal node
195 		bool IsLeaf()                                 { return (m_level == 0); } // A leaf, contains data
196 
197 		int m_count;                                  ///< Count
198 		int m_level;                                  ///< Leaf is zero, others positive
199 		Branch[MaxNodes] m_branch;                    ///< Branch
200 	}
201 
202 	// A link list of nodes for reinsertion after a delete operation
203 	struct ListNode
204 	{
205 		ListNode* m_next;                             ///< Next in list
206 		Node* m_node;                                 ///< Node
207 	}
208 
209 	// Variables for finding a split partition
210 	struct PartitionVars
211 	{
212 		enum { NOT_TAKEN = -1 } // indicates that position
213 
214 		int[MaxNodes+1]    m_partition;
215 		int                m_total;
216 		int                m_minFill;
217 		int[2]             m_count;
218 		Rect[2]            m_cover;
219 		ElemTypeReal[2]    m_area;
220 
221 		Branch[MaxNodes+1] m_branchBuf;
222 		int                m_branchCount;
223 		Rect               m_coverSplit;
224 		ElemTypeReal       m_coverSplitArea;
225 	}
226 
227 	Node* AllocNode()
228 	{
229 		auto newNode = new Node;
230 		InitNode(newNode);
231 		return newNode;
232 	}
233 
234 	void FreeNode(Node* a_node)
235 	{
236 		assert(a_node);
237 		destroy(a_node);
238 		a_node = null;
239 	}
240 
241 	void InitNode(Node* a_node)
242 	{
243 		a_node.m_count = 0;
244 		a_node.m_level = -1;
245 	}
246 
247 	void InitRect(Rect* a_rect)
248 	{
249 		for(int index = 0; index < NumDims; ++index)
250 		{
251 			a_rect.m_min[index] = cast(ElemType) 0;
252 			a_rect.m_max[index] = cast(ElemType) 0;
253 		}
254 	}
255 
256 	bool InsertRectRec(ref Branch a_branch, Node* a_node, Node** a_newNode, int a_level)
257 	{
258 		assert(a_node && a_newNode);
259 		assert(a_level >= 0 && a_level <= a_node.m_level);
260 
261 		// recurse until we reach the correct level for the new record. data records
262 		// will always be called with a_level == 0 (leaf)
263 		if(a_node.m_level > a_level)
264 		{
265 			// Still above level for insertion, go down tree recursively
266 			Node* otherNode;
267 
268 			// find the optimal branch for this record
269 			int index = PickBranch(&a_branch.m_rect, a_node);
270 
271 			// recursively insert this record into the picked branch
272 			bool childWasSplit = InsertRectRec(a_branch, a_node.m_branch[index].m_child, &otherNode, a_level);
273 
274 			if (!childWasSplit)
275 			{
276 				// Child was not split. Merge the bounding box of the new record with the
277 				// existing bounding box
278 				a_node.m_branch[index].m_rect = CombineRect(&a_branch.m_rect, &(a_node.m_branch[index].m_rect));
279 				return false;
280 			}
281 			else
282 			{
283 				// Child was split. The old branches are now re-partitioned to two nodes
284 				// so we have to re-calculate the bounding boxes of each node
285 				a_node.m_branch[index].m_rect = NodeCover(a_node.m_branch[index].m_child);
286 				Branch branch;
287 				branch.m_child = otherNode;
288 				branch.m_rect = NodeCover(otherNode);
289 
290 				// The old node is already a child of a_node. Now add the newly-created
291 				// node to a_node as well. a_node might be split because of that.
292 				return AddBranch(&branch, a_node, a_newNode);
293 			}
294 		}
295 		else if(a_node.m_level == a_level)
296 		{
297 			// We have reached level for insertion. Add rect, split if necessary
298 			return AddBranch(&a_branch, a_node, a_newNode);
299 		}
300 		else
301 		{
302 			// Should never occur
303 			debug
304 			{
305 				assert(0);
306 			}
307 			else
308 			{
309 				return false;
310 			}
311 		}
312 	}
313 
314 	bool InsertRect(ref Branch a_branch, Node** a_root, int a_level)
315 	{
316 		assert(a_root);
317 		assert(a_level >= 0 && a_level <= (*a_root).m_level);
318 		debug
319 		{
320 			for(int index=0; index < NumDims; ++index)
321 			{
322 				assert(a_branch.m_rect.m_min[index] <= a_branch.m_rect.m_max[index]);
323 			}
324 		}
325 
326 		Node* newNode;
327 
328 		if (InsertRectRec(a_branch, *a_root, &newNode, a_level))  // Root split
329 		{
330 			// Grow tree taller and new root
331 			Node* newRoot = AllocNode();
332 			newRoot.m_level = (*a_root).m_level + 1;
333 
334 			Branch branch;
335 
336 			// add old root node as a child of the new root
337 			branch.m_rect = NodeCover(*a_root);
338 			branch.m_child = *a_root;
339 			AddBranch(&branch, newRoot, null);
340 
341 			// add the split node as a child of the new root
342 			branch.m_rect = NodeCover(newNode);
343 			branch.m_child = newNode;
344 			AddBranch(&branch, newRoot, null);
345 
346 			// set the new root as the root node
347 			*a_root = newRoot;
348 
349 			return true;
350 		}
351 
352 		return false;
353 	}
354 
355 	Rect NodeCover(Node* a_node)
356 	{
357 		assert(a_node);
358 
359 		Rect rect = a_node.m_branch[0].m_rect;
360 		for(int index = 1; index < a_node.m_count; ++index)
361 		{
362 			rect = CombineRect(&rect, &(a_node.m_branch[index].m_rect));
363 		}
364 
365 		return rect;
366 	}
367 
368 	bool AddBranch(Branch* a_branch, Node* a_node, Node** a_newNode)
369 	{
370 		assert(a_branch);
371 		assert(a_node);
372 
373 		if(a_node.m_count < MaxNodes)  // Split won't be necessary
374 		{
375 			a_node.m_branch[a_node.m_count] = *a_branch;
376 			++a_node.m_count;
377 
378 			return false;
379 		}
380 		else
381 		{
382 			assert(a_newNode);
383 
384 			SplitNode(a_node, a_branch, a_newNode);
385 			return true;
386 		}
387 	}
388 
389 	void DisconnectBranch(Node* a_node, int a_index)
390 	{
391 		assert(a_node && (a_index >= 0) && (a_index < MaxNodes));
392 		assert(a_node.m_count > 0);
393 
394 		// Remove element by swapping with the last element to prevent gaps in array
395 		a_node.m_branch[a_index] = a_node.m_branch[a_node.m_count - 1];
396 
397 		--a_node.m_count;
398 	}
399 
400 	int PickBranch(const Rect* a_rect, Node* a_node)
401 	{
402 		assert(a_rect && a_node);
403 
404 		bool firstTime = true;
405 		ElemTypeReal increase;
406 		ElemTypeReal bestIncr = cast(ElemTypeReal) -1;
407 		ElemTypeReal area;
408 		ElemTypeReal bestArea;
409 		int best;
410 		Rect tempRect;
411 
412 		for(int index=0; index < a_node.m_count; ++index)
413 		{
414 			Rect* curRect = &a_node.m_branch[index].m_rect;
415 			area = CalcRectVolume(curRect);
416 			tempRect = CombineRect(a_rect, curRect);
417 			increase = CalcRectVolume(&tempRect) - area;
418 			if((increase < bestIncr) || firstTime)
419 			{
420 				best = index;
421 				bestArea = area;
422 				bestIncr = increase;
423 				firstTime = false;
424 			}
425 			else if((increase == bestIncr) && (area < bestArea))
426 			{
427 				best = index;
428 				bestArea = area;
429 				bestIncr = increase;
430 			}
431 		}
432 		return best;
433 	}
434 
435 	Rect CombineRect(const Rect* a_rectA, const Rect* a_rectB)
436 	{
437 		assert(a_rectA && a_rectB);
438 
439 		Rect newRect;
440 
441 		for(int index = 0; index < NumDims; ++index)
442 		{
443 			import std.algorithm : min, max;
444 			newRect.m_min[index] = min(a_rectA.m_min[index], a_rectB.m_min[index]);
445 			newRect.m_max[index] = max(a_rectA.m_max[index], a_rectB.m_max[index]);
446 		}
447 
448 		return newRect;
449 	}
450 
451 	void SplitNode(Node* a_node, Branch* a_branch, Node** a_newNode)
452 	{
453 		assert(a_node);
454 		assert(a_branch);
455 
456 		// Could just use local here, but member or external is faster since it is reused
457 		PartitionVars localVars;
458 		PartitionVars* parVars = &localVars;
459 
460 		// Load all the branches into a buffer, initialize old node
461 		GetBranches(a_node, a_branch, parVars);
462 
463 		// Find partition
464 		ChoosePartition(parVars, MinNodes);
465 
466 		// Create a new node to hold (about) half of the branches
467 		*a_newNode = AllocNode();
468 		(*a_newNode).m_level = a_node.m_level;
469 
470 		// Put branches from buffer into 2 nodes according to the chosen partition
471 		a_node.m_count = 0;
472 		LoadNodes(a_node, *a_newNode, parVars);
473 
474 		assert((a_node.m_count + (*a_newNode).m_count) == parVars.m_total);
475 	}
476 
477 	ElemTypeReal RectSphericalVolume(Rect* a_rect)
478 	{
479 		assert(a_rect);
480 
481 		ElemTypeReal sumOfSquares = cast(ElemTypeReal) 0;
482 		ElemTypeReal radius;
483 
484 		for(int index=0; index < NumDims; ++index)
485 		{
486 			ElemTypeReal halfExtent = (cast(ElemTypeReal) a_rect.m_max[index] - cast(ElemTypeReal) a_rect.m_min[index]) * 0.5f;
487 			sumOfSquares += halfExtent * halfExtent;
488 		}
489 
490 		import std.math : sqrt;
491 		radius = cast(ElemTypeReal) sqrt(sumOfSquares);
492 
493 		// Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x.
494 		static if(NumDims == 3)
495 		{
496 			return (radius * radius * radius * unitSphereVolume);
497 		}
498 		else static if(NumDims == 2)
499 		{
500 			return (radius * radius * unitSphereVolume);
501 		}
502 		else
503 		{
504 			return cast(ElemTypeReal) (pow(radius, NumDims) * unitSphereVolume);
505 		}
506 	}
507 
508 	ElemTypeReal RectVolume(Rect* a_rect)
509 	{
510 		assert(a_rect);
511 
512 		ElemTypeReal volume = cast(ElemTypeReal) 1;
513 
514 		for(int index=0; index<NumDims; ++index)
515 		{
516 			volume *= a_rect.m_max[index] - a_rect.m_min[index];
517 		}
518 
519 		assert(volume >= cast(ElemTypeReal) 0);
520 
521 		return volume;
522 	}
523 
524 	ElemTypeReal CalcRectVolume(Rect* a_rect)
525 	{
526 		version(RTREE_USE_SPHERICAL_VOLUME)
527 		{
528 			return RectSphericalVolume(a_rect); // Slower but helps certain merge cases
529 		}
530 		else
531 		{
532 			return RectVolume(a_rect); // Faster but can cause poor merges
533 		}
534 	}
535 
536 	void GetBranches(Node* a_node, Branch* a_branch, PartitionVars* a_parVars)
537 	{
538 		assert(a_node);
539 		assert(a_branch);
540 
541 		assert(a_node.m_count == MaxNodes);
542 
543 		// Load the branch buffer
544 		for(int index=0; index < MaxNodes; ++index)
545 		{
546 			a_parVars.m_branchBuf[index] = a_node.m_branch[index];
547 		}
548 		a_parVars.m_branchBuf[MaxNodes] = *a_branch;
549 		a_parVars.m_branchCount = MaxNodes + 1;
550 
551 		// Calculate rect containing all in the set
552 		a_parVars.m_coverSplit = a_parVars.m_branchBuf[0].m_rect;
553 		for(int index=1; index < MaxNodes+1; ++index)
554 		{
555 			a_parVars.m_coverSplit = CombineRect(&a_parVars.m_coverSplit, &a_parVars.m_branchBuf[index].m_rect);
556 		}
557 		a_parVars.m_coverSplitArea = CalcRectVolume(&a_parVars.m_coverSplit);
558 	}
559 
560 	void ChoosePartition(PartitionVars* a_parVars, int a_minFill)
561 	{
562 		assert(a_parVars);
563 
564 		ElemTypeReal biggestDiff;
565 		int group, chosen, betterGroup;
566 
567 		InitParVars(a_parVars, a_parVars.m_branchCount, a_minFill);
568 		PickSeeds(a_parVars);
569 
570 		while (((a_parVars.m_count[0] + a_parVars.m_count[1]) < a_parVars.m_total)
571 			&& (a_parVars.m_count[0] < (a_parVars.m_total - a_parVars.m_minFill))
572 			&& (a_parVars.m_count[1] < (a_parVars.m_total - a_parVars.m_minFill)))
573 		{
574 			biggestDiff = cast(ElemTypeReal) -1;
575 			for(int index=0; index<a_parVars.m_total; ++index)
576 			{
577 				if(PartitionVars.NOT_TAKEN == a_parVars.m_partition[index])
578 				{
579 					Rect* curRect = &a_parVars.m_branchBuf[index].m_rect;
580 					Rect rect0 = CombineRect(curRect, &a_parVars.m_cover[0]);
581 					Rect rect1 = CombineRect(curRect, &a_parVars.m_cover[1]);
582 					ElemTypeReal growth0 = CalcRectVolume(&rect0) - a_parVars.m_area[0];
583 					ElemTypeReal growth1 = CalcRectVolume(&rect1) - a_parVars.m_area[1];
584 					ElemTypeReal diff = growth1 - growth0;
585 					if(diff >= 0)
586 					{
587 						group = 0;
588 					}
589 					else
590 					{
591 						group = 1;
592 						diff = -diff;
593 					}
594 
595 					if(diff > biggestDiff)
596 					{
597 						biggestDiff = diff;
598 						chosen = index;
599 						betterGroup = group;
600 					}
601 					else if((diff == biggestDiff) && (a_parVars.m_count[group] < a_parVars.m_count[betterGroup]))
602 					{
603 						chosen = index;
604 						betterGroup = group;
605 					}
606 				}
607 			}
608 			Classify(chosen, betterGroup, a_parVars);
609 		}
610 
611 		// If one group too full, put remaining rects in the other
612 		if((a_parVars.m_count[0] + a_parVars.m_count[1]) < a_parVars.m_total)
613 		{
614 			if(a_parVars.m_count[0] >= a_parVars.m_total - a_parVars.m_minFill)
615 			{
616 				group = 1;
617 			}
618 			else
619 			{
620 				group = 0;
621 			}
622 
623 			for(int index=0; index<a_parVars.m_total; ++index)
624 			{
625 				if(PartitionVars.NOT_TAKEN == a_parVars.m_partition[index])
626 				{
627 					Classify(index, group, a_parVars);
628 				}
629 			}
630 		}
631 
632 		assert((a_parVars.m_count[0] + a_parVars.m_count[1]) == a_parVars.m_total);
633 		assert((a_parVars.m_count[0] >= a_parVars.m_minFill) &&
634 			(a_parVars.m_count[1] >= a_parVars.m_minFill));
635 	}
636 
637 	void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars)
638 	{
639 		assert(a_nodeA);
640 		assert(a_nodeB);
641 		assert(a_parVars);
642 
643 		for(int index=0; index < a_parVars.m_total; ++index)
644 		{
645 			assert(a_parVars.m_partition[index] == 0 || a_parVars.m_partition[index] == 1);
646 
647 			int targetNodeIndex = a_parVars.m_partition[index];
648 			Node*[2] targetNodes = [a_nodeA, a_nodeB];
649 
650 			// It is assured that AddBranch here will not cause a node split.
651 			bool nodeWasSplit = AddBranch(&a_parVars.m_branchBuf[index], targetNodes[targetNodeIndex], null);
652 			assert(!nodeWasSplit);
653 		}
654 	}
655 
656 	void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill)
657 	{
658 		assert(a_parVars);
659 
660 		a_parVars.m_count[0] = a_parVars.m_count[1] = 0;
661 		a_parVars.m_area[0] = a_parVars.m_area[1] = cast(ElemTypeReal) 0;
662 		a_parVars.m_total = a_maxRects;
663 		a_parVars.m_minFill = a_minFill;
664 		for(int index=0; index < a_maxRects; ++index)
665 		{
666 			a_parVars.m_partition[index] = PartitionVars.NOT_TAKEN;
667 		}
668 	}
669 
670 	void PickSeeds(PartitionVars* a_parVars)
671 	{
672 		int seed0 = 0;
673 		int seed1 = seed0 + 1;
674 		ElemTypeReal worst, waste;
675 		ElemTypeReal[MaxNodes+1] area;
676 
677 		for(int index=0; index<a_parVars.m_total; ++index)
678 		{
679 			area[index] = CalcRectVolume(&a_parVars.m_branchBuf[index].m_rect);
680 		}
681 
682 		worst = -a_parVars.m_coverSplitArea - 1;
683 		for(int indexA = seed0; indexA < a_parVars.m_total-1; ++indexA)
684 		{
685 			for(int indexB = seed1; indexB < a_parVars.m_total; ++indexB)
686 			{
687 				Rect oneRect = CombineRect(&a_parVars.m_branchBuf[indexA].m_rect, &a_parVars.m_branchBuf[indexB].m_rect);
688 				waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB];
689 				if(waste > worst)
690 				{
691 					worst = waste;
692 					seed0 = indexA;
693 					seed1 = indexB;
694 				}
695 			}
696 		}
697 
698 		Classify(seed0, 0, a_parVars);
699 		Classify(seed1, 1, a_parVars);
700 	}
701 
702 	void Classify(int a_index, int a_group, PartitionVars* a_parVars)
703 	{
704 		assert(a_parVars);
705 		assert(PartitionVars.NOT_TAKEN == a_parVars.m_partition[a_index]);
706 
707 		a_parVars.m_partition[a_index] = a_group;
708 
709 		// Calculate combined rect
710 		if (a_parVars.m_count[a_group] == 0)
711 		{
712 			a_parVars.m_cover[a_group] = a_parVars.m_branchBuf[a_index].m_rect;
713 		}
714 		else
715 		{
716 			a_parVars.m_cover[a_group] = CombineRect(&a_parVars.m_branchBuf[a_index].m_rect, &a_parVars.m_cover[a_group]);
717 		}
718 
719 		// Calculate volume of combined rect
720 		a_parVars.m_area[a_group] = CalcRectVolume(&a_parVars.m_cover[a_group]);
721 
722 		++a_parVars.m_count[a_group];
723 	}
724 
725 	bool RemoveRect(Rect* a_rect, ref const DataType a_id, Node** a_root)
726 	{
727 		assert(a_rect && a_root);
728 		assert(*a_root);
729 
730 		ListNode* reInsertList = null;
731 
732 		if (!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList))
733 		{
734 			// Found and deleted a data item
735 			// Reinsert any branches from eliminated nodes
736 			while(reInsertList)
737 			{
738 				Node* tempNode = reInsertList.m_node;
739 
740 				for(int index = 0; index < tempNode.m_count; ++index)
741 				{
742 					// TODO go over this code. should I use (tempNode.m_level - 1)?
743 					InsertRect(tempNode.m_branch[index],
744 					       a_root,
745 					       tempNode.m_level);
746 				}
747 
748 				ListNode* remLNode = reInsertList;
749 				reInsertList = reInsertList.m_next;
750 
751 				FreeNode(remLNode.m_node);
752 				FreeListNode(remLNode);
753 			}
754 
755 			// Check for redundant root (not leaf, 1 child) and eliminate TODO replace
756 			// if with while? In case there is a whole branch of redundant roots...
757 			if((*a_root).m_count == 1 && (*a_root).IsInternalNode())
758 			{
759 				Node* tempNode = (*a_root).m_branch[0].m_child;
760 
761 				assert(tempNode);
762 				FreeNode(*a_root);
763 				*a_root = tempNode;
764 			}
765 			return false;
766 		}
767 		else
768 		{
769 			return true;
770 		}
771 	}
772 
773 	bool RemoveRectRec(Rect* a_rect, ref const DataType a_id, Node* a_node, ListNode** a_listNode)
774 	{
775 		assert(a_rect && a_node && a_listNode);
776 		assert(a_node.m_level >= 0);
777 
778 		if(a_node.IsInternalNode())  // not a leaf node
779 		{
780 			for(int index = 0; index < a_node.m_count; ++index)
781 			{
782 				if(Overlap(a_rect, &(a_node.m_branch[index].m_rect)))
783 				{
784 					if(!RemoveRectRec(a_rect, a_id, a_node.m_branch[index].m_child, a_listNode))
785 					{
786 						if(a_node.m_branch[index].m_child.m_count >= MinNodes)
787 						{
788 							// child removed, just resize parent rect
789 							a_node.m_branch[index].m_rect = NodeCover(a_node.m_branch[index].m_child);
790 						}
791 						else
792 						{
793 							// child removed, not enough entries in node, eliminate node
794 							ReInsert(a_node.m_branch[index].m_child, a_listNode);
795 							DisconnectBranch(a_node, index); // Must return after this call as count has changed
796 						}
797 						return false;
798 					}
799 				}
800 			}
801 			return true;
802 		}
803 		else // A leaf node
804 		{
805 			for(int index = 0; index < a_node.m_count; ++index)
806 			{
807 				if(a_node.m_branch[index].m_data == a_id)
808 				{
809 					DisconnectBranch(a_node, index); // Must return after this call as count has changed
810 					return false;
811 				}
812 			}
813 			return true;
814 		}
815 	}
816 
817 	ListNode* AllocListNode()
818 	{
819 		return new ListNode;
820 	}
821 
822 	void FreeListNode(ListNode* a_listNode)
823 	{
824 		destroy(a_listNode);
825 	}
826 
827 	bool Overlap(Rect* a_rectA, Rect* a_rectB)
828 	{
829 		assert(a_rectA && a_rectB);
830 
831 		for(int index=0; index < NumDims; ++index)
832 		{
833 			if (a_rectA.m_min[index] > a_rectB.m_max[index] ||
834 				a_rectB.m_min[index] > a_rectA.m_max[index])
835 			{
836 				return false;
837 			}
838 		}
839 		return true;
840 	}
841 
842 	void ReInsert(Node* a_node, ListNode** a_listNode)
843 	{
844 		ListNode* newListNode;
845 
846 		newListNode = AllocListNode();
847 		newListNode.m_node = a_node;
848 		newListNode.m_next = *a_listNode;
849 		*a_listNode = newListNode;
850 	}
851 
852 	bool Search(Node* a_node, Rect* a_rect, ref Array!DataType result)
853 	{
854 		assert(a_node);
855 		assert(a_node.m_level >= 0);
856 		assert(a_rect);
857 
858 		if(a_node.IsInternalNode())
859 		{
860 			// This is an internal node in the tree
861 			for(int index=0; index < a_node.m_count; ++index)
862 			{
863 				if(Overlap(a_rect, &a_node.m_branch[index].m_rect))
864 				{
865 					Search(a_node.m_branch[index].m_child, a_rect, result);
866 				}
867 			}
868 		}
869 		else
870 		{
871 			// This is a leaf node
872 			for(int index=0; index < a_node.m_count; ++index)
873 			{
874 				if(Overlap(a_rect, &a_node.m_branch[index].m_rect))
875 				{
876 					result ~= a_node.m_branch[index].m_data;
877 				}
878 			}
879 		}
880 
881 		return true; // Continue searching
882 	}
883 
884 	void RemoveAllRec(Node* a_node)
885 	{
886 		assert(a_node);
887 		assert(a_node.m_level >= 0);
888 
889 		if(a_node.IsInternalNode()) // This is an internal node in the tree
890 		{
891 			for(int index=0; index < a_node.m_count; ++index)
892 			{
893 				RemoveAllRec(a_node.m_branch[index].m_child);
894 			}
895 		}
896 		FreeNode(a_node);
897 	}
898 
899 	void Reset()
900 	{
901 		RemoveAllRec(m_root);
902 	}
903 
904 	void CountRec(Node* a_node, ref int a_count)
905 	{
906 		if(a_node.IsInternalNode())  // not a leaf node
907 		{
908 			for(int index = 0; index < a_node.m_count; ++index)
909 			{
910 				CountRec(a_node.m_branch[index].m_child, a_count);
911 			}
912 		}
913 		else // A leaf node
914 		{
915 			a_count += a_node.m_count;
916 		}
917 	}
918 
919 	// Root of tree
920 	Node* m_root;
921 }