Beispiel #1
0
        public void SetAsBox(float hx, float hy, Vec2 center, float angle)
        {
            VertexCount = 4;
            Vertices[0].Set(-hx, -hy);
            Vertices[1].Set(hx, -hy);
            Vertices[2].Set(hx, hy);
            Vertices[3].Set(-hx, hy);
            Normals[0].Set(0.0f, -1.0f);
            Normals[1].Set(1.0f, 0.0f);
            Normals[2].Set(0.0f, 1.0f);
            Normals[3].Set(-1.0f, 0.0f);
            Centroid = center;

            Transform xf = new Transform();

            xf.Position = center;
            xf.R.Set(angle);

            // Transform vertices and normals.
            for (int i = 0; i < VertexCount; ++i)
            {
                Vertices[i] = Math.Mul(xf, Vertices[i]);
                Normals[i]  = Math.Mul(xf.R, Normals[i]);
            }
        }
Beispiel #2
0
        public override bool TestPoint(Transform transform, Vec2 p)
        {
            Vec2 center = transform.Position + Math.Mul(transform.R, _p);
            Vec2 d      = p - center;

            return(Vec2.Dot(d, d) <= _radius * _radius);
        }
Beispiel #3
0
        private void DrawShape(Fixture fixture, Transform xf, Color color)
        {
            Color coreColor = new Color(0.9f, 0.6f, 0.6f);

            switch (fixture.GetType())
            {
            case ShapeType.CircleShape:
            {
                CircleShape circle = (CircleShape)fixture.GetShape();

                Vec2  center = Math.Mul(xf, circle._p);
                float radius = circle._radius;
                Vec2  axis   = xf.R.Col1;

                _debugDraw.DrawSolidCircle(center, radius, axis, color);
            }
            break;

            case ShapeType.PolygonShape:
            {
                PolygonShape poly        = (PolygonShape)fixture.GetShape();
                int          vertexCount = poly.VertexCount;
                Box2DXDebug.Assert(vertexCount <= Settings.MaxPolygonVertices);
                Vec2[] vertices = new Vec2[Settings.MaxPolygonVertices];

                for (int i = 0; i < vertexCount; ++i)
                {
                    vertices[i] = Math.Mul(xf, poly.Vertices[i]);
                }

                _debugDraw.DrawSolidPolygon(vertices, vertexCount, color);
            }
            break;
            }
        }
Beispiel #4
0
        internal Body(BodyDef bd, World world)
        {
            _flags = 0;

            if (bd.IsBullet)
            {
                _flags |= BodyFlags.Bullet;
            }
            if (bd.FixedRotation)
            {
                _flags |= BodyFlags.FixedRotation;
            }
            if (bd.AllowSleep)
            {
                _flags |= BodyFlags.AllowSleep;
            }
            if (bd.IsSleeping)
            {
                _flags |= BodyFlags.Sleep;
            }

            _world = world;

            _xf.Position = bd.Position;
            _xf.R.Set(bd.Angle);

            _sweep.LocalCenter.SetZero();
            _sweep.T0 = 1.0f;
            _sweep.A0 = _sweep.A = bd.Angle;
            _sweep.C0 = _sweep.C = Math.Mul(_xf, _sweep.LocalCenter);

            _jointList   = null;
            _contactList = null;
            _prev        = null;
            _next        = null;

            _linearVelocity  = bd.LinearVelocity;
            _angularVelocity = bd.AngularVelocity;

            _linearDamping  = bd.LinearDamping;
            _angularDamping = bd.AngularDamping;

            _force.Set(0.0f, 0.0f);
            _torque = 0.0f;

            _sleepTime = 0.0f;

            _mass    = 0;
            _invMass = 0.0f;
            _I       = 0.0f;
            _invI    = 0.0f;

            _type = BodyType.Static;

            _userData = bd.UserData;

            _fixtureList  = null;
            _fixtureCount = 0;
        }
Beispiel #5
0
        public override void ComputeAABB(out AABB aabb, ref Transform transform)
        {
            aabb = new AABB();

            Vec2 p = transform.Position + Math.Mul(transform.R, _p);

            aabb.LowerBound.Set(p.X - _radius, p.Y - _radius);
            aabb.UpperBound.Set(p.X + _radius, p.Y + _radius);
        }
