Ejemplo n.º 1
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(IRayCastEnabled callback, RayCastInput input)
        {
            Vec2 p1 = input.P1;
            Vec2 p2 = input.P2;
            Vec2 r  = p2 - p1;

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

            // v is perpendicular to the segment.
            Vec2 v     = Vec2.Cross(1.0f, r);
            Vec2 abs_v = Math.Abs(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.
            AABB segmentAABB = new AABB();
            {
                Vec2 t = p1 + maxFraction * (p2 - p1);
                segmentAABB.LowerBound = Math.Min(p1, t);
                segmentAABB.UpperBound = Math.Max(p1, t);
            }

            const int k_stackSize = 128;

            int[] stack = new int[k_stackSize];

            int count = 0;

            stack[count++] = _root;

            while (count > 0)
            {
                int nodeId = stack[--count];
                if (nodeId == NullNode)
                {
                    continue;
                }

                DynamicTreeNode node = _nodes[nodeId];

                if (Collision.TestOverlap(node.Aabb, segmentAABB) == false)
                {
                    continue;
                }

                // Separating axis for segment (Gino, p80).
                // |dot(v, p1 - c)| > dot(|v|, h)
                Vec2  c          = node.Aabb.GetCenter();
                Vec2  h          = node.Aabb.GetExtents();
                float separation = Math.Abs(Vec2.Dot(v, p1 - c)) - Vec2.Dot(abs_v, h);
                if (separation > 0.0f)
                {
                    continue;
                }

                if (node.IsLeaf())
                {
                    RayCastInput subInput = new RayCastInput();
                    subInput.P1          = input.P1;
                    subInput.P2          = input.P2;
                    subInput.MaxFraction = maxFraction;

                    maxFraction = callback.RayCastCallback(subInput, nodeId);

                    if (maxFraction == 0.0f)
                    {
                        return;
                    }

                    // Update segment bounding box.
                    {
                        Vec2 t = p1 + maxFraction * (p2 - p1);
                        segmentAABB.LowerBound = Math.Min(p1, t);
                        segmentAABB.UpperBound = Math.Max(p1, t);
                    }
                }
                else
                {
                    Box2DXDebug.Assert(count + 1 < k_stackSize);
                    stack[count++] = node.Child1;
                    stack[count++] = node.Child2;
                }
            }
        }
Ejemplo n.º 2
0
        public void InsertLeaf(int leaf)
        {
            ++_insertionCount;

            if (_root == NullNode)
            {
                _root = leaf;
                _nodes[_root].Parent = NullNode;
                return;
            }

            // Find the best sibling for this node.
            Vec2 center  = _nodes[leaf].Aabb.GetCenter();
            int  sibling = _root;

            if (_nodes[sibling].IsLeaf() == false)
            {
                do
                {
                    int child1 = _nodes[sibling].Child1;
                    int child2 = _nodes[sibling].Child2;

                    Vec2 delta1 = Math.Abs(_nodes[child1].Aabb.GetCenter() - center);
                    Vec2 delta2 = Math.Abs(_nodes[child2].Aabb.GetCenter() - center);

                    float norm1 = delta1.X + delta1.Y;
                    float norm2 = delta2.X + delta2.Y;

                    if (norm1 < norm2)
                    {
                        sibling = child1;
                    }
                    else
                    {
                        sibling = child2;
                    }
                }while (_nodes[sibling].IsLeaf() == false);
            }

            // Create a parent for the siblings.
            int node1 = _nodes[sibling].Parent;
            int node2 = AllocateNode();

            _nodes[node2].Parent   = node1;
            _nodes[node2].UserData = null;
            _nodes[node2].Aabb.Combine(_nodes[leaf].Aabb, _nodes[sibling].Aabb);

            if (node1 != NullNode)
            {
                if (_nodes[_nodes[sibling].Parent].Child1 == sibling)
                {
                    _nodes[node1].Child1 = node2;
                }
                else
                {
                    _nodes[node1].Child2 = node2;
                }

                _nodes[node2].Child1   = sibling;
                _nodes[node2].Child2   = leaf;
                _nodes[sibling].Parent = node2;
                _nodes[leaf].Parent    = node2;

                do
                {
                    if (_nodes[node1].Aabb.Contains(_nodes[node2].Aabb))
                    {
                        break;
                    }

                    _nodes[node1].Aabb.Combine(_nodes[_nodes[node1].Child1].Aabb, _nodes[_nodes[node1].Child2].Aabb);
                    node2 = node1;
                    node1 = _nodes[node1].Parent;
                }while (node1 != NullNode);
            }
            else
            {
                _nodes[node2].Child1   = sibling;
                _nodes[node2].Child2   = leaf;
                _nodes[sibling].Parent = node2;
                _nodes[leaf].Parent    = node2;
                _root = node2;
            }
        }