GCC Code Coverage Report


Directory: ./
File: src/broadphase/detail/interval_tree.cpp
Date: 2025-04-01 09:23:31
Exec Total Coverage
Lines: 158 268 59.0%
Branches: 66 150 44.0%

Line Branch Exec Source
1 /*
2 * Software License Agreement (BSD License)
3 *
4 * Copyright (c) 2011-2014, Willow Garage, Inc.
5 * Copyright (c) 2014-2016, Open Source Robotics Foundation
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 *
12 * * Redistributions of source code must retain the above copyright
13 * notice, this list of conditions and the following disclaimer.
14 * * Redistributions in binary form must reproduce the above
15 * copyright notice, this list of conditions and the following
16 * disclaimer in the documentation and/or other materials provided
17 * with the distribution.
18 * * Neither the name of Open Source Robotics Foundation nor the names of its
19 * contributors may be used to endorse or promote products derived
20 * from this software without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
23 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
24 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
25 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
26 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
28 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
29 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
30 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
32 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
33 * POSSIBILITY OF SUCH DAMAGE.
34 */
35
36 /** @author Jia Pan */
37
38 #ifndef COAL_INTERVAL_TREE_INL_H
39 #define COAL_INTERVAL_TREE_INL_H
40
41 #include "coal/broadphase/detail/interval_tree.h"
42
43 #include <algorithm>
44
45 namespace coal {
46 namespace detail {
47
48 //==============================================================================
49 192 IntervalTree::IntervalTree() {
50
1/2
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
192 invalid_node = new IntervalTreeNode;
51 192 invalid_node->left = invalid_node->right = invalid_node->parent =
52 192 invalid_node;
53 192 invalid_node->red = false;
54 192 invalid_node->key = invalid_node->high = invalid_node->max_high =
55 192 -(std::numeric_limits<Scalar>::max)();
56 192 invalid_node->stored_interval = nullptr;
57
58
1/2
✓ Branch 2 taken 192 times.
✗ Branch 3 not taken.
192 root = new IntervalTreeNode;
59 192 root->parent = root->left = root->right = invalid_node;
60 384 root->key = root->high = root->max_high =
61 192 (std::numeric_limits<Scalar>::max)();
62 192 root->red = false;
63 192 root->stored_interval = nullptr;
64
65 /// the following are used for the query function
66 192 recursion_node_stack_size = 128;
67 192 recursion_node_stack = (it_recursion_node*)malloc(recursion_node_stack_size *
68 sizeof(it_recursion_node));
69 192 recursion_node_stack_top = 1;
70 192 recursion_node_stack[0].start_node = nullptr;
71 192 }
72
73 //==============================================================================
74 189 IntervalTree::~IntervalTree() {
75 189 IntervalTreeNode* x = root->left;
76 189 std::deque<IntervalTreeNode*> nodes_to_free;
77
78
2/2
✓ Branch 0 taken 165 times.
✓ Branch 1 taken 24 times.
189 if (x != invalid_node) {
79
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if (x->left != invalid_node) {
80 165 nodes_to_free.push_back(x->left);
81 }
82
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 if (x->right != invalid_node) {
83 165 nodes_to_free.push_back(x->right);
84 }
85
86
1/2
✓ Branch 0 taken 165 times.
✗ Branch 1 not taken.
165 delete x;
87
2/2
✓ Branch 1 taken 40980 times.
✓ Branch 2 taken 165 times.
41145 while (nodes_to_free.size() > 0) {
88 40980 x = nodes_to_free.back();
89 40980 nodes_to_free.pop_back();
90
2/2
✓ Branch 0 taken 20392 times.
✓ Branch 1 taken 20588 times.
40980 if (x->left != invalid_node) {
91 20392 nodes_to_free.push_back(x->left);
92 }
93
2/2
✓ Branch 0 taken 20258 times.
✓ Branch 1 taken 20722 times.
40980 if (x->right != invalid_node) {
94 20258 nodes_to_free.push_back(x->right);
95 }
96
1/2
✓ Branch 0 taken 40980 times.
✗ Branch 1 not taken.
40980 delete x;
97 }
98 }
99
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 delete invalid_node;
100
1/2
✓ Branch 0 taken 189 times.
✗ Branch 1 not taken.
189 delete root;
101 189 free(recursion_node_stack);
102 189 }
103
104 //==============================================================================
105 23831 void IntervalTree::leftRotate(IntervalTreeNode* x) {
106 IntervalTreeNode* y;
107
108 23831 y = x->right;
109 23831 x->right = y->left;
110
111
2/2
✓ Branch 0 taken 9783 times.
✓ Branch 1 taken 14048 times.
23831 if (y->left != invalid_node) y->left->parent = x;
112
113 23831 y->parent = x->parent;
114
115
2/2
✓ Branch 0 taken 6873 times.
✓ Branch 1 taken 16958 times.
23831 if (x == x->parent->left)
116 6873 x->parent->left = y;
117 else
118 16958 x->parent->right = y;
119
120 23831 y->left = x;
121 23831 x->parent = y;
122
123 23831 x->max_high =
124 23831 std::max(x->left->max_high, std::max(x->right->max_high, x->high));
125 23831 y->max_high = std::max(x->max_high, std::max(y->right->max_high, y->high));
126 23831 }
127
128 //==============================================================================
129 9390 void IntervalTree::rightRotate(IntervalTreeNode* y) {
130 IntervalTreeNode* x;
131
132 9390 x = y->left;
133 9390 y->left = x->right;
134
135
2/2
✓ Branch 0 taken 2681 times.
✓ Branch 1 taken 6709 times.
9390 if (invalid_node != x->right) x->right->parent = y;
136
137 9390 x->parent = y->parent;
138
2/2
✓ Branch 0 taken 3536 times.
✓ Branch 1 taken 5854 times.
9390 if (y == y->parent->left)
139 3536 y->parent->left = x;
140 else
141 5854 y->parent->right = x;
142
143 9390 x->right = y;
144 9390 y->parent = x;
145
146 9390 y->max_high =
147 9390 std::max(y->left->max_high, std::max(y->right->max_high, y->high));
148 9390 x->max_high = std::max(x->left->max_high, std::max(y->max_high, x->high));
149 9390 }
150
151 //==============================================================================
152 42045 void IntervalTree::recursiveInsert(IntervalTreeNode* z) {
153 IntervalTreeNode* x;
154 IntervalTreeNode* y;
155
156 42045 z->left = z->right = invalid_node;
157 42045 y = root;
158 42045 x = root->left;
159
2/2
✓ Branch 0 taken 705590 times.
✓ Branch 1 taken 42045 times.
747635 while (x != invalid_node) {
160 705590 y = x;
161
2/2
✓ Branch 0 taken 381862 times.
✓ Branch 1 taken 323728 times.
705590 if (x->key > z->key)
162 381862 x = x->left;
163 else
164 323728 x = x->right;
165 }
166 42045 z->parent = y;
167
4/4
✓ Branch 0 taken 41877 times.
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 13671 times.
✓ Branch 3 taken 28206 times.
42045 if ((y == root) || (y->key > z->key))
168 13839 y->left = z;
169 else
170 28206 y->right = z;
171 42045 }
172
173 //==============================================================================
174 42045 void IntervalTree::fixupMaxHigh(IntervalTreeNode* x) {
175
2/2
✓ Branch 0 taken 705590 times.
✓ Branch 1 taken 42045 times.
747635 while (x != root) {
176 705590 x->max_high =
177 705590 std::max(x->high, std::max(x->left->max_high, x->right->max_high));
178 705590 x = x->parent;
179 }
180 42045 }
181
182 //==============================================================================
183 42045 IntervalTreeNode* IntervalTree::insert(SimpleInterval* new_interval) {
184 IntervalTreeNode* y;
185 IntervalTreeNode* x;
186 IntervalTreeNode* new_node;
187
188
1/2
✓ Branch 2 taken 42045 times.
✗ Branch 3 not taken.
42045 x = new IntervalTreeNode(new_interval);
189 42045 recursiveInsert(x);
190 42045 fixupMaxHigh(x->parent);
191 42045 new_node = x;
192 42045 x->red = true;
193
2/2
✓ Branch 0 taken 90249 times.
✓ Branch 1 taken 42045 times.
132294 while (x->parent->red) {
194 /// use sentinel instead of checking for root
195
2/2
✓ Branch 0 taken 44725 times.
✓ Branch 1 taken 45524 times.
90249 if (x->parent == x->parent->parent->left) {
196 44725 y = x->parent->parent->right;
197
2/2
✓ Branch 0 taken 38027 times.
✓ Branch 1 taken 6698 times.
44725 if (y->red) {
198 38027 x->parent->red = true;
199 38027 y->red = true;
200 38027 x->parent->parent->red = true;
201 38027 x = x->parent->parent;
202 } else {
203
2/2
✓ Branch 0 taken 3553 times.
✓ Branch 1 taken 3145 times.
6698 if (x == x->parent->right) {
204 3553 x = x->parent;
205 3553 leftRotate(x);
206 }
207 6698 x->parent->red = false;
208 6698 x->parent->parent->red = true;
209 6698 rightRotate(x->parent->parent);
210 }
211 } else {
212 45524 y = x->parent->parent->left;
213
2/2
✓ Branch 0 taken 25246 times.
✓ Branch 1 taken 20278 times.
45524 if (y->red) {
214 25246 x->parent->red = false;
215 25246 y->red = false;
216 25246 x->parent->parent->red = true;
217 25246 x = x->parent->parent;
218 } else {
219
2/2
✓ Branch 0 taken 2692 times.
✓ Branch 1 taken 17586 times.
20278 if (x == x->parent->left) {
220 2692 x = x->parent;
221 2692 rightRotate(x);
222 }
223 20278 x->parent->red = false;
224 20278 x->parent->parent->red = true;
225 20278 leftRotate(x->parent->parent);
226 }
227 }
228 }
229 42045 root->left->red = false;
230 42045 return new_node;
231 }
232
233 //==============================================================================
234 IntervalTreeNode* IntervalTree::getSuccessor(IntervalTreeNode* x) const {
235 IntervalTreeNode* y;
236
237 if (invalid_node != (y = x->right)) {
238 while (y->left != invalid_node) y = y->left;
239 return y;
240 } else {
241 y = x->parent;
242 while (x == y->right) {
243 x = y;
244 y = y->parent;
245 }
246 if (y == root) return invalid_node;
247 return y;
248 }
249 }
250
251 //==============================================================================
252 IntervalTreeNode* IntervalTree::getPredecessor(IntervalTreeNode* x) const {
253 IntervalTreeNode* y;
254
255 if (invalid_node != (y = x->left)) {
256 while (y->right != invalid_node) y = y->right;
257 return y;
258 } else {
259 y = x->parent;
260 while (x == y->left) {
261 if (y == root) return invalid_node;
262 x = y;
263 y = y->parent;
264 }
265 return y;
266 }
267 }
268
269 //==============================================================================
270 void IntervalTree::recursivePrint(IntervalTreeNode* x) const {
271 if (x != invalid_node) {
272 recursivePrint(x->left);
273 x->print(invalid_node, root);
274 recursivePrint(x->right);
275 }
276 }
277
278 //==============================================================================
279 void IntervalTree::print() const { recursivePrint(root->left); }
280
281 //==============================================================================
282 void IntervalTree::deleteFixup(IntervalTreeNode* x) {
283 IntervalTreeNode* w;
284 IntervalTreeNode* root_left_node = root->left;
285
286 while ((!x->red) && (root_left_node != x)) {
287 if (x == x->parent->left) {
288 w = x->parent->right;
289 if (w->red) {
290 w->red = false;
291 x->parent->red = true;
292 leftRotate(x->parent);
293 w = x->parent->right;
294 }
295 if ((!w->right->red) && (!w->left->red)) {
296 w->red = true;
297 x = x->parent;
298 } else {
299 if (!w->right->red) {
300 w->left->red = false;
301 w->red = true;
302 rightRotate(w);
303 w = x->parent->right;
304 }
305 w->red = x->parent->red;
306 x->parent->red = false;
307 w->right->red = false;
308 leftRotate(x->parent);
309 x = root_left_node;
310 }
311 } else {
312 w = x->parent->left;
313 if (w->red) {
314 w->red = false;
315 x->parent->red = true;
316 rightRotate(x->parent);
317 w = x->parent->left;
318 }
319 if ((!w->right->red) && (!w->left->red)) {
320 w->red = true;
321 x = x->parent;
322 } else {
323 if (!w->left->red) {
324 w->right->red = false;
325 w->red = true;
326 leftRotate(w);
327 w = x->parent->left;
328 }
329 w->red = x->parent->red;
330 x->parent->red = false;
331 w->left->red = false;
332 rightRotate(x->parent);
333 x = root_left_node;
334 }
335 }
336 }
337 x->red = false;
338 }
339
340 //==============================================================================
341 void IntervalTree::deleteNode(SimpleInterval* ivl) {
342 IntervalTreeNode* node = recursiveSearch(root, ivl);
343 if (node) deleteNode(node);
344 }
345
346 //==============================================================================
347 IntervalTreeNode* IntervalTree::recursiveSearch(IntervalTreeNode* node,
348 SimpleInterval* ivl) const {
349 if (node != invalid_node) {
350 if (node->stored_interval == ivl) return node;
351
352 IntervalTreeNode* left = recursiveSearch(node->left, ivl);
353 if (left != invalid_node) return left;
354 IntervalTreeNode* right = recursiveSearch(node->right, ivl);
355 if (right != invalid_node) return right;
356 }
357
358 return invalid_node;
359 }
360
361 //==============================================================================
362 SimpleInterval* IntervalTree::deleteNode(IntervalTreeNode* z) {
363 IntervalTreeNode* y;
364 IntervalTreeNode* x;
365 SimpleInterval* node_to_delete = z->stored_interval;
366
367 y = ((z->left == invalid_node) || (z->right == invalid_node))
368 ? z
369 : getSuccessor(z);
370 x = (y->left == invalid_node) ? y->right : y->left;
371 if (root == (x->parent = y->parent)) {
372 root->left = x;
373 } else {
374 if (y == y->parent->left) {
375 y->parent->left = x;
376 } else {
377 y->parent->right = x;
378 }
379 }
380
381 /// @brief y should not be invalid_node in this case
382 /// y is the node to splice out and x is its child
383 if (y != z) {
384 y->max_high = -(std::numeric_limits<Scalar>::max)();
385 y->left = z->left;
386 y->right = z->right;
387 y->parent = z->parent;
388 z->left->parent = z->right->parent = y;
389 if (z == z->parent->left)
390 z->parent->left = y;
391 else
392 z->parent->right = y;
393
394 fixupMaxHigh(x->parent);
395 if (!(y->red)) {
396 y->red = z->red;
397 deleteFixup(x);
398 } else
399 y->red = z->red;
400 delete z;
401 } else {
402 fixupMaxHigh(x->parent);
403 if (!(y->red)) deleteFixup(x);
404 delete y;
405 }
406
407 return node_to_delete;
408 }
409
410 //==============================================================================
411 /// @brief returns 1 if the intervals overlap, and 0 otherwise
412 8180287 bool overlap(Scalar a1, Scalar a2, Scalar b1, Scalar b2) {
413
2/2
✓ Branch 0 taken 8044966 times.
✓ Branch 1 taken 135321 times.
8180287 if (a1 <= b1) {
414 8044966 return (b1 <= a2);
415 } else {
416 135321 return (a1 <= b2);
417 }
418 }
419
420 //==============================================================================
421 19398 std::deque<SimpleInterval*> IntervalTree::query(Scalar low, Scalar high) {
422 19398 std::deque<SimpleInterval*> result_stack;
423 19398 IntervalTreeNode* x = root->left;
424 19398 bool run = (x != invalid_node);
425
426 19398 current_parent = 0;
427
428
2/2
✓ Branch 0 taken 8180287 times.
✓ Branch 1 taken 19398 times.
8199685 while (run) {
429
3/4
✓ Branch 1 taken 8180287 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6549945 times.
✓ Branch 4 taken 1630342 times.
8180287 if (overlap(low, high, x->key, x->high)) {
430
1/2
✓ Branch 1 taken 6549945 times.
✗ Branch 2 not taken.
6549945 result_stack.push_back(x->stored_interval);
431 6549945 recursion_node_stack[current_parent].try_right_branch = true;
432 }
433
2/2
✓ Branch 0 taken 4360976 times.
✓ Branch 1 taken 3819311 times.
8180287 if (x->left->max_high >= low) {
434
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 4360974 times.
4360976 if (recursion_node_stack_top == recursion_node_stack_size) {
435 2 recursion_node_stack_size *= 2;
436 2 recursion_node_stack = (it_recursion_node*)realloc(
437 2 recursion_node_stack,
438 2 recursion_node_stack_size * sizeof(it_recursion_node));
439
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if (recursion_node_stack == nullptr) abort();
440 }
441 4360976 recursion_node_stack[recursion_node_stack_top].start_node = x;
442 4360976 recursion_node_stack[recursion_node_stack_top].try_right_branch = false;
443 4360976 recursion_node_stack[recursion_node_stack_top].parent_index =
444 4360976 current_parent;
445 4360976 current_parent = recursion_node_stack_top++;
446 4360976 x = x->left;
447 } else
448 3819311 x = x->right;
449
450 8180287 run = (x != invalid_node);
451
4/4
✓ Branch 0 taken 4380374 times.
✓ Branch 1 taken 8160889 times.
✓ Branch 2 taken 4360976 times.
✓ Branch 3 taken 19398 times.
12541263 while ((!run) && (recursion_node_stack_top > 1)) {
452
2/2
✓ Branch 0 taken 3701996 times.
✓ Branch 1 taken 658980 times.
4360976 if (recursion_node_stack[--recursion_node_stack_top].try_right_branch) {
453 3701996 x = recursion_node_stack[recursion_node_stack_top].start_node->right;
454 3701996 current_parent =
455 3701996 recursion_node_stack[recursion_node_stack_top].parent_index;
456 3701996 recursion_node_stack[current_parent].try_right_branch = true;
457 3701996 run = (x != invalid_node);
458 }
459 }
460 }
461 19398 return result_stack;
462 }
463
464 } // namespace detail
465 } // namespace coal
466
467 #endif
468