Esempio n. 1
0
        public Branch AddSubtree(string name)
        {
            var newBranch = new Branch(name);

            Subtrees.Add(newBranch);
            return(newBranch);
        }
Esempio n. 2
0
        unsafe int CreateStagingNode(int parentIndex, int indexInParent, ref BoundingBox boundingBox,
                                     ref Subtrees subtrees, int start, int count,
                                     Node *stagingNodes, ref int stagingNodeCount, out float childTreeletsCost)
        {
            var stagingNodeIndex = stagingNodeCount++;
            var stagingNode      = stagingNodes + stagingNodeIndex;

            if (count <= ChildrenCapacity)
            {
                //No need to do any sorting. This node can fit every remaining subtree.
                var localIndexMap = subtrees.IndexMap + start;
                stagingNode->ChildCount = count;
                var stagingNodeBounds   = &stagingNode->A;
                var stagingNodeChildren = &stagingNode->ChildA;
                var leafCounts          = &stagingNode->LeafCountA;
                for (int i = 0; i < count; ++i)
                {
                    var subtreeIndex = localIndexMap[i];
                    stagingNodeBounds[i]   = subtrees.BoundingBoxes[subtreeIndex];
                    leafCounts[i]          = subtrees.LeafCounts[subtreeIndex];
                    stagingNodeChildren[i] = Encode(subtreeIndex);
                }
                //Because subtrees do not change in size, they cannot change the cost.
                childTreeletsCost = 0;
                return(stagingNodeIndex);
            }

            const int recursionDepth = ChildrenCapacity == 32 ? 4 : ChildrenCapacity == 16 ? 3 : ChildrenCapacity == 8 ? 2 : ChildrenCapacity == 4 ? 1 : 0;


            SplitSubtreesIntoChildren(recursionDepth, ref subtrees, start, count, ref boundingBox, stagingNodes, stagingNodeIndex, ref stagingNodeCount, out childTreeletsCost);


            return(stagingNodeIndex);
        }
Esempio n. 3
0
 public void DeleteSubtree(Branch branch)
 {
     Subtrees.Remove(branch);
 }
Esempio n. 4
0
        unsafe void SplitSubtreesIntoChildren(int depthRemaining, ref Subtrees subtrees,
                                              int start, int count, ref BoundingBox boundingBox,
                                              Node *stagingNodes, int stagingNodeIndex, ref int stagingNodesCount, out float childrenTreeletsCost)
        {
            if (count > 1)
            {
                BoundingBox a, b;
                int         leafCountA, leafCountB;
                int         splitIndex;
                FindPartition(ref subtrees, start, count, out splitIndex, out a, out b, out leafCountA, out leafCountB);

                float costA, costB;
                if (depthRemaining > 0)
                {
                    --depthRemaining;
                    SplitSubtreesIntoChildren(depthRemaining, ref subtrees, start, splitIndex - start, ref a, stagingNodes, stagingNodeIndex, ref stagingNodesCount, out costA);
                    SplitSubtreesIntoChildren(depthRemaining, ref subtrees, splitIndex, start + count - splitIndex, ref b, stagingNodes, stagingNodeIndex, ref stagingNodesCount, out costB);
                }
                else
                {
                    //Recursion bottomed out.
                    var stagingNode = stagingNodes + stagingNodeIndex;
                    var childIndexA = stagingNode->ChildCount++;
                    var childIndexB = stagingNode->ChildCount++;
                    Debug.Assert(stagingNode->ChildCount <= ChildrenCapacity);

                    var stagingBounds     = &stagingNode->A;
                    var stagingChildren   = &stagingNode->ChildA;
                    var stagingLeafCounts = &stagingNode->LeafCountA;

                    stagingBounds[childIndexA] = a;
                    stagingBounds[childIndexB] = b;

                    stagingLeafCounts[childIndexA] = leafCountA;
                    stagingLeafCounts[childIndexB] = leafCountB;

                    int subtreeCountA = splitIndex - start;
                    int subtreeCountB = start + count - splitIndex;
                    if (subtreeCountA > 1)
                    {
                        stagingChildren[childIndexA] = CreateStagingNode(stagingNodeIndex, childIndexA, ref a, ref subtrees, start, subtreeCountA,
                                                                         stagingNodes, ref stagingNodesCount, out costA);
                        costA += ComputeBoundsMetric(ref a); //An internal node was created; measure its cost.
                    }
                    else
                    {
                        Debug.Assert(subtreeCountA == 1);
                        //Only one subtree. Don't create another node.
                        stagingChildren[childIndexA] = Encode(subtrees.IndexMap[start]);
                        costA = 0;
                    }
                    if (subtreeCountB > 1)
                    {
                        stagingChildren[childIndexB] = CreateStagingNode(stagingNodeIndex, childIndexB, ref b, ref subtrees, splitIndex, subtreeCountB,
                                                                         stagingNodes, ref stagingNodesCount, out costB);
                        costB += ComputeBoundsMetric(ref b); //An internal node was created; measure its cost.
                    }
                    else
                    {
                        Debug.Assert(subtreeCountB == 1);
                        //Only one subtree. Don't create another node.
                        stagingChildren[childIndexB] = Encode(subtrees.IndexMap[splitIndex]);
                        costB = 0;
                    }
                }
                childrenTreeletsCost = costA + costB;
            }
            else
            {
                Debug.Assert(count == 1);
                //Only one subtree. Just stick it directly into the node.
                var childIndex   = stagingNodes[stagingNodeIndex].ChildCount++;
                var subtreeIndex = subtrees.IndexMap[start];
                Debug.Assert(stagingNodes[stagingNodeIndex].ChildCount <= ChildrenCapacity);
                (&stagingNodes[stagingNodeIndex].A)[childIndex]          = subtrees.BoundingBoxes[subtreeIndex];
                (&stagingNodes[stagingNodeIndex].ChildA)[childIndex]     = Encode(subtreeIndex);
                (&stagingNodes[stagingNodeIndex].LeafCountA)[childIndex] = subtrees.LeafCounts[subtreeIndex];
                //Subtrees cannot contribute to change in cost.
                childrenTreeletsCost = 0;
            }
        }
