def competetive_fast_marching(vertices, graph, seeds):
    '''
    Label all vertices on highres mesh to the closest seed vertex
    using a balanced binary search tree
    '''
    import numpy as np
    import sys
    from bintrees import FastAVLTree
    # make a labelling container to be filled with the search tree
    # first column are the vertex indices of the complex mesh
    # second column are the labels from the simple mesh
    # (-1 for all but the corresponding points for now)
    labels = np.zeros((vertices.shape[0],2), dtype='int64')-1
    labels[:,0] = range(vertices.shape[0])
    for i in range(seeds.shape[0]):
        labels[seeds[i]][1] = i
    # initiate AVLTree for binary search
    tree = FastAVLTree()
    # organisation of the tree will be
    # key: edge length; value: tuple of vertices (source, target)
    # add all neighbours of the voronoi seeds
    for v in seeds:
        add_neighbours(v, 0, graph, labels, tree)
    # Competetive fast marching starting from voronoi seeds
    printcount = 0
    while tree.count > 0:
        
        printcount += 1
        
        #pdb.set_trace()
        # pop the item with minimum edge length
        min_item = tree.pop_min()
        length = min_item[0]
        source = min_item[1][0]
        target = min_item[1][1]
        #if target no label yet (but source does!), assign label of source
        if labels[target][1] == -1:
            if labels[source][1] == -1:
                sys.exit('Source has no label, something went wrong!')
            else:
                # assign label of source to target
                labels[target][1] = labels[source][1]
        
        # test if labelling is complete
        if any(labels[:,1]==-1):
            # if not, add neighbours of target to tree
            add_neighbours(target, length, graph, labels, tree)
        else:
            break
        
        if np.mod(printcount, 100) == 0.0:
            print 'tree '+str(tree.count)
            print 'labels '+str(np.where(labels[:,1]==-1)[0].shape[0])
    
    return labels
def find_voronoi_seeds(simple_vertices,
                       simple_faces,
                       complex_vertices,
                       complex_faces,
                       log_file,
                       cutoff_angle=(np.pi / 2)):
    '''
    Finds those points on the complex mesh that correspond best to the
    simple mesh (taking into accound euclidian distance and direction of normals)
    while forcing a one-to-one mapping
    '''
    from bintrees import FastAVLTree
    import scipy.spatial as spatial
    from utils import log

    # calculate normals for simple and complex vertices
    simple_normals = calculate_normals(simple_vertices, simple_faces)
    complex_normals = calculate_normals(complex_vertices, complex_faces)

    # prepare array to store seeds
    voronoi_seed_idx = np.zeros(
        (simple_vertices.shape[0], ), dtype='int64') - 1
    missing = np.where(voronoi_seed_idx == -1)[0].shape[0]

    # initialize with all vertices and small number of neighbours
    remaining_idxs = range(simple_vertices.shape[0])
    neighbours = 100

    while missing > 0:

        log(log_file, 'producing nearest neighbours k=%i' % (neighbours))
        # find nearest neighbours of simple vertices on complex mesh using kdtree
        inaccuracy, mapping = spatial.KDTree(complex_vertices).query(
            simple_vertices[remaining_idxs], k=neighbours)

        # create tidy long-format lists
        simple_idxs = np.asarray([
            neighbours * [simple_idx] for simple_idx in remaining_idxs
        ]).flatten()
        candidate_idxs = mapping.flatten()
        diff_euclid = inaccuracy.flatten()

        # for each vertex pair calculate the angle between their normals
        diff_normals, _ = compare_normals(simple_normals[simple_idxs],
                                          complex_normals[candidate_idxs])
        log(log_file, 'candidates %i' % (diff_normals.shape[0]))
        # remove those pairs that have an angle / distance above cutoff
        #mask = np.unique(np.concatenate((np.where(diff_euclid>cutoff_euclid)[0], np.where(diff_normals>cutoff_rad)[0])))
        mask = np.unique(np.where(diff_normals > cutoff_angle)[0])
        diff_normals = np.delete(diff_normals, mask)
        diff_euclid = np.delete(diff_euclid, mask)
        simple_idxs = np.delete(simple_idxs, mask)
        candidate_idxs = np.delete(candidate_idxs, mask)

        log(log_file, 'remaining candidates %i' % (diff_normals.shape[0]))
        # calculate scores for each vertex pair
        scores = (diff_normals -
                  np.mean(diff_normals)) + (diff_euclid - np.mean(diff_euclid))

        log(log_file, 'producing tree')
        # make a binary search tree from the scores and vertex pairs,
        # organisation is key: score, values: tuple(simple_vertex, candiate_complex_vertex)
        tree = FastAVLTree(zip(scores, zip(simple_idxs, candidate_idxs)))

        while tree.count > 0:

            min_item = tree.pop_min()
            simple_idx = min_item[1][0]
            candidate_idx = min_item[1][1]

            if (voronoi_seed_idx[simple_idx] == -1):
                if candidate_idx not in voronoi_seed_idx:
                    voronoi_seed_idx[simple_idx] = candidate_idx
                else:
                    pass
            else:
                pass

            missing = np.where(voronoi_seed_idx == -1)[0].shape[0]
            if missing == 0:
                break

        # if the tree is empty, but there are still seeds missing, increase the number of nearest neighbours
        # and repeat procedure, but only for those simple vertices that have not been matched yet
        log(log_file, 'missing %i' % (missing))
        remaining_idxs = np.where(voronoi_seed_idx == -1)[0]
        neighbours *= 5

    return voronoi_seed_idx, inaccuracy, log_file
