How to effectively get results from Octree / Quadtree?

I am working on 3D software that sometimes has to intersect between massive numbers of curves (sometimes ~ 100,000). The most natural way to do this is to test the bounding box N ^ 2, and then intersect the curves that overlap the bounding fields.

I heard well about octets, so I decided to try to see if I would get improved performance.

Here is my design: Each octree node is implemented as a class with a list of subnods and an ordered list of object indices.

When an object is added, it is added to the lower node, which completely contains the object, or some of what node children are, if the object does not fill all the children.

Now I want to get all the objects that share the node tree with this object. To do this, I traverse all nodes of the tree, and if they contain a given index, I add all their other indexes to the ordered list.

This is effective because the indexes inside each node are already ordered, so finding out that each index is already in the list is quick. However, the list needs to be changed, and this takes up most of the time in the algorithm. Therefore, I need some kind of tree-like data structure that will allow me to efficiently add ordered data, as well as be efficient in memory.

Any suggestions?

+3
source share
2 answers

SortedDictionary (.NET 2+) SortedSet ( .NET 4), , . .

SortedList , List .

, . , , , . , HashSet . , SortedList , .

, , , , , .

SortedDictionary . . , SortedDictionary , , + . SortedList .

SortedDictionary . ( 6 ). "" .Distinct() (, , ) .

:

class Heap<T>
{
    public Heap(int limit, IComparer<T> comparer)
    {
        this.comparer = comparer;
        data = new T[limit];
    }

    int count = 0;
    T[] data;

    public void Add(T t)
    {
        data[count++] = t;
        promote(count-1);
    }

    IComparer<T> comparer;

    public int Count { get { return count; } }

    public T Pop()
    {
        T result = data[0];
        fill(0);
        return result;
    }

    bool less(T a, T b)
    {
        return comparer.Compare(a,b)<0;
    }

    void fill(int index)
    {
        int child1 = index*2+1;
        int child2 = index*2+2;
        if(child1 >= Count)
        {
            data[index] = data[--count];
            if(index!=count)
                promote(index);
        }
        else
        {
            int bestChild = child1;
            if(child2 < Count && less(data[child2], data[child1]))
            {
                bestChild = child2;
            }

            data[index] = data[bestChild];
            fill(bestChild);
        }
    }

    void promote(int index)
    {
        if(index==0)
            return;
        int parent = (index-1)/2;
        if(less(data[index], data[parent]))
        {
            T tmp = data[parent];
            data[parent] = data[index];
            data[index] = tmp;
            promote(parent);
        }
    }
}

struct ArrayCursor<T>
{
    public T [] Array {get;set;}
    public int Index {get;set;}
    public bool Finished {get{return Array.Length == Index;}}
    public T Value{get{return Array[Index];}}
}

class ArrayComparer<T> : IComparer<ArrayCursor<T>>
{
    IComparer<T> comparer;
    public ArrayComparer(IComparer<T> comparer)
    {
        this.comparer = comparer;
    }

    public int Compare (ArrayCursor<T> a, ArrayCursor<T> b)
    {
        return comparer.Compare(a.Value, b.Value);
    }
}

static class HeapMerger
{
    public static IEnumerable<T> MergeUnique<T>(this T[][] arrays)
    {
        bool first = true;
        T last = default(T);
        IEqualityComparer<T> eq = EqualityComparer<T>.Default;
        foreach(T i in Merge(arrays))
            if(first || !eq.Equals(last,i))
            {
                yield return i;
                last = i;
                first = false;
            }
    }

    public static IEnumerable<T> Merge<T>(this T[][] arrays)
    {
        var map = new Heap<ArrayCursor<T>>(arrays.Length, new ArrayComparer<T>(Comparer<T>.Default));

        Action<ArrayCursor<T>> tryAdd = (a)=>
        {
            if(!a.Finished)
                map.Add(a);
        };

        for(int i=0;i<arrays.Length;i++)
            tryAdd(new ArrayCursor<T>{Array=arrays[i], Index=0});

        while(map.Count>0)
        {
            ArrayCursor<T> lowest = map.Pop();
            yield return lowest.Value;
            lowest.Index++;
            tryAdd(lowest);
        }
    }
}
0

, OctTree , , , , . , . , SortedList .

var results = new SortedList<Node>( octTree.Count );
// now find the node and add the points
results = result.TrimToSize(); // reclaim space as needed

, node node. node , . , , /, node, / .

+1

Source: https://habr.com/ru/post/1750343/


All Articles