Пример #1
0
    private void ValidateStructure(int index)
    {
        if (index == Settings.b2_nullNode)
        {
            return;
        }

        if (index == m_root)
        {
            Debug.Assert(m_nodes[index].parentOrNext == Settings.b2_nullNode);
        }

        b2TreeNode node = m_nodes[index];

        int child1 = node.child1;
        int child2 = node.child2;

        if (node.IsLeaf())
        {
            Debug.Assert(child1 == Settings.b2_nullNode);
            Debug.Assert(child2 == Settings.b2_nullNode);
            Debug.Assert(node.height == 0);
            return;
        }

        Debug.Assert(0 <= child1 && child1 < m_nodeCapacity);
        Debug.Assert(0 <= child2 && child2 < m_nodeCapacity);

        Debug.Assert(m_nodes[child1].parentOrNext == index);
        Debug.Assert(m_nodes[child2].parentOrNext == index);

        ValidateStructure(child1);
        ValidateStructure(child2);
    }
Пример #2
0
    /// Query an AABB for overlapping proxies. The callback class
    /// is called for each proxy that overlaps the supplied AABB.
    public void Query(b2BroadphaseQueryCallback callback, b2AABB aabb)
    {
        Stack <int> stack = new Stack <int>(256);

        stack.Push(m_root);

        while (stack.Count > 0)
        {
            int nodeId = stack.Pop();
            if (nodeId == Settings.b2_nullNode)
            {
                continue;
            }

            b2TreeNode node = m_nodes[nodeId];

            if (Utils.b2TestOverlap(ref node.aabb, ref aabb))
            {
                if (node.IsLeaf())
                {
                    bool proceed = callback(nodeId);
                    if (proceed == false)
                    {
                        return;
                    }
                }
                else
                {
                    stack.Push(node.child1);
                    stack.Push(node.child2);
                }
            }
        }
    }
Пример #3
0
    // Compute the height of a sub-tree.
    private int ComputeHeight(int nodeId)
    {
        Debug.Assert(0 <= nodeId && nodeId < m_nodeCapacity);
        b2TreeNode node = m_nodes[nodeId];

        if (node.IsLeaf())
        {
            return(0);
        }

        int height1 = ComputeHeight(node.child1);
        int height2 = ComputeHeight(node.child2);

        return(1 + Utils.b2Max(height1, height2));
    }
Пример #4
0
    private void ValidateMetrics(int index)
    {
        if (index == Settings.b2_nullNode)
        {
            return;
        }

        b2TreeNode node = m_nodes[index];

        int child1 = node.child1;
        int child2 = node.child2;

        if (node.IsLeaf())
        {
            Debug.Assert(child1 == Settings.b2_nullNode);
            Debug.Assert(child2 == Settings.b2_nullNode);
            Debug.Assert(node.height == 0);
            return;
        }

        Debug.Assert(0 <= child1 && child1 < m_nodeCapacity);
        Debug.Assert(0 <= child2 && child2 < m_nodeCapacity);

        int height1 = m_nodes[child1].height;
        int height2 = m_nodes[child2].height;
        int height;

        height = 1 + Utils.b2Max(height1, height2);
        Debug.Assert(node.height == height);

        b2AABB aabb = new b2AABB();

        aabb.Combine(ref m_nodes[child1].aabb, ref m_nodes[child2].aabb);

        Debug.Assert(aabb.lowerBound == node.aabb.lowerBound);
        Debug.Assert(aabb.upperBound == node.aabb.upperBound);

        ValidateMetrics(child1);
        ValidateMetrics(child2);
    }
