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