def competetive_fast_marching(vertices, graph, seeds):
    '''
    Label all vertices on highres mesh to the closest seed vertex
    using a balanced binary search tree
    '''
    import numpy as np
    import sys
    from bintrees import FastAVLTree
    # make a labelling container to be filled with the search tree
    # first column are the vertex indices of the complex mesh
    # second column are the labels from the simple mesh
    # (-1 for all but the corresponding points for now)
    labels = np.zeros((vertices.shape[0], 2), dtype='int64') - 1
    labels[:, 0] = range(vertices.shape[0])
    for i in range(seeds.shape[0]):
        labels[seeds[i]][1] = i
    # initiate AVLTree for binary search
    tree = FastAVLTree()
    # organisation of the tree will be
    # key: edge length; value: tuple of vertices (source, target)
    # add all neighbours of the voronoi seeds
    for v in seeds:
        add_neighbours(v, 0, graph, labels, tree)
    # Competetive fast marching starting from voronoi seeds
    printcount = 0
    while tree.count > 0:

        printcount += 1

        # pdb.set_trace()
        # pop the item with minimum edge length
        min_item = tree.pop_min()
        length = min_item[0]
        source = min_item[1][0]
        target = min_item[1][1]
        # if target no label yet (but source does!), assign label of source
        if labels[target][1] == -1:
            if labels[source][1] == -1:
                sys.exit('Source has no label, something went wrong!')
            else:
                # assign label of source to target
                labels[target][1] = labels[source][1]

            # test if labelling is complete
            if any(labels[:, 1] == -1):
                # if not, add neighbours of target to tree
                add_neighbours(target, length, graph, labels, tree)
            else:
                break

        # if the target already has a label the item is just popped out of the
        # tree and nothing else happens
        else:
            pass

        # for monitoring the progress
        if np.mod(printcount, 100) == 0.0:
            print 'tree ' + str(tree.count)
            print 'labels ' + str(np.where(labels[:, 1] == -1)[0].shape[0])

    return labels
class PriorityQueue(object):
    """ Combined priority queue and set data structure. Acts like
        a priority queue, except that its items are guaranteed to
        be unique.

        Provides O(1) membership test, O(log N) insertion and
        O(log N) removal of the smallest item.

        Important: the items of this data structure must be both
        comparable and hashable (i.e. must implement __cmp__ and
        __hash__). This is true of Python's built-in objects, but
        you should implement those methods if you want to use
        the data structure for custom objects.
    """
    def __init__(self, items=[], key = None , maxitems=None, maxkey=None):
        """ Create a new PriorityQueueSet.

            items:
                An initial item list - it can be unsorted and
                non-unique. The data structure will be created in
                O(N).
        """
        if key == None:
            self.key=lambda  x: x
        else:
            self.key=key

        self.tree = FastAVLTree()
        #self.tree = AVLTree()

        self.maxitems = maxitems
        self.maxkey = maxkey

        for x in items:
            self.add(x)



    def has_item(self, item):
        """ Check if *item* exists in the queue
        """
        return bool(self.tree.get(self.key(item), False))

    def pop_smallest(self):
        return self.tree.pop_min()


    def peek(self, d = None):
        try:
            return self.tree.min_item()[1]
        except:
            return d

    def __setitem__(self, key, value):
        self.tree[self.key(key)]=value

    def __getitem__(self, item):
        return self.tree[self.key(item)]


    # updateing by removing and reinserting
    # i cant find a anode by object ??
    # i hate your data structures ... index in O(n) :(
    def update(self, item):
        itemsbykey = self.tree[self.key(item):self.key(item)]
        del self.tree[self.key(item):self.key(item)]
        for x in itemsbykey:
            #if not (x is item):
            self.add(x)



    def add(self, item):
        """ Add *item* to the queue. The item will be added only
            if it doesn't already exist in the queue.
        """
        #print "PriorityQue add  " + str(item)
        if self.maxkey and self.key(item) > self.maxkey:
            return

        if self.tree.get(self.key(item), None) is None:
            self.tree[self.key(item)]=item

        # sholdnt it be pop biggest??? [yes we need a tree]
        if self.maxitems and self.tree.__len__() > self.maxitems:
            self.tree.pop_max()

        #print "PriorityQue add peek " + str(self.peek())

    def prettyprint(self):
        pp = operator.methodcaller('prettyprint')
        return "".join(map(pp,self.tree.values()))

    """