mirror of
https://github.com/CopterExpress/clover.git
synced 2026-06-03 00:19:33 +00:00
209 lines
5.6 KiB
C++
209 lines
5.6 KiB
C++
// This file is part of OpenCV project.
|
|
// It is subject to the license terms in the LICENSE file found in the top-level directory
|
|
// of this distribution and at http://opencv.org/license.html.
|
|
//
|
|
// Copyright (C) 2013-2016, The Regents of The University of Michigan.
|
|
//
|
|
// This software was developed in the APRIL Robotics Lab under the
|
|
// direction of Edwin Olson, ebolson@umich.edu. This software may be
|
|
// available under alternative licensing terms; contact the address above.
|
|
//
|
|
// The views and conclusions contained in the software and documentation are those
|
|
// of the authors and should not be interpreted as representing official policies,
|
|
// either expressed or implied, of the Regents of The University of Michigan.
|
|
|
|
#include "precomp.hpp"
|
|
#include "zmaxheap.hpp"
|
|
|
|
|
|
// 0
|
|
// 1 2
|
|
// 3 4 5 6
|
|
// 7 8 9 10 11 12 13 14
|
|
//
|
|
// Children of node i: 2*i+1, 2*i+2
|
|
// Parent of node i: (i-1) / 2
|
|
//
|
|
// Heap property: a parent is greater than (or equal to) its children.
|
|
|
|
#define MIN_CAPACITY 16
|
|
namespace cv {
|
|
namespace aruco {
|
|
struct zmaxheap
|
|
{
|
|
size_t el_sz;
|
|
|
|
int size;
|
|
int alloc;
|
|
|
|
float *values;
|
|
char *data;
|
|
|
|
void (*swap)(zmaxheap_t *heap, int a, int b);
|
|
};
|
|
|
|
static inline void _swap_default(zmaxheap_t *heap, int a, int b)
|
|
{
|
|
float t = heap->values[a];
|
|
heap->values[a] = heap->values[b];
|
|
heap->values[b] = t;
|
|
|
|
cv::AutoBuffer<char> tmp(heap->el_sz);
|
|
/* NOTE: OpenCV v<3.3 does not have .data() member for AutoBuffer */
|
|
memcpy(tmp, &heap->data[a*heap->el_sz], heap->el_sz);
|
|
memcpy(&heap->data[a*heap->el_sz], &heap->data[b*heap->el_sz], heap->el_sz);
|
|
memcpy(&heap->data[b*heap->el_sz], tmp, heap->el_sz);
|
|
}
|
|
|
|
static inline void _swap_pointer(zmaxheap_t *heap, int a, int b)
|
|
{
|
|
float t = heap->values[a];
|
|
heap->values[a] = heap->values[b];
|
|
heap->values[b] = t;
|
|
|
|
void **pp = (void**) heap->data;
|
|
void *tmp = pp[a];
|
|
pp[a] = pp[b];
|
|
pp[b] = tmp;
|
|
}
|
|
|
|
|
|
zmaxheap_t *zmaxheap_create(size_t el_sz)
|
|
{
|
|
zmaxheap_t *heap = (zmaxheap_t*)calloc(1, sizeof(zmaxheap_t));
|
|
heap->el_sz = el_sz;
|
|
|
|
heap->swap = _swap_default;
|
|
|
|
if (el_sz == sizeof(void*))
|
|
heap->swap = _swap_pointer;
|
|
|
|
return heap;
|
|
}
|
|
|
|
void zmaxheap_destroy(zmaxheap_t *heap)
|
|
{
|
|
free(heap->values);
|
|
free(heap->data);
|
|
memset(heap, 0, sizeof(zmaxheap_t));
|
|
free(heap);
|
|
}
|
|
|
|
static void _zmaxheap_ensure_capacity(zmaxheap_t *heap, int capacity)
|
|
{
|
|
if (heap->alloc >= capacity)
|
|
return;
|
|
|
|
int newcap = heap->alloc;
|
|
|
|
while (newcap < capacity) {
|
|
if (newcap < MIN_CAPACITY) {
|
|
newcap = MIN_CAPACITY;
|
|
continue;
|
|
}
|
|
|
|
newcap *= 2;
|
|
}
|
|
|
|
heap->values = (float*)realloc(heap->values, newcap * sizeof(float));
|
|
heap->data = (char*)realloc(heap->data, newcap * heap->el_sz);
|
|
heap->alloc = newcap;
|
|
}
|
|
|
|
void zmaxheap_add(zmaxheap_t *heap, void *p, float v)
|
|
{
|
|
_zmaxheap_ensure_capacity(heap, heap->size + 1);
|
|
|
|
int idx = heap->size;
|
|
|
|
heap->values[idx] = v;
|
|
memcpy(&heap->data[idx*heap->el_sz], p, heap->el_sz);
|
|
|
|
heap->size++;
|
|
|
|
while (idx > 0) {
|
|
|
|
int parent = (idx - 1) / 2;
|
|
|
|
// we're done!
|
|
if (heap->values[parent] >= v)
|
|
break;
|
|
|
|
// else, swap and recurse upwards.
|
|
heap->swap(heap, idx, parent);
|
|
idx = parent;
|
|
}
|
|
}
|
|
|
|
// Removes the item in the heap at the given index. Returns 1 if the
|
|
// item existed. 0 Indicates an invalid idx (heap is smaller than
|
|
// idx). This is mostly intended to be used by zmaxheap_remove_max.
|
|
static int zmaxheap_remove_index(zmaxheap_t *heap, int idx, void *p, float *v)
|
|
{
|
|
if (idx >= heap->size)
|
|
return 0;
|
|
|
|
// copy out the requested element from the heap.
|
|
if (v != NULL)
|
|
*v = heap->values[idx];
|
|
if (p != NULL)
|
|
memcpy(p, &heap->data[idx*heap->el_sz], heap->el_sz);
|
|
|
|
heap->size--;
|
|
|
|
// If this element is already the last one, then there's nothing
|
|
// for us to do.
|
|
if (idx == heap->size)
|
|
return 1;
|
|
|
|
// copy last element to first element. (which probably upsets
|
|
// the heap property).
|
|
heap->values[idx] = heap->values[heap->size];
|
|
memcpy(&heap->data[idx*heap->el_sz], &heap->data[heap->el_sz * heap->size], heap->el_sz);
|
|
|
|
// now fix the heap. Note, as we descend, we're "pushing down"
|
|
// the same node the entire time. Thus, while the index of the
|
|
// parent might change, the parent_score doesn't.
|
|
int parent = idx;
|
|
float parent_score = heap->values[idx];
|
|
|
|
// descend, fixing the heap.
|
|
while (parent < heap->size) {
|
|
|
|
int left = 2*parent + 1;
|
|
int right = left + 1;
|
|
|
|
// assert(parent_score == heap->values[parent]);
|
|
|
|
float left_score = (left < heap->size) ? heap->values[left] : -INFINITY;
|
|
float right_score = (right < heap->size) ? heap->values[right] : -INFINITY;
|
|
|
|
// put the biggest of (parent, left, right) as the parent.
|
|
|
|
// already okay?
|
|
if (parent_score >= left_score && parent_score >= right_score)
|
|
break;
|
|
|
|
// if we got here, then one of the children is bigger than the parent.
|
|
if (left_score >= right_score) {
|
|
CV_Assert(left < heap->size);
|
|
heap->swap(heap, parent, left);
|
|
parent = left;
|
|
} else {
|
|
// right_score can't be less than left_score if right_score is -INFINITY.
|
|
CV_Assert(right < heap->size);
|
|
heap->swap(heap, parent, right);
|
|
parent = right;
|
|
}
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
int zmaxheap_remove_max(zmaxheap_t *heap, void *p, float *v)
|
|
{
|
|
return zmaxheap_remove_index(heap, 0, p, v);
|
|
}
|
|
|
|
}}
|