(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -0,0 +1,154 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
/// <summary>
/// An easy to use factory for creating bodies
/// </summary>
public partial class Body
{
/// <summary>
/// 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 method is locked during callbacks.
/// </summary>
/// <param name="shape">The shape.</param>
/// <param name="userData">Application specific data</param>
/// <returns></returns>
public virtual Fixture CreateFixture(Shape shape)
{
Fixture fixture = new Fixture(shape);
Add(fixture);
return fixture;
}
public Fixture CreateEdge(Vector2 start, Vector2 end)
{
EdgeShape edgeShape = new EdgeShape(start, end);
return CreateFixture(edgeShape);
}
public Fixture CreateChainShape(Vertices vertices)
{
ChainShape shape = new ChainShape(vertices);
return CreateFixture(shape);
}
public Fixture CreateLoopShape(Vertices vertices)
{
ChainShape shape = new ChainShape(vertices, true);
return CreateFixture(shape);
}
public Fixture CreateRectangle(float width, float height, float density, Vector2 offset)
{
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2);
rectangleVertices.Translate(ref offset);
PolygonShape rectangleShape = new PolygonShape(rectangleVertices, density);
return CreateFixture(rectangleShape);
}
public Fixture CreateRectangle(float width, float height, float density, float rotation, Vector2 offset)
{
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2, Vector2.Zero, rotation);
rectangleVertices.Translate(ref offset);
PolygonShape rectangleShape = new PolygonShape(rectangleVertices, density);
return CreateFixture(rectangleShape);
}
public Fixture CreateCircle(float radius, float density)
{
if (radius <= 0)
throw new ArgumentOutOfRangeException("radius", "Radius must be more than 0 meters");
CircleShape circleShape = new CircleShape(radius, density);
return CreateFixture(circleShape);
}
public Fixture CreateCircle(float radius, float density, Vector2 offset)
{
if (radius <= 0)
throw new ArgumentOutOfRangeException("radius", "Radius must be more than 0 meters");
CircleShape circleShape = new CircleShape(radius, density);
circleShape.Position = offset;
return CreateFixture(circleShape);
}
public Fixture CreatePolygon(Vertices vertices, float density)
{
if (vertices.Count <= 1)
throw new ArgumentOutOfRangeException("vertices", "Too few points to be a polygon");
PolygonShape polygon = new PolygonShape(vertices, density);
return CreateFixture(polygon);
}
public Fixture CreateEllipse(float xRadius, float yRadius, int edges, float density)
{
if (xRadius <= 0)
throw new ArgumentOutOfRangeException("xRadius", "X-radius must be more than 0");
if (yRadius <= 0)
throw new ArgumentOutOfRangeException("yRadius", "Y-radius must be more than 0");
Vertices ellipseVertices = PolygonTools.CreateEllipse(xRadius, yRadius, edges);
PolygonShape polygonShape = new PolygonShape(ellipseVertices, density);
return CreateFixture(polygonShape);
}
public List<Fixture> CreateCompoundPolygon(List<Vertices> list, float density)
{
List<Fixture> res = new List<Fixture>(list.Count);
//Then we create several fixtures using the body
foreach (Vertices vertices in list)
{
if (vertices.Count == 2)
{
EdgeShape shape = new EdgeShape(vertices[0], vertices[1]);
res.Add(CreateFixture(shape));
}
else
{
PolygonShape shape = new PolygonShape(vertices, density);
res.Add(CreateFixture(shape));
}
}
return res;
}
public Fixture CreateLineArc(float radians, int sides, float radius, bool closed)
{
Vertices arc = PolygonTools.CreateArc(radians, sides, radius);
arc.Rotate((MathHelper.Pi - radians) / 2);
return closed ? CreateLoopShape(arc) : CreateChainShape(arc);
}
public List<Fixture> CreateSolidArc(float density, float radians, int sides, float radius)
{
Vertices arc = PolygonTools.CreateArc(radians, sides, radius);
arc.Rotate((MathHelper.Pi - radians) / 2);
//Close the arc
arc.Add(arc[0]);
List<Vertices> triangles = Triangulate.ConvexPartition(arc, TriangulationAlgorithm.Earclip);
return CreateCompoundPolygon(triangles, density);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
* Original source Box2D:
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* 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.
*/
namespace FarseerPhysics
{
/// <summary>
/// The body type.
/// </summary>
public enum BodyType
{
/// <summary>
/// Zero velocity, may be manually moved. Note: even static bodies have mass.
/// </summary>
Static,
/// <summary>
/// Zero mass, non-zero velocity set by user, moved by solver
/// </summary>
Kinematic,
/// <summary>
/// Positive mass, non-zero velocity determined by forces, moved by solver
/// </summary>
Dynamic,
}
}
@@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
/// <summary>
/// A type of body that supports multiple fixtures that can break apart.
/// </summary>
public class BreakableBody
{
private float[] _angularVelocitiesCache = new float[8];
private bool _break;
private Vector2[] _velocitiesCache = new Vector2[8];
private World _world;
public BreakableBody(IEnumerable<Vertices> vertices, World world, float density)
{
_world = world;
_world.ContactManager.PostSolve += PostSolve;
MainBody = new Body(_world);
MainBody.BodyType = BodyType.Dynamic;
foreach (Vertices part in vertices)
{
PolygonShape polygonShape = new PolygonShape(part, density);
Fixture fixture = MainBody.CreateFixture(polygonShape);
Parts.Add(fixture);
}
}
public BreakableBody(IEnumerable<Shape> shapes, World world)
{
_world = world;
_world.ContactManager.PostSolve += PostSolve;
MainBody = new Body(_world);
MainBody.BodyType = BodyType.Dynamic;
foreach (Shape part in shapes)
{
Fixture fixture = MainBody.CreateFixture(part);
Parts.Add(fixture);
}
}
public bool Broken;
public Body MainBody;
public List<Fixture> Parts = new List<Fixture>(8);
/// <summary>
/// The force needed to break the body apart.
/// Default: 500
/// </summary>
public float Strength = 500.0f;
private void PostSolve(Contact contact, ContactVelocityConstraint impulse)
{
if (!Broken)
{
if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))
{
float maxImpulse = 0.0f;
int count = contact.Manifold.PointCount;
for (int i = 0; i < count; ++i)
{
maxImpulse = Math.Max(maxImpulse, impulse.points[i].normalImpulse);
}
if (maxImpulse > Strength)
{
// Flag the body for breaking.
_break = true;
}
}
}
}
public void Update()
{
if (_break)
{
Decompose();
Broken = true;
_break = false;
}
// Cache velocities to improve movement on breakage.
if (Broken == false)
{
//Enlarge the cache if needed
if (Parts.Count > _angularVelocitiesCache.Length)
{
_velocitiesCache = new Vector2[Parts.Count];
_angularVelocitiesCache = new float[Parts.Count];
}
//Cache the linear and angular velocities.
for (int i = 0; i < Parts.Count; i++)
{
_velocitiesCache[i] = Parts[i].Body.LinearVelocity;
_angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;
}
}
}
private void Decompose()
{
//Unsubsribe from the PostSolve delegate
_world.ContactManager.PostSolve -= PostSolve;
for (int i = 0; i < Parts.Count; i++)
{
Fixture oldFixture = Parts[i];
Shape shape = oldFixture.Shape.Clone();
object userData = oldFixture.UserData;
MainBody.DestroyFixture(oldFixture);
Body body = BodyFactory.CreateBody(_world);
body.BodyType = BodyType.Dynamic;
body.Position = MainBody.Position;
body.Rotation = MainBody.Rotation;
body.UserData = MainBody.UserData;
Fixture newFixture = body.CreateFixture(shape);
newFixture.UserData = userData;
Parts[i] = newFixture;
body.AngularVelocity = _angularVelocitiesCache[i];
body.LinearVelocity = _velocitiesCache[i];
}
_world.RemoveBody(MainBody);
_world.RemoveBreakableBody(this);
}
public void Break()
{
_break = true;
}
}
}
@@ -0,0 +1,76 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
* Original source Box2D:
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* 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.Dynamics.Contacts;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
[Flags]
public enum Category
{
None = 0x00000000,
Cat1 = 0x00000001,
Cat2 = 0x00000002,
Cat3 = 0x00000004,
Cat4 = 0x00000008,
Cat5 = 0x00000010,
Cat6 = 0x00000020,
Cat7 = 0x00000040,
Cat8 = 0x00000080,
Cat9 = 0x00000100,
Cat10 = 0x00000200,
Cat11 = 0x00000400,
Cat12 = 0x00000800,
Cat13 = 0x00001000,
Cat14 = 0x00002000,
Cat15 = 0x00004000,
Cat16 = 0x00008000,
Cat17 = 0x00010000,
Cat18 = 0x00020000,
Cat19 = 0x00040000,
Cat20 = 0x00080000,
Cat21 = 0x00100000,
Cat22 = 0x00200000,
Cat23 = 0x00400000,
Cat24 = 0x00800000,
Cat25 = 0x01000000,
Cat26 = 0x02000000,
Cat27 = 0x04000000,
Cat28 = 0x08000000,
Cat29 = 0x10000000,
Cat30 = 0x20000000,
Cat31 = 0x40000000,
All = int.MaxValue,
}
}
@@ -1,4 +1,11 @@
/*
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -19,7 +26,6 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//#define USE_ACTIVE_CONTACT_SET
using System.Collections.Generic;
using FarseerPhysics.Collision;
@@ -29,6 +35,33 @@ namespace FarseerPhysics.Dynamics
{
public class ContactManager
{
#region Settings
/// <summary>
/// A threshold for activating multiple cores to solve VelocityConstraints.
/// An Island with a contact count above this threshold will use multiple threads to solve VelocityConstraints.
/// A value of 0 will always use multithreading. A value of (int.MaxValue) will never use multithreading.
/// Typical values are {128 or 256}.
/// </summary>
public int VelocityConstraintsMultithreadThreshold = 128;
/// <summary>
/// A threshold for activating multiple cores to solve PositionConstraints.
/// An Island with a contact count above this threshold will use multiple threads to solve PositionConstraints.
/// A value of 0 will always use multithreading. A value of (int.MaxValue) will never use multithreading.
/// Typical values are {128 or 256}.
/// </summary>
public int PositionConstraintsMultithreadThreshold = 128;
/// <summary>
/// A threshold for activating multiple cores to solve Collide.
/// An World with a contact count above this threshold will use multiple threads to solve Collide.
/// A value of 0 will always use multithreading. A value of (int.MaxValue) will never use multithreading.
/// Typical values are {128 or 256}.
/// </summary>
public int CollideMultithreadThreshold = 64;
#endregion
/// <summary>
/// Fires when a contact is created
/// </summary>
@@ -36,12 +69,15 @@ namespace FarseerPhysics.Dynamics
public IBroadPhase BroadPhase;
public readonly ContactListHead ContactList;
public int ContactCount { get; private set; }
internal readonly ContactListHead _contactPoolList;
/// <summary>
/// The filter used by the contact manager.
/// </summary>
public CollisionFilterDelegate ContactFilter;
public List<Contact> ContactList = new List<Contact>(256);
#if USE_ACTIVE_CONTACT_SET
/// <summary>
@@ -79,21 +115,22 @@ namespace FarseerPhysics.Dynamics
internal ContactManager(IBroadPhase broadPhase)
{
ContactList = new ContactListHead();
ContactCount = 0;
_contactPoolList = new ContactListHead();
BroadPhase = broadPhase;
OnBroadphaseCollision = AddPair;
}
// Broad-phase callback.
private void AddPair(ref FixtureProxy proxyA, ref FixtureProxy proxyB)
private void AddPair(int proxyIdA, int proxyIdB)
{
Fixture fixtureA = proxyA.Fixture;
Fixture fixtureB = proxyB.Fixture;
FixtureProxy proxyA = BroadPhase.GetProxy(proxyIdA);
FixtureProxy proxyB = BroadPhase.GetProxy(proxyIdB);
int indexA = proxyA.ChildIndex;
int indexB = proxyB.ChildIndex;
Body bodyA = fixtureA.Body;
Body bodyB = fixtureB.Body;
Body bodyA = proxyA.Body;
Body bodyB = proxyB.Body;
// Are the fixtures on the same body?
if (bodyA == bodyB)
@@ -101,16 +138,21 @@ namespace FarseerPhysics.Dynamics
return;
}
Fixture fixtureA = proxyA.Fixture;
Fixture fixtureB = proxyB.Fixture;
int indexA = proxyA.ChildIndex;
int indexB = proxyB.ChildIndex;
// Does a contact already exist?
ContactEdge edge = bodyB.ContactList;
while (edge != null)
for (ContactEdge ceB = bodyB.ContactList; ceB != null; ceB = ceB.Next)
{
if (edge.Other == bodyA)
if (ceB.Other == bodyA)
{
Fixture fA = edge.Contact.FixtureA;
Fixture fB = edge.Contact.FixtureB;
int iA = edge.Contact.ChildIndexA;
int iB = edge.Contact.ChildIndexB;
Fixture fA = ceB.Contact.FixtureA;
Fixture fB = ceB.Contact.FixtureB;
int iA = ceB.Contact.ChildIndexA;
int iB = ceB.Contact.ChildIndexB;
if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB)
{
@@ -124,8 +166,6 @@ namespace FarseerPhysics.Dynamics
return;
}
}
edge = edge.Next;
}
// Does a joint override collision? Is at least one body dynamic?
@@ -148,7 +188,7 @@ namespace FarseerPhysics.Dynamics
return;
// Call the factory.
Contact c = Contact.Create(fixtureA, indexA, fixtureB, indexB);
Contact c = Contact.Create(this, fixtureA, indexA, fixtureB, indexB);
if (c == null)
return;
@@ -160,7 +200,11 @@ namespace FarseerPhysics.Dynamics
bodyB = fixtureB.Body;
// Insert into the world.
ContactList.Add(c);
c.Prev = ContactList;
c.Next = c.Prev.Next;
c.Prev.Next = c;
c.Next.Prev = c;
ContactCount++;
#if USE_ACTIVE_CONTACT_SET
ActiveContacts.Add(c);
@@ -215,73 +259,79 @@ namespace FarseerPhysics.Dynamics
{
//Report the separation to both participants:
if (fixtureA != null && fixtureA.OnSeparation != null)
fixtureA.OnSeparation(fixtureA, fixtureB);
fixtureA.OnSeparation(fixtureA, fixtureB, contact);
//Reverse the order of the reported fixtures. The first fixture is always the one that the
//user subscribed to.
if (fixtureB != null && fixtureB.OnSeparation != null)
fixtureB.OnSeparation(fixtureB, fixtureA);
fixtureB.OnSeparation(fixtureB, fixtureA, contact);
//Report the separation to both bodies:
if (fixtureA != null && fixtureA.Body != null && fixtureA.Body.onSeparationEventHandler != null)
fixtureA.Body.onSeparationEventHandler(fixtureA, fixtureB, contact);
//Reverse the order of the reported fixtures. The first fixture is always the one that the
//user subscribed to.
if (fixtureB != null && fixtureB.Body != null && fixtureB.Body.onSeparationEventHandler != null)
fixtureB.Body.onSeparationEventHandler(fixtureB, fixtureA, contact);
if (EndContact != null)
EndContact(contact);
}
// Remove from the world.
ContactList.Remove(contact);
contact.Prev.Next = contact.Next;
contact.Next.Prev = contact.Prev;
contact.Next = null;
contact.Prev = null;
ContactCount--;
// Remove from body 1
if (contact._nodeA.Prev != null)
{
contact._nodeA.Prev.Next = contact._nodeA.Next;
}
if (contact._nodeA.Next != null)
{
contact._nodeA.Next.Prev = contact._nodeA.Prev;
}
if (contact._nodeA == bodyA.ContactList)
{
bodyA.ContactList = contact._nodeA.Next;
}
if (contact._nodeA.Prev != null)
contact._nodeA.Prev.Next = contact._nodeA.Next;
if (contact._nodeA.Next != null)
contact._nodeA.Next.Prev = contact._nodeA.Prev;
// Remove from body 2
if (contact._nodeB.Prev != null)
{
contact._nodeB.Prev.Next = contact._nodeB.Next;
}
if (contact._nodeB.Next != null)
{
contact._nodeB.Next.Prev = contact._nodeB.Prev;
}
if (contact._nodeB == bodyB.ContactList)
{
bodyB.ContactList = contact._nodeB.Next;
}
if (contact._nodeB.Prev != null)
contact._nodeB.Prev.Next = contact._nodeB.Next;
if (contact._nodeB.Next != null)
contact._nodeB.Next.Prev = contact._nodeB.Prev;
#if USE_ACTIVE_CONTACT_SET
if (ActiveContacts.Contains(contact))
{
ActiveContacts.Remove(contact);
}
#endif
contact.Destroy();
// Insert into the pool.
contact.Next = _contactPoolList.Next;
_contactPoolList.Next = contact;
}
internal void Collide()
{
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
if (this.ContactCount > CollideMultithreadThreshold && System.Environment.ProcessorCount > 1)
{
CollideMultiCore();
return;
}
#endif
// Update awake contacts.
#if USE_ACTIVE_CONTACT_SET
ActiveList.AddRange(ActiveContacts);
foreach (var c in ActiveList)
{
#else
for (int i = 0; i < ContactList.Count; i++)
ActiveList.AddRange(ActiveContacts);
foreach (var tmpc in ActiveList)
{
Contact c = tmpc;
#else
for (Contact c = ContactList.Next; c != ContactList;)
{
Contact c = ContactList[i];
#endif
Fixture fixtureA = c.FixtureA;
Fixture fixtureB = c.FixtureB;
@@ -292,7 +342,10 @@ namespace FarseerPhysics.Dynamics
//Do no try to collide disabled bodies
if (!bodyA.Enabled || !bodyB.Enabled)
{
c = c.Next;
continue;
}
// Is this contact flagged for filtering?
if (c.FilterFlag)
@@ -301,6 +354,7 @@ namespace FarseerPhysics.Dynamics
if (bodyB.ShouldCollide(bodyA) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
@@ -309,6 +363,7 @@ namespace FarseerPhysics.Dynamics
if (ShouldCollide(fixtureA, fixtureB) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
@@ -317,6 +372,7 @@ namespace FarseerPhysics.Dynamics
if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
@@ -334,6 +390,7 @@ namespace FarseerPhysics.Dynamics
#if USE_ACTIVE_CONTACT_SET
ActiveContacts.Remove(c);
#endif
c = c.Next;
continue;
}
@@ -346,12 +403,15 @@ namespace FarseerPhysics.Dynamics
if (overlap == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
// The contact persists.
c.Update(this);
c = c.Next;
}
#if USE_ACTIVE_CONTACT_SET
@@ -359,87 +419,196 @@ namespace FarseerPhysics.Dynamics
#endif
}
/// <summary>
/// A temporary list of contacts to be updated during Collide().
/// </summary>
List<Contact> updateList = new List<Contact>();
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
internal void CollideMultiCore()
{
int lockOrder = 0;
// Update awake contacts.
#if USE_ACTIVE_CONTACT_SET
ActiveList.AddRange(ActiveContacts);
foreach (var tmpc in ActiveList)
{
Contact c = tmpc;
#else
for (Contact c = ContactList.Next; c != ContactList; )
{
#endif
Fixture fixtureA = c.FixtureA;
Fixture fixtureB = c.FixtureB;
int indexA = c.ChildIndexA;
int indexB = c.ChildIndexB;
Body bodyA = fixtureA.Body;
Body bodyB = fixtureB.Body;
//Do no try to collide disabled bodies
if (!bodyA.Enabled || !bodyB.Enabled)
{
c = c.Next;
continue;
}
// Is this contact flagged for filtering?
if (c.FilterFlag)
{
// Should these bodies collide?
if (bodyB.ShouldCollide(bodyA) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
// Check default filtering
if (ShouldCollide(fixtureA, fixtureB) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
// Check user filtering.
if (ContactFilter != null && ContactFilter(fixtureA, fixtureB) == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
// Clear the filtering flag.
c.FilterFlag = false;
}
bool activeA = bodyA.Awake && bodyA.BodyType != BodyType.Static;
bool activeB = bodyB.Awake && bodyB.BodyType != BodyType.Static;
// At least one body must be awake and it must be dynamic or kinematic.
if (activeA == false && activeB == false)
{
#if USE_ACTIVE_CONTACT_SET
ActiveContacts.Remove(c);
#endif
c = c.Next;
continue;
}
int proxyIdA = fixtureA.Proxies[indexA].ProxyId;
int proxyIdB = fixtureB.Proxies[indexB].ProxyId;
bool overlap = BroadPhase.TestOverlap(proxyIdA, proxyIdB);
// Here we destroy contacts that cease to overlap in the broad-phase.
if (overlap == false)
{
Contact cNuke = c;
c = c.Next;
Destroy(cNuke);
continue;
}
// The contact persists.
updateList.Add(c);
// Assign a unique id for lock order
bodyA._lockOrder = lockOrder++;
bodyB._lockOrder = lockOrder++;
c = c.Next;
}
#if USE_ACTIVE_CONTACT_SET
ActiveList.Clear();
#endif
// update contacts
System.Threading.Tasks.Parallel.ForEach<Contact>(updateList, (c) =>
{
// find lower order item
Fixture fixtureA = c.FixtureA;
Fixture fixtureB = c.FixtureB;
// find lower order item
Body orderedBodyA = fixtureA.Body;
Body orderedBodyB = fixtureB.Body;
int idA = orderedBodyA._lockOrder;
int idB = orderedBodyB._lockOrder;
if (idA == idB)
throw new System.Exception();
if (idA > idB)
{
orderedBodyA = fixtureB.Body;
orderedBodyB = fixtureA.Body;
}
// obtain lock
for (; ; )
{
if (System.Threading.Interlocked.CompareExchange(ref orderedBodyA._lock, 1, 0) == 0)
{
if (System.Threading.Interlocked.CompareExchange(ref orderedBodyB._lock, 1, 0) == 0)
break;
System.Threading.Interlocked.Exchange(ref orderedBodyA._lock, 0);
}
#if NET40 || NET45
System.Threading.Thread.Sleep(0);
#endif
}
c.Update(this);
System.Threading.Interlocked.Exchange(ref orderedBodyB._lock, 0);
System.Threading.Interlocked.Exchange(ref orderedBodyA._lock, 0);
});
updateList.Clear();
}
#endif
private static bool ShouldCollide(Fixture fixtureA, Fixture fixtureB)
{
if (Settings.UseFPECollisionCategories)
if (fixtureA.CollisionGroup != 0 && fixtureA.CollisionGroup == fixtureB.CollisionGroup)
{
if ((fixtureA.CollisionGroup == fixtureB.CollisionGroup) &&
fixtureA.CollisionGroup != 0 && fixtureB.CollisionGroup != 0)
return false;
if (((fixtureA.CollisionCategories & fixtureB.CollidesWith) ==
Category.None) &
((fixtureB.CollisionCategories & fixtureA.CollidesWith) ==
Category.None))
return false;
if (fixtureA.IsFixtureIgnored(fixtureB) ||
fixtureB.IsFixtureIgnored(fixtureA))
return false;
return true;
return (fixtureA.CollisionGroup > 0);
}
if (fixtureA.CollisionGroup == fixtureB.CollisionGroup &&
fixtureA.CollisionGroup != 0)
{
return fixtureA.CollisionGroup > 0;
}
bool collide = (fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0 &&
(fixtureA.CollisionCategories & fixtureB.CollidesWith) != 0;
if (collide)
{
if (fixtureA.IsFixtureIgnored(fixtureB) ||
fixtureB.IsFixtureIgnored(fixtureA))
{
return false;
}
}
bool collide = ((fixtureA.CollidesWith & fixtureB.CollisionCategories) != 0) &&
((fixtureB.CollidesWith & fixtureA.CollisionCategories) != 0);
return collide;
}
internal void UpdateContacts(ContactEdge contactEdge, bool value)
#if USE_ACTIVE_CONTACT_SET
internal void UpdateActiveContacts(ContactEdge ContactList, bool value)
{
#if USE_ACTIVE_CONTACT_SET
if(value)
{
while(contactEdge != null)
{
var c = contactEdge.Contact;
if (!ActiveContacts.Contains(c))
{
ActiveContacts.Add(c);
}
contactEdge = contactEdge.Next;
}
}
else
{
while (contactEdge != null)
{
var c = contactEdge.Contact;
if (!contactEdge.Other.Awake)
{
if (ActiveContacts.Contains(c))
{
ActiveContacts.Remove(c);
}
}
contactEdge = contactEdge.Next;
}
}
#endif
if(value)
{
for (var contactEdge = ContactList; contactEdge != null; contactEdge = contactEdge.Next)
{
if (!ActiveContacts.Contains(contactEdge.Contact))
ActiveContacts.Add(contactEdge.Contact);
}
}
else
{
for (var contactEdge = ContactList; contactEdge != null; contactEdge = contactEdge.Next)
{
if (!contactEdge.Other.Awake)
{
if (ActiveContacts.Contains(contactEdge.Contact))
ActiveContacts.Remove(contactEdge.Contact);
}
}
}
}
#if USE_ACTIVE_CONTACT_SET
internal void RemoveActiveContact(Contact contact)
{
if (ActiveContacts.Contains(contact))
ActiveContacts.Remove(contact);
}
#endif
}
}
@@ -1,3 +1,10 @@
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -19,7 +26,6 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//#define USE_ACTIVE_CONTACT_SET
using System.Collections.Generic;
using System.Diagnostics;
@@ -42,22 +48,22 @@ namespace FarseerPhysics.Dynamics.Contacts
/// <summary>
/// The contact
/// </summary>
public Contact Contact;
/// <summary>
/// The next contact edge in the body's contact list
/// </summary>
public ContactEdge Next;
public Contact Contact { get; internal set; }
/// <summary>
/// Provides quick access to the other body attached.
/// </summary>
public Body Other;
public Body Other { get; internal set; }
/// <summary>
/// The next contact edge in the body's contact list
/// </summary>
public ContactEdge Next { get; internal set; }
/// <summary>
/// The previous contact edge in the body's contact list
/// </summary>
public ContactEdge Prev;
public ContactEdge Prev { get; internal set; }
}
/// <summary>
@@ -108,8 +114,9 @@ namespace FarseerPhysics.Dynamics.Contacts
internal int _toiCount;
internal float _toi;
public Fixture FixtureA;
public Fixture FixtureB;
public Fixture FixtureA { get; internal set; }
public Fixture FixtureB { get; internal set; }
public float Friction { get; set; }
public float Restitution { get; set; }
@@ -142,6 +149,18 @@ namespace FarseerPhysics.Dynamics.Contacts
/// <value>The child index B.</value>
public int ChildIndexB { get; internal set; }
/// <summary>
/// Get the next contact in the world's contact list.
/// </summary>
/// <value>The next.</value>
public Contact Next { get; internal set; }
/// <summary>
/// Get the previous contact in the world's contact list.
/// </summary>
/// <value>The prev.</value>
public Contact Prev { get; internal set; }
/// <summary>
/// Determines whether this contact is touching.
/// </summary>
@@ -164,7 +183,7 @@ namespace FarseerPhysics.Dynamics.Contacts
Friction = Settings.MixFriction(FixtureA.Friction, FixtureB.Friction);
}
private Contact(Fixture fA, int indexA, Fixture fB, int indexB)
protected Contact(Fixture fA, int indexA, Fixture fB, int indexB)
{
Reset(fA, indexA, fB, indexB);
}
@@ -198,15 +217,18 @@ namespace FarseerPhysics.Dynamics.Contacts
Manifold.PointCount = 0;
Next = null;
Prev = null;
_nodeA.Contact = null;
_nodeA.Prev = null;
_nodeA.Next = null;
_nodeA.Other = null;
_nodeA.Next = null;
_nodeA.Prev = null;
_nodeB.Contact = null;
_nodeB.Prev = null;
_nodeB.Next = null;
_nodeB.Other = null;
_nodeB.Next = null;
_nodeB.Prev = null;
_toiCount = 0;
@@ -295,45 +317,37 @@ namespace FarseerPhysics.Dynamics.Contacts
{
if (touching)
{
if (Settings.AllCollisionCallbacksAgree)
{
bool enabledA = true, enabledB = true;
bool enabledA = true, enabledB = true;
// Report the collision to both participants. Track which ones returned true so we can
// later call OnSeparation if the contact is disabled for a different reason.
if (FixtureA.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
enabledA = handler(FixtureA, FixtureB, this) && enabledA;
// Report the collision to both participants. Track which ones returned true so we can
// later call OnSeparation if the contact is disabled for a different reason.
if (FixtureA.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
enabledA = handler(FixtureA, FixtureB, this) && enabledA;
// Reverse the order of the reported fixtures. The first fixture is always the one that the
// user subscribed to.
if (FixtureB.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureB.OnCollision.GetInvocationList())
enabledB = handler(FixtureB, FixtureA, this) && enabledB;
// Reverse the order of the reported fixtures. The first fixture is always the one that the
// user subscribed to.
if (FixtureB.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureB.OnCollision.GetInvocationList())
enabledB = handler(FixtureB, FixtureA, this) && enabledB;
Enabled = enabledA && enabledB;
// Report the collision to both bodies:
if (FixtureA.Body != null && FixtureA.Body.onCollisionEventHandler != null)
foreach (OnCollisionEventHandler handler in FixtureA.Body.onCollisionEventHandler.GetInvocationList())
enabledA = handler(FixtureA, FixtureB, this) && enabledA;
// BeginContact can also return false and disable the contact
if (enabledA && enabledB && contactManager.BeginContact != null)
Enabled = contactManager.BeginContact(this);
}
else
{
//Report the collision to both participants:
if (FixtureA.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureA.OnCollision.GetInvocationList())
Enabled = handler(FixtureA, FixtureB, this);
// Reverse the order of the reported fixtures. The first fixture is always the one that the
// user subscribed to.
if (FixtureB.Body != null && FixtureB.Body.onCollisionEventHandler != null)
foreach (OnCollisionEventHandler handler in FixtureB.Body.onCollisionEventHandler.GetInvocationList())
enabledB = handler(FixtureB, FixtureA, this) && enabledB;
//Reverse the order of the reported fixtures. The first fixture is always the one that the
//user subscribed to.
if (FixtureB.OnCollision != null)
foreach (OnCollisionEventHandler handler in FixtureB.OnCollision.GetInvocationList())
Enabled = handler(FixtureB, FixtureA, this);
//BeginContact can also return false and disable the contact
if (contactManager.BeginContact != null)
Enabled = contactManager.BeginContact(this);
}
Enabled = enabledA && enabledB;
// BeginContact can also return false and disable the contact
if (enabledA && enabledB && contactManager.BeginContact != null)
Enabled = contactManager.BeginContact(this);
// If the user disabled the contact (needed to exclude it in TOI solver) at any point by
// any of the callbacks, we need to mark it as not touching and call any separation
@@ -348,12 +362,22 @@ namespace FarseerPhysics.Dynamics.Contacts
{
//Report the separation to both participants:
if (FixtureA != null && FixtureA.OnSeparation != null)
FixtureA.OnSeparation(FixtureA, FixtureB);
FixtureA.OnSeparation(FixtureA, FixtureB, this);
//Reverse the order of the reported fixtures. The first fixture is always the one that the
//user subscribed to.
if (FixtureB != null && FixtureB.OnSeparation != null)
FixtureB.OnSeparation(FixtureB, FixtureA);
FixtureB.OnSeparation(FixtureB, FixtureA, this);
//Report the separation to both bodies:
if (FixtureA != null && FixtureA.Body != null && FixtureA.Body.onSeparationEventHandler != null)
FixtureA.Body.onSeparationEventHandler(FixtureA, FixtureB, this);
//Reverse the order of the reported fixtures. The first fixture is always the one that the
//user subscribed to.
if (FixtureB != null && FixtureB.Body != null && FixtureB.Body.onSeparationEventHandler != null)
FixtureB.Body.onSeparationEventHandler(FixtureB, FixtureA, this);
if (contactManager.EndContact != null)
contactManager.EndContact(this);
@@ -405,7 +429,7 @@ namespace FarseerPhysics.Dynamics.Contacts
}
}
internal static Contact Create(Fixture fixtureA, int indexA, Fixture fixtureB, int indexB)
internal static Contact Create(ContactManager contactManager, Fixture fixtureA, int indexA, Fixture fixtureB, int indexB)
{
ShapeType type1 = fixtureA.Shape.ShapeType;
ShapeType type2 = fixtureB.Shape.ShapeType;
@@ -413,32 +437,32 @@ namespace FarseerPhysics.Dynamics.Contacts
Debug.Assert(ShapeType.Unknown < type1 && type1 < ShapeType.TypeCount);
Debug.Assert(ShapeType.Unknown < type2 && type2 < ShapeType.TypeCount);
Contact c;
Queue<Contact> pool = fixtureA.Body._world._contactPool;
if (pool.Count > 0)
Contact c = null;
var contactPoolList = contactManager._contactPoolList;
if (contactPoolList.Next != contactPoolList)
{
// get first item in the pool.
c = contactPoolList.Next;
// Remove from the pool.
contactPoolList.Next = c.Next;
c.Next = null;
}
// Edge+Polygon is non-symetrical due to the way Erin handles collision type registration.
if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))
{
c = pool.Dequeue();
if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))
{
c.Reset(fixtureA, indexA, fixtureB, indexB);
}
if (c == null)
c = new Contact(fixtureA, indexA, fixtureB, indexB);
else
{
c.Reset(fixtureB, indexB, fixtureA, indexA);
}
c.Reset(fixtureA, indexA, fixtureB, indexB);
}
else
{
// Edge+Polygon is non-symetrical due to the way Erin handles collision type registration.
if ((type1 >= type2 || (type1 == ShapeType.Edge && type2 == ShapeType.Polygon)) && !(type2 == ShapeType.Edge && type1 == ShapeType.Polygon))
{
c = new Contact(fixtureA, indexA, fixtureB, indexB);
}
else
{
if (c == null)
c = new Contact(fixtureB, indexB, fixtureA, indexA);
}
else
c.Reset(fixtureB, indexB, fixtureA, indexA);
}
c._type = _registers[(int)type1, (int)type2];
@@ -447,11 +471,6 @@ namespace FarseerPhysics.Dynamics.Contacts
internal void Destroy()
{
#if USE_ACTIVE_CONTACT_SET
FixtureA.Body.World.ContactManager.RemoveActiveContact(this);
#endif
FixtureA.Body._world._contactPool.Enqueue(this);
if (Manifold.PointCount > 0 && FixtureA.IsSensor == false && FixtureB.IsSensor == false)
{
FixtureA.Body.Awake = true;
@@ -0,0 +1,69 @@
// Copyright (c) 2017 Kastellanos Nikolaos
using System;
using System.Collections;
using System.Collections.Generic;
namespace FarseerPhysics.Dynamics.Contacts
{
/// <summary>
/// Head of a circular doubly linked list.
/// </summary>
public class ContactListHead : Contact , IEnumerable<Contact>
{
internal ContactListHead(): base(null, 0, null, 0)
{
this.Prev = this;
this.Next = this;
}
IEnumerator<Contact> IEnumerable<Contact>.GetEnumerator()
{
return new ContactEnumerator(this);
}
IEnumerator IEnumerable.GetEnumerator()
{
return new ContactEnumerator(this);
}
#region Nested type: ContactEnumerator
private struct ContactEnumerator : IEnumerator<Contact>
{
private ContactListHead _head;
private Contact _current;
public Contact Current { get { return _current; } }
object IEnumerator.Current { get { return _current; } }
public ContactEnumerator(ContactListHead contact)
{
_head = contact;
_current = _head;
}
public void Reset()
{
_current = _head;
}
public bool MoveNext()
{
_current = _current.Next;
return (_current != _head);
}
public void Dispose()
{
_head = null;
_current = null;
}
}
#endregion
}
}
@@ -1,3 +1,10 @@
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -25,7 +32,12 @@ using System.Diagnostics;
using FarseerPhysics.Collision;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
using System.Threading;
using System.Threading.Tasks;
#endif
namespace FarseerPhysics.Dynamics.Contacts
{
@@ -82,21 +94,24 @@ namespace FarseerPhysics.Dynamics.Contacts
public class ContactSolver
{
public TimeStep _step;
public Position[] _positions;
public Velocity[] _velocities;
public ContactPositionConstraint[] _positionConstraints;
public ContactVelocityConstraint[] _velocityConstraints;
public Contact[] _contacts;
public int _count;
int _velocityConstraintsMultithreadThreshold;
int _positionConstraintsMultithreadThreshold;
public void Reset(TimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities, bool warmstarting = Settings.EnableWarmstarting)
public void Reset(ref TimeStep step, int count, Contact[] contacts, Position[] positions, Velocity[] velocities,
int velocityConstraintsMultithreadThreshold, int positionConstraintsMultithreadThreshold)
{
_step = step;
_count = count;
_positions = positions;
_velocities = velocities;
_contacts = contacts;
_velocityConstraintsMultithreadThreshold = velocityConstraintsMultithreadThreshold;
_positionConstraintsMultithreadThreshold = positionConstraintsMultithreadThreshold;
// grow the array
if (_velocityConstraints == null || _velocityConstraints.Length < count)
@@ -169,10 +184,10 @@ namespace FarseerPhysics.Dynamics.Contacts
ManifoldPoint cp = manifold.Points[j];
VelocityConstraintPoint vcp = vc.points[j];
if (Settings.EnableWarmstarting)
if (step.warmStarting)
{
vcp.normalImpulse = _step.dtRatio * cp.NormalImpulse;
vcp.tangentImpulse = _step.dtRatio * cp.TangentImpulse;
vcp.normalImpulse = step.dtRatio * cp.NormalImpulse;
vcp.tangentImpulse = step.dtRatio * cp.TangentImpulse;
}
else
{
@@ -224,18 +239,17 @@ namespace FarseerPhysics.Dynamics.Contacts
Debug.Assert(manifold.PointCount > 0);
Transform xfA = new Transform();
Transform xfB = new Transform();
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
Transform xfA = new Transform(Vector2.Zero, aA);
Transform xfB = new Transform(Vector2.Zero, aB);
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
Vector2 normal;
FixedArray2<Vector2> points;
WorldManifold.Initialize(ref manifold, ref xfA, radiusA, ref xfB, radiusB, out normal, out points);
vc.normal = normal;
Vector2 tangent = MathUtils.Rot270(ref vc.normal);
int pointCount = vc.pointCount;
for (int j = 0; j < pointCount; ++j)
@@ -245,17 +259,16 @@ namespace FarseerPhysics.Dynamics.Contacts
vcp.rA = points[j] - cA;
vcp.rB = points[j] - cB;
float rnA = MathUtils.Cross(vcp.rA, vc.normal);
float rnB = MathUtils.Cross(vcp.rB, vc.normal);
float rnA = MathUtils.Cross(ref vcp.rA, ref vc.normal);
float rnB = MathUtils.Cross(ref vcp.rB, ref vc.normal);
float kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
vcp.normalMass = kNormal > 0.0f ? 1.0f / kNormal : 0.0f;
Vector2 tangent = MathUtils.Cross(vc.normal, 1.0f);
float rtA = MathUtils.Cross(vcp.rA, tangent);
float rtB = MathUtils.Cross(vcp.rB, tangent);
float rtA = MathUtils.Cross(ref vcp.rA, ref tangent);
float rtB = MathUtils.Cross(ref vcp.rB, ref tangent);
float kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
@@ -263,7 +276,7 @@ namespace FarseerPhysics.Dynamics.Contacts
// Setup a velocity bias for restitution.
vcp.velocityBias = 0.0f;
float vRel = Vector2.Dot(vc.normal, vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA));
float vRel = Vector2.Dot(vc.normal, vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA));
if (vRel < -Settings.VelocityThreshold)
{
vcp.velocityBias = -vc.restitution * vRel;
@@ -276,10 +289,10 @@ namespace FarseerPhysics.Dynamics.Contacts
VelocityConstraintPoint vcp1 = vc.points[0];
VelocityConstraintPoint vcp2 = vc.points[1];
float rn1A = MathUtils.Cross(vcp1.rA, vc.normal);
float rn1B = MathUtils.Cross(vcp1.rB, vc.normal);
float rn2A = MathUtils.Cross(vcp2.rA, vc.normal);
float rn2B = MathUtils.Cross(vcp2.rB, vc.normal);
float rn1A = MathUtils.Cross(ref vcp1.rA, ref vc.normal);
float rn1B = MathUtils.Cross(ref vcp1.rB, ref vc.normal);
float rn2A = MathUtils.Cross(ref vcp2.rA, ref vc.normal);
float rn2B = MathUtils.Cross(ref vcp2.rB, ref vc.normal);
float k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
float k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
@@ -325,15 +338,15 @@ namespace FarseerPhysics.Dynamics.Contacts
float wB = _velocities[indexB].w;
Vector2 normal = vc.normal;
Vector2 tangent = MathUtils.Cross(normal, 1.0f);
Vector2 tangent = MathUtils.Rot270(ref normal);
for (int j = 0; j < pointCount; ++j)
{
VelocityConstraintPoint vcp = vc.points[j];
Vector2 P = vcp.normalImpulse * normal + vcp.tangentImpulse * tangent;
wA -= iA * MathUtils.Cross(vcp.rA, P);
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
vA -= mA * P;
wB += iB * MathUtils.Cross(vcp.rB, P);
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
vB += mB * P;
}
@@ -346,10 +359,115 @@ namespace FarseerPhysics.Dynamics.Contacts
public void SolveVelocityConstraints()
{
for (int i = 0; i < _count; ++i)
if (_count >= _velocityConstraintsMultithreadThreshold && System.Environment.ProcessorCount > 1)
{
if (_count == 0) return;
var batchSize = (int)Math.Ceiling((float)_count / System.Environment.ProcessorCount);
var batches = (int)Math.Ceiling((float)_count / batchSize);
#if NET40 || NET45
SolveVelocityConstraintsWaitLock.Reset(batches);
for (int i = 0; i < batches; i++)
{
var start = i * batchSize;
var end = Math.Min(start + batchSize, _count);
ThreadPool.QueueUserWorkItem( SolveVelocityConstraintsCallback, SolveVelocityConstraintsState.Get(this, start,end));
}
// We avoid SolveVelocityConstraintsWaitLock.Wait(); because it spins a few milliseconds before going into sleep. Going into sleep(0) directly in a while loop is faster.
while (SolveVelocityConstraintsWaitLock.CurrentCount > 0)
Thread.Sleep(0);
#elif PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
Parallel.For(0, batches, (i) =>
{
var start = i * batchSize;
var end = Math.Min(start + batchSize, _count);
SolveVelocityConstraints(start, end);
});
#else
SolveVelocityConstraints(0, _count);
#endif
}
else
{
SolveVelocityConstraints(0, _count);
}
return;
}
#if NET40 || NET45
CountdownEvent SolveVelocityConstraintsWaitLock = new CountdownEvent(0);
static void SolveVelocityConstraintsCallback(object state)
{
var svcState = (SolveVelocityConstraintsState)state;
svcState.ContactSolver.SolveVelocityConstraints(svcState.Start, svcState.End);
SolveVelocityConstraintsState.Return(svcState);
svcState.ContactSolver.SolveVelocityConstraintsWaitLock.Signal();
}
private class SolveVelocityConstraintsState
{
private static System.Collections.Concurrent.ConcurrentQueue<SolveVelocityConstraintsState> _queue = new System.Collections.Concurrent.ConcurrentQueue<SolveVelocityConstraintsState>(); // pool
public ContactSolver ContactSolver;
public int Start { get; private set; }
public int End { get; private set; }
private SolveVelocityConstraintsState()
{
}
internal static object Get(ContactSolver contactSolver, int start, int end)
{
SolveVelocityConstraintsState result;
if (!_queue.TryDequeue(out result))
result = new SolveVelocityConstraintsState();
result.ContactSolver = contactSolver;
result.Start = start;
result.End = end;
return result;
}
internal static void Return(object state)
{
_queue.Enqueue((SolveVelocityConstraintsState)state);
}
}
#endif
private void SolveVelocityConstraints(int start, int end)
{
for (int i = start; i < end; ++i)
{
ContactVelocityConstraint vc = _velocityConstraints[i];
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
// find lower order item
int orderedIndexA = vc.indexA;
int orderedIndexB = vc.indexB;
if (orderedIndexB < orderedIndexA)
{
orderedIndexA = vc.indexB;
orderedIndexB = vc.indexA;
}
for (; ; )
{
if (Interlocked.CompareExchange(ref _velocities[orderedIndexA].Lock, 1, 0) == 0)
{
if (Interlocked.CompareExchange(ref _velocities[orderedIndexB].Lock, 1, 0) == 0)
break;
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexA].Lock, 0);
}
#if NET40 || NET45
Thread.Sleep(0);
#endif
}
#endif
int indexA = vc.indexA;
int indexB = vc.indexB;
float mA = vc.invMassA;
@@ -364,7 +482,7 @@ namespace FarseerPhysics.Dynamics.Contacts
float wB = _velocities[indexB].w;
Vector2 normal = vc.normal;
Vector2 tangent = MathUtils.Cross(normal, 1.0f);
Vector2 tangent = MathUtils.Rot270(ref normal);
float friction = vc.friction;
Debug.Assert(pointCount == 1 || pointCount == 2);
@@ -376,7 +494,7 @@ namespace FarseerPhysics.Dynamics.Contacts
VelocityConstraintPoint vcp = vc.points[j];
// Relative velocity at contact
Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);
Vector2 dv = vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA);
// Compute tangent force
float vt = Vector2.Dot(dv, tangent) - vc.tangentSpeed;
@@ -392,10 +510,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P = lambda * tangent;
vA -= mA * P;
wA -= iA * MathUtils.Cross(vcp.rA, P);
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
vB += mB * P;
wB += iB * MathUtils.Cross(vcp.rB, P);
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
}
// Solve normal constraints
@@ -404,7 +522,7 @@ namespace FarseerPhysics.Dynamics.Contacts
VelocityConstraintPoint vcp = vc.points[0];
// Relative velocity at contact
Vector2 dv = vB + MathUtils.Cross(wB, vcp.rB) - vA - MathUtils.Cross(wA, vcp.rA);
Vector2 dv = vB + MathUtils.Cross(wB, ref vcp.rB) - vA - MathUtils.Cross(wA, ref vcp.rA);
// Compute normal impulse
float vn = Vector2.Dot(dv, normal);
@@ -418,10 +536,10 @@ namespace FarseerPhysics.Dynamics.Contacts
// Apply contact impulse
Vector2 P = lambda * normal;
vA -= mA * P;
wA -= iA * MathUtils.Cross(vcp.rA, P);
wA -= iA * MathUtils.Cross(ref vcp.rA, ref P);
vB += mB * P;
wB += iB * MathUtils.Cross(vcp.rB, P);
wB += iB * MathUtils.Cross(ref vcp.rB, ref P);
}
else
{
@@ -465,8 +583,8 @@ namespace FarseerPhysics.Dynamics.Contacts
Debug.Assert(a.X >= 0.0f && a.Y >= 0.0f);
// Relative velocity at contact
Vector2 dv1 = vB + MathUtils.Cross(wB, cp1.rB) - vA - MathUtils.Cross(wA, cp1.rA);
Vector2 dv2 = vB + MathUtils.Cross(wB, cp2.rB) - vA - MathUtils.Cross(wA, cp2.rA);
Vector2 dv1 = vB + MathUtils.Cross(wB, ref cp1.rB) - vA - MathUtils.Cross(wA, ref cp1.rA);
Vector2 dv2 = vB + MathUtils.Cross(wB, ref cp2.rB) - vA - MathUtils.Cross(wA, ref cp2.rA);
// Compute normal velocity
float vn1 = Vector2.Dot(dv1, normal);
@@ -477,7 +595,7 @@ namespace FarseerPhysics.Dynamics.Contacts
b.Y = vn2 - cp2.velocityBias;
// Compute b'
b -= MathUtils.Mul(ref vc.K, a);
b -= MathUtils.Mul(ref vc.K, ref a);
const float k_errorTol = 1e-3f;
//B2_NOT_USED(k_errorTol);
@@ -493,7 +611,7 @@ namespace FarseerPhysics.Dynamics.Contacts
//
// x = - inv(A) * b'
//
Vector2 x = -MathUtils.Mul(ref vc.normalMass, b);
Vector2 x = -MathUtils.Mul(ref vc.normalMass, ref b);
if (x.X >= 0.0f && x.Y >= 0.0f)
{
@@ -504,10 +622,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P1 = d.X * normal;
Vector2 P2 = d.Y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
vB += mB * (P1 + P2);
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
// Accumulate
cp1.normalImpulse = x.X;
@@ -548,10 +666,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P1 = d.X * normal;
Vector2 P2 = d.Y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
vB += mB * (P1 + P2);
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
// Accumulate
cp1.normalImpulse = x.X;
@@ -590,10 +708,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P1 = d.X * normal;
Vector2 P2 = d.Y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
vB += mB * (P1 + P2);
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
// Accumulate
cp1.normalImpulse = x.X;
@@ -630,10 +748,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P1 = d.X * normal;
Vector2 P2 = d.Y * normal;
vA -= mA * (P1 + P2);
wA -= iA * (MathUtils.Cross(cp1.rA, P1) + MathUtils.Cross(cp2.rA, P2));
wA -= iA * (MathUtils.Cross(ref cp1.rA, ref P1) + MathUtils.Cross(ref cp2.rA, ref P2));
vB += mB * (P1 + P2);
wB += iB * (MathUtils.Cross(cp1.rB, P1) + MathUtils.Cross(cp2.rB, P2));
wB += iB * (MathUtils.Cross(ref cp1.rB, ref P1) + MathUtils.Cross(ref cp2.rB, ref P2));
// Accumulate
cp1.normalImpulse = x.X;
@@ -651,6 +769,11 @@ namespace FarseerPhysics.Dynamics.Contacts
_velocities[indexA].w = wA;
_velocities[indexB].v = vB;
_velocities[indexB].w = wB;
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexB].Lock, 0);
System.Threading.Interlocked.Exchange(ref _velocities[orderedIndexA].Lock, 0);
#endif
}
}
@@ -674,12 +797,71 @@ namespace FarseerPhysics.Dynamics.Contacts
}
public bool SolvePositionConstraints()
{
bool contactsOkay = false;
if (_count >= _positionConstraintsMultithreadThreshold && System.Environment.ProcessorCount > 1)
{
if (_count == 0) return true;
var batchSize = (int)Math.Ceiling((float)_count / System.Environment.ProcessorCount);
var batches = (int)Math.Ceiling((float)_count / batchSize);
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
Parallel.For(0, batches, (i) =>
{
var start = i * batchSize;
var end = Math.Min(start + batchSize, _count);
var res = SolvePositionConstraints(start, end);
lock (this)
{
contactsOkay = contactsOkay || res;
}
});
#else
contactsOkay = SolvePositionConstraints(0, _count);
#endif
}
else
{
contactsOkay = SolvePositionConstraints(0, _count);
}
return contactsOkay;
}
private bool SolvePositionConstraints(int start, int end)
{
float minSeparation = 0.0f;
for (int i = 0; i < _count; ++i)
for (int i = start; i < end; ++i)
{
ContactPositionConstraint pc = _positionConstraints[i];
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
// Find lower order item.
int orderedIndexA = pc.indexA;
int orderedIndexB = pc.indexB;
if (orderedIndexB < orderedIndexA)
{
orderedIndexA = pc.indexB;
orderedIndexB = pc.indexA;
}
// Lock bodies.
for (; ; )
{
if (Interlocked.CompareExchange(ref _positions[orderedIndexA].Lock, 1, 0) == 0)
{
if (Interlocked.CompareExchange(ref _positions[orderedIndexB].Lock, 1, 0) == 0)
break;
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexA].Lock, 0);
}
#if NET40 || NET45
Thread.Sleep(0);
#endif
}
#endif
int indexA = pc.indexA;
int indexB = pc.indexB;
@@ -693,25 +875,22 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 cA = _positions[indexA].c;
float aA = _positions[indexA].a;
Vector2 cB = _positions[indexB].c;
float aB = _positions[indexB].a;
// Solve normal constraints
for (int j = 0; j < pointCount; ++j)
{
Transform xfA = new Transform();
Transform xfB = new Transform();
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
Transform xfA = new Transform(Vector2.Zero, aA);
Transform xfB = new Transform(Vector2.Zero, aB);
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
Vector2 normal;
Vector2 point;
float separation;
PositionSolverManifold.Initialize(pc, xfA, xfB, j, out normal, out point, out separation);
PositionSolverManifold.Initialize(pc, ref xfA, ref xfB, j, out normal, out point, out separation);
Vector2 rA = point - cA;
Vector2 rB = point - cB;
@@ -723,8 +902,8 @@ namespace FarseerPhysics.Dynamics.Contacts
float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);
// Compute the effective mass.
float rnA = MathUtils.Cross(rA, normal);
float rnB = MathUtils.Cross(rB, normal);
float rnA = MathUtils.Cross(ref rA, ref normal);
float rnB = MathUtils.Cross(ref rB, ref normal);
float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
// Compute normal impulse
@@ -733,17 +912,22 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P = impulse * normal;
cA -= mA * P;
aA -= iA * MathUtils.Cross(rA, P);
aA -= iA * MathUtils.Cross(ref rA, ref P);
cB += mB * P;
aB += iB * MathUtils.Cross(rB, P);
aB += iB * MathUtils.Cross(ref rB, ref P);
}
_positions[indexA].c = cA;
_positions[indexA].a = aA;
_positions[indexB].c = cB;
_positions[indexB].a = aB;
#if NET40 || NET45 || PORTABLE40 || PORTABLE45 || W10 || W8_1 || WP8_1
// Unlock bodies.
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexB].Lock, 0);
System.Threading.Interlocked.Exchange(ref _positions[orderedIndexA].Lock, 0);
#endif
}
// We can't expect minSpeparation >= -b2_linearSlop because we don't
@@ -791,18 +975,16 @@ namespace FarseerPhysics.Dynamics.Contacts
// Solve normal constraints
for (int j = 0; j < pointCount; ++j)
{
Transform xfA = new Transform();
Transform xfB = new Transform();
xfA.q.Set(aA);
xfB.q.Set(aB);
xfA.p = cA - MathUtils.Mul(xfA.q, localCenterA);
xfB.p = cB - MathUtils.Mul(xfB.q, localCenterB);
Transform xfA = new Transform(Vector2.Zero, aA);
Transform xfB = new Transform(Vector2.Zero, aB);
xfA.p = cA - Complex.Multiply(ref localCenterA, ref xfA.q);
xfB.p = cB - Complex.Multiply(ref localCenterB, ref xfB.q);
Vector2 normal;
Vector2 point;
float separation;
PositionSolverManifold.Initialize(pc, xfA, xfB, j, out normal, out point, out separation);
PositionSolverManifold.Initialize(pc, ref xfA, ref xfB, j, out normal, out point, out separation);
Vector2 rA = point - cA;
Vector2 rB = point - cB;
@@ -814,8 +996,8 @@ namespace FarseerPhysics.Dynamics.Contacts
float C = MathUtils.Clamp(Settings.Baumgarte * (separation + Settings.LinearSlop), -Settings.MaxLinearCorrection, 0.0f);
// Compute the effective mass.
float rnA = MathUtils.Cross(rA, normal);
float rnB = MathUtils.Cross(rB, normal);
float rnA = MathUtils.Cross(ref rA, ref normal);
float rnB = MathUtils.Cross(ref rB, ref normal);
float K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
// Compute normal impulse
@@ -824,10 +1006,10 @@ namespace FarseerPhysics.Dynamics.Contacts
Vector2 P = impulse * normal;
cA -= mA * P;
aA -= iA * MathUtils.Cross(rA, P);
aA -= iA * MathUtils.Cross(ref rA, ref P);
cB += mB * P;
aB += iB * MathUtils.Cross(rB, P);
aB += iB * MathUtils.Cross(ref rB, ref P);
}
_positions[indexA].c = cA;
@@ -872,8 +1054,8 @@ namespace FarseerPhysics.Dynamics.Contacts
case ManifoldType.Circles:
{
normal = new Vector2(1.0f, 0.0f);
Vector2 pointA = MathUtils.Mul(ref xfA, manifold.LocalPoint);
Vector2 pointB = MathUtils.Mul(ref xfB, manifold.Points[0].LocalPoint);
Vector2 pointA = Transform.Multiply(ref manifold.LocalPoint, ref xfA);
Vector2 pointB = Transform.Multiply(manifold.Points[0].LocalPoint, ref xfB);
if (Vector2.DistanceSquared(pointA, pointB) > Settings.Epsilon * Settings.Epsilon)
{
normal = pointB - pointA;
@@ -888,12 +1070,12 @@ namespace FarseerPhysics.Dynamics.Contacts
case ManifoldType.FaceA:
{
normal = MathUtils.Mul(xfA.q, manifold.LocalNormal);
Vector2 planePoint = MathUtils.Mul(ref xfA, manifold.LocalPoint);
normal = Complex.Multiply(ref manifold.LocalNormal, ref xfA.q);
Vector2 planePoint = Transform.Multiply(ref manifold.LocalPoint, ref xfA);
for (int i = 0; i < manifold.PointCount; ++i)
{
Vector2 clipPoint = MathUtils.Mul(ref xfB, manifold.Points[i].LocalPoint);
Vector2 clipPoint = Transform.Multiply(manifold.Points[i].LocalPoint, ref xfB);
Vector2 cA = clipPoint + (radiusA - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
Vector2 cB = clipPoint - radiusB * normal;
points[i] = 0.5f * (cA + cB);
@@ -903,12 +1085,12 @@ namespace FarseerPhysics.Dynamics.Contacts
case ManifoldType.FaceB:
{
normal = MathUtils.Mul(xfB.q, manifold.LocalNormal);
Vector2 planePoint = MathUtils.Mul(ref xfB, manifold.LocalPoint);
normal = Complex.Multiply(ref manifold.LocalNormal, ref xfB.q);
Vector2 planePoint = Transform.Multiply(ref manifold.LocalPoint, ref xfB);
for (int i = 0; i < manifold.PointCount; ++i)
{
Vector2 clipPoint = MathUtils.Mul(ref xfA, manifold.Points[i].LocalPoint);
Vector2 clipPoint = Transform.Multiply(manifold.Points[i].LocalPoint, ref xfA);
Vector2 cB = clipPoint + (radiusB - Vector2.Dot(clipPoint - planePoint, normal)) * normal;
Vector2 cA = clipPoint - radiusA * normal;
points[i] = 0.5f * (cA + cB);
@@ -924,19 +1106,22 @@ namespace FarseerPhysics.Dynamics.Contacts
private static class PositionSolverManifold
{
public static void Initialize(ContactPositionConstraint pc, Transform xfA, Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)
public static void Initialize(ContactPositionConstraint pc, ref Transform xfA, ref Transform xfB, int index, out Vector2 normal, out Vector2 point, out float separation)
{
Debug.Assert(pc.pointCount > 0);
switch (pc.type)
{
case ManifoldType.Circles:
{
Vector2 pointA = MathUtils.Mul(ref xfA, pc.localPoint);
Vector2 pointB = MathUtils.Mul(ref xfB, pc.localPoints[0]);
Vector2 pointA = Transform.Multiply(ref pc.localPoint, ref xfA);
Vector2 pointB = Transform.Multiply(pc.localPoints[0], ref xfB);
normal = pointB - pointA;
normal.Normalize();
// Handle zero normalization
if (normal != Vector2.Zero)
normal.Normalize();
point = 0.5f * (pointA + pointB);
separation = Vector2.Dot(pointB - pointA, normal) - pc.radiusA - pc.radiusB;
}
@@ -944,10 +1129,10 @@ namespace FarseerPhysics.Dynamics.Contacts
case ManifoldType.FaceA:
{
normal = MathUtils.Mul(xfA.q, pc.localNormal);
Vector2 planePoint = MathUtils.Mul(ref xfA, pc.localPoint);
Complex.Multiply(ref pc.localNormal, ref xfA.q, out normal);
Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfA);
Vector2 clipPoint = MathUtils.Mul(ref xfB, pc.localPoints[index]);
Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfB);
separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
point = clipPoint;
}
@@ -955,10 +1140,10 @@ namespace FarseerPhysics.Dynamics.Contacts
case ManifoldType.FaceB:
{
normal = MathUtils.Mul(xfB.q, pc.localNormal);
Vector2 planePoint = MathUtils.Mul(ref xfB, pc.localPoint);
Complex.Multiply(ref pc.localNormal, ref xfB.q, out normal);
Vector2 planePoint = Transform.Multiply(ref pc.localPoint, ref xfB);
Vector2 clipPoint = MathUtils.Mul(ref xfA, pc.localPoints[index]);
Vector2 clipPoint = Transform.Multiply(pc.localPoints[index], ref xfA);
separation = Vector2.Dot(clipPoint - planePoint, normal) - pc.radiusA - pc.radiusB;
point = clipPoint;
@@ -976,4 +1161,6 @@ namespace FarseerPhysics.Dynamics.Contacts
}
}
}
}
@@ -1,3 +1,10 @@
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -19,7 +26,6 @@
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
//#define USE_IGNORE_CCD_CATEGORIES
using System;
using System.Collections.Generic;
@@ -32,55 +38,6 @@ using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
[Flags]
public enum Category
{
None = 0,
All = int.MaxValue,
Cat1 = 1,
Cat2 = 2,
Cat3 = 4,
Cat4 = 8,
Cat5 = 16,
Cat6 = 32,
Cat7 = 64,
Cat8 = 128,
Cat9 = 256,
Cat10 = 512,
Cat11 = 1024,
Cat12 = 2048,
Cat13 = 4096,
Cat14 = 8192,
Cat15 = 16384,
Cat16 = 32768,
Cat17 = 65536,
Cat18 = 131072,
Cat19 = 262144,
Cat20 = 524288,
Cat21 = 1048576,
Cat22 = 2097152,
Cat23 = 4194304,
Cat24 = 8388608,
Cat25 = 16777216,
Cat26 = 33554432,
Cat27 = 67108864,
Cat28 = 134217728,
Cat29 = 268435456,
Cat30 = 536870912,
Cat31 = 1073741824
}
/// <summary>
/// This proxy is used internally to connect fixtures to the broad-phase.
/// </summary>
public struct FixtureProxy
{
public AABB AABB;
public int ChildIndex;
public Fixture Fixture;
public int ProxyId;
}
/// <summary>
/// A fixture is used to attach a Shape to a body for collision detection. A fixture
/// inherits its transform from its parent. Fixtures hold additional non-geometric data
@@ -88,10 +45,8 @@ namespace FarseerPhysics.Dynamics
/// Fixtures are created via Body.CreateFixture.
/// Warning: You cannot reuse fixtures.
/// </summary>
public class Fixture : IDisposable
public class Fixture
{
[ThreadStatic]
private static int _fixtureIdCounter;
private bool _isSensor;
private float _friction;
private float _restitution;
@@ -99,11 +54,9 @@ namespace FarseerPhysics.Dynamics
internal Category _collidesWith;
internal Category _collisionCategories;
internal short _collisionGroup;
internal HashSet<int> _collisionIgnores;
public FixtureProxy[] Proxies;
public int ProxyCount;
public Category IgnoreCCDWith;
public FixtureProxy[] Proxies { get; private set; }
public int ProxyCount { get; private set; }
/// <summary>
/// Fires after two shapes has collided and are solved. This gives you a chance to get the impact force.
@@ -129,47 +82,32 @@ namespace FarseerPhysics.Dynamics
/// </summary>
public OnSeparationEventHandler OnSeparation;
internal Fixture()
{
FixtureId = _fixtureIdCounter++;
_collisionCategories = Settings.DefaultFixtureCollisionCategories;
_collidesWith = Settings.DefaultFixtureCollidesWith;
internal Fixture() // Note: This is internal because it's used by Deserialization.
{
_collisionCategories = Category.Cat1;
_collidesWith = Category.All;
_collisionGroup = 0;
_collisionIgnores = new HashSet<int>();
IgnoreCCDWith = Settings.DefaultFixtureIgnoreCCDWith;
//Fixture defaults
Friction = 0.2f;
Restitution = 0;
Restitution = 0f;
}
internal Fixture(Body body, Shape shape, object userData = null)
: this()
public Fixture(Shape shape) : this()
{
#if DEBUG
if (shape.ShapeType == ShapeType.Polygon)
((PolygonShape)shape).Vertices.AttachedToBody = true;
#endif
Body = body;
UserData = userData;
Shape = shape.Clone();
RegisterFixture();
// Reserve proxy space
Proxies = new FixtureProxy[Shape.ChildCount];
ProxyCount = 0;
}
/// <summary>
/// Defaults to 0
///
/// If Settings.UseFPECollisionCategories is set to false:
/// Collision groups allow a certain group of objects to never collide (negative)
/// or always collide (positive). Zero means no collision group. Non-zero group
/// filtering always wins against the mask bits.
///
/// If Settings.UseFPECollisionCategories is set to true:
/// If 2 fixtures are in the same collision group, they will not collide.
/// </summary>
public short CollisionGroup
{
@@ -189,7 +127,6 @@ namespace FarseerPhysics.Dynamics
///
/// The collision mask bits. This states the categories that this
/// fixture would accept for collision.
/// Use Settings.UseFPECollisionCategories to change the behavior.
/// </summary>
public Category CollidesWith
{
@@ -208,11 +145,7 @@ namespace FarseerPhysics.Dynamics
/// <summary>
/// The collision categories this fixture is a part of.
///
/// If Settings.UseFPECollisionCategories is set to false:
/// Defaults to Category.Cat1
///
/// If Settings.UseFPECollisionCategories is set to true:
/// Defaults to Category.All
/// </summary>
public Category CollisionCategories
{
@@ -229,11 +162,10 @@ namespace FarseerPhysics.Dynamics
}
/// <summary>
/// Get the child Shape. You can modify the child Shape, however you should not change the
/// number of vertices because this will crash some collision caching mechanisms.
/// Get the child Shape.
/// </summary>
/// <value>The shape.</value>
public Shape Shape { get; internal set; }
public Shape Shape { get; private set; }
/// <summary>
/// Gets or sets a value indicating whether this fixture is a sensor.
@@ -261,7 +193,7 @@ namespace FarseerPhysics.Dynamics
/// Set the user data. Use this to store your application specific data.
/// </summary>
/// <value>The user data.</value>
public object UserData { get; set; }
public object UserData;
/// <summary>
/// Set the coefficient of friction. This will _not_ change the friction of
@@ -274,7 +206,6 @@ namespace FarseerPhysics.Dynamics
set
{
Debug.Assert(!float.IsNaN(value));
_friction = value;
}
}
@@ -290,71 +221,11 @@ namespace FarseerPhysics.Dynamics
set
{
Debug.Assert(!float.IsNaN(value));
_restitution = value;
}
}
/// <summary>
/// Gets a unique ID for this fixture.
/// </summary>
/// <value>The fixture id.</value>
public int FixtureId { get; internal set; }
#region IDisposable Members
public bool IsDisposed { get; set; }
public void Dispose()
{
if (!IsDisposed)
{
Body.DestroyFixture(this);
IsDisposed = true;
GC.SuppressFinalize(this);
}
}
#endregion
/// <summary>
/// Restores collisions between this fixture and the provided fixture.
/// </summary>
/// <param name="fixture">The fixture.</param>
public void RestoreCollisionWith(Fixture fixture)
{
if (_collisionIgnores.Contains(fixture.FixtureId))
{
_collisionIgnores.Remove(fixture.FixtureId);
Refilter();
}
}
/// <summary>
/// Ignores collisions between this fixture and the provided fixture.
/// </summary>
/// <param name="fixture">The fixture.</param>
public void IgnoreCollisionWith(Fixture fixture)
{
if (!_collisionIgnores.Contains(fixture.FixtureId))
{
_collisionIgnores.Add(fixture.FixtureId);
Refilter();
}
}
/// <summary>
/// Determines whether collisions are ignored between this fixture and the provided fixture.
/// </summary>
/// <param name="fixture">The fixture.</param>
/// <returns>
/// <c>true</c> if the fixture is ignored; otherwise, <c>false</c>.
/// </returns>
public bool IsFixtureIgnored(Fixture fixture)
{
return _collisionIgnores.Contains(fixture.FixtureId);
}
/// <summary>
/// Contacts are persistant and will keep being persistant unless they are
/// flagged for filtering.
@@ -377,49 +248,24 @@ namespace FarseerPhysics.Dynamics
edge = edge.Next;
}
World world = Body._world;
World world = Body.World;
if (world == null)
{
return;
}
// Touch each proxy so that new pairs may be created
IBroadPhase broadPhase = world.ContactManager.BroadPhase;
for (int i = 0; i < ProxyCount; ++i)
{
broadPhase.TouchProxy(Proxies[i].ProxyId);
}
TouchProxies(broadPhase);
}
private void RegisterFixture()
/// <summary>
/// Touch each proxy so that new pairs may be created
/// </summary>
/// <param name="broadPhase"></param>
internal void TouchProxies(IBroadPhase broadPhase)
{
// Reserve proxy space
Proxies = new FixtureProxy[Shape.ChildCount];
ProxyCount = 0;
if (Body.Enabled)
{
IBroadPhase broadPhase = Body._world.ContactManager.BroadPhase;
CreateProxies(broadPhase, ref Body._xf);
}
Body.FixtureList.Add(this);
// Adjust mass properties if needed.
if (Shape._density > 0.0f)
{
Body.ResetMassData();
}
// Let the world know we have a new fixture. This will cause new contacts
// to be created at the beginning of the next time step.
Body._world._worldHasNewFixture = true;
if (Body._world.FixtureAdded != null)
{
Body._world.FixtureAdded(this);
}
for (int i = 0; i < ProxyCount; ++i)
broadPhase.TouchProxy(Proxies[i].ProxyId);
}
/// <summary>
@@ -457,43 +303,11 @@ namespace FarseerPhysics.Dynamics
aabb = Proxies[childIndex].AABB;
}
internal void Destroy()
{
#if DEBUG
if (Shape.ShapeType == ShapeType.Polygon)
((PolygonShape)Shape).Vertices.AttachedToBody = false;
#endif
// The proxies must be destroyed before calling this.
Debug.Assert(ProxyCount == 0);
// Free the proxy array.
Proxies = null;
Shape = null;
//FPE: We set the userdata to null here to help prevent bugs related to stale references in GC
UserData = null;
BeforeCollision = null;
OnCollision = null;
OnSeparation = null;
AfterCollision = null;
if (Body._world.FixtureRemoved != null)
{
Body._world.FixtureRemoved(this);
}
Body._world.FixtureAdded = null;
Body._world.FixtureRemoved = null;
OnSeparation = null;
OnCollision = null;
}
// These support body activation/deactivation.
internal void CreateProxies(IBroadPhase broadPhase, ref Transform xf)
{
Debug.Assert(ProxyCount == 0);
if (ProxyCount != 0)
throw new InvalidOperationException("Proxies already created for this Fixture.");
// Create proxies in the broad-phase.
ProxyCount = Shape.ChildCount;
@@ -501,12 +315,12 @@ namespace FarseerPhysics.Dynamics
for (int i = 0; i < ProxyCount; ++i)
{
FixtureProxy proxy = new FixtureProxy();
Shape.ComputeAABB(out proxy.AABB, ref xf, i);
proxy.Fixture = this;
proxy.ChildIndex = i;
//FPE note: This line needs to be after the previous two because FixtureProxy is a struct
proxy.ProxyId = broadPhase.AddProxy(ref proxy);
proxy.Body = this.Body;
Shape.ComputeAABB(out proxy.AABB, ref xf, i);
proxy.ProxyId = broadPhase.AddProxy(ref proxy.AABB);
broadPhase.SetProxy(proxy.ProxyId, ref proxy);
Proxies[i] = proxy;
}
@@ -526,11 +340,6 @@ namespace FarseerPhysics.Dynamics
internal void Synchronize(IBroadPhase broadPhase, ref Transform transform1, ref Transform transform2)
{
if (ProxyCount == 0)
{
return;
}
for (int i = 0; i < ProxyCount; ++i)
{
FixtureProxy proxy = Proxies[i];
@@ -549,55 +358,24 @@ namespace FarseerPhysics.Dynamics
}
/// <summary>
/// Only compares the values of this fixture, and not the attached shape or body.
/// This is used for deduplication in serialization only.
/// </summary>
internal bool CompareTo(Fixture fixture)
{
return (_collidesWith == fixture._collidesWith &&
_collisionCategories == fixture._collisionCategories &&
_collisionGroup == fixture._collisionGroup &&
Friction == fixture.Friction &&
IsSensor == fixture.IsSensor &&
Restitution == fixture.Restitution &&
UserData == fixture.UserData &&
IgnoreCCDWith == fixture.IgnoreCCDWith &&
SequenceEqual(_collisionIgnores, fixture._collisionIgnores));
}
private bool SequenceEqual<T>(HashSet<T> first, HashSet<T> second)
{
if (first.Count != second.Count)
return false;
using (IEnumerator<T> enumerator1 = first.GetEnumerator())
{
using (IEnumerator<T> enumerator2 = second.GetEnumerator())
{
while (enumerator1.MoveNext())
{
if (!enumerator2.MoveNext() || !Equals(enumerator1.Current, enumerator2.Current))
return false;
}
if (enumerator2.MoveNext())
return false;
}
}
return true;
}
/// <summary>
/// Clones the fixture and attached shape onto the specified body.
/// Clones the fixture onto the specified body.
/// </summary>
/// <param name="body">The body you wish to clone the fixture onto.</param>
/// <returns>The cloned fixture.</returns>
public Fixture CloneOnto(Body body)
{
Fixture fixture = new Fixture();
fixture.Body = body;
fixture.Shape = Shape.Clone();
return CloneOnto(body, this.Shape);
}
/// <summary>
/// Clones the fixture and attached shape onto the specified body.
/// Note: This is used only by Deserialization.
/// </summary>
/// <param name="body">The body you wish to clone the fixture onto.</param>
/// <returns>The cloned fixture.</returns>
internal Fixture CloneOnto(Body body, Shape shape)
{
Fixture fixture = new Fixture(shape.Clone());
fixture.UserData = UserData;
fixture.Restitution = Restitution;
fixture.Friction = Friction;
@@ -605,15 +383,9 @@ namespace FarseerPhysics.Dynamics
fixture._collisionGroup = _collisionGroup;
fixture._collisionCategories = _collisionCategories;
fixture._collidesWith = _collidesWith;
fixture.IgnoreCCDWith = IgnoreCCDWith;
foreach (int ignore in _collisionIgnores)
{
fixture._collisionIgnores.Add(ignore);
}
fixture.RegisterFixture();
body.Add(fixture);
return fixture;
}
}
}
}
@@ -0,0 +1,50 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
* Original source Box2D:
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* 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.Dynamics.Contacts;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
/// <summary>
/// This proxy is used internally to connect fixtures to the broad-phase.
/// </summary>
public struct FixtureProxy
{
public AABB AABB;
public int ChildIndex;
public Fixture Fixture;
public int ProxyId;
public Body Body;
}
}
@@ -1,4 +1,11 @@
/*
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -22,10 +29,11 @@
using System;
using System.Diagnostics;
using Microsoft.Xna.Framework;
using FarseerPhysics.Common;
using FarseerPhysics.Diagnostics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
@@ -54,7 +62,7 @@ namespace FarseerPhysics.Dynamics
public int BodyCapacity;
public int ContactCapacity;
public int JointCapacity;
public float JointUpdateTime;
public TimeSpan JointUpdateTime;
public void Reset(int bodyCapacity, int contactCapacity, int jointCapacity, ContactManager contactManager)
{
@@ -118,7 +126,7 @@ namespace FarseerPhysics.Dynamics
if (b.IgnoreGravity)
v += h * (b._invMass * b._force);
else
v += h * (b.GravityScale * gravity + b._invMass * b._force);
v += h * (gravity + b._invMass * b._force);
w += h * b._invI * b._torque;
@@ -145,10 +153,11 @@ namespace FarseerPhysics.Dynamics
solverData.positions = _positions;
solverData.velocities = _velocities;
_contactSolver.Reset(step, ContactCount, _contacts, _positions, _velocities);
_contactSolver.Reset(ref step, ContactCount, _contacts, _positions, _velocities,
_contactManager.VelocityConstraintsMultithreadThreshold, _contactManager.PositionConstraintsMultithreadThreshold);
_contactSolver.InitializeVelocityConstraints();
if (Settings.EnableWarmstarting)
if (step.warmStarting)
{
_contactSolver.WarmStart();
}
@@ -166,7 +175,7 @@ namespace FarseerPhysics.Dynamics
_watch.Stop();
// Solve velocity constraints.
for (int i = 0; i < Settings.VelocityIterations; ++i)
for (int i = 0; i < step.velocityIterations; ++i)
{
for (int j = 0; j < JointCount; ++j)
{
@@ -227,7 +236,7 @@ namespace FarseerPhysics.Dynamics
// Solve position constraints
bool positionSolved = false;
for (int i = 0; i < Settings.PositionIterations; ++i)
for (int i = 0; i < step.positionIterations; ++i)
{
bool contactsOkay = _contactSolver.SolvePositionConstraints();
@@ -260,7 +269,7 @@ namespace FarseerPhysics.Dynamics
if (Settings.EnableDiagnostics)
{
JointUpdateTime = _watch.ElapsedTicks;
JointUpdateTime = TimeSpan.FromTicks(_watch.ElapsedTicks);
_watch.Reset();
}
@@ -311,7 +320,7 @@ namespace FarseerPhysics.Dynamics
}
}
internal void SolveTOI(ref TimeStep subStep, int toiIndexA, int toiIndexB, bool warmstarting)
internal void SolveTOI(ref TimeStep subStep, int toiIndexA, int toiIndexB)
{
Debug.Assert(toiIndexA < BodyCount);
Debug.Assert(toiIndexB < BodyCount);
@@ -326,10 +335,11 @@ namespace FarseerPhysics.Dynamics
_velocities[i].w = b._angularVelocity;
}
_contactSolver.Reset(subStep, ContactCount, _contacts, _positions, _velocities, warmstarting);
_contactSolver.Reset(ref subStep, ContactCount, _contacts, _positions, _velocities,
_contactManager.VelocityConstraintsMultithreadThreshold, _contactManager.PositionConstraintsMultithreadThreshold);
// Solve position constraints.
for (int i = 0; i < Settings.TOIPositionIterations; ++i)
for (int i = 0; i < subStep.positionIterations; ++i)
{
bool contactsOkay = _contactSolver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);
if (contactsOkay)
@@ -349,7 +359,7 @@ namespace FarseerPhysics.Dynamics
_contactSolver.InitializeVelocityConstraints();
// Solve velocity constraints.
for (int i = 0; i < Settings.TOIVelocityIterations; ++i)
for (int i = 0; i < subStep.velocityIterations; ++i)
{
_contactSolver.SolveVelocityConstraints();
}
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -23,6 +28,7 @@
using System;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -187,10 +193,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
_u = cB + _rB - cA - _rA;
// Handle singularity.
@@ -204,8 +211,8 @@ namespace FarseerPhysics.Dynamics.Joints
_u = Vector2.Zero;
}
float crAu = MathUtils.Cross(_rA, _u);
float crBu = MathUtils.Cross(_rB, _u);
float crAu = MathUtils.Cross(ref _rA, ref _u);
float crBu = MathUtils.Cross(ref _rB, ref _u);
float invMass = _invMassA + _invIA * crAu * crAu + _invMassB + _invIB * crBu * crBu;
// Compute the effective mass matrix.
@@ -216,7 +223,7 @@ namespace FarseerPhysics.Dynamics.Joints
float C = length - Length;
// Frequency
float omega = 2.0f * Settings.Pi * Frequency;
float omega = 2.0f * MathHelper.Pi * Frequency;
// Damping coefficient
float d = 2.0f * _mass * DampingRatio * omega;
@@ -239,16 +246,16 @@ namespace FarseerPhysics.Dynamics.Joints
_bias = 0.0f;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
_impulse *= data.step.dtRatio;
Vector2 P = _impulse * _u;
vA -= _invMassA * P;
wA -= _invIA * MathUtils.Cross(_rA, P);
wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
vB += _invMassB * P;
wB += _invIB * MathUtils.Cross(_rB, P);
wB += _invIB * MathUtils.Cross(ref _rB, ref P);
}
else
{
@@ -269,8 +276,8 @@ namespace FarseerPhysics.Dynamics.Joints
float wB = data.velocities[_indexB].w;
// Cdot = dot(u, v + cross(w, r))
Vector2 vpA = vA + MathUtils.Cross(wA, _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, _rB);
Vector2 vpA = vA + MathUtils.Cross(wA, ref _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, ref _rB);
float Cdot = Vector2.Dot(_u, vpB - vpA);
float impulse = -_mass * (Cdot + _bias + _gamma * _impulse);
@@ -278,9 +285,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = impulse * _u;
vA -= _invMassA * P;
wA -= _invIA * MathUtils.Cross(_rA, P);
wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
vB += _invMassB * P;
wB += _invIB * MathUtils.Cross(_rB, P);
wB += _invIB * MathUtils.Cross(ref _rB, ref P);
data.velocities[_indexA].v = vA;
data.velocities[_indexA].w = wA;
@@ -302,10 +309,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 u = cB + rB - cA - rA;
float length = u.Length(); u.Normalize();
@@ -316,9 +324,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = impulse * u;
cA -= _invMassA * P;
aA -= _invIA * MathUtils.Cross(rA, P);
aA -= _invIA * MathUtils.Cross(ref rA, ref P);
cB += _invMassB * P;
aB += _invIB * MathUtils.Cross(rB, P);
aB += _invIB * MathUtils.Cross(ref rB, ref P);
data.positions[_indexA].c = cA;
data.positions[_indexA].a = aA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -81,7 +87,7 @@ namespace FarseerPhysics.Dynamics.Joints
Debug.Assert(worldAnchor.IsValid());
_worldAnchor = worldAnchor;
LocalAnchorA = MathUtils.MulT(BodyA._xf, worldAnchor);
LocalAnchorA = Transform.Divide(ref worldAnchor, ref BodyA._xf);
}
/// <summary>
@@ -168,12 +174,12 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vA = data.velocities[_indexA].v;
float wA = data.velocities[_indexA].w;
Rot qA = new Rot(aA);
Complex qA = Complex.FromAngle(aA);
float mass = BodyA.Mass;
// Frequency
float omega = 2.0f * Settings.Pi * Frequency;
float omega = 2.0f * MathHelper.Pi * Frequency;
// Damping coefficient
float d = 2.0f * mass * DampingRatio * omega;
@@ -195,7 +201,7 @@ namespace FarseerPhysics.Dynamics.Joints
_beta = h * k * _gamma;
// Compute the effective mass matrix.
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
// K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
// = [1/m1+1/m2 0 ] + invI1 * [r1.Y*r1.Y -r1.X*r1.Y] + invI2 * [r1.Y*r1.Y -r1.X*r1.Y]
// [ 0 1/m1+1/m2] [-r1.X*r1.Y r1.X*r1.X] [-r1.X*r1.Y r1.X*r1.X]
@@ -213,11 +219,11 @@ namespace FarseerPhysics.Dynamics.Joints
// Cheat with some damping
wA *= 0.98f;
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
_impulse *= data.step.dtRatio;
vA += _invMassA * _impulse;
wA += _invIA * MathUtils.Cross(_rA, _impulse);
wA += _invIA * MathUtils.Cross(ref _rA, ref _impulse);
}
else
{
@@ -234,7 +240,7 @@ namespace FarseerPhysics.Dynamics.Joints
float wA = data.velocities[_indexA].w;
// Cdot = v + cross(w, r)
Vector2 Cdot = vA + MathUtils.Cross(wA, _rA);
Vector2 Cdot = vA + MathUtils.Cross(wA, ref _rA);
Vector2 impulse = MathUtils.Mul(ref _mass, -(Cdot + _C + _gamma * _impulse));
Vector2 oldImpulse = _impulse;
@@ -247,7 +253,7 @@ namespace FarseerPhysics.Dynamics.Joints
impulse = _impulse - oldImpulse;
vA += _invMassA * impulse;
wA += _invIA * MathUtils.Cross(_rA, impulse);
wA += _invIA * MathUtils.Cross(ref _rA, ref impulse);
data.velocities[_indexA].v = vA;
data.velocities[_indexA].w = wA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -21,6 +26,7 @@
*/
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -151,11 +157,12 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
// Compute the effective mass matrix.
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
@@ -183,7 +190,7 @@ namespace FarseerPhysics.Dynamics.Joints
_angularMass = 1.0f / _angularMass;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
_linearImpulse *= data.step.dtRatio;
@@ -191,9 +198,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(_linearImpulse.X, _linearImpulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + _angularImpulse);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + _angularImpulse);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + _angularImpulse);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + _angularImpulse);
}
else
{
@@ -235,9 +242,9 @@ namespace FarseerPhysics.Dynamics.Joints
// Solve linear friction
{
Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);
Vector2 Cdot = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA);
Vector2 impulse = -MathUtils.Mul(ref _linearMass, Cdot);
Vector2 impulse = -MathUtils.Mul(ref _linearMass, ref Cdot);
Vector2 oldImpulse = _linearImpulse;
_linearImpulse += impulse;
@@ -252,10 +259,10 @@ namespace FarseerPhysics.Dynamics.Joints
impulse = _linearImpulse - oldImpulse;
vA -= mA * impulse;
wA -= iA * MathUtils.Cross(_rA, impulse);
wA -= iA * MathUtils.Cross(ref _rA, ref impulse);
vB += mB * impulse;
wB += iB * MathUtils.Cross(_rB, impulse);
wB += iB * MathUtils.Cross(ref _rB, ref impulse);
}
data.velocities[_indexA].v = vA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -148,7 +154,7 @@ namespace FarseerPhysics.Dynamics.Joints
_localAxisC = prismatic.LocalXAxis;
Vector2 pC = _localAnchorC;
Vector2 pA = MathUtils.MulT(xfC.q, MathUtils.Mul(xfA.q, _localAnchorA) + (xfA.p - xfC.p));
Vector2 pA = Complex.Divide(Complex.Multiply(ref _localAnchorA, ref xfA.q) + (xfA.p - xfC.p), ref xfC.q);
coordinateA = Vector2.Dot(pA - pC, _localAxisC);
}
@@ -180,7 +186,7 @@ namespace FarseerPhysics.Dynamics.Joints
_localAxisD = prismatic.LocalXAxis;
Vector2 pD = _localAnchorD;
Vector2 pB = MathUtils.MulT(xfD.q, MathUtils.Mul(xfB.q, _localAnchorB) + (xfB.p - xfD.p));
Vector2 pB = Complex.Divide(Complex.Multiply(ref _localAnchorB, ref xfB.q) + (xfB.p - xfD.p), ref xfD.q);
coordinateB = Vector2.Dot(pB - pD, _localAxisD);
}
@@ -271,7 +277,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vD = data.velocities[_indexD].v;
float wD = data.velocities[_indexD].w;
Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Complex qC = Complex.FromAngle(aC);
Complex qD = Complex.FromAngle(aD);
_mass = 0.0f;
@@ -284,12 +293,12 @@ namespace FarseerPhysics.Dynamics.Joints
}
else
{
Vector2 u = MathUtils.Mul(qC, _localAxisC);
Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC);
Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA);
Vector2 u = Complex.Multiply(ref _localAxisC, ref qC);
Vector2 rC = Complex.Multiply(_localAnchorC - _lcC, ref qC);
Vector2 rA = Complex.Multiply(_localAnchorA - _lcA, ref qA);
_JvAC = u;
_JwC = MathUtils.Cross(rC, u);
_JwA = MathUtils.Cross(rA, u);
_JwC = MathUtils.Cross(ref rC, ref u);
_JwA = MathUtils.Cross(ref rA, ref u);
_mass += _mC + _mA + _iC * _JwC * _JwC + _iA * _JwA * _JwA;
}
@@ -302,19 +311,19 @@ namespace FarseerPhysics.Dynamics.Joints
}
else
{
Vector2 u = MathUtils.Mul(qD, _localAxisD);
Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD);
Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB);
Vector2 u = Complex.Multiply(ref _localAxisD, ref qD);
Vector2 rD = Complex.Multiply(_localAnchorD - _lcD, ref qD);
Vector2 rB = Complex.Multiply(_localAnchorB - _lcB, ref qB);
_JvBD = _ratio * u;
_JwD = _ratio * MathUtils.Cross(rD, u);
_JwB = _ratio * MathUtils.Cross(rB, u);
_JwD = _ratio * MathUtils.Cross(ref rD, ref u);
_JwB = _ratio * MathUtils.Cross(ref rB, ref u);
_mass += _ratio * _ratio * (_mD + _mB) + _iD * _JwD * _JwD + _iB * _JwB * _JwB;
}
// Compute effective mass.
_mass = _mass > 0.0f ? 1.0f / _mass : 0.0f;
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
vA += (_mA * _impulse) * _JvAC;
wA += _iA * _impulse * _JwA;
@@ -387,7 +396,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cD = data.positions[_indexD].c;
float aD = data.positions[_indexD].a;
Rot qA = new Rot(aA), qB = new Rot(aB), qC = new Rot(aC), qD = new Rot(aD);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Complex qC = Complex.FromAngle(aC);
Complex qD = Complex.FromAngle(aD);
const float linearError = 0.0f;
@@ -408,16 +420,16 @@ namespace FarseerPhysics.Dynamics.Joints
}
else
{
Vector2 u = MathUtils.Mul(qC, _localAxisC);
Vector2 rC = MathUtils.Mul(qC, _localAnchorC - _lcC);
Vector2 rA = MathUtils.Mul(qA, _localAnchorA - _lcA);
Vector2 u = Complex.Multiply(ref _localAxisC, ref qC);
Vector2 rC = Complex.Multiply(_localAnchorC - _lcC, ref qC);
Vector2 rA = Complex.Multiply(_localAnchorA - _lcA, ref qA);
JvAC = u;
JwC = MathUtils.Cross(rC, u);
JwA = MathUtils.Cross(rA, u);
JwC = MathUtils.Cross(ref rC, ref u);
JwA = MathUtils.Cross(ref rA, ref u);
mass += _mC + _mA + _iC * JwC * JwC + _iA * JwA * JwA;
Vector2 pC = _localAnchorC - _lcC;
Vector2 pA = MathUtils.MulT(qC, rA + (cA - cC));
Vector2 pA = Complex.Divide(rA + (cA - cC), ref qC);
coordinateA = Vector2.Dot(pA - pC, _localAxisC);
}
@@ -432,16 +444,16 @@ namespace FarseerPhysics.Dynamics.Joints
}
else
{
Vector2 u = MathUtils.Mul(qD, _localAxisD);
Vector2 rD = MathUtils.Mul(qD, _localAnchorD - _lcD);
Vector2 rB = MathUtils.Mul(qB, _localAnchorB - _lcB);
Vector2 u = Complex.Multiply(ref _localAxisD, ref qD);
Vector2 rD = Complex.Multiply(_localAnchorD - _lcD, ref qD);
Vector2 rB = Complex.Multiply(_localAnchorB - _lcB, ref qB);
JvBD = _ratio * u;
JwD = _ratio * MathUtils.Cross(rD, u);
JwB = _ratio * MathUtils.Cross(rB, u);
JwD = _ratio * MathUtils.Cross(ref rD, ref u);
JwB = _ratio * MathUtils.Cross(ref rB, ref u);
mass += _ratio * _ratio * (_mD + _mB) + _iD * JwD * JwD + _iB * JwB * JwB;
Vector2 pD = _localAnchorD - _lcD;
Vector2 pB = MathUtils.MulT(qD, rB + (cB - cD));
Vector2 pB = Complex.Divide(rB + (cB - cD), ref qD);
coordinateB = Vector2.Dot(pB - pD, _localAxisD);
}
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -162,7 +167,7 @@ namespace FarseerPhysics.Dynamics.Joints
/// Set the user data pointer.
/// </summary>
/// <value>The data.</value>
public object UserData { get; set; }
public object Tag;
/// <summary>
/// Set this flag to true if the attached bodies should collide.
@@ -0,0 +1,124 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
{
/// <summary>
/// An easy to use factory for using joints.
/// </summary>
public static class JointFactory
{
public static MotorJoint CreateMotorJoint(World world, Body bodyA, Body bodyB, bool useWorldCoordinates = false)
{
MotorJoint joint = new MotorJoint(bodyA, bodyB, useWorldCoordinates);
world.Add(joint);
return joint;
}
public static RevoluteJoint CreateRevoluteJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)
{
RevoluteJoint joint = new RevoluteJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);
world.Add(joint);
return joint;
}
public static RevoluteJoint CreateRevoluteJoint(World world, Body bodyA, Body bodyB, Vector2 anchor)
{
Vector2 localanchorA = bodyA.GetLocalPoint(bodyB.GetWorldPoint(anchor));
RevoluteJoint joint = new RevoluteJoint(bodyA, bodyB, localanchorA, anchor);
world.Add(joint);
return joint;
}
public static RopeJoint CreateRopeJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)
{
RopeJoint ropeJoint = new RopeJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);
world.Add(ropeJoint);
return ropeJoint;
}
public static WeldJoint CreateWeldJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)
{
WeldJoint weldJoint = new WeldJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);
world.Add(weldJoint);
return weldJoint;
}
public static PrismaticJoint CreatePrismaticJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)
{
PrismaticJoint joint = new PrismaticJoint(bodyA, bodyB, anchor, axis, useWorldCoordinates);
world.Add(joint);
return joint;
}
public static WheelJoint CreateWheelJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, Vector2 axis, bool useWorldCoordinates = false)
{
WheelJoint joint = new WheelJoint(bodyA, bodyB, anchor, axis, useWorldCoordinates);
world.Add(joint);
return joint;
}
public static WheelJoint CreateWheelJoint(World world, Body bodyA, Body bodyB, Vector2 axis)
{
return CreateWheelJoint(world, bodyA, bodyB, Vector2.Zero, axis);
}
public static AngleJoint CreateAngleJoint(World world, Body bodyA, Body bodyB)
{
AngleJoint angleJoint = new AngleJoint(bodyA, bodyB);
world.Add(angleJoint);
return angleJoint;
}
public static DistanceJoint CreateDistanceJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, bool useWorldCoordinates = false)
{
DistanceJoint distanceJoint = new DistanceJoint(bodyA, bodyB, anchorA, anchorB, useWorldCoordinates);
world.Add(distanceJoint);
return distanceJoint;
}
public static DistanceJoint CreateDistanceJoint(World world, Body bodyA, Body bodyB)
{
return CreateDistanceJoint(world, bodyA, bodyB, Vector2.Zero, Vector2.Zero);
}
public static FrictionJoint CreateFrictionJoint(World world, Body bodyA, Body bodyB, Vector2 anchor, bool useWorldCoordinates = false)
{
FrictionJoint frictionJoint = new FrictionJoint(bodyA, bodyB, anchor, useWorldCoordinates);
world.Add(frictionJoint);
return frictionJoint;
}
public static FrictionJoint CreateFrictionJoint(World world, Body bodyA, Body bodyB)
{
return CreateFrictionJoint(world, bodyA, bodyB, Vector2.Zero);
}
public static GearJoint CreateGearJoint(World world, Body bodyA, Body bodyB, Joint jointA, Joint jointB, float ratio)
{
GearJoint gearJoint = new GearJoint(bodyA, bodyB, jointA, jointB, ratio);
world.Add(gearJoint);
return gearJoint;
}
public static PulleyJoint CreatePulleyJoint(World world, Body bodyA, Body bodyB, Vector2 anchorA, Vector2 anchorB, Vector2 worldAnchorA, Vector2 worldAnchorB, float ratio, bool useWorldCoordinates = false)
{
PulleyJoint pulleyJoint = new PulleyJoint(bodyA, bodyB, anchorA, anchorB, worldAnchorA, worldAnchorB, ratio, useWorldCoordinates);
world.Add(pulleyJoint);
return pulleyJoint;
}
public static FixedMouseJoint CreateFixedMouseJoint(World world, Body body, Vector2 worldAnchor)
{
FixedMouseJoint joint = new FixedMouseJoint(body, worldAnchor);
world.Add(joint);
return joint;
}
}
}
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -193,12 +199,12 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA);
Rot qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
// Compute the effective mass matrix.
_rA = MathUtils.Mul(qA, -_localCenterA);
_rB = MathUtils.Mul(qB, -_localCenterB);
_rA = -Complex.Multiply(ref _localCenterA, ref qA);
_rB = -Complex.Multiply(ref _localCenterB, ref qB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
@@ -226,10 +232,10 @@ namespace FarseerPhysics.Dynamics.Joints
_angularMass = 1.0f / _angularMass;
}
_linearError = cB + _rB - cA - _rA - MathUtils.Mul(qA, _linearOffset);
_linearError = cB + _rB - cA - _rA - Complex.Multiply(ref _linearOffset, ref qA);
_angularError = aB - aA - _angularOffset;
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
_linearImpulse *= data.step.dtRatio;
@@ -238,9 +244,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(_linearImpulse.X, _linearImpulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + _angularImpulse);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + _angularImpulse);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + _angularImpulse);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + _angularImpulse);
}
else
{
@@ -283,7 +289,7 @@ namespace FarseerPhysics.Dynamics.Joints
// Solve linear friction
{
Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA) + inv_h * CorrectionFactor * _linearError;
Vector2 Cdot = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA) + inv_h * CorrectionFactor * _linearError;
Vector2 impulse = -MathUtils.Mul(ref _linearMass, ref Cdot);
Vector2 oldImpulse = _linearImpulse;
@@ -300,10 +306,10 @@ namespace FarseerPhysics.Dynamics.Joints
impulse = _linearImpulse - oldImpulse;
vA -= mA * impulse;
wA -= iA * MathUtils.Cross(_rA, impulse);
wA -= iA * MathUtils.Cross(ref _rA, ref impulse);
vB += mB * impulse;
wB += iB * MathUtils.Cross(_rB, impulse);
wB += iB * MathUtils.Cross(ref _rB, ref impulse);
}
data.velocities[_indexA].v = vA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -23,6 +28,7 @@
using System;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -98,6 +104,7 @@ namespace FarseerPhysics.Dynamics.Joints
/// </summary>
public class PrismaticJoint : Joint
{
private Vector2 _localXAxis;
private Vector2 _localYAxisA;
private Vector3 _impulse;
private float _lowerTranslation;
@@ -207,7 +214,7 @@ namespace FarseerPhysics.Dynamics.Joints
get
{
Vector2 d = BodyB.GetWorldPoint(LocalAnchorB) - BodyA.GetWorldPoint(LocalAnchorA);
Vector2 axis = BodyA.GetWorldVector(LocalXAxis);
Vector2 axis = BodyA.GetWorldVector(ref _localXAxis);
return Vector2.Dot(d, axis);
}
@@ -221,23 +228,22 @@ namespace FarseerPhysics.Dynamics.Joints
{
get
{
Transform xf1, xf2;
BodyA.GetTransform(out xf1);
BodyB.GetTransform(out xf2);
Transform xf1 = BodyA.GetTransform();
Transform xf2 = BodyB.GetTransform();
Vector2 r1 = MathUtils.Mul(ref xf1.q, LocalAnchorA - BodyA.LocalCenter);
Vector2 r2 = MathUtils.Mul(ref xf2.q, LocalAnchorB - BodyB.LocalCenter);
Vector2 r1 = Complex.Multiply(LocalAnchorA - BodyA.LocalCenter, ref xf1.q);
Vector2 r2 = Complex.Multiply(LocalAnchorB - BodyB.LocalCenter, ref xf2.q);
Vector2 p1 = BodyA._sweep.C + r1;
Vector2 p2 = BodyB._sweep.C + r2;
Vector2 d = p2 - p1;
Vector2 axis = BodyA.GetWorldVector(LocalXAxis);
Vector2 axis = BodyA.GetWorldVector(ref _localXAxis);
Vector2 v1 = BodyA._linearVelocity;
Vector2 v2 = BodyB._linearVelocity;
float w1 = BodyA._angularVelocity;
float w2 = BodyB._angularVelocity;
float speed = Vector2.Dot(d, MathUtils.Cross(w1, axis)) + Vector2.Dot(axis, v2 + MathUtils.Cross(w2, r2) - v1 - MathUtils.Cross(w1, r1));
float speed = Vector2.Dot(d, MathUtils.Cross(w1, ref axis)) + Vector2.Dot(axis, v2 + MathUtils.Cross(w2, ref r2) - v1 - MathUtils.Cross(w1, ref r1));
return speed;
}
}
@@ -380,16 +386,16 @@ namespace FarseerPhysics.Dynamics.Joints
set
{
_axis1 = value;
LocalXAxis = BodyA.GetLocalVector(_axis1);
LocalXAxis.Normalize();
_localYAxisA = MathUtils.Cross(1.0f, LocalXAxis);
_localXAxis = BodyA.GetLocalVector(_axis1);
_localXAxis.Normalize();
_localYAxisA = MathUtils.Cross(1.0f, ref _localXAxis);
}
}
/// <summary>
/// The axis in local coordinates relative to BodyA
/// </summary>
public Vector2 LocalXAxis { get; private set; }
public Vector2 LocalXAxis { get { return _localXAxis; } }
/// <summary>
/// The reference angle.
@@ -427,11 +433,12 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
// Compute the effective masses.
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 d = (cB - cA) + rB - rA;
float mA = _invMassA, mB = _invMassB;
@@ -439,9 +446,9 @@ namespace FarseerPhysics.Dynamics.Joints
// Compute motor Jacobian and effective mass.
{
_axis = MathUtils.Mul(qA, LocalXAxis);
_axis = Complex.Multiply(ref _localXAxis, ref qA);
_a1 = MathUtils.Cross(d + rA, _axis);
_a2 = MathUtils.Cross(rB, _axis);
_a2 = MathUtils.Cross(ref rB, ref _axis);
_motorMass = mA + mB + iA * _a1 * _a1 + iB * _a2 * _a2;
if (_motorMass > 0.0f)
@@ -452,10 +459,10 @@ namespace FarseerPhysics.Dynamics.Joints
// Prismatic constraint.
{
_perp = MathUtils.Mul(qA, _localYAxisA);
_perp = Complex.Multiply(ref _localYAxisA, ref qA);
_s1 = MathUtils.Cross(d + rA, _perp);
_s2 = MathUtils.Cross(rB, _perp);
_s2 = MathUtils.Cross(ref rB, ref _perp);
float k11 = mA + mB + iA * _s1 * _s1 + iB * _s2 * _s2;
float k12 = iA * _s1 + iB * _s2;
@@ -515,7 +522,7 @@ namespace FarseerPhysics.Dynamics.Joints
MotorImpulse = 0.0f;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Account for variable time step.
_impulse *= data.step.dtRatio;
@@ -647,23 +654,24 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
float mA = _invMassA, mB = _invMassB;
float iA = _invIA, iB = _invIB;
// Compute fresh Jacobians
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 d = cB + rB - cA - rA;
Vector2 axis = MathUtils.Mul(qA, LocalXAxis);
Vector2 axis = Complex.Multiply(ref _localXAxis, ref qA);
float a1 = MathUtils.Cross(d + rA, axis);
float a2 = MathUtils.Cross(rB, axis);
Vector2 perp = MathUtils.Mul(qA, _localYAxisA);
float a2 = MathUtils.Cross(ref rB, ref axis);
Vector2 perp = Complex.Multiply(ref _localYAxisA, ref qA);
float s1 = MathUtils.Cross(d + rA, perp);
float s2 = MathUtils.Cross(rB, perp);
float s2 = MathUtils.Cross(ref rB, ref perp);
Vector3 impulse;
Vector2 C1 = new Vector2();
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -23,6 +28,7 @@
using System;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -225,10 +231,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
// Get the pulley axes.
_uA = cA + _rA - WorldAnchorA;
@@ -256,8 +263,8 @@ namespace FarseerPhysics.Dynamics.Joints
}
// Compute effective mass.
float ruA = MathUtils.Cross(_rA, _uA);
float ruB = MathUtils.Cross(_rB, _uB);
float ruA = MathUtils.Cross(ref _rA, ref _uA);
float ruB = MathUtils.Cross(ref _rB, ref _uB);
float mA = _invMassA + _invIA * ruA * ruA;
float mB = _invMassB + _invIB * ruB * ruB;
@@ -269,7 +276,7 @@ namespace FarseerPhysics.Dynamics.Joints
_mass = 1.0f / _mass;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale impulses to support variable time steps.
_impulse *= data.step.dtRatio;
@@ -279,9 +286,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 PB = (-Ratio * _impulse) * _uB;
vA += _invMassA * PA;
wA += _invIA * MathUtils.Cross(_rA, PA);
wA += _invIA * MathUtils.Cross(ref _rA, ref PA);
vB += _invMassB * PB;
wB += _invIB * MathUtils.Cross(_rB, PB);
wB += _invIB * MathUtils.Cross(ref _rB, ref PB);
}
else
{
@@ -301,8 +308,8 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Vector2 vpA = vA + MathUtils.Cross(wA, _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, _rB);
Vector2 vpA = vA + MathUtils.Cross(wA, ref _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, ref _rB);
float Cdot = -Vector2.Dot(_uA, vpA) - Ratio * Vector2.Dot(_uB, vpB);
float impulse = -_mass * Cdot;
@@ -311,9 +318,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 PA = -impulse * _uA;
Vector2 PB = -Ratio * impulse * _uB;
vA += _invMassA * PA;
wA += _invIA * MathUtils.Cross(_rA, PA);
wA += _invIA * MathUtils.Cross(ref _rA, ref PA);
vB += _invMassB * PB;
wB += _invIB * MathUtils.Cross(_rB, PB);
wB += _invIB * MathUtils.Cross(ref _rB, ref PB);
data.velocities[_indexA].v = vA;
data.velocities[_indexA].w = wA;
@@ -328,10 +335,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
// Get the pulley axes.
Vector2 uA = cA + rA - WorldAnchorA;
@@ -359,8 +367,8 @@ namespace FarseerPhysics.Dynamics.Joints
}
// Compute effective mass.
float ruA = MathUtils.Cross(rA, uA);
float ruB = MathUtils.Cross(rB, uB);
float ruA = MathUtils.Cross(ref rA, ref uA);
float ruB = MathUtils.Cross(ref rB, ref uB);
float mA = _invMassA + _invIA * ruA * ruA;
float mB = _invMassB + _invIB * ruB * ruB;
@@ -381,9 +389,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 PB = -Ratio * impulse * uB;
cA += _invMassA * PA;
aA += _invIA * MathUtils.Cross(rA, PA);
aA += _invIA * MathUtils.Cross(ref rA, ref PA);
cB += _invMassB * PB;
aB += _invIB * MathUtils.Cross(rB, PB);
aB += _invIB * MathUtils.Cross(ref rB, ref PB);
data.positions[_indexA].c = cA;
data.positions[_indexA].a = aA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -322,10 +328,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
@@ -396,7 +403,7 @@ namespace FarseerPhysics.Dynamics.Joints
_limitState = LimitState.Inactive;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
_impulse *= data.step.dtRatio;
@@ -405,10 +412,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(_impulse.X, _impulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + MotorImpulse + _impulse.Z);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + MotorImpulse + _impulse.Z);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + MotorImpulse + _impulse.Z);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + MotorImpulse + _impulse.Z);
}
else
{
@@ -451,7 +458,7 @@ namespace FarseerPhysics.Dynamics.Joints
// Solve limit constraint.
if (_enableLimit && _limitState != LimitState.Inactive && fixedRotation == false)
{
Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);
Vector2 Cdot1 = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA);
float Cdot2 = wB - wA;
Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);
@@ -503,25 +510,25 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(impulse.X, impulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + impulse.Z);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + impulse.Z);
}
else
{
// Solve point-to-point constraint
Vector2 Cdot = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);
Vector2 Cdot = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA);
Vector2 impulse = _mass.Solve22(-Cdot);
_impulse.X += impulse.X;
_impulse.Y += impulse.Y;
vA -= mA * impulse;
wA -= iA * MathUtils.Cross(_rA, impulse);
wA -= iA * MathUtils.Cross(ref _rA, ref impulse);
vB += mB * impulse;
wB += iB * MathUtils.Cross(_rB, impulse);
wB += iB * MathUtils.Cross(ref _rB, ref impulse);
}
data.velocities[_indexA].v = vA;
@@ -537,7 +544,6 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
float angularError = 0.0f;
float positionError;
@@ -582,10 +588,10 @@ namespace FarseerPhysics.Dynamics.Joints
// Solve point-to-point constraint.
{
qA.Set(aA);
qB.Set(aB);
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 C = cB + rB - cA - rA;
positionError = C.Length();
@@ -602,10 +608,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 impulse = -K.Solve(C);
cA -= mA * impulse;
aA -= iA * MathUtils.Cross(rA, impulse);
aA -= iA * MathUtils.Cross(ref rA, ref impulse);
cB += mB * impulse;
aB += iB * MathUtils.Cross(rB, impulse);
aB += iB * MathUtils.Cross(ref rB, ref impulse);
}
data.positions[_indexA].c = cA;
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -22,6 +27,7 @@
using System;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -159,10 +165,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
_u = cB + _rB - cA - _rA;
_length = _u.Length();
@@ -190,22 +197,22 @@ namespace FarseerPhysics.Dynamics.Joints
}
// Compute effective mass.
float crA = MathUtils.Cross(_rA, _u);
float crB = MathUtils.Cross(_rB, _u);
float crA = MathUtils.Cross(ref _rA, ref _u);
float crB = MathUtils.Cross(ref _rB, ref _u);
float invMass = _invMassA + _invIA * crA * crA + _invMassB + _invIB * crB * crB;
_mass = invMass != 0.0f ? 1.0f / invMass : 0.0f;
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale the impulse to support a variable time step.
_impulse *= data.step.dtRatio;
Vector2 P = _impulse * _u;
vA -= _invMassA * P;
wA -= _invIA * MathUtils.Cross(_rA, P);
wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
vB += _invMassB * P;
wB += _invIB * MathUtils.Cross(_rB, P);
wB += _invIB * MathUtils.Cross(ref _rB, ref P);
}
else
{
@@ -226,8 +233,8 @@ namespace FarseerPhysics.Dynamics.Joints
float wB = data.velocities[_indexB].w;
// Cdot = dot(u, v + cross(w, r))
Vector2 vpA = vA + MathUtils.Cross(wA, _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, _rB);
Vector2 vpA = vA + MathUtils.Cross(wA, ref _rA);
Vector2 vpB = vB + MathUtils.Cross(wB, ref _rB);
float C = _length - MaxLength;
float Cdot = Vector2.Dot(_u, vpB - vpA);
@@ -244,9 +251,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = impulse * _u;
vA -= _invMassA * P;
wA -= _invIA * MathUtils.Cross(_rA, P);
wA -= _invIA * MathUtils.Cross(ref _rA, ref P);
vB += _invMassB * P;
wB += _invIB * MathUtils.Cross(_rB, P);
wB += _invIB * MathUtils.Cross(ref _rB, ref P);
data.velocities[_indexA].v = vA;
data.velocities[_indexA].w = wA;
@@ -261,10 +268,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 u = cB + rB - cA - rA;
float length = u.Length(); u.Normalize();
@@ -276,9 +284,9 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = impulse * u;
cA -= _invMassA * P;
aA -= _invIA * MathUtils.Cross(rA, P);
aA -= _invIA * MathUtils.Cross(ref rA, ref P);
cB += _invMassB * P;
aB += _invIB * MathUtils.Cross(rB, P);
aB += _invIB * MathUtils.Cross(ref rB, ref P);
data.positions[_indexA].c = cA;
data.positions[_indexA].a = aA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -68,11 +74,6 @@ namespace FarseerPhysics.Dynamics.Joints
private float _invIB;
private Mat33 _mass;
/// <summary>
/// If true, body B is treated as if it was kinematic (i.e. as if it had infinite mass)
/// </summary>
public bool KinematicBodyB;
internal WeldJoint()
{
JointType = JointType.Weld;
@@ -116,6 +117,11 @@ namespace FarseerPhysics.Dynamics.Joints
/// </summary>
public Vector2 LocalAnchorB { get; set; }
/// <summary>
/// If true, body B is treated as if it was kinematic (i.e. as if it had infinite mass)
/// </summary>
public bool KinematicBodyB;
public override Vector2 WorldAnchorA
{
get { return BodyA.GetWorldPoint(LocalAnchorA); }
@@ -165,6 +171,7 @@ namespace FarseerPhysics.Dynamics.Joints
_invMassA = BodyA._invMass;
_invMassB = KinematicBodyB ? 0.0f : BodyB._invMass;
_invIA = BodyA._invI;
_invIB = BodyB._invI;
_invIB = KinematicBodyB ? 0.0f : BodyB._invI;
float aA = data.positions[_indexA].a;
@@ -175,10 +182,11 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
_rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
_rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
_rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
_rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
// J = [-I -r1_skew I r2_skew]
// [ 0 -1 0 1]
@@ -213,7 +221,7 @@ namespace FarseerPhysics.Dynamics.Joints
float C = aB - aA - ReferenceAngle;
// Frequency
float omega = 2.0f * Settings.Pi * FrequencyHz;
float omega = 2.0f * MathHelper.Pi * FrequencyHz;
// Damping coefficient
float d = 2.0f * m * DampingRatio * omega;
@@ -230,6 +238,12 @@ namespace FarseerPhysics.Dynamics.Joints
invM += _gamma;
_mass.ez.Z = invM != 0.0f ? 1.0f / invM : 0.0f;
}
else if (K.ez.Z == 0.0f)
{
K.GetInverse22(ref _mass);
_gamma = 0.0f;
_bias = 0.0f;
}
else
{
K.GetSymInverse33(ref _mass);
@@ -237,7 +251,7 @@ namespace FarseerPhysics.Dynamics.Joints
_bias = 0.0f;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Scale impulses to support a variable time step.
_impulse *= data.step.dtRatio;
@@ -245,10 +259,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(_impulse.X, _impulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + _impulse.Z);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + _impulse.Z);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + _impulse.Z);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + _impulse.Z);
}
else
{
@@ -281,7 +295,7 @@ namespace FarseerPhysics.Dynamics.Joints
wA -= iA * impulse2;
wB += iB * impulse2;
Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);
Vector2 Cdot1 = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA);
Vector2 impulse1 = -MathUtils.Mul22(_mass, Cdot1);
_impulse.X += impulse1.X;
@@ -290,14 +304,14 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = impulse1;
vA -= mA * P;
wA -= iA * MathUtils.Cross(_rA, P);
wA -= iA * MathUtils.Cross(ref _rA, ref P);
vB += mB * P;
wB += iB * MathUtils.Cross(_rB, P);
wB += iB * MathUtils.Cross(ref _rB, ref P);
}
else
{
Vector2 Cdot1 = vB + MathUtils.Cross(wB, _rB) - vA - MathUtils.Cross(wA, _rA);
Vector2 Cdot1 = vB + MathUtils.Cross(wB, ref _rB) - vA - MathUtils.Cross(wA, ref _rA);
float Cdot2 = wB - wA;
Vector3 Cdot = new Vector3(Cdot1.X, Cdot1.Y, Cdot2);
@@ -307,10 +321,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = new Vector2(impulse.X, impulse.Y);
vA -= mA * P;
wA -= iA * (MathUtils.Cross(_rA, P) + impulse.Z);
wA -= iA * (MathUtils.Cross(ref _rA, ref P) + impulse.Z);
vB += mB * P;
wB += iB * (MathUtils.Cross(_rB, P) + impulse.Z);
wB += iB * (MathUtils.Cross(ref _rB, ref P) + impulse.Z);
}
data.velocities[_indexA].v = vA;
@@ -326,13 +340,14 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
float mA = _invMassA, mB = _invMassB;
float iA = _invIA, iB = _invIB;
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
float positionError, angularError;
@@ -357,10 +372,10 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 P = -K.Solve22(C1);
cA -= mA * P;
aA -= iA * MathUtils.Cross(rA, P);
aA -= iA * MathUtils.Cross(ref rA, ref P);
cB += mB * P;
aB += iB * MathUtils.Cross(rB, P);
aB += iB * MathUtils.Cross(ref rB, ref P);
}
else
{
@@ -372,14 +387,23 @@ namespace FarseerPhysics.Dynamics.Joints
Vector3 C = new Vector3(C1.X, C1.Y, C2);
Vector3 impulse = -K.Solve33(C);
Vector3 impulse;
if (K.ez.Z <= 0.0f)
{
Vector2 impulse2 = -K.Solve22(C1);
impulse = new Vector3(impulse2.X, impulse2.Y, 0.0f);
}
else
{
impulse = -K.Solve33(C);
}
Vector2 P = new Vector2(impulse.X, impulse.Y);
cA -= mA * P;
aA -= iA * (MathUtils.Cross(rA, P) + impulse.Z);
aA -= iA * (MathUtils.Cross(ref rA, ref P) + impulse.Z);
cB += mB * P;
aB += iB * (MathUtils.Cross(rB, P) + impulse.Z);
aB += iB * (MathUtils.Cross(ref rB, ref P) + impulse.Z);
}
data.positions[_indexA].c = cA;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -22,6 +27,7 @@
using System;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics.Joints
@@ -52,6 +58,7 @@ namespace FarseerPhysics.Dynamics.Joints
public class WheelJoint : Joint
{
// Solver shared
private Vector2 _localXAxis;
private Vector2 _localYAxis;
private float _impulse;
@@ -147,15 +154,15 @@ namespace FarseerPhysics.Dynamics.Joints
set
{
_axis = value;
LocalXAxis = BodyA.GetLocalVector(_axis);
_localYAxis = MathUtils.Cross(1.0f, LocalXAxis);
_localXAxis = BodyA.GetLocalVector(_axis);
_localYAxis = MathUtils.Rot90(ref _localXAxis);
}
}
/// <summary>
/// The axis in local coordinates relative to BodyA
/// </summary>
public Vector2 LocalXAxis { get; private set; }
public Vector2 LocalXAxis { get { return _localXAxis; } }
/// <summary>
/// The desired motor speed in radians per second.
@@ -206,7 +213,7 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 pA = bA.GetWorldPoint(LocalAnchorA);
Vector2 pB = bB.GetWorldPoint(LocalAnchorB);
Vector2 d = pB - pA;
Vector2 axis = bA.GetWorldVector(LocalXAxis);
Vector2 axis = bA.GetWorldVector(ref _localXAxis);
float translation = Vector2.Dot(d, axis);
return translation;
@@ -282,18 +289,19 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 vB = data.velocities[_indexB].v;
float wB = data.velocities[_indexB].w;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
// Compute the effective masses.
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 d1 = cB + rB - cA - rA;
// Point to line constraint
{
_ay = MathUtils.Mul(qA, _localYAxis);
_ay = Complex.Multiply(ref _localYAxis, ref qA);
_sAy = MathUtils.Cross(d1 + rA, _ay);
_sBy = MathUtils.Cross(rB, _ay);
_sBy = MathUtils.Cross(ref rB, ref _ay);
_mass = mA + mB + iA * _sAy * _sAy + iB * _sBy * _sBy;
@@ -309,9 +317,9 @@ namespace FarseerPhysics.Dynamics.Joints
_gamma = 0.0f;
if (Frequency > 0.0f)
{
_ax = MathUtils.Mul(qA, LocalXAxis);
_ax = Complex.Multiply(ref _localXAxis, ref qA);
_sAx = MathUtils.Cross(d1 + rA, _ax);
_sBx = MathUtils.Cross(rB, _ax);
_sBx = MathUtils.Cross(ref rB, ref _ax);
float invMass = mA + mB + iA * _sAx * _sAx + iB * _sBx * _sBx;
@@ -322,7 +330,7 @@ namespace FarseerPhysics.Dynamics.Joints
float C = Vector2.Dot(d1, _ax);
// Frequency
float omega = 2.0f * Settings.Pi * Frequency;
float omega = 2.0f * MathHelper.Pi * Frequency;
// Damping coefficient
float d = 2.0f * _springMass * DampingRatio * omega;
@@ -367,7 +375,7 @@ namespace FarseerPhysics.Dynamics.Joints
_motorImpulse = 0.0f;
}
if (Settings.EnableWarmstarting)
if (data.step.warmStarting)
{
// Account for variable time step.
_impulse *= data.step.dtRatio;
@@ -468,16 +476,17 @@ namespace FarseerPhysics.Dynamics.Joints
Vector2 cB = data.positions[_indexB].c;
float aB = data.positions[_indexB].a;
Rot qA = new Rot(aA), qB = new Rot(aB);
Complex qA = Complex.FromAngle(aA);
Complex qB = Complex.FromAngle(aB);
Vector2 rA = MathUtils.Mul(qA, LocalAnchorA - _localCenterA);
Vector2 rB = MathUtils.Mul(qB, LocalAnchorB - _localCenterB);
Vector2 rA = Complex.Multiply(LocalAnchorA - _localCenterA, ref qA);
Vector2 rB = Complex.Multiply(LocalAnchorB - _localCenterB, ref qB);
Vector2 d = (cB - cA) + rB - rA;
Vector2 ay = MathUtils.Mul(qA, _localYAxis);
Vector2 ay = Complex.Multiply(ref _localYAxis, ref qA);
float sAy = MathUtils.Cross(d + rA, ay);
float sBy = MathUtils.Cross(rB, ay);
float sBy = MathUtils.Cross(ref rB, ref ay);
float C = Vector2.Dot(d, ay);
@@ -0,0 +1,19 @@
// Copyright (c) 2018 Kastellanos Nikolaos
namespace FarseerPhysics.Dynamics
{
public struct SolverIterations
{
/// <summary>The number of velocity iterations used in the solver.</summary>
public int VelocityIterations;
/// <summary>The number of position iterations used in the solver.</summary>
public int PositionIterations;
/// <summary>The number of velocity iterations in the TOI solver</summary>
public int TOIVelocityIterations;
/// <summary>The number of position iterations in the TOI solver</summary>
public int TOIPositionIterations;
}
}
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Original source Box2D:
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
@@ -40,6 +45,11 @@ namespace FarseerPhysics.Dynamics
/// Inverse time step (0 if dt == 0).
/// </summary>
public float inv_dt;
public int positionIterations;
public int velocityIterations;
public bool warmStarting;
}
/// This is an internal structure.
@@ -47,6 +57,7 @@ namespace FarseerPhysics.Dynamics
{
public Vector2 c;
public float a;
internal int Lock;
}
/// This is an internal structure.
@@ -54,6 +65,7 @@ namespace FarseerPhysics.Dynamics
{
public Vector2 v;
public float w;
internal int Lock;
}
/// Solver Data
@@ -0,0 +1,260 @@
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Dynamics.Joints;
namespace FarseerPhysics.Dynamics
{
public partial class World
{
public virtual Body CreateBody(Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Body body = new Body();
body.Position = position;
body.Rotation = rotation;
body.BodyType = bodyType;
AddAsync(body);
return body;
}
public Body CreateEdge(Vector2 start, Vector2 end)
{
Body body = CreateBody();
body.CreateEdge(start, end);
return body;
}
public Body CreateChainShape(Vertices vertices, Vector2 position = new Vector2())
{
Body body = CreateBody(position);
body.CreateChainShape(vertices);
return body;
}
public Body CreateLoopShape(Vertices vertices, Vector2 position = new Vector2())
{
Body body = CreateBody(position);
body.CreateLoopShape(vertices);
return body;
}
public Body CreateRectangle(float width, float height, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
if (width <= 0)
throw new ArgumentOutOfRangeException("width", "Width must be more than 0 meters");
if (height <= 0)
throw new ArgumentOutOfRangeException("height", "Height must be more than 0 meters");
Body body = CreateBody(position, rotation, bodyType);
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2);
body.CreatePolygon(rectangleVertices, density);
return body;
}
public Body CreateCircle(float radius, float density, Vector2 position = new Vector2(), BodyType bodyType = BodyType.Static)
{
Body body = CreateBody(position, 0, bodyType);
body.CreateCircle(radius, density);
return body;
}
public Body CreateEllipse(float xRadius, float yRadius, int edges, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Body body = CreateBody(position, rotation, bodyType);
body.CreateEllipse(xRadius, yRadius, edges, density);
return body;
}
public Body CreatePolygon(Vertices vertices, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Body body = CreateBody(position, rotation, bodyType);
body.CreatePolygon(vertices, density);
return body;
}
public Body CreateCompoundPolygon(List<Vertices> list, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
//We create a single body
Body body = CreateBody(position, rotation, bodyType);
body.CreateCompoundPolygon(list, density);
return body;
}
public Body CreateGear(float radius, int numberOfTeeth, float tipPercentage, float toothHeight, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Vertices gearPolygon = PolygonTools.CreateGear(radius, numberOfTeeth, tipPercentage, toothHeight);
//Gears can in some cases be convex
if (!gearPolygon.IsConvex())
{
//Decompose the gear:
List<Vertices> list = Triangulate.ConvexPartition(gearPolygon, TriangulationAlgorithm.Earclip);
return CreateCompoundPolygon(list, density, position, rotation, bodyType);
}
return CreatePolygon(gearPolygon, density, position, rotation, bodyType);
}
public Body CreateCapsule(float height, float topRadius, int topEdges, float bottomRadius, int bottomEdges, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Vertices verts = PolygonTools.CreateCapsule(height, topRadius, topEdges, bottomRadius, bottomEdges);
//There are too many vertices in the capsule. We decompose it.
if (verts.Count >= Settings.MaxPolygonVertices)
{
List<Vertices> vertList = Triangulate.ConvexPartition(verts, TriangulationAlgorithm.Earclip);
return CreateCompoundPolygon(vertList, density, position, rotation, bodyType);
}
return CreatePolygon(verts, density, position, rotation, bodyType);
}
public Body CreateCapsuleHorizontal(float width, float endRadius, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
//Create the middle rectangle
Vertices rectangle = PolygonTools.CreateRectangle(width / 2, endRadius);
List<Vertices> list = new List<Vertices>();
list.Add(rectangle);
Body body = CreateCompoundPolygon(list, density, position, rotation, bodyType);
body.CreateCircle(endRadius, density, new Vector2(width / 2, 0));
body.CreateCircle(endRadius, density, new Vector2(-width / 2, 0));
//Create the two circles
//CircleShape topCircle = new CircleShape(endRadius, density);
//topCircle.Position = new Vector2(0, height / 2);
//body.CreateFixture(topCircle);
//CircleShape bottomCircle = new CircleShape(endRadius, density);
//bottomCircle.Position = new Vector2(0, -(height / 2));
//body.CreateFixture(bottomCircle);
return body;
}
public Body CreateCapsule(float height, float endRadius, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
//Create the middle rectangle
Vertices rectangle = PolygonTools.CreateRectangle(endRadius, height / 2);
List<Vertices> list = new List<Vertices>();
list.Add(rectangle);
Body body = CreateCompoundPolygon(list, density, position, rotation, bodyType);
body.CreateCircle(endRadius, density, new Vector2(0, height / 2));
body.CreateCircle(endRadius, density, new Vector2(0, -(height / 2)));
//Create the two circles
//CircleShape topCircle = new CircleShape(endRadius, density);
//topCircle.Position = new Vector2(0, height / 2);
//body.CreateFixture(topCircle);
//CircleShape bottomCircle = new CircleShape(endRadius, density);
//bottomCircle.Position = new Vector2(0, -(height / 2));
//body.CreateFixture(bottomCircle);
return body;
}
public Body CreateRoundedRectangle(float width, float height, float xRadius, float yRadius, int segments, float density, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Vertices verts = PolygonTools.CreateRoundedRectangle(width, height, xRadius, yRadius, segments);
//There are too many vertices in the capsule. We decompose it.
if (verts.Count >= Settings.MaxPolygonVertices)
{
List<Vertices> vertList = Triangulate.ConvexPartition(verts, TriangulationAlgorithm.Earclip);
return CreateCompoundPolygon(vertList, density, position, rotation, bodyType);
}
return CreatePolygon(verts, density, position, rotation, bodyType);
}
public Body CreateLineArc(float radians, int sides, float radius, bool closed = false, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Body body = CreateBody(position, rotation, bodyType);
body.CreateLineArc(radians, sides, radius, closed);
return body;
}
public Body CreateSolidArc(float density, float radians, int sides, float radius, Vector2 position = new Vector2(), float rotation = 0, BodyType bodyType = BodyType.Static)
{
Body body = CreateBody(position, rotation, bodyType);
body.CreateSolidArc(density, radians, sides, radius);
return body;
}
/// <summary>
/// Creates a chain.
/// </summary>
/// <param name="world">The world.</param>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
/// <param name="linkWidth">The width.</param>
/// <param name="linkHeight">The height.</param>
/// <param name="numberOfLinks">The number of links.</param>
/// <param name="linkDensity">The link density.</param>
/// <param name="attachRopeJoint">Creates a rope joint between start and end. This enforces the length of the rope. Said in another way: it makes the rope less bouncy.</param>
/// <returns></returns>
public Path CreateChain(Vector2 start, Vector2 end, float linkWidth, float linkHeight, int numberOfLinks, float linkDensity, bool attachRopeJoint)
{
System.Diagnostics.Debug.Assert(numberOfLinks >= 2);
//Chain start / end
Path path = new Path();
path.Add(start);
path.Add(end);
//A single chainlink
PolygonShape shape = new PolygonShape(PolygonTools.CreateRectangle(linkWidth, linkHeight), linkDensity);
//Use PathManager to create all the chainlinks based on the chainlink created before.
List<Body> chainLinks = PathManager.EvenlyDistributeShapesAlongPath(this, path, shape, BodyType.Dynamic, numberOfLinks);
//TODO
//if (fixStart)
//{
// //Fix the first chainlink to the world
// JointFactory.CreateFixedRevoluteJoint(this, chainLinks[0], new Vector2(0, -(linkHeight / 2)),
// chainLinks[0].Position);
//}
//if (fixEnd)
//{
// //Fix the last chainlink to the world
// JointFactory.CreateFixedRevoluteJoint(this, chainLinks[chainLinks.Count - 1],
// new Vector2(0, (linkHeight / 2)),
// chainLinks[chainLinks.Count - 1].Position);
//}
//Attach all the chainlinks together with a revolute joint
PathManager.AttachBodiesWithRevoluteJoint(this, chainLinks, new Vector2(0, -linkHeight), new Vector2(0, linkHeight), false, false);
if (attachRopeJoint)
JointFactory.CreateRopeJoint(this, chainLinks[0], chainLinks[chainLinks.Count - 1], Vector2.Zero, Vector2.Zero);
return path;
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,11 @@
/*
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -41,23 +48,23 @@ namespace FarseerPhysics.Dynamics
public delegate void PostSolveDelegate(Contact contact, ContactVelocityConstraint impulse);
public delegate void FixtureDelegate(Fixture fixture);
public delegate void FixtureDelegate(World sender, Body body, Fixture fixture);
public delegate void JointDelegate(Joint joint);
public delegate void JointDelegate(World sender, Joint joint);
public delegate void BodyDelegate(Body body);
public delegate void BodyDelegate(World sender, Body body);
public delegate void ControllerDelegate(Controller controller);
public delegate void ControllerDelegate(World sender, Controller controller);
public delegate bool CollisionFilterDelegate(Fixture fixtureA, Fixture fixtureB);
public delegate void BroadphaseDelegate(ref FixtureProxy proxyA, ref FixtureProxy proxyB);
public delegate void BroadphaseDelegate(int proxyIdA, int proxyIdB);
public delegate bool BeforeCollisionEventHandler(Fixture fixtureA, Fixture fixtureB);
public delegate bool BeforeCollisionEventHandler(Fixture sender, Fixture other);
public delegate bool OnCollisionEventHandler(Fixture fixtureA, Fixture fixtureB, Contact contact);
public delegate bool OnCollisionEventHandler(Fixture sender, Fixture other, Contact contact);
public delegate void AfterCollisionEventHandler(Fixture fixtureA, Fixture fixtureB, Contact contact, ContactVelocityConstraint impulse);
public delegate void AfterCollisionEventHandler(Fixture sender, Fixture other, Contact contact, ContactVelocityConstraint impulse);
public delegate void OnSeparationEventHandler(Fixture fixtureA, Fixture fixtureB);
public delegate void OnSeparationEventHandler(Fixture sender, Fixture other, Contact contact);
}