1 #include <2geom/orphan-code/rtree.h>
2 #include <limits>
3
4 /*
5 Based on source (BibTex):
6 @inproceedings{DBLP:conf/sigmod/Guttman84,
7 author = {Antonin Guttman},
8 title = {R-Trees: A Dynamic Index Structure for Spatial Searching},
9 booktitle = {SIGMOD Conference},
10 year = {1984},
11 pages = {47-57},
12 ee = {http://doi.acm.org/10.1145/602259.602266, db/conf/sigmod/Guttman84.html},
13 }
14 */
15
16 /*
17 #define _RTREE_PRINT(x) std::cout << x << std::endl;
18 #define _RTREE_PRINT_TREE( x, y ) print_tree( x, y );
19 #define _RTREE_PRINT_TREE_INS( x, y, z ) print_tree( x, y, z );
20 */
21 //comment the following if you want output during RTree operations
22
23
24 #define _RTREE_PRINT(x) ;
25 #define _RTREE_PRINT_TREE( x, y ) ;
26 #define _RTREE_PRINT_TREE_INS( x, y, z ) ;
27
28
29
30 /*
31 TODO 1
32 some if(non_leaf)
33 else // leaf
34 could be eliminated when function starts from a leaf
35 do leaf action
36 then repeat function for non-leafs only
37 candidates:
38 - adjust_tree
39 - condense_tree
40
41 TODO 2
42 generalize in a different way the splitting techniques
43
44 */
45
46
47 namespace Geom{
48
49 /*=============================================================================
50 insert
51 ===============================================================================
52 insert a new index entry E into the R-tree:
53
54 I1) find position of new record:
55 choose_node will find a leaf node L (position) in which to place r
56 I2) add record to leaf node:
57 if L has room for another entry install E
58 else split_node will obtain L and LL containing E and all the old entries of L
59 from the available splitting strategies we chose quadtratic-cost algorithm (just to begin
60 with sth)
61 // TODO implement more of them
62 I3) propagate changes upward:
63 Invoke adjust_tree on L, also passing LL if a split was performed.
64 I4) grow tree taller:
65 if a node spilt propagation, cuased the root to split
66 create new root whose children are the 2 resulting nodes
67 */
68
insert(Rect const & r,unsigned shape)69 void RTree::insert( Rect const &r, unsigned shape ){
70 _RTREE_PRINT("\n=====================================");
71 _RTREE_PRINT("insert");
72 RTreeRecord_Leaf* leaf_record= new RTreeRecord_Leaf( r, shape );
73 insert( *leaf_record );
74 }
75
76
77
insert(const RTreeRecord_Leaf & leaf_record,const bool & insert_high,const unsigned & stop_height,const RTreeRecord_NonLeaf & nonleaf_record)78 void RTree::insert( const RTreeRecord_Leaf &leaf_record,
79 const bool &insert_high /* false */,
80 const unsigned &stop_height /* 0 */,
81 const RTreeRecord_NonLeaf &nonleaf_record /* 0 */
82 )
83 {
84 _RTREE_PRINT("\n--------------");
85 _RTREE_PRINT("insert private. element:" << leaf_record.data << " insert high:" << insert_high << " stop height:" << stop_height );
86 RTreeNode *position = 0;
87
88 // if tree is unused create the root Node, not described in source, stupid me :P
89 if(root == 0){
90 root = new RTreeNode();
91 }
92
93 _RTREE_PRINT("I1"); // I1
94 if( insert_high == false ){ // choose leaf node
95 position = choose_node( leaf_record.bounding_box );
96 }
97 else { // choose nonleaf node
98 position = choose_node( nonleaf_record.bounding_box, insert_high, stop_height );
99 }
100 _RTREE_PRINT("leaf node chosen: " );
101 _RTREE_PRINT_TREE( position , 0 );
102 std::pair< RTreeNode*, RTreeNode* > node_division;
103
104 bool split_performed = false;
105
106 if( position->children_nodes.size() > 0 ){ // non-leaf node: position
107 // we must reach here only to insert high non leaf node, not insert leaf node
108 assert( insert_high == true );
109
110 // put new element in node temporarily. Later on, if we need to, we will split the node.
111 position->children_nodes.push_back( nonleaf_record );
112 if( position->children_nodes.size() <= max_records ){
113 _RTREE_PRINT("I2 nonleaf: no split: " << position->children_nodes.size() ); // I2
114 }
115 else{
116 _RTREE_PRINT("I2 nonleaf: split: " << position->children_nodes.size() ); // I2
117 node_division = split_node( position );
118 split_performed = true;
119 }
120
121 }
122 else { // leaf node: position:
123 // we must reach here only to insert leaf node, not insert high non leaf node
124 assert( insert_high == false );
125
126
127 // put new element in node temporarily. Later on, if we need to, we will split the node.
128 position->children_leaves.push_back( leaf_record );
129 if( position->children_leaves.size() <= max_records ){
130 _RTREE_PRINT("I2 leaf: no split: " << position->children_leaves.size() ); // I2
131 }
132 else{
133 _RTREE_PRINT("I2 leaf: split: " << position->children_leaves.size() << " max_records:" << max_records); // I2
134 node_division = split_node( position );
135 split_performed = true;
136
137 _RTREE_PRINT(" group A");
138 _RTREE_PRINT_TREE( node_division.first , 3 );
139 _RTREE_PRINT(" group B");
140 _RTREE_PRINT_TREE( node_division.second , 3 );
141
142 }
143
144 }
145
146 _RTREE_PRINT("I3"); // I3
147 bool root_split_performed = adjust_tree( position, node_division, split_performed );
148 _RTREE_PRINT("root split: " << root_split_performed);
149
150
151 // _RTREE_PRINT("TREE:");
152 // print_tree( root , 2 );
153
154 _RTREE_PRINT("I4"); // I4
155 if( root_split_performed ){
156 std::pair<RTreeNode*, RTreeNode*> root_division;
157 root_division = quadratic_split( root ); // AT5
158
159 Rect first_record_bounding_box;
160 Rect second_record_bounding_box;
161
162 RTreeRecord_NonLeaf first_new_record = create_nonleaf_record_from_rtreenode( first_record_bounding_box, root_division.first );
163 RTreeRecord_NonLeaf second_new_record = create_nonleaf_record_from_rtreenode( second_record_bounding_box, root_division.second );
164 _RTREE_PRINT(" 1st:");
165 _RTREE_PRINT_TREE( first_new_record.data, 5 );
166 _RTREE_PRINT(" 2nd:");
167 _RTREE_PRINT_TREE( second_new_record.data, 5 );
168
169 // *new* root is by definition non-leaf. Install the new records there
170 RTreeNode* new_root = new RTreeNode();
171 new_root->children_nodes.push_back( first_new_record );
172 new_root->children_nodes.push_back( second_new_record );
173
174 delete root;
175
176 root = new_root;
177 tree_height++; // increse tree height
178
179 _RTREE_PRINT_TREE( root, 5 );
180 sanity_check( root, 0 );
181 }
182 _RTREE_PRINT("done");
183
184 /*
185 the node_division.second is saved on the tree
186 the node_division.first was copied in existing tree in node
187 so we don't need this anymore
188 */
189 delete node_division.first;
190 }
191
192 /* I1 =========================================================================
193
194 original: choose_node will find a leaf node L in which to place r
195 changed to choose_node will find a node L in which to place r
196 the node L is:
197 non-leaf: if flag is set. the height of the node is insert_at_height
198 leaf: if flag is NOT set
199
200 1) Initialize: set N to be the root node
201 2) Leaf Check:
202 insert_height = false
203 if N is leaf return N
204 insert_height = true
205 3) Choose subtree: If N not leaf OR not we are not in the proper height then
206 let F be an entry in N whose rect Fi needs least enlargement to include r
207 ties resolved with rect of smallest area
208 4) descend until a leaf is reached OR proper height is reached: set N to the child node pointed to by F and goto 2.
209 */
210
211 // TODO keep stack with visited nodes
212
choose_node(const Rect & r,const bool & insert_high,const unsigned & stop_height) const213 RTreeNode* RTree::choose_node( const Rect &r, const bool &insert_high /* false */, const unsigned &stop_height /* 0 */) const {
214
215 _RTREE_PRINT(" CL1");// CL1
216 RTreeNode *pos = root;
217
218 double min_enlargement;
219 double current_enlargement;
220 int node_min_enlargement;
221 unsigned current_height = 0; // zero is the root
222
223 _RTREE_PRINT(" CL2 current_height:" << current_height << " stop_height:" << stop_height << " insert_high:" << insert_high);
224 // CL2 Leaf check && Height check
225 while( ( insert_high ? true : pos->children_nodes.size() != 0 )
226 && ( insert_high ? current_height < stop_height : true ) )
227 /* Leaf check, during insert leaf */
228 /* node height check, during insert non-leaf */
229 {
230 _RTREE_PRINT(" CL3 current_height:" << current_height << " stop_height:" << stop_height ); // CL3
231 min_enlargement = std::numeric_limits<double>::max();
232 current_enlargement = 0;
233 node_min_enlargement = 0;
234
235 for(unsigned i=0; i< pos->children_nodes.size(); i++){
236 current_enlargement = find_enlargement( pos->children_nodes[i].bounding_box, r );
237
238 // TODO tie not solved!
239 if( current_enlargement < min_enlargement ){
240 node_min_enlargement = i;
241 min_enlargement = current_enlargement;
242 }
243 }
244 _RTREE_PRINT(" CL4"); // CL4
245 // descend to the node with the min_enlargement
246 pos = pos->children_nodes[node_min_enlargement].data;
247 current_height++; // increase current visiting height
248 }
249
250 return pos;
251 }
252
253
254 /*
255 find_enlargement:
256
257 enlargement that "a" needs in order to include "b"
258 b is the new rect we want to insert.
259 a is the rect of the node we try to see if b should go in.
260 */
find_enlargement(const Rect & a,const Rect & b) const261 double RTree::find_enlargement( const Rect &a, const Rect &b ) const{
262
263
264 Rect union_rect(a);
265 union_rect.unionWith(b);
266
267 OptRect a_intersection_b = intersect( a, b );
268
269 // a, b do not intersect
270 if( a_intersection_b.empty() ){
271 _RTREE_PRINT(" find_enlargement (no intersect): " << union_rect.area() - a.area() - b.area() );
272 return union_rect.area() - a.area() - b.area();
273 }
274
275 // a, b intersect
276
277 // a contains b
278 if( a.contains( b ) ){
279 _RTREE_PRINT(" find_enlargement (intersect: a cont b): " << a.area() - b.area() );
280 //return a.area() - b.area();
281 return b.area() - a.area(); // enlargement is negative in this case.
282 }
283
284 // b contains a
285 if( b.contains( a ) ){
286 _RTREE_PRINT(" find_enlargement (intersect: b cont a): " << a.area() - b.area() );
287 return b.area() - a.area();
288 }
289
290 // a partially cover b
291 _RTREE_PRINT(" find_enlargement (intersect: a partial cover b): " << union_rect.area() - a.area() - b.area() - a_intersection_b->area() );
292 return union_rect.area()
293 - ( a.area() - a_intersection_b->area() )
294 - ( b.area() - a_intersection_b->area() );
295 }
296
297
298 /* I2 =========================================================================
299 use one split strategy
300 */
301
split_node(RTreeNode * s)302 std::pair<RTreeNode*, RTreeNode*> RTree::split_node( RTreeNode *s ){
303 /*
304 if( split_strategy == LINEAR_COST ){
305 linear_cost_split( ............. );
306 }
307 */
308 return quadratic_split( s ); // else QUADRATIC_SPIT
309 }
310
311
312 /*-----------------------------------------------------------------------------
313 Quadratic Split
314
315 QS1) Pick first entry for each group:
316 Appy pick_seeds to choose 2 entries to be the first elements of the groups. Assign each one of
317 them to one group
318 QS2) check if done:
319 a) if all entries have been assinged stop
320 b) if one group has so few entries that all the rest must be assignmed to it, in order for it to
321 have the min number , assign them and stop
322 QS3) select entry and assign:
323 Inkvoke pick_next() to choose the next entry to assign.
324 *[in pick_next] Add it to the group whose covering rectangle will have to be enlrarged least to
325 accommodate it. Resolve ties by adding the entry to the group with the smaller are, then to the
326 one with fewer entries, then to either of the two.
327 goto 2.
328 */
quadratic_split(RTreeNode * s)329 std::pair<RTreeNode*, RTreeNode*> RTree::quadratic_split( RTreeNode *s ) {
330
331 // s is the original leaf node or non-leaf node
332 RTreeNode* group_a = new RTreeNode(); // a is the 1st group
333 RTreeNode* group_b = new RTreeNode(); // b is the 2nd group
334
335
336 _RTREE_PRINT(" QS1"); // QS1
337 std::pair<unsigned, unsigned> initial_seeds;
338 initial_seeds = pick_seeds(s);
339
340 // if non-leaf node: s
341 if( s->children_nodes.size() > 0 ){
342 _RTREE_PRINT(" non-leaf node");
343 // each element is true if the node has been assinged to either "a" or "b"
344 std::vector<bool> assigned_v( s->children_nodes.size() );
345 std::fill( assigned_v.begin(), assigned_v.end(), false );
346
347 group_a->children_nodes.push_back( s->children_nodes[initial_seeds.first] );
348 assert(initial_seeds.first < assigned_v.size());
349 assigned_v[ initial_seeds.first ] = true;
350
351 group_b->children_nodes.push_back( s->children_nodes[initial_seeds.second] );
352 assert(initial_seeds.second < assigned_v.size());
353 assigned_v[ initial_seeds.second ] = true;
354
355 _RTREE_PRINT(" QS2"); // QS2
356 unsigned num_of_not_assigned = s->children_nodes.size() - 2;
357 // so far we have assinged 2 out of all
358
359 while( num_of_not_assigned ){// QS2 a
360 _RTREE_PRINT(" QS2 b, num_of_not_assigned:" << num_of_not_assigned); // QS2 b
361 /*
362 we are on NON leaf node so children of split groups must be nodes
363
364 Check each group to see if one group has so few entries that all the rest must
365 be assignmed to it, in order for it to have the min number.
366 */
367 if( group_a->children_nodes.size() + num_of_not_assigned <= min_records ){
368 // add the non-assigned to group_a
369 for(unsigned i = 0; i < assigned_v.size(); i++){
370 if(assigned_v[i] == false){
371 group_a->children_nodes.push_back( s->children_nodes[i] );
372 assigned_v[i] = true;
373 }
374 }
375 break;
376 }
377
378 if( group_b->children_nodes.size() + num_of_not_assigned <= min_records ){
379 // add the non-assigned to group_b
380 for( unsigned i = 0; i < assigned_v.size(); i++ ){
381 if( assigned_v[i] == false ){
382 group_b->children_nodes.push_back( s->children_nodes[i] );
383 assigned_v[i] = true;
384 }
385 }
386 break;
387 }
388
389 _RTREE_PRINT(" QS3"); // QS3
390 std::pair<unsigned, enum_add_to_group> next_element;
391 next_element = pick_next( group_a, group_b, s, assigned_v );
392 if( next_element.second == ADD_TO_GROUP_A ){
393 group_a->children_nodes.push_back( s->children_nodes[ next_element.first ] );
394 }
395 else{
396 group_b->children_nodes.push_back( s->children_nodes[ next_element.first ] );
397 }
398
399 num_of_not_assigned--;
400 }
401 }
402 // else leaf node: s
403 else{
404 _RTREE_PRINT(" leaf node");
405 // each element is true if the node has been assinged to either "a" or "b"
406 std::vector<bool> assigned_v( s->children_leaves.size() );
407 std::fill( assigned_v.begin(), assigned_v.end(), false );
408
409 // assign 1st seed to group a
410 group_a->children_leaves.push_back( s->children_leaves[initial_seeds.first] );
411 assert(initial_seeds.first < assigned_v.size());
412 assigned_v[ initial_seeds.first ] = true;
413
414 // assign 2nd seed to group b
415 group_b->children_leaves.push_back( s->children_leaves[initial_seeds.second] );
416 assert(initial_seeds.second < assigned_v.size());
417 assigned_v[ initial_seeds.second ] = true;
418
419 _RTREE_PRINT(" QS2"); // QS2
420 unsigned num_of_not_assigned = s->children_leaves.size() - 2;
421 // so far we have assinged 2 out of all
422
423 while( num_of_not_assigned ){// QS2 a
424 _RTREE_PRINT(" QS2 b, num_of_not_assigned:" << num_of_not_assigned); // QS2 b
425 /*
426 we are on leaf node so children of split groups must be leaves
427
428 Check each group to see if one group has so few entries that all the rest must
429 be assignmed to it, in order for it to have the min number.
430 */
431 if( group_a->children_leaves.size() + num_of_not_assigned <= min_records ){
432 _RTREE_PRINT(" add the non-assigned to group_a");
433 // add the non-assigned to group_a
434 for( unsigned i = 0; i < assigned_v.size(); i++ ){
435 if( assigned_v[i] == false ){
436 group_a->children_leaves.push_back( s->children_leaves[i] );
437 assigned_v[i] = true;
438 }
439 }
440 break;
441 }
442
443 if( group_b->children_leaves.size() + num_of_not_assigned <= min_records ){
444 _RTREE_PRINT(" add the non-assigned to group_b");
445 // add the non-assigned to group_b
446 for( unsigned i = 0; i < assigned_v.size(); i++ ){
447 if( assigned_v[i] == false ){
448 group_b->children_leaves.push_back( s->children_leaves[i] );
449 assigned_v[i] = true;
450 }
451 }
452 break;
453 }
454
455 _RTREE_PRINT(" QS3"); // QS3
456 std::pair<unsigned, enum_add_to_group> next_element;
457 next_element = pick_next(group_a, group_b, s, assigned_v);
458 if( next_element.second == ADD_TO_GROUP_A ){
459 group_a->children_leaves.push_back( s->children_leaves[ next_element.first ] );
460 }
461 else{
462 group_b->children_leaves.push_back( s->children_leaves[ next_element.first ] );
463 }
464
465 num_of_not_assigned--;
466 }
467 }
468 assert( initial_seeds.first != initial_seeds.second );
469 return std::make_pair( group_a, group_b );
470 }
471
472 /*
473 PS1) caclulate ineffeciency of grouping entries together:
474 Foreach pair of entries E1 (i), E2 (j) compose rectangle J (i_union_j) including E1, E2.
475 Calculate d = area(i_union_j) - area(i) - area(j)
476 PS2) choose the most wastefull pair:
477 Choose pair with largest d
478 */
479
pick_seeds(RTreeNode * s) const480 std::pair<unsigned, unsigned> RTree::pick_seeds( RTreeNode *s ) const{
481 double current_d = 0;
482 double max_d = std::numeric_limits<double>::min();
483 unsigned seed_a = 0;
484 unsigned seed_b = 1;
485 _RTREE_PRINT(" pick_seeds");
486
487 // if non leaf node: s
488 if( s->children_nodes.size() > 0 ){
489 _RTREE_PRINT(" non leaf");
490 _RTREE_PRINT(" PS1"); // PS1
491 for( unsigned a = 0; a < s->children_nodes.size(); a++ ){
492 // with j=i we check only the upper (diagonal) half
493 // with j=i+1 we also avoid checking for b==a (we don't need it)
494 for( unsigned b = a+1; b < s->children_nodes.size(); b++ ){
495 _RTREE_PRINT(" PS2 " << a << " - " << b ); // PS2
496 current_d = find_waste_area( s->children_nodes[a].bounding_box, s->children_nodes[b].bounding_box );
497
498 if( current_d > max_d ){
499 max_d = current_d;
500 seed_a = a;
501 seed_b = b;
502 }
503 }
504 }
505 }
506 // else leaf node: s
507 else{
508 _RTREE_PRINT(" leaf node");
509 _RTREE_PRINT(" PS1"); // PS1
510 for( unsigned a = 0; a < s->children_leaves.size(); a++ ){
511 // with j=i we check only the upper (diagonal) half
512 // with j=i+1 we also avoid checking for j==i (we don't need this one)
513 for( unsigned b = a+1; b < s->children_leaves.size(); b++ ){
514 _RTREE_PRINT(" PS2 " << s->children_leaves[a].data << ":" << s->children_leaves[a].bounding_box.area()
515 << " - " << s->children_leaves[b].data << ":" << s->children_leaves[b].bounding_box.area() ); // PS2
516 current_d = find_waste_area( s->children_leaves[a].bounding_box, s->children_leaves[b].bounding_box );
517
518 if( current_d > max_d ){
519 max_d = current_d;
520 seed_a = a;
521 seed_b = b;
522 }
523 }
524 }
525 }
526 _RTREE_PRINT(" seed_a: " << seed_a << " seed_b: " << seed_b );
527 return std::make_pair( seed_a, seed_b );
528 }
529
530 /*
531 find_waste_area (used in pick_seeds step 1)
532
533 for a pair A, B compose a rect union_rect that includes a and b
534 calculate area of union_rect - area of a - area b
535 */
find_waste_area(const Rect & a,const Rect & b) const536 double RTree::find_waste_area( const Rect &a, const Rect &b ) const{
537 Rect union_rect(a);
538 union_rect.unionWith(b);
539
540 return union_rect.area() - a.area() - b.area();
541 }
542
543 /*
544 pick_next:
545 select one remaining entry for classification in a group
546
547 PN1) Determine cost of putting each entry in each group:
548 Foreach entry E not yet in a group, calculate
549 d1= area increase required in the cover rect of Group 1 to include E
550 d2= area increase required in the cover rect of Group 2 to include E
551 PN2) Find entry with greatest preference for each group:
552 Choose any entry with the maximum difference between d1 and d2
553
554 */
555
pick_next(RTreeNode * group_a,RTreeNode * group_b,RTreeNode * s,std::vector<bool> & assigned_v)556 std::pair<unsigned, enum_add_to_group> RTree::pick_next( RTreeNode* group_a,
557 RTreeNode* group_b,
558 RTreeNode* s,
559 std::vector<bool> &assigned_v )
560 {
561 double max_increase_difference = std::numeric_limits<double>::min();
562 unsigned max_increase_difference_node = 0;
563 double current_increase_difference = 0;
564
565 enum_add_to_group group_to_add = ADD_TO_GROUP_A;
566
567 /*
568 bounding boxes of the 2 new groups. This info isn't available, since they
569 have no parent nodes (so that the parent node knows the bounding box).
570 */
571 Rect bounding_box_a;
572 Rect bounding_box_b;
573
574 double increase_area_a = 0;
575 double increase_area_b = 0;
576
577 _RTREE_PRINT(" pick_next, assigned_v.size:" << assigned_v.size() );
578
579 // if non leaf node: one of the 2 groups (both groups are the same, either leaf/nonleaf)
580 if( group_a->children_nodes.size() > 0 ){
581 _RTREE_PRINT(" non leaf");
582
583 // calculate the bounding boxes of the 2 new groups.
584 bounding_box_a = Rect( group_a->children_nodes[0].bounding_box );
585 for( unsigned i = 1; i < group_a->children_nodes.size(); i++ ){
586 bounding_box_a.unionWith( group_a->children_nodes[i].bounding_box );
587 }
588
589 bounding_box_b = Rect( group_b->children_nodes[0].bounding_box );
590 for( unsigned i = 1; i < group_b->children_nodes.size(); i++ ){
591 bounding_box_b.unionWith( group_b->children_nodes[i].bounding_box );
592 }
593
594
595 _RTREE_PRINT(" PN1"); // PN1
596 for( unsigned i = 0; i < assigned_v.size(); i++ ){
597 _RTREE_PRINT(" i:" << i << " assigned:" << assigned_v[i]);
598 if( assigned_v[i] == false ){
599
600 increase_area_a = find_enlargement( bounding_box_a, s->children_nodes[i].bounding_box );
601 increase_area_b = find_enlargement( bounding_box_b, s->children_nodes[i].bounding_box );
602
603 current_increase_difference = std::abs( increase_area_a - increase_area_b );
604 _RTREE_PRINT(" PN2 " << i << ": " << current_increase_difference ); // PN2
605 if( current_increase_difference > max_increase_difference ){
606 max_increase_difference = current_increase_difference;
607 max_increase_difference_node = i;
608
609 // TODO tie not solved!
610 if( increase_area_a < increase_area_b ){
611 group_to_add = ADD_TO_GROUP_A;
612 }
613 else{
614 group_to_add = ADD_TO_GROUP_B;
615 }
616 }
617 }
618 }
619 //assert(max_increase_difference_node >= 0);
620 assert(max_increase_difference_node < assigned_v.size());
621 assigned_v[max_increase_difference_node] = true;
622 _RTREE_PRINT(" ... i:" << max_increase_difference_node << " assigned:" << assigned_v[max_increase_difference_node] );
623 }
624 else{ // else leaf node
625 _RTREE_PRINT(" leaf");
626
627 // calculate the bounding boxes of the 2 new groups
628 bounding_box_a = Rect( group_a->children_leaves[0].bounding_box );
629 for( unsigned i = 1; i < group_a->children_leaves.size(); i++ ){
630 std::cout<< " lala";
631 bounding_box_a.unionWith( group_a->children_leaves[i].bounding_box );
632 }
633
634 bounding_box_b = Rect( group_b->children_leaves[0].bounding_box );
635 for( unsigned i = 1; i < group_b->children_leaves.size(); i++ ){
636 std::cout<< " lala";
637 bounding_box_b.unionWith( group_b->children_leaves[i].bounding_box );
638 }
639 std::cout<< "" << std::endl;
640
641 _RTREE_PRINT(" PN1"); // PN1
642 for( unsigned i = 0; i < assigned_v.size(); i++ ){
643 _RTREE_PRINT(" i:" << i << " assigned:" << assigned_v[i]);
644 if( assigned_v[i] == false ){
645 increase_area_a = find_enlargement( bounding_box_a, s->children_leaves[i].bounding_box );
646 increase_area_b = find_enlargement( bounding_box_b, s->children_leaves[i].bounding_box );
647
648 current_increase_difference = std::abs( increase_area_a - increase_area_b );
649 _RTREE_PRINT(" PN2 " << i << ": " << current_increase_difference ); // PN2
650
651 if( current_increase_difference > max_increase_difference ){
652 max_increase_difference = current_increase_difference;
653 max_increase_difference_node = i;
654
655 // TODO tie not solved!
656 if( increase_area_a < increase_area_b ){
657 group_to_add = ADD_TO_GROUP_A;
658 }
659 else{
660 group_to_add = ADD_TO_GROUP_B;
661 }
662 }
663 }
664 }
665 assert(max_increase_difference_node < assigned_v.size());
666 assigned_v[max_increase_difference_node] = true;
667 _RTREE_PRINT(" ... i:" << max_increase_difference_node << " assigned:" << assigned_v[max_increase_difference_node] );
668 }
669
670 _RTREE_PRINT(" node:" << max_increase_difference_node << " added:" << group_to_add );
671 return std::make_pair( max_increase_difference_node, group_to_add );
672 }
673
674 /* I3 =========================================================================
675
676 adjust_tree:
677 Ascend from a leaf node L to root, adjusting covering rectangles and propagating node splits as
678 necessary
679
680 We modified this one from the source in the step AT1 and AT5
681
682 AT1) Initialize:
683 Set N=L
684 IF L was spilt previously, set NN to be the resulting second node AND
685 (not mentioned in the original source but that's what it should mean)
686 Assign all entries of first node to L
687 AT2) check if done:
688 IF N is root stop
689 AT3) adjust covering rectangle in parent entry
690 1) Let P be the parent of N
691 2) Let EN be the N's entry in P
692 3) Adjust EN bounding box so that it tightly enclosses all entry rectangles in N
693 AT4) Propagate node split upward
694 IF N has a partner NN resulting from an earlier split
695 create a new entry ENN with ENN "p" pointing to NN and ENN bounding box enclosing all
696 rectangles in NN
697
698 IF there is room in P add ENN
699 ELSE invoke split_node to produce P an PP containing ENN and all P's old entries.
700 AT5) Move up to next level
701 Set N=P,
702 IF a split occurred, set NN=PP
703 goto AT1 (was goto AT2)
704 */
705
adjust_tree(RTreeNode * position,std::pair<RTreeNode *,RTreeNode * > & node_division,bool initial_split_performed)706 bool RTree::adjust_tree( RTreeNode* position,
707 // modified: it holds the last split group
708 std::pair<RTreeNode*, RTreeNode*> &node_division,
709 bool initial_split_performed)
710 {
711 RTreeNode* parent;
712 unsigned child_in_parent; // the element in parent node that points to current posistion
713 std::pair< RTreeNode*, bool > find_result;
714 bool split_performed = initial_split_performed;
715 bool root_split_performed = false;
716
717 _RTREE_PRINT(" adjust_tree");
718 _RTREE_PRINT(" AT1");
719
720 while( true ){
721 _RTREE_PRINT(" ------- current tree status:");
722 _RTREE_PRINT_TREE_INS(root, 2, true);
723
724 // check for loop BREAK
725 if( position == root ){
726 _RTREE_PRINT(" AT2: found root");
727 if( split_performed ){
728 root_split_performed = true;
729 }
730 break;
731 }
732
733 if( split_performed ){
734 copy_group_a_to_existing_node( position, node_division.first );
735 }
736
737 /*
738 pick randomly, let's say the 1st entry of the current node.
739 Search for this spatial area in the tree, and stop to the parent node.
740 Then find position of current node pointer, in the parent node.
741 */
742 _RTREE_PRINT(" AT3.1"); // AT3.1 Let P be the parent of N
743 if( position->children_nodes.size() > 0 ){
744 find_result = find_parent( root, position->children_nodes[0].bounding_box, position);
745 }
746 else{
747 find_result = find_parent( root, position->children_leaves[0].bounding_box, position);
748 }
749 parent = find_result.first;
750
751 // parent is a non-leaf, by definition
752 _RTREE_PRINT(" AT3.2"); // AT3.2 Let EN be the N's entry in P
753 for( child_in_parent = 0; child_in_parent < parent->children_nodes.size(); child_in_parent++ ){
754 if( parent->children_nodes[ child_in_parent ].data == position){
755 _RTREE_PRINT(" child_in_parent: " << child_in_parent);
756 break;
757 }
758 }
759
760 _RTREE_PRINT(" AT3.3");
761 // AT3.2 Adjust EN bounding box so that it tightly enclosses all entry rectangles in N
762 recalculate_bounding_box( parent, position, child_in_parent );
763
764
765 _RTREE_PRINT(" AT4"); // AT4
766 if( split_performed ){
767 // create new record (from group_b)
768 //RTreeNode* new_node = new RTreeNode();
769 Rect new_record_bounding;
770
771 RTreeRecord_NonLeaf new_record = create_nonleaf_record_from_rtreenode( new_record_bounding, node_division.second );
772
773 // install new entry (group_b)
774 if( parent->children_nodes.size() < max_records ){
775 parent->children_nodes.push_back( new_record );
776 split_performed = false;
777 }
778 else{
779 parent->children_nodes.push_back( new_record );
780 node_division = quadratic_split( parent ); // AT5
781 split_performed = true;
782 }
783
784 }
785 _RTREE_PRINT(" AT5"); // AT5
786 position = parent;
787 }
788
789 return root_split_performed;
790 }
791
792 /*
793 find_parent:
794 The source only mentions that we should "find" the parent. But it doesn't seay how. So we made a
795 modification of search.
796
797 Initially we take the root, a rect of the node, of which the parent we look for and the node we seek
798
799 We do a spatial search for this rect. If we find get an intersecttion with the rect we check if the
800 child is the one we look for.
801 If not we call find_parent again recursively
802 */
803
find_parent(RTreeNode * subtree_root,Rect search_area,RTreeNode * wanted) const804 std::pair< RTreeNode*, bool > RTree::find_parent( RTreeNode* subtree_root,
805 Rect search_area,
806 RTreeNode* wanted) const
807 {
808 _RTREE_PRINT("find_parent");
809
810 std::pair< RTreeNode*, bool > result;
811 if( subtree_root->children_nodes.size() > 0 ){
812
813 for( unsigned i=0; i < subtree_root->children_nodes.size(); i++ ){
814 if( subtree_root->children_nodes[i].data == wanted){
815 _RTREE_PRINT("FOUND!!"); // non leaf node
816 return std::make_pair( subtree_root, true );
817 }
818
819 if( subtree_root->children_nodes[i].bounding_box.intersects( search_area ) ){
820 result = find_parent( subtree_root->children_nodes[i].data, search_area, wanted);
821 if ( result.second ){
822 break;
823 }
824 }
825 }
826 }
827 return result;
828 }
829
830
copy_group_a_to_existing_node(RTreeNode * position,RTreeNode * group_a)831 void RTree::copy_group_a_to_existing_node( RTreeNode *position, RTreeNode* group_a ){
832 // clear position (the one that was split) and put there all the nodes of group_a
833 if( position->children_nodes.size() > 0 ){
834 _RTREE_PRINT(" copy_group...(): install group A to existing non-leaf node");
835 // non leaf-node: position
836 position->children_nodes.clear();
837 for(auto & children_node : group_a->children_nodes){
838 position->children_nodes.push_back( children_node );
839 }
840 }
841 else{
842 _RTREE_PRINT(" copy_group...(): install group A to existing leaf node");
843 // leaf-node: positions
844 position->children_leaves.clear();
845 for(auto & children_leave : group_a->children_leaves){
846 position->children_leaves.push_back( children_leave );
847 }
848 }
849 }
850
851
852
create_nonleaf_record_from_rtreenode(Rect & new_entry_bounding,RTreeNode * rtreenode)853 RTreeRecord_NonLeaf RTree::create_nonleaf_record_from_rtreenode( Rect &new_entry_bounding, RTreeNode* rtreenode ){
854
855 if( rtreenode->children_nodes.size() > 0 ){
856 // found bounding box of new entry
857 new_entry_bounding = Rect( rtreenode->children_nodes[0].bounding_box );
858 for(unsigned i = 1; i < rtreenode->children_nodes.size(); i++ ){
859 new_entry_bounding.unionWith( rtreenode->children_nodes[ i ].bounding_box );
860 }
861 }
862 else{ // non leaf: rtreenode
863 // found bounding box of new entry
864 new_entry_bounding = Rect( rtreenode->children_leaves[0].bounding_box );
865 for(unsigned i = 1; i < rtreenode->children_leaves.size(); i++ ){
866 new_entry_bounding.unionWith( rtreenode->children_leaves[ i ].bounding_box );
867 }
868 }
869 return RTreeRecord_NonLeaf( new_entry_bounding, rtreenode );
870 }
871
872
873
874 /*
875 print the elements of the tree
876 based on ordered tree walking
877 */
print_tree(RTreeNode * subtree_root,int depth) const878 void RTree::print_tree(RTreeNode* subtree_root, int depth ) const{
879
880 if( subtree_root->children_nodes.size() > 0 ){
881
882 // descend in each one of the elements and call print_tree
883 for( unsigned i=0; i < subtree_root->children_nodes.size(); i++ ){
884 //print spaces for indentation
885 for(int j=0; j < depth; j++){
886 std::cout << " " ;
887 }
888
889 std::cout << subtree_root->children_nodes[i].bounding_box << ", " << subtree_root->children_nodes.size() << std::endl ;
890 _RTREE_PRINT_TREE_INS( subtree_root->children_nodes[i].data, depth+1, used_during_insert);
891 }
892
893 }
894 else{
895 for(int j=0; j < depth; j++){
896 std::cout << " " ;
897 }
898 std::cout << subtree_root->children_leaves.size() << ": " ;
899
900 // print all the elements of the leaf node
901 for(auto & children_leave : subtree_root->children_leaves){
902 std::cout << children_leave.data << ", " ;
903 }
904 std::cout << std::endl ;
905
906 }
907 }
908
909
sanity_check(RTreeNode * subtree_root,int depth,bool used_during_insert) const910 void RTree::sanity_check(RTreeNode* subtree_root, int depth, bool used_during_insert ) const{
911
912 if( subtree_root->children_nodes.size() > 0 ){
913 // descend in each one of the elements and call sanity_check
914 for(auto & children_node : subtree_root->children_nodes){
915 sanity_check( children_node.data, depth+1, used_during_insert);
916 }
917
918
919 // sanity check
920 if( subtree_root != root ){
921 assert( subtree_root->children_nodes.size() >= min_records);
922 }
923 /*
924 else{
925 assert( subtree_root->children_nodes.size() >= 1);
926 }
927 */
928
929 if( used_during_insert ){
930 // allow one more during for insert
931 assert( subtree_root->children_nodes.size() <= max_records + 1 );
932 }
933 else{
934 assert( subtree_root->children_nodes.size() <= max_records );
935 }
936
937 }
938 else{
939 // sanity check
940 if( subtree_root != root ){
941 assert( subtree_root->children_leaves.size() >= min_records);
942 }
943 /*
944 else{
945 assert( subtree_root->children_leaves.size() >= 1);
946 }
947 */
948
949 if( used_during_insert ){
950 // allow one more during for insert
951 assert( subtree_root->children_leaves.size() <= max_records + 1 );
952 }
953 else{
954 assert( subtree_root->children_nodes.size() <= max_records );
955 }
956 }
957 }
958
959
960
961 /*=============================================================================
962 search
963 ===============================================================================
964 Given an RTree whose root node is T find all index records whose rects overlap search rect S
965 S1) Search subtrees:
966 IF T isn't a leaf, check every entry E to determine whether E I overlaps S
967 FOR all overlapping entries invoke Search on the tree whose root node is pointed by E P
968 S2) ELSE T is leaf
969 check all entries E to determine whether E I overlaps S
970 IF so E is a qualifying record
971 */
972
973
search(const Rect & search_area,std::vector<int> * result,const RTreeNode * subtree) const974 void RTree::search( const Rect &search_area, std::vector< int >* result, const RTreeNode* subtree ) const {
975 // S1
976 if( subtree->children_nodes.size() > 0 ){ // non-leaf: subtree
977 for(const auto & children_node : subtree->children_nodes){
978 if( children_node.bounding_box.intersects( search_area ) ){
979 search( search_area, result, children_node.data );
980 }
981 }
982 }
983 // S2
984 else{ // leaf: subtree
985 for(const auto & children_leave : subtree->children_leaves){
986 if( children_leave.bounding_box.intersects( search_area ) ){
987 result->push_back( children_leave.data );
988 }
989 }
990 }
991 }
992
993
994 /*=============================================================================
995 erase
996 ===============================================================================
997 we changed steps D2)
998 D1) Find node containing record
999 Invoke find_leaf() to locate the leaf node L containing E
1000 IF record is found stop
1001 D2) Delete record
1002 Remove E from L (it happened in find_leaf step FL2)
1003 D3) Propagate changes
1004 Invoke condense_tree, passing L
1005 D4) Shorten tree
1006 If root node has only one child, after the tree was adjusted, make the child new root
1007
1008 return
1009 0 on success
1010 1 in case no entry was found
1011
1012 */
1013 //int RTree::erase( const RTreeRecord_Leaf & record_to_erase ){
erase(const Rect & search_area,const int shape_to_delete)1014 int RTree::erase( const Rect &search_area, const int shape_to_delete ){
1015 _RTREE_PRINT("\n=====================================");
1016 _RTREE_PRINT("erase element: " << shape_to_delete);
1017 // D1 + D2: entry is deleted in find_leaf
1018 _RTREE_PRINT("D1 & D2 : find and delete the leaf");
1019 RTreeNode* contains_record = find_leaf( root, search_area, shape_to_delete );
1020 if( !contains_record ){ // no entry returned from find_leaf
1021 return 1; // no entry found
1022 }
1023
1024 // D3
1025 //bool root_elimination_performed = condense_tree( contains_record );
1026
1027 // D4
1028
1029 //if( root_elimination_performed ){
1030 if( root->children_nodes.size() > 0 ){ // non leaf: root
1031 // D4
1032 if( root->children_nodes.size() == 1 ){
1033 _RTREE_PRINT("D4 : non leaf: ");
1034 tree_height--;
1035 RTreeNode* t = root;
1036 root = root->children_nodes[0].data;
1037 delete t;
1038 }
1039
1040 }
1041 else { // leaf: root
1042 // D4
1043 // do nothing
1044 }
1045 sanity_check( root, 0 );
1046 return 0; // success
1047 }
1048
1049
1050 /*
1051 find_leaf()
1052 Given an RTree whose root node is T find the leaf node containing index entry E
1053
1054 FL1) Search subtrees
1055 IF T is non leaf, check each entry F in T to determine if F I overlaps E I
1056 foreach such entry invoke find_leaf on the tree whose root is pointed to by F P until E is
1057 found or all entries have been checked
1058 FL2) search leaf node for record
1059 IF T is leaf, check each entry to see if it matches E
1060 IF E is found return T
1061 AND delete element E (step D2)
1062 */
1063
find_leaf(RTreeNode * subtree,const Rect & search_area,const int shape_to_delete) const1064 RTreeNode* RTree::find_leaf( RTreeNode* subtree, const Rect &search_area, const int shape_to_delete ) const {
1065 // FL1
1066 if( subtree->children_nodes.size() > 0 ){ // non-leaf: subtree
1067 for(auto & children_node : subtree->children_nodes){
1068 if( children_node.bounding_box.intersects( search_area ) ){
1069 RTreeNode* t = find_leaf( children_node.data, search_area, shape_to_delete );
1070 if( t ){ // if search was successful terminate
1071 return t;
1072 }
1073 }
1074 }
1075 }
1076 // FL2
1077 else{ // leaf: subtree
1078 for( std::vector< RTreeRecord_Leaf >::iterator it = subtree->children_leaves.begin(); it!=subtree->children_leaves.end(); ++it ){
1079 if( it->data == shape_to_delete ){
1080 // delete element: implement step D2)
1081 subtree->children_leaves.erase( it );
1082 return subtree;
1083 }
1084 }
1085 }
1086 return 0;
1087 }
1088
1089
1090 /*
1091 condense_tree()
1092 Given a Leaf node L from which an entry has been deleted eliminate the node if it has too few entries and reallocate its entries
1093 Propagate node elimination upwards as necessary
1094 Adjust all covering recsts n the path to the root making them smaller if possible
1095
1096 CT1) Initialize
1097 Set N=L
1098 Set Q the set of eliminated nodes to be empty
1099 CT2) // Find parent entry (was there but doesn't make sense)
1100 IF N is the root
1101 goto CT6
1102 ELSE
1103 1) Find parent entry
1104 2) let P be the parent of N
1105 3) and let EN be N's entry in P
1106 CT3) IF N has fewer than m entries
1107 Eliminate underfull node
1108 1) delete EN from P
1109 2) and add N to set Q
1110 CT4) ELSE
1111 adjust EN I to tightly contain all entries in N
1112 CT5) move up one level in tree
1113 set N=P and repeat from CT2
1114
1115 CT6) Re insert orphaned entries
1116 Re-inser all entreis of nodes in set Q
1117 Entries from eliminated leaf nodes are re-inserted in tree leaves (like in insert)
1118 BUT non-leaf nodes must be placed higher in the tree so that leaves of their dependent subtrees
1119 will be on the same level as leaves of the main tree. (on the same height they originally were)
1120 (not mentioned in the source description: the criteria for placing the node should be
1121 again TODO ??? least enlargement)
1122
1123 */
1124 // TODO this can be merged with adjust_tree or refactor to reutilize some parts. less readable
condense_tree(RTreeNode * position)1125 bool RTree::condense_tree( RTreeNode* position )
1126 {
1127 RTreeNode* parent;
1128 unsigned child_in_parent = 0; // the element in parent node that points to current posistion
1129
1130 std::pair< RTreeNode*, bool > find_result;
1131 bool elimination_performed = false;
1132 bool root_elimination_performed = false;
1133 unsigned current_height = tree_height+1;
1134 Rect special_case_bounding_box;
1135 _RTREE_PRINT(" condense_tree");
1136 _RTREE_PRINT(" CT1");
1137 // leaf records that were eliminated due to under-full node
1138 std::vector< RTreeRecord_Leaf > Q_leaf_records( 0 );
1139
1140 // < non-leaf records, their height > that were eliminated due to under-full node
1141 std::vector< std::pair< RTreeRecord_NonLeaf, unsigned > > Q_nonleaf_records( 0 );
1142
1143
1144 while( true ){
1145
1146 // check for loop BREAK
1147 if( position == root ){
1148 _RTREE_PRINT(" CT2 position is root");
1149 if( elimination_performed ){
1150 root_elimination_performed = true;
1151 }
1152 break;
1153 }
1154
1155 /*
1156 pick randomly, let's say the 1st entry of the current node.
1157 Search for this spatial area in the tree, and stop to the parent node.
1158 Then find position of current node pointer, in the parent node.
1159 */
1160 /*
1161 special case. if elimination due to children being underfull was performed AND
1162 AND parent had only 1 record ,then this one record was removed.
1163 */
1164 if( position->children_nodes.size() > 0 ){
1165 _RTREE_PRINT(" CT2.1 - 2 non leaf: find parent, P is parent");
1166 // CT2.1 find parent. By definition it's nonleaf
1167 find_result = find_parent( root, position->children_nodes[0].bounding_box, position);
1168 }
1169 else if( position->children_nodes.size() == 0
1170 && position->children_leaves.size() == 0
1171 && elimination_performed )
1172 { // special case
1173 _RTREE_PRINT(" CT2.1 - 2 special case: find parent, P is parent");
1174 // CT2.1 find parent. By definition it's nonleaf
1175 find_result = find_parent( root, special_case_bounding_box, position);
1176 }
1177 else{
1178 _RTREE_PRINT(" CT2.1 - 2 leaf: find parent, P is parent");
1179 // CT2.1 find parent. By definition it's nonleaf
1180 find_result = find_parent( root, position->children_leaves[0].bounding_box, position);
1181 }
1182 // CT2.2 Let P be the parent of N
1183 parent = find_result.first;
1184
1185
1186 // parent is a non-leaf, by definition. Calculate "child_in_parent"
1187 _RTREE_PRINT(" CT2.3 find in parent, position's record EN");
1188 // CT2.3 Let EN be the N's entry in P
1189 for( child_in_parent = 0; child_in_parent < parent->children_nodes.size(); child_in_parent++ ){
1190 if( parent->children_nodes[ child_in_parent ].data == position){
1191 _RTREE_PRINT(" child_in_parent: " << child_in_parent << " out of " << parent->children_nodes.size() << " (size)" );
1192 break;
1193 }
1194 }
1195
1196 if( position->children_nodes.size() > 0 ){ // non leaf node: position
1197 _RTREE_PRINT(" CT3 nonleaf: eliminate underfull node");
1198 // CT3 Eliminate underfull node
1199 if( position->children_nodes.size() < min_records ){
1200 _RTREE_PRINT(" CT3.2 add N to Q");
1201 // CT3.2 add N to set Q ( EN the record that points to N )
1202 for(auto & children_node : position->children_nodes){
1203 _RTREE_PRINT(" i " << i );
1204 std::pair< RTreeRecord_NonLeaf, unsigned > t = std::make_pair( children_node, current_height-1);
1205 Q_nonleaf_records.push_back( t );
1206
1207 }
1208 special_case_bounding_box = parent->children_nodes[ child_in_parent ].bounding_box;
1209
1210 _RTREE_PRINT(" CT3.1 delete in parent, position's record EN");
1211 // CT3.1 delete EN from P ( parent is by definition nonleaf )
1212 if( remove_record_from_parent( parent, position ) ){ // TODO does erase, delete to the pointer ???
1213 _RTREE_PRINT(" remove_record_from_parent error ");
1214 }
1215 elimination_performed = true;
1216 }
1217 else{
1218 _RTREE_PRINT(" CT4 "); /// CT4) if not underfull
1219 recalculate_bounding_box( parent, position, child_in_parent );
1220 elimination_performed = false;
1221 }
1222
1223 }
1224 else{ // leaf node: position
1225 _RTREE_PRINT(" CT3 leaf: eliminate underfull node");
1226 // CT3 Eliminate underfull node
1227 if( position->children_leaves.size() < min_records ){
1228 _RTREE_PRINT(" CT3.2 add N to Q " << position->children_leaves.size() );
1229 // CT3.2 add N to set Q
1230 for(auto & children_leave : position->children_leaves){
1231 _RTREE_PRINT(" i " << i );
1232 Q_leaf_records.push_back( children_leave ); // TODO problem here
1233 special_case_bounding_box = children_leave.bounding_box;
1234 }
1235
1236 _RTREE_PRINT(" CT3.1 delete in parent, position's record EN");
1237 // CT3.1 delete EN from P ( parent is by definition nonleaf )
1238 if( remove_record_from_parent( parent, position ) ){
1239 _RTREE_PRINT(" remove_record_from_parent error ");
1240 }
1241 elimination_performed = true;
1242 }
1243 else{
1244 _RTREE_PRINT(" CT4 "); /// CT4) if not underfull
1245 recalculate_bounding_box( parent, position, child_in_parent );
1246 elimination_performed = false;
1247 }
1248 }
1249 _RTREE_PRINT(" CT5 ");// CT5) move up one level in tree
1250 position = parent;
1251
1252 current_height--;
1253 }
1254 // CT6: reinsert
1255 _RTREE_PRINT(" ------ Q_leaf");
1256 for( std::vector< RTreeRecord_Leaf >::iterator it = Q_leaf_records.begin(); it != Q_leaf_records.end(); ++it ){
1257 _RTREE_PRINT(" leaf:" << (*it).data);
1258 }
1259 _RTREE_PRINT(" ------ Q_nonleaf");
1260 for( std::vector< std::pair< RTreeRecord_NonLeaf, unsigned > >::iterator it = Q_nonleaf_records.begin(); it != Q_nonleaf_records.end(); ++it ){
1261 _RTREE_PRINT(" ------- " << it->second );
1262 _RTREE_PRINT_TREE( it->first.data, 0);
1263 }
1264
1265 _RTREE_PRINT(" CT6 ");
1266 for(auto & Q_leaf_record : Q_leaf_records){
1267 insert( Q_leaf_record );
1268 _RTREE_PRINT(" inserted leaf:" << (*it).data << " ------------");
1269 _RTREE_PRINT_TREE( root, 0);
1270 }
1271
1272
1273 for(auto & Q_nonleaf_record : Q_nonleaf_records){
1274 insert( RTreeRecord_Leaf() , true, Q_nonleaf_record.second, Q_nonleaf_record.first );
1275 _RTREE_PRINT(" inserted nonleaf------------");
1276 _RTREE_PRINT_TREE( root, 0);
1277 // TODO this fake RTreeRecord_Leaf() looks stupid. find better way to do this ???
1278 }
1279
1280 return root_elimination_performed;
1281 }
1282
1283
1284 /*
1285 given:
1286 - a parent
1287 - a child node
1288 - and the position of the child node in the parent
1289 recalculate the parent record's bounding box of the child, in order to ightly contain all entries of child
1290
1291 NOTE! child must be indeed child of the parent, otherwise it screws up things. So find parent and child
1292 before calling this function
1293 */
recalculate_bounding_box(RTreeNode * parent,RTreeNode * child,unsigned & child_in_parent)1294 void RTree::recalculate_bounding_box( RTreeNode* parent, RTreeNode* child, unsigned &child_in_parent ) {
1295 if( child->children_nodes.size() > 0 ){
1296 _RTREE_PRINT(" non-leaf: recalculate bounding box of parent "); // non leaf-node: child
1297 parent->children_nodes[ child_in_parent ].bounding_box = Rect( child->children_nodes[0].bounding_box );
1298 for( unsigned i=1; i < child->children_nodes.size(); i++ ){
1299 parent->children_nodes[ child_in_parent ].bounding_box.unionWith( child->children_nodes[i].bounding_box );
1300 }
1301 }
1302 else{
1303 _RTREE_PRINT(" leaf: recalculate bounding box of parent "); // leaf-node: child
1304 parent->children_nodes[ child_in_parent ].bounding_box = Rect( child->children_leaves[0].bounding_box );
1305
1306 for( unsigned i=1; i < child->children_leaves.size(); i++ ){
1307 parent->children_nodes[ child_in_parent ].bounding_box.unionWith( child->children_leaves[i].bounding_box );
1308 }
1309 }
1310 }
1311
1312 /*
1313 given:
1314 - a parent
1315 - a child node
1316 it removes the child record from the parent
1317
1318 NOTE! child must be indeed child of the parent, otherwise it screws up things.
1319 So find parent and child before calling this function
1320 */
remove_record_from_parent(RTreeNode * parent,RTreeNode * child)1321 int RTree::remove_record_from_parent( RTreeNode* parent, RTreeNode* child ) {
1322 _RTREE_PRINT( "remove_record_from_parent)" );
1323 for( std::vector< RTreeRecord_NonLeaf >::iterator it = parent->children_nodes.begin(); it!=parent->children_nodes.end(); ++it ){
1324 if( it->data == child ){
1325 // delete element: implement step D2)
1326 parent->children_nodes.erase( it );
1327 return 0; // success
1328 }
1329 }
1330 return 1; // failure
1331 }
1332
1333 /*=============================================================================
1334 TODO update
1335 ===============================================================================
1336 */
1337
1338
1339 };
1340
1341 /*
1342 Local Variables:
1343 mode:c++
1344 c-file-style:"stroustrup"
1345 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
1346 indent-tabs-mode:nil
1347 fill-column:99
1348 End:
1349 */
1350 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
1351