Beispiel #6
0
        /// Set the mass properties to override the mass properties of the fixtures.
        /// Note that this changes the center of mass position. You can make the body
        /// static by using zero mass.
        /// Note that creating or destroying fixtures can also alter the mass.
        /// @warning The supplied rotational inertia is assumed to be relative to the center of mass.
        /// @param massData the mass properties.
        // TODO ERIN adjust linear velocity and torque to account for movement of center.
        public void SetMassData(MassData massData)
        {
            Box2DXDebug.Assert(_world.IsLocked() == false);
            if (_world.IsLocked() == true)
            {
                return;
            }

            _invMass = 0.0f;
            _I       = 0.0f;
            _invI    = 0.0f;

            _mass = massData.Mass;

            if (_mass > 0.0f)
            {
                _invMass = 1.0f / _mass;
            }

            if (massData.I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
            {
                _I    = massData.I - _mass * Vec2.Dot(massData.Center, massData.Center);
                _invI = 1.0f / _I;
            }

            // Move center of mass.
            Vec2 oldCenter = _sweep.C;

            _sweep.LocalCenter = massData.Center;
            _sweep.C0          = _sweep.C = Math.Mul(_xf, _sweep.LocalCenter);

            // Update center of mass velocity.
            _linearVelocity += Vec2.Cross(_angularVelocity, _sweep.C - oldCenter);

            BodyType oldType = _type;

            if (_invMass == 0.0f && _invI == 0.0f)
            {
                _type = BodyType.Static;
            }
            else
            {
                _type = BodyType.Dynamic;
            }

            // If the body type changed, we need to flag contacts for filtering.
            if (oldType != _type)
            {
                for (ContactEdge ce = _contactList; ce != null; ce = ce.Next)
                {
                    ce.Contact.FlagForFiltering();
                }
            }
        }
Beispiel #7
0
        //TODO: uncomment
        //public void Rebalance(int iterations)
        //{
        //    if (_root == NullNode)
        //    {
        //        return;
        //    }

        //    for (int i = 0; i < iterations; ++i)
        //    {
        //        int node = _root;

        //        uint bit = 0;
        //        while (_nodes[node].IsLeaf() == false)
        //        {
        //            int children = _nodes[node].Child1;
        //            node = children[(_path >> bit) & 1];
        //            bit = (bit + 1) & (8 * sizeof(uint) - 1);
        //        }
        //        ++_path;

        //        RemoveLeaf(node);
        //        InsertLeaf(node);
        //    }
        //}

        // Compute the height of a sub-tree.
        public int ComputeHeight(int nodeId)
        {
            if (nodeId == NullNode)
            {
                return(0);
            }

            Box2DXDebug.Assert(0 <= nodeId && nodeId < _nodeCapacity);
            DynamicTreeNode node    = _nodes[nodeId];
            int             height1 = ComputeHeight(node.Child1);
            int             height2 = ComputeHeight(node.Child2);

            return(1 + Math.Max(height1, height2));
        }
Beispiel #8
0
        internal void SynchronizeFixtures()
        {
            Transform xf1 = new Transform();

            xf1.R.Set(_sweep.A0);
            xf1.Position = _sweep.C0 - Math.Mul(xf1.R, _sweep.LocalCenter);

            BroadPhase broadPhase = _world._contactManager._broadPhase;

            for (Fixture f = _fixtureList; f != null; f = f._next)
            {
                f.Synchronize(broadPhase, xf1, _xf);
            }
        }
Beispiel #9
0
        public override void Step(Settings settings)
        {
            base.Step(settings);

            DistanceInput input = new DistanceInput();

            input.TransformA = _transformA;
            input.TransformB = _transformB;
            input.UseRadii   = true;
            SimplexCache cache = new SimplexCache();

            cache.Count = 0;
            DistanceOutput output;

            Collision.Distance(out output, ref cache, ref input, _polygonA, _polygonB);

            StringBuilder strBld = new StringBuilder();

            strBld.AppendFormat("distance = {0}", new object[] { output.Distance });
            OpenGLDebugDraw.DrawString(5, _textLine, strBld.ToString());
            _textLine += 15;

            strBld = new StringBuilder();
            strBld.AppendFormat("iterations = {0}", new object[] { output.Iterations });
            OpenGLDebugDraw.DrawString(5, _textLine, strBld.ToString());
            _textLine += 15;

            {
                Color color = new Color(0.9f, 0.9f, 0.9f);
                int   i;
                for (i = 0; i < _polygonA.VertexCount; ++i)
                {
                    _dv[i] = Math.Mul(_transformA, _polygonA.Vertices[i]);
                }
                _debugDraw.DrawPolygon(_dv, _polygonA.VertexCount, color);

                for (i = 0; i < _polygonB.VertexCount; ++i)
                {
                    _dv[i] = Math.Mul(_transformB, _polygonB.Vertices[i]);
                }
                _debugDraw.DrawPolygon(_dv, _polygonB.VertexCount, color);
            }

            Vec2 x1 = output.PointA;
            Vec2 x2 = output.PointB;

            OpenGLDebugDraw.DrawPoint(x1, 4.0f, new Color(1, 0, 0));
            OpenGLDebugDraw.DrawSegment(x1, x2, new Color(1, 1, 0));
            OpenGLDebugDraw.DrawPoint(x2, 4.0f, new Color(1, 0, 0));
        }
Beispiel #10
0
        public override bool TestPoint(Transform xf, Vec2 p)
        {
            Vec2 pLocal = Math.MulT(xf.R, p - xf.Position);

            for (int i = 0; i < VertexCount; ++i)
            {
                float dot = Vec2.Dot(Normals[i], pLocal - Vertices[i]);
                if (dot > 0.0f)
                {
                    return(false);
                }
            }

            return(true);
        }
Beispiel #11
0
        public override void ComputeAABB(out AABB aabb, ref Transform xf)
        {
            Vec2 lower = Math.Mul(xf, Vertices[0]);
            Vec2 upper = lower;

            for (int i = 1; i < VertexCount; ++i)
            {
                Vec2 v = Math.Mul(xf, Vertices[i]);
                lower = Math.Min(lower, v);
                upper = Math.Max(upper, v);
            }

            Vec2 r = new Vec2(_radius, _radius);

            aabb.LowerBound = lower - r;
            aabb.UpperBound = upper + r;
        }
        public override void Step(TimeStep step)
        {
            //B2_NOT_USED(step);
            if (InvSqr)
            {
                for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
                {
                    Body body1 = i.body;
                    for (ControllerEdge j = _bodyList; j != i; j = j.nextBody)
                    {
                        Body    body2 = j.body;
                        Vector2 d     = body2.GetWorldCenter() - body1.GetWorldCenter();
                        float   r2    = d.LengthSquared;
                        if (r2 < Settings.FLT_EPSILON)
                        {
                            continue;
                        }

                        Vector2 f = G / r2 / Math.Sqrt(r2) * body1.GetMass() * body2.GetMass() * d;
                        body1.ApplyForce(f, body1.GetWorldCenter());
                        body2.ApplyForce(-1.0f * f, body2.GetWorldCenter());
                    }
                }
            }
            else
            {
                for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
                {
                    Body body1 = i.body;
                    for (ControllerEdge j = _bodyList; j != i; j = j.nextBody)
                    {
                        Body    body2 = j.body;
                        Vector2 d     = body2.GetWorldCenter() - body1.GetWorldCenter();
                        float   r2    = d.LengthSquared;
                        if (r2 < Settings.FLT_EPSILON)
                        {
                            continue;
                        }
                        Vector2 f = G / r2 * body1.GetMass() * body2.GetMass() * d;
                        body1.ApplyForce(f, body1.GetWorldCenter());
                        body2.ApplyForce(-1.0f * f, body2.GetWorldCenter());
                    }
                }
            }
        }
Beispiel #13
0
        // Collision Detection in Interactive 3D Environments by Gino van den Bergen
        // From Section 3.1.2
        // x = s + a * r
        // norm(x) = radius
        public override void RayCast(out RayCastOutput output, ref RayCastInput input, Transform transform)
        {
            output = new RayCastOutput();

            Vec2  position = transform.Position + Math.Mul(transform.R, _p);
            Vec2  s        = input.P1 - position;
            float b        = Vec2.Dot(s, s) - _radius * _radius;

            // Solve quadratic equation.
            Vec2  r     = input.P2 - input.P1;
            float c     = Vec2.Dot(s, r);
            float rr    = Vec2.Dot(r, r);
            float sigma = c * c - rr * b;

            // Check for negative discriminant and short segment.
            if (sigma < 0.0f || rr < Settings.FLT_EPSILON)
            {
                output.Hit = false;
                return;
            }

            // Find the point of intersection of the line with the circle.
            float a = -(c + Math.Sqrt(sigma));

            // Is the intersection point on the segment?
            if (0.0f <= a && a <= input.MaxFraction * rr)
            {
                a              /= rr;
                output.Hit      = true;
                output.Fraction = a;
                output.Normal   = s + a * r;
                output.Normal.Normalize();
                return;
            }

            output.Hit = false;
            return;
        }
Beispiel #14
0
        public void SetTransform(Vec2 position, float angle)
        {
            Box2DXDebug.Assert(_world.IsLocked() == false);
            if (_world.IsLocked() == true)
            {
                return;
            }

            _xf.R.Set(angle);
            _xf.Position = position;

            _sweep.C0 = _sweep.C = Math.Mul(_xf, _sweep.LocalCenter);
            _sweep.A0 = _sweep.A = angle;

            BroadPhase broadPhase = _world._contactManager._broadPhase;

            for (Fixture f = _fixtureList; f != null; f = f._next)
            {
                f.Synchronize(broadPhase, _xf, _xf);
            }

            _world._contactManager.FindNewContacts();
        }
Beispiel #15
0
        /// <summary>
        /// Create a joint to constrain bodies together. No reference to the definition
        /// is retained. This may cause the connected bodies to cease colliding.
        /// @warning This function is locked during callbacks.
        /// </summary>
        /// <param name="def"></param>
        /// <returns></returns>
        public Joint CreateJoint(JointDef def)
        {
            Box2DXDebug.Assert(IsLocked() == false);
            if (IsLocked())
            {
                return(null);
            }

            Joint j = Joint.Create(def);

            // Connect to the world list.
            j._prev = null;
            j._next = _jointList;
            if (_jointList != null)
            {
                _jointList._prev = j;
            }
            _jointList = j;
            ++_jointCount;

            // Connect to the bodies' doubly linked lists.
            j._edgeA.Joint = j;
            j._edgeA.Other = j._bodyB;
            j._edgeA.Prev  = null;
            j._edgeA.Next  = j._bodyA._jointList;
            if (j._bodyA._jointList != null)
            {
                j._bodyA._jointList.Prev = j._edgeA;
            }
            j._bodyA._jointList = j._edgeA;

            j._edgeB.Joint = j;
            j._edgeB.Other = j._bodyA;
            j._edgeB.Prev  = null;
            j._edgeB.Next  = j._bodyB._jointList;
            if (j._bodyB._jointList != null)
            {
                j._bodyB._jointList.Prev = j._edgeB;
            }
            j._bodyB._jointList = j._edgeB;

            Body bodyA = def.Body1;
            Body bodyB = def.Body2;

            bool staticA = bodyA.IsStatic();
            bool staticB = bodyB.IsStatic();

            // If the joint prevents collisions, then flag any contacts for filtering.
            if (def.CollideConnected == false && (staticA == false || staticB == false))
            {
                // Ensure we iterate over contacts on a dynamic body (usually have less contacts
                // than a static body). Ideally we will have a contact count on both bodies.
                if (staticB)
                {
                    Math.Swap(ref bodyA, ref bodyB);
                }

                ContactEdge edge = bodyB.GetContactList();
                while (edge != null)
                {
                    if (edge.Other == bodyA)
                    {
                        // Flag the contact for filtering at the next time step (where either
                        // body is awake).
                        edge.Contact.FlagForFiltering();
                    }

                    edge = edge.Next;
                }
            }

            // Note: creating a joint doesn't wake the bodies.

            return(j);
        }
Beispiel #16
0
        public override void RayCast(out RayCastOutput output, ref RayCastInput input, Transform xf)
        {
            output = new RayCastOutput();

            float lower = 0.0f, upper = input.MaxFraction;

            // Put the ray into the polygon's frame of reference.
            Vec2 p1    = Math.MulT(xf.R, input.P1 - xf.Position);
            Vec2 p2    = Math.MulT(xf.R, input.P2 - xf.Position);
            Vec2 d     = p2 - p1;
            int  index = -1;

            output.Hit = false;

            for (int i = 0; i < VertexCount; ++i)
            {
                // p = p1 + a * d
                // dot(normal, p - v) = 0
                // dot(normal, p1 - v) + a * dot(normal, d) = 0
                float numerator   = Vec2.Dot(Normals[i], Vertices[i] - p1);
                float denominator = Vec2.Dot(Normals[i], d);

                if (denominator == 0.0f)
                {
                    if (numerator < 0.0f)
                    {
                        return;
                    }
                }
                else
                {
                    // Note: we want this predicate without division:
                    // lower < numerator / denominator, where denominator < 0
                    // Since denominator < 0, we have to flip the inequality:
                    // lower < numerator / denominator <==> denominator * lower > numerator.
                    if (denominator < 0.0f && numerator < lower * denominator)
                    {
                        // Increase lower.
                        // The segment enters this half-space.
                        lower = numerator / denominator;
                        index = i;
                    }
                    else if (denominator > 0.0f && numerator < upper * denominator)
                    {
                        // Decrease upper.
                        // The segment exits this half-space.
                        upper = numerator / denominator;
                    }
                }

                if (upper < lower)
                {
                    return;
                }
            }

            Box2DXDebug.Assert(0.0f <= lower && lower <= input.MaxFraction);

            if (index >= 0)
            {
                output.Hit      = true;
                output.Fraction = lower;
                output.Normal   = Math.Mul(xf.R, Normals[index]);
                return;
            }
        }
Beispiel #17
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;
            }
        }
