/*
* Farseer Physics Engine based on Box2D.XNA port:
* Copyright (c) 2010 Ian Qvist
* 
* Box2D.XNA port of Box2D:
* Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler
*
* Original source Box2D:
* Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com 
* 
* This software is provided 'as-is', without any express or implied 
* warranty.  In no event will the authors be held liable for any damages 
* arising from the use of this software. 
* Permission is granted to anyone to use this software for any purpose, 
* including commercial applications, and to alter it and redistribute it 
* freely, subject to the following restrictions: 
* 1. The origin of this software must not be misrepresented; you must not 
* claim that you wrote the original software. If you use this software 
* in a product, an acknowledgment in the product documentation would be 
* appreciated but is not required. 
* 2. Altered source versions must be plainly marked as such, and must not be 
* misrepresented as being the original software. 
* 3. This notice may not be removed or altered from any source distribution. 
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using FarseerPhysics.Collision;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Controllers;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
    /// 
    /// The body type.
    /// 
    public enum BodyType
    {
        /// 
        /// Zero velocity, may be manually moved. Note: even static bodies have mass.
        /// 
        Static,
        /// 
        /// Zero mass, non-zero velocity set by user, moved by solver
        /// 
        Kinematic,
        /// 
        /// Positive mass, non-zero velocity determined by forces, moved by solver
        /// 
        Dynamic,
    }
    [Flags]
    public enum BodyFlags
    {
        None = 0,
        Island = (1 << 0),
        Awake = (1 << 1),
        AutoSleep = (1 << 2),
        Bullet = (1 << 3),
        FixedRotation = (1 << 4),
        Enabled = (1 << 5),
        IgnoreGravity = (1 << 6),
        IgnoreCCD = (1 << 7),
    }
    public class Body : IDisposable
    {
        private static int _bodyIdCounter;
        internal float AngularVelocityInternal;
        public int BodyId;
        public ControllerFilter ControllerFilter;
        internal BodyFlags Flags;
        internal Vector2 Force;
        internal float InvI;
        internal float InvMass;
        internal Vector2 LinearVelocityInternal;
        public PhysicsLogicFilter PhysicsLogicFilter;
        internal float SleepTime;
        internal Sweep Sweep; // the swept motion for CCD
        internal float Torque;
        internal World World;
        internal Transform Xf; // the body origin transform
        private float _angularDamping;
        private BodyType _bodyType;
        private float _inertia;
        private float _linearDamping;
        private float _mass;
        internal Body()
        {
            FixtureList = new List(32);
        }
        public Body(World world)
            : this(world, null)
        {
        }
        public Body(World world, object userData)
        {
            FixtureList = new List(32);
            BodyId = _bodyIdCounter++;
            World = world;
            UserData = userData;
            FixedRotation = false;
            IsBullet = false;
            SleepingAllowed = true;
            Awake = true;
            BodyType = BodyType.Static;
            Enabled = true;
            Xf.R.Set(0);
            world.AddBody(this);
        }
        /// 
        /// Gets the total number revolutions the body has made.
        /// 
        /// The revolutions.
        public float Revolutions
        {
            get { return Rotation / (float)Math.PI; }
        }
        /// 
        /// Gets or sets the body type.
        /// 
        /// The type of body.
        public BodyType BodyType
        {
            get { return _bodyType; }
            set
            {
                if (_bodyType == value)
                {
                    return;
                }
                _bodyType = value;
                ResetMassData();
                if (_bodyType == BodyType.Static)
                {
                    LinearVelocityInternal = Vector2.Zero;
                    AngularVelocityInternal = 0.0f;
                }
                Awake = true;
                Force = Vector2.Zero;
                Torque = 0.0f;
                // Since the body type changed, we need to flag contacts for filtering.
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.Refilter();
                }
            }
        }
        /// 
        /// Get or sets the linear velocity of the center of mass.
        /// 
        /// The linear velocity.
        public Vector2 LinearVelocity
        {
            set
            {
                Debug.Assert(!float.IsNaN(value.X) && !float.IsNaN(value.Y));
                if (_bodyType == BodyType.Static)
                    return;
                if (Vector2.Dot(value, value) > 0.0f)
                    Awake = true;
                LinearVelocityInternal = value;
            }
            get { return LinearVelocityInternal; }
        }
        /// 
        /// Gets or sets the angular velocity. Radians/second.
        /// 
        /// The angular velocity.
        public float AngularVelocity
        {
            set
            {
                Debug.Assert(!float.IsNaN(value));
                if (_bodyType == BodyType.Static)
                    return;
                if (value * value > 0.0f)
                    Awake = true;
                AngularVelocityInternal = value;
            }
            get { return AngularVelocityInternal; }
        }
        /// 
        /// Gets or sets the linear damping.
        /// 
        /// The linear damping.
        public float LinearDamping
        {
            get { return _linearDamping; }
            set
            {
                Debug.Assert(!float.IsNaN(value));
                _linearDamping = value;
            }
        }
        /// 
        /// Gets or sets the angular damping.
        /// 
        /// The angular damping.
        public float AngularDamping
        {
            get { return _angularDamping; }
            set
            {
                Debug.Assert(!float.IsNaN(value));
                _angularDamping = value;
            }
        }
        /// 
        /// Gets or sets a value indicating whether this body should be included in the CCD solver.
        /// 
        /// true if this instance is included in CCD; otherwise, false.
        public bool IsBullet
        {
            set
            {
                if (value)
                {
                    Flags |= BodyFlags.Bullet;
                }
                else
                {
                    Flags &= ~BodyFlags.Bullet;
                }
            }
            get { return (Flags & BodyFlags.Bullet) == BodyFlags.Bullet; }
        }
        /// 
        /// You can disable sleeping on this body. If you disable sleeping, the
        /// body will be woken.
        /// 
        /// true if sleeping is allowed; otherwise, false.
        public bool SleepingAllowed
        {
            set
            {
                if (value)
                {
                    Flags |= BodyFlags.AutoSleep;
                }
                else
                {
                    Flags &= ~BodyFlags.AutoSleep;
                    Awake = true;
                }
            }
            get { return (Flags & BodyFlags.AutoSleep) == BodyFlags.AutoSleep; }
        }
        /// 
        /// Set the sleep state of the body. A sleeping body has very
        /// low CPU cost.
        /// 
        /// true if awake; otherwise, false.
        public bool Awake
        {
            set
            {
                if (value)
                {
                    if ((Flags & BodyFlags.Awake) == 0)
                    {
                        Flags |= BodyFlags.Awake;
                        SleepTime = 0.0f;
                    }
                }
                else
                {
                    Flags &= ~BodyFlags.Awake;
                    SleepTime = 0.0f;
                    LinearVelocityInternal = Vector2.Zero;
                    AngularVelocityInternal = 0.0f;
                    Force = Vector2.Zero;
                    Torque = 0.0f;
                }
            }
            get { return (Flags & BodyFlags.Awake) == BodyFlags.Awake; }
        }
        /// 
        /// Set the active state of the body. An inactive body is not
        /// simulated and cannot be collided with or woken up.
        /// If you pass a flag of true, all fixtures will be added to the
        /// broad-phase.
        /// If you pass a flag of false, all fixtures will be removed from
        /// the broad-phase and all contacts will be destroyed.
        /// Fixtures and joints are otherwise unaffected. You may continue
        /// to create/destroy fixtures and joints on inactive bodies.
        /// Fixtures on an inactive body are implicitly inactive and will
        /// not participate in collisions, ray-casts, or queries.
        /// Joints connected to an inactive body are implicitly inactive.
        /// An inactive body is still owned by a b2World object and remains
        /// in the body list.
        /// 
        /// true if active; otherwise, false.
        public bool Enabled
        {
            set
            {
                if (value == Enabled)
                {
                    return;
                }
                if (value)
                {
                    Flags |= BodyFlags.Enabled;
                    // Create all proxies.
                    IBroadPhase broadPhase = World.ContactManager.BroadPhase;
                    for (int i = 0; i < FixtureList.Count; i++)
                    {
                        FixtureList[i].CreateProxies(broadPhase, ref Xf);
                    }
                    // Contacts are created the next time step.
                }
                else
                {
                    Flags &= ~BodyFlags.Enabled;
                    // Destroy all proxies.
                    IBroadPhase broadPhase = World.ContactManager.BroadPhase;
                    for (int i = 0; i < FixtureList.Count; i++)
                    {
                        FixtureList[i].DestroyProxies(broadPhase);
                    }
                    // Destroy the attached contacts.
                    ContactEdge ce = ContactList;
                    while (ce != null)
                    {
                        ContactEdge ce0 = ce;
                        ce = ce.Next;
                        World.ContactManager.Destroy(ce0.Contact);
                    }
                    ContactList = null;
                }
            }
            get { return (Flags & BodyFlags.Enabled) == BodyFlags.Enabled; }
        }
        /// 
        /// Set this body to have fixed rotation. This causes the mass
        /// to be reset.
        /// 
        /// true if it has fixed rotation; otherwise, false.
        public bool FixedRotation
        {
            set
            {
                if (value)
                {
                    Flags |= BodyFlags.FixedRotation;
                }
                else
                {
                    Flags &= ~BodyFlags.FixedRotation;
                }
                ResetMassData();
            }
            get { return (Flags & BodyFlags.FixedRotation) == BodyFlags.FixedRotation; }
        }
        /// 
        /// Gets all the fixtures attached to this body.
        /// 
        /// The fixture list.
        public List FixtureList { get; internal set; }
        /// 
        /// Get the list of all joints attached to this body.
        /// 
        /// The joint list.
        public JointEdge JointList { get; internal set; }
        /// 
        /// Get the list of all contacts attached to this body.
        /// Warning: this list changes during the time step and you may
        /// miss some collisions if you don't use ContactListener.
        /// 
        /// The contact list.
        public ContactEdge ContactList { get; internal set; }
        /// 
        /// Set the user data. Use this to store your application specific data.
        /// 
        /// The user data.
        private object _userdata;
        public object UserData
         {
             get
             {
                 return this._userdata;
             }
             set
             {
                 this._userdata = value;
                 foreach (Fixture f in this.FixtureList)
                     f.UserData = value;
             }
         }
        /// 
        /// Get the world body origin position.
        /// 
        /// Return the world position of the body's origin.
        public Vector2 Position
        {
            get { return Xf.Position; }
            set
            {
                Debug.Assert(!float.IsNaN(value.X) && !float.IsNaN(value.Y));
                SetTransform(ref value, Rotation);
            }
        }
        /// 
        /// Get the angle in radians.
        /// 
        /// Return the current world rotation angle in radians.
        public float Rotation
        {
            get { return Sweep.A; }
            set
            {
                Debug.Assert(!float.IsNaN(value));
                SetTransform(ref Xf.Position, value);
            }
        }
        /// 
        /// Gets or sets a value indicating whether this body is static.
        /// 
        /// true if this instance is static; otherwise, false.
        public bool IsStatic
        {
            get { return _bodyType == BodyType.Static; }
            set
            {
                if (value)
                    BodyType = BodyType.Static;
                else
                    BodyType = BodyType.Dynamic;
            }
        }
        /// 
        /// Gets or sets a value indicating whether this body ignores gravity.
        /// 
        /// true if  it ignores gravity; otherwise, false.
        public bool IgnoreGravity
        {
            get { return (Flags & BodyFlags.IgnoreGravity) == BodyFlags.IgnoreGravity; }
            set
            {
                if (value)
                    Flags |= BodyFlags.IgnoreGravity;
                else
                    Flags &= ~BodyFlags.IgnoreGravity;
            }
        }
        /// 
        /// Get the world position of the center of mass.
        /// 
        /// The world position.
        public Vector2 WorldCenter
        {
            get { return Sweep.C; }
        }
        /// 
        /// Get the local position of the center of mass.
        /// 
        /// The local position.
        public Vector2 LocalCenter
        {
            get { return Sweep.LocalCenter; }
            set
            {
                if (_bodyType != BodyType.Dynamic)
                    return;
                // Move center of mass.
                Vector2 oldCenter = Sweep.C;
                Sweep.LocalCenter = value;
                Sweep.C0 = Sweep.C = MathUtils.Multiply(ref Xf, ref Sweep.LocalCenter);
                // Update center of mass velocity.
                Vector2 a = Sweep.C - oldCenter;
                LinearVelocityInternal += new Vector2(-AngularVelocityInternal * a.Y, AngularVelocityInternal * a.X);
            }
        }
        /// 
        /// Gets or sets the mass. Usually in kilograms (kg).
        /// 
        /// The mass.
        public float Mass
        {
            get { return _mass; }
            set
            {
                Debug.Assert(!float.IsNaN(value));
                if (_bodyType != BodyType.Dynamic)
                    return;
                _mass = value;
                if (_mass <= 0.0f)
                    _mass = 1.0f;
                InvMass = 1.0f / _mass;
            }
        }
        /// 
        /// Get or set the rotational inertia of the body about the local origin. usually in kg-m^2.
        /// 
        /// The inertia.
        public float Inertia
        {
            get { return _inertia + Mass * Vector2.Dot(Sweep.LocalCenter, Sweep.LocalCenter); }
            set
            {
                Debug.Assert(!float.IsNaN(value));
                if (_bodyType != BodyType.Dynamic)
                    return;
                if (value > 0.0f && (Flags & BodyFlags.FixedRotation) == 0)
                {
                    _inertia = value - Mass * Vector2.Dot(LocalCenter, LocalCenter);
                    Debug.Assert(_inertia > 0.0f);
                    InvI = 1.0f / _inertia;
                }
            }
        }
        public float Restitution
        {
            get
            {
                float res = 0;
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    res += f.Restitution;
                }
                return res / FixtureList.Count;
            }
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.Restitution = value;
                }
            }
        }
        public float Friction
        {
            get
            {
                float res = 0;
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    res += f.Friction;
                }
                return res / FixtureList.Count;
            }
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.Friction = value;
                }
            }
        }
        public Category CollisionCategories
        {
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.CollisionCategories = value;
                }
            }
        }
        public Category CollidesWith
        {
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.CollidesWith = value;
                }
            }
        }
        public short CollisionGroup
        {
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.CollisionGroup = value;
                }
            }
        }
        public bool IsSensor
        {
            set
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    Fixture f = FixtureList[i];
                    f.IsSensor = value;
                }
            }
        }
        public bool IgnoreCCD
        {
            get { return (Flags & BodyFlags.IgnoreCCD) == BodyFlags.IgnoreCCD; }
            set
            {
                if (value)
                    Flags |= BodyFlags.IgnoreCCD;
                else
                    Flags &= ~BodyFlags.IgnoreCCD;
            }
        }
        #region IDisposable Members
        public bool IsDisposed { get; set; }
        public void Dispose()
        {
            if (!IsDisposed)
            {
                World.RemoveBody(this);
                IsDisposed = true;
                GC.SuppressFinalize(this);
            }
        }
        #endregion
        /// 
        /// Resets the dynamics of this body.
        /// Sets torque, force and linear/angular velocity to 0
        /// 
        public void ResetDynamics()
        {
            Torque = 0;
            AngularVelocityInternal = 0;
            Force = Vector2.Zero;
            LinearVelocityInternal = Vector2.Zero;
        }
        /// 
        /// Creates a fixture and attach it to this body.
        /// If the density is non-zero, this function automatically updates the mass of the body.
        /// Contacts are not created until the next time step.
        /// Warning: This function is locked during callbacks.
        /// 
        /// The shape.
        /// 
        public Fixture CreateFixture(Shape shape)
        {
            return new Fixture(this, shape);
        }
        /// 
        /// Creates a fixture and attach it to this body.
        /// If the density is non-zero, this function automatically updates the mass of the body.
        /// Contacts are not created until the next time step.
        /// Warning: This function is locked during callbacks.
        /// 
        /// The shape.
        /// Application specific data
        /// 
        public Fixture CreateFixture(Shape shape, object userData)
        {
            return new Fixture(this, shape, userData);
        }
        /// 
        /// Destroy a fixture. This removes the fixture from the broad-phase and
        /// destroys all contacts associated with this fixture. This will
        /// automatically adjust the mass of the body if the body is dynamic and the
        /// fixture has positive density.
        /// All fixtures attached to a body are implicitly destroyed when the body is destroyed.
        /// Warning: This function is locked during callbacks.
        /// 
        /// The fixture to be removed.
        public void DestroyFixture(Fixture fixture)
        {
            Debug.Assert(fixture.Body == this);
            // Remove the fixture from this body's singly linked list.
            Debug.Assert(FixtureList.Count > 0);
            // You tried to remove a fixture that not present in the fixturelist.
            Debug.Assert(FixtureList.Contains(fixture));
            // Destroy any contacts associated with the fixture.
            ContactEdge edge = ContactList;
            while (edge != null)
            {
                Contact c = edge.Contact;
                edge = edge.Next;
                Fixture fixtureA = c.FixtureA;
                Fixture fixtureB = c.FixtureB;
                if (fixture == fixtureA || fixture == fixtureB)
                {
                    // This destroys the contact and removes it from
                    // this body's contact list.
                    World.ContactManager.Destroy(c);
                }
            }
            if ((Flags & BodyFlags.Enabled) == BodyFlags.Enabled)
            {
                IBroadPhase broadPhase = World.ContactManager.BroadPhase;
                fixture.DestroyProxies(broadPhase);
            }
            FixtureList.Remove(fixture);
            fixture.Destroy();
            fixture.Body = null;
            ResetMassData();
        }
        /// 
        /// Set the position of the body's origin and rotation.
        /// This breaks any contacts and wakes the other bodies.
        /// Manipulating a body's transform may cause non-physical behavior.
        /// 
        /// The world position of the body's local origin.
        /// The world rotation in radians.
        public void SetTransform(ref Vector2 position, float rotation)
        {
            SetTransformIgnoreContacts(ref position, rotation);
            World.ContactManager.FindNewContacts();
        }
        /// 
        /// Set the position of the body's origin and rotation.
        /// This breaks any contacts and wakes the other bodies.
        /// Manipulating a body's transform may cause non-physical behavior.
        /// 
        /// The world position of the body's local origin.
        /// The world rotation in radians.
        public void SetTransform(Vector2 position, float rotation)
        {
            SetTransform(ref position, rotation);
        }
        /// 
        /// For teleporting a body without considering new contacts immediately.
        /// 
        /// The position.
        /// The angle.
        public void SetTransformIgnoreContacts(ref Vector2 position, float angle)
        {
            Xf.R.Set(angle);
            Xf.Position = position;
            Sweep.C0 =
                Sweep.C =
                new Vector2(Xf.Position.X + Xf.R.Col1.X * Sweep.LocalCenter.X + Xf.R.Col2.X * Sweep.LocalCenter.Y,
                            Xf.Position.Y + Xf.R.Col1.Y * Sweep.LocalCenter.X + Xf.R.Col2.Y * Sweep.LocalCenter.Y);
            Sweep.A0 = Sweep.A = angle;
            IBroadPhase broadPhase = World.ContactManager.BroadPhase;
            for (int i = 0; i < FixtureList.Count; i++)
            {
                FixtureList[i].Synchronize(broadPhase, ref Xf, ref Xf);
            }
        }
        /// 
        /// Get the body transform for the body's origin.
        /// 
        /// The transform of the body's origin.
        public void GetTransform(out Transform transform)
        {
            transform = Xf;
        }
        /// 
        /// Apply a force at a world point. If the force is not
        /// applied at the center of mass, it will generate a torque and
        /// affect the angular velocity. This wakes up the body.
        /// 
        /// The world force vector, usually in Newtons (N).
        /// The world position of the point of application.
        public void ApplyForce(Vector2 force, Vector2 point)
        {
            ApplyForce(ref force, ref point);
        }
        /// 
        /// Applies a force at the center of mass.
        /// 
        /// The force.
        public void ApplyForce(ref Vector2 force)
        {
            ApplyForce(ref force, ref Xf.Position);
        }
        /// 
        /// Applies a force at the center of mass.
        /// 
        /// The force.
        public void ApplyForce(Vector2 force)
        {
            ApplyForce(ref force, ref Xf.Position);
        }
        /// 
        /// Apply a force at a world point. If the force is not
        /// applied at the center of mass, it will generate a torque and
        /// affect the angular velocity. This wakes up the body.
        /// 
        /// The world force vector, usually in Newtons (N).
        /// The world position of the point of application.
        public void ApplyForce(ref Vector2 force, ref Vector2 point)
        {
            Debug.Assert(!float.IsNaN(force.X));
            Debug.Assert(!float.IsNaN(force.Y));
            Debug.Assert(!float.IsNaN(point.X));
            Debug.Assert(!float.IsNaN(point.Y));
            if (_bodyType == BodyType.Dynamic)
            {
                if (Awake == false)
                {
                    Awake = true;
                }
                Force += force;
                Torque += (point.X - Sweep.C.X) * force.Y - (point.Y - Sweep.C.Y) * force.X;
            }
        }
        /// 
        /// Apply a torque. This affects the angular velocity
        /// without affecting the linear velocity of the center of mass.
        /// This wakes up the body.
        /// 
        /// The torque about the z-axis (out of the screen), usually in N-m.
        public void ApplyTorque(float torque)
        {
            Debug.Assert(!float.IsNaN(torque));
            if (_bodyType == BodyType.Dynamic)
            {
                if (Awake == false)
                {
                    Awake = true;
                }
                Torque += torque;
            }
        }
        /// 
        /// Apply an impulse at a point. This immediately modifies the velocity.
        /// This wakes up the body.
        /// 
        /// The world impulse vector, usually in N-seconds or kg-m/s.
        public void ApplyLinearImpulse(Vector2 impulse)
        {
            ApplyLinearImpulse(ref impulse);
        }
        /// 
        /// Apply an impulse at a point. This immediately modifies the velocity.
        /// It also modifies the angular velocity if the point of application
        /// is not at the center of mass.
        /// This wakes up the body.
        /// 
        /// The world impulse vector, usually in N-seconds or kg-m/s.
        /// The world position of the point of application.
        public void ApplyLinearImpulse(Vector2 impulse, Vector2 point)
        {
            ApplyLinearImpulse(ref impulse, ref point);
        }
        /// 
        /// Apply an impulse at a point. This immediately modifies the velocity.
        /// This wakes up the body.
        /// 
        /// The world impulse vector, usually in N-seconds or kg-m/s.
        public void ApplyLinearImpulse(ref Vector2 impulse)
        {
            if (_bodyType != BodyType.Dynamic)
            {
                return;
            }
            if (Awake == false)
            {
                Awake = true;
            }
            LinearVelocityInternal += InvMass * impulse;
        }
        /// 
        /// Apply an impulse at a point. This immediately modifies the velocity.
        /// It also modifies the angular velocity if the point of application
        /// is not at the center of mass.
        /// This wakes up the body.
        /// 
        /// The world impulse vector, usually in N-seconds or kg-m/s.
        /// The world position of the point of application.
        public void ApplyLinearImpulse(ref Vector2 impulse, ref Vector2 point)
        {
            if (_bodyType != BodyType.Dynamic)
                return;
            if (Awake == false)
                Awake = true;
            LinearVelocityInternal += InvMass * impulse;
            AngularVelocityInternal += InvI * ((point.X - Sweep.C.X) * impulse.Y - (point.Y - Sweep.C.Y) * impulse.X);
        }
        /// 
        /// Apply an angular impulse.
        /// 
        /// The angular impulse in units of kg*m*m/s.
        public void ApplyAngularImpulse(float impulse)
        {
            if (_bodyType != BodyType.Dynamic)
            {
                return;
            }
            if (Awake == false)
            {
                Awake = true;
            }
            AngularVelocityInternal += InvI * impulse;
        }
        /// 
        /// 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 ResetMassData()
        {
            // Compute mass data from shapes. Each shape has its own density.
            _mass = 0.0f;
            InvMass = 0.0f;
            _inertia = 0.0f;
            InvI = 0.0f;
            Sweep.LocalCenter = Vector2.Zero;
            // Kinematic bodies have zero mass.
            if (BodyType == BodyType.Kinematic)
            {
                Sweep.C0 = Sweep.C = Xf.Position;
                return;
            }
            Debug.Assert(BodyType == BodyType.Dynamic || BodyType == BodyType.Static);
            // Accumulate mass over all fixtures.
            Vector2 center = Vector2.Zero;
            foreach (Fixture f in FixtureList)
            {
                if (f.Shape._density == 0)
                {
                    continue;
                }
                MassData massData = f.Shape.MassData;
                _mass += massData.Mass;
                center += massData.Mass * massData.Centroid;
                _inertia += massData.Inertia;
            }
            //Static bodies only have mass, they don't have other properties. A little hacky tho...
            if (BodyType == BodyType.Static)
            {
                Sweep.C0 = Sweep.C = Xf.Position;
                return;
            }
            // Compute center of mass.
            if (_mass > 0.0f)
            {
                InvMass = 1.0f / _mass;
                center *= InvMass;
            }
            else
            {
                // Force all dynamic bodies to have a positive mass.
                _mass = 1.0f;
                InvMass = 1.0f;
            }
            if (_inertia > 0.0f && (Flags & BodyFlags.FixedRotation) == 0)
            {
                // Center the inertia about the center of mass.
                _inertia -= _mass * Vector2.Dot(center, center);
                Debug.Assert(_inertia > 0.0f);
                InvI = 1.0f / _inertia;
            }
            else
            {
                _inertia = 0.0f;
                InvI = 0.0f;
            }
            // Move center of mass.
            Vector2 oldCenter = Sweep.C;
            Sweep.LocalCenter = center;
            Sweep.C0 = Sweep.C = MathUtils.Multiply(ref Xf, ref Sweep.LocalCenter);
            // Update center of mass velocity.
            Vector2 a = Sweep.C - oldCenter;
            LinearVelocityInternal += new Vector2(-AngularVelocityInternal * a.Y, AngularVelocityInternal * a.X);
        }
        /// 
        /// Get the world coordinates of a point given the local coordinates.
        /// 
        /// A point on the body measured relative the the body's origin.
        /// The same point expressed in world coordinates.
        public Vector2 GetWorldPoint(ref Vector2 localPoint)
        {
            return new Vector2(Xf.Position.X + Xf.R.Col1.X * localPoint.X + Xf.R.Col2.X * localPoint.Y,
                               Xf.Position.Y + Xf.R.Col1.Y * localPoint.X + Xf.R.Col2.Y * localPoint.Y);
        }
        /// 
        /// Get the world coordinates of a point given the local coordinates.
        /// 
        /// A point on the body measured relative the the body's origin.
        /// The same point expressed in world coordinates.
        public Vector2 GetWorldPoint(Vector2 localPoint)
        {
            return GetWorldPoint(ref localPoint);
        }
        /// 
        /// Get the world coordinates of a vector given the local coordinates.
        /// Note that the vector only takes the rotation into account, not the position.
        /// 
        /// A vector fixed in the body.
        /// The same vector expressed in world coordinates.
        public Vector2 GetWorldVector(ref Vector2 localVector)
        {
            return new Vector2(Xf.R.Col1.X * localVector.X + Xf.R.Col2.X * localVector.Y,
                               Xf.R.Col1.Y * localVector.X + Xf.R.Col2.Y * localVector.Y);
        }
        /// 
        /// Get the world coordinates of a vector given the local coordinates.
        /// 
        /// A vector fixed in the body.
        /// The same vector expressed in world coordinates.
        public Vector2 GetWorldVector(Vector2 localVector)
        {
            return GetWorldVector(ref localVector);
        }
        /// 
        /// Gets a local point relative to the body's origin given a world point.
        /// Note that the vector only takes the rotation into account, not the position.
        /// 
        /// A point in world coordinates.
        /// The corresponding local point relative to the body's origin.
        public Vector2 GetLocalPoint(ref Vector2 worldPoint)
        {
            return
                new Vector2((worldPoint.X - Xf.Position.X) * Xf.R.Col1.X + (worldPoint.Y - Xf.Position.Y) * Xf.R.Col1.Y,
                            (worldPoint.X - Xf.Position.X) * Xf.R.Col2.X + (worldPoint.Y - Xf.Position.Y) * Xf.R.Col2.Y);
        }
        /// 
        /// Gets a local point relative to the body's origin given a world point.
        /// 
        /// A point in world coordinates.
        /// The corresponding local point relative to the body's origin.
        public Vector2 GetLocalPoint(Vector2 worldPoint)
        {
            return GetLocalPoint(ref worldPoint);
        }
        /// 
        /// Gets a local vector given a world vector.
        /// Note that the vector only takes the rotation into account, not the position.
        /// 
        /// A vector in world coordinates.
        /// The corresponding local vector.
        public Vector2 GetLocalVector(ref Vector2 worldVector)
        {
            return new Vector2(worldVector.X * Xf.R.Col1.X + worldVector.Y * Xf.R.Col1.Y,
                               worldVector.X * Xf.R.Col2.X + worldVector.Y * Xf.R.Col2.Y);
        }
        /// 
        /// Gets a local vector given a world vector.
        /// Note that the vector only takes the rotation into account, not the position.
        /// 
        /// A vector in world coordinates.
        /// The corresponding local vector.
        public Vector2 GetLocalVector(Vector2 worldVector)
        {
            return GetLocalVector(ref worldVector);
        }
        /// 
        /// Get the world linear velocity of a world point attached to this body.
        /// 
        /// A point in world coordinates.
        /// The world velocity of a point.
        public Vector2 GetLinearVelocityFromWorldPoint(Vector2 worldPoint)
        {
            return GetLinearVelocityFromWorldPoint(ref worldPoint);
        }
        /// 
        /// Get the world linear velocity of a world point attached to this body.
        /// 
        /// A point in world coordinates.
        /// The world velocity of a point.
        public Vector2 GetLinearVelocityFromWorldPoint(ref Vector2 worldPoint)
        {
            return LinearVelocityInternal +
                   new Vector2(-AngularVelocityInternal * (worldPoint.Y - Sweep.C.Y),
                               AngularVelocityInternal * (worldPoint.X - Sweep.C.X));
        }
        /// 
        /// Get the world velocity of a local point.
        /// 
        /// A point in local coordinates.
        /// The world velocity of a point.
        public Vector2 GetLinearVelocityFromLocalPoint(Vector2 localPoint)
        {
            return GetLinearVelocityFromLocalPoint(ref localPoint);
        }
        /// 
        /// Get the world velocity of a local point.
        /// 
        /// A point in local coordinates.
        /// The world velocity of a point.
        public Vector2 GetLinearVelocityFromLocalPoint(ref Vector2 localPoint)
        {
            return GetLinearVelocityFromWorldPoint(GetWorldPoint(ref localPoint));
        }
        public Body DeepClone()
        {
            Body body = Clone();
            for (int i = 0; i < FixtureList.Count; i++)
            {
                FixtureList[i].Clone(body);
            }
            return body;
        }
        public Body Clone()
        {
            Body body = new Body();
            body.World = World;
            body.UserData = UserData;
            body.LinearDamping = LinearDamping;
            body.LinearVelocityInternal = LinearVelocityInternal;
            body.AngularDamping = AngularDamping;
            body.AngularVelocityInternal = AngularVelocityInternal;
            body.Position = Position;
            body.Rotation = Rotation;
            body._bodyType = _bodyType;
            body.Flags = Flags;
            World.AddBody(body);
            return body;
        }
        internal void SynchronizeFixtures()
        {
            Transform xf1 = new Transform();
            float c = (float)Math.Cos(Sweep.A0), s = (float)Math.Sin(Sweep.A0);
            xf1.R.Col1.X = c;
            xf1.R.Col2.X = -s;
            xf1.R.Col1.Y = s;
            xf1.R.Col2.Y = c;
            xf1.Position.X = Sweep.C0.X - (xf1.R.Col1.X * Sweep.LocalCenter.X + xf1.R.Col2.X * Sweep.LocalCenter.Y);
            xf1.Position.Y = Sweep.C0.Y - (xf1.R.Col1.Y * Sweep.LocalCenter.X + xf1.R.Col2.Y * Sweep.LocalCenter.Y);
            IBroadPhase broadPhase = World.ContactManager.BroadPhase;
            for (int i = 0; i < FixtureList.Count; i++)
            {
                FixtureList[i].Synchronize(broadPhase, ref xf1, ref Xf);
            }
        }
        internal void SynchronizeTransform()
        {
            Xf.R.Set(Sweep.A);
            float vx = Xf.R.Col1.X * Sweep.LocalCenter.X + Xf.R.Col2.X * Sweep.LocalCenter.Y;
            float vy = Xf.R.Col1.Y * Sweep.LocalCenter.X + Xf.R.Col2.Y * Sweep.LocalCenter.Y;
            Xf.Position.X = Sweep.C.X - vx;
            Xf.Position.Y = Sweep.C.Y - vy;
        }
        /// 
        /// This is used to prevent connected bodies from colliding.
        /// It may lie, depending on the collideConnected flag.
        /// 
        /// The other body.
        /// 
        internal bool ShouldCollide(Body other)
        {
            // At least one body should be dynamic.
            if (_bodyType != BodyType.Dynamic && other._bodyType != BodyType.Dynamic)
            {
                return false;
            }
            // Does a joint prevent collision?
            for (JointEdge jn = JointList; jn != null; jn = jn.Next)
            {
                if (jn.Other == other)
                {
                    if (jn.Joint.CollideConnected == false)
                    {
                        return false;
                    }
                }
            }
            return true;
        }
        internal void Advance(float alpha)
        {
            // Advance to the new safe time.
            Sweep.Advance(alpha);
            Sweep.C = Sweep.C0;
            Sweep.A = Sweep.A0;
            SynchronizeTransform();
        }
        public event OnCollisionEventHandler OnCollision
        {
            add
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    FixtureList[i].OnCollision += value;
                }
            }
            remove
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    FixtureList[i].OnCollision -= value;
                }
            }
        }
        public event OnSeparationEventHandler OnSeparation
        {
            add
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    FixtureList[i].OnSeparation += value;
                }
            }
            remove
            {
                for (int i = 0; i < FixtureList.Count; i++)
                {
                    FixtureList[i].OnSeparation -= value;
                }
            }
        }
        public void IgnoreCollisionWith(Body other)
        {
            for (int i = 0; i < FixtureList.Count; i++)
            {
                Fixture f = FixtureList[i];
                for (int j = 0; j < other.FixtureList.Count; j++)
                {
                    Fixture f2 = other.FixtureList[j];
                    f.IgnoreCollisionWith(f2);
                }
            }
        }
        public void RestoreCollisionWith(Body other)
        {
            for (int i = 0; i < FixtureList.Count; i++)
            {
                Fixture f = FixtureList[i];
                for (int j = 0; j < other.FixtureList.Count; j++)
                {
                    Fixture f2 = other.FixtureList[j];
                    f.RestoreCollisionWith(f2);
                }
            }
        }
    }
}