Пример #5
0
    /// Get the maximum balance of an node in the tree. The balance is the difference
    /// in height of the two children of a node.
    public int GetMaxBalance()
    {
        int maxBalance = 0;

        for (int i = 0; i < m_nodeCapacity; ++i)
        {
            b2TreeNode node = m_nodes[i];
            if (node.height <= 1)
            {
                continue;
            }

            Debug.Assert(node.IsLeaf() == false);

            int child1  = node.child1;
            int child2  = node.child2;
            int balance = Utils.b2Abs(m_nodes[child2].height - m_nodes[child1].height);
            maxBalance = Utils.b2Max(maxBalance, balance);
        }

        return(maxBalance);
    }
Пример #6
0
    // Perform a left or right rotation if node A is imbalanced.
    // Returns the new root index.
    private int Balance(int iA)
    {
        Debug.Assert(iA != Settings.b2_nullNode);

        b2TreeNode A = m_nodes[iA];

        if (A.IsLeaf() || A.height < 2)
        {
            return(iA);
        }

        int iB = A.child1;
        int iC = A.child2;

        Debug.Assert(0 <= iB && iB < m_nodeCapacity);
        Debug.Assert(0 <= iC && iC < m_nodeCapacity);

        b2TreeNode B = m_nodes[iB];
        b2TreeNode C = m_nodes[iC];

        int balance = C.height - B.height;

        // Rotate C up
        if (balance > 1)
        {
            int        iF = C.child1;
            int        iG = C.child2;
            b2TreeNode F  = m_nodes[iF];
            b2TreeNode G  = m_nodes[iG];
            Debug.Assert(0 <= iF && iF < m_nodeCapacity);
            Debug.Assert(0 <= iG && iG < m_nodeCapacity);

            // Swap A and C
            C.child1       = iA;
            C.parentOrNext = A.parentOrNext;
            A.parentOrNext = iC;

            // A's old parentOrNext should point to C
            if (C.parentOrNext != Settings.b2_nullNode)
            {
                if (m_nodes[C.parentOrNext].child1 == iA)
                {
                    m_nodes[C.parentOrNext].child1 = iC;
                }
                else
                {
                    Debug.Assert(m_nodes[C.parentOrNext].child2 == iA);
                    m_nodes[C.parentOrNext].child2 = iC;
                }
            }
            else
            {
                m_root = iC;
            }

            // Rotate
            if (F.height > G.height)
            {
                C.child2       = iF;
                A.child2       = iG;
                G.parentOrNext = iA;
                A.aabb.Combine(ref B.aabb, ref G.aabb);
                C.aabb.Combine(ref A.aabb, ref F.aabb);

                A.height = 1 + Utils.b2Max(B.height, G.height);
                C.height = 1 + Utils.b2Max(A.height, F.height);
            }
            else
            {
                C.child2       = iG;
                A.child2       = iF;
                F.parentOrNext = iA;
                A.aabb.Combine(ref B.aabb, ref F.aabb);
                C.aabb.Combine(ref A.aabb, ref G.aabb);

                A.height = 1 + Utils.b2Max(B.height, F.height);
                C.height = 1 + Utils.b2Max(A.height, G.height);
            }

            return(iC);
        }

        // Rotate B up
        if (balance < -1)
        {
            int        iD = B.child1;
            int        iE = B.child2;
            b2TreeNode D  = m_nodes[iD];
            b2TreeNode E  = m_nodes[iE];
            Debug.Assert(0 <= iD && iD < m_nodeCapacity);
            Debug.Assert(0 <= iE && iE < m_nodeCapacity);

            // Swap A and B
            B.child1       = iA;
            B.parentOrNext = A.parentOrNext;
            A.parentOrNext = iB;

            // A's old parentOrNext should point to B
            if (B.parentOrNext != Settings.b2_nullNode)
            {
                if (m_nodes[B.parentOrNext].child1 == iA)
                {
                    m_nodes[B.parentOrNext].child1 = iB;
                }
                else
                {
                    Debug.Assert(m_nodes[B.parentOrNext].child2 == iA);
                    m_nodes[B.parentOrNext].child2 = iB;
                }
            }
            else
            {
                m_root = iB;
            }

            // Rotate
            if (D.height > E.height)
            {
                B.child2       = iD;
                A.child1       = iE;
                E.parentOrNext = iA;
                A.aabb.Combine(ref C.aabb, ref E.aabb);
                B.aabb.Combine(ref A.aabb, ref D.aabb);

                A.height = 1 + Utils.b2Max(C.height, E.height);
                B.height = 1 + Utils.b2Max(A.height, D.height);
            }
            else
            {
                B.child2       = iE;
                A.child1       = iD;
                D.parentOrNext = iA;
                A.aabb.Combine(ref C.aabb, ref D.aabb);
                B.aabb.Combine(ref A.aabb, ref E.aabb);

                A.height = 1 + Utils.b2Max(C.height, D.height);
                B.height = 1 + Utils.b2Max(A.height, E.height);
            }

            return(iB);
        }

        return(iA);
    }