Beispiel #18
0
 internal void SynchronizeTransform()
 {
     _xf.R.Set(_sweep.A);
     _xf.Position = _sweep.C - Math.Mul(_xf.R, _sweep.LocalCenter);
 }
Beispiel #19
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;
                }
            }
        }
Beispiel #20
0
        /// This resets the mass properties to the sum of the mass properties of the fixtures.
        /// This normally does not need to be called unless you called SetMassData to override
        /// the mass and you later want to reset the mass.
        public void ResetMass()
        {
            // Compute mass data from shapes. Each shape has its own density.
            _mass    = 0.0f;
            _invMass = 0.0f;
            _I       = 0.0f;
            _invI    = 0.0f;

            Vec2 center = Vec2.Zero;

            for (Fixture f = _fixtureList; f != null; f = f._next)
            {
                MassData massData = f.GetMassData();
                _mass  += massData.Mass;
                center += massData.Mass * massData.Center;
                _I     += massData.I;
            }

            // Compute center of mass.
            if (_mass > 0.0f)
            {
                _invMass = 1.0f / _mass;
                center  *= _invMass;
            }

            if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
            {
                // Center the inertia about the center of mass.
                _I -= _mass * Vec2.Dot(center, center);
                Box2DXDebug.Assert(_I > 0.0f);
                _invI = 1.0f / _I;
            }
            else
            {
                _I    = 0.0f;
                _invI = 0.0f;
            }

            // Move center of mass.
            Vec2 oldCenter = _sweep.C;

            _sweep.LocalCenter = center;
            _sweep.C0          = _sweep.C = Math.Mul(_xf, _sweep.LocalCenter);

            // Update center of mass velocity.
            _linearVelocity += Vec2.Cross(_angularVelocity, _sweep.C - oldCenter);

            // Determine the new body type.
            BodyType oldType = _type;

            if (_invMass == 0.0f && _invI == 0.0f)
            {
                _type = BodyType.Static;
            }
            else
            {
                _type = BodyType.Dynamic;
            }

            // If the body type changed, we need to flag contacts for filtering.
            if (oldType != _type)
            {
                for (ContactEdge ce = _contactList; ce != null; ce = ce.Next)
                {
                    ce.Contact.FlagForFiltering();
                }
            }
        }