Esempio n. 5
0
        unsafe void FindPartition(ref Subtrees subtrees, int start, int count,
                                  out int splitIndex, out BoundingBox a, out BoundingBox b, out int leafCountA, out int leafCountB)
        {
            //A variety of potential microoptimizations exist here.
            //Don't reallocate centroids (because JIT is forced to zero by roslyn), do swaps better, etc.
            var indexMapX = stackalloc int[count];
            var indexMapY = stackalloc int[count];
            var indexMapZ = stackalloc int[count];

            //Initialize the per-axis candidate maps.
            var localIndexMap = subtrees.IndexMap + start;

            for (int i = 0; i < count; ++i)
            {
                var originalValue = localIndexMap[i];
                indexMapX[i] = originalValue;
                indexMapY[i] = originalValue;
                indexMapZ[i] = originalValue;
            }

            int         xSplitIndex, xLeafCountA, xLeafCountB, ySplitIndex, yLeafCountA, yLeafCountB, zSplitIndex, zLeafCountA, zLeafCountB;
            BoundingBox xA, xB, yA, yB, zA, zB;
            float       xCost, yCost, zCost;

            FindPartitionForAxis(subtrees.BoundingBoxes, subtrees.LeafCounts, subtrees.CentroidsX, indexMapX, count, out xSplitIndex, out xCost, out xA, out xB, out xLeafCountA, out xLeafCountB);
            FindPartitionForAxis(subtrees.BoundingBoxes, subtrees.LeafCounts, subtrees.CentroidsY, indexMapY, count, out ySplitIndex, out yCost, out yA, out yB, out yLeafCountA, out yLeafCountB);
            FindPartitionForAxis(subtrees.BoundingBoxes, subtrees.LeafCounts, subtrees.CentroidsZ, indexMapZ, count, out zSplitIndex, out zCost, out zA, out zB, out zLeafCountA, out zLeafCountB);

            int *bestIndexMap;

            if (xCost <= yCost && xCost <= zCost)
            {
                splitIndex   = xSplitIndex;
                a            = xA;
                b            = xB;
                leafCountA   = xLeafCountA;
                leafCountB   = xLeafCountB;
                bestIndexMap = indexMapX;
            }
            else if (yCost <= zCost)
            {
                splitIndex   = ySplitIndex;
                a            = yA;
                b            = yB;
                leafCountA   = yLeafCountA;
                leafCountB   = yLeafCountB;
                bestIndexMap = indexMapY;
            }
            else
            {
                splitIndex   = zSplitIndex;
                a            = zA;
                b            = zB;
                leafCountA   = zLeafCountA;
                leafCountB   = zLeafCountB;
                bestIndexMap = indexMapZ;
            }
            for (int i = 0; i < count; ++i)
            {
                localIndexMap[i] = bestIndexMap[i];
            }

            splitIndex += start;
        }