Пример #7
0
    /// Ray-cast against the proxies in the tree. This relies on the callback
    /// to perform a exact ray-cast in the case were the proxy contains a shape.
    /// The callback also performs the any collision filtering. This has performance
    /// roughly equal to k * log(n), where k is the number of collisions and n is the
    /// number of proxies in the tree.
    /// @param input the ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).
    /// @param callback a callback class that is called for each proxy that is hit by the ray.
    public void RayCast(b2BroadphaseRayCastCallback callback, b2RayCastInput input)
    {
        b2Vec2 p1 = new b2Vec2(input.p1);
        b2Vec2 p2 = new b2Vec2(input.p2);
        b2Vec2 r  = p2 - p1;

        Debug.Assert(r.LengthSquared() > 0.0f);
        r.Normalize();

        // v is perpendicular to the segment.
        b2Vec2 v     = Utils.b2Cross(1.0f, r);
        b2Vec2 abs_v = Utils.b2Abs(v);

        // Separating axis for segment (Gino, p80).
        // |dot(v, p1 - c)| > dot(|v|, h)

        float maxFraction = input.maxFraction;

        // Build a bounding box for the segment.
        b2AABB segmentAABB = new b2AABB();
        {
            b2Vec2 t = p1 + maxFraction * (p2 - p1);
            segmentAABB.lowerBound = Utils.b2Min(p1, t);
            segmentAABB.upperBound = Utils.b2Max(p1, t);
        }

        Stack <int> stack = new Stack <int>(256);

        stack.Push(m_root);

        while (stack.Count > 0)
        {
            int nodeId = stack.Pop();
            if (nodeId == Settings.b2_nullNode)
            {
                continue;
            }

            b2TreeNode node = m_nodes[nodeId];

            if (Utils.b2TestOverlap(ref node.aabb, ref segmentAABB) == false)
            {
                continue;
            }

            // Separating axis for segment (Gino, p80).
            // |dot(v, p1 - c)| > dot(|v|, h)
            b2Vec2 c          = node.aabb.GetCenter();
            b2Vec2 h          = node.aabb.GetExtents();
            float  separation = Utils.b2Abs(Utils.b2Dot(v, p1 - c)) - Utils.b2Dot(abs_v, h);
            if (separation > 0.0f)
            {
                continue;
            }

            if (node.IsLeaf())
            {
                b2RayCastInput subInput = new b2RayCastInput();
                subInput.p1          = input.p1;
                subInput.p2          = input.p2;
                subInput.maxFraction = maxFraction;

                float value = callback(subInput, nodeId);

                if (value == 0.0f)
                {
                    // The client has terminated the ray cast.
                    return;
                }

                if (value > 0.0f)
                {
                    // Update segment bounding box.
                    maxFraction = value;
                    b2Vec2 t = p1 + maxFraction * (p2 - p1);
                    segmentAABB.lowerBound = Utils.b2Min(p1, t);
                    segmentAABB.upperBound = Utils.b2Max(p1, t);
                }
            }
            else
            {
                stack.Push(node.child1);
                stack.Push(node.child2);
            }
        }
    }