Beispiel #21
0
        // Find TOI contacts and solve them.
        private void SolveTOI(TimeStep step)
        {
            // Reserve an island and a queue for TOI island solution.
            Island island = new Island(_bodyCount,
                                       Settings.MaxTOIContactsPerIsland,
                                       Settings.MaxTOIJointsPerIsland,
                                       _contactManager._contactListener);

            //Simple one pass queue
            //Relies on the fact that we're only making one pass
            //through and each body can only be pushed/popped once.
            //To push:
            //  queue[queueStart+queueSize++] = newElement;
            //To pop:
            //	poppedElement = queue[queueStart++];
            //  --queueSize;
            int queueCapacity = _bodyCount;

            Body[] queue = new Body[queueCapacity];

            for (Body b = _bodyList; b != null; b = b._next)
            {
                b._flags   &= ~Body.BodyFlags.Island;
                b._sweep.T0 = 0.0f;
            }

            for (Contact c = _contactManager._contactList; c != null; c = c.Next)
            {
                // Invalidate TOI
                c.Flags &= ~(ContactFlag.ToiFlag | ContactFlag.IslandFlag);
            }

            for (Joint j = _jointList; j != null; j = j._next)
            {
                j._islandFlag = false;
            }

            // Find TOI events and solve them.
            for (; ;)
            {
                // Find the first TOI.
                Contact minContact = null;
                float   minTOI     = 1.0f;

                for (Contact c = _contactManager._contactList; c != null; c = c.Next)
                {
                    // Can this contact generate a solid TOI contact?
                    if (c.IsSolid() == false || c.IsContinuous() == false)
                    {
                        continue;
                    }

                    // TODO_ERIN keep a counter on the contact, only respond to M TOIs per contact.

                    float toi = 1.0f;
                    if ((c.Flags & ContactFlag.ToiFlag) != 0)
                    {
                        // This contact has a valid cached TOI.
                        toi = c.Toi;
                    }
                    else
                    {
                        // Compute the TOI for this contact.
                        Fixture s1 = c.GetFixtureA();
                        Fixture s2 = c.GetFixtureB();
                        Body    b1 = s1.GetBody();
                        Body    b2 = s2.GetBody();

                        if ((b1.IsStatic() || b1.IsSleeping()) && (b2.IsStatic() || b2.IsSleeping()))
                        {
                            continue;
                        }

                        // Put the sweeps onto the same time interval.
                        float t0 = b1._sweep.T0;

                        if (b1._sweep.T0 < b2._sweep.T0)
                        {
                            t0 = b2._sweep.T0;
                            b1._sweep.Advance(t0);
                        }
                        else if (b2._sweep.T0 < b1._sweep.T0)
                        {
                            t0 = b1._sweep.T0;
                            b2._sweep.Advance(t0);
                        }

                        Box2DXDebug.Assert(t0 < 1.0f);

                        // Compute the time of impact.
                        toi = c.ComputeTOI(b1._sweep, b2._sweep);

                        Box2DXDebug.Assert(0.0f <= toi && toi <= 1.0f);

                        // If the TOI is in range ...
                        if (0.0f < toi && toi < 1.0f)
                        {
                            // Interpolate on the actual range.
                            toi = Math.Min((1.0f - toi) * t0 + toi, 1.0f);
                        }


                        c.Toi    = toi;
                        c.Flags |= ContactFlag.ToiFlag;
                    }

                    if (Settings.FLT_EPSILON < toi && toi < minTOI)
                    {
                        // This is the minimum TOI found so far.
                        minContact = c;
                        minTOI     = toi;
                    }
                }

                if (minContact == null || 1.0f - 100.0f * Settings.FLT_EPSILON < minTOI)
                {
                    // No more TOI events. Done!
                    break;
                }

                // Advance the bodies to the TOI.
                Fixture f1 = minContact.GetFixtureA();
                Fixture f2 = minContact.GetFixtureB();
                Body    b3 = f1.GetBody();
                Body    b4 = f2.GetBody();

                Sweep backup1 = b3._sweep;
                Sweep backup2 = b4._sweep;

                b3.Advance(minTOI);
                b4.Advance(minTOI);

                // The TOI contact likely has some new contact points.
                minContact.Update(_contactManager._contactListener);
                minContact.Flags &= ~ContactFlag.ToiFlag;

                // Is the contact solid?
                if (minContact.IsSolid() == false)
                {
                    // Restore the sweeps.
                    b3._sweep = backup1;
                    b4._sweep = backup2;
                    b3.SynchronizeTransform();
                    b4.SynchronizeTransform();
                    continue;
                }

                // Did numerical issues prevent a contact point from being generated?
                if (minContact.IsTouching() == false)
                {
                    // Give up on this TOI.
                    continue;
                }

                // Build the TOI island. We need a dynamic seed.
                Body seed = b3;
                if (seed.IsStatic())
                {
                    seed = b4;
                }

                // Reset island and queue.
                island.Clear();

                int queueStart = 0; // starting index for queue
                int queueSize  = 0; // elements in queue
                queue[queueStart + queueSize++] = seed;
                seed._flags |= Body.BodyFlags.Island;

                // Perform a breadth first search (BFS) on the contact/joint graph.
                while (queueSize > 0)
                {
                    // Grab the next body off the stack and add it to the island.
                    Body b = queue[queueStart++];
                    --queueSize;

                    island.Add(ref b);

                    // Make sure the body is awake.
                    b._flags &= ~Body.BodyFlags.Sleep;

                    // To keep islands as small as possible, we don't
                    // propagate islands across static bodies.
                    if (b.IsStatic())
                    {
                        continue;
                    }

                    // Search all contacts connected to this body.
                    for (ContactEdge cEdge = b._contactList; cEdge != null; cEdge = cEdge.Next)
                    {
                        // Does the TOI island still have space for contacts?
                        if (island.ContactCount == island.ContactCapacity)
                        {
                            break;
                        }

                        // Has this contact already been added to an island? Skip slow or non-solid contacts.
                        if ((cEdge.Contact.Flags & ContactFlag.IslandFlag) != 0)
                        {
                            continue;
                        }

                        // Is this contact touching? For performance we are not updating this contact.
                        if (cEdge.Contact.IsSolid() == false || cEdge.Contact.IsTouching() == false)
                        {
                            continue;
                        }

                        island.Add(ref cEdge.Contact);
                        cEdge.Contact.Flags |= ContactFlag.IslandFlag;

                        // Update other body.
                        Body other = cEdge.Other;

                        // Was the other body already added to this island?
                        if ((other._flags & Body.BodyFlags.Island) != 0)
                        {
                            continue;
                        }

                        // March forward, this can do no harm since this is the min TOI.
                        if (other.IsStatic() == false)
                        {
                            other.Advance(minTOI);
                            other.WakeUp();
                        }

                        Box2DXDebug.Assert(queueStart + queueSize < queueCapacity);
                        queue[queueStart + queueSize] = other;
                        ++queueSize;
                        other._flags |= Body.BodyFlags.Island;
                    }

                    for (JointEdge jEdge = b._jointList; jEdge != null; jEdge = jEdge.Next)
                    {
                        if (island.JointCount == island.JointCapacity)
                        {
                            continue;
                        }

                        if (jEdge.Joint._islandFlag == true)
                        {
                            continue;
                        }

                        island.Add(jEdge.Joint);

                        jEdge.Joint._islandFlag = true;

                        Body other = jEdge.Other;

                        if ((other._flags & Body.BodyFlags.Island) != 0)
                        {
                            continue;
                        }

                        if (!other.IsStatic())
                        {
                            other.Advance(minTOI);
                            other.WakeUp();
                        }

                        Box2DXDebug.Assert(queueStart + queueSize < queueCapacity);
                        queue[queueStart + queueSize] = other;
                        ++queueSize;
                        other._flags |= Body.BodyFlags.Island;
                    }
                }

                TimeStep subStep;
                subStep.WarmStarting       = false;
                subStep.Dt                 = (1.0f - minTOI) * step.Dt;
                subStep.Inv_Dt             = 1.0f / subStep.Dt;
                subStep.DtRatio            = 0.0f;
                subStep.VelocityIterations = step.VelocityIterations;
                subStep.PositionIterations = step.PositionIterations;

                island.SolveTOI(ref subStep);

                // Post solve cleanup.
                for (int i = 0; i < island.BodyCount; ++i)
                {
                    // Allow bodies to participate in future TOI islands.
                    Body b = island.Bodies[i];
                    b._flags &= ~Body.BodyFlags.Island;

                    if ((b._flags & Body.BodyFlags.Sleep) != 0)
                    {
                        continue;
                    }

                    if (b.IsStatic())
                    {
                        continue;
                    }

                    b.SynchronizeFixtures();

                    // Invalidate all contact TOIs associated with this body. Some of these
                    // may not be in the island because they were not touching.
                    for (ContactEdge ce = b._contactList; ce != null; ce = ce.Next)
                    {
                        ce.Contact.Flags &= ~ContactFlag.ToiFlag;
                    }
                }

                for (int i = 0; i < island.ContactCount; ++i)
                {
                    // Allow contacts to participate in future TOI islands.
                    Contact c = island.Contacts[i];
                    c.Flags &= ~(ContactFlag.ToiFlag | ContactFlag.IslandFlag);
                }

                for (int i = 0; i < island.JointCount; ++i)
                {
                    // Allow joints to participate in future TOI islands.
                    Joint j = island.Joints[i];
                    j._islandFlag = false;
                }

                // Commit fixture proxy movements to the broad-phase so that new contacts are created.
                // Also, some contacts can be destroyed.
                _contactManager.FindNewContacts();
            }

            queue = null;
        }