summaryrefslogtreecommitdiff
path: root/Box2d/Assets/Program
diff options
context:
space:
mode:
Diffstat (limited to 'Box2d/Assets/Program')
-rw-r--r--Box2d/Assets/Program/Box2d/Box2DXDebug.cs67
-rw-r--r--Box2d/Assets/Program/Box2d/Box2DXDebug.cs.meta (renamed from Box2d/Assets/Program/Box2d/Box2d.cs.meta)2
-rw-r--r--Box2d/Assets/Program/Box2d/Box2d.cs10
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs1183
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs.meta (renamed from Box2d/Assets/Program/Box2d/Rope/Rope.cs.meta)2
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs155
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs.meta (renamed from Box2d/Assets/Program/Box2d/Common/Transform.cs.meta)2
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs100
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs309
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs630
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs378
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Collision.cs624
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/PairManager.cs493
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/PairManager.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs179
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs277
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/PolygonShape.cs723
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs144
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/TODO.txt1
-rw-r--r--Box2d/Assets/Program/Box2d/Collision/TODO.txt.meta7
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Mat22.cs243
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Mat33.cs93
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Math.cs288
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Settings.cs181
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Settings.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Sweep.cs68
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Transform.cs23
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Vec2.cs339
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Vec3.cs177
-rw-r--r--Box2d/Assets/Program/Box2d/Common/Vec3.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Common/XForm.cs72
-rw-r--r--Box2d/Assets/Program/Box2d/Common/XForm.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Body.cs1069
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs232
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs52
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/Contact.cs375
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs712
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs55
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs35
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs52
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs52
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs52
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers.meta (renamed from Box2d/Assets/Program/Box2d/Rope.meta)2
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs156
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs56
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs57
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs174
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs96
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs89
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs478
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Island.cs522
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Island.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs277
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs322
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/Joint.cs313
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs710
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs229
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs756
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs566
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs636
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/World.cs1448
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/World.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs240
-rw-r--r--Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs.meta11
-rw-r--r--Box2d/Assets/Program/Box2d/Rope/Rope.cs7
94 files changed, 16606 insertions, 380 deletions
diff --git a/Box2d/Assets/Program/Box2d/Box2DXDebug.cs b/Box2d/Assets/Program/Box2d/Box2DXDebug.cs
new file mode 100644
index 0000000..49013a6
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Box2DXDebug.cs
@@ -0,0 +1,67 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Text;
+using System.Diagnostics;
+using System.Collections.Generic;
+
+namespace Box2DX
+{
+ public static class Box2DXDebug
+ {
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition)
+ {
+ if (!condition)
+ {
+ condition = condition;
+ }
+ Debug.Assert(condition);
+ }
+
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition, string message)
+ {
+ if (!condition)
+ {
+ condition = condition;
+ }
+ Debug.Assert(condition, message);
+ }
+
+ [Conditional("DEBUG")]
+ public static void Assert(bool condition, string message, string detailMessage)
+ {
+ if (!condition)
+ {
+ condition = condition;
+ }
+ Debug.Assert(condition, message, detailMessage);
+ }
+
+ public static void ThrowBox2DXException(String message)
+ {
+ string msg = String.Format("Error: {0}", message);
+ throw new Exception(msg);
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Box2d.cs.meta b/Box2d/Assets/Program/Box2d/Box2DXDebug.cs.meta
index 3e25ab6..eb18c32 100644
--- a/Box2d/Assets/Program/Box2d/Box2d.cs.meta
+++ b/Box2d/Assets/Program/Box2d/Box2DXDebug.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 7d074173b374c384397568691e8bbb72
+guid: 5f18711c9f994954bbce75799319eb0f
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Box2d/Assets/Program/Box2d/Box2d.cs b/Box2d/Assets/Program/Box2d/Box2d.cs
deleted file mode 100644
index 48acd74..0000000
--- a/Box2d/Assets/Program/Box2d/Box2d.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-
-namespace Box2D
-{
- ///////////////////////////////////
- // Box2D C# port
- // author: chai
- ///////////////////////////////////
-}
diff --git a/Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs b/Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs
new file mode 100644
index 0000000..8a9e4c9
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs
@@ -0,0 +1,1183 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/*
+This broad phase uses the Sweep and Prune algorithm as described in:
+Collision Detection in Interactive 3D Environments by Gino van den Bergen
+Also, some ideas, such as using integral values for fast compares comes from
+Bullet (http:/www.bulletphysics.com).
+*/
+
+// Notes:
+// - we use bound arrays instead of linked lists for cache coherence.
+// - we use quantized integral values for fast compares.
+// - we use short indices rather than pointers to save memory.
+// - we use a stabbing count for fast overlap queries (less than order N).
+// - we also use a time stamp on each proxy to speed up the registration of
+// overlap query results.
+// - where possible, we compare bound indices instead of values to reduce
+// cache misses (TODO_ERIN).
+// - no broadphase is perfect and neither is this one: it is not great for huge
+// worlds (use a multi-SAP instead), it is not great for large objects.
+
+#define ALLOWUNSAFE
+//#define TARGET_FLOAT32_IS_FIXED
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public delegate float SortKeyFunc(object shape);
+
+#warning "CAS"
+ public class BoundValues
+ {
+ public ushort[/*2*/] LowerValues = new ushort[2];
+ public ushort[/*2*/] UpperValues = new ushort[2];
+ }
+#warning "CAS"
+ public class Bound
+ {
+ public bool IsLower { get { return (Value & (ushort)1) == (ushort)0; } }
+ public bool IsUpper { get { return (Value & (ushort)1) == (ushort)1; } }
+
+ public ushort Value;
+ public ushort ProxyId;
+ public ushort StabbingCount;
+
+ public Bound Clone()
+ {
+ Bound newBound = new Bound();
+ newBound.Value = this.Value;
+ newBound.ProxyId = this.ProxyId;
+ newBound.StabbingCount = this.StabbingCount;
+ return newBound;
+ }
+ }
+#warning "CAS"
+ public class Proxy
+ {
+ public ushort[/*2*/] LowerBounds = new ushort[2], UpperBounds = new ushort[2];
+ public ushort OverlapCount;
+ public ushort TimeStamp;
+ public object UserData;
+
+ public ushort Next
+ {
+ get { return LowerBounds[0]; }
+ set { LowerBounds[0] = value; }
+ }
+
+ public bool IsValid { get { return OverlapCount != BroadPhase.Invalid; } }
+ }
+
+ public class BroadPhase
+ {
+#if TARGET_FLOAT32_IS_FIXED
+ public static readonly ushort BROADPHASE_MAX = (Common.Math.USHRT_MAX/2);
+#else
+ public static readonly ushort BROADPHASE_MAX = Common.Math.USHRT_MAX;
+#endif
+
+ public static readonly ushort Invalid = BROADPHASE_MAX;
+ public static readonly ushort NullEdge = BROADPHASE_MAX;
+
+ public PairManager _pairManager;
+
+ public Proxy[] _proxyPool = new Proxy[Settings.MaxProxies];
+ public ushort _freeProxy;
+
+ public Bound[][] _bounds = new Bound[2][/*(2 * Settings.MaxProxies)*/];
+
+ public ushort[] _queryResults = new ushort[Settings.MaxProxies];
+ public float[] _querySortKeys = new float[Settings.MaxProxies];
+ public int _queryResultCount;
+
+ public AABB _worldAABB;
+ public Vec2 _quantizationFactor;
+ public int _proxyCount;
+ public ushort _timeStamp;
+
+ public static bool IsValidate = false;
+
+ public BroadPhase(AABB worldAABB, PairCallback callback)
+ {
+ _pairManager = new PairManager();
+ _pairManager.Initialize(this, callback);
+
+ Box2DXDebug.Assert(worldAABB.IsValid);
+ _worldAABB = worldAABB;
+ _proxyCount = 0;
+
+ Vec2 d = worldAABB.UpperBound - worldAABB.LowerBound;
+ _quantizationFactor.X = (float)BROADPHASE_MAX / d.X;
+ _quantizationFactor.Y = (float)BROADPHASE_MAX / d.Y;
+
+ for (ushort i = 0; i < Settings.MaxProxies - 1; ++i)
+ {
+ _proxyPool[i] = new Proxy();
+ _proxyPool[i].Next = (ushort)(i + 1);
+ _proxyPool[i].TimeStamp = 0;
+ _proxyPool[i].OverlapCount = BroadPhase.Invalid;
+ _proxyPool[i].UserData = null;
+ }
+ _proxyPool[Settings.MaxProxies - 1] = new Proxy();
+ _proxyPool[Settings.MaxProxies - 1].Next = PairManager.NullProxy;
+ _proxyPool[Settings.MaxProxies - 1].TimeStamp = 0;
+ _proxyPool[Settings.MaxProxies - 1].OverlapCount = BroadPhase.Invalid;
+ _proxyPool[Settings.MaxProxies - 1].UserData = null;
+ _freeProxy = 0;
+
+ _timeStamp = 1;
+ _queryResultCount = 0;
+
+ for (int i = 0; i < 2; i++)
+ {
+ _bounds[i] = new Bound[(2 * Settings.MaxProxies)];
+ }
+
+ int bCount = 2 * Settings.MaxProxies;
+ for (int j = 0; j < 2; j++)
+ for (int k = 0; k < bCount; k++)
+ _bounds[j][k] = new Bound();
+ }
+
+ // Use this to see if your proxy is in range. If it is not in range,
+ // it should be destroyed. Otherwise you may get O(m^2) pairs, where m
+ // is the number of proxies that are out of range.
+ public bool InRange(AABB aabb)
+ {
+ Vec2 d = Common.Math.Max(aabb.LowerBound - _worldAABB.UpperBound, _worldAABB.LowerBound - aabb.UpperBound);
+ return Common.Math.Max(d.X, d.Y) < 0.0f;
+ }
+
+ // Create and destroy proxies. These call Flush first.
+ public ushort CreateProxy(AABB aabb, object userData)
+ {
+ Box2DXDebug.Assert(_proxyCount < Settings.MaxProxies);
+ Box2DXDebug.Assert(_freeProxy != PairManager.NullProxy);
+
+ ushort proxyId = _freeProxy;
+ Proxy proxy = _proxyPool[proxyId];
+ _freeProxy = proxy.Next;
+
+ proxy.OverlapCount = 0;
+ proxy.UserData = userData;
+
+ int boundCount = 2 * _proxyCount;
+
+ ushort[] lowerValues = new ushort[2], upperValues = new ushort[2];
+ ComputeBounds(out lowerValues, out upperValues, aabb);
+
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+ int lowerIndex, upperIndex;
+ Query(out lowerIndex, out upperIndex, lowerValues[axis], upperValues[axis], bounds, boundCount, axis);
+
+#warning "Check this"
+ //memmove(bounds + upperIndex + 2, bounds + upperIndex, (boundCount - upperIndex) * sizeof(b2Bound));
+ Bound[] tmp = new Bound[boundCount - upperIndex];
+ for (int i = 0; i < (boundCount - upperIndex); i++)
+ {
+ tmp[i] = bounds[upperIndex + i].Clone();
+ }
+ for (int i = 0; i < (boundCount - upperIndex); i++)
+ {
+ bounds[upperIndex + 2 + i] = tmp[i];
+ }
+
+ //memmove(bounds + lowerIndex + 1, bounds + lowerIndex, (upperIndex - lowerIndex) * sizeof(b2Bound));
+ tmp = new Bound[upperIndex - lowerIndex];
+ for (int i = 0; i < (upperIndex - lowerIndex); i++)
+ {
+ tmp[i] = bounds[lowerIndex + i].Clone();
+ }
+ for (int i = 0; i < (upperIndex - lowerIndex); i++)
+ {
+ bounds[lowerIndex + 1 + i] = tmp[i];
+ }
+
+ // The upper index has increased because of the lower bound insertion.
+ ++upperIndex;
+
+ // Copy in the new bounds.
+ bounds[lowerIndex].Value = lowerValues[axis];
+ bounds[lowerIndex].ProxyId = proxyId;
+ bounds[upperIndex].Value = upperValues[axis];
+ bounds[upperIndex].ProxyId = proxyId;
+
+ bounds[lowerIndex].StabbingCount = lowerIndex == 0 ? (ushort)0 : bounds[lowerIndex - 1].StabbingCount;
+ bounds[upperIndex].StabbingCount = bounds[upperIndex - 1].StabbingCount;
+
+ // Adjust the stabbing count between the new bounds.
+ for (int index = lowerIndex; index < upperIndex; ++index)
+ {
+ ++bounds[index].StabbingCount;
+ }
+
+ // Adjust the all the affected bound indices.
+ for (int index = lowerIndex; index < boundCount + 2; ++index)
+ {
+ Proxy proxy_ = _proxyPool[bounds[index].ProxyId];
+ if (bounds[index].IsLower)
+ {
+ proxy_.LowerBounds[axis] = (ushort)index;
+ }
+ else
+ {
+ proxy_.UpperBounds[axis] = (ushort)index;
+ }
+ }
+ }
+
+ ++_proxyCount;
+
+ Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);
+
+ // Create pairs if the AABB is in range.
+ for (int i = 0; i < _queryResultCount; ++i)
+ {
+ Box2DXDebug.Assert(_queryResults[i] < Settings.MaxProxies);
+ Box2DXDebug.Assert(_proxyPool[_queryResults[i]].IsValid);
+
+ _pairManager.AddBufferedPair(proxyId, _queryResults[i]);
+ }
+
+ _pairManager.Commit();
+
+ if (IsValidate)
+ {
+ Validate();
+ }
+
+ // Prepare for next query.
+ _queryResultCount = 0;
+ IncrementTimeStamp();
+
+ return proxyId;
+ }
+
+ public void DestroyProxy(int proxyId)
+ {
+ Box2DXDebug.Assert(0 < _proxyCount && _proxyCount <= Settings.MaxProxies);
+ Proxy proxy = _proxyPool[proxyId];
+ Box2DXDebug.Assert(proxy.IsValid);
+
+ int boundCount = 2 * _proxyCount;
+
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+
+ int lowerIndex = proxy.LowerBounds[axis];
+ int upperIndex = proxy.UpperBounds[axis];
+ ushort lowerValue = bounds[lowerIndex].Value;
+ ushort upperValue = bounds[upperIndex].Value;
+
+#warning "Check this"
+ //memmove(bounds + lowerIndex, bounds + lowerIndex + 1, (upperIndex - lowerIndex - 1) * sizeof(b2Bound));
+ Bound[] tmp = new Bound[upperIndex - lowerIndex - 1];
+ for (int i = 0; i < (upperIndex - lowerIndex - 1); i++)
+ {
+ tmp[i] = bounds[lowerIndex + 1 + i].Clone();
+ }
+ for (int i = 0; i < (upperIndex - lowerIndex - 1); i++)
+ {
+ bounds[lowerIndex + i] = tmp[i];
+ }
+
+ //memmove(bounds + upperIndex - 1, bounds + upperIndex + 1, (boundCount - upperIndex - 1) * sizeof(b2Bound));
+ tmp = new Bound[boundCount - upperIndex - 1];
+ for (int i = 0; i < (boundCount - upperIndex - 1); i++)
+ {
+ tmp[i] = bounds[upperIndex + 1 + i].Clone();
+ }
+ for (int i = 0; i < (boundCount - upperIndex - 1); i++)
+ {
+ bounds[upperIndex - 1 + i] = tmp[i];
+ }
+
+ // Fix bound indices.
+ for (int index = lowerIndex; index < boundCount - 2; ++index)
+ {
+ Proxy proxy_ = _proxyPool[bounds[index].ProxyId];
+ if (bounds[index].IsLower)
+ {
+ proxy_.LowerBounds[axis] = (ushort)index;
+ }
+ else
+ {
+ proxy_.UpperBounds[axis] = (ushort)index;
+ }
+ }
+
+ // Fix stabbing count.
+ for (int index = lowerIndex; index < upperIndex - 1; ++index)
+ {
+ --bounds[index].StabbingCount;
+ }
+
+ // Query for pairs to be removed. lowerIndex and upperIndex are not needed.
+ Query(out lowerIndex, out upperIndex, lowerValue, upperValue, bounds, boundCount - 2, axis);
+ }
+
+ Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);
+
+ for (int i = 0; i < _queryResultCount; ++i)
+ {
+ Box2DXDebug.Assert(_proxyPool[_queryResults[i]].IsValid);
+ _pairManager.RemoveBufferedPair(proxyId, _queryResults[i]);
+ }
+
+ _pairManager.Commit();
+
+ // Prepare for next query.
+ _queryResultCount = 0;
+ IncrementTimeStamp();
+
+ // Return the proxy to the pool.
+ proxy.UserData = null;
+ proxy.OverlapCount = BroadPhase.Invalid;
+ proxy.LowerBounds[0] = BroadPhase.Invalid;
+ proxy.LowerBounds[1] = BroadPhase.Invalid;
+ proxy.UpperBounds[0] = BroadPhase.Invalid;
+ proxy.UpperBounds[1] = BroadPhase.Invalid;
+
+ proxy.Next = _freeProxy;
+ _freeProxy = (ushort)proxyId;
+ --_proxyCount;
+
+ if (IsValidate)
+ {
+ Validate();
+ }
+ }
+
+ // Call MoveProxy as many times as you like, then when you are done
+ // call Commit to finalized the proxy pairs (for your time step).
+ public void MoveProxy(int proxyId, AABB aabb)
+ {
+ if (proxyId == PairManager.NullProxy || Settings.MaxProxies <= proxyId)
+ {
+ Box2DXDebug.Assert(false);
+ return;
+ }
+
+ if (aabb.IsValid == false)
+ {
+ Box2DXDebug.Assert(false);
+ return;
+ }
+
+ int boundCount = 2 * _proxyCount;
+
+ Proxy proxy = _proxyPool[proxyId];
+
+ // Get new bound values
+ BoundValues newValues = new BoundValues(); ;
+ ComputeBounds(out newValues.LowerValues, out newValues.UpperValues, aabb);
+
+ // Get old bound values
+ BoundValues oldValues = new BoundValues();
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ oldValues.LowerValues[axis] = _bounds[axis][proxy.LowerBounds[axis]].Value;
+ oldValues.UpperValues[axis] = _bounds[axis][proxy.UpperBounds[axis]].Value;
+ }
+
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+
+ int lowerIndex = proxy.LowerBounds[axis];
+ int upperIndex = proxy.UpperBounds[axis];
+
+ ushort lowerValue = newValues.LowerValues[axis];
+ ushort upperValue = newValues.UpperValues[axis];
+
+ int deltaLower = lowerValue - bounds[lowerIndex].Value;
+ int deltaUpper = upperValue - bounds[upperIndex].Value;
+
+ bounds[lowerIndex].Value = lowerValue;
+ bounds[upperIndex].Value = upperValue;
+
+ //
+ // Expanding adds overlaps
+ //
+
+ // Should we move the lower bound down?
+ if (deltaLower < 0)
+ {
+ int index = lowerIndex;
+ while (index > 0 && lowerValue < bounds[index - 1].Value)
+ {
+ Bound bound = bounds[index];
+ Bound prevBound = bounds[index - 1];
+
+ int prevProxyId = prevBound.ProxyId;
+ Proxy prevProxy = _proxyPool[prevBound.ProxyId];
+
+ ++prevBound.StabbingCount;
+
+ if (prevBound.IsUpper == true)
+ {
+ if (TestOverlap(newValues, prevProxy))
+ {
+ _pairManager.AddBufferedPair(proxyId, prevProxyId);
+ }
+
+ ++prevProxy.UpperBounds[axis];
+ ++bound.StabbingCount;
+ }
+ else
+ {
+ ++prevProxy.LowerBounds[axis];
+ --bound.StabbingCount;
+ }
+
+ --proxy.LowerBounds[axis];
+ Common.Math.Swap<Bound>(ref bounds[index], ref bounds[index - 1]);
+ --index;
+ }
+ }
+
+ // Should we move the upper bound up?
+ if (deltaUpper > 0)
+ {
+ int index = upperIndex;
+ while (index < boundCount - 1 && bounds[index + 1].Value <= upperValue)
+ {
+ Bound bound = bounds[index];
+ Bound nextBound = bounds[index + 1];
+ int nextProxyId = nextBound.ProxyId;
+ Proxy nextProxy = _proxyPool[nextProxyId];
+
+ ++nextBound.StabbingCount;
+
+ if (nextBound.IsLower == true)
+ {
+ if (TestOverlap(newValues, nextProxy))
+ {
+ _pairManager.AddBufferedPair(proxyId, nextProxyId);
+ }
+
+ --nextProxy.LowerBounds[axis];
+ ++bound.StabbingCount;
+ }
+ else
+ {
+ --nextProxy.UpperBounds[axis];
+ --bound.StabbingCount;
+ }
+
+ ++proxy.UpperBounds[axis];
+ Common.Math.Swap<Bound>(ref bounds[index], ref bounds[index + 1]);
+ ++index;
+ }
+ }
+
+ //
+ // Shrinking removes overlaps
+ //
+
+ // Should we move the lower bound up?
+ if (deltaLower > 0)
+ {
+ int index = lowerIndex;
+ while (index < boundCount - 1 && bounds[index + 1].Value <= lowerValue)
+ {
+ Bound bound = bounds[index];
+ Bound nextBound = bounds[index + 1];
+
+ int nextProxyId = nextBound.ProxyId;
+ Proxy nextProxy = _proxyPool[nextProxyId];
+
+ --nextBound.StabbingCount;
+
+ if (nextBound.IsUpper)
+ {
+ if (TestOverlap(oldValues, nextProxy))
+ {
+ _pairManager.RemoveBufferedPair(proxyId, nextProxyId);
+ }
+
+ --nextProxy.UpperBounds[axis];
+ --bound.StabbingCount;
+ }
+ else
+ {
+ --nextProxy.LowerBounds[axis];
+ ++bound.StabbingCount;
+ }
+
+ ++proxy.LowerBounds[axis];
+ Common.Math.Swap<Bound>(ref bounds[index], ref bounds[index + 1]);
+ ++index;
+ }
+ }
+
+ // Should we move the upper bound down?
+ if (deltaUpper < 0)
+ {
+ int index = upperIndex;
+ while (index > 0 && upperValue < bounds[index - 1].Value)
+ {
+ Bound bound = bounds[index];
+ Bound prevBound = bounds[index - 1];
+
+ int prevProxyId = prevBound.ProxyId;
+ Proxy prevProxy = _proxyPool[prevProxyId];
+
+ --prevBound.StabbingCount;
+
+ if (prevBound.IsLower == true)
+ {
+ if (TestOverlap(oldValues, prevProxy))
+ {
+ _pairManager.RemoveBufferedPair(proxyId, prevProxyId);
+ }
+
+ ++prevProxy.LowerBounds[axis];
+ --bound.StabbingCount;
+ }
+ else
+ {
+ ++prevProxy.UpperBounds[axis];
+ ++bound.StabbingCount;
+ }
+
+ --proxy.UpperBounds[axis];
+ Common.Math.Swap<Bound>(ref bounds[index], ref bounds[index - 1]);
+ --index;
+ }
+ }
+ }
+
+ if (IsValidate)
+ {
+ Validate();
+ }
+ }
+
+ public void Commit()
+ {
+ _pairManager.Commit();
+ }
+
+ // Get a single proxy. Returns NULL if the id is invalid.
+ public Proxy GetProxy(int proxyId)
+ {
+ if (proxyId == PairManager.NullProxy || _proxyPool[proxyId].IsValid == false)
+ {
+ return null;
+ }
+
+ return _proxyPool[proxyId];
+ }
+
+ // Query an AABB for overlapping proxies, returns the user data and
+ // the count, up to the supplied maximum count.
+ public int Query(AABB aabb, object[] userData, int maxCount)
+ {
+ ushort[] lowerValues;
+ ushort[] upperValues;
+ ComputeBounds(out lowerValues, out upperValues, aabb);
+
+ int lowerIndex, upperIndex;
+
+ Query(out lowerIndex, out upperIndex, lowerValues[0], upperValues[0], _bounds[0], 2 * _proxyCount, 0);
+ Query(out lowerIndex, out upperIndex, lowerValues[1], upperValues[1], _bounds[1], 2 * _proxyCount, 1);
+
+ Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);
+
+ int count = 0;
+ for (int i = 0; i < _queryResultCount && count < maxCount; ++i, ++count)
+ {
+ Box2DXDebug.Assert(_queryResults[i] < Settings.MaxProxies);
+ Proxy proxy = _proxyPool[_queryResults[i]];
+ Box2DXDebug.Assert(proxy.IsValid);
+ userData[i] = proxy.UserData;
+ }
+
+ // Prepare for next query.
+ _queryResultCount = 0;
+ IncrementTimeStamp();
+
+ return count;
+ }
+
+ /// <summary>
+ /// Query a segment for overlapping proxies, returns the user data and
+ /// the count, up to the supplied maximum count.
+ /// If sortKey is provided, then it is a function mapping from proxy userDatas to distances along the segment (between 0 & 1)
+ /// Then the returned proxies are sorted on that, before being truncated to maxCount
+ /// The sortKey of a proxy is assumed to be larger than the closest point inside the proxy along the segment, this allows for early exits
+ /// Proxies with a negative sortKey are discarded
+ /// </summary>
+ public
+#if ALLOWUNSAFE
+ unsafe
+#endif //#if ALLOWUNSAFE
+ int QuerySegment(Segment segment, object[] userData, int maxCount, SortKeyFunc sortKey)
+ {
+ float maxLambda = 1;
+
+ float dx = (segment.P2.X - segment.P1.X) * _quantizationFactor.X;
+ float dy = (segment.P2.Y - segment.P1.Y) * _quantizationFactor.Y;
+
+ int sx = dx < -Settings.FLT_EPSILON ? -1 : (dx > Settings.FLT_EPSILON ? 1 : 0);
+ int sy = dy < -Settings.FLT_EPSILON ? -1 : (dy > Settings.FLT_EPSILON ? 1 : 0);
+
+ Box2DXDebug.Assert(sx != 0 || sy != 0);
+
+ float p1x = (segment.P1.X - _worldAABB.LowerBound.X) * _quantizationFactor.X;
+ float p1y = (segment.P1.Y - _worldAABB.LowerBound.Y) * _quantizationFactor.Y;
+#if ALLOWUNSAFE
+ ushort* startValues = stackalloc ushort[2];
+ ushort* startValues2 = stackalloc ushort[2];
+#else
+ ushort[] startValues = new ushort[2];
+ ushort[] startValues2 = new ushort[2];
+#endif
+
+ int xIndex;
+ int yIndex;
+
+ ushort proxyId;
+ Proxy proxy;
+
+ // TODO_ERIN implement fast float to ushort conversion.
+ startValues[0] = (ushort)((ushort)(p1x) & (BROADPHASE_MAX - 1));
+ startValues2[0] = (ushort)((ushort)(p1x) | 1);
+
+ startValues[1] = (ushort)((ushort)(p1y) & (BROADPHASE_MAX - 1));
+ startValues2[1] = (ushort)((ushort)(p1y) | 1);
+
+ //First deal with all the proxies that contain segment.p1
+ int lowerIndex;
+ int upperIndex;
+ Query(out lowerIndex, out upperIndex, startValues[0], startValues2[0], _bounds[0], 2 * _proxyCount, 0);
+ if (sx >= 0) xIndex = upperIndex - 1;
+ else xIndex = lowerIndex;
+ Query(out lowerIndex, out upperIndex, startValues[1], startValues2[1], _bounds[1], 2 * _proxyCount, 1);
+ if (sy >= 0) yIndex = upperIndex - 1;
+ else yIndex = lowerIndex;
+
+ //If we are using sortKey, then sort what we have so far, filtering negative keys
+ if (sortKey != null)
+ {
+ //Fill keys
+ for (int j = 0; j < _queryResultCount; j++)
+ {
+ _querySortKeys[j] = sortKey(_proxyPool[_queryResults[j]].UserData);
+ }
+ //Bubble sort keys
+ //Sorting negative values to the top, so we can easily remove them
+ int i = 0;
+ while (i < _queryResultCount - 1)
+ {
+ float a = _querySortKeys[i];
+ float b = _querySortKeys[i + 1];
+ if ((a < 0) ? (b >= 0) : (a > b && b >= 0))
+ {
+ _querySortKeys[i + 1] = a;
+ _querySortKeys[i] = b;
+ ushort tempValue = _queryResults[i + 1];
+ _queryResults[i + 1] = _queryResults[i];
+ _queryResults[i] = tempValue;
+ i--;
+ if (i == -1) i = 1;
+ }
+ else
+ {
+ i++;
+ }
+ }
+ //Skim off negative values
+ while (_queryResultCount > 0 && _querySortKeys[_queryResultCount - 1] < 0)
+ _queryResultCount--;
+ }
+
+ //Now work through the rest of the segment
+ for (; ; )
+ {
+ float xProgress = 0;
+ float yProgress = 0;
+ if (xIndex < 0 || xIndex >= _proxyCount * 2)
+ break;
+ if (yIndex < 0 || yIndex >= _proxyCount * 2)
+ break;
+ if (sx != 0)
+ {
+ //Move on to the next bound
+ if (sx > 0)
+ {
+ xIndex++;
+ if (xIndex == _proxyCount * 2)
+ break;
+ }
+ else
+ {
+ xIndex--;
+ if (xIndex < 0)
+ break;
+ }
+ xProgress = (_bounds[0][xIndex].Value - p1x) / dx;
+ }
+ if (sy != 0)
+ {
+ //Move on to the next bound
+ if (sy > 0)
+ {
+ yIndex++;
+ if (yIndex == _proxyCount * 2)
+ break;
+ }
+ else
+ {
+ yIndex--;
+ if (yIndex < 0)
+ break;
+ }
+ yProgress = (_bounds[1][yIndex].Value - p1y) / dy;
+ }
+ for (; ; )
+ {
+ if (sy == 0 || (sx != 0 && xProgress < yProgress))
+ {
+ if (xProgress > maxLambda)
+ break;
+
+ //Check that we are entering a proxy, not leaving
+ if (sx > 0 ? _bounds[0][xIndex].IsLower : _bounds[0][xIndex].IsUpper)
+ {
+ //Check the other axis of the proxy
+ proxyId = _bounds[0][xIndex].ProxyId;
+ proxy = _proxyPool[proxyId];
+ if (sy >= 0)
+ {
+ if (proxy.LowerBounds[1] <= yIndex - 1 && proxy.UpperBounds[1] >= yIndex)
+ {
+ //Add the proxy
+ if (sortKey != null)
+ {
+ AddProxyResult(proxyId, proxy, maxCount, sortKey);
+ }
+ else
+ {
+ _queryResults[_queryResultCount] = proxyId;
+ ++_queryResultCount;
+ }
+ }
+ }
+ else
+ {
+ if (proxy.LowerBounds[1] <= yIndex && proxy.UpperBounds[1] >= yIndex + 1)
+ {
+ //Add the proxy
+ if (sortKey != null)
+ {
+ AddProxyResult(proxyId, proxy, maxCount, sortKey);
+ }
+ else
+ {
+ _queryResults[_queryResultCount] = proxyId;
+ ++_queryResultCount;
+ }
+ }
+ }
+ }
+
+ //Early out
+ if (sortKey != null && _queryResultCount == maxCount && _queryResultCount > 0 && xProgress > _querySortKeys[_queryResultCount - 1])
+ break;
+
+ //Move on to the next bound
+ if (sx > 0)
+ {
+ xIndex++;
+ if (xIndex == _proxyCount * 2)
+ break;
+ }
+ else
+ {
+ xIndex--;
+ if (xIndex < 0)
+ break;
+ }
+ xProgress = (_bounds[0][xIndex].Value - p1x) / dx;
+ }
+ else
+ {
+ if (yProgress > maxLambda)
+ break;
+
+ //Check that we are entering a proxy, not leaving
+ if (sy > 0 ? _bounds[1][yIndex].IsLower : _bounds[1][yIndex].IsUpper)
+ {
+ //Check the other axis of the proxy
+ proxyId = _bounds[1][yIndex].ProxyId;
+ proxy = _proxyPool[proxyId];
+ if (sx >= 0)
+ {
+ if (proxy.LowerBounds[0] <= xIndex - 1 && proxy.UpperBounds[0] >= xIndex)
+ {
+ //Add the proxy
+ if (sortKey != null)
+ {
+ AddProxyResult(proxyId, proxy, maxCount, sortKey);
+ }
+ else
+ {
+ _queryResults[_queryResultCount] = proxyId;
+ ++_queryResultCount;
+ }
+ }
+ }
+ else
+ {
+ if (proxy.LowerBounds[0] <= xIndex && proxy.UpperBounds[0] >= xIndex + 1)
+ {
+ //Add the proxy
+ if (sortKey != null)
+ {
+ AddProxyResult(proxyId, proxy, maxCount, sortKey);
+ }
+ else
+ {
+ _queryResults[_queryResultCount] = proxyId;
+ ++_queryResultCount;
+ }
+ }
+ }
+ }
+
+ //Early out
+ if (sortKey != null && _queryResultCount == maxCount && _queryResultCount > 0 && yProgress > _querySortKeys[_queryResultCount - 1])
+ break;
+
+ //Move on to the next bound
+ if (sy > 0)
+ {
+ yIndex++;
+ if (yIndex == _proxyCount * 2)
+ break;
+ }
+ else
+ {
+ yIndex--;
+ if (yIndex < 0)
+ break;
+ }
+ yProgress = (_bounds[1][yIndex].Value - p1y) / dy;
+ }
+ }
+
+ break;
+ }
+
+ int count = 0;
+ for (int i = 0; i < _queryResultCount && count < maxCount; ++i, ++count)
+ {
+ Box2DXDebug.Assert(_queryResults[i] < Settings.MaxProxies);
+ Proxy proxy_ = _proxyPool[_queryResults[i]];
+ Box2DXDebug.Assert(proxy_.IsValid);
+ userData[i] = proxy_.UserData;
+ }
+
+ // Prepare for next query.
+ _queryResultCount = 0;
+ IncrementTimeStamp();
+
+ return count;
+ }
+
+ public void Validate()
+ {
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+
+ int boundCount = 2 * _proxyCount;
+ ushort stabbingCount = 0;
+
+ for (int i = 0; i < boundCount; ++i)
+ {
+ Bound bound = bounds[i];
+ Box2DXDebug.Assert(i == 0 || bounds[i - 1].Value <= bound.Value);
+ Box2DXDebug.Assert(bound.ProxyId != PairManager.NullProxy);
+ Box2DXDebug.Assert(_proxyPool[bound.ProxyId].IsValid);
+
+ if (bound.IsLower == true)
+ {
+ Box2DXDebug.Assert(_proxyPool[bound.ProxyId].LowerBounds[axis] == i);
+ ++stabbingCount;
+ }
+ else
+ {
+ Box2DXDebug.Assert(_proxyPool[bound.ProxyId].UpperBounds[axis] == i);
+ --stabbingCount;
+ }
+
+ Box2DXDebug.Assert(bound.StabbingCount == stabbingCount);
+ }
+ }
+ }
+
+ private void ComputeBounds(out ushort[] lowerValues, out ushort[] upperValues, AABB aabb)
+ {
+ lowerValues = new ushort[2];
+ upperValues = new ushort[2];
+
+ Box2DXDebug.Assert(aabb.UpperBound.X >= aabb.LowerBound.X);
+ Box2DXDebug.Assert(aabb.UpperBound.Y >= aabb.LowerBound.Y);
+
+ Vec2 minVertex = Common.Math.Clamp(aabb.LowerBound, _worldAABB.LowerBound, _worldAABB.UpperBound);
+ Vec2 maxVertex = Common.Math.Clamp(aabb.UpperBound, _worldAABB.LowerBound, _worldAABB.UpperBound);
+
+ // Bump lower bounds downs and upper bounds up. This ensures correct sorting of
+ // lower/upper bounds that would have equal values.
+ // TODO_ERIN implement fast float to uint16 conversion.
+ lowerValues[0] = (ushort)((ushort)(_quantizationFactor.X * (minVertex.X - _worldAABB.LowerBound.X)) & (BROADPHASE_MAX - 1));
+ upperValues[0] = (ushort)((ushort)(_quantizationFactor.X * (maxVertex.X - _worldAABB.LowerBound.X)) | 1);
+
+ lowerValues[1] = (ushort)((ushort)(_quantizationFactor.Y * (minVertex.Y - _worldAABB.LowerBound.Y)) & (BROADPHASE_MAX - 1));
+ upperValues[1] = (ushort)((ushort)(_quantizationFactor.Y * (maxVertex.Y - _worldAABB.LowerBound.Y)) | 1);
+ }
+
+ // This one is only used for validation.
+ internal bool TestOverlap(Proxy p1, Proxy p2)
+ {
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+
+ Box2DXDebug.Assert(p1.LowerBounds[axis] < 2 * _proxyCount);
+ Box2DXDebug.Assert(p1.UpperBounds[axis] < 2 * _proxyCount);
+ Box2DXDebug.Assert(p2.LowerBounds[axis] < 2 * _proxyCount);
+ Box2DXDebug.Assert(p2.UpperBounds[axis] < 2 * _proxyCount);
+
+ if (bounds[p1.LowerBounds[axis]].Value > bounds[p2.UpperBounds[axis]].Value)
+ return false;
+
+ if (bounds[p1.UpperBounds[axis]].Value < bounds[p2.LowerBounds[axis]].Value)
+ return false;
+ }
+
+ return true;
+ }
+
+ internal bool TestOverlap(BoundValues b, Proxy p)
+ {
+ for (int axis = 0; axis < 2; ++axis)
+ {
+ Bound[] bounds = _bounds[axis];
+
+ Box2DXDebug.Assert(p.LowerBounds[axis] < 2 * _proxyCount);
+ Box2DXDebug.Assert(p.UpperBounds[axis] < 2 * _proxyCount);
+
+ if (b.LowerValues[axis] > bounds[p.UpperBounds[axis]].Value)
+ return false;
+
+ if (b.UpperValues[axis] < bounds[p.LowerBounds[axis]].Value)
+ return false;
+ }
+
+ return true;
+ }
+
+ private void Query(out int lowerQueryOut, out int upperQueryOut,
+ ushort lowerValue, ushort upperValue,
+ Bound[] bounds, int boundCount, int axis)
+ {
+ int lowerQuery = BinarySearch(bounds, boundCount, lowerValue);
+ int upperQuery = BinarySearch(bounds, boundCount, upperValue);
+
+ // Easy case: lowerQuery <= lowerIndex(i) < upperQuery
+ // Solution: search query range for min bounds.
+ for (int i = lowerQuery; i < upperQuery; ++i)
+ {
+ if (bounds[i].IsLower)
+ {
+ IncrementOverlapCount(bounds[i].ProxyId);
+ }
+ }
+
+ // Hard case: lowerIndex(i) < lowerQuery < upperIndex(i)
+ // Solution: use the stabbing count to search down the bound array.
+ if (lowerQuery > 0)
+ {
+ int i = lowerQuery - 1;
+ int s = bounds[i].StabbingCount;
+
+ // Find the s overlaps.
+ while (s != 0)
+ {
+ Box2DXDebug.Assert(i >= 0);
+
+ if (bounds[i].IsLower)
+ {
+ Proxy proxy = _proxyPool[bounds[i].ProxyId];
+ if (lowerQuery <= proxy.UpperBounds[axis])
+ {
+ IncrementOverlapCount(bounds[i].ProxyId);
+ --s;
+ }
+ }
+ --i;
+ }
+ }
+
+ lowerQueryOut = lowerQuery;
+ upperQueryOut = upperQuery;
+ }
+ int qi1 = 0;
+ int qi2 = 0;
+ private void IncrementOverlapCount(int proxyId)
+ {
+ Proxy proxy = _proxyPool[proxyId];
+ if (proxy.TimeStamp < _timeStamp)
+ {
+ proxy.TimeStamp = _timeStamp;
+ proxy.OverlapCount = 1;
+ qi1++;
+ }
+ else
+ {
+ proxy.OverlapCount = 2;
+ Box2DXDebug.Assert(_queryResultCount < Settings.MaxProxies);
+ _queryResults[_queryResultCount] = (ushort)proxyId;
+ ++_queryResultCount;
+ qi2++;
+ }
+ }
+
+ private void IncrementTimeStamp()
+ {
+ if (_timeStamp == BROADPHASE_MAX)
+ {
+ for (ushort i = 0; i < Settings.MaxProxies; ++i)
+ {
+ _proxyPool[i].TimeStamp = 0;
+ }
+ _timeStamp = 1;
+ }
+ else
+ {
+ ++_timeStamp;
+ }
+ }
+
+#if ALLOWUNSAFE
+ public unsafe void AddProxyResult(ushort proxyId, Proxy proxy, int maxCount, SortKeyFunc sortKey)
+ {
+ float key = sortKey(proxy.UserData);
+ //Filter proxies on positive keys
+ if (key < 0)
+ return;
+ //Merge the new key into the sorted list.
+ //float32* p = std::lower_bound(m_querySortKeys,m_querySortKeys+m_queryResultCount,key);
+ fixed (float* querySortKeysPtr = _querySortKeys)
+ {
+ float* p = querySortKeysPtr;
+ while (*p < key && p < &querySortKeysPtr[_queryResultCount])
+ p++;
+ int i = (int)(p - &querySortKeysPtr[0]);
+ if (maxCount == _queryResultCount && i == _queryResultCount)
+ return;
+ if (maxCount == _queryResultCount)
+ _queryResultCount--;
+ //std::copy_backward
+ for (int j = _queryResultCount + 1; j > i; --j)
+ {
+ _querySortKeys[j] = _querySortKeys[j - 1];
+ _queryResults[j] = _queryResults[j - 1];
+ }
+ _querySortKeys[i] = key;
+ _queryResults[i] = proxyId;
+ _queryResultCount++;
+ }
+ }
+#else
+ public void AddProxyResult(ushort proxyId, Proxy proxy, int maxCount, SortKeyFunc sortKey)
+ {
+ float key = sortKey(proxy.UserData);
+ //Filter proxies on positive keys
+ if (key < 0)
+ return;
+ //Merge the new key into the sorted list.
+ //float32* p = std::lower_bound(m_querySortKeys,m_querySortKeys+m_queryResultCount,key);
+ float[] querySortKeysPtr = _querySortKeys;
+
+ int ip = 0;
+ float p = querySortKeysPtr[ip];
+ while (p < key && ip < _queryResultCount)
+ {
+ p = querySortKeysPtr[ip];
+ ip++;
+ }
+ int i = ip;
+ if (maxCount == _queryResultCount && i == _queryResultCount)
+ return;
+ if (maxCount == _queryResultCount)
+ _queryResultCount--;
+ //std::copy_backward
+ for (int j = _queryResultCount + 1; j > i; --j)
+ {
+ _querySortKeys[j] = _querySortKeys[j - 1];
+ _queryResults[j] = _queryResults[j - 1];
+ }
+ _querySortKeys[i] = key;
+ _queryResults[i] = proxyId;
+ _queryResultCount++;
+ }
+#endif
+
+ private static int BinarySearch(Bound[] bounds, int count, ushort value)
+ {
+ int low = 0;
+ int high = count - 1;
+ while (low <= high)
+ {
+ int mid = (low + high) >> 1;
+ if (bounds[mid].Value > value)
+ {
+ high = mid - 1;
+ }
+ else if (bounds[mid].Value < value)
+ {
+ low = mid + 1;
+ }
+ else
+ {
+ return (ushort)mid;
+ }
+ }
+
+ return low;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Rope/Rope.cs.meta b/Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs.meta
index fa9b631..efd4471 100644
--- a/Box2d/Assets/Program/Box2d/Rope/Rope.cs.meta
+++ b/Box2d/Assets/Program/Box2d/Collision/BroadPhase.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: d56353be4c8ccf942941c4bd085c71ba
+guid: 507394c33d29e434193da81ba5fe878a
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs
new file mode 100644
index 0000000..fa10a9e
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs
@@ -0,0 +1,155 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public partial class Collision
+ {
+ public static void CollideCircles(ref Manifold manifold,
+ CircleShape circle1, XForm xf1, CircleShape circle2, XForm xf2)
+ {
+ manifold.PointCount = 0;
+
+ Vec2 p1 = Common.Math.Mul(xf1, circle1._position);
+ Vec2 p2 = Common.Math.Mul(xf2, circle2._position);
+
+ Vec2 d = p2 - p1;
+ float distSqr = Vec2.Dot(d, d);
+ float radius = circle1._radius + circle2._radius;
+ if (distSqr > radius * radius)
+ {
+ return;
+ }
+
+ manifold.Type = ManifoldType.Circles;
+ manifold.LocalPoint = circle1._position;
+ manifold.LocalPlaneNormal.SetZero();
+ manifold.PointCount = 1;
+
+ manifold.Points[0].LocalPoint = circle2._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+
+ public static void CollidePolygonAndCircle(ref Manifold manifold,
+ PolygonShape polygon, XForm xf1, CircleShape circle, XForm xf2)
+ {
+ manifold.PointCount = 0;
+
+ // Compute circle position in the frame of the polygon.
+ Vec2 c = Common.Math.Mul(xf2, circle._position);
+ Vec2 cLocal = Common.Math.MulT(xf1, c);
+
+ // Find the min separating edge.
+ int normalIndex = 0;
+ float separation = -Settings.FLT_MAX;
+ float radius = polygon._radius + circle._radius;
+ int vertexCount = polygon._vertexCount;
+ Vec2[] vertices = polygon._vertices;
+ Vec2[] normals = polygon._normals;
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ float s = Vec2.Dot(normals[i], cLocal - vertices[i]);
+ if (s > radius)
+ {
+ // Early out.
+ return;
+ }
+
+ if (s > separation)
+ {
+ separation = s;
+ normalIndex = i;
+ }
+ }
+
+ // Vertices that subtend the incident face.
+ int vertIndex1 = normalIndex;
+ int vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
+ Vec2 v1 = vertices[vertIndex1];
+ Vec2 v2 = vertices[vertIndex2];
+
+ // If the center is inside the polygon ...
+ if (separation < Common.Settings.FLT_EPSILON)
+ {
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = normals[normalIndex];
+ manifold.LocalPoint = 0.5f * (v1 + v2);
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ return;
+ }
+
+ // Compute barycentric coordinates
+ float u1 = Vec2.Dot(cLocal - v1, v2 - v1);
+ float u2 = Vec2.Dot(cLocal - v2, v1 - v2);
+ if (u1 <= 0.0f)
+ {
+ if (Vec2.DistanceSquared(cLocal, v1) > radius * radius)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = cLocal - v1;
+ manifold.LocalPlaneNormal.Normalize();
+ manifold.LocalPoint = v1;
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ else if (u2 <= 0.0f)
+ {
+ if (Vec2.DistanceSquared(cLocal, v2) > radius * radius)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = cLocal - v2;
+ manifold.LocalPlaneNormal.Normalize();
+ manifold.LocalPoint = v2;
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ else
+ {
+ Vec2 faceCenter = 0.5f * (v1 + v2);
+ float separation_ = Vec2.Dot(cLocal - faceCenter, normals[vertIndex1]);
+ if (separation_ > radius)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = normals[vertIndex1];
+ manifold.LocalPoint = faceCenter;
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Common/Transform.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs.meta
index d8b844b..4d53a38 100644
--- a/Box2d/Assets/Program/Box2d/Common/Transform.cs.meta
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideCircle.cs.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: 0ad1c5e9a9ce05e40995e4c863ba9adc
+guid: 71b3a2ec035f35d47b5bcc3a724a5907
MonoImporter:
externalObjects: {}
serializedVersion: 2
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs
new file mode 100644
index 0000000..8ea3821
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs
@@ -0,0 +1,100 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public partial class Collision
+ {
+ // This implements 2-sided edge vs circle collision.
+ public static void CollideEdgeAndCircle(ref Manifold manifold, EdgeShape edge, XForm transformA, CircleShape circle, XForm transformB)
+ {
+ manifold.PointCount = 0;
+ Vec2 cLocal = Common.Math.MulT(transformA, Common.Math.Mul(transformB, circle._position));
+ Vec2 normal = edge._normal;
+ Vec2 v1 = edge._v1;
+ Vec2 v2 = edge._v2;
+ float radius = edge._radius + circle._radius;
+
+ // Barycentric coordinates
+ float u1 = Vec2.Dot(cLocal - v1, v2 - v1);
+ float u2 = Vec2.Dot(cLocal - v2, v1 - v2);
+
+ if (u1 <= 0.0f)
+ {
+ // Behind v1
+ if (Vec2.DistanceSquared(cLocal, v1) > radius * radius)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = cLocal - v1;
+ manifold.LocalPlaneNormal.Normalize();
+ manifold.LocalPoint = v1;
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ else if (u2 <= 0.0f)
+ {
+ // Ahead of v2
+ if (Vec2.DistanceSquared(cLocal, v2) > radius * radius)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = cLocal - v2;
+ manifold.LocalPlaneNormal.Normalize();
+ manifold.LocalPoint = v2;
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ else
+ {
+ float separation = Vec2.Dot(cLocal - v1, normal);
+ if (separation < -radius || radius < separation)
+ {
+ return;
+ }
+
+ manifold.PointCount = 1;
+ manifold.Type = ManifoldType.FaceA;
+ manifold.LocalPlaneNormal = separation < 0.0f ? -normal : normal;
+ manifold.LocalPoint = 0.5f * (v1 + v2);
+ manifold.Points[0].LocalPoint = circle._position;
+ manifold.Points[0].ID.Key = 0;
+ }
+ }
+
+ // Polygon versus 2-sided edge.
+ public static void CollidePolyAndEdge(ref Manifold manifold, PolygonShape polygon, XForm transformA, EdgeShape edge, XForm transformB)
+ {
+ PolygonShape polygonB = new PolygonShape();
+ polygonB.SetAsEdge(edge._v1, edge._v2);
+
+ CollidePolygons(ref manifold, polygon, transformA, polygonB, transformB);
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs.meta
new file mode 100644
index 0000000..b71db55
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollideEdge.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b683cd8505628a247bde0d512af54021
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs
new file mode 100644
index 0000000..65c48e4
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs
@@ -0,0 +1,309 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public partial class Collision
+ {
+ /// <summary>
+ /// Find the separation between poly1 and poly2 for a give edge normal on poly1.
+ /// </summary>
+ public static float EdgeSeparation(PolygonShape poly1, XForm xf1, int edge1, PolygonShape poly2, XForm xf2)
+ {
+ int count1 = poly1._vertexCount;
+ Vec2[] vertices1 = poly1._vertices;
+ Vec2[] normals1 = poly1._normals;
+
+ int count2 = poly2._vertexCount;
+ Vec2[] vertices2 = poly2._vertices;
+
+ Box2DXDebug.Assert(0 <= edge1 && edge1 < count1);
+
+ // Convert normal from poly1's frame into poly2's frame.
+ Vec2 normal1World = Common.Math.Mul(xf1.R, normals1[edge1]);
+ Vec2 normal1 = Common.Math.MulT(xf2.R, normal1World);
+
+ // Find support vertex on poly2 for -normal.
+ int index = 0;
+ float minDot = Common.Settings.FLT_MAX;
+ for (int i = 0; i < count2; ++i)
+ {
+ float dot = Vec2.Dot(vertices2[i], normal1);
+ if (dot < minDot)
+ {
+ minDot = dot;
+ index = i;
+ }
+ }
+
+ Vec2 v1 = Common.Math.Mul(xf1, vertices1[edge1]);
+ Vec2 v2 = Common.Math.Mul(xf2, vertices2[index]);
+ float separation = Vec2.Dot(v2 - v1, normal1World);
+ return separation;
+ }
+
+ /// <summary>
+ /// Find the max separation between poly1 and poly2 using edge normals from poly1.
+ /// </summary>
+ public static float FindMaxSeparation(ref int edgeIndex, PolygonShape poly1, XForm xf1, PolygonShape poly2, XForm xf2)
+ {
+ int count1 = poly1._vertexCount;
+ Vec2[] normals1 = poly1._normals;
+
+ // Vector pointing from the centroid of poly1 to the centroid of poly2.
+ Vec2 d = Common.Math.Mul(xf2, poly2._centroid) - Common.Math.Mul(xf1, poly1._centroid);
+ Vec2 dLocal1 = Common.Math.MulT(xf1.R, d);
+
+ // Find edge normal on poly1 that has the largest projection onto d.
+ int edge = 0;
+ float maxDot = -Common.Settings.FLT_MAX;
+ for (int i = 0; i < count1; ++i)
+ {
+ float dot = Vec2.Dot(normals1[i], dLocal1);
+ if (dot > maxDot)
+ {
+ maxDot = dot;
+ edge = i;
+ }
+ }
+
+ // Get the separation for the edge normal.
+ float s = Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+
+ // Check the separation for the previous edge normal.
+ int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
+ float sPrev = Collision.EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2);
+
+ // Check the separation for the next edge normal.
+ int nextEdge = edge + 1 < count1 ? edge + 1 : 0;
+ float sNext = Collision.EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2);
+
+ // Find the best edge and the search direction.
+ int bestEdge;
+ float bestSeparation;
+ int increment;
+ if (sPrev > s && sPrev > sNext)
+ {
+ increment = -1;
+ bestEdge = prevEdge;
+ bestSeparation = sPrev;
+ }
+ else if (sNext > s)
+ {
+ increment = 1;
+ bestEdge = nextEdge;
+ bestSeparation = sNext;
+ }
+ else
+ {
+ edgeIndex = edge;
+ return s;
+ }
+
+ // Perform a local search for the best edge normal.
+ for (; ; )
+ {
+ if (increment == -1)
+ edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1;
+ else
+ edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
+
+ s = Collision.EdgeSeparation(poly1, xf1, edge, poly2, xf2);
+
+ if (s > bestSeparation)
+ {
+ bestEdge = edge;
+ bestSeparation = s;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ edgeIndex = bestEdge;
+ return bestSeparation;
+ }
+
+ public static void FindIncidentEdge(out ClipVertex[] c,
+ PolygonShape poly1, XForm xf1, int edge1, PolygonShape poly2, XForm xf2)
+ {
+ int count1 = poly1._vertexCount;
+ Vec2[] normals1 = poly1._normals;
+
+ int count2 = poly2._vertexCount;
+ Vec2[] vertices2 = poly2._vertices;
+ Vec2[] normals2 = poly2._normals;
+
+ Box2DXDebug.Assert(0 <= edge1 && edge1 < count1);
+
+ // Get the normal of the reference edge in poly2's frame.
+ Vec2 normal1 = Common.Math.MulT(xf2.R, Common.Math.Mul(xf1.R, normals1[edge1]));
+
+ // Find the incident edge on poly2.
+ int index = 0;
+ float minDot = Settings.FLT_MAX;
+ for (int i = 0; i < count2; ++i)
+ {
+ float dot = Vec2.Dot(normal1, normals2[i]);
+ if (dot < minDot)
+ {
+ minDot = dot;
+ index = i;
+ }
+ }
+
+ // Build the clip vertices for the incident edge.
+ int i1 = index;
+ int i2 = i1 + 1 < count2 ? i1 + 1 : 0;
+
+ c = new ClipVertex[2];
+
+ c[0].V = Common.Math.Mul(xf2, vertices2[i1]);
+ c[0].ID.Features.ReferenceEdge = (byte)edge1;
+ c[0].ID.Features.IncidentEdge = (byte)i1;
+ c[0].ID.Features.IncidentVertex = 0;
+
+ c[1].V = Common.Math.Mul(xf2, vertices2[i2]);
+ c[1].ID.Features.ReferenceEdge = (byte)edge1;
+ c[1].ID.Features.IncidentEdge = (byte)i2;
+ c[1].ID.Features.IncidentVertex = 1;
+ }
+
+ // Find edge normal of max separation on A - return if separating axis is found
+ // Find edge normal of max separation on B - return if separation axis is found
+ // Choose reference edge as min(minA, minB)
+ // Find incident edge
+ // Clip
+ // The normal points from 1 to 2
+ public static void CollidePolygons(ref Manifold manifold,
+ PolygonShape polyA, XForm xfA, PolygonShape polyB, XForm xfB)
+ {
+ manifold.PointCount = 0;
+ float totalRadius = polyA._radius + polyB._radius;
+
+ int edgeA = 0;
+ float separationA = Collision.FindMaxSeparation(ref edgeA, polyA, xfA, polyB, xfB);
+ if (separationA > totalRadius)
+ return;
+
+ int edgeB = 0;
+ float separationB = Collision.FindMaxSeparation(ref edgeB, polyB, xfB, polyA, xfA);
+ if (separationB > totalRadius)
+ return;
+
+ PolygonShape poly1; // reference poly
+ PolygonShape poly2; // incident poly
+ XForm xf1, xf2;
+ int edge1; // reference edge
+ byte flip;
+ const float k_relativeTol = 0.98f;
+ const float k_absoluteTol = 0.001f;
+
+ if (separationB > k_relativeTol * separationA + k_absoluteTol)
+ {
+ poly1 = polyB;
+ poly2 = polyA;
+ xf1 = xfB;
+ xf2 = xfA;
+ edge1 = edgeB;
+ manifold.Type = ManifoldType.FaceB;
+ flip = 1;
+ }
+ else
+ {
+ poly1 = polyA;
+ poly2 = polyB;
+ xf1 = xfA;
+ xf2 = xfB;
+ edge1 = edgeA;
+ manifold.Type = ManifoldType.FaceA;
+ flip = 0;
+ }
+
+ ClipVertex[] incidentEdge;
+ Collision.FindIncidentEdge(out incidentEdge, poly1, xf1, edge1, poly2, xf2);
+
+ int count1 = poly1._vertexCount;
+ Vec2[] vertices1 = poly1._vertices;
+
+ Vec2 v11 = vertices1[edge1];
+ Vec2 v12 = edge1 + 1 < count1 ? vertices1[edge1 + 1] : vertices1[0];
+
+ Vec2 dv = v12 - v11;
+
+ Vec2 localNormal = Vec2.Cross(dv, 1.0f);
+ localNormal.Normalize();
+ Vec2 planePoint = 0.5f * (v11 + v12);
+
+ Vec2 sideNormal = Common.Math.Mul(xf1.R, v12 - v11);
+ sideNormal.Normalize();
+ Vec2 frontNormal = Vec2.Cross(sideNormal, 1.0f);
+
+ v11 = Common.Math.Mul(xf1, v11);
+ v12 = Common.Math.Mul(xf1, v12);
+
+ float frontOffset = Vec2.Dot(frontNormal, v11);
+ float sideOffset1 = -Vec2.Dot(sideNormal, v11);
+ float sideOffset2 = Vec2.Dot(sideNormal, v12);
+
+ // Clip incident edge against extruded edge1 side edges.
+ ClipVertex[] clipPoints1;
+ ClipVertex[] clipPoints2;
+ int np;
+
+ // Clip to box side 1
+ np = Collision.ClipSegmentToLine(out clipPoints1, incidentEdge, -sideNormal, sideOffset1);
+
+ if (np < 2)
+ return;
+
+ // Clip to negative box side 1
+ np = ClipSegmentToLine(out clipPoints2, clipPoints1, sideNormal, sideOffset2);
+
+ if (np < 2)
+ return;
+
+ // Now clipPoints2 contains the clipped points.
+ manifold.LocalPlaneNormal = localNormal;
+ manifold.LocalPoint = planePoint;
+
+ int pointCount = 0;
+ for (int i = 0; i < Settings.MaxManifoldPoints; ++i)
+ {
+ float separation = Vec2.Dot(frontNormal, clipPoints2[i].V) - frontOffset;
+
+ if (separation <= totalRadius)
+ {
+ ManifoldPoint cp = manifold.Points[pointCount];
+ cp.LocalPoint = Common.Math.MulT(xf2, clipPoints2[i].V);
+ cp.ID = clipPoints2[i].ID;
+ cp.ID.Features.Flip = flip;
+ ++pointCount;
+ }
+ }
+
+ manifold.PointCount = pointCount;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs.meta
new file mode 100644
index 0000000..f206015
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.CollidePoly.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ff780a3060f9b7c48a616f7935751bb0
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs
new file mode 100644
index 0000000..d6abeb6
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs
@@ -0,0 +1,630 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#define DEBUG
+
+using System;
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ /// <summary>
+ /// Used to warm start Distance.
+ /// Set count to zero on first call.
+ /// </summary>
+ public struct SimplexCache
+ {
+ /// <summary>
+ /// Length or area.
+ /// </summary>
+ public Single Metric;
+ public UInt16 Count;
+ /// <summary>
+ /// Vertices on shape A.
+ /// </summary>
+ //public Byte[/*3*/] IndexA;
+ public IndexArray IndexA;
+ /// <summary>
+ /// Vertices on shape B.
+ /// </summary>
+ //public Byte[/*3*/] IndexB;
+ public IndexArray IndexB;
+
+ //public SimplexCache(byte init)
+ //{
+ // Metric = 0;
+ // Count = 0;
+ // IndexA = new Byte[3];
+ // IndexB = new Byte[3];
+ //}
+ }
+
+ public struct IndexArray
+ {
+ private Byte I0, I1, I2;
+
+ public Byte this[int index]
+ {
+ get
+ {
+#if DEBUG
+ Box2DXDebug.Assert(index >= 0 && index < 3);
+#endif
+ if (index == 0) return I0;
+ else if (index == 1) return I1;
+ else return I2;
+ }
+ set
+ {
+#if DEBUG
+ Box2DXDebug.Assert(index >= 0 && index < 3);
+#endif
+ if (index == 0) I0 = value;
+ else if (index == 1) I1 = value;
+ else I2 = value;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Input for Distance.
+ /// You have to option to use the shape radii
+ /// in the computation.
+ /// </summary>
+ public struct DistanceInput
+ {
+ public XForm TransformA;
+ public XForm TransformB;
+ public bool UseRadii;
+ }
+
+ /// <summary>
+ /// Output for Distance.
+ /// </summary>
+ public struct DistanceOutput
+ {
+ /// <summary>
+ /// Closest point on shapeA.
+ /// </summary>
+ public Vec2 PointA;
+ /// <summary>
+ /// Closest point on shapeB.
+ /// </summary>
+ public Vec2 PointB;
+ public float Distance;
+ /// <summary>
+ /// Number of GJK iterations used.
+ /// </summary>
+ public int Iterations;
+ }
+
+ // GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
+
+ internal struct SimplexVertex
+ {
+ internal Vec2 wA; // support point in shapeA
+ internal Vec2 wB; // support point in shapeB
+ internal Vec2 w; // wB - wA
+ internal float a; // barycentric coordinate for closest point
+ internal int indexA; // wA index
+ internal int indexB; // wB index
+ }
+
+ internal struct Simplex
+ {
+ internal SimplexVertex _v1, _v2, _v3;
+ internal int _count;
+
+ internal unsafe void ReadCache(SimplexCache* cache, Shape shapeA, XForm transformA, Shape shapeB, XForm transformB)
+ {
+ Box2DXDebug.Assert(0 <= cache->Count && cache->Count <= 3);
+
+ // Copy data from cache.
+ _count = cache->Count;
+ SimplexVertex** vertices = stackalloc SimplexVertex*[3];
+ fixed (SimplexVertex* v1Ptr = &_v1, v2Ptr = &_v2, v3Ptr = &_v3)
+ {
+ vertices[0] = v1Ptr;
+ vertices[1] = v2Ptr;
+ vertices[2] = v3Ptr;
+ for (int i = 0; i < _count; ++i)
+ {
+ SimplexVertex* v = vertices[i];
+ v->indexA = cache->IndexA[i];
+ v->indexB = cache->IndexB[i];
+ Vec2 wALocal = shapeA.GetVertex(v->indexA);
+ Vec2 wBLocal = shapeB.GetVertex(v->indexB);
+ v->wA = Common.Math.Mul(transformA, wALocal);
+ v->wB = Common.Math.Mul(transformB, wBLocal);
+ v->w = v->wB - v->wA;
+ v->a = 0.0f;
+ }
+
+ // Compute the new simplex metric, if it is substantially different than
+ // old metric then flush the simplex.
+ if (_count > 1)
+ {
+ float metric1 = cache->Metric;
+ float metric2 = GetMetric();
+ if (metric2 < 0.5f * metric1 || 2.0f * metric1 < metric2 || metric2 < Common.Settings.FLT_EPSILON)
+ {
+ // Reset the simplex.
+ _count = 0;
+ }
+ }
+
+ // If the cache is empty or invalid ...
+ if (_count == 0)
+ {
+ SimplexVertex* v = vertices[0];
+ v->indexA = 0;
+ v->indexB = 0;
+ Vec2 wALocal = shapeA.GetVertex(0);
+ Vec2 wBLocal = shapeB.GetVertex(0);
+ v->wA = Common.Math.Mul(transformA, wALocal);
+ v->wB = Common.Math.Mul(transformB, wBLocal);
+ v->w = v->wB - v->wA;
+ _count = 1;
+ }
+ }
+ }
+
+ internal unsafe void WriteCache(SimplexCache* cache)
+ {
+ cache->Metric = GetMetric();
+ cache->Count = (UInt16)_count;
+ SimplexVertex** vertices = stackalloc SimplexVertex*[3];
+ fixed (SimplexVertex* v1Ptr = &_v1, v2Ptr = &_v2, v3Ptr = &_v3)
+ {
+ vertices[0] = v1Ptr;
+ vertices[1] = v2Ptr;
+ vertices[2] = v3Ptr;
+ for (int i = 0; i < _count; ++i)
+ {
+ cache->IndexA[i] = (Byte)(vertices[i]->indexA);
+ cache->IndexB[i] = (Byte)(vertices[i]->indexB);
+ }
+ }
+ }
+
+ internal Vec2 GetClosestPoint()
+ {
+ switch (_count)
+ {
+ case 0:
+#if DEBUG
+ Box2DXDebug.Assert(false);
+#endif
+ return Vec2.Zero;
+ case 1:
+ return _v1.w;
+ case 2:
+ return _v1.a * _v1.w + _v2.a * _v2.w;
+ case 3:
+ return Vec2.Zero;
+ default:
+#if DEBUG
+ Box2DXDebug.Assert(false);
+#endif
+ return Vec2.Zero;
+ }
+ }
+
+ internal unsafe void GetWitnessPoints(Vec2* pA, Vec2* pB)
+ {
+ switch (_count)
+ {
+ case 0:
+ Box2DXDebug.Assert(false);
+ break;
+
+ case 1:
+ *pA = _v1.wA;
+ *pB = _v1.wB;
+ break;
+
+ case 2:
+ *pA = _v1.a * _v1.wA + _v2.a * _v2.wA;
+ *pB = _v1.a * _v1.wB + _v2.a * _v2.wB;
+ break;
+
+ case 3:
+ *pA = _v1.a * _v1.wA + _v2.a * _v2.wA + _v3.a * _v3.wA;
+ *pB = *pA;
+ break;
+
+ default:
+ Box2DXDebug.Assert(false);
+ break;
+ }
+ }
+
+ internal float GetMetric()
+ {
+ switch (_count)
+ {
+ case 0:
+#if DEBUG
+ Box2DXDebug.Assert(false);
+#endif
+ return 0.0f;
+
+ case 1:
+ return 0.0f;
+
+ case 2:
+ return Vec2.Distance(_v1.w, _v2.w);
+
+ case 3:
+ return Vec2.Cross(_v2.w - _v1.w, _v3.w - _v1.w);
+
+ default:
+#if DEBUG
+ Box2DXDebug.Assert(false);
+#endif
+ return 0.0f;
+ }
+ }
+
+ // Solve a line segment using barycentric coordinates.
+ //
+ // p = a1 * w1 + a2 * w2
+ // a1 + a2 = 1
+ //
+ // The vector from the origin to the closest point on the line is
+ // perpendicular to the line.
+ // e12 = w2 - w1
+ // dot(p, e) = 0
+ // a1 * dot(w1, e) + a2 * dot(w2, e) = 0
+ //
+ // 2-by-2 linear system
+ // [1 1 ][a1] = [1]
+ // [w1.e12 w2.e12][a2] = [0]
+ //
+ // Define
+ // d12_1 = dot(w2, e12)
+ // d12_2 = -dot(w1, e12)
+ // d12 = d12_1 + d12_2
+ //
+ // Solution
+ // a1 = d12_1 / d12
+ // a2 = d12_2 / d12
+ internal void Solve2()
+ {
+ Vec2 w1 = _v1.w;
+ Vec2 w2 = _v2.w;
+ Vec2 e12 = w2 - w1;
+
+ // w1 region
+ float d12_2 = -Vec2.Dot(w1, e12);
+ if (d12_2 <= 0.0f)
+ {
+ // a2 <= 0, so we clamp it to 0
+ _v1.a = 1.0f;
+ _count = 1;
+ return;
+ }
+
+ // w2 region
+ float d12_1 = Vec2.Dot(w2, e12);
+ if (d12_1 <= 0.0f)
+ {
+ // a1 <= 0, so we clamp it to 0
+ _v2.a = 1.0f;
+ _count = 1;
+ _v1 = _v2;
+ return;
+ }
+
+ // Must be in e12 region.
+ float inv_d12 = 1.0f / (d12_1 + d12_2);
+ _v1.a = d12_1 * inv_d12;
+ _v2.a = d12_2 * inv_d12;
+ _count = 2;
+ }
+
+ // Possible regions:
+ // - points[2]
+ // - edge points[0]-points[2]
+ // - edge points[1]-points[2]
+ // - inside the triangle
+ internal void Solve3()
+ {
+ Vec2 w1 = _v1.w;
+ Vec2 w2 = _v2.w;
+ Vec2 w3 = _v3.w;
+
+ // Edge12
+ // [1 1 ][a1] = [1]
+ // [w1.e12 w2.e12][a2] = [0]
+ // a3 = 0
+ Vec2 e12 = w2 - w1;
+ float w1e12 = Vec2.Dot(w1, e12);
+ float w2e12 = Vec2.Dot(w2, e12);
+ float d12_1 = w2e12;
+ float d12_2 = -w1e12;
+
+ // Edge13
+ // [1 1 ][a1] = [1]
+ // [w1.e13 w3.e13][a3] = [0]
+ // a2 = 0
+ Vec2 e13 = w3 - w1;
+ float w1e13 = Vec2.Dot(w1, e13);
+ float w3e13 = Vec2.Dot(w3, e13);
+ float d13_1 = w3e13;
+ float d13_2 = -w1e13;
+
+ // Edge23
+ // [1 1 ][a2] = [1]
+ // [w2.e23 w3.e23][a3] = [0]
+ // a1 = 0
+ Vec2 e23 = w3 - w2;
+ float w2e23 = Vec2.Dot(w2, e23);
+ float w3e23 = Vec2.Dot(w3, e23);
+ float d23_1 = w3e23;
+ float d23_2 = -w2e23;
+
+ // Triangle123
+ float n123 = Vec2.Cross(e12, e13);
+
+ float d123_1 = n123 * Vec2.Cross(w2, w3);
+ float d123_2 = n123 * Vec2.Cross(w3, w1);
+ float d123_3 = n123 * Vec2.Cross(w1, w2);
+
+ // w1 region
+ if (d12_2 <= 0.0f && d13_2 <= 0.0f)
+ {
+ _v1.a = 1.0f;
+ _count = 1;
+ return;
+ }
+
+ // e12
+ if (d12_1 > 0.0f && d12_2 > 0.0f && d123_3 <= 0.0f)
+ {
+ float inv_d12 = 1.0f / (d12_1 + d12_2);
+ _v1.a = d12_1 * inv_d12;
+ _v2.a = d12_1 * inv_d12;
+ _count = 2;
+ return;
+ }
+
+ // e13
+ if (d13_1 > 0.0f && d13_2 > 0.0f && d123_2 <= 0.0f)
+ {
+ float inv_d13 = 1.0f / (d13_1 + d13_2);
+ _v1.a = d13_1 * inv_d13;
+ _v3.a = d13_2 * inv_d13;
+ _count = 2;
+ _v2 = _v3;
+ return;
+ }
+
+ // w2 region
+ if (d12_1 <= 0.0f && d23_2 <= 0.0f)
+ {
+ _v2.a = 1.0f;
+ _count = 1;
+ _v1 = _v2;
+ return;
+ }
+
+ // w3 region
+ if (d13_1 <= 0.0f && d23_1 <= 0.0f)
+ {
+ _v3.a = 1.0f;
+ _count = 1;
+ _v1 = _v3;
+ return;
+ }
+
+ // e23
+ if (d23_1 > 0.0f && d23_2 > 0.0f && d123_1 <= 0.0f)
+ {
+ float inv_d23 = 1.0f / (d23_1 + d23_2);
+ _v2.a = d23_1 * inv_d23;
+ _v3.a = d23_2 * inv_d23;
+ _count = 2;
+ _v1 = _v3;
+ return;
+ }
+
+ // Must be in triangle123
+ float inv_d123 = 1.0f / (d123_1 + d123_2 + d123_3);
+ _v1.a = d123_1 * inv_d123;
+ _v2.a = d123_2 * inv_d123;
+ _v3.a = d123_3 * inv_d123;
+ _count = 3;
+ }
+ }
+
+ public partial class Collision
+ {
+ /// <summary>
+ /// Compute the closest points between two shapes. Supports any combination of:
+ /// CircleShape, PolygonShape, EdgeShape. The simplex cache is input/output.
+ /// On the first call set SimplexCache.Count to zero.
+ /// </summary>
+ public unsafe static void Distance(out DistanceOutput output, ref SimplexCache cache, ref DistanceInput input, Shape shapeA, Shape shapeB)
+ {
+ output = new DistanceOutput();
+
+ XForm transformA = input.TransformA;
+ XForm transformB = input.TransformB;
+
+ // Initialize the simplex.
+ Simplex simplex = new Simplex();
+ fixed (SimplexCache* sPtr = &cache)
+ {
+ simplex.ReadCache(sPtr, shapeA, transformA, shapeB, transformB);
+ }
+
+ // Get simplex vertices as an array.
+ SimplexVertex* vertices = &simplex._v1;
+
+ // These store the vertices of the last simplex so that we
+ // can check for duplicates and prevent cycling.
+ int* lastA = stackalloc int[4], lastB = stackalloc int[4];
+ int lastCount;
+
+ // Main iteration loop.
+ int iter = 0;
+ const int k_maxIterationCount = 20;
+ while (iter < k_maxIterationCount)
+ {
+ // Copy simplex so we can identify duplicates.
+ lastCount = simplex._count;
+ int i;
+ for (i = 0; i < lastCount; ++i)
+ {
+ lastA[i] = vertices[i].indexA;
+ lastB[i] = vertices[i].indexB;
+ }
+
+ switch (simplex._count)
+ {
+ case 1:
+ break;
+
+ case 2:
+ simplex.Solve2();
+ break;
+
+ case 3:
+ simplex.Solve3();
+ break;
+
+ default:
+#if DEBUG
+ Box2DXDebug.Assert(false);
+#endif
+ break;
+ }
+
+ // If we have 3 points, then the origin is in the corresponding triangle.
+ if (simplex._count == 3)
+ {
+ break;
+ }
+
+ // Compute closest point.
+ Vec2 p = simplex.GetClosestPoint();
+ float distanceSqr = p.LengthSquared();
+
+ // Ensure the search direction is numerically fit.
+ if (distanceSqr < Common.Settings.FLT_EPSILON_SQUARED)
+ {
+ // The origin is probably contained by a line segment
+ // or triangle. Thus the shapes are overlapped.
+
+ // We can't return zero here even though there may be overlap.
+ // In case the simplex is a point, segment, or triangle it is difficult
+ // to determine if the origin is contained in the CSO or very close to it.
+ break;
+ }
+
+ // Compute a tentative new simplex vertex using support points.
+ SimplexVertex* vertex = vertices + simplex._count;
+ vertex->indexA = shapeA.GetSupport(Common.Math.MulT(transformA.R, p));
+ vertex->wA = Common.Math.Mul(transformA, shapeA.GetVertex(vertex->indexA));
+ //Vec2 wBLocal;
+ vertex->indexB = shapeB.GetSupport(Common.Math.MulT(transformB.R, -p));
+ vertex->wB = Common.Math.Mul(transformB, shapeB.GetVertex(vertex->indexB));
+ vertex->w = vertex->wB - vertex->wA;
+
+ // Iteration count is equated to the number of support point calls.
+ ++iter;
+
+ // Check for convergence.
+ float lowerBound = Vec2.Dot(p, vertex->w);
+ float upperBound = distanceSqr;
+ const float k_relativeTolSqr = 0.01f * 0.01f; // 1:100
+ if (upperBound - lowerBound <= k_relativeTolSqr * upperBound)
+ {
+ // Converged!
+ break;
+ }
+
+ // Check for duplicate support points.
+ bool duplicate = false;
+ for (i = 0; i < lastCount; ++i)
+ {
+ if (vertex->indexA == lastA[i] && vertex->indexB == lastB[i])
+ {
+ duplicate = true;
+ break;
+ }
+ }
+
+ // If we found a duplicate support point we must exit to avoid cycling.
+ if (duplicate)
+ {
+ break;
+ }
+
+ // New vertex is ok and needed.
+ ++simplex._count;
+ }
+
+
+ fixed (DistanceOutput* doPtr = &output)
+ {
+ // Prepare output.
+ simplex.GetWitnessPoints(&doPtr->PointA, &doPtr->PointB);
+ doPtr->Distance = Vec2.Distance(doPtr->PointA, doPtr->PointB);
+ doPtr->Iterations = iter;
+ }
+
+ fixed (SimplexCache* sPtr = &cache)
+ {
+ // Cache the simplex.
+ simplex.WriteCache(sPtr);
+ }
+
+ // Apply radii if requested.
+ if (input.UseRadii)
+ {
+ float rA = shapeA._radius;
+ float rB = shapeB._radius;
+
+ if (output.Distance > rA + rB && output.Distance > Common.Settings.FLT_EPSILON)
+ {
+ // Shapes are still no overlapped.
+ // Move the witness points to the outer surface.
+ output.Distance -= rA + rB;
+ Vec2 normal = output.PointB - output.PointA;
+ normal.Normalize();
+ output.PointA += rA * normal;
+ output.PointB -= rB * normal;
+ }
+ else
+ {
+ // Shapes are overlapped when radii are considered.
+ // Move the witness points to the middle.
+ Vec2 p = 0.5f * (output.PointA + output.PointB);
+ output.PointA = p;
+ output.PointB = p;
+ output.Distance = 0.0f;
+ }
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs.meta
new file mode 100644
index 0000000..3d28a57
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.Distance.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5656ed372fda8334c9f0ff84dc0922fe
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs
new file mode 100644
index 0000000..b59f19b
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs
@@ -0,0 +1,378 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ /// <summary>
+ /// Inpute parameters for TimeOfImpact
+ /// </summary>
+ public struct TOIInput
+ {
+ public Sweep SweepA;
+ public Sweep SweepB;
+ public float SweepRadiusA;
+ public float SweepRadiusB;
+ public float Tolerance;
+ }
+
+ internal struct SeparationFunction
+ {
+ internal enum Type
+ {
+ Points,
+ FaceA,
+ FaceB
+ };
+
+ internal unsafe void Initialize(SimplexCache* cache,
+ Shape shapeA, XForm transformA,
+ Shape shapeB, XForm transformB)
+ {
+ ShapeA = shapeA;
+ ShapeB = shapeB;
+ int count = cache->Count;
+ Box2DXDebug.Assert(0 < count && count < 3);
+
+ if (count == 1)
+ {
+ FaceType = Type.Points;
+ Vec2 localPointA = ShapeA.GetVertex(cache->IndexA[0]);
+ Vec2 localPointB = ShapeB.GetVertex(cache->IndexB[0]);
+ Vec2 pointA = Common.Math.Mul(transformA, localPointA);
+ Vec2 pointB = Common.Math.Mul(transformB, localPointB);
+ Axis = pointB - pointA;
+ Axis.Normalize();
+ }
+ else if (cache->IndexB[0] == cache->IndexB[1])
+ {
+ // Two points on A and one on B
+ FaceType = Type.FaceA;
+ Vec2 localPointA1 = ShapeA.GetVertex(cache->IndexA[0]);
+ Vec2 localPointA2 = ShapeA.GetVertex(cache->IndexA[1]);
+ Vec2 localPointB = ShapeB.GetVertex(cache->IndexB[0]);
+ LocalPoint = 0.5f * (localPointA1 + localPointA2);
+ Axis = Vec2.Cross(localPointA2 - localPointA1, 1.0f);
+ Axis.Normalize();
+
+ Vec2 normal = Common.Math.Mul(transformA.R, Axis);
+ Vec2 pointA = Common.Math.Mul(transformA, LocalPoint);
+ Vec2 pointB = Common.Math.Mul(transformB, localPointB);
+
+ float s = Vec2.Dot(pointB - pointA, normal);
+ if (s < 0.0f)
+ {
+ Axis = -Axis;
+ }
+ }
+ else
+ {
+ // Two points on B and one or two points on A.
+ // We ignore the second point on A.
+ FaceType = Type.FaceB;
+ Vec2 localPointA = shapeA.GetVertex(cache->IndexA[0]);
+ Vec2 localPointB1 = shapeB.GetVertex(cache->IndexB[0]);
+ Vec2 localPointB2 = shapeB.GetVertex(cache->IndexB[1]);
+ LocalPoint = 0.5f * (localPointB1 + localPointB2);
+ Axis = Vec2.Cross(localPointB2 - localPointB1, 1.0f);
+ Axis.Normalize();
+
+ Vec2 normal = Common.Math.Mul(transformB.R, Axis);
+ Vec2 pointB = Common.Math.Mul(transformB, LocalPoint);
+ Vec2 pointA = Common.Math.Mul(transformA, localPointA);
+
+ float s = Vec2.Dot(pointA - pointB, normal);
+ if (s < 0.0f)
+ {
+ Axis = -Axis;
+ }
+ }
+ }
+
+ internal float Evaluate(XForm transformA, XForm transformB)
+ {
+ switch (FaceType)
+ {
+ case Type.Points:
+ {
+ Vec2 axisA = Common.Math.MulT(transformA.R, Axis);
+ Vec2 axisB = Common.Math.MulT(transformB.R, -Axis);
+ Vec2 localPointA = ShapeA.GetSupportVertex(axisA);
+ Vec2 localPointB = ShapeB.GetSupportVertex(axisB);
+ Vec2 pointA = Common.Math.Mul(transformA, localPointA);
+ Vec2 pointB = Common.Math.Mul(transformB, localPointB);
+ float separation = Vec2.Dot(pointB - pointA, Axis);
+ return separation;
+ }
+
+ case Type.FaceA:
+ {
+ Vec2 normal = Common.Math.Mul(transformA.R, Axis);
+ Vec2 pointA = Common.Math.Mul(transformA, LocalPoint);
+
+ Vec2 axisB = Common.Math.MulT(transformB.R, -normal);
+
+ Vec2 localPointB = ShapeB.GetSupportVertex(axisB);
+ Vec2 pointB = Common.Math.Mul(transformB, localPointB);
+
+ float separation = Vec2.Dot(pointB - pointA, normal);
+ return separation;
+ }
+
+ case Type.FaceB:
+ {
+ Vec2 normal = Common.Math.Mul(transformB.R, Axis);
+ Vec2 pointB = Common.Math.Mul(transformB, LocalPoint);
+
+ Vec2 axisA = Common.Math.MulT(transformA.R, -normal);
+
+ Vec2 localPointA = ShapeA.GetSupportVertex(axisA);
+ Vec2 pointA = Common.Math.Mul(transformA, localPointA);
+
+ float separation = Vec2.Dot(pointA - pointB, normal);
+ return separation;
+ }
+
+ default:
+ Box2DXDebug.Assert(false);
+ return 0.0f;
+ }
+ }
+
+ internal Shape ShapeA;
+ internal Shape ShapeB;
+ internal Type FaceType;
+ internal Vec2 LocalPoint;
+ internal Vec2 Axis;
+ }
+
+ public partial class Collision
+ {
+ public static int MaxToiIters;
+ public static int MaxToiRootIters;
+
+ // CCD via the secant method.
+ /// <summary>
+ /// Compute the time when two shapes begin to touch or touch at a closer distance.
+ /// TOI considers the shape radii. It attempts to have the radii overlap by the tolerance.
+ /// Iterations terminate with the overlap is within 0.5 * tolerance. The tolerance should be
+ /// smaller than sum of the shape radii.
+ /// Warning the sweeps must have the same time interval.
+ /// </summary>
+ /// <returns>
+ /// The fraction between [0,1] in which the shapes first touch.
+ /// fraction=0 means the shapes begin touching/overlapped, and fraction=1 means the shapes don't touch.
+ /// </returns>
+ public static float TimeOfImpact(TOIInput input, Shape shapeA, Shape shapeB)
+ {
+ Sweep sweepA = input.SweepA;
+ Sweep sweepB = input.SweepB;
+
+ Box2DXDebug.Assert(sweepA.T0 == sweepB.T0);
+ Box2DXDebug.Assert(1.0f - sweepA.T0 > Common.Settings.FLT_EPSILON);
+
+ float radius = shapeA._radius + shapeB._radius;
+ float tolerance = input.Tolerance;
+
+ float alpha = 0.0f;
+
+ const int k_maxIterations = 1000; // TODO_ERIN b2Settings
+ int iter = 0;
+ float target = 0.0f;
+
+ // Prepare input for distance query.
+ SimplexCache cache = new SimplexCache();
+ cache.Count = 0;
+ DistanceInput distanceInput;
+ distanceInput.UseRadii = false;
+
+ for (; ; )
+ {
+ XForm xfA, xfB;
+ sweepA.GetTransform(out xfA, alpha);
+ sweepB.GetTransform(out xfB, alpha);
+
+ // Get the distance between shapes.
+ distanceInput.TransformA = xfA;
+ distanceInput.TransformB = xfB;
+ DistanceOutput distanceOutput;
+ Distance(out distanceOutput, ref cache, ref distanceInput, shapeA, shapeB);
+
+ if (distanceOutput.Distance <= 0.0f)
+ {
+ alpha = 1.0f;
+ break;
+ }
+
+ SeparationFunction fcn = new SeparationFunction();
+ unsafe
+ {
+ fcn.Initialize(&cache, shapeA, xfA, shapeB, xfB);
+ }
+
+ float separation = fcn.Evaluate(xfA, xfB);
+ if (separation <= 0.0f)
+ {
+ alpha = 1.0f;
+ break;
+ }
+
+ if (iter == 0)
+ {
+ // Compute a reasonable target distance to give some breathing room
+ // for conservative advancement. We take advantage of the shape radii
+ // to create additional clearance.
+ if (separation > radius)
+ {
+ target = Common.Math.Max(radius - tolerance, 0.75f * radius);
+ }
+ else
+ {
+ target = Common.Math.Max(separation - tolerance, 0.02f * radius);
+ }
+ }
+
+ if (separation - target < 0.5f * tolerance)
+ {
+ if (iter == 0)
+ {
+ alpha = 1.0f;
+ break;
+ }
+
+ break;
+ }
+
+#if _FALSE
+ // Dump the curve seen by the root finder
+ {
+ const int32 N = 100;
+ float32 dx = 1.0f / N;
+ float32 xs[N+1];
+ float32 fs[N+1];
+
+ float32 x = 0.0f;
+
+ for (int32 i = 0; i <= N; ++i)
+ {
+ sweepA.GetTransform(&xfA, x);
+ sweepB.GetTransform(&xfB, x);
+ float32 f = fcn.Evaluate(xfA, xfB) - target;
+
+ printf("%g %g\n", x, f);
+
+ xs[i] = x;
+ fs[i] = f;
+
+ x += dx;
+ }
+ }
+#endif
+
+ // Compute 1D root of: f(x) - target = 0
+ float newAlpha = alpha;
+ {
+ float x1 = alpha, x2 = 1.0f;
+
+ float f1 = separation;
+
+ sweepA.GetTransform(out xfA, x2);
+ sweepB.GetTransform(out xfB, x2);
+ float f2 = fcn.Evaluate(xfA, xfB);
+
+ // If intervals don't overlap at t2, then we are done.
+ if (f2 >= target)
+ {
+ alpha = 1.0f;
+ break;
+ }
+
+ // Determine when intervals intersect.
+ int rootIterCount = 0;
+ for (; ; )
+ {
+ // Use a mix of the secant rule and bisection.
+ float x;
+ if ((rootIterCount & 1) != 0)
+ {
+ // Secant rule to improve convergence.
+ x = x1 + (target - f1) * (x2 - x1) / (f2 - f1);
+ }
+ else
+ {
+ // Bisection to guarantee progress.
+ x = 0.5f * (x1 + x2);
+ }
+
+ sweepA.GetTransform(out xfA, x);
+ sweepB.GetTransform(out xfB, x);
+
+ float f = fcn.Evaluate(xfA, xfB);
+
+ if (Common.Math.Abs(f - target) < 0.025f * tolerance)
+ {
+ newAlpha = x;
+ break;
+ }
+
+ // Ensure we continue to bracket the root.
+ if (f > target)
+ {
+ x1 = x;
+ f1 = f;
+ }
+ else
+ {
+ x2 = x;
+ f2 = f;
+ }
+
+ ++rootIterCount;
+
+ Box2DXDebug.Assert(rootIterCount < 50);
+ }
+
+ MaxToiRootIters = Common.Math.Max(MaxToiRootIters, rootIterCount);
+ }
+
+ // Ensure significant advancement.
+ if (newAlpha < (1.0f + 100.0f * Common.Settings.FLT_EPSILON) * alpha)
+ {
+ break;
+ }
+
+ alpha = newAlpha;
+
+ ++iter;
+
+ if (iter == k_maxIterations)
+ {
+ break;
+ }
+ }
+
+ MaxToiIters = Common.Math.Max(MaxToiIters, iter);
+
+ return alpha;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs.meta
new file mode 100644
index 0000000..146887c
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.TimeOfImpact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d06765dfbd7e9c940b64509b22111f19
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Collision.cs b/Box2d/Assets/Program/Box2d/Collision/Collision.cs
index 85ae672..e77e23b 100644
--- a/Box2d/Assets/Program/Box2d/Collision/Collision.cs
+++ b/Box2d/Assets/Program/Box2d/Collision/Collision.cs
@@ -1,7 +1,623 @@
-using System.Collections;
-using System.Collections.Generic;
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
-namespace Box2D
+ 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 Box2DX.Common;
+
+namespace Box2DX.Collision
{
+ // Structures and functions used for computing contact points, distance
+ // queries, and TOI queries.
+
+ public partial class Collision
+ {
+ public static readonly byte NullFeature = Common.Math.UCHAR_MAX;
+
+ public static bool TestOverlap(AABB a, AABB b)
+ {
+ Vec2 d1, d2;
+ d1 = b.LowerBound - a.UpperBound;
+ d2 = a.LowerBound - b.UpperBound;
+
+ if (d1.X > 0.0f || d1.Y > 0.0f)
+ return false;
+
+ if (d2.X > 0.0f || d2.Y > 0.0f)
+ return false;
+
+ return true;
+ }
+
+ /// <summary>
+ /// Compute the point states given two manifolds. The states pertain to the transition from manifold1
+ /// to manifold2. So state1 is either persist or remove while state2 is either add or persist.
+ /// </summary>
+ public static void GetPointStates(PointState[/*b2_maxManifoldPoints*/] state1, PointState[/*b2_maxManifoldPoints*/] state2,
+ Manifold manifold1, Manifold manifold2)
+ {
+ for (int i = 0; i < Common.Settings.MaxManifoldPoints; ++i)
+ {
+ state1[i] = PointState.NullState;
+ state2[i] = PointState.NullState;
+ }
+
+ // Detect persists and removes.
+ for (int i = 0; i < manifold1.PointCount; ++i)
+ {
+ ContactID id = manifold1.Points[i].ID;
+
+ state1[i] = PointState.RemoveState;
+
+ for (int j = 0; j < manifold2.PointCount; ++j)
+ {
+ if (manifold2.Points[j].ID.Key == id.Key)
+ {
+ state1[i] = PointState.PersistState;
+ break;
+ }
+ }
+ }
+
+ // Detect persists and adds.
+ for (int i = 0; i < manifold2.PointCount; ++i)
+ {
+ ContactID id = manifold2.Points[i].ID;
+
+ state2[i] = PointState.AddState;
+
+ for (int j = 0; j < manifold1.PointCount; ++j)
+ {
+ if (manifold1.Points[j].ID.Key == id.Key)
+ {
+ state2[i] = PointState.PersistState;
+ break;
+ }
+ }
+ }
+ }
+
+ // Sutherland-Hodgman clipping.
+ public static int ClipSegmentToLine(out ClipVertex[/*2*/] vOut, ClipVertex[/*2*/] vIn, Vec2 normal, float offset)
+ {
+ vOut = new ClipVertex[2];
+
+ // Start with no output points
+ int numOut = 0;
+
+ // Calculate the distance of end points to the line
+ float distance0 = Vec2.Dot(normal, vIn[0].V) - offset;
+ float distance1 = Vec2.Dot(normal, vIn[1].V) - offset;
+
+ // If the points are behind the plane
+ if (distance0 <= 0.0f) vOut[numOut++] = vIn[0];
+ if (distance1 <= 0.0f) vOut[numOut++] = vIn[1];
+
+ // If the points are on different sides of the plane
+ if (distance0 * distance1 < 0.0f)
+ {
+ // Find intersection point of edge and plane
+ float interp = distance0 / (distance0 - distance1);
+ vOut[numOut].V = vIn[0].V + interp * (vIn[1].V - vIn[0].V);
+ if (distance0 > 0.0f)
+ {
+ vOut[numOut].ID = vIn[0].ID;
+ }
+ else
+ {
+ vOut[numOut].ID = vIn[1].ID;
+ }
+ ++numOut;
+ }
+
+ return numOut;
+ }
+ }
+
+ /// <summary>
+ /// The features that intersect to form the contact point.
+ /// </summary>
+ public struct Features
+ {
+ /// <summary>
+ /// The edge that defines the outward contact normal.
+ /// </summary>
+ public Byte ReferenceEdge;
+
+ /// <summary>
+ /// The edge most anti-parallel to the reference edge.
+ /// </summary>
+ public Byte IncidentEdge;
+
+ /// <summary>
+ /// The vertex (0 or 1) on the incident edge that was clipped.
+ /// </summary>
+ public Byte IncidentVertex;
+
+ /// <summary>
+ /// A value of 1 indicates that the reference edge is on shape2.
+ /// </summary>
+ public Byte Flip;
+ }
+
+ /// <summary>
+ /// Contact ids to facilitate warm starting.
+ /// </summary>
+ [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
+ public struct ContactID
+ {
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ public Features Features;
+
+ /// <summary>
+ /// Used to quickly compare contact ids.
+ /// </summary>
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ public UInt32 Key;
+ }
+
+ /// <summary>
+ /// A manifold point is a contact point belonging to a contact
+ /// manifold. It holds details related to the geometry and dynamics
+ /// of the contact points.
+ /// The local point usage depends on the manifold type:
+ /// -Circles: the local center of circleB
+ /// -FaceA: the local center of cirlceB or the clip point of polygonB
+ /// -FaceB: the clip point of polygonA
+ /// This structure is stored across time steps, so we keep it small.
+ /// Note: the impulses are used for internal caching and may not
+ /// provide reliable contact forces, especially for high speed collisions.
+ /// </summary>
+ public class ManifoldPoint
+ {
+ /// <summary>
+ /// Usage depends on manifold type.
+ /// </summary>
+ public Vec2 LocalPoint;
+
+ /// <summary>
+ /// The non-penetration impulse.
+ /// </summary>
+ public float NormalImpulse;
+
+ /// <summary>
+ /// The friction impulse.
+ /// </summary>
+ public float TangentImpulse;
+
+ /// <summary>
+ /// Uniquely identifies a contact point between two shapes.
+ /// </summary>
+ public ContactID ID;
+
+ public ManifoldPoint Clone()
+ {
+ ManifoldPoint newPoint = new ManifoldPoint();
+ newPoint.LocalPoint = this.LocalPoint;
+ newPoint.NormalImpulse = this.NormalImpulse;
+ newPoint.TangentImpulse = this.TangentImpulse;
+ newPoint.ID = this.ID;
+ return newPoint;
+ }
+ }
+
+ public enum ManifoldType
+ {
+ Circles,
+ FaceA,
+ FaceB
+ }
+
+ /// <summary>
+ /// A manifold for two touching convex shapes.
+ /// </summary>
+ public class Manifold
+ {
+ /// <summary>
+ /// The points of contact.
+ /// </summary>
+ public ManifoldPoint[/*Settings.MaxManifoldPoints*/] Points = new ManifoldPoint[Settings.MaxManifoldPoints];
+
+ public Vec2 LocalPlaneNormal;
+
+ /// <summary>
+ /// Usage depends on manifold type.
+ /// </summary>
+ public Vec2 LocalPoint;
+
+ public ManifoldType Type;
+
+ /// <summary>
+ /// The number of manifold points.
+ /// </summary>
+ public int PointCount;
+
+ public Manifold()
+ {
+ for (int i = 0; i < Settings.MaxManifoldPoints; i++)
+ Points[i] = new ManifoldPoint();
+ }
+
+ public Manifold Clone()
+ {
+ Manifold newManifold = new Manifold();
+ newManifold.LocalPlaneNormal = this.LocalPlaneNormal;
+ newManifold.LocalPoint = this.LocalPoint;
+ newManifold.Type = this.Type;
+ newManifold.PointCount = this.PointCount;
+ int pointCount = this.Points.Length;
+ ManifoldPoint[] tmp = new ManifoldPoint[pointCount];
+ for (int i = 0; i < pointCount; i++)
+ {
+ tmp[i] = this.Points[i].Clone();
+ }
+ newManifold.Points = tmp;
+ return newManifold;
+ }
+ }
+
+ /// <summary>
+ /// A line segment.
+ /// </summary>
+ public struct Segment
+ {
+ // Collision Detection in Interactive 3D Environments by Gino van den Bergen
+ // From Section 3.4.1
+ // x = mu1 * p1 + mu2 * p2
+ // mu1 + mu2 = 1 && mu1 >= 0 && mu2 >= 0
+ // mu1 = 1 - mu2;
+ // x = (1 - mu2) * p1 + mu2 * p2
+ // = p1 + mu2 * (p2 - p1)
+ // x = s + a * r (s := start, r := end - start)
+ // s + a * r = p1 + mu2 * d (d := p2 - p1)
+ // -a * r + mu2 * d = b (b := s - p1)
+ // [-r d] * [a; mu2] = b
+ // Cramer's rule:
+ // denom = det[-r d]
+ // a = det[b d] / denom
+ // mu2 = det[-r b] / denom
+ /// <summary>
+ /// Ray cast against this segment with another segment.
+ /// </summary>
+ public bool TestSegment(out float lambda, out Vec2 normal, Segment segment, float maxLambda)
+ {
+ lambda = 0f;
+ normal = new Vec2();
+
+ Vec2 s = segment.P1;
+ Vec2 r = segment.P2 - s;
+ Vec2 d = P2 - P1;
+ Vec2 n = Vec2.Cross(d, 1.0f);
+
+ float k_slop = 100.0f * Common.Settings.FLT_EPSILON;
+ float denom = -Vec2.Dot(r, n);
+
+ // Cull back facing collision and ignore parallel segments.
+ if (denom > k_slop)
+ {
+ // Does the segment intersect the infinite line associated with this segment?
+ Vec2 b = s - P1;
+ float a = Vec2.Dot(b, n);
+
+ if (0.0f <= a && a <= maxLambda * denom)
+ {
+ float mu2 = -r.X * b.Y + r.Y * b.X;
+
+ // Does the segment intersect this segment?
+ if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop))
+ {
+ a /= denom;
+ n.Normalize();
+ lambda = a;
+ normal = n;
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// The starting point.
+ /// </summary>
+ public Vec2 P1;
+
+ /// <summary>
+ /// The ending point.
+ /// </summary>
+ public Vec2 P2;
+ }
+
+ /// <summary>
+ /// An axis aligned bounding box.
+ /// </summary>
+ public struct AABB
+ {
+ /// <summary>
+ /// The lower vertex.
+ /// </summary>
+ public Vec2 LowerBound;
+
+ /// <summary>
+ /// The upper vertex.
+ /// </summary>
+ public Vec2 UpperBound;
+
+ /// Verify that the bounds are sorted.
+ public bool IsValid
+ {
+ get
+ {
+ Vec2 d = UpperBound - LowerBound;
+ bool valid = d.X >= 0.0f && d.Y >= 0.0f;
+ valid = valid && LowerBound.IsValid && UpperBound.IsValid;
+ return valid;
+ }
+ }
+
+ /// Get the center of the AABB.
+ public Vec2 Center
+ {
+ get { return 0.5f * (LowerBound + UpperBound); }
+ }
+
+ /// Get the extents of the AABB (half-widths).
+ public Vec2 Extents
+ {
+ get { return 0.5f * (UpperBound - LowerBound); }
+ }
+
+ /// Combine two AABBs into this one.
+ public void Combine(AABB aabb1, AABB aabb2)
+ {
+ LowerBound = Common.Math.Min(aabb1.LowerBound, aabb2.LowerBound);
+ UpperBound = Common.Math.Max(aabb1.UpperBound, aabb2.UpperBound);
+ }
+
+ /// Does this aabb contain the provided AABB.
+ public bool Contains(AABB aabb)
+ {
+ bool result = LowerBound.X <= aabb.LowerBound.X;
+ result = result && LowerBound.Y <= aabb.LowerBound.Y;
+ result = result && aabb.UpperBound.X <= UpperBound.X;
+ result = result && aabb.UpperBound.Y <= UpperBound.Y;
+ return result;
+ }
+
+ /// <summary>
+ // From Real-time Collision Detection, p179.
+ /// </summary>
+ public void RayCast(out RayCastOutput output, RayCastInput input)
+ {
+ float tmin = -Common.Settings.FLT_MAX;
+ float tmax = Common.Settings.FLT_MAX;
+
+ output = new RayCastOutput();
+
+ output.Hit = false;
+
+ Vec2 p = input.P1;
+ Vec2 d = input.P2 - input.P1;
+ Vec2 absD = Common.Math.Abs(d);
+
+ Vec2 normal = new Vec2(0);
+
+ for (int i = 0; i < 2; ++i)
+ {
+ if (absD[i] < Common.Settings.FLT_EPSILON)
+ {
+ // Parallel.
+ if (p[i] < LowerBound[i] || UpperBound[i] < p[i])
+ {
+ return;
+ }
+ }
+ else
+ {
+ float inv_d = 1.0f / d[i];
+ float t1 = (LowerBound[i] - p[i]) * inv_d;
+ float t2 = (UpperBound[i] - p[i]) * inv_d;
+
+ // Sign of the normal vector.
+ float s = -1.0f;
+
+ if (t1 > t2)
+ {
+ Common.Math.Swap(ref t1, ref t2);
+ s = 1.0f;
+ }
+
+ // Push the min up
+ if (t1 > tmin)
+ {
+ normal.SetZero();
+ normal[i] = s;
+ tmin = t1;
+ }
+
+ // Pull the max down
+ tmax = Common.Math.Min(tmax, t2);
+
+ if (tmin > tmax)
+ {
+ return;
+ }
+ }
+ }
+
+ // Does the ray start inside the box?
+ // Does the ray intersect beyond the max fraction?
+ if (tmin < 0.0f || input.MaxFraction < tmin)
+ {
+ return;
+ }
+
+ // Intersection.
+ output.Fraction = tmin;
+ output.Normal = normal;
+ output.Hit = true;
+ }
+ }
+
+ /// <summary>
+ /// This is used for determining the state of contact points.
+ /// </summary>
+ public enum PointState
+ {
+ /// <summary>
+ /// Point does not exist.
+ /// </summary>
+ NullState,
+ /// <summary>
+ /// Point was added in the update.
+ /// </summary>
+ AddState,
+ /// <summary>
+ /// Point persisted across the update.
+ /// </summary>
+ PersistState,
+ /// <summary>
+ ///Point was removed in the update.
+ /// </summary>
+ RemoveState
+ }
+
+ /// <summary>
+ /// This is used to compute the current state of a contact manifold.
+ /// </summary>
+ public class WorldManifold
+ {
+ /// <summary>
+ /// World vector pointing from A to B.
+ /// </summary>
+ public Vec2 Normal;
+ /// <summary>
+ /// World contact point (point of intersection).
+ /// </summary>
+ public Vec2[] Points = new Vec2[Common.Settings.MaxManifoldPoints];
+
+ public WorldManifold Clone()
+ {
+ WorldManifold newManifold = new WorldManifold();
+ newManifold.Normal = this.Normal;
+ this.Points.CopyTo(newManifold.Points, 0);
+ return newManifold;
+ }
+
+ /// Evaluate the manifold with supplied transforms. This assumes
+ /// modest motion from the original state. This does not change the
+ /// point count, impulses, etc. The radii must come from the shapes
+ /// that generated the manifold.
+ public void Initialize(Manifold manifold, XForm xfA, float radiusA, XForm xfB, float radiusB)
+ {
+ if (manifold.PointCount == 0)
+ {
+ return;
+ }
+
+ switch (manifold.Type)
+ {
+ case ManifoldType.Circles:
+ {
+ Vec2 pointA = Common.Math.Mul(xfA, manifold.LocalPoint);
+ Vec2 pointB = Common.Math.Mul(xfB, manifold.Points[0].LocalPoint);
+ Vec2 normal = new Vec2(1.0f, 0.0f);
+ if (Vec2.DistanceSquared(pointA, pointB) > Common.Settings.FLT_EPSILON_SQUARED)
+ {
+ normal = pointB - pointA;
+ normal.Normalize();
+ }
+
+ Normal = normal;
+
+ Vec2 cA = pointA + radiusA * normal;
+ Vec2 cB = pointB - radiusB * normal;
+ Points[0] = 0.5f * (cA + cB);
+ }
+ break;
+
+ case ManifoldType.FaceA:
+ {
+ Vec2 normal = Common.Math.Mul(xfA.R, manifold.LocalPlaneNormal);
+ Vec2 planePoint = Common.Math.Mul(xfA, manifold.LocalPoint);
+
+ // Ensure normal points from A to B.
+ Normal = normal;
+
+ for (int i = 0; i < manifold.PointCount; ++i)
+ {
+ Vec2 clipPoint = Common.Math.Mul(xfB, manifold.Points[i].LocalPoint);
+ Vec2 cA = clipPoint + (radiusA - Vec2.Dot(clipPoint - planePoint, normal)) * normal;
+ Vec2 cB = clipPoint - radiusB * normal;
+ Points[i] = 0.5f * (cA + cB);
+ }
+ }
+ break;
+
+ case ManifoldType.FaceB:
+ {
+ Vec2 normal = Common.Math.Mul(xfB.R, manifold.LocalPlaneNormal);
+ Vec2 planePoint = Common.Math.Mul(xfB, manifold.LocalPoint);
+
+ // Ensure normal points from A to B.
+ Normal = -normal;
+
+ for (int i = 0; i < manifold.PointCount; ++i)
+ {
+ Vec2 clipPoint = Common.Math.Mul(xfA, manifold.Points[i].LocalPoint);
+ Vec2 cA = clipPoint - radiusA * normal;
+ Vec2 cB = clipPoint + (radiusB - Vec2.Dot(clipPoint - planePoint, normal)) * normal;
+ Points[i] = 0.5f * (cA + cB);
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Used for computing contact manifolds.
+ /// </summary>
+ public struct ClipVertex
+ {
+ public Vec2 V;
+ public ContactID ID;
+ }
+
+ /// <summary>
+ /// Ray-cast input data.
+ /// </summary>
+ public struct RayCastInput
+ {
+ public Vec2 P1, P2;
+ public float MaxFraction;
+ }
-}
+ /// <summary>
+ /// Ray-cast output data.
+ /// </summary>
+ public struct RayCastOutput
+ {
+ public Vec2 Normal;
+ public float Fraction;
+ public bool Hit;
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/PairManager.cs b/Box2d/Assets/Program/Box2d/Collision/PairManager.cs
new file mode 100644
index 0000000..0fcb8ab
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/PairManager.cs
@@ -0,0 +1,493 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// The pair manager is used by the broad-phase to quickly add/remove/find pairs
+// of overlapping proxies. It is based closely on code provided by Pierre Terdiman.
+// http://www.codercorner.com/IncrementalSAP.txt
+
+#define DEBUG
+
+using System;
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public class Pair
+ {
+ [Flags]
+ public enum PairStatus
+ {
+ PairBuffered = 0x0001,
+ PairRemoved = 0x0002,
+ PairFinal = 0x0004
+ }
+
+ public void SetBuffered() { Status |= PairStatus.PairBuffered; }
+ public void ClearBuffered() { Status &= ~PairStatus.PairBuffered; }
+ public bool IsBuffered() { return (Status & PairStatus.PairBuffered) == PairStatus.PairBuffered; }
+
+ public void SetRemoved() { Status |= PairStatus.PairRemoved; }
+ public void ClearRemoved() { Status &= ~PairStatus.PairRemoved; }
+ public bool IsRemoved() { return (Status & PairStatus.PairRemoved) == PairStatus.PairRemoved; }
+
+ public void SetFinal() { Status |= PairStatus.PairFinal; }
+ public bool IsFinal() { return (Status & PairStatus.PairFinal) == PairStatus.PairFinal; }
+
+ public object UserData;
+ public ushort ProxyId1;
+ public ushort ProxyId2;
+ public ushort Next;
+ public PairStatus Status;
+ }
+
+ public struct BufferedPair
+ {
+ public ushort ProxyId1;
+ public ushort ProxyId2;
+ }
+
+ public abstract class PairCallback
+ {
+ // This should return the new pair user data. It is ok if the
+ // user data is null.
+ public abstract object PairAdded(object proxyUserData1, object proxyUserData2);
+
+ // This should free the pair's user data. In extreme circumstances, it is possible
+ // this will be called with null pairUserData because the pair never existed.
+ public abstract void PairRemoved(object proxyUserData1, object proxyUserData2, object pairUserData);
+ }
+
+ public class PairManager
+ {
+ public static readonly ushort NullPair = Common.Math.USHRT_MAX;
+ public static readonly ushort NullProxy = Common.Math.USHRT_MAX;
+ public static readonly int TableCapacity = Settings.MaxPairs; // must be a power of two
+ public static readonly int TableMask = PairManager.TableCapacity - 1;
+
+ public BroadPhase _broadPhase;
+ public PairCallback _callback;
+ public Pair[] _pairs = new Pair[Settings.MaxPairs];
+ public ushort _freePair;
+ public int _pairCount;
+
+ public BufferedPair[] _pairBuffer = new BufferedPair[Settings.MaxPairs];
+ public int _pairBufferCount;
+
+ public ushort[] _hashTable = new ushort[PairManager.TableCapacity];
+
+ public PairManager()
+ {
+ Box2DXDebug.Assert(Common.Math.IsPowerOfTwo((uint)PairManager.TableCapacity) == true);
+ Box2DXDebug.Assert(PairManager.TableCapacity >= Settings.MaxPairs);
+ for (int i = 0; i < PairManager.TableCapacity; ++i)
+ {
+ _hashTable[i] = PairManager.NullPair;
+ }
+ _freePair = 0;
+ for (int i = 0; i < Settings.MaxPairs; ++i)
+ {
+ _pairs[i] = new Pair();//todo: need some pool here
+ _pairs[i].ProxyId1 = PairManager.NullProxy;
+ _pairs[i].ProxyId2 = PairManager.NullProxy;
+ _pairs[i].UserData = null;
+ _pairs[i].Status = 0;
+ _pairs[i].Next = (ushort)(i + 1U);
+ }
+ _pairs[Settings.MaxPairs - 1].Next = PairManager.NullPair;
+ _pairCount = 0;
+ _pairBufferCount = 0;
+ }
+
+ public void Initialize(BroadPhase broadPhase, PairCallback callback)
+ {
+ _broadPhase = broadPhase;
+ _callback = callback;
+ }
+
+ /*
+ As proxies are created and moved, many pairs are created and destroyed. Even worse, the same
+ pair may be added and removed multiple times in a single time step of the physics engine. To reduce
+ traffic in the pair manager, we try to avoid destroying pairs in the pair manager until the
+ end of the physics step. This is done by buffering all the RemovePair requests. AddPair
+ requests are processed immediately because we need the hash table entry for quick lookup.
+
+ All user user callbacks are delayed until the buffered pairs are confirmed in Commit.
+ This is very important because the user callbacks may be very expensive and client logic
+ may be harmed if pairs are added and removed within the same time step.
+
+ Buffer a pair for addition.
+ We may add a pair that is not in the pair manager or pair buffer.
+ We may add a pair that is already in the pair manager and pair buffer.
+ If the added pair is not a new pair, then it must be in the pair buffer (because RemovePair was called).
+ */
+ public void AddBufferedPair(int id1, int id2)
+ {
+ Box2DXDebug.Assert(id1 != PairManager.NullProxy && id2 != PairManager.NullProxy);
+ Box2DXDebug.Assert(_pairBufferCount < Settings.MaxPairs);
+
+ Pair pair = AddPair(id1, id2);
+
+ // If this pair is not in the pair buffer ...
+ if (pair.IsBuffered() == false)
+ {
+ // This must be a newly added pair.
+ Box2DXDebug.Assert(pair.IsFinal() == false);
+
+ // Add it to the pair buffer.
+ pair.SetBuffered();
+ _pairBuffer[_pairBufferCount].ProxyId1 = pair.ProxyId1;
+ _pairBuffer[_pairBufferCount].ProxyId2 = pair.ProxyId2;
+ ++_pairBufferCount;
+
+ Box2DXDebug.Assert(_pairBufferCount <= _pairCount);
+ }
+
+ // Confirm this pair for the subsequent call to Commit.
+ pair.ClearRemoved();
+
+ if (BroadPhase.IsValidate)
+ {
+ ValidateBuffer();
+ }
+ }
+
+ // Buffer a pair for removal.
+ public void RemoveBufferedPair(int id1, int id2)
+ {
+ Box2DXDebug.Assert(id1 != PairManager.NullProxy && id2 != PairManager.NullProxy);
+ Box2DXDebug.Assert(_pairBufferCount < Settings.MaxPairs);
+
+ Pair pair = Find(id1, id2);
+
+ if (pair == null)
+ {
+ // The pair never existed. This is legal (due to collision filtering).
+ return;
+ }
+
+ // If this pair is not in the pair buffer ...
+ if (pair.IsBuffered() == false)
+ {
+ // This must be an old pair.
+ Box2DXDebug.Assert(pair.IsFinal() == true);
+
+ pair.SetBuffered();
+ _pairBuffer[_pairBufferCount].ProxyId1 = pair.ProxyId1;
+ _pairBuffer[_pairBufferCount].ProxyId2 = pair.ProxyId2;
+ ++_pairBufferCount;
+
+ Box2DXDebug.Assert(_pairBufferCount <= _pairCount);
+ }
+
+ pair.SetRemoved();
+
+ if (BroadPhase.IsValidate)
+ {
+ ValidateBuffer();
+ }
+ }
+
+ public void Commit()
+ {
+ int removeCount = 0;
+
+ Proxy[] proxies = _broadPhase._proxyPool;
+
+ for (int i = 0; i < _pairBufferCount; ++i)
+ {
+ Pair pair = Find(_pairBuffer[i].ProxyId1, _pairBuffer[i].ProxyId2);
+ Box2DXDebug.Assert(pair.IsBuffered());
+ pair.ClearBuffered();
+
+ Box2DXDebug.Assert(pair.ProxyId1 < Settings.MaxProxies && pair.ProxyId2 < Settings.MaxProxies);
+
+ Proxy proxy1 = proxies[pair.ProxyId1];
+ Proxy proxy2 = proxies[pair.ProxyId2];
+
+ Box2DXDebug.Assert(proxy1.IsValid);
+ Box2DXDebug.Assert(proxy2.IsValid);
+
+ if (pair.IsRemoved())
+ {
+ // It is possible a pair was added then removed before a commit. Therefore,
+ // we should be careful not to tell the user the pair was removed when the
+ // the user didn't receive a matching add.
+ if (pair.IsFinal() == true)
+ {
+ _callback.PairRemoved(proxy1.UserData, proxy2.UserData, pair.UserData);
+ }
+
+ // Store the ids so we can actually remove the pair below.
+ _pairBuffer[removeCount].ProxyId1 = pair.ProxyId1;
+ _pairBuffer[removeCount].ProxyId2 = pair.ProxyId2;
+ ++removeCount;
+ }
+ else
+ {
+ Box2DXDebug.Assert(_broadPhase.TestOverlap(proxy1, proxy2) == true);
+
+ if (pair.IsFinal() == false)
+ {
+ pair.UserData = _callback.PairAdded(proxy1.UserData, proxy2.UserData);
+ pair.SetFinal();
+ }
+ }
+ }
+
+ for (int i = 0; i < removeCount; ++i)
+ {
+ RemovePair(_pairBuffer[i].ProxyId1, _pairBuffer[i].ProxyId2);
+ }
+
+ _pairBufferCount = 0;
+
+ if (BroadPhase.IsValidate)
+ {
+ ValidateTable();
+ }
+ }
+
+ private Pair Find(int proxyId1, int proxyId2)
+ {
+ if (proxyId1 > proxyId2)
+ Common.Math.Swap<int>(ref proxyId1, ref proxyId2);
+
+ uint hash = (uint)(Hash((uint)proxyId1, (uint)proxyId2) & PairManager.TableMask);
+
+ return Find(proxyId1, proxyId2, hash);
+ }
+
+ private Pair Find(int proxyId1, int proxyId2, uint hash)
+ {
+ int index = _hashTable[hash];
+
+ while (index != PairManager.NullPair && Equals(_pairs[index], proxyId1, proxyId2) == false)
+ {
+ index = _pairs[index].Next;
+ }
+
+ if (index == PairManager.NullPair)
+ {
+ return null;
+ }
+
+ Box2DXDebug.Assert(index < Settings.MaxPairs);
+
+ return _pairs[index];
+ }
+
+ // Returns existing pair or creates a new one.
+ private Pair AddPair(int proxyId1, int proxyId2)
+ {
+ if (proxyId1 > proxyId2)
+ Common.Math.Swap<int>(ref proxyId1, ref proxyId2);
+
+ int hash = (int)(Hash((uint)proxyId1, (uint)proxyId2) & PairManager.TableMask);
+
+ Pair pair = Find(proxyId1, proxyId2, (uint)hash);
+ if (pair != null)
+ {
+ return pair;
+ }
+
+ Box2DXDebug.Assert(_pairCount < Settings.MaxPairs && _freePair != PairManager.NullPair);
+
+ ushort pairIndex = _freePair;
+ pair = _pairs[pairIndex];
+ _freePair = pair.Next;
+
+ pair.ProxyId1 = (ushort)proxyId1;
+ pair.ProxyId2 = (ushort)proxyId2;
+ pair.Status = 0;
+ pair.UserData = null;
+ pair.Next = _hashTable[hash];
+
+ _hashTable[hash] = pairIndex;
+
+ ++_pairCount;
+
+ return pair;
+ }
+
+ // Removes a pair. The pair must exist.
+ private object RemovePair(int proxyId1, int proxyId2)
+ {
+ Box2DXDebug.Assert(_pairCount > 0);
+
+ if (proxyId1 > proxyId2)
+ Common.Math.Swap<int>(ref proxyId1, ref proxyId2);
+
+ int hash = (int)(Hash((uint)proxyId1, (uint)proxyId2) & PairManager.TableMask);
+
+ //uint16* node = &m_hashTable[hash];
+ ushort node = _hashTable[hash];
+ bool ion = false;
+ int ni = 0;
+ while (node != PairManager.NullPair)
+ {
+ if (Equals(_pairs[node], proxyId1, proxyId2))
+ {
+ //uint16 index = *node;
+ //*node = m_pairs[*node].next;
+
+ ushort index = node;
+ node = _pairs[node].Next;
+ if (ion)
+ _pairs[ni].Next = node;
+ else
+ {
+ _hashTable[hash] = node;
+ }
+
+ Pair pair = _pairs[index];
+ object userData = pair.UserData;
+
+ // Scrub
+ pair.Next = _freePair;
+ pair.ProxyId1 = PairManager.NullProxy;
+ pair.ProxyId2 = PairManager.NullProxy;
+ pair.UserData = null;
+ pair.Status = 0;
+
+ _freePair = index;
+ --_pairCount;
+ return userData;
+ }
+ else
+ {
+ //node = &m_pairs[*node].next;
+ ni = node;
+ node = _pairs[ni].Next;
+ ion = true;
+ }
+ }
+
+ Box2DXDebug.Assert(false);
+ return null;
+ }
+
+ private void ValidateBuffer()
+ {
+#if DEBUG
+ Box2DXDebug.Assert(_pairBufferCount <= _pairCount);
+
+ //std::sort(m_pairBuffer, m_pairBuffer + m_pairBufferCount);
+ BufferedPair[] tmp = new BufferedPair[_pairBufferCount];
+ Array.Copy(_pairBuffer, 0, tmp, 0, _pairBufferCount);
+ Array.Sort<BufferedPair>(tmp, BufferedPairSortPredicate);
+ Array.Copy(tmp, 0, _pairBuffer, 0, _pairBufferCount);
+
+ for (int i = 0; i < _pairBufferCount; ++i)
+ {
+ if (i > 0)
+ {
+ Box2DXDebug.Assert(Equals(_pairBuffer[i], _pairBuffer[i - 1]) == false);
+ }
+
+ Pair pair = Find(_pairBuffer[i].ProxyId1, _pairBuffer[i].ProxyId2);
+ Box2DXDebug.Assert(pair.IsBuffered());
+
+ Box2DXDebug.Assert(pair.ProxyId1 != pair.ProxyId2);
+ Box2DXDebug.Assert(pair.ProxyId1 < Settings.MaxProxies);
+ Box2DXDebug.Assert(pair.ProxyId2 < Settings.MaxProxies);
+
+ Proxy proxy1 = _broadPhase._proxyPool[pair.ProxyId1];
+ Proxy proxy2 = _broadPhase._proxyPool[pair.ProxyId2];
+
+ Box2DXDebug.Assert(proxy1.IsValid == true);
+ Box2DXDebug.Assert(proxy2.IsValid == true);
+ }
+#endif
+ }
+
+ private void ValidateTable()
+ {
+#if DEBUG
+ for (int i = 0; i < PairManager.TableCapacity; ++i)
+ {
+ ushort index = _hashTable[i];
+ while (index != PairManager.NullPair)
+ {
+ Pair pair = _pairs[index];
+ Box2DXDebug.Assert(pair.IsBuffered() == false);
+ Box2DXDebug.Assert(pair.IsFinal() == true);
+ Box2DXDebug.Assert(pair.IsRemoved() == false);
+
+ Box2DXDebug.Assert(pair.ProxyId1 != pair.ProxyId2);
+ Box2DXDebug.Assert(pair.ProxyId1 < Settings.MaxProxies);
+ Box2DXDebug.Assert(pair.ProxyId2 < Settings.MaxProxies);
+
+ Proxy proxy1 = _broadPhase._proxyPool[pair.ProxyId1];
+ Proxy proxy2 = _broadPhase._proxyPool[pair.ProxyId2];
+
+ Box2DXDebug.Assert(proxy1.IsValid == true);
+ Box2DXDebug.Assert(proxy2.IsValid == true);
+
+ Box2DXDebug.Assert(_broadPhase.TestOverlap(proxy1, proxy2) == true);
+
+ index = pair.Next;
+ }
+ }
+#endif
+ }
+
+ // Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm
+ // This assumes proxyId1 and proxyId2 are 16-bit.
+ private uint Hash(uint proxyId1, uint proxyId2)
+ {
+ uint key = (proxyId2 << 16) | proxyId1;
+ key = ~key + (key << 15);
+ key = key ^ (key >> 12);
+ key = key + (key << 2);
+ key = key ^ (key >> 4);
+ key = key * 2057;
+ key = key ^ (key >> 16);
+ return key;
+ }
+
+ private bool Equals(Pair pair, int proxyId1, int proxyId2)
+ {
+ return pair.ProxyId1 == proxyId1 && pair.ProxyId2 == proxyId2;
+ }
+
+ private bool Equals(ref BufferedPair pair1, ref BufferedPair pair2)
+ {
+ return pair1.ProxyId1 == pair2.ProxyId1 && pair1.ProxyId2 == pair2.ProxyId2;
+ }
+
+ public static int BufferedPairSortPredicate(BufferedPair pair1, BufferedPair pair2)
+ {
+ if (pair1.ProxyId1 < pair2.ProxyId1)
+ return 1;
+ else if (pair1.ProxyId1 > pair2.ProxyId1)
+ return -1;
+ else
+ {
+ if (pair1.ProxyId2 < pair2.ProxyId2)
+ return 1;
+ else if (pair1.ProxyId2 > pair2.ProxyId2)
+ return -1;
+ }
+
+ return 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/PairManager.cs.meta b/Box2d/Assets/Program/Box2d/Collision/PairManager.cs.meta
new file mode 100644
index 0000000..4aedb0e
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/PairManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 2c78d8fd3c4c22944a9cade8b7fdb31b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs b/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs
new file mode 100644
index 0000000..553accd
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs
@@ -0,0 +1,179 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ /// <summary>
+ /// A circle shape.
+ /// </summary>
+ public class CircleShape : Shape
+ {
+ // Position
+ internal Vec2 _position;
+
+ public CircleShape()
+ {
+ _type = ShapeType.CircleShape;
+ }
+
+ public override bool TestPoint(XForm transform, Vec2 p)
+ {
+ Vec2 center = transform.Position + Common.Math.Mul(transform.R, _position);
+ Vec2 d = p - center;
+ return Vec2.Dot(d, d) <= _radius * _radius;
+ }
+
+ // Collision Detection in Interactive 3D Environments by Gino van den Bergen
+ // From Section 3.1.2
+ // x = s + a * r
+ // norm(x) = radius
+ public override SegmentCollide TestSegment(XForm transform, out float lambda, out Vec2 normal, Segment segment, float maxLambda)
+ {
+ lambda = 0f;
+ normal = Vec2.Zero;
+
+ Vec2 position = transform.Position + Common.Math.Mul(transform.R, _position);
+ Vec2 s = segment.P1 - position;
+ float b = Vec2.Dot(s, s) - _radius * _radius;
+
+ // Does the segment start inside the circle?
+ if (b < 0.0f)
+ {
+ lambda = 0f;
+ return SegmentCollide.StartInsideCollide;
+ }
+
+ // Solve quadratic equation.
+ Vec2 r = segment.P2 - segment.P1;
+ float c = Vec2.Dot(s, r);
+ float rr = Vec2.Dot(r, r);
+ float sigma = c * c - rr * b;
+
+ // Check for negative discriminant and short segment.
+ if (sigma < 0.0f || rr < Common.Settings.FLT_EPSILON)
+ {
+ return SegmentCollide.MissCollide;
+ }
+
+ // Find the point of intersection of the line with the circle.
+ float a = -(c + Common.Math.Sqrt(sigma));
+
+ // Is the intersection point on the segment?
+ if (0.0f <= a && a <= maxLambda * rr)
+ {
+ a /= rr;
+ lambda = a;
+ normal = s + a * r;
+ normal.Normalize();
+ return SegmentCollide.HitCollide;
+ }
+
+ return SegmentCollide.MissCollide;
+ }
+
+ public override void ComputeAABB(out AABB aabb, XForm transform)
+ {
+ aabb = new AABB();
+
+ Vec2 p = transform.Position + Common.Math.Mul(transform.R, _position);
+ aabb.LowerBound.Set(p.X - _radius, p.Y - _radius);
+ aabb.UpperBound.Set(p.X + _radius, p.Y + _radius);
+ }
+
+ public override void ComputeMass(out MassData massData, float density)
+ {
+ massData = new MassData();
+
+ massData.Mass = density * Settings.Pi * _radius * _radius;
+ massData.Center = _position;
+
+ // inertia about the local origin
+ massData.I = massData.Mass * (0.5f * _radius * _radius + Vec2.Dot(_position, _position));
+ }
+
+ public override float ComputeSubmergedArea(Vec2 normal, float offset, XForm xf, out Vec2 c)
+ {
+ Vec2 p = Box2DX.Common.Math.Mul(xf, _position);
+ float l = -(Vec2.Dot(normal, p) - offset);
+ if (l < -_radius + Box2DX.Common.Settings.FLT_EPSILON)
+ {
+ //Completely dry
+ c = new Vec2();
+ return 0;
+ }
+ if (l > _radius)
+ {
+ //Completely wet
+ c = p;
+ return Box2DX.Common.Settings.Pi * _radius * _radius;
+ }
+
+ //Magic
+ float r2 = _radius * _radius;
+ float l2 = l * l;
+ float area = r2 * ((float)System.Math.Asin(l / _radius) + Box2DX.Common.Settings.Pi / 2) +
+ l * Box2DX.Common.Math.Sqrt(r2 - l2);
+ float com = -2.0f / 3.0f * (float)System.Math.Pow(r2 - l2, 1.5f) / area;
+
+ c.X = p.X + normal.X * com;
+ c.Y = p.Y + normal.Y * com;
+
+ return area;
+ }
+
+ /// <summary>
+ /// Get the supporting vertex index in the given direction.
+ /// </summary>
+ public override int GetSupport(Vec2 d)
+ {
+ return 0;
+ }
+
+ /// <summary>
+ /// Get the supporting vertex in the given direction.
+ /// </summary>
+ public override Vec2 GetSupportVertex(Vec2 d)
+ {
+ return _position;
+ }
+
+ /// <summary>
+ /// Get a vertex by index. Used by Distance.
+ /// </summary>
+ public override Vec2 GetVertex(int index)
+ {
+ Box2DXDebug.Assert(index == 0);
+ return _position;
+ }
+
+ public override float ComputeSweepRadius(Vec2 pivot)
+ {
+ return Vec2.Distance(_position, pivot);
+ }
+
+ /// <summary>
+ /// Get the vertex count.
+ /// </summary>
+ public int VertexCount { get { return 1; } }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs.meta
new file mode 100644
index 0000000..f9be13f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/CircleShape.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bd3059081b10a7c49be772d675ea7525
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs b/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs
new file mode 100644
index 0000000..348a293
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs
@@ -0,0 +1,277 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ public class EdgeShape : Shape
+ {
+ public Vec2 _v1;
+ public Vec2 _v2;
+
+ public float _length;
+
+ public Vec2 _normal;
+
+ public Vec2 _direction;
+
+ // Unit vector halfway between m_direction and m_prevEdge.m_direction:
+ public Vec2 _cornerDir1;
+
+ // Unit vector halfway between m_direction and m_nextEdge.m_direction:
+ public Vec2 _cornerDir2;
+
+ public bool _cornerConvex1;
+ public bool _cornerConvex2;
+
+ public EdgeShape _nextEdge;
+ public EdgeShape _prevEdge;
+
+ public EdgeShape()
+ {
+ _type = ShapeType.EdgeShape;
+ _radius = Settings.PolygonRadius;
+ }
+
+ public override void Dispose()
+ {
+ if (_prevEdge != null)
+ {
+ _prevEdge._nextEdge = null;
+ }
+
+ if (_nextEdge != null)
+ {
+ _nextEdge._prevEdge = null;
+ }
+ }
+
+ public void Set(Vec2 v1, Vec2 v2)
+ {
+ _v1 = v1;
+ _v2 = v2;
+
+ _direction = _v2 - _v1;
+ _length = _direction.Normalize();
+ _normal = Vec2.Cross(_direction, 1.0f);
+
+ _cornerDir1 = _normal;
+ _cornerDir2 = -1.0f * _normal;
+ }
+
+ public override bool TestPoint(XForm transform, Vec2 p)
+ {
+ return false;
+ }
+
+ public override SegmentCollide TestSegment(XForm transform, out float lambda, out Vec2 normal, Segment segment, float maxLambda)
+ {
+ Vec2 r = segment.P2 - segment.P1;
+ Vec2 v1 = Common.Math.Mul(transform, _v1);
+ Vec2 d = Common.Math.Mul(transform, _v2) - v1;
+ Vec2 n = Vec2.Cross(d, 1.0f);
+
+ float k_slop = 100.0f * Common.Settings.FLT_EPSILON;
+ float denom = -Vec2.Dot(r, n);
+
+ // Cull back facing collision and ignore parallel segments.
+ if (denom > k_slop)
+ {
+ // Does the segment intersect the infinite line associated with this segment?
+ Vec2 b = segment.P1 - v1;
+ float a = Vec2.Dot(b, n);
+
+ if (0.0f <= a && a <= maxLambda * denom)
+ {
+ float mu2 = -r.X * b.Y + r.Y * b.X;
+
+ // Does the segment intersect this segment?
+ if (-k_slop * denom <= mu2 && mu2 <= denom * (1.0f + k_slop))
+ {
+ a /= denom;
+ n.Normalize();
+ lambda = a;
+ normal = n;
+ return SegmentCollide.HitCollide;
+ }
+ }
+ }
+
+ lambda = 0;
+ normal = new Vec2();
+ return SegmentCollide.MissCollide;
+ }
+
+ public override void ComputeAABB(out AABB aabb, XForm transform)
+ {
+ Vec2 v1 = Common.Math.Mul(transform, _v1);
+ Vec2 v2 = Common.Math.Mul(transform, _v2);
+
+ Vec2 r = new Vec2(_radius, _radius);
+ aabb.LowerBound = Common.Math.Min(v1, v2) - r;
+ aabb.UpperBound = Common.Math.Max(v1, v2) + r;
+ }
+
+ public override void ComputeMass(out MassData massData, float density)
+ {
+ massData.Mass = 0.0f;
+ massData.Center = _v1;
+ massData.I = 0.0f;
+ }
+
+ public void SetPrevEdge(EdgeShape edge, Vec2 cornerDir, bool convex)
+ {
+ _prevEdge = edge;
+ _cornerDir1 = cornerDir;
+ _cornerConvex1 = convex;
+ }
+
+ public void SetNextEdge(EdgeShape edge, Vec2 cornerDir, bool convex)
+ {
+ _nextEdge = edge;
+ _cornerDir2 = cornerDir;
+ _cornerConvex2 = convex;
+ }
+
+ public override float ComputeSubmergedArea(Vec2 normal, float offset, XForm xf, out Vec2 c)
+ {
+ //Note that v0 is independent of any details of the specific edge
+ //We are relying on v0 being consistent between multiple edges of the same body
+ Vec2 v0 = offset * normal;
+ //b2Vec2 v0 = xf.position + (offset - b2Dot(normal, xf.position)) * normal;
+
+ Vec2 v1 = Common.Math.Mul(xf, _v1);
+ Vec2 v2 = Common.Math.Mul(xf, _v2);
+
+ float d1 = Vec2.Dot(normal, v1) - offset;
+ float d2 = Vec2.Dot(normal, v2) - offset;
+
+ if (d1 > 0.0f)
+ {
+ if (d2 > 0.0f)
+ {
+ c = new Vec2();
+ return 0.0f;
+ }
+ else
+ {
+ v1 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2;
+ }
+ }
+ else
+ {
+ if (d2 > 0.0f)
+ {
+ v2 = -d2 / (d1 - d2) * v1 + d1 / (d1 - d2) * v2;
+ }
+ else
+ {
+ //Nothing
+ }
+ }
+
+ // v0,v1,v2 represents a fully submerged triangle
+ float k_inv3 = 1.0f / 3.0f;
+
+ // Area weighted centroid
+ c = k_inv3 * (v0 + v1 + v2);
+
+ Vec2 e1 = v1 - v0;
+ Vec2 e2 = v2 - v0;
+
+ return 0.5f * Vec2.Cross(e1, e2);
+ }
+
+ public float Length
+ {
+ get { return _length; }
+ }
+
+ public Vec2 Vertex1
+ {
+ get { return _v1; }
+ }
+
+ public Vec2 Vertex2
+ {
+ get { return _v2; }
+ }
+
+ public Vec2 NormalVector
+ {
+ get { return _normal; }
+ }
+
+ public Vec2 DirectionVector
+ {
+ get { return _direction; }
+ }
+
+ public Vec2 Corner1Vector
+ {
+ get { return _cornerDir1; }
+ }
+
+ public Vec2 Corner2Vector
+ {
+ get { return _cornerDir2; }
+ }
+
+ public override int GetSupport(Vec2 d)
+ {
+ return Vec2.Dot(_v1, d) > Vec2.Dot(_v2, d) ? 0 : 1;
+ }
+
+ public override Vec2 GetSupportVertex(Vec2 d)
+ {
+ return Vec2.Dot(_v1, d) > Vec2.Dot(_v2, d) ? _v1 : _v2;
+ }
+
+ public override Vec2 GetVertex(int index)
+ {
+ Box2DXDebug.Assert(0 <= index && index < 2);
+ if (index == 0) return _v1;
+ else return _v2;
+ }
+
+ public bool Corner1IsConvex
+ {
+ get { return _cornerConvex1; }
+ }
+
+ public bool Corner2IsConvex
+ {
+ get { return _cornerConvex2; }
+ }
+
+ public override float ComputeSweepRadius(Vec2 pivot)
+ {
+ float ds1 = Vec2.DistanceSquared(_v1, pivot);
+ float ds2 = Vec2.DistanceSquared(_v2, pivot);
+ return Common.Math.Sqrt(Common.Math.Max(ds1, ds2));
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs.meta
new file mode 100644
index 0000000..8051fd4
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/EdgeShape.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1e86753e9f98b2d429a099076e61bf32
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/PolygonShape.cs b/Box2d/Assets/Program/Box2d/Collision/Shapes/PolygonShape.cs
index 85ae672..6a655f7 100644
--- a/Box2d/Assets/Program/Box2d/Collision/Shapes/PolygonShape.cs
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/PolygonShape.cs
@@ -1,7 +1,724 @@
-using System.Collections;
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#define DEBUG
+
+using System;
using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
-namespace Box2D
+namespace Box2DX.Collision
{
+ /// <summary>
+ /// A convex polygon. It is assumed that the interior of the polygon is to the left of each edge.
+ /// </summary>
+ public class PolygonShape : Shape
+ {
+ internal Vec2 _centroid;
+ internal Vec2[] _vertices = new Vec2[Settings.MaxPolygonVertices];
+ internal Vec2[] _normals = new Vec2[Settings.MaxPolygonVertices];
+
+ internal int _vertexCount;
+
+ public int VertexCount
+ {
+ get { return _vertexCount; }
+ }
+
+ public Vec2[] Vertices
+ {
+ get { return _vertices; }
+ }
+
+ /// <summary>
+ /// Copy vertices. This assumes the vertices define a convex polygon.
+ /// It is assumed that the exterior is the the right of each edge.
+ /// </summary>
+ public void Set(Vec2[] vertices, int count)
+ {
+ Box2DXDebug.Assert(3 <= count && count <= Settings.MaxPolygonVertices);
+ _vertexCount = count;
+
+ int i;
+ // Copy vertices.
+ for (i = 0; i < _vertexCount; ++i)
+ {
+ _vertices[i] = vertices[i];
+ }
+
+ // Compute normals. Ensure the edges have non-zero length.
+ for (i = 0; i < _vertexCount; ++i)
+ {
+ int i1 = i;
+ int i2 = i + 1 < count ? i + 1 : 0;
+ Vec2 edge = _vertices[i2] - _vertices[i1];
+ Box2DXDebug.Assert(edge.LengthSquared() > Settings.FLT_EPSILON_SQUARED);
+ _normals[i] = Vec2.Cross(edge, 1.0f);
+ _normals[i].Normalize();
+ }
+
+#if DEBUG
+ // Ensure the polygon is convex and the interior
+ // is to the left of each edge.
+ for (i = 0; i < _vertexCount; ++i)
+ {
+ int i1 = i;
+ int i2 = i + 1 < count ? i + 1 : 0;
+ Vec2 edge = _vertices[i2] - _vertices[i1];
+
+ for (int j = 0; j < _vertexCount; ++j)
+ {
+ // Don't check vertices on the current edge.
+ if (j == i1 || j == i2)
+ {
+ continue;
+ }
+
+ Vec2 r = _vertices[j] - _vertices[i1];
+
+ // Your polygon is non-convex (it has an indentation) or
+ // has colinear edges.
+ float s = Vec2.Cross(edge, r);
+ Box2DXDebug.Assert(s > 0.0f);
+ }
+ }
+#endif
+
+ // Compute the polygon centroid.
+ _centroid = ComputeCentroid(_vertices, _vertexCount);
+ }
+
+ /// <summary>
+ /// Build vertices to represent an axis-aligned box.
+ /// </summary>
+ /// <param name="hx">The half-width</param>
+ /// <param name="hy">The half-height.</param>
+ public void SetAsBox(float hx, float hy)
+ {
+ _vertexCount = 4;
+ _vertices[0].Set(-hx, -hy);
+ _vertices[1].Set(hx, -hy);
+ _vertices[2].Set(hx, hy);
+ _vertices[3].Set(-hx, hy);
+ _normals[0].Set(0.0f, -1.0f);
+ _normals[1].Set(1.0f, 0.0f);
+ _normals[2].Set(0.0f, 1.0f);
+ _normals[3].Set(-1.0f, 0.0f);
+ _centroid = new Vec2(0);
+ }
+
+
+ /// <summary>
+ /// Build vertices to represent an oriented box.
+ /// </summary>
+ /// <param name="hx">The half-width</param>
+ /// <param name="hy">The half-height.</param>
+ /// <param name="center">The center of the box in local coordinates.</param>
+ /// <param name="angle">The rotation of the box in local coordinates.</param>
+ public void SetAsBox(float hx, float hy, Vec2 center, float angle)
+ {
+ SetAsBox(hx, hy);
+
+ XForm xf = new XForm();
+ xf.Position = center;
+ xf.R.Set(angle);
+
+ // Transform vertices and normals.
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ _vertices[i] = Common.Math.Mul(xf, _vertices[i]);
+ _normals[i] = Common.Math.Mul(xf.R, _normals[i]);
+ }
+ }
+
+ public void SetAsEdge(Vec2 v1, Vec2 v2)
+ {
+ _vertexCount = 2;
+ _vertices[0] = v1;
+ _vertices[1] = v2;
+ _centroid = 0.5f * (v1 + v2);
+ _normals[0] = Vec2.Cross(v2 - v1, 1.0f);
+ _normals[0].Normalize();
+ _normals[1] = -_normals[0];
+ }
+
+ public override bool TestPoint(XForm xf, Vec2 p)
+ {
+ Vec2 pLocal = Common.Math.MulT(xf.R, p - xf.Position);
+
+ int vc = _vertexCount;
+ for (int i = 0; i < vc; ++i)
+ {
+ float dot = Vec2.Dot(_normals[i], pLocal - _vertices[i]);
+ if (dot > 0.0f)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public override SegmentCollide TestSegment(XForm xf, out float lambda, out Vec2 normal, Segment segment, float maxLambda)
+ {
+ lambda = 0f;
+ normal = Vec2.Zero;
+
+ float lower = 0.0f, upper = maxLambda;
+
+ Vec2 p1 = Common.Math.MulT(xf.R, segment.P1 - xf.Position);
+ Vec2 p2 = Common.Math.MulT(xf.R, segment.P2 - xf.Position);
+ Vec2 d = p2 - p1;
+ int index = -1;
+
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ // p = p1 + a * d
+ // dot(normal, p - v) = 0
+ // dot(normal, p1 - v) + a * dot(normal, d) = 0
+ float numerator = Vec2.Dot(_normals[i], _vertices[i] - p1);
+ float denominator = Vec2.Dot(_normals[i], d);
+
+ if (denominator == 0.0f)
+ {
+ if (numerator < 0.0f)
+ {
+ return SegmentCollide.MissCollide;
+ }
+ }
+ else
+ {
+ // Note: we want this predicate without division:
+ // lower < numerator / denominator, where denominator < 0
+ // Since denominator < 0, we have to flip the inequality:
+ // lower < numerator / denominator <==> denominator * lower > numerator.
+ if (denominator < 0.0f && numerator < lower * denominator)
+ {
+ // Increase lower.
+ // The segment enters this half-space.
+ lower = numerator / denominator;
+ index = i;
+ }
+ else if (denominator > 0.0f && numerator < upper * denominator)
+ {
+ // Decrease upper.
+ // The segment exits this half-space.
+ upper = numerator / denominator;
+ }
+ }
+
+ if (upper < lower)
+ {
+ return SegmentCollide.MissCollide;
+ }
+ }
+
+ Box2DXDebug.Assert(0.0f <= lower && lower <= maxLambda);
+
+ if (index >= 0)
+ {
+ lambda = lower;
+ normal = Common.Math.Mul(xf.R, _normals[index]);
+ return SegmentCollide.HitCollide;
+ }
+
+ lambda = 0f;
+ return SegmentCollide.StartInsideCollide;
+ }
+
+ public override void ComputeAABB(out AABB aabb, XForm xf)
+ {
+ Vec2 lower = Common.Math.Mul(xf, _vertices[0]);
+ Vec2 upper = lower;
+
+ for (int i = 1; i < _vertexCount; ++i)
+ {
+ Vec2 v = Common.Math.Mul(xf, _vertices[i]);
+ lower = Common.Math.Min(lower, v);
+ upper = Common.Math.Max(upper, v);
+ }
+
+ Vec2 r = new Vec2(_radius);
+ aabb.LowerBound = lower - r;
+ aabb.UpperBound = upper + r;
+ }
+
+ public override void ComputeMass(out MassData massData, float denstity)
+ {
+ // Polygon mass, centroid, and inertia.
+ // Let rho be the polygon density in mass per unit area.
+ // Then:
+ // mass = rho * int(dA)
+ // centroid.x = (1/mass) * rho * int(x * dA)
+ // centroid.y = (1/mass) * rho * int(y * dA)
+ // I = rho * int((x*x + y*y) * dA)
+ //
+ // We can compute these integrals by summing all the integrals
+ // for each triangle of the polygon. To evaluate the integral
+ // for a single triangle, we make a change of variables to
+ // the (u,v) coordinates of the triangle:
+ // x = x0 + e1x * u + e2x * v
+ // y = y0 + e1y * u + e2y * v
+ // where 0 <= u && 0 <= v && u + v <= 1.
+ //
+ // We integrate u from [0,1-v] and then v from [0,1].
+ // We also need to use the Jacobian of the transformation:
+ // D = cross(e1, e2)
+ //
+ // Simplification: triangle centroid = (1/3) * (p1 + p2 + p3)
+ //
+ // The rest of the derivation is handled by computer algebra.
+
+ Box2DXDebug.Assert(_vertexCount >= 3);
+
+ Vec2 center = new Vec2(0);
+ float area = 0.0f;
+ float I = 0.0f;
+
+ // pRef is the reference point for forming triangles.
+ // It's location doesn't change the result (except for rounding error).
+ Vec2 pRef = new Vec2(0);
+
+#if O
+ // This code would put the reference point inside the polygon.
+ for (int i = 0; i < vCount; ++i)
+ {
+ pRef += _vertices[i];
+ }
+ pRef *= 1.0f / count;
+#endif
+
+ const float k_inv3 = 1.0f / 3.0f;
+
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ // Triangle vertices.
+ Vec2 p1 = pRef;
+ Vec2 p2 = _vertices[i];
+ Vec2 p3 = i + 1 < _vertexCount ? _vertices[i + 1] : _vertices[0];
+
+ Vec2 e1 = p2 - p1;
+ Vec2 e2 = p3 - p1;
+
+ float D = Vec2.Cross(e1, e2);
+
+ float triangleArea = 0.5f * D;
+ area += triangleArea;
+
+ // Area weighted centroid
+ center += triangleArea * k_inv3 * (p1 + p2 + p3);
+
+ float px = p1.X, py = p1.Y;
+ float ex1 = e1.X, ey1 = e1.Y;
+ float ex2 = e2.X, ey2 = e2.Y;
+
+ float intx2 = k_inv3 * (0.25f * (ex1 * ex1 + ex2 * ex1 + ex2 * ex2) + (px * ex1 + px * ex2)) + 0.5f * px * px;
+ float inty2 = k_inv3 * (0.25f * (ey1 * ey1 + ey2 * ey1 + ey2 * ey2) + (py * ey1 + py * ey2)) + 0.5f * py * py;
+
+ I += D * (intx2 + inty2);
+ }
+
+ // Total mass
+ massData.Mass = denstity * area;
+
+ // Center of mass
+ Box2DXDebug.Assert(area > Common.Settings.FLT_EPSILON);
+ center *= 1.0f / area;
+ massData.Center = center;
+
+ // Inertia tensor relative to the local origin.
+ massData.I = denstity * I;
+ }
+
+ public override float ComputeSubmergedArea(Vec2 normal, float offset, XForm xf, out Vec2 c)
+ {
+ //Transform plane into shape co-ordinates
+ Vec2 normalL = Box2DX.Common.Math.MulT(xf.R, normal);
+ float offsetL = offset - Vec2.Dot(normal, xf.Position);
+
+ float[] depths = new float[Common.Settings.MaxPolygonVertices];
+ int diveCount = 0;
+ int intoIndex = -1;
+ int outoIndex = -1;
+
+ bool lastSubmerged = false;
+ int i;
+ for (i = 0; i < _vertexCount; i++)
+ {
+ depths[i] = Vec2.Dot(normalL, _vertices[i]) - offsetL;
+ bool isSubmerged = depths[i] < -Common.Settings.FLT_EPSILON;
+ if (i > 0)
+ {
+ if (isSubmerged)
+ {
+ if (!lastSubmerged)
+ {
+ intoIndex = i - 1;
+ diveCount++;
+ }
+ }
+ else
+ {
+ if (lastSubmerged)
+ {
+ outoIndex = i - 1;
+ diveCount++;
+ }
+ }
+ }
+ lastSubmerged = isSubmerged;
+ }
+ switch (diveCount)
+ {
+ case 0:
+ if (lastSubmerged)
+ {
+ //Completely submerged
+ MassData md;
+ ComputeMass(out md, 1f);
+ c = Common.Math.Mul(xf, md.Center);
+ return md.Mass;
+ }
+ else
+ {
+ //Completely dry
+ c = new Vec2();
+ return 0;
+ }
+ break;
+ case 1:
+ if (intoIndex == -1)
+ {
+ intoIndex = _vertexCount - 1;
+ }
+ else
+ {
+ outoIndex = _vertexCount - 1;
+ }
+ break;
+ }
+ int intoIndex2 = (intoIndex + 1) % _vertexCount;
+ int outoIndex2 = (outoIndex + 1) % _vertexCount;
+
+ float intoLambda = (0 - depths[intoIndex]) / (depths[intoIndex2] - depths[intoIndex]);
+ float outoLambda = (0 - depths[outoIndex]) / (depths[outoIndex2] - depths[outoIndex]);
+
+ Vec2 intoVec = new Vec2(_vertices[intoIndex].X * (1 - intoLambda) + _vertices[intoIndex2].X * intoLambda,
+ _vertices[intoIndex].Y * (1 - intoLambda) + _vertices[intoIndex2].Y * intoLambda);
+ Vec2 outoVec = new Vec2(_vertices[outoIndex].X * (1 - outoLambda) + _vertices[outoIndex2].X * outoLambda,
+ _vertices[outoIndex].Y * (1 - outoLambda) + _vertices[outoIndex2].Y * outoLambda);
+
+ //Initialize accumulator
+ float area = 0;
+ Vec2 center = new Vec2(0);
+ Vec2 p2 = _vertices[intoIndex2];
+ Vec2 p3;
+
+ const float k_inv3 = 1.0f / 3.0f;
+
+ //An awkward loop from intoIndex2+1 to outIndex2
+ i = intoIndex2;
+ while (i != outoIndex2)
+ {
+ i = (i + 1) % _vertexCount;
+ if (i == outoIndex2)
+ p3 = outoVec;
+ else
+ p3 = _vertices[i];
+ //Add the triangle formed by intoVec,p2,p3
+ {
+ Vec2 e1 = p2 - intoVec;
+ Vec2 e2 = p3 - intoVec;
+
+ float D = Vec2.Cross(e1, e2);
+
+ float triangleArea = 0.5f * D;
+
+ area += triangleArea;
+
+ // Area weighted centroid
+ center += triangleArea * k_inv3 * (intoVec + p2 + p3);
+
+ }
+ //
+ p2 = p3;
+ }
+
+ //Normalize and transform centroid
+ center *= 1.0f / area;
+
+ c = Common.Math.Mul(xf, center);
+
+ return area;
+ }
+
+ public override float ComputeSweepRadius(Vec2 pivot)
+ {
+ int vCount = _vertexCount;
+ Box2DXDebug.Assert(vCount > 0);
+ float sr = Vec2.DistanceSquared(_vertices[0], pivot);
+ for (int i = 1; i < vCount; ++i)
+ {
+ sr = Common.Math.Max(sr, Vec2.DistanceSquared(_vertices[i], pivot));
+ }
+
+ return Common.Math.Sqrt(sr);
+ }
+
+ /// <summary>
+ /// Get the supporting vertex index in the given direction.
+ /// </summary>
+ public override int GetSupport(Vec2 d)
+ {
+ int bestIndex = 0;
+ float bestValue = Vec2.Dot(_vertices[0], d);
+ for (int i = 1; i < _vertexCount; ++i)
+ {
+ float value = Vec2.Dot(_vertices[i], d);
+ if (value > bestValue)
+ {
+ bestIndex = i;
+ bestValue = value;
+ }
+ }
+
+ return bestIndex;
+ }
+
+ public override Vec2 GetSupportVertex(Vec2 d)
+ {
+ int bestIndex = 0;
+ float bestValue = Vec2.Dot(_vertices[0], d);
+ for (int i = 1; i < _vertexCount; ++i)
+ {
+ float value = Vec2.Dot(_vertices[i], d);
+ if (value > bestValue)
+ {
+ bestIndex = i;
+ bestValue = value;
+ }
+ }
+
+ return _vertices[bestIndex];
+ }
+
+ public override Vec2 GetVertex(int index)
+ {
+ Box2DXDebug.Assert(0 <= index && index < _vertexCount);
+ return _vertices[index];
+ }
+
+ public static Vec2 ComputeCentroid(Vec2[] vs, int count)
+ {
+ Box2DXDebug.Assert(count >= 3);
+
+ Vec2 c = new Vec2(0f);
+ float area = 0f;
+
+ // pRef is the reference point for forming triangles.
+ // It's location doesn't change the result (except for rounding error).
+ Vec2 pRef = new Vec2(0f);
+#if O
+ // This code would put the reference point inside the polygon.
+ for (int i = 0; i < count; ++i)
+ {
+ pRef += vs[i];
+ }
+ pRef *= 1.0f / count;
+#endif
+
+ const float inv3 = 1.0f / 3.0f;
+
+ for (int i = 0; i < count; ++i)
+ {
+ // Triangle vertices.
+ Vec2 p1 = pRef;
+ Vec2 p2 = vs[i];
+ Vec2 p3 = i + 1 < count ? vs[i + 1] : vs[0];
+
+ Vec2 e1 = p2 - p1;
+ Vec2 e2 = p3 - p1;
+
+ float D = Vec2.Cross(e1, e2);
+
+ float triangleArea = 0.5f * D;
+ area += triangleArea;
+
+ // Area weighted centroid
+ c += triangleArea * inv3 * (p1 + p2 + p3);
+ }
+
+ // Centroid
+ Box2DXDebug.Assert(area > Common.Settings.FLT_EPSILON);
+ c *= 1.0f / area;
+ return c;
+ }
+
+ public PolygonShape()
+ {
+ _type = ShapeType.PolygonShape;
+ _radius = Settings.PolygonRadius;
+
+ /*Box2DXDebug.Assert(def.Type == ShapeType.PolygonShape);
+ _type = ShapeType.PolygonShape;
+ PolygonDef poly = (PolygonDef)def;
+
+ // Get the vertices transformed into the body frame.
+ _vertexCount = poly.VertexCount;
+ Box2DXDebug.Assert(3 <= _vertexCount && _vertexCount <= Settings.MaxPolygonVertices);
+
+ // Copy vertices.
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ _vertices[i] = poly.Vertices[i];
+ }
+
+ // Compute normals. Ensure the edges have non-zero length.
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ int i1 = i;
+ int i2 = i + 1 < _vertexCount ? i + 1 : 0;
+ Vec2 edge = _vertices[i2] - _vertices[i1];
+ Box2DXDebug.Assert(edge.LengthSquared() > Common.Settings.FLT_EPSILON * Common.Settings.FLT_EPSILON);
+ _normals[i] = Vec2.Cross(edge, 1.0f);
+ _normals[i].Normalize();
+ }
+
+#if DEBUG
+ // Ensure the polygon is convex.
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ for (int j = 0; j < _vertexCount; ++j)
+ {
+ // Don't check vertices on the current edge.
+ if (j == i || j == (i + 1) % _vertexCount)
+ {
+ continue;
+ }
+
+ // Your polygon is non-convex (it has an indentation).
+ // Or your polygon is too skinny.
+ float s = Vec2.Dot(_normals[i], _vertices[j] - _vertices[i]);
+ Box2DXDebug.Assert(s < -Settings.LinearSlop);
+ }
+ }
+
+ // Ensure the polygon is counter-clockwise.
+ for (int i = 1; i < _vertexCount; ++i)
+ {
+ float cross = Vec2.Cross(_normals[i - 1], _normals[i]);
+
+ // Keep asinf happy.
+ cross = Common.Math.Clamp(cross, -1.0f, 1.0f);
+
+ // You have consecutive edges that are almost parallel on your polygon.
+ float angle = (float)System.Math.Asin(cross);
+ Box2DXDebug.Assert(angle > Settings.AngularSlop);
+ }
+#endif
+
+ // Compute the polygon centroid.
+ _centroid = ComputeCentroid(poly.Vertices, poly.VertexCount);
+
+ // Compute the oriented bounding box.
+ ComputeOBB(out _obb, _vertices, _vertexCount);
+
+ // Create core polygon shape by shifting edges inward.
+ // Also compute the min/max radius for CCD.
+ for (int i = 0; i < _vertexCount; ++i)
+ {
+ int i1 = i - 1 >= 0 ? i - 1 : _vertexCount - 1;
+ int i2 = i;
+
+ Vec2 n1 = _normals[i1];
+ Vec2 n2 = _normals[i2];
+ Vec2 v = _vertices[i] - _centroid; ;
+
+ Vec2 d = new Vec2();
+ d.X = Vec2.Dot(n1, v) - Settings.ToiSlop;
+ d.Y = Vec2.Dot(n2, v) - Settings.ToiSlop;
+
+ // Shifting the edge inward by b2_toiSlop should
+ // not cause the plane to pass the centroid.
+
+ // Your shape has a radius/extent less than b2_toiSlop.
+ Box2DXDebug.Assert(d.X >= 0.0f);
+ Box2DXDebug.Assert(d.Y >= 0.0f);
+ Mat22 A = new Mat22();
+ A.Col1.X = n1.X; A.Col2.X = n1.Y;
+ A.Col1.Y = n2.X; A.Col2.Y = n2.Y;
+ _coreVertices[i] = A.Solve(d) + _centroid;
+ }*/
+ }
+
+ /*// http://www.geometrictools.com/Documentation/MinimumAreaRectangle.pdf
+ public static void ComputeOBB(out OBB obb, Vec2[] vs, int count)
+ {
+ obb = new OBB();
+
+ Box2DXDebug.Assert(count <= Settings.MaxPolygonVertices);
+ Vec2[] p = new Vec2[Settings.MaxPolygonVertices + 1];
+ for (int i = 0; i < count; ++i)
+ {
+ p[i] = vs[i];
+ }
+ p[count] = p[0];
+
+ float minArea = Common.Settings.FLT_MAX;
+
+ for (int i = 1; i <= count; ++i)
+ {
+ Vec2 root = p[i - 1];
+ Vec2 ux = p[i] - root;
+ float length = ux.Normalize();
+ Box2DXDebug.Assert(length > Common.Settings.FLT_EPSILON);
+ Vec2 uy = new Vec2(-ux.Y, ux.X);
+ Vec2 lower = new Vec2(Common.Settings.FLT_MAX, Common.Settings.FLT_MAX);
+ Vec2 upper = new Vec2(-Common.Settings.FLT_MAX, -Common.Settings.FLT_MAX);
+
+ for (int j = 0; j < count; ++j)
+ {
+ Vec2 d = p[j] - root;
+ Vec2 r = new Vec2();
+ r.X = Vec2.Dot(ux, d);
+ r.Y = Vec2.Dot(uy, d);
+ lower = Common.Math.Min(lower, r);
+ upper = Common.Math.Max(upper, r);
+ }
+
+ float area = (upper.X - lower.X) * (upper.Y - lower.Y);
+ if (area < 0.95f * minArea)
+ {
+ minArea = area;
+ obb.R.Col1 = ux;
+ obb.R.Col2 = uy;
+ Vec2 center = 0.5f * (lower + upper);
+ obb.Center = root + Common.Math.Mul(obb.R, center);
+ obb.Extents = 0.5f * (upper - lower);
+ }
+ }
-}
+ Box2DXDebug.Assert(minArea < Common.Settings.FLT_MAX);
+ }*/
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs b/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs
new file mode 100644
index 0000000..1afd116
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs
@@ -0,0 +1,144 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using Box2DX.Common;
+
+namespace Box2DX.Collision
+{
+ /// <summary>
+ /// This holds the mass data computed for a shape.
+ /// </summary>
+ public struct MassData
+ {
+ /// <summary>
+ /// The mass of the shape, usually in kilograms.
+ /// </summary>
+ public float Mass;
+
+ /// <summary>
+ /// The position of the shape's centroid relative to the shape's origin.
+ /// </summary>
+ public Vec2 Center;
+
+ /// <summary>
+ /// The rotational inertia of the shape.
+ /// </summary>
+ public float I;
+ }
+
+ /// <summary>
+ /// The various collision shape types supported by Box2D.
+ /// </summary>
+ public enum ShapeType
+ {
+ UnknownShape = -1,
+ CircleShape,
+ PolygonShape,
+ EdgeShape,
+ ShapeTypeCount,
+ }
+
+ /// <summary>
+ /// Returns code from TestSegment
+ /// </summary>
+ public enum SegmentCollide
+ {
+ StartInsideCollide = -1,
+ MissCollide = 0,
+ HitCollide = 1
+ }
+
+ /// <summary>
+ /// A shape is used for collision detection. You can create a shape however you like.
+ /// Shapes used for simulation in World are created automatically when a Fixture is created.
+ /// </summary>
+ public abstract class Shape : IDisposable
+ {
+ #region Fields
+
+ protected ShapeType _type = ShapeType.UnknownShape;
+ internal float _radius;
+
+ #endregion Fields
+
+ protected Shape() { }
+
+ /// <summary>
+ /// Test a point for containment in this shape. This only works for convex shapes.
+ /// </summary>
+ /// <param name="xf">The shape world transform.</param>
+ /// <param name="p">A point in world coordinates.</param>
+ /// <returns></returns>
+ public abstract bool TestPoint(XForm xf, Vec2 p);
+
+ /// <summary>
+ /// Perform a ray cast against this shape.
+ /// </summary>
+ /// <param name="xf">The shape world transform.</param>
+ /// <param name="lambda">Returns the hit fraction. You can use this to compute the contact point
+ /// p = (1 - lambda) * segment.P1 + lambda * segment.P2.</param>
+ /// <param name="normal"> Returns the normal at the contact point. If there is no intersection,
+ /// the normal is not set.</param>
+ /// <param name="segment">Defines the begin and end point of the ray cast.</param>
+ /// <param name="maxLambda">A number typically in the range [0,1].</param>
+ public abstract SegmentCollide TestSegment(XForm xf, out float lambda, out Vec2 normal, Segment segment, float maxLambda);
+
+ /// <summary>
+ /// Given a transform, compute the associated axis aligned bounding box for this shape.
+ /// </summary>
+ /// <param name="aabb">Returns the axis aligned box.</param>
+ /// <param name="xf">The world transform of the shape.</param>
+ public abstract void ComputeAABB(out AABB aabb, XForm xf);
+
+ /// <summary>
+ /// Compute the mass properties of this shape using its dimensions and density.
+ /// The inertia tensor is computed about the local origin, not the centroid.
+ /// </summary>
+ /// <param name="massData">Returns the mass data for this shape</param>
+ public abstract void ComputeMass(out MassData massData, float density);
+
+ /// <summary>
+ /// Compute the volume and centroid of this shape intersected with a half plane.
+ /// </summary>
+ /// <param name="normal">Normal the surface normal.</param>
+ /// <param name="offset">Offset the surface offset along normal.</param>
+ /// <param name="xf">The shape transform.</param>
+ /// <param name="c">Returns the centroid.</param>
+ /// <returns>The total volume less than offset along normal.</returns>
+ public abstract float ComputeSubmergedArea(Vec2 normal, float offset, XForm xf, out Vec2 c);
+
+ /// <summary>
+ /// Compute the sweep radius. This is used for conservative advancement (continuous collision detection).
+ /// </summary>
+ /// <param name="pivot">Pivot is the pivot point for rotation.</param>
+ /// <returns>The distance of the furthest point from the pivot.</returns>
+ public abstract float ComputeSweepRadius(Vec2 pivot);
+
+ public abstract Vec2 GetVertex(int index);
+
+ public abstract int GetSupport(Vec2 d);
+
+ public abstract Vec2 GetSupportVertex(Vec2 d);
+
+ public virtual void Dispose(){}
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs.meta b/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs.meta
new file mode 100644
index 0000000..b67f3b4
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/Shapes/Shape.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cfde5d8f3b66ef849b75c54fff38f0b6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Collision/TODO.txt b/Box2d/Assets/Program/Box2d/Collision/TODO.txt
new file mode 100644
index 0000000..312bdc2
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/TODO.txt
@@ -0,0 +1 @@
+check broadphase, port dynamictree \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Collision/TODO.txt.meta b/Box2d/Assets/Program/Box2d/Collision/TODO.txt.meta
new file mode 100644
index 0000000..3719ec6
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Collision/TODO.txt.meta
@@ -0,0 +1,7 @@
+fileFormatVersion: 2
+guid: 18843330e42568c4bbff292ac904fd78
+TextScriptImporter:
+ externalObjects: {}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Common/Mat22.cs b/Box2d/Assets/Program/Box2d/Common/Mat22.cs
index 01ef830..ba70149 100644
--- a/Box2d/Assets/Program/Box2d/Common/Mat22.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Mat22.cs
@@ -1,99 +1,150 @@
-using System;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
-namespace Box2D
+ 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.Text;
+
+namespace Box2DX.Common
{
- class Mat22
- {
- public Mat22()
- {
- }
-
- public Mat22(Vec2 c1, Vec2 c2)
- {
- col1.Set(c1);
- col2.Set(c2);
- }
-
- public Mat22(float a11, float a12, float a21, float a22)
- {
- col1.x = a11; col1.y = a21;
- col2.x = a12; col2.y = a22;
- }
-
- public void Set(Vec2 c1, Vec2 c2)
- {
- col1.Set(c1);
- col2.Set(c2);
- }
-
- void SetIdentity()
- {
- col1.x = 1.0f; col2.x = 0.0f;
- col1.y = 0.0f; col2.y = 1.0f;
- }
-
- void SetZero()
- {
- col1.Set(0, 0);
- col2.Set(0, 0);
- }
-
- public float GetAngle()
- {
- return Convert.ToSingle(System.Math.Atan2(col1.y, col1.x));
- }
-
- /// <summary>
- /// Compute the inverse of this matrix, such that inv(A) * A = identity.
- /// </summary>
- /// <returns></returns>
- public Mat22 GetInverse()
- {
- float a = col1.x;
- float b = col2.x;
- float c = col1.y;
- float d = col2.y;
- float det = a * d - b * c;
- if(det != 0.0)
- {
- det = 1 / det;
- }
- Mat22 m = new Mat22();
- m.col1.x = det * d; m.col2.x = -det * b;
- m.col1.y = -det * c; m.col2.y = det * a;
- return m;
- }
-
- public Vec2 Solve(float bx, float by)
- {
- float a11 = col1.x;
- float a12 = col2.x;
- float a21 = col1.y;
- float a22 = col2.y;
- float det = a11 * a22 - a12 * a21;
- if(det != 0.0)
- {
- det = 1 / det;
- }
- Vec2 v = new Vec2();
- v.x = det * (a22 * bx - a12 * by);
- v.y = det * (a11 * by - a21 * bx);
- return v;
- }
-
- public void Abs()
- {
- col1.Abs();
- col2.Abs();
- }
-
- /*
- * col1.x col2.x
- *
- *
- * col1.y col2.y
- */
- Vec2 col1 = new Vec2();
- Vec2 col2 = new Vec2();
- }
+ /// <summary>
+ /// A 2-by-2 matrix. Stored in column-major order.
+ /// </summary>
+ public struct Mat22
+ {
+ public Vec2 Col1, Col2;
+
+ /// <summary>
+ /// Construct this matrix using columns.
+ /// </summary>
+ public Mat22(Vec2 c1, Vec2 c2)
+ {
+ Col1 = c1;
+ Col2 = c2;
+ }
+
+ /// <summary>
+ /// Construct this matrix using scalars.
+ /// </summary>
+ public Mat22(float a11, float a12, float a21, float a22)
+ {
+ Col1.X = a11; Col1.Y = a21;
+ Col2.X = a12; Col2.Y = a22;
+ }
+
+ /// <summary>
+ /// Construct this matrix using an angle.
+ /// This matrix becomes an orthonormal rotation matrix.
+ /// </summary>
+ public Mat22(float angle)
+ {
+ float c = (float)System.Math.Cos(angle), s = (float)System.Math.Sin(angle);
+ Col1.X = c; Col2.X = -s;
+ Col1.Y = s; Col2.Y = c;
+ }
+
+ /// <summary>
+ /// Initialize this matrix using columns.
+ /// </summary>
+ public void Set(Vec2 c1, Vec2 c2)
+ {
+ Col1 = c1;
+ Col2 = c2;
+ }
+
+ /// <summary>
+ /// Initialize this matrix using an angle.
+ /// This matrix becomes an orthonormal rotation matrix.
+ /// </summary>
+ public void Set(float angle)
+ {
+ float c = (float)System.Math.Cos(angle), s = (float)System.Math.Sin(angle);
+ Col1.X = c; Col2.X = -s;
+ Col1.Y = s; Col2.Y = c;
+ }
+
+ /// <summary>
+ /// Set this to the identity matrix.
+ /// </summary>
+ public void SetIdentity()
+ {
+ Col1.X = 1.0f; Col2.X = 0.0f;
+ Col1.Y = 0.0f; Col2.Y = 1.0f;
+ }
+
+ /// <summary>
+ /// Set this matrix to all zeros.
+ /// </summary>
+ public void SetZero()
+ {
+ Col1.X = 0.0f; Col2.X = 0.0f;
+ Col1.Y = 0.0f; Col2.Y = 0.0f;
+ }
+
+ /// <summary>
+ /// Extract the angle from this matrix (assumed to be a rotation matrix).
+ /// </summary>
+ public float GetAngle()
+ {
+ return (float)System.Math.Atan2(Col1.Y, Col1.X);
+ }
+
+ /// <summary>
+ /// Compute the inverse of this matrix, such that inv(A) * A = identity.
+ /// </summary>
+ public Mat22 GetInverse()
+ {
+ float a = Col1.X, b = Col2.X, c = Col1.Y, d = Col2.Y;
+ Mat22 B = new Mat22();
+ float det = a * d - b * c;
+ Box2DXDebug.Assert(det != 0.0f);
+ det = 1.0f / det;
+ B.Col1.X = det * d; B.Col2.X = -det * b;
+ B.Col1.Y = -det * c; B.Col2.Y = det * a;
+ return B;
+ }
+
+ /// <summary>
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases.
+ /// </summary>
+ public Vec2 Solve(Vec2 b)
+ {
+ float a11 = Col1.X, a12 = Col2.X, a21 = Col1.Y, a22 = Col2.Y;
+ float det = a11 * a22 - a12 * a21;
+ Box2DXDebug.Assert(det != 0.0f);
+ det = 1.0f / det;
+ Vec2 x = new Vec2();
+ x.X = det * (a22 * b.X - a12 * b.Y);
+ x.Y = det * (a11 * b.Y - a21 * b.X);
+ return x;
+ }
+
+ public static Mat22 Identity { get { return new Mat22(1, 0, 0, 1); } }
+
+ public static Mat22 operator +(Mat22 A, Mat22 B)
+ {
+ Mat22 C = new Mat22();
+ C.Set(A.Col1 + B.Col1, A.Col2 + B.Col2);
+ return C;
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Common/Mat33.cs b/Box2d/Assets/Program/Box2d/Common/Mat33.cs
index 13f5205..ffb6036 100644
--- a/Box2d/Assets/Program/Box2d/Common/Mat33.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Mat33.cs
@@ -1,11 +1,90 @@
-using System;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+//r175
+
+using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
-namespace Assets.Program.Box2D.Common
+namespace Box2DX.Common
{
- class Mat33
- {
- }
-}
+ /// <summary>
+ /// A 3-by-3 matrix. Stored in column-major order.
+ /// </summary>
+ public struct Mat33
+ {
+ /// <summary>
+ /// Construct this matrix using columns.
+ /// </summary>
+ public Mat33(Vec3 c1, Vec3 c2, Vec3 c3)
+ {
+ Col1 = c1;
+ Col2 = c2;
+ Col3 = c3;
+ }
+
+ /// <summary>
+ /// Set this matrix to all zeros.
+ /// </summary>
+ public void SetZero()
+ {
+ Col1.SetZero();
+ Col2.SetZero();
+ Col3.SetZero();
+ }
+
+ /// <summary>
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases.
+ /// </summary>
+ public Vec3 Solve33(Vec3 b)
+ {
+ float det = Vec3.Dot(Col1, Vec3.Cross(Col2, Col3));
+ Box2DXDebug.Assert(det != 0.0f);
+ det = 1.0f / det;
+ Vec3 x = new Vec3();
+ x.X = det * Vec3.Dot(b, Vec3.Cross(Col2, Col3));
+ x.Y = det * Vec3.Dot(Col1, Vec3.Cross(b, Col3));
+ x.Z = det * Vec3.Dot(Col1, Vec3.Cross(Col2, b));
+ return x;
+ }
+
+ /// <summary>
+ /// Solve A * x = b, where b is a column vector. This is more efficient
+ /// than computing the inverse in one-shot cases. Solve only the upper
+ /// 2-by-2 matrix equation.
+ /// </summary>
+ public Vec2 Solve22(Vec2 b)
+ {
+ float a11 = Col1.X, a12 = Col2.X, a21 = Col1.Y, a22 = Col2.Y;
+ float det = a11 * a22 - a12 * a21;
+ Box2DXDebug.Assert(det != 0.0f);
+ det = 1.0f / det;
+ Vec2 x = new Vec2();
+ x.X = det * (a22 * b.X - a12 * b.Y);
+ x.Y = det * (a11 * b.Y - a21 * b.X);
+ return x;
+ }
+
+ public Vec3 Col1, Col2, Col3;
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Common/Math.cs b/Box2d/Assets/Program/Box2d/Common/Math.cs
index d3a5afc..8c35e3a 100644
--- a/Box2d/Assets/Program/Box2d/Common/Math.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Math.cs
@@ -1,33 +1,265 @@
-using System;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
-namespace Box2D
+ 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.Text;
+
+namespace Box2DX.Common
{
+ public class Math
+ {
+ public static readonly ushort USHRT_MAX = 0xffff;
+ public static readonly byte UCHAR_MAX = 0xff;
+ public static readonly int RAND_LIMIT = 32767;
+
+ /// <summary>
+ /// This function is used to ensure that a floating point number is
+ /// not a NaN or infinity.
+ /// </summary>
+ public static bool IsValid(float x)
+ {
+ return !(float.IsNaN(x) || float.IsNegativeInfinity(x) || float.IsPositiveInfinity(x));
+ }
+
+ [System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Explicit)]
+ public struct Convert
+ {
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ public float x;
+
+ [System.Runtime.InteropServices.FieldOffset(0)]
+ public int i;
+ }
+
+ /// <summary>
+ /// This is a approximate yet fast inverse square-root.
+ /// </summary>
+ public static float InvSqrt(float x)
+ {
+ Convert convert = new Convert();
+ convert.x = x;
+ float xhalf = 0.5f * x;
+ convert.i = 0x5f3759df - (convert.i >> 1);
+ x = convert.x;
+ x = x * (1.5f - xhalf * x * x);
+ return x;
+ }
+
+ public static float Sqrt(float x)
+ {
+ return (float)System.Math.Sqrt(x);
+ }
+
+ private static Random s_rnd = new Random();
+ /// <summary>
+ /// Random number in range [-1,1]
+ /// </summary>
+ public static float Random()
+ {
+ float r = (float)(s_rnd.Next() & RAND_LIMIT);
+ r /= RAND_LIMIT;
+ r = 2.0f * r - 1.0f;
+ return r;
+ }
+
+ /// <summary>
+ /// Random floating point number in range [lo, hi]
+ /// </summary>
+ public static float Random(float lo, float hi)
+ {
+ float r = (float)(s_rnd.Next() & RAND_LIMIT);
+ r /= RAND_LIMIT;
+ r = (hi - lo) * r + lo;
+ return r;
+ }
+
+ /// <summary>
+ /// "Next Largest Power of 2
+ /// Given a binary integer value x, the next largest power of 2 can be computed by a SWAR algorithm
+ /// that recursively "folds" the upper bits into the lower bits. This process yields a bit vector with
+ /// the same most significant 1 as x, but all 1's below it. Adding 1 to that value yields the next
+ /// largest power of 2. For a 32-bit value:"
+ /// </summary>
+ public static uint NextPowerOfTwo(uint x)
+ {
+ x |= (x >> 1);
+ x |= (x >> 2);
+ x |= (x >> 4);
+ x |= (x >> 8);
+ x |= (x >> 16);
+ return x + 1;
+ }
+
+ public static bool IsPowerOfTwo(uint x)
+ {
+ bool result = x > 0 && (x & (x - 1)) == 0;
+ return result;
+ }
+
+ public static float Abs(float a)
+ {
+ return a > 0.0f ? a : -a;
+ }
+
+ public static Vec2 Abs(Vec2 a)
+ {
+ Vec2 b = new Vec2();
+ b.Set(Math.Abs(a.X), Math.Abs(a.Y));
+ return b;
+ }
+
+ public static Mat22 Abs(Mat22 A)
+ {
+ Mat22 B = new Mat22();
+ B.Set(Math.Abs(A.Col1), Math.Abs(A.Col2));
+ return B;
+ }
+
+ public static float Min(float a, float b)
+ {
+ return a < b ? a : b;
+ }
+
+ public static int Min(int a, int b)
+ {
+ return a < b ? a : b;
+ }
+
+ public static Vec2 Min(Vec2 a, Vec2 b)
+ {
+ Vec2 c = new Vec2();
+ c.X = Math.Min(a.X, b.X);
+ c.Y = Math.Min(a.Y, b.Y);
+ return c;
+ }
+
+ public static float Max(float a, float b)
+ {
+ return a > b ? a : b;
+ }
+
+ public static int Max(int a, int b)
+ {
+ return a > b ? a : b;
+ }
+
+ public static Vec2 Max(Vec2 a, Vec2 b)
+ {
+ Vec2 c = new Vec2();
+ c.X = Math.Max(a.X, b.X);
+ c.Y = Math.Max(a.Y, b.Y);
+ return c;
+ }
+
+ public static float Clamp(float a, float low, float high)
+ {
+ return Math.Max(low, Math.Min(a, high));
+ }
+
+ public static int Clamp(int a, int low, int high)
+ {
+ return Math.Max(low, Math.Min(a, high));
+ }
+
+ public static Vec2 Clamp(Vec2 a, Vec2 low, Vec2 high)
+ {
+ return Math.Max(low, Math.Min(a, high));
+ }
+
+ public static void Swap<T>(ref T a, ref T b)
+ {
+ T tmp = a;
+ a = b;
+ b = tmp;
+ }
+
+ /// <summary>
+ /// Multiply a matrix times a vector. If a rotation matrix is provided,
+ /// then this transforms the vector from one frame to another.
+ /// </summary>
+ public static Vec2 Mul(Mat22 A, Vec2 v)
+ {
+ Vec2 u = new Vec2();
+ u.Set(A.Col1.X * v.X + A.Col2.X * v.Y, A.Col1.Y * v.X + A.Col2.Y * v.Y);
+ return u;
+ }
+
+ /// <summary>
+ /// Multiply a matrix transpose times a vector. If a rotation matrix is provided,
+ /// then this transforms the vector from one frame to another (inverse transform).
+ /// </summary>
+ public static Vec2 MulT(Mat22 A, Vec2 v)
+ {
+ Vec2 u = new Vec2();
+ u.Set(Vec2.Dot(v, A.Col1), Vec2.Dot(v, A.Col2));
+ return u;
+ }
+
+ /// <summary>
+ /// A * B
+ /// </summary>
+ public static Mat22 Mul(Mat22 A, Mat22 B)
+ {
+ Mat22 C = new Mat22();
+ C.Set(Math.Mul(A, B.Col1), Math.Mul(A, B.Col2));
+ return C;
+ }
+
+ /// <summary>
+ /// A^T * B
+ /// </summary>
+ public static Mat22 MulT(Mat22 A, Mat22 B)
+ {
+ Vec2 c1 = new Vec2();
+ c1.Set(Vec2.Dot(A.Col1, B.Col1), Vec2.Dot(A.Col2, B.Col1));
+ Vec2 c2 = new Vec2();
+ c2.Set(Vec2.Dot(A.Col1, B.Col2), Vec2.Dot(A.Col2, B.Col2));
+ Mat22 C = new Mat22();
+ C.Set(c1, c2);
+ return C;
+ }
+
+ public static Vec2 Mul(XForm T, Vec2 v)
+ {
+ return T.Position + Math.Mul(T.R, v);
+ }
+
+ public static Vec2 MulT(XForm T, Vec2 v)
+ {
+ return Math.MulT(T.R, v - T.Position);
+ }
- /// <summary>
- /// common functions
- /// </summary>
- class Math
- {
- /// This function is used to ensure that a floating point number is not a NaN or infinity.
- public static bool IsValid(float x)
- {
- return x != float.PositiveInfinity
- && x != float.NaN
- && x != float.NegativeInfinity;
- }
-
- /// This is a approximate yet fast inverse square-root.
- public static float InvSqrt(float x)
- {
- //float xhalf = 0.5f * x;
- //int i = BitConverter.ToInt32(BitConverter.GetBytes(x), 0);
- //i = 0x5f3759df - (i >> 1);
- //x = BitConverter.ToSingle(BitConverter.GetBytes(i), 0);
- //x = x * (1.5f - xhalf * x * x);
- //return x;
- return Convert.ToSingle(1 / System.Math.Sqrt(x));
- }
-
- }
+ /// <summary>
+ /// Multiply a matrix times a vector.
+ /// </summary>
+ public static Vec3 Mul(Mat33 A, Vec3 v)
+ {
+ Vec3 u = v.X * A.Col1 + v.Y * A.Col2 + v.Z * A.Col3;
+ return u;
+ }
+ public static float Atan2(float y, float x)
+ {
+ return (float)System.Math.Atan2(y, x);
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Common/Settings.cs b/Box2d/Assets/Program/Box2d/Common/Settings.cs
new file mode 100644
index 0000000..d9184ad
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Common/Settings.cs
@@ -0,0 +1,181 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Box2DX.Common
+{
+ public class Settings
+ {
+#if TARGET_FLOAT32_IS_FIXED
+ public static readonly float FLT_EPSILON = FIXED_EPSILON;
+ public static readonly float FLT_MAX = FIXED_MAX;
+ public static float FORCE_SCALE2(x){ return x<<7;}
+ public static float FORCE_INV_SCALE2(x) {return x>>7;}
+#else
+ public static readonly float FLT_EPSILON = 1.192092896e-07F;//smallest such that 1.0f+FLT_EPSILON != 1.0f
+ public static readonly float FLT_EPSILON_SQUARED = FLT_EPSILON * FLT_EPSILON;//smallest such that 1.0f+FLT_EPSILON != 1.0f
+ public static readonly float FLT_MAX = 3.402823466e+38F;
+ public static float FORCE_SCALE(float x) { return x; }
+ public static float FORCE_INV_SCALE(float x) { return x; }
+#endif
+
+ public static readonly float Pi = 3.14159265359f;
+
+ // Global tuning constants based on meters-kilograms-seconds (MKS) units.
+
+ // Collision
+ public static readonly int MaxManifoldPoints = 2;
+ public static readonly int MaxPolygonVertices = 8;
+ public static readonly int MaxProxies = 512; // this must be a power of two
+ public static readonly int MaxPairs = 8 * MaxProxies; // this must be a power of two
+
+ // Dynamics
+
+ /// <summary>
+ /// A small length used as a collision and constraint tolerance. Usually it is
+ /// chosen to be numerically significant, but visually insignificant.
+ /// </summary>
+ public static readonly float LinearSlop = 0.005f; // 0.5 cm
+
+ /// <summary>
+ /// A small angle used as a collision and constraint tolerance. Usually it is
+ /// chosen to be numerically significant, but visually insignificant.
+ /// </summary>
+ public static readonly float AngularSlop = 2.0f / 180.0f * Pi; // 2 degrees
+
+ /// <summary>
+ /// The radius of the polygon/edge shape skin. This should not be modified. Making
+ /// this smaller means polygons will have and insufficient for continuous collision.
+ /// Making it larger may create artifacts for vertex collision.
+ /// </summary>
+ public static readonly float PolygonRadius = 2.0f * LinearSlop;
+
+ /// <summary>
+ /// Continuous collision detection (CCD) works with core, shrunken shapes. This is amount
+ /// by which shapes are automatically shrunk to work with CCD.
+ /// This must be larger than LinearSlop.
+ /// </summary>
+ public static readonly float ToiSlop = 8.0f * LinearSlop;
+
+ /// <summary>
+ /// Maximum number of contacts to be handled to solve a TOI island.
+ /// </summary>
+ public static readonly int MaxTOIContactsPerIsland = 32;
+
+ /// <summary>
+ /// Maximum number of joints to be handled to solve a TOI island.
+ /// </summary>
+ public static readonly int MaxTOIJointsPerIsland = 32;
+
+ /// <summary>
+ /// A velocity threshold for elastic collisions. Any collision with a relative linear
+ /// velocity below this threshold will be treated as inelastic.
+ /// </summary>
+ public static readonly float VelocityThreshold = 1.0f; // 1 m/s
+
+ /// <summary>
+ /// The maximum linear position correction used when solving constraints.
+ /// This helps to prevent overshoot.
+ /// </summary>
+ public static readonly float MaxLinearCorrection = 0.2f; // 20 cm
+
+ /// <summary>
+ /// The maximum angular position correction used when solving constraints.
+ /// This helps to prevent overshoot.
+ /// </summary>
+ public static readonly float MaxAngularCorrection = 8.0f / 180.0f * Pi; // 8 degrees
+
+ /// <summary>
+ /// The maximum linear velocity of a body. This limit is very large and is used
+ /// to prevent numerical problems. You shouldn't need to adjust this.
+ /// </summary>
+#if TARGET_FLOAT32_IS_FIXED
+ public static readonly float MaxLinearVelocity = 100.0f;
+#else
+ public static readonly float MaxLinearVelocity = 200.0f;
+ public static readonly float MaxLinearVelocitySquared = MaxLinearVelocity * MaxLinearVelocity;
+#endif
+ /// <summary>
+ /// The maximum angular velocity of a body. This limit is very large and is used
+ /// to prevent numerical problems. You shouldn't need to adjust this.
+ /// </summary>
+ public static readonly float MaxAngularVelocity = 250.0f;
+#if !TARGET_FLOAT32_IS_FIXED
+ public static readonly float MaxAngularVelocitySquared = MaxAngularVelocity * MaxAngularVelocity;
+#endif
+
+ /// <summary>
+ /// The maximum linear velocity of a body. This limit is very large and is used
+ /// to prevent numerical problems. You shouldn't need to adjust this.
+ /// </summary>
+ public static readonly float MaxTranslation = 2.0f;
+ public static readonly float MaxTranslationSquared = (MaxTranslation * MaxTranslation);
+
+ /// <summary>
+ /// The maximum angular velocity of a body. This limit is very large and is used
+ /// to prevent numerical problems. You shouldn't need to adjust this.
+ /// </summary>
+ public static readonly float MaxRotation = (0.5f * Pi);
+ public static readonly float MaxRotationSquared = (MaxRotation * MaxRotation);
+
+ /// <summary>
+ /// This scale factor controls how fast overlap is resolved. Ideally this would be 1 so
+ /// that overlap is removed in one time step. However using values close to 1 often lead to overshoot.
+ /// </summary>
+ public static readonly float ContactBaumgarte = 0.2f;
+
+ // Sleep
+
+ /// <summary>
+ /// The time that a body must be still before it will go to sleep.
+ /// </summary>
+ public static readonly float TimeToSleep = 0.5f; // half a second
+
+ /// <summary>
+ /// A body cannot sleep if its linear velocity is above this tolerance.
+ /// </summary>
+ public static readonly float LinearSleepTolerance = 0.01f; // 1 cm/s
+
+ /// <summary>
+ /// A body cannot sleep if its angular velocity is above this tolerance.
+ /// </summary>
+ public static readonly float AngularSleepTolerance = 2.0f / 180.0f; // 2 degrees/s
+
+ /// <summary>
+ /// Friction mixing law. Feel free to customize this.
+ /// </summary>
+ public static float MixFriction(float friction1, float friction2)
+ {
+ return (float)System.Math.Sqrt(friction1 * friction2);
+ }
+
+ /// <summary>
+ /// Restitution mixing law. Feel free to customize this.
+ /// </summary>
+ public static float MixRestitution(float restitution1, float restitution2)
+ {
+ return restitution1 > restitution2 ? restitution1 : restitution2;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Common/Settings.cs.meta b/Box2d/Assets/Program/Box2d/Common/Settings.cs.meta
new file mode 100644
index 0000000..68e59da
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Common/Settings.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: ab0be1eda9abcd94ca9b9e1ca92f6f1b
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Common/Sweep.cs b/Box2d/Assets/Program/Box2d/Common/Sweep.cs
index ba1fd07..09e9560 100644
--- a/Box2d/Assets/Program/Box2d/Common/Sweep.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Sweep.cs
@@ -1,11 +1,67 @@
-using System;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+//r175
+
+using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
-namespace Assets.Program.Box2D.Common
+namespace Box2DX.Common
{
- class Sweep
- {
- }
+ public struct Sweep
+ {
+ public Vec2 LocalCenter; //local center of mass position
+ public Vec2 C0, C; //local center of mass position
+ public float A0, A; //world angles
+ public float T0; //time interval = [T0,1], where T0 is in [0,1]
+
+ /// <summary>
+ /// Get the interpolated transform at a specific time.
+ /// </summary>
+ /// <param name="alpha">Alpha is a factor in [0,1], where 0 indicates t0.</param>
+ public void GetTransform(out XForm xf, float alpha)
+ {
+ xf = new XForm();
+ xf.Position = (1.0f - alpha) * C0 + alpha * C;
+ float angle = (1.0f - alpha) * A0 + alpha * A;
+ xf.R.Set(angle);
+
+ // Shift to origin
+ xf.Position -= Common.Math.Mul(xf.R, LocalCenter);
+ }
+
+ /// <summary>
+ /// Advance the sweep forward, yielding a new initial state.
+ /// </summary>
+ /// <param name="t">The new initial time.</param>
+ public void Advance(float t)
+ {
+ if (T0 < t && 1.0f - T0 > Settings.FLT_EPSILON)
+ {
+ float alpha = (t - T0) / (1.0f - T0);
+ C0 = (1.0f - alpha) * C0 + alpha * C;
+ A0 = (1.0f - alpha) * A0 + alpha * A;
+ T0 = t;
+ }
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Common/Transform.cs b/Box2d/Assets/Program/Box2d/Common/Transform.cs
deleted file mode 100644
index b244fb0..0000000
--- a/Box2d/Assets/Program/Box2d/Common/Transform.cs
+++ /dev/null
@@ -1,23 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-
-namespace Box2D
-{
- class Transform
- {
- public Transform()
- {
-
- }
-
- public void Initialize()
- {
-
- }
-
- public Vec2 position;
- public Mat22 R;
- }
-}
diff --git a/Box2d/Assets/Program/Box2d/Common/Vec2.cs b/Box2d/Assets/Program/Box2d/Common/Vec2.cs
index ab803dd..d614845 100644
--- a/Box2d/Assets/Program/Box2d/Common/Vec2.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Vec2.cs
@@ -1,113 +1,230 @@
-using System;
-
-namespace Box2D
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Box2DX.Common
{
- class Vec2
- {
- public Vec2(float x, float y)
- {
- this.x = x;
- this.y = y;
- }
-
- public Vec2()
- {
- this.x = 0;
- this.y = 0;
- }
-
- public void SetZero()
- {
- x = 0;
- y = 0;
- }
-
- public void Set(float _x, float _y)
- {
- x = _x;
- y = _y;
- }
-
- public void Set(Vec2 v)
- {
- x = v.x;
- y = v.y;
- }
-
- public Vec2 GetNegtive()
- {
- return new Vec2(-x, -y);
- }
-
- public Vec2 Copy()
- {
- return new Vec2(x, y);
- }
-
- public Vec2 Clone()
- {
- return new Vec2(x, y);
- }
-
- public static Vec2 operator -(Vec2 l, Vec2 r)
- {
- Vec2 v = new Vec2(l.x - r.x, l.y - r.y);
- return v;
- }
-
- public static Vec2 operator +(Vec2 l, Vec2 r)
- {
- Vec2 v = new Vec2(l.x + r.x, l.y + r.y);
- return v;
- }
-
- public static Vec2 operator *(Vec2 l, float a)
- {
- return new Vec2(l.x * a, l.y * a);
- }
-
- public float Length()
- {
- return Convert.ToSingle(System.Math.Sqrt(x * x + y * y));
- }
-
- public float LengthSquared()
- {
- return x * x + y * y;
- }
-
- /// Convert this vector into a unit vector. Returns the length.
- public float Normalize()
- {
- float length = Length();
- if(length < float.Epsilon)
- {
- return 0;
- }
- float invLength = 1 / length;
- x *= invLength;
- y *= invLength;
- return length;
- }
-
- /// Does this vector contain finite coordinates?
- public bool IsValid()
- {
- return Math.IsValid(x) && Math.IsValid(y);
- }
-
- /// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
- public Vec2 Skew()
- {
- return new Vec2(-y, x);
- }
-
- public void Abs()
- {
- if (x < 0) x = -x;
- if (y < 0) y = -y;
- }
-
- public float x, y;
- }
+ /// <summary>
+ /// A 2D column vector.
+ /// </summary>
+ public struct Vec2
+ {
+ public float X, Y;
+
+ public float this[int i]
+ {
+ get
+ {
+ if (i == 0) return X;
+ else if (i == 1) return Y;
+ else
+ {
+ Box2DXDebug.Assert(false, "Incorrect Vec2 element!");
+ return 0;
+ }
+ }
+ set
+ {
+ if (i == 0) X = value;
+ else if (i == 1) Y = value;
+ else
+ {
+ Box2DXDebug.Assert(false, "Incorrect Vec2 element!");
+ }
+ }
+ }
+
+ /// <summary>
+ /// Construct using coordinates.
+ /// </summary>
+ public Vec2(float x)
+ {
+ X = x;
+ Y = x;
+ }
+
+ /// <summary>
+ /// Construct using coordinates.
+ /// </summary>
+ public Vec2(float x, float y)
+ {
+ X = x;
+ Y = y;
+ }
+
+ /// <summary>
+ /// Set this vector to all zeros.
+ /// </summary>
+ public void SetZero() { X = 0.0f; Y = 0.0f; }
+
+ /// <summary>
+ /// Set this vector to some specified coordinates.
+ /// </summary>
+ public void Set(float x, float y) { X = x; Y = y; }
+
+ public void Set(float xy) { X = xy; Y = xy; }
+
+ /// <summary>
+ /// Get the length of this vector (the norm).
+ /// </summary>
+ public float Length()
+ {
+ return (float)System.Math.Sqrt(X * X + Y * Y);
+ }
+
+ /// <summary>
+ /// Get the length squared. For performance, use this instead of
+ /// Length (if possible).
+ /// </summary>
+ public float LengthSquared()
+ {
+ return X * X + Y * Y;
+ }
+
+ /// <summary>
+ /// Convert this vector into a unit vector. Returns the length.
+ /// </summary>
+ public float Normalize()
+ {
+ float length = Length();
+ if (length < Settings.FLT_EPSILON)
+ {
+ return 0.0f;
+ }
+ float invLength = 1.0f / length;
+ X *= invLength;
+ Y *= invLength;
+
+ return length;
+ }
+
+ /// <summary>
+ /// Does this vector contain finite coordinates?
+ /// </summary>
+ public bool IsValid
+ {
+ get { return Math.IsValid(X) && Math.IsValid(Y); }
+ }
+
+ /// <summary>
+ /// Negate this vector.
+ /// </summary>
+ public static Vec2 operator -(Vec2 v1)
+ {
+ Vec2 v = new Vec2();
+ v.Set(-v1.X, -v1.Y);
+ return v;
+ }
+
+ public static Vec2 operator +(Vec2 v1, Vec2 v2)
+ {
+ Vec2 v = new Vec2();
+ v.Set(v1.X + v2.X, v1.Y + v2.Y);
+ return v;
+ }
+
+ public static Vec2 operator -(Vec2 v1, Vec2 v2)
+ {
+ Vec2 v = new Vec2();
+ v.Set(v1.X - v2.X, v1.Y - v2.Y);
+ return v;
+ }
+
+ public static Vec2 operator *(Vec2 v1, float a)
+ {
+ Vec2 v = new Vec2();
+ v.Set(v1.X * a, v1.Y * a);
+ return v;
+ }
+
+ public static Vec2 operator *(float a, Vec2 v1)
+ {
+ Vec2 v = new Vec2();
+ v.Set(v1.X * a, v1.Y * a);
+ return v;
+ }
+
+ public static bool operator ==(Vec2 a, Vec2 b)
+ {
+ return a.X == b.X && a.Y == b.Y;
+ }
+
+ public static bool operator !=(Vec2 a, Vec2 b)
+ {
+ return a.X != b.X || a.Y != b.Y;
+ }
+
+ public static Vec2 Zero { get { return new Vec2(0, 0); } }
+
+ /// <summary>
+ /// Peform the dot product on two vectors.
+ /// </summary>
+ public static float Dot(Vec2 a, Vec2 b)
+ {
+ return a.X * b.X + a.Y * b.Y;
+ }
+
+ /// <summary>
+ /// Perform the cross product on two vectors. In 2D this produces a scalar.
+ /// </summary>
+ public static float Cross(Vec2 a, Vec2 b)
+ {
+ return a.X * b.Y - a.Y * b.X;
+ }
+
+ /// <summary>
+ /// Perform the cross product on a vector and a scalar.
+ /// In 2D this produces a vector.
+ /// </summary>
+ public static Vec2 Cross(Vec2 a, float s)
+ {
+ Vec2 v = new Vec2();
+ v.Set(s * a.Y, -s * a.X);
+ return v;
+ }
+
+ /// <summary>
+ /// Perform the cross product on a scalar and a vector.
+ /// In 2D this produces a vector.
+ /// </summary>
+ public static Vec2 Cross(float s, Vec2 a)
+ {
+ Vec2 v = new Vec2();
+ v.Set(-s * a.Y, s * a.X);
+ return v;
+ }
+
+ public static float Distance(Vec2 a, Vec2 b)
+ {
+ Vec2 c = a - b;
+ return c.Length();
+ }
+
+ public static float DistanceSquared(Vec2 a, Vec2 b)
+ {
+ Vec2 c = a - b;
+ return Vec2.Dot(c, c);
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Common/Vec3.cs b/Box2d/Assets/Program/Box2d/Common/Vec3.cs
index d4bb361..f702021 100644
--- a/Box2d/Assets/Program/Box2d/Common/Vec3.cs
+++ b/Box2d/Assets/Program/Box2d/Common/Vec3.cs
@@ -1,77 +1,108 @@
-using System;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+//r175
+
+using System;
using System.Collections.Generic;
-using System.Linq;
using System.Text;
-namespace Box2D
+namespace Box2DX.Common
{
- class Vec3
- {
- public Vec3()
- {
- x = 0;
- y = 0;
- z = 0;
- }
-
- public Vec3(float _x, float _y, float _z)
- {
- x = _x;
- y = _y;
- z = _z;
- }
-
- public void SetZero()
- {
- x = y = z = 0.0f;
- }
-
- public void Set(float _x, float _y, float _z)
- {
- x = _x;
- y = _y;
- z = _z;
- }
-
- public static Vec3 operator -(Vec3 l, Vec3 r)
- {
- Vec3 v = new Vec3(l.x - r.x, l.y - r.y, l.z - r.z);
- return v;
- }
-
- public static Vec3 operator +(Vec3 l, Vec3 r)
- {
- Vec3 v = new Vec3(l.x + r.x, l.y + r.y, l.z + r.z);
- return v;
- }
-
- public static Vec3 operator *(Vec3 l, float a)
- {
- Vec3 v = new Vec3(l.x * a, l.y * a, l.z * a);
- return v;
- }
-
- public void Add(Vec3 r)
- {
- x += r.x;
- y += r.y;
- z += r.z;
- }
-
- public void Minus(Vec3 r)
- {
- x -= r.x;
- y -= r.y;
- z -= r.z;
- }
-
- public void Multiply(float a)
- {
- x *= a;
- y *= a;
- z *= a;
- }
-
- public float x, y, z;
- }
-}
+ /// <summary>
+ /// A 2D column vector with 3 elements.
+ /// </summary>
+ public struct Vec3
+ {
+ /// <summary>
+ /// Construct using coordinates.
+ /// </summary>
+ public Vec3(float x, float y, float z) { X = x; Y = y; Z = z; }
+
+ /// <summary>
+ /// Set this vector to all zeros.
+ /// </summary>
+ public void SetZero() { X = 0.0f; Y = 0.0f; Z = 0.0f; }
+
+ /// <summary>
+ /// Set this vector to some specified coordinates.
+ /// </summary>
+ public void Set(float x, float y, float z) { X = x; Y = y; Z = z; }
+
+ /// <summary>
+ /// Perform the dot product on two vectors.
+ /// </summary>
+ public static float Dot(Vec3 a, Vec3 b)
+ {
+ return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
+ }
+
+ /// <summary>
+ /// Perform the cross product on two vectors.
+ /// </summary>
+ public static Vec3 Cross(Vec3 a, Vec3 b)
+ {
+ return new Vec3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
+ }
+
+ /// <summary>
+ /// Negate this vector.
+ /// </summary>
+ public static Vec3 operator -(Vec3 v)
+ {
+ return new Vec3(-v.X, -v.Y, -v.Z);
+ }
+
+ /// <summary>
+ /// Add two vectors component-wise.
+ /// </summary>
+ public static Vec3 operator +(Vec3 v1, Vec3 v2)
+ {
+ return new Vec3(v1.X + v2.X, v1.Y + v2.Y, v1.Z + v2.Z);
+ }
+
+ /// <summary>
+ /// Subtract two vectors component-wise.
+ /// </summary>
+ public static Vec3 operator -(Vec3 v1, Vec3 v2)
+ {
+ return new Vec3(v1.X - v2.X, v1.Y - v2.Y, v1.Z - v2.Z);
+ }
+
+ /// <summary>
+ /// Multiply this vector by a scalar.
+ /// </summary>
+ public static Vec3 operator *(Vec3 v, float s)
+ {
+ return new Vec3(v.X * s, v.Y * s, v.Z * s);
+ }
+
+ /// <summary>
+ /// Multiply this vector by a scalar.
+ /// </summary>
+ public static Vec3 operator *(float s, Vec3 v)
+ {
+ return new Vec3(v.X * s, v.Y * s, v.Z * s);
+ }
+
+ public float X, Y, Z;
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Common/Vec3.cs.meta b/Box2d/Assets/Program/Box2d/Common/Vec3.cs.meta
new file mode 100644
index 0000000..5f28808
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Common/Vec3.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 35d36f97a10c8e4478fc2d9a1fc36613
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Common/XForm.cs b/Box2d/Assets/Program/Box2d/Common/XForm.cs
new file mode 100644
index 0000000..de507b5
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Common/XForm.cs
@@ -0,0 +1,72 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Box2DX.Common
+{
+ /// <summary>
+ /// A transform contains translation and rotation.
+ /// It is used to represent the position and orientation of rigid frames.
+ /// </summary>
+ public struct XForm
+ {
+ public Vec2 Position;
+ public Mat22 R;
+
+ /// <summary>
+ /// Initialize using a position vector and a rotation matrix.
+ /// </summary>
+ /// <param name="position"></param>
+ /// <param name="R"></param>
+ public XForm(Vec2 position, Mat22 rotation)
+ {
+ Position = position;
+ R = rotation;
+ }
+
+ /// <summary>
+ /// Set this to the identity transform.
+ /// </summary>
+ public void SetIdentity()
+ {
+ Position.SetZero();
+ R.SetIdentity();
+ }
+
+ /// Set this based on the position and angle.
+ public void Set(Vec2 p, float angle)
+ {
+ Position = p;
+ R.Set(angle);
+ }
+
+ /// Calculate the angle that the rotation matrix represents.
+ public float GetAngle()
+ {
+ return Math.Atan2(R.Col1.Y, R.Col1.X);
+ }
+
+ public static XForm Identity { get { return new XForm(Vec2.Zero, Mat22.Identity); } }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Common/XForm.cs.meta b/Box2d/Assets/Program/Box2d/Common/XForm.cs.meta
new file mode 100644
index 0000000..082e1aa
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Common/XForm.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 1808091e7f7554e4a8925c67159c00e7
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Body.cs b/Box2d/Assets/Program/Box2d/Dynamics/Body.cs
index 85ae672..1daa9a5 100644
--- a/Box2d/Assets/Program/Box2d/Dynamics/Body.cs
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Body.cs
@@ -1,7 +1,1070 @@
-using System.Collections;
-using System.Collections.Generic;
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
-namespace Box2D
+ 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 Box2DX.Common;
+using Box2DX.Collision;
+
+namespace Box2DX.Dynamics
{
+ /// <summary>
+ /// A body definition holds all the data needed to construct a rigid body.
+ /// You can safely re-use body definitions.
+ /// </summary>
+ public struct BodyDef
+ {
+ /// <summary>
+ /// This constructor sets the body definition default values.
+ /// </summary>
+ public BodyDef(byte init)
+ {
+ MassData = new MassData();
+ MassData.Center.SetZero();
+ MassData.Mass = 0.0f;
+ MassData.I = 0.0f;
+ UserData = null;
+ Position = new Vec2();
+ Position.Set(0.0f, 0.0f);
+ Angle = 0.0f;
+ LinearVelocity = new Vec2(0f, 0f);
+ AngularVelocity = 0.0f;
+ LinearDamping = 0.0f;
+ AngularDamping = 0.0f;
+ AllowSleep = true;
+ IsSleeping = false;
+ FixedRotation = false;
+ IsBullet = false;
+ }
+
+ /// <summary>
+ /// You can use this to initialized the mass properties of the body.
+ /// If you prefer, you can set the mass properties after the shapes
+ /// have been added using Body.SetMassFromShapes.
+ /// </summary>
+ public MassData MassData;
+
+ /// <summary>
+ /// Use this to store application specific body data.
+ /// </summary>
+ public object UserData;
+
+ /// <summary>
+ /// The world position of the body. Avoid creating bodies at the origin
+ /// since this can lead to many overlapping shapes.
+ /// </summary>
+ public Vec2 Position;
+
+ /// <summary>
+ /// The world angle of the body in radians.
+ /// </summary>
+ public float Angle;
+
+ /// The linear velocity of the body in world co-ordinates.
+ public Vec2 LinearVelocity;
+
+ // The angular velocity of the body.
+ public float AngularVelocity;
+
+ /// <summary>
+ /// Linear damping is use to reduce the linear velocity. The damping parameter
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the
+ /// time step when the damping parameter is large.
+ /// </summary>
+ public float LinearDamping;
+
+ /// <summary>
+ /// Angular damping is use to reduce the angular velocity. The damping parameter
+ /// can be larger than 1.0f but the damping effect becomes sensitive to the
+ /// time step when the damping parameter is large.
+ /// </summary>
+ public float AngularDamping;
+
+ /// <summary>
+ /// Set this flag to false if this body should never fall asleep. Note that
+ /// this increases CPU usage.
+ /// </summary>
+ public bool AllowSleep;
+
+ /// <summary>
+ /// Is this body initially sleeping?
+ /// </summary>
+ public bool IsSleeping;
+
+ /// <summary>
+ /// Should this body be prevented from rotating? Useful for characters.
+ /// </summary>
+ public bool FixedRotation;
+
+ /// <summary>
+ /// Is this a fast moving body that should be prevented from tunneling through
+ /// other moving bodies? Note that all bodies are prevented from tunneling through
+ /// static bodies.
+ /// @warning You should use this flag sparingly since it increases processing time.
+ /// </summary>
+ public bool IsBullet;
+ }
+
+ /// <summary>
+ /// A rigid body. These are created via World.CreateBody.
+ /// </summary>
+ public class Body : IDisposable
+ {
+ [Flags]
+ public enum BodyFlags
+ {
+ Frozen = 0x0002,
+ Island = 0x0004,
+ Sleep = 0x0008,
+ AllowSleep = 0x0010,
+ Bullet = 0x0020,
+ FixedRotation = 0x0040
+ }
+
+ public enum BodyType
+ {
+ Static,
+ Dynamic,
+ MaxTypes
+ }
+
+ internal BodyFlags _flags;
+ private BodyType _type;
+
+ internal int _islandIndex;
+
+ internal XForm _xf; // the body origin transform
+
+ internal Sweep _sweep; // the swept motion for CCD
+
+ internal Vec2 _linearVelocity;
+ internal float _angularVelocity;
+
+ internal Vec2 _force;
+ internal float _torque;
+
+ private World _world;
+ internal Body _prev;
+ internal Body _next;
+
+ internal Fixture _fixtureList;
+ internal int _fixtureCount;
+
+ internal JointEdge _jointList;
+ internal ContactEdge _contactList;
+
+ internal Controllers.ControllerEdge _controllerList;
+
+ internal float _mass;
+ internal float _invMass;
+ internal float _I;
+ internal float _invI;
+
+ internal float _linearDamping;
+ internal float _angularDamping;
+
+ internal float _sleepTime;
+
+ private object _userData;
+
+ internal Body(BodyDef bd, World world)
+ {
+ Box2DXDebug.Assert(world._lock == false);
+
+ _flags = 0;
+
+ if (bd.IsBullet)
+ {
+ _flags |= BodyFlags.Bullet;
+ }
+ if (bd.FixedRotation)
+ {
+ _flags |= BodyFlags.FixedRotation;
+ }
+ if (bd.AllowSleep)
+ {
+ _flags |= BodyFlags.AllowSleep;
+ }
+ if (bd.IsSleeping)
+ {
+ _flags |= BodyFlags.Sleep;
+ }
+
+ _world = world;
+
+ _xf.Position = bd.Position;
+ _xf.R.Set(bd.Angle);
+
+ _sweep.LocalCenter = bd.MassData.Center;
+ _sweep.T0 = 1.0f;
+ _sweep.A0 = _sweep.A = bd.Angle;
+ _sweep.C0 = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);
+
+ //_jointList = null;
+ //_contactList = null;
+ //_controllerList = null;
+ //_prev = null;
+ //_next = null;
+
+ _linearVelocity = bd.LinearVelocity;
+ _angularVelocity = bd.AngularVelocity;
+
+ _linearDamping = bd.LinearDamping;
+ _angularDamping = bd.AngularDamping;
+
+ //_force.Set(0.0f, 0.0f);
+ //_torque = 0.0f;
+
+ //_linearVelocity.SetZero();
+ //_angularVelocity = 0.0f;
+
+ //_sleepTime = 0.0f;
+
+ //_invMass = 0.0f;
+ //_I = 0.0f;
+ //_invI = 0.0f;
+
+ _mass = bd.MassData.Mass;
+
+ if (_mass > 0.0f)
+ {
+ _invMass = 1.0f / _mass;
+ }
+
+ _I = bd.MassData.I;
+
+ if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
+ {
+ _invI = 1.0f / _I;
+ }
+
+ if (_invMass == 0.0f && _invI == 0.0f)
+ {
+ _type = BodyType.Static;
+ }
+ else
+ {
+ _type = BodyType.Dynamic;
+ }
+
+ _userData = bd.UserData;
+
+ //_fixtureList = null;
+ //_fixtureCount = 0;
+ }
+
+ public void Dispose()
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ // shapes and joints are destroyed in World.Destroy
+ }
+
+ internal bool SynchronizeFixtures()
+ {
+ XForm xf1 = new XForm();
+ xf1.R.Set(_sweep.A0);
+ xf1.Position = _sweep.C0 - Common.Math.Mul(xf1.R, _sweep.LocalCenter);
+
+ bool inRange = true;
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ inRange = f.Synchronize(_world._broadPhase, xf1, _xf);
+ if (inRange == false)
+ {
+ break;
+ }
+ }
+
+ if (inRange == false)
+ {
+ _flags |= BodyFlags.Frozen;
+ _linearVelocity.SetZero();
+ _angularVelocity = 0.0f;
+
+ // Failure
+ return false;
+ }
+
+ // Success
+ return true;
+ }
+
+ // This is used to prevent connected bodies from colliding.
+ // It may lie, depending on the collideConnected flag.
+ internal bool IsConnected(Body other)
+ {
+ for (JointEdge jn = _jointList; jn != null; jn = jn.Next)
+ {
+ if (jn.Other == other)
+ return jn.Joint._collideConnected == false;
+ }
+
+ return false;
+ }
+
+ /// <summary>
+ /// Creates a fixture and attach it to this body.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="def">The fixture definition.</param>
+ public Fixture CreateFixture(FixtureDef def)
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ if (_world._lock == true)
+ {
+ return null;
+ }
+
+ BroadPhase broadPhase = _world._broadPhase;
+
+ Fixture fixture = new Fixture();
+ fixture.Create(broadPhase, this, _xf, def);
+
+ fixture._next = _fixtureList;
+ _fixtureList = fixture;
+ ++_fixtureCount;
+
+ fixture._body = this;
+
+ return fixture;
+ }
+
+ /// <summary>
+ /// Destroy a fixture. This removes the fixture from the broad-phase and
+ /// therefore destroys any contacts associated with this fixture. All fixtures
+ /// attached to a body are implicitly destroyed when the body is destroyed.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="fixture">The fixture to be removed.</param>
+ public void DestroyFixture(Fixture fixture)
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ if (_world._lock == true)
+ {
+ return;
+ }
+
+ Box2DXDebug.Assert(fixture.Body == this);
+
+ // Remove the fixture from this body's singly linked list.
+ Box2DXDebug.Assert(_fixtureCount > 0);
+ Fixture node = _fixtureList;
+ bool found = false;
+ while (node != null)
+ {
+ if (node == fixture)
+ {
+ //*node = fixture->m_next;
+ _fixtureList = fixture.Next;
+ found = true;
+ break;
+ }
+
+ node = node.Next;
+ }
+
+ // You tried to remove a shape that is not attached to this body.
+ Box2DXDebug.Assert(found);
+
+ BroadPhase broadPhase = _world._broadPhase;
+
+ fixture.Destroy(broadPhase);
+ fixture._body = null;
+ fixture._next = null;
+
+ --_fixtureCount;
+ }
+
+ // TODO_ERIN adjust linear velocity and torque to account for movement of center.
+ /// <summary>
+ /// Set the mass properties. Note that this changes the center of mass position.
+ /// If you are not sure how to compute mass properties, use SetMassFromShapes.
+ /// The inertia tensor is assumed to be relative to the center of mass.
+ /// </summary>
+ /// <param name="massData">The mass properties.</param>
+ public void SetMass(MassData massData)
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ if (_world._lock == true)
+ {
+ return;
+ }
+
+ _invMass = 0.0f;
+ _I = 0.0f;
+ _invI = 0.0f;
+
+ _mass = massData.Mass;
+
+ if (_mass > 0.0f)
+ {
+ _invMass = 1.0f / _mass;
+ }
+
+ _I = massData.I;
+
+ if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
+ {
+ _invI = 1.0f / _I;
+ }
+
+ // Move center of mass.
+ _sweep.LocalCenter = massData.Center;
+ _sweep.C0 = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);
+
+ BodyType oldType = _type;
+ if (_invMass == 0.0f && _invI == 0.0f)
+ {
+ _type = BodyType.Static;
+ }
+ else
+ {
+ _type = BodyType.Dynamic;
+ }
+
+ // If the body type changed, we need to refilter the broad-phase proxies.
+ if (oldType != _type)
+ {
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ f.RefilterProxy(_world._broadPhase, _xf);
+ }
+ }
+ }
+
+ // TODO_ERIN adjust linear velocity and torque to account for movement of center.
+ /// <summary>
+ /// Compute the mass properties from the attached shapes. You typically call this
+ /// after adding all the shapes. If you add or remove shapes later, you may want
+ /// to call this again. Note that this changes the center of mass position.
+ /// </summary>
+ public void SetMassFromShapes()
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ if (_world._lock == true)
+ {
+ return;
+ }
+
+ // Compute mass data from shapes. Each shape has its own density.
+ _mass = 0.0f;
+ _invMass = 0.0f;
+ _I = 0.0f;
+ _invI = 0.0f;
+
+ Vec2 center = Vec2.Zero;
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ MassData massData;
+ f.ComputeMass(out massData);
+ _mass += massData.Mass;
+ center += massData.Mass * massData.Center;
+ _I += massData.I;
+ }
+
+ // Compute center of mass, and shift the origin to the COM.
+ if (_mass > 0.0f)
+ {
+ _invMass = 1.0f / _mass;
+ center *= _invMass;
+ }
+
+ if (_I > 0.0f && (_flags & BodyFlags.FixedRotation) == 0)
+ {
+ // Center the inertia about the center of mass.
+ _I -= _mass * Vec2.Dot(center, center);
+ Box2DXDebug.Assert(_I > 0.0f);
+ _invI = 1.0f / _I;
+ }
+ else
+ {
+ _I = 0.0f;
+ _invI = 0.0f;
+ }
+
+ // Move center of mass.
+ _sweep.LocalCenter = center;
+ _sweep.C0 = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);
+
+ BodyType oldType = _type;
+ if (_invMass == 0.0f && _invI == 0.0f)
+ {
+ _type = BodyType.Static;
+ }
+ else
+ {
+ _type = BodyType.Dynamic;
+ }
+
+ // If the body type changed, we need to refilter the broad-phase proxies.
+ if (oldType != _type)
+ {
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ f.RefilterProxy(_world._broadPhase, _xf);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Set the position of the body's origin and rotation (radians).
+ /// This breaks any contacts and wakes the other bodies.
+ /// </summary>
+ /// <param name="position">The new world position of the body's origin (not necessarily
+ /// the center of mass).</param>
+ /// <param name="angle">The new world rotation angle of the body in radians.</param>
+ /// <returns>Return false if the movement put a shape outside the world. In this case the
+ /// body is automatically frozen.</returns>
+ public bool SetXForm(Vec2 position, float angle)
+ {
+ Box2DXDebug.Assert(_world._lock == false);
+ if (_world._lock == true)
+ {
+ return true;
+ }
+
+ if (IsFrozen())
+ {
+ return false;
+ }
+
+ _xf.R.Set(angle);
+ _xf.Position = position;
+
+ _sweep.C0 = _sweep.C = Common.Math.Mul(_xf, _sweep.LocalCenter);
+ _sweep.A0 = _sweep.A = angle;
+
+ bool freeze = false;
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ bool inRange = f.Synchronize(_world._broadPhase, _xf, _xf);
+
+ if (inRange == false)
+ {
+ freeze = true;
+ break;
+ }
+ }
+
+ if (freeze == true)
+ {
+ _flags |= BodyFlags.Frozen;
+ _linearVelocity.SetZero();
+ _angularVelocity = 0.0f;
+
+ // Failure
+ return false;
+ }
+
+ // Success
+ _world._broadPhase.Commit();
+ return true;
+ }
+
+ /// <summary>
+ /// Set the position of the body's origin and rotation (radians).
+ /// This breaks any contacts and wakes the other bodies.
+ /// Note this is less efficient than the other overload - you should use that
+ /// if the angle is available.
+ /// </summary>
+ /// <param name="xf">The transform of position and angle to set the body to.</param>
+ /// <returns>False if the movement put a shape outside the world. In this case the
+ /// body is automatically frozen.</returns>
+ public bool SetXForm(XForm xf)
+ {
+ return SetXForm(xf.Position, xf.GetAngle());
+ }
+
+ /// <summary>
+ /// Get the body transform for the body's origin.
+ /// </summary>
+ /// <returns>Return the world transform of the body's origin.</returns>
+ public XForm GetXForm()
+ {
+ return _xf;
+ }
+
+ /// <summary>
+ /// Set the world body origin position.
+ /// </summary>
+ /// <param name="position">The new position of the body.</param>
+ public void SetPosition(Vec2 position)
+ {
+ SetXForm(position, GetAngle());
+ }
+
+ /// <summary>
+ /// Set the world body angle.
+ /// </summary>
+ /// <param name="angle">The new angle of the body.</param>
+ public void SetAngle(float angle)
+ {
+ SetXForm(GetPosition(), angle);
+ }
+
+ /// <summary>
+ /// Get the world body origin position.
+ /// </summary>
+ /// <returns>Return the world position of the body's origin.</returns>
+ public Vec2 GetPosition()
+ {
+ return _xf.Position;
+ }
+
+ /// <summary>
+ /// Get the angle in radians.
+ /// </summary>
+ /// <returns>Return the current world rotation angle in radians.</returns>
+ public float GetAngle()
+ {
+ return _sweep.A;
+ }
+
+ /// <summary>
+ /// Get the world position of the center of mass.
+ /// </summary>
+ /// <returns></returns>
+ public Vec2 GetWorldCenter()
+ {
+ return _sweep.C;
+ }
+
+ /// <summary>
+ /// Get the local position of the center of mass.
+ /// </summary>
+ /// <returns></returns>
+ public Vec2 GetLocalCenter()
+ {
+ return _sweep.LocalCenter;
+ }
+
+ /// <summary>
+ /// Set the linear velocity of the center of mass.
+ /// </summary>
+ /// <param name="v">The new linear velocity of the center of mass.</param>
+ public void SetLinearVelocity(Vec2 v)
+ {
+ _linearVelocity = v;
+ }
+
+ /// <summary>
+ /// Get the linear velocity of the center of mass.
+ /// </summary>
+ /// <returns>Return the linear velocity of the center of mass.</returns>
+ public Vec2 GetLinearVelocity()
+ {
+ return _linearVelocity;
+ }
+
+ /// <summary>
+ /// Set the angular velocity.
+ /// </summary>
+ /// <param name="omega">The new angular velocity in radians/second.</param>
+ public void SetAngularVelocity(float w)
+ {
+ _angularVelocity = w;
+ }
+
+ /// <summary>
+ /// Get the angular velocity.
+ /// </summary>
+ /// <returns>Return the angular velocity in radians/second.</returns>
+ public float GetAngularVelocity()
+ {
+ return _angularVelocity;
+ }
+
+ /// <summary>
+ /// Apply a force at a world point. If the force is not
+ /// applied at the center of mass, it will generate a torque and
+ /// affect the angular velocity. This wakes up the body.
+ /// </summary>
+ /// <param name="force">The world force vector, usually in Newtons (N).</param>
+ /// <param name="point">The world position of the point of application.</param>
+ public void ApplyForce(Vec2 force, Vec2 point)
+ {
+ if (IsSleeping())
+ {
+ WakeUp();
+ }
+ _force += force;
+ _torque += Vec2.Cross(point - _sweep.C, force);
+ }
+
+ /// <summary>
+ /// Apply a torque. This affects the angular velocity
+ /// without affecting the linear velocity of the center of mass.
+ /// This wakes up the body.
+ /// </summary>
+ /// <param name="torque">Torque about the z-axis (out of the screen), usually in N-m.</param>
+ public void ApplyTorque(float torque)
+ {
+ if (IsSleeping())
+ {
+ WakeUp();
+ }
+ _torque += torque;
+ }
+
+ /// <summary>
+ /// Apply an impulse at a point. This immediately modifies the velocity.
+ /// It also modifies the angular velocity if the point of application
+ /// is not at the center of mass. This wakes up the body.
+ /// </summary>
+ /// <param name="impulse">The world impulse vector, usually in N-seconds or kg-m/s.</param>
+ /// <param name="point">The world position of the point of application.</param>
+ public void ApplyImpulse(Vec2 impulse, Vec2 point)
+ {
+ if (IsSleeping())
+ {
+ WakeUp();
+ }
+ _linearVelocity += _invMass * impulse;
+ _angularVelocity += _invI * Vec2.Cross(point - _sweep.C, impulse);
+ }
+
+ /// <summary>
+ /// Get the total mass of the body.
+ /// </summary>
+ /// <returns>Return the mass, usually in kilograms (kg).</returns>
+ public float GetMass()
+ {
+ return _mass;
+ }
+
+ /// <summary>
+ /// Get the central rotational inertia of the body.
+ /// </summary>
+ /// <returns>Return the rotational inertia, usually in kg-m^2.</returns>
+ public float GetInertia()
+ {
+ return _I;
+ }
+
+ /// <summary>
+ /// Get the mass data of the body.
+ /// </summary>
+ /// <returns>A struct containing the mass, inertia and center of the body.</returns>
+ public MassData GetMassData()
+ {
+ MassData massData = new MassData();
+ massData.Mass = _mass;
+ massData.I = _I;
+ massData.Center = GetWorldCenter();
+ return massData;
+ }
+
+ /// <summary>
+ /// Get the world coordinates of a point given the local coordinates.
+ /// </summary>
+ /// <param name="localPoint">A point on the body measured relative the the body's origin.</param>
+ /// <returns>Return the same point expressed in world coordinates.</returns>
+ public Vec2 GetWorldPoint(Vec2 localPoint)
+ {
+ return Common.Math.Mul(_xf, localPoint);
+ }
+
+ /// <summary>
+ /// Get the world coordinates of a vector given the local coordinates.
+ /// </summary>
+ /// <param name="localVector">A vector fixed in the body.</param>
+ /// <returns>Return the same vector expressed in world coordinates.</returns>
+ public Vec2 GetWorldVector(Vec2 localVector)
+ {
+ return Common.Math.Mul(_xf.R, localVector);
+ }
+
+ /// <summary>
+ /// Gets a local point relative to the body's origin given a world point.
+ /// </summary>
+ /// <param name="worldPoint">A point in world coordinates.</param>
+ /// <returns>Return the corresponding local point relative to the body's origin.</returns>
+ public Vec2 GetLocalPoint(Vec2 worldPoint)
+ {
+ return Common.Math.MulT(_xf, worldPoint);
+ }
+
+ /// <summary>
+ /// Gets a local vector given a world vector.
+ /// </summary>
+ /// <param name="worldVector">A vector in world coordinates.</param>
+ /// <returns>Return the corresponding local vector.</returns>
+ public Vec2 GetLocalVector(Vec2 worldVector)
+ {
+ return Common.Math.MulT(_xf.R, worldVector);
+ }
+
+ /// <summary>
+ /// Get the world linear velocity of a world point attached to this body.
+ /// </summary>
+ /// <param name="worldPoint">A point in world coordinates.</param>
+ /// <returns>The world velocity of a point.</returns>
+ public Vec2 GetLinearVelocityFromWorldPoint(Vec2 worldPoint)
+ {
+ return _linearVelocity + Vec2.Cross(_angularVelocity, worldPoint - _sweep.C);
+ }
+
+ /// <summary>
+ /// Get the world velocity of a local point.
+ /// </summary>
+ /// <param name="localPoint">A point in local coordinates.</param>
+ /// <returns>The world velocity of a point.</returns>
+ public Vec2 GetLinearVelocityFromLocalPoint(Vec2 localPoint)
+ {
+ return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint));
+ }
+
+ public float GetLinearDamping()
+ {
+ return _linearDamping;
+ }
+
+ public void SetLinearDamping(float linearDamping)
+ {
+ _linearDamping = linearDamping;
+ }
+
+ public float GetAngularDamping()
+ {
+ return _angularDamping;
+ }
+
+ public void SetAngularDamping(float angularDamping)
+ {
+ _angularDamping = angularDamping;
+ }
+
+ /// <summary>
+ /// Is this body treated like a bullet for continuous collision detection?
+ /// </summary>
+ /// <returns></returns>
+ public bool IsBullet()
+ {
+ return (_flags & BodyFlags.Bullet) == BodyFlags.Bullet;
+ }
+
+ /// <summary>
+ /// Should this body be treated like a bullet for continuous collision detection?
+ /// </summary>
+ /// <param name="flag"></param>
+ public void SetBullet(bool flag)
+ {
+ if (flag)
+ {
+ _flags |= BodyFlags.Bullet;
+ }
+ else
+ {
+ _flags &= ~BodyFlags.Bullet;
+ }
+ }
+
+ public bool IsFixedRotation()
+ {
+ return (_flags & BodyFlags.FixedRotation) == BodyFlags.FixedRotation;
+ }
+
+ public void SetFixedRotation(bool fixedr)
+ {
+ if (fixedr)
+ {
+ _angularVelocity = 0.0f;
+ _invI = 0.0f;
+ _flags |= BodyFlags.FixedRotation;
+ }
+ else
+ {
+ if (_I > 0.0f)
+ {
+ // Recover _invI from _I.
+ _invI = 1.0f / _I;
+ _flags &= BodyFlags.FixedRotation;
+ }
+ // TODO: Else what?
+ }
+ }
+
+ /// <summary>
+ /// Is this body static (immovable)?
+ /// </summary>
+ /// <returns></returns>
+ public bool IsStatic()
+ {
+ return _type == BodyType.Static;
+ }
+
+ public void SetStatic()
+ {
+ if (_type == BodyType.Static)
+ return;
+ _mass = 0.0f;
+ _invMass = 0.0f;
+ _I = 0.0f;
+ _invI = 0.0f;
+ _type = BodyType.Static;
+
+ for (Fixture f = _fixtureList; f != null; f = f.Next)
+ {
+ f.RefilterProxy(_world._broadPhase, _xf);
+ }
+ }
+
+ /// <summary>
+ /// Is this body dynamic (movable)?
+ /// </summary>
+ /// <returns></returns>
+ public bool IsDynamic()
+ {
+ return _type == BodyType.Dynamic;
+ }
+
+ /// <summary>
+ /// Is this body frozen?
+ /// </summary>
+ /// <returns></returns>
+ public bool IsFrozen()
+ {
+ return (_flags & BodyFlags.Frozen) == BodyFlags.Frozen;
+ }
+
+ /// <summary>
+ /// Is this body sleeping (not simulating).
+ /// </summary>
+ /// <returns></returns>
+ public bool IsSleeping()
+ {
+ return (_flags & BodyFlags.Sleep) == BodyFlags.Sleep;
+ }
+
+ public bool IsAllowSleeping()
+ {
+ return (_flags & BodyFlags.AllowSleep) == BodyFlags.AllowSleep;
+ }
+
+ /// <summary>
+ /// You can disable sleeping on this body.
+ /// </summary>
+ /// <param name="flag"></param>
+ public void AllowSleeping(bool flag)
+ {
+ if (flag)
+ {
+ _flags |= BodyFlags.AllowSleep;
+ }
+ else
+ {
+ _flags &= ~BodyFlags.AllowSleep;
+ WakeUp();
+ }
+ }
+
+ /// <summary>
+ /// Wake up this body so it will begin simulating.
+ /// </summary>
+ public void WakeUp()
+ {
+ _flags &= ~BodyFlags.Sleep;
+ _sleepTime = 0.0f;
+ }
+
+ /// <summary>
+ /// Put this body to sleep so it will stop simulating.
+ /// This also sets the velocity to zero.
+ /// </summary>
+ public void PutToSleep()
+ {
+ _flags |= BodyFlags.Sleep;
+ _sleepTime = 0.0f;
+ _linearVelocity.SetZero();
+ _angularVelocity = 0.0f;
+ _force.SetZero();
+ _torque = 0.0f;
+ }
+
+ /// <summary>
+ /// Get the list of all fixtures attached to this body.
+ /// </summary>
+ /// <returns></returns>
+ public Fixture GetFixtureList()
+ {
+ return _fixtureList;
+ }
+
+ /// <summary>
+ /// Get the list of all joints attached to this body.
+ /// </summary>
+ /// <returns></returns>
+ public JointEdge GetJointList()
+ {
+ return _jointList;
+ }
+
+ public Controllers.ControllerEdge GetControllerList()
+ {
+ return _controllerList;
+ }
+
+ /// <summary>
+ /// Get the next body in the world's body list.
+ /// </summary>
+ /// <returns></returns>
+ public Body GetNext()
+ {
+ return _next;
+ }
+
+ /// <summary>
+ /// Get the user data pointer that was provided in the body definition.
+ /// </summary>
+ /// <returns></returns>
+ public object GetUserData()
+ {
+ return _userData;
+ }
+
+ /// <summary>
+ /// Set the user data. Use this to store your application specific data.
+ /// </summary>
+ /// <param name="data"></param>
+ public void SetUserData(object data) { _userData = data; }
+
+ /// <summary>
+ /// Get the parent world of this body.
+ /// </summary>
+ /// <returns></returns>
+ public World GetWorld() { return _world; }
+
+ internal void SynchronizeTransform()
+ {
+ _xf.R.Set(_sweep.A);
+ _xf.Position = _sweep.C - Common.Math.Mul(_xf.R, _sweep.LocalCenter);
+ }
+ internal void Advance(float t)
+ {
+ // Advance to the new safe time.
+ _sweep.Advance(t);
+ _sweep.C = _sweep.C0;
+ _sweep.A = _sweep.A0;
+ SynchronizeTransform();
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs b/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs
new file mode 100644
index 0000000..667c848
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs
@@ -0,0 +1,232 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ // Delegate of World.
+ /// </summary>
+ public class ContactManager : PairCallback
+ {
+ public World _world;
+
+ // This lets us provide broadphase proxy pair user data for
+ // contacts that shouldn't exist.
+ public NullContact _nullContact;
+
+ public bool _destroyImmediate;
+
+ public ContactManager() { }
+
+ // This is a callback from the broadphase when two AABB proxies begin
+ // to overlap. We create a Contact to manage the narrow phase.
+ public override object PairAdded(object proxyUserDataA, object proxyUserDataB)
+ {
+ Fixture fixtureA = proxyUserDataA as Fixture;
+ Fixture fixtureB = proxyUserDataB as Fixture;
+
+ Body bodyA = fixtureA.Body;
+ Body bodyB = fixtureB.Body;
+
+ if (bodyA.IsStatic() && bodyB.IsStatic())
+ {
+ return _nullContact;
+ }
+
+ if (fixtureA.Body == fixtureB.Body)
+ {
+ return _nullContact;
+ }
+
+ if (bodyB.IsConnected(bodyA))
+ {
+ return _nullContact;
+ }
+
+ if (_world._contactFilter != null && _world._contactFilter.ShouldCollide(fixtureA, fixtureB) == false)
+ {
+ return _nullContact;
+ }
+
+ // Call the factory.
+ Contact c = Contact.Create(fixtureA, fixtureB);
+
+ if (c == null)
+ {
+ return _nullContact;
+ }
+
+ // Contact creation may swap shapes.
+ fixtureA = c.FixtureA;
+ fixtureB = c.FixtureB;
+ bodyA = fixtureA.Body;
+ bodyB = fixtureB.Body;
+
+ // Insert into the world.
+ c._prev = null;
+ c._next = _world._contactList;
+ if (_world._contactList != null)
+ {
+ _world._contactList._prev = c;
+ }
+ _world._contactList = c;
+
+ // Connect to island graph.
+
+ // Connect to body 1
+ c._nodeA.Contact = c;
+ c._nodeA.Other = bodyB;
+
+ c._nodeA.Prev = null;
+ c._nodeA.Next = bodyA._contactList;
+ if (bodyA._contactList != null)
+ {
+ bodyA._contactList.Prev = c._nodeA;
+ }
+ bodyA._contactList = c._nodeA;
+
+ // Connect to body 2
+ c._nodeB.Contact = c;
+ c._nodeB.Other = bodyA;
+
+ c._nodeB.Prev = null;
+ c._nodeB.Next = bodyB._contactList;
+ if (bodyB._contactList != null)
+ {
+ bodyB._contactList.Prev = c._nodeB;
+ }
+ bodyB._contactList = c._nodeB;
+
+ ++_world._contactCount;
+ return c;
+ }
+
+ // This is a callback from the broadphase when two AABB proxies cease
+ // to overlap. We retire the Contact.
+ public override void PairRemoved(object proxyUserData1, object proxyUserData2, object pairUserData)
+ {
+ //B2_NOT_USED(proxyUserData1);
+ //B2_NOT_USED(proxyUserData2);
+
+ if (pairUserData == null)
+ {
+ return;
+ }
+
+ Contact c = pairUserData as Contact;
+ if (c == _nullContact)
+ {
+ return;
+ }
+
+ // An attached body is being destroyed, we must destroy this contact
+ // immediately to avoid orphaned shape pointers.
+ Destroy(c);
+ }
+
+ public void Destroy(Contact c)
+ {
+ Fixture fixtureA = c.FixtureA;
+ Fixture fixtureB = c.FixtureB;
+ Body bodyA = fixtureA.Body;
+ Body bodyB = fixtureB.Body;
+
+ if (c.Manifold.PointCount > 0)
+ {
+ if(_world._contactListener!=null)
+ _world._contactListener.EndContact(c);
+ }
+
+ // Remove from the world.
+ if (c._prev != null)
+ {
+ c._prev._next = c._next;
+ }
+
+ if (c._next != null)
+ {
+ c._next._prev = c._prev;
+ }
+
+ if (c == _world._contactList)
+ {
+ _world._contactList = c._next;
+ }
+
+ // Remove from body 1
+ if (c._nodeA.Prev != null)
+ {
+ c._nodeA.Prev.Next = c._nodeA.Next;
+ }
+
+ if (c._nodeA.Next != null)
+ {
+ c._nodeA.Next.Prev = c._nodeA.Prev;
+ }
+
+ if (c._nodeA == bodyA._contactList)
+ {
+ bodyA._contactList = c._nodeA.Next;
+ }
+
+ // Remove from body 2
+ if (c._nodeB.Prev != null)
+ {
+ c._nodeB.Prev.Next = c._nodeB.Next;
+ }
+
+ if (c._nodeB.Next != null)
+ {
+ c._nodeB.Next.Prev = c._nodeB.Prev;
+ }
+
+ if (c._nodeB == bodyB._contactList)
+ {
+ bodyB._contactList = c._nodeB.Next;
+ }
+
+ // Call the factory.
+ Contact.Destroy(ref c);
+ --_world._contactCount;
+ }
+
+ // This is the top level collision call for the time step. Here
+ // all the narrow phase collision is processed for the world
+ // contact list.
+ public void Collide()
+ {
+ // Update awake contacts.
+ for (Contact c = _world._contactList; c != null; c = c.GetNext())
+ {
+ Body bodyA = c._fixtureA.Body;
+ Body bodyB = c._fixtureB.Body;
+ if (bodyA.IsSleeping() && bodyB.IsSleeping())
+ {
+ continue;
+ }
+
+ c.Update(_world._contactListener);
+ }
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs.meta
new file mode 100644
index 0000000..83bfbf8
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/ContactManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 67b73dad9d40aa0458f9fc9e0fb15b9d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs
new file mode 100644
index 0000000..98fe5fd
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs
@@ -0,0 +1,52 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class CircleContact : Contact
+ {
+ public CircleContact(Fixture fixtureA, Fixture fixtureB)
+ : base(fixtureA, fixtureB)
+ {
+ Box2DXDebug.Assert(fixtureA.ShapeType == ShapeType.CircleShape);
+ Box2DXDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape);
+ CollideShapeFunction = CollideCircles;
+ }
+
+ private static void CollideCircles(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2)
+ {
+ Collision.Collision.CollideCircles(ref manifold, (CircleShape)shape1, xf1, (CircleShape)shape2, xf2);
+ }
+
+ new public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ return new CircleContact(fixtureA, fixtureB);
+ }
+
+ new public static void Destroy(ref Contact contact)
+ {
+ contact = null;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs.meta
new file mode 100644
index 0000000..5f63bd5
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/CircleContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bca3f5e232ed4e240a0e1cb79225517a
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/Contact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/Contact.cs
index 85ae672..7c23ca5 100644
--- a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/Contact.cs
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/Contact.cs
@@ -1,7 +1,376 @@
-using System.Collections;
-using System.Collections.Generic;
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
-namespace Box2D
+ 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 Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
{
+ public delegate Contact ContactCreateFcn(Fixture fixtureA, Fixture fixtureB);
+ public delegate void ContactDestroyFcn(ref Contact contact);
+
+ public struct ContactRegister
+ {
+ public ContactCreateFcn CreateFcn;
+ public ContactDestroyFcn DestroyFcn;
+ public bool Primary;
+ }
+
+ /// <summary>
+ /// A contact edge is used to connect bodies and contacts together
+ /// in a contact graph where each body is a node and each contact
+ /// is an edge. A contact edge belongs to a doubly linked list
+ /// maintained in each attached body. Each contact has two contact
+ /// nodes, one for each attached body.
+ /// </summary>
+ public class ContactEdge
+ {
+ /// <summary>
+ /// Provides quick access to the other body attached.
+ /// </summary>
+ public Body Other;
+ /// <summary>
+ /// The contact.
+ /// </summary>
+ public Contact Contact;
+ /// <summary>
+ /// The previous contact edge in the body's contact list.
+ /// </summary>
+ public ContactEdge Prev;
+ /// <summary>
+ /// The next contact edge in the body's contact list.
+ /// </summary>
+ public ContactEdge Next;
+ }
+
+ /// <summary>
+ /// The class manages contact between two shapes. A contact exists for each overlapping
+ /// AABB in the broad-phase (except if filtered). Therefore a contact object may exist
+ /// that has no contact points.
+ /// </summary>
+ public abstract class Contact
+ {
+ [Flags]
+ public enum CollisionFlags
+ {
+ NonSolid = 0x0001,
+ Slow = 0x0002,
+ Island = 0x0004,
+ Toi = 0x0008,
+ Touch = 0x0010
+ }
+
+ public static ContactRegister[][] s_registers =
+ new ContactRegister[(int)ShapeType.ShapeTypeCount][/*(int)ShapeType.ShapeTypeCount*/];
+ public static bool s_initialized;
+
+ public CollisionFlags _flags;
+
+ // World pool and list pointers.
+ public Contact _prev;
+ public Contact _next;
+
+ // Nodes for connecting bodies.
+ public ContactEdge _nodeA;
+ public ContactEdge _nodeB;
+
+ public Fixture _fixtureA;
+ public Fixture _fixtureB;
+
+ public Manifold _manifold = new Manifold();
+
+ public float _toi;
+
+ internal delegate void CollideShapeDelegate(
+ ref Manifold manifold, Shape circle1, XForm xf1, Shape circle2, XForm xf2);
+ internal CollideShapeDelegate CollideShapeFunction;
+
+ public Contact(){}
+
+ public Contact(Fixture fA, Fixture fB)
+ {
+ _flags = 0;
+
+ if (fA.IsSensor || fB.IsSensor)
+ {
+ _flags |= CollisionFlags.NonSolid;
+ }
+
+ _fixtureA = fA;
+ _fixtureB = fB;
+
+ _manifold.PointCount = 0;
+
+ _prev = null;
+ _next = null;
+
+ _nodeA = new ContactEdge();
+ _nodeB = new ContactEdge();
+ }
+
+ public static void AddType(ContactCreateFcn createFcn, ContactDestroyFcn destoryFcn,
+ ShapeType type1, ShapeType type2)
+ {
+ Box2DXDebug.Assert(ShapeType.UnknownShape < type1 && type1 < ShapeType.ShapeTypeCount);
+ Box2DXDebug.Assert(ShapeType.UnknownShape < type2 && type2 < ShapeType.ShapeTypeCount);
+
+ if (s_registers[(int)type1] == null)
+ s_registers[(int)type1] = new ContactRegister[(int)ShapeType.ShapeTypeCount];
+
+ s_registers[(int)type1][(int)type2].CreateFcn = createFcn;
+ s_registers[(int)type1][(int)type2].DestroyFcn = destoryFcn;
+ s_registers[(int)type1][(int)type2].Primary = true;
+
+ if (type1 != type2)
+ {
+ s_registers[(int)type2][(int)type1].CreateFcn = createFcn;
+ s_registers[(int)type2][(int)type1].DestroyFcn = destoryFcn;
+ s_registers[(int)type2][(int)type1].Primary = false;
+ }
+ }
+
+ public static void InitializeRegisters()
+ {
+ AddType(CircleContact.Create, CircleContact.Destroy, ShapeType.CircleShape, ShapeType.CircleShape);
+ AddType(PolyAndCircleContact.Create, PolyAndCircleContact.Destroy, ShapeType.PolygonShape, ShapeType.CircleShape);
+ AddType(PolygonContact.Create, PolygonContact.Destroy, ShapeType.PolygonShape, ShapeType.PolygonShape);
+
+ AddType(EdgeAndCircleContact.Create, EdgeAndCircleContact.Destroy, ShapeType.EdgeShape, ShapeType.CircleShape);
+ AddType(PolyAndEdgeContact.Create, PolyAndEdgeContact.Destroy, ShapeType.PolygonShape, ShapeType.EdgeShape);
+ }
+
+ public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ if (s_initialized == false)
+ {
+ InitializeRegisters();
+ s_initialized = true;
+ }
+
+ ShapeType type1 = fixtureA.ShapeType;
+ ShapeType type2 = fixtureB.ShapeType;
+
+ Box2DXDebug.Assert(ShapeType.UnknownShape < type1 && type1 < ShapeType.ShapeTypeCount);
+ Box2DXDebug.Assert(ShapeType.UnknownShape < type2 && type2 < ShapeType.ShapeTypeCount);
+
+ ContactCreateFcn createFcn = s_registers[(int)type1][(int)type2].CreateFcn;
+ if (createFcn != null)
+ {
+ if (s_registers[(int)type1][(int)type2].Primary)
+ {
+ return createFcn(fixtureA, fixtureB);
+ }
+ else
+ {
+ return createFcn(fixtureB, fixtureA);
+ }
+ }
+ else
+ {
+ return null;
+ }
+ }
+
+ public static void Destroy(ref Contact contact)
+ {
+ Box2DXDebug.Assert(s_initialized == true);
+
+ if (contact._manifold.PointCount > 0)
+ {
+ contact.FixtureA.Body.WakeUp();
+ contact.FixtureB.Body.WakeUp();
+ }
+
+ ShapeType typeA = contact.FixtureA.ShapeType;
+ ShapeType typeB = contact.FixtureB.ShapeType;
+
+ Box2DXDebug.Assert(ShapeType.UnknownShape < typeA && typeA < ShapeType.ShapeTypeCount);
+ Box2DXDebug.Assert(ShapeType.UnknownShape < typeB && typeB < ShapeType.ShapeTypeCount);
+
+ ContactDestroyFcn destroyFcn = s_registers[(int)typeA][(int)typeB].DestroyFcn;
+ destroyFcn(ref contact);
+ }
+
+ public void Update(ContactListener listener)
+ {
+ Manifold oldManifold = _manifold.Clone();
+
+ Evaluate();
+
+ Body bodyA = _fixtureA.Body;
+ Body bodyB = _fixtureB.Body;
+
+ int oldCount = oldManifold.PointCount;
+ int newCount = _manifold.PointCount;
+
+ if (newCount == 0 && oldCount > 0)
+ {
+ bodyA.WakeUp();
+ bodyB.WakeUp();
+ }
+
+ // Slow contacts don't generate TOI events.
+ if (bodyA.IsStatic() || bodyA.IsBullet() || bodyB.IsStatic() || bodyB.IsBullet())
+ {
+ _flags &= ~CollisionFlags.Slow;
+ }
+ else
+ {
+ _flags |= CollisionFlags.Slow;
+ }
+
+ // Match old contact ids to new contact ids and copy the
+ // stored impulses to warm start the solver.
+ for (int i = 0; i < _manifold.PointCount; ++i)
+ {
+ ManifoldPoint mp2 = _manifold.Points[i];
+ mp2.NormalImpulse = 0.0f;
+ mp2.TangentImpulse = 0.0f;
+ ContactID id2 = mp2.ID;
+
+ for (int j = 0; j < oldManifold.PointCount; ++j)
+ {
+ ManifoldPoint mp1 = oldManifold.Points[j];
+
+ if (mp1.ID.Key == id2.Key)
+ {
+ mp2.NormalImpulse = mp1.NormalImpulse;
+ mp2.TangentImpulse = mp1.TangentImpulse;
+ break;
+ }
+ }
+ }
+
+ if (oldCount == 0 && newCount > 0)
+ {
+ _flags |= CollisionFlags.Touch;
+ if(listener!=null)
+ listener.BeginContact(this);
+ }
+
+ if (oldCount > 0 && newCount == 0)
+ {
+ _flags &= ~CollisionFlags.Touch;
+ if (listener != null)
+ listener.EndContact(this);
+ }
+
+ if ((_flags & CollisionFlags.NonSolid) == 0)
+ {
+ if (listener != null)
+ listener.PreSolve(this, oldManifold);
+
+ // The user may have disabled contact.
+ if (_manifold.PointCount == 0)
+ {
+ _flags &= ~CollisionFlags.Touch;
+ }
+ }
+ }
+
+ public void Evaluate()
+ {
+ Body bodyA = _fixtureA.Body;
+ Body bodyB = _fixtureB.Body;
+
+ Box2DXDebug.Assert(CollideShapeFunction!=null);
+
+ CollideShapeFunction(ref _manifold, _fixtureA.Shape, bodyA.GetXForm(), _fixtureB.Shape, bodyB.GetXForm());
+ }
+
+ public float ComputeTOI(Sweep sweepA, Sweep sweepB)
+ {
+ TOIInput input = new TOIInput();
+ input.SweepA = sweepA;
+ input.SweepB = sweepB;
+ input.SweepRadiusA = _fixtureA.ComputeSweepRadius(sweepA.LocalCenter);
+ input.SweepRadiusB = _fixtureB.ComputeSweepRadius(sweepB.LocalCenter);
+ input.Tolerance = Common.Settings.LinearSlop;
+
+ return Collision.Collision.TimeOfImpact(input, _fixtureA.Shape, _fixtureB.Shape);
+ }
+
+ /// <summary>
+ /// Get the contact manifold.
+ /// </summary>
+ public Manifold Manifold
+ {
+ get { return _manifold; }
+ }
+
+ /// <summary>
+ /// Get the world manifold.
+ /// </summary>
+ public void GetWorldManifold(out WorldManifold worldManifold)
+ {
+ worldManifold = new WorldManifold();
+
+ Body bodyA = _fixtureA.Body;
+ Body bodyB = _fixtureB.Body;
+ Shape shapeA = _fixtureA.Shape;
+ Shape shapeB = _fixtureB.Shape;
+
+ worldManifold.Initialize(_manifold, bodyA.GetXForm(), shapeA._radius, bodyB.GetXForm(), shapeB._radius);
+ }
+
+ /// <summary>
+ /// Is this contact solid?
+ /// </summary>
+ /// <returns>True if this contact should generate a response.</returns>
+ public bool IsSolid
+ {
+ get { return (_flags & CollisionFlags.NonSolid) == 0; }
+ }
+
+ /// <summary>
+ /// Are fixtures touching?
+ /// </summary>
+ public bool AreTouching
+ {
+ get { return (_flags & CollisionFlags.Touch) == CollisionFlags.Touch; }
+ }
+
+ /// <summary>
+ /// Get the next contact in the world's contact list.
+ /// </summary>
+ public Contact GetNext()
+ {
+ return _next;
+ }
+
+ /// <summary>
+ /// Get the first fixture in this contact.
+ /// </summary>
+ public Fixture FixtureA
+ {
+ get { return _fixtureA; }
+ }
+ /// <summary>
+ /// Get the second fixture in this contact.
+ /// </summary>
+ public Fixture FixtureB
+ {
+ get { return _fixtureB; }
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs
new file mode 100644
index 0000000..a8affb6
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs
@@ -0,0 +1,712 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+//#define B2_DEBUG_SOLVER
+
+using System;
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public struct ContactConstraintPoint
+ {
+ public Vec2 LocalPoint;
+ public Vec2 RA;
+ public Vec2 RB;
+ public float NormalImpulse;
+ public float TangentImpulse;
+ public float NormalMass;
+ public float TangentMass;
+ public float EqualizedMass;
+ public float VelocityBias;
+ }
+
+ public class ContactConstraint
+ {
+ public ContactConstraintPoint[] Points = new ContactConstraintPoint[Settings.MaxManifoldPoints];
+ public Vec2 LocalPlaneNormal;
+ public Vec2 LocalPoint;
+ public Vec2 Normal;
+ public Mat22 NormalMass;
+ public Mat22 K;
+ public Body BodyA;
+ public Body BodyB;
+ public ManifoldType Type;
+ public float Radius;
+ public float Friction;
+ public float Restitution;
+ public int PointCount;
+ public Manifold Manifold;
+
+ //public ContactConstraint()
+ //{
+ // for (int i = 0; i < Settings.MaxManifoldPoints; i++)
+ // Points[i] = new ContactConstraintPoint();
+ //}
+ }
+
+ public class ContactSolver : IDisposable
+ {
+ public TimeStep _step;
+ public ContactConstraint[] _constraints;
+ public int _constraintCount;
+
+ public ContactSolver(TimeStep step, Contact[] contacts, int contactCount)
+ {
+ _step = step;
+ _constraintCount = contactCount;
+
+ _constraints = new ContactConstraint[_constraintCount];
+ for (int i = 0; i < _constraintCount; i++)
+ _constraints[i] = new ContactConstraint();
+
+ int count = 0;
+ for (int i = 0; i < _constraintCount; ++i)
+ {
+ Contact contact = contacts[i];
+
+ Fixture fixtureA = contact._fixtureA;
+ Fixture fixtureB = contact._fixtureB;
+ Shape shapeA = fixtureA.Shape;
+ Shape shapeB = fixtureB.Shape;
+ float radiusA = shapeA._radius;
+ float radiusB = shapeB._radius;
+ Body bodyA = fixtureA.Body;
+ Body bodyB = fixtureB.Body;
+ Manifold manifold = contact.Manifold;
+
+ float friction = Settings.MixFriction(fixtureA.Friction, fixtureB.Friction);
+ float restitution = Settings.MixRestitution(fixtureA.Restitution, fixtureB.Restitution);
+
+ Vec2 vA = bodyA._linearVelocity;
+ Vec2 vB = bodyB._linearVelocity;
+ float wA = bodyA._angularVelocity;
+ float wB = bodyB._angularVelocity;
+
+ Box2DXDebug.Assert(manifold.PointCount > 0);
+
+ WorldManifold worldManifold = new WorldManifold();
+ worldManifold.Initialize(manifold, bodyA._xf, radiusA, bodyB._xf, radiusB);
+
+ ContactConstraint cc = _constraints[i];
+ cc.BodyA = bodyA;
+ cc.BodyB = bodyB;
+ cc.Manifold = manifold;
+ cc.Normal = worldManifold.Normal;
+ cc.PointCount = manifold.PointCount;
+ cc.Friction = friction;
+ cc.Restitution = restitution;
+
+ cc.LocalPlaneNormal = manifold.LocalPlaneNormal;
+ cc.LocalPoint = manifold.LocalPoint;
+ cc.Radius = radiusA + radiusB;
+ cc.Type = manifold.Type;
+
+ unsafe
+ {
+ fixed (ContactConstraintPoint* ccPointsPtr = cc.Points)
+ {
+ for (int j = 0; j < cc.PointCount; ++j)
+ {
+ ManifoldPoint cp = manifold.Points[j];
+ ContactConstraintPoint* ccp = &ccPointsPtr[j];
+
+ ccp->NormalImpulse = cp.NormalImpulse;
+ ccp->TangentImpulse = cp.TangentImpulse;
+
+ ccp->LocalPoint = cp.LocalPoint;
+
+ ccp->RA = worldManifold.Points[j] - bodyA._sweep.C;
+ ccp->RB = worldManifold.Points[j] - bodyB._sweep.C;
+
+ float rnA = Vec2.Cross(ccp->RA, cc.Normal);
+ float rnB = Vec2.Cross(ccp->RB, cc.Normal);
+ rnA *= rnA;
+ rnB *= rnB;
+
+ float kNormal = bodyA._invMass + bodyB._invMass + bodyA._invI * rnA + bodyB._invI * rnB;
+
+ Box2DXDebug.Assert(kNormal > Common.Settings.FLT_EPSILON);
+ ccp->NormalMass = 1.0f / kNormal;
+
+ float kEqualized = bodyA._mass * bodyA._invMass + bodyB._mass * bodyB._invMass;
+ kEqualized += bodyA._mass * bodyA._invI * rnA + bodyB._mass * bodyB._invI * rnB;
+
+ Box2DXDebug.Assert(kEqualized > Common.Settings.FLT_EPSILON);
+ ccp->EqualizedMass = 1.0f / kEqualized;
+
+ Vec2 tangent = Vec2.Cross(cc.Normal, 1.0f);
+
+ float rtA = Vec2.Cross(ccp->RA, tangent);
+ float rtB = Vec2.Cross(ccp->RB, tangent);
+ rtA *= rtA;
+ rtB *= rtB;
+
+ float kTangent = bodyA._invMass + bodyB._invMass + bodyA._invI * rtA + bodyB._invI * rtB;
+
+ Box2DXDebug.Assert(kTangent > Common.Settings.FLT_EPSILON);
+ ccp->TangentMass = 1.0f / kTangent;
+
+ // Setup a velocity bias for restitution.
+ ccp->VelocityBias = 0.0f;
+ float vRel = Vec2.Dot(cc.Normal, vB + Vec2.Cross(wB, ccp->RB) - vA - Vec2.Cross(wA, ccp->RA));
+ if (vRel < -Common.Settings.VelocityThreshold)
+ {
+ ccp->VelocityBias = -cc.Restitution * vRel;
+ }
+ }
+
+ // If we have two points, then prepare the block solver.
+ if (cc.PointCount == 2)
+ {
+ ContactConstraintPoint* ccp1 = &ccPointsPtr[0];
+ ContactConstraintPoint* ccp2 = &ccPointsPtr[1];
+
+ float invMassA = bodyA._invMass;
+ float invIA = bodyA._invI;
+ float invMassB = bodyB._invMass;
+ float invIB = bodyB._invI;
+
+ float rn1A = Vec2.Cross(ccp1->RA, cc.Normal);
+ float rn1B = Vec2.Cross(ccp1->RB, cc.Normal);
+ float rn2A = Vec2.Cross(ccp2->RA, cc.Normal);
+ float rn2B = Vec2.Cross(ccp2->RB, cc.Normal);
+
+ float k11 = invMassA + invMassB + invIA * rn1A * rn1A + invIB * rn1B * rn1B;
+ float k22 = invMassA + invMassB + invIA * rn2A * rn2A + invIB * rn2B * rn2B;
+ float k12 = invMassA + invMassB + invIA * rn1A * rn2A + invIB * rn1B * rn2B;
+
+ // Ensure a reasonable condition number.
+ const float k_maxConditionNumber = 100.0f;
+ if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12))
+ {
+ // K is safe to invert.
+ cc.K.Col1.Set(k11, k12);
+ cc.K.Col2.Set(k12, k22);
+ cc.NormalMass = cc.K.GetInverse();
+ }
+ else
+ {
+ // The constraints are redundant, just use one.
+ // TODO_ERIN use deepest?
+ cc.PointCount = 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void Dispose()
+ {
+ _constraints = null;
+ }
+
+ public void InitVelocityConstraints(TimeStep step)
+ {
+ unsafe
+ {
+ // Warm start.
+ for (int i = 0; i < _constraintCount; ++i)
+ {
+ ContactConstraint c = _constraints[i];
+
+ Body bodyA = c.BodyA;
+ Body bodyB = c.BodyB;
+ float invMassA = bodyA._invMass;
+ float invIA = bodyA._invI;
+ float invMassB = bodyB._invMass;
+ float invIB = bodyB._invI;
+ Vec2 normal = c.Normal;
+ Vec2 tangent = Vec2.Cross(normal, 1.0f);
+
+ fixed (ContactConstraintPoint* pointsPtr = c.Points)
+ {
+ if (step.WarmStarting)
+ {
+ for (int j = 0; j < c.PointCount; ++j)
+ {
+ ContactConstraintPoint* ccp = &pointsPtr[j];
+ ccp->NormalImpulse *= step.DtRatio;
+ ccp->TangentImpulse *= step.DtRatio;
+ Vec2 P = ccp->NormalImpulse * normal + ccp->TangentImpulse * tangent;
+ bodyA._angularVelocity -= invIA * Vec2.Cross(ccp->RA, P);
+ bodyA._linearVelocity -= invMassA * P;
+ bodyB._angularVelocity += invIB * Vec2.Cross(ccp->RB, P);
+ bodyB._linearVelocity += invMassB * P;
+ }
+ }
+ else
+ {
+ for (int j = 0; j < c.PointCount; ++j)
+ {
+ ContactConstraintPoint* ccp = &pointsPtr[j];
+ ccp->NormalImpulse = 0.0f;
+ ccp->TangentImpulse = 0.0f;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ public void SolveVelocityConstraints()
+ {
+ for (int i = 0; i < _constraintCount; ++i)
+ {
+ ContactConstraint c = _constraints[i];
+ Body bodyA = c.BodyA;
+ Body bodyB = c.BodyB;
+ float wA = bodyA._angularVelocity;
+ float wB = bodyB._angularVelocity;
+ Vec2 vA = bodyA._linearVelocity;
+ Vec2 vB = bodyB._linearVelocity;
+ float invMassA = bodyA._invMass;
+ float invIA = bodyA._invI;
+ float invMassB = bodyB._invMass;
+ float invIB = bodyB._invI;
+ Vec2 normal = c.Normal;
+ Vec2 tangent = Vec2.Cross(normal, 1.0f);
+ float friction = c.Friction;
+
+ Box2DXDebug.Assert(c.PointCount == 1 || c.PointCount == 2);
+
+ unsafe
+ {
+ fixed (ContactConstraintPoint* pointsPtr = c.Points)
+ {
+ // Solve tangent constraints
+ for (int j = 0; j < c.PointCount; ++j)
+ {
+ ContactConstraintPoint* ccp = &pointsPtr[j];
+
+ // Relative velocity at contact
+ Vec2 dv = vB + Vec2.Cross(wB, ccp->RB) - vA - Vec2.Cross(wA, ccp->RA);
+
+ // Compute tangent force
+ float vt = Vec2.Dot(dv, tangent);
+ float lambda = ccp->TangentMass * (-vt);
+
+ // b2Clamp the accumulated force
+ float maxFriction = friction * ccp->NormalImpulse;
+ float newImpulse = Common.Math.Clamp(ccp->TangentImpulse + lambda, -maxFriction, maxFriction);
+ lambda = newImpulse - ccp->TangentImpulse;
+
+ // Apply contact impulse
+ Vec2 P = lambda * tangent;
+
+ vA -= invMassA * P;
+ wA -= invIA * Vec2.Cross(ccp->RA, P);
+
+ vB += invMassB * P;
+ wB += invIB * Vec2.Cross(ccp->RB, P);
+
+ ccp->TangentImpulse = newImpulse;
+ }
+
+ // Solve normal constraints
+ if (c.PointCount == 1)
+ {
+ ContactConstraintPoint ccp = c.Points[0];
+
+ // Relative velocity at contact
+ Vec2 dv = vB + Vec2.Cross(wB, ccp.RB) - vA - Vec2.Cross(wA, ccp.RA);
+
+ // Compute normal impulse
+ float vn = Vec2.Dot(dv, normal);
+ float lambda = -ccp.NormalMass * (vn - ccp.VelocityBias);
+
+ // Clamp the accumulated impulse
+ float newImpulse = Common.Math.Max(ccp.NormalImpulse + lambda, 0.0f);
+ lambda = newImpulse - ccp.NormalImpulse;
+
+ // Apply contact impulse
+ Vec2 P = lambda * normal;
+ vA -= invMassA * P;
+ wA -= invIA * Vec2.Cross(ccp.RA, P);
+
+ vB += invMassB * P;
+ wB += invIB * Vec2.Cross(ccp.RB, P);
+ ccp.NormalImpulse = newImpulse;
+ }
+ else
+ {
+ // Block solver developed in collaboration with Dirk Gregorius (back in 01/07 on Box2D_Lite).
+ // Build the mini LCP for this contact patch
+ //
+ // vn = A * x + b, vn >= 0, , vn >= 0, x >= 0 and vn_i * x_i = 0 with i = 1..2
+ //
+ // A = J * W * JT and J = ( -n, -r1 x n, n, r2 x n )
+ // b = vn_0 - velocityBias
+ //
+ // The system is solved using the "Total enumeration method" (s. Murty). The complementary constraint vn_i * x_i
+ // implies that we must have in any solution either vn_i = 0 or x_i = 0. So for the 2D contact problem the cases
+ // vn1 = 0 and vn2 = 0, x1 = 0 and x2 = 0, x1 = 0 and vn2 = 0, x2 = 0 and vn1 = 0 need to be tested. The first valid
+ // solution that satisfies the problem is chosen.
+ //
+ // In order to account of the accumulated impulse 'a' (because of the iterative nature of the solver which only requires
+ // that the accumulated impulse is clamped and not the incremental impulse) we change the impulse variable (x_i).
+ //
+ // Substitute:
+ //
+ // x = x' - a
+ //
+ // Plug into above equation:
+ //
+ // vn = A * x + b
+ // = A * (x' - a) + b
+ // = A * x' + b - A * a
+ // = A * x' + b'
+ // b' = b - A * a;
+
+ ContactConstraintPoint* cp1 = &pointsPtr[0];
+ ContactConstraintPoint* cp2 = &pointsPtr[1];
+
+ Vec2 a = new Vec2(cp1->NormalImpulse, cp2->NormalImpulse);
+ Box2DXDebug.Assert(a.X >= 0.0f && a.Y >= 0.0f);
+
+ // Relative velocity at contact
+ Vec2 dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);
+ Vec2 dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);
+
+ // Compute normal velocity
+ float vn1 = Vec2.Dot(dv1, normal);
+ float vn2 = Vec2.Dot(dv2, normal);
+
+ Vec2 b;
+ b.X = vn1 - cp1->VelocityBias;
+ b.Y = vn2 - cp2->VelocityBias;
+ b -= Common.Math.Mul(c.K, a);
+
+ const float k_errorTol = 1e-3f;
+ //B2_NOT_USED(k_errorTol);
+
+ for (; ; )
+ {
+ //
+ // Case 1: vn = 0
+ //
+ // 0 = A * x' + b'
+ //
+ // Solve for x':
+ //
+ // x' = - inv(A) * b'
+ //
+ Vec2 x = -Common.Math.Mul(c.NormalMass, b);
+
+ if (x.X >= 0.0f && x.Y >= 0.0f)
+ {
+ // Resubstitute for the incremental impulse
+ Vec2 d = x - a;
+
+ // Apply incremental impulse
+ Vec2 P1 = d.X * normal;
+ Vec2 P2 = d.Y * normal;
+ vA -= invMassA * (P1 + P2);
+ wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));
+
+ vB += invMassB * (P1 + P2);
+ wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));
+
+ // Accumulate
+ cp1->NormalImpulse = x.X;
+ cp2->NormalImpulse = x.Y;
+
+#if DEBUG_SOLVER
+ // Postconditions
+ dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);
+ dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);
+
+ // Compute normal velocity
+ vn1 = Vec2.Dot(dv1, normal);
+ vn2 = Vec2.Dot(dv2, normal);
+
+ Box2DXDebug.Assert(Common.Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);
+ Box2DXDebug.Assert(Common.Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+ //
+ // Case 2: vn1 = 0 and x2 = 0
+ //
+ // 0 = a11 * x1' + a12 * 0 + b1'
+ // vn2 = a21 * x1' + a22 * 0 + b2'
+ //
+ x.X = -cp1->NormalMass * b.X;
+ x.Y = 0.0f;
+ vn1 = 0.0f;
+ vn2 = c.K.Col1.Y * x.X + b.Y;
+
+ if (x.X >= 0.0f && vn2 >= 0.0f)
+ {
+ // Resubstitute for the incremental impulse
+ Vec2 d = x - a;
+
+ // Apply incremental impulse
+ Vec2 P1 = d.X * normal;
+ Vec2 P2 = d.Y * normal;
+ vA -= invMassA * (P1 + P2);
+ wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));
+
+ vB += invMassB * (P1 + P2);
+ wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));
+
+ // Accumulate
+ cp1->NormalImpulse = x.X;
+ cp2->NormalImpulse = x.Y;
+
+#if DEBUG_SOLVER
+ // Postconditions
+ dv1 = vB + Vec2.Cross(wB, cp1->RB) - vA - Vec2.Cross(wA, cp1->RA);
+
+ // Compute normal velocity
+ vn1 = Vec2.Dot(dv1, normal);
+
+ Box2DXDebug.Assert(Common.Math.Abs(vn1 - cp1.VelocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+
+ //
+ // Case 3: w2 = 0 and x1 = 0
+ //
+ // vn1 = a11 * 0 + a12 * x2' + b1'
+ // 0 = a21 * 0 + a22 * x2' + b2'
+ //
+ x.X = 0.0f;
+ x.Y = -cp2->NormalMass * b.Y;
+ vn1 = c.K.Col2.X * x.Y + b.X;
+ vn2 = 0.0f;
+
+ if (x.Y >= 0.0f && vn1 >= 0.0f)
+ {
+ // Resubstitute for the incremental impulse
+ Vec2 d = x - a;
+
+ // Apply incremental impulse
+ Vec2 P1 = d.X * normal;
+ Vec2 P2 = d.Y * normal;
+ vA -= invMassA * (P1 + P2);
+ wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));
+
+ vB += invMassB * (P1 + P2);
+ wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));
+
+ // Accumulate
+ cp1->NormalImpulse = x.X;
+ cp2->NormalImpulse = x.Y;
+
+#if DEBUG_SOLVER
+ // Postconditions
+ dv2 = vB + Vec2.Cross(wB, cp2->RB) - vA - Vec2.Cross(wA, cp2->RA);
+
+ // Compute normal velocity
+ vn2 = Vec2.Dot(dv2, normal);
+
+ Box2DXDebug.Assert(Common.Math.Abs(vn2 - cp2.VelocityBias) < k_errorTol);
+#endif
+ break;
+ }
+
+ //
+ // Case 4: x1 = 0 and x2 = 0
+ //
+ // vn1 = b1
+ // vn2 = b2;
+ x.X = 0.0f;
+ x.Y = 0.0f;
+ vn1 = b.X;
+ vn2 = b.Y;
+
+ if (vn1 >= 0.0f && vn2 >= 0.0f)
+ {
+ // Resubstitute for the incremental impulse
+ Vec2 d = x - a;
+
+ // Apply incremental impulse
+ Vec2 P1 = d.X * normal;
+ Vec2 P2 = d.Y * normal;
+ vA -= invMassA * (P1 + P2);
+ wA -= invIA * (Vec2.Cross(cp1->RA, P1) + Vec2.Cross(cp2->RA, P2));
+
+ vB += invMassB * (P1 + P2);
+ wB += invIB * (Vec2.Cross(cp1->RB, P1) + Vec2.Cross(cp2->RB, P2));
+
+ // Accumulate
+ cp1->NormalImpulse = x.X;
+ cp2->NormalImpulse = x.Y;
+
+ break;
+ }
+
+ // No solution, give up. This is hit sometimes, but it doesn't seem to matter.
+ break;
+ }
+ }
+
+ bodyA._linearVelocity = vA;
+ bodyA._angularVelocity = wA;
+ bodyB._linearVelocity = vB;
+ bodyB._angularVelocity = wB;
+ }
+ }
+ }
+ }
+
+ public void FinalizeVelocityConstraints()
+ {
+ for (int i = 0; i < _constraintCount; ++i)
+ {
+ ContactConstraint c = _constraints[i];
+ Manifold m = c.Manifold;
+
+ for (int j = 0; j < c.PointCount; ++j)
+ {
+ m.Points[j].NormalImpulse = c.Points[j].NormalImpulse;
+ m.Points[j].TangentImpulse = c.Points[j].TangentImpulse;
+ }
+ }
+ }
+
+ internal class PositionSolverManifold
+ {
+ internal Vec2 Normal;
+ internal Vec2[] Points = new Vec2[Settings.MaxManifoldPoints];
+ internal float[] Separations = new float[Settings.MaxManifoldPoints];
+
+ internal void Initialize(ContactConstraint cc)
+ {
+ Box2DXDebug.Assert(cc.PointCount > 0);
+
+ switch (cc.Type)
+ {
+ case ManifoldType.Circles:
+ {
+ Vec2 pointA = cc.BodyA.GetWorldPoint(cc.LocalPoint);
+ Vec2 pointB = cc.BodyB.GetWorldPoint(cc.Points[0].LocalPoint);
+ if (Vec2.DistanceSquared(pointA, pointB) > Settings.FLT_EPSILON_SQUARED)
+ {
+ Normal = pointB - pointA;
+ Normal.Normalize();
+ }
+ else
+ {
+ Normal.Set(1.0f, 0.0f);
+ }
+
+ Points[0] = 0.5f * (pointA + pointB);
+ Separations[0] = Vec2.Dot(pointB - pointA, Normal) - cc.Radius;
+ }
+ break;
+
+ case ManifoldType.FaceA:
+ {
+ Normal = cc.BodyA.GetWorldVector(cc.LocalPlaneNormal);
+ Vec2 planePoint = cc.BodyA.GetWorldPoint(cc.LocalPoint);
+
+ for (int i = 0; i < cc.PointCount; ++i)
+ {
+ Vec2 clipPoint = cc.BodyB.GetWorldPoint(cc.Points[i].LocalPoint);
+ Separations[i] = Vec2.Dot(clipPoint - planePoint, Normal) - cc.Radius;
+ Points[i] = clipPoint;
+ }
+ }
+ break;
+
+ case ManifoldType.FaceB:
+ {
+ Normal = cc.BodyB.GetWorldVector(cc.LocalPlaneNormal);
+ Vec2 planePoint = cc.BodyB.GetWorldPoint(cc.LocalPoint);
+
+ for (int i = 0; i < cc.PointCount; ++i)
+ {
+ Vec2 clipPoint = cc.BodyA.GetWorldPoint(cc.Points[i].LocalPoint);
+ Separations[i] = Vec2.Dot(clipPoint - planePoint, Normal) - cc.Radius;
+ Points[i] = clipPoint;
+ }
+
+ // Ensure normal points from A to B
+ Normal = -Normal;
+ }
+ break;
+ }
+ }
+ }
+
+ private static PositionSolverManifold s_PositionSolverManifold = new PositionSolverManifold();
+
+ public bool SolvePositionConstraints(float baumgarte)
+ {
+ float minSeparation = 0.0f;
+
+ for (int i = 0; i < _constraintCount; ++i)
+ {
+ ContactConstraint c = _constraints[i];
+ Body bodyA = c.BodyA;
+ Body bodyB = c.BodyB;
+
+ float invMassA = bodyA._mass * bodyA._invMass;
+ float invIA = bodyA._mass * bodyA._invI;
+ float invMassB = bodyB._mass * bodyB._invMass;
+ float invIB = bodyB._mass * bodyB._invI;
+
+ s_PositionSolverManifold.Initialize(c);
+ Vec2 normal = s_PositionSolverManifold.Normal;
+
+ // Solver normal constraints
+ for (int j = 0; j < c.PointCount; ++j)
+ {
+ Vec2 point = s_PositionSolverManifold.Points[j];
+ float separation = s_PositionSolverManifold.Separations[j];
+
+ Vec2 rA = point - bodyA._sweep.C;
+ Vec2 rB = point - bodyB._sweep.C;
+
+ // Track max constraint error.
+ minSeparation = Common.Math.Min(minSeparation, separation);
+
+ // Prevent large corrections and allow slop.
+ float C = baumgarte * Common.Math.Clamp(separation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+
+ // Compute normal impulse
+ float impulse = -c.Points[j].EqualizedMass * C;
+
+ Vec2 P = impulse * normal;
+
+ bodyA._sweep.C -= invMassA * P;
+ bodyA._sweep.A -= invIA * Vec2.Cross(rA, P);
+ bodyA.SynchronizeTransform();
+
+ bodyB._sweep.C += invMassB * P;
+ bodyB._sweep.A += invIB * Vec2.Cross(rB, P);
+ bodyB.SynchronizeTransform();
+ }
+ }
+
+ // We can't expect minSpeparation >= -Settings.LinearSlop because we don't
+ // push the separation above -Settings.LinearSlop.
+ return minSeparation >= -1.5f * Settings.LinearSlop;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs.meta
new file mode 100644
index 0000000..de24a40
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/ContactSolver.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9948c0dabccb51240a006dacbe528d2e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs
new file mode 100644
index 0000000..999154c
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs
@@ -0,0 +1,55 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class EdgeAndCircleContact : Contact
+ {
+ public EdgeAndCircleContact(Fixture fixtureA, Fixture fixtureB)
+ : base(fixtureA, fixtureB)
+ {
+ Box2DXDebug.Assert(fixtureA.ShapeType == ShapeType.EdgeShape);
+ Box2DXDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape);
+ _manifold.PointCount = 0;
+ _manifold.Points[0].NormalImpulse = 0.0f;
+ _manifold.Points[0].TangentImpulse = 0.0f;
+ CollideShapeFunction = CollideEdgeAndCircle;
+ }
+
+ private static void CollideEdgeAndCircle(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2)
+ {
+ Collision.Collision.CollideEdgeAndCircle(ref manifold, (EdgeShape)shape1, xf1, (CircleShape)shape2, xf2);
+ }
+
+ new public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ return new EdgeAndCircleContact(fixtureA, fixtureB);
+ }
+
+ new public static void Destroy(ref Contact contact)
+ {
+ contact = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs.meta
new file mode 100644
index 0000000..442c45d
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/EdgeAndCircleContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 576caff6a1c4ee846aa596cfb70c8a29
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs
new file mode 100644
index 0000000..31c7bb1
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs
@@ -0,0 +1,35 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class NullContact : Contact
+ {
+ public NullContact()
+ {
+ CollideShapeFunction = Collide;
+ }
+ private static void Collide(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2) { }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs.meta
new file mode 100644
index 0000000..fca685f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/NullContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 75a72f933e8900b4a97d40ee2cb66e8d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs
new file mode 100644
index 0000000..4a63bf8
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs
@@ -0,0 +1,52 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class PolyAndCircleContact : Contact
+ {
+ public PolyAndCircleContact(Fixture fixtureA, Fixture fixtureB)
+ : base(fixtureA, fixtureB)
+ {
+ Box2DXDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape);
+ Box2DXDebug.Assert(fixtureB.ShapeType == ShapeType.CircleShape);
+ CollideShapeFunction = CollidePolygonCircle;
+ }
+
+ private static void CollidePolygonCircle(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2)
+ {
+ Collision.Collision.CollidePolygonAndCircle(ref manifold, (PolygonShape)shape1, xf1, (CircleShape)shape2, xf2);
+ }
+
+ new public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ return new PolyAndCircleContact(fixtureA, fixtureB);
+ }
+
+ new public static void Destroy(ref Contact contact)
+ {
+ contact = null;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs.meta
new file mode 100644
index 0000000..23fa9d5
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndCircleContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 17b4ab04cd464e741a5c1d390f898c69
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs
new file mode 100644
index 0000000..a50553f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs
@@ -0,0 +1,52 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class PolyAndEdgeContact : Contact
+ {
+ public PolyAndEdgeContact(Fixture fixtureA, Fixture fixtureB)
+ : base(fixtureA, fixtureB)
+ {
+ Box2DXDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape);
+ Box2DXDebug.Assert(fixtureB.ShapeType == ShapeType.EdgeShape);
+ CollideShapeFunction = CollidePolyAndEdgeContact;
+ }
+
+ private static void CollidePolyAndEdgeContact(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2)
+ {
+ Collision.Collision.CollidePolyAndEdge(ref manifold, (PolygonShape)shape1, xf1, (EdgeShape)shape2, xf2);
+ }
+
+ new public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ return new PolyAndEdgeContact(fixtureA, fixtureB);
+ }
+
+ new public static void Destroy(ref Contact contact)
+ {
+ contact = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs.meta
new file mode 100644
index 0000000..5f83e8a
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyAndEdgeContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c42cbf67f18e2414192739161ff94e89
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs
new file mode 100644
index 0000000..5b101fb
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs
@@ -0,0 +1,52 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ public class PolygonContact : Contact
+ {
+ public PolygonContact(Fixture fixtureA, Fixture fixtureB)
+ : base(fixtureA, fixtureB)
+ {
+ Box2DXDebug.Assert(fixtureA.ShapeType == ShapeType.PolygonShape);
+ Box2DXDebug.Assert(fixtureB.ShapeType == ShapeType.PolygonShape);
+ CollideShapeFunction = CollidePolygons;
+ }
+
+ private static void CollidePolygons(ref Manifold manifold, Shape shape1, XForm xf1, Shape shape2, XForm xf2)
+ {
+ Collision.Collision.CollidePolygons(ref manifold, (PolygonShape)shape1, xf1, (PolygonShape)shape2, xf2);
+ }
+
+ new public static Contact Create(Fixture fixtureA, Fixture fixtureB)
+ {
+ return new PolygonContact(fixtureA, fixtureB);
+ }
+
+ new public static void Destroy(ref Contact contact)
+ {
+ contact = null;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs.meta
new file mode 100644
index 0000000..75be79e
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Contacts/PolyContact.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e0b5ca3d1b8329748865e1dae48d3aee
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Rope.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers.meta
index 5581851..446ed50 100644
--- a/Box2d/Assets/Program/Box2d/Rope.meta
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers.meta
@@ -1,5 +1,5 @@
fileFormatVersion: 2
-guid: dbd6d3a358e95ab42ade19d1fcbeed91
+guid: 960c2a03774a86d4986f403eb182daaa
folderAsset: yes
DefaultImporter:
externalObjects: {}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs
new file mode 100644
index 0000000..dcdb244
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs
@@ -0,0 +1,156 @@
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics.Controllers
+{
+ /// <summary>
+ /// This class is used to build buoyancy controllers
+ /// </summary>
+ public class BuoyancyControllerDef
+ {
+ /// The outer surface normal
+ public Vec2 Normal;
+ /// The height of the fluid surface along the normal
+ public float Offset;
+ /// The fluid density
+ public float Density;
+ /// Fluid velocity, for drag calculations
+ public Vec2 Velocity;
+ /// Linear drag co-efficient
+ public float LinearDrag;
+ /// Linear drag co-efficient
+ public float AngularDrag;
+ /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities
+ public bool UseDensity; //False by default to prevent a gotcha
+ /// If true, gravity is taken from the world instead of the gravity parameter.
+ public bool UseWorldGravity;
+ /// Gravity vector, if the world's gravity is not used
+ public Vec2 Gravity;
+
+ public BuoyancyControllerDef()
+ {
+ Normal = new Vec2(0, 1);
+ Offset = 0;
+ Density = 0;
+ Velocity = new Vec2(0, 0);
+ LinearDrag = 0;
+ AngularDrag = 0;
+ UseDensity = false;
+ UseWorldGravity = true;
+ Gravity = new Vec2(0, 0);
+ }
+ }
+
+ /// <summary>
+ /// Calculates buoyancy forces for fluids in the form of a half plane.
+ /// </summary>
+ public class BuoyancyController : Controller
+ {
+ /// The outer surface normal
+ public Vec2 Normal;
+ /// The height of the fluid surface along the normal
+ public float Offset;
+ /// The fluid density
+ public float Density;
+ /// Fluid velocity, for drag calculations
+ public Vec2 Velocity;
+ /// Linear drag co-efficient
+ public float LinearDrag;
+ /// Linear drag co-efficient
+ public float AngularDrag;
+ /// If false, bodies are assumed to be uniformly dense, otherwise use the shapes densities
+ public bool UseDensity; //False by default to prevent a gotcha
+ /// If true, gravity is taken from the world instead of the gravity parameter.
+ public bool UseWorldGravity;
+ /// Gravity vector, if the world's gravity is not used
+ public Vec2 Gravity;
+
+ public BuoyancyController(BuoyancyControllerDef buoyancyControllerDef)
+ {
+ Normal = buoyancyControllerDef.Normal;
+ Offset = buoyancyControllerDef.Offset;
+ Density = buoyancyControllerDef.Density;
+ Velocity = buoyancyControllerDef.Velocity;
+ LinearDrag = buoyancyControllerDef.LinearDrag;
+ AngularDrag = buoyancyControllerDef.AngularDrag;
+ UseDensity = buoyancyControllerDef.UseDensity;
+ UseWorldGravity = buoyancyControllerDef.UseWorldGravity;
+ Gravity = buoyancyControllerDef.Gravity;
+ }
+
+ public override void Step(TimeStep step)
+ {
+ //B2_NOT_USED(step);
+ if (_bodyList == null)
+ return;
+
+ if (UseWorldGravity)
+ {
+ Gravity = _world.Gravity;
+ }
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body = i.body;
+ if (body.IsSleeping())
+ {
+ //Buoyancy force is just a function of position,
+ //so unlike most forces, it is safe to ignore sleeping bodes
+ continue;
+ }
+ Vec2 areac = new Vec2(0, 0);
+ Vec2 massc = new Vec2(0, 0);
+ float area = 0;
+ float mass = 0;
+ for (Fixture shape = body.GetFixtureList(); shape != null; shape = shape.Next)
+ {
+ Vec2 sc;
+ float sarea = shape.ComputeSubmergedArea(Normal, Offset, out sc);
+ area += sarea;
+ areac.X += sarea * sc.X;
+ areac.Y += sarea * sc.Y;
+ float shapeDensity = 0;
+ if (UseDensity)
+ {
+ //TODO: Expose density publicly
+ shapeDensity = shape.Density;
+ }
+ else
+ {
+ shapeDensity = 1;
+ }
+ mass += sarea * shapeDensity;
+ massc.X += sarea * sc.X * shapeDensity;
+ massc.Y += sarea * sc.Y * shapeDensity;
+ }
+ areac.X /= area;
+ areac.Y /= area;
+ //Vec2 localCentroid = Math.MulT(body.GetXForm(), areac);
+ massc.X /= mass;
+ massc.Y /= mass;
+ if (area < Settings.FLT_EPSILON)
+ continue;
+ //Buoyancy
+ Vec2 buoyancyForce = -Density * area * Gravity;
+ body.ApplyForce(buoyancyForce, massc);
+ //Linear drag
+ Vec2 dragForce = body.GetLinearVelocityFromWorldPoint(areac) - Velocity;
+ dragForce *= -LinearDrag * area;
+ body.ApplyForce(dragForce, areac);
+ //Angular drag
+ //TODO: Something that makes more physical sense?
+ body.ApplyTorque(-body.GetInertia() / body.GetMass() * area * body.GetAngularVelocity() * AngularDrag);
+
+ }
+ }
+
+ public override void Draw(DebugDraw debugDraw)
+ {
+ float r = 1000;
+ Vec2 p1 = Offset * Normal + Vec2.Cross(Normal, r);
+ Vec2 p2 = Offset * Normal - Vec2.Cross(Normal, r);
+
+ Color color = new Color(0, 0, 0.8f);
+
+ debugDraw.DrawSegment(p1, p2, color);
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs.meta
new file mode 100644
index 0000000..7785241
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/BuoyancyController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 41543fe534c548f4b817e2ae3fab50e5
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs
new file mode 100644
index 0000000..421ca04
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs
@@ -0,0 +1,56 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics.Controllers
+{
+
+ /// This class is used to build constant acceleration controllers
+ public class ConstantAccelControllerDef
+ {
+ /// <summary>
+ /// The force to apply
+ /// </summary>
+ public Vec2 A;
+ }
+
+ public class ConstantAccelController : Controller
+ {
+ /// <summary>
+ /// The force to apply
+ /// </summary>
+ public Vec2 A;
+
+ public ConstantAccelController(ConstantAccelControllerDef def)
+ {
+ A = def.A;
+ }
+
+ public override void Step(TimeStep step)
+ {
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body = i.body;
+ if (body.IsSleeping())
+ continue;
+ body.SetLinearVelocity(body.GetLinearVelocity() + step.Dt * A);
+ }
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs.meta
new file mode 100644
index 0000000..80e33fc
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantAccelController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9c5b0816bc173a74f8f8534af62524d4
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs
new file mode 100644
index 0000000..8ef9a57
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs
@@ -0,0 +1,57 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics.Controllers
+{
+
+ /// <summary>
+ /// This class is used to build constant force controllers
+ /// </summary>
+ public class ConstantForceControllerDef
+ {
+ /// The force to apply
+ public Vec2 F;
+ }
+
+ public class ConstantForceController : Controller
+ {
+ /// <summary>
+ /// The force to apply
+ /// </summary>
+ Vec2 F;
+
+ public ConstantForceController(ConstantForceControllerDef def)
+ {
+ F = def.F;
+ }
+
+ public override void Step(TimeStep step)
+ {
+ //B2_NOT_USED(step);
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body = i.body;
+ if (body.IsSleeping())
+ continue;
+ body.ApplyForce(F, body.GetWorldCenter());
+ }
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs.meta
new file mode 100644
index 0000000..fb47c5a
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/ConstantForceController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: aa5d8d9cf6eba0b46bd1484725fb9423
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs
new file mode 100644
index 0000000..26bfbdf
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs
@@ -0,0 +1,174 @@
+using System;
+
+namespace Box2DX.Dynamics.Controllers
+{
+ /// <summary>
+ /// A controller edge is used to connect bodies and controllers together
+ /// in a bipartite graph.
+ /// </summary>
+ public class ControllerEdge
+ {
+ public Controller controller; // provides quick access to other end of this edge.
+ public Body body; // the body
+ public ControllerEdge prevBody; // the previous controller edge in the controllers's joint list
+ public ControllerEdge nextBody; // the next controller edge in the controllers's joint list
+ public ControllerEdge prevController; // the previous controller edge in the body's joint list
+ public ControllerEdge nextController; // the next controller edge in the body's joint list
+ }
+
+ /// <summary>
+ /// Base class for controllers. Controllers are a convience for encapsulating common
+ /// per-step functionality.
+ /// </summary>
+ public abstract class Controller : IDisposable
+ {
+ internal Controller _prev;
+ internal Controller _next;
+
+ internal World _world;
+ protected ControllerEdge _bodyList;
+ protected int _bodyCount;
+
+ public Controller()
+ {
+ _bodyList = null;
+ _bodyCount = 0;
+ }
+
+ public Controller(World world)
+ {
+ _bodyList = null;
+ _bodyCount = 0;
+
+ _world = world;
+ }
+
+ public void Dispose()
+ {
+ //Remove attached bodies
+
+ //Previus implementation:
+ //while (_bodyCount > 0)
+ // RemoveBody(_bodyList.body);
+
+ Clear();
+ }
+
+ /// <summary>
+ /// Controllers override this to implement per-step functionality.
+ /// </summary>
+ public abstract void Step(TimeStep step);
+
+ /// <summary>
+ /// Controllers override this to provide debug drawing.
+ /// </summary>
+ public virtual void Draw(DebugDraw debugDraw) { }
+
+ /// <summary>
+ /// Adds a body to the controller list.
+ /// </summary>
+ public void AddBody(Body body)
+ {
+ ControllerEdge edge = new ControllerEdge();
+
+ edge.body = body;
+ edge.controller = this;
+
+ //Add edge to controller list
+ edge.nextBody = _bodyList;
+ edge.prevBody = null;
+ if (_bodyList != null)
+ _bodyList.prevBody = edge;
+ _bodyList = edge;
+ ++_bodyCount;
+
+ //Add edge to body list
+ edge.nextController = body._controllerList;
+ edge.prevController = null;
+ if (body._controllerList != null)
+ body._controllerList.prevController = edge;
+ body._controllerList = edge;
+ }
+
+ /// <summary>
+ /// Removes a body from the controller list.
+ /// </summary>
+ public void RemoveBody(Body body)
+ {
+ //Assert that the controller is not empty
+ Box2DXDebug.Assert(_bodyCount > 0);
+
+ //Find the corresponding edge
+ ControllerEdge edge = _bodyList;
+ while (edge != null && edge.body != body)
+ edge = edge.nextBody;
+
+ //Assert that we are removing a body that is currently attached to the controller
+ Box2DXDebug.Assert(edge != null);
+
+ //Remove edge from controller list
+ if (edge.prevBody != null)
+ edge.prevBody.nextBody = edge.nextBody;
+ if (edge.nextBody != null)
+ edge.nextBody.prevBody = edge.prevBody;
+ if (edge == _bodyList)
+ _bodyList = edge.nextBody;
+ --_bodyCount;
+
+ //Remove edge from body list
+ if (edge.prevController != null)
+ edge.prevController.nextController = edge.nextController;
+ if (edge.nextController != null)
+ edge.nextController.prevController = edge.prevController;
+ if (edge == body._controllerList)
+ body._controllerList = edge.nextController;
+
+ //Free the edge
+ edge = null;
+ }
+
+ /// <summary>
+ /// Removes all bodies from the controller list.
+ /// </summary>
+ public void Clear()
+ {
+#warning "Check this"
+ ControllerEdge current = _bodyList;
+ while (current != null)
+ {
+ ControllerEdge edge = current;
+
+ //Remove edge from controller list
+ _bodyList = edge.nextBody;
+
+ //Remove edge from body list
+ if (edge.prevController != null)
+ edge.prevController.nextController = edge.nextController;
+ if (edge.nextController != null)
+ edge.nextController.prevController = edge.prevController;
+ if (edge == edge.body._controllerList)
+ edge.body._controllerList = edge.nextController;
+
+ //Free the edge
+ //m_world->m_blockAllocator.Free(edge, sizeof(b2ControllerEdge));
+ }
+
+ _bodyCount = 0;
+ }
+
+ /// <summary>
+ /// Get the next body in the world's body list.
+ /// </summary>
+ internal Controller GetNext() { return _next; }
+
+ /// <summary>
+ /// Get the parent world of this body.
+ /// </summary>
+ internal World GetWorld() { return _world; }
+
+ /// <summary>
+ /// Get the attached body list
+ /// </summary>
+ internal ControllerEdge GetBodyList() { return _bodyList; }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs.meta
new file mode 100644
index 0000000..197cb7f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/Controller.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5cca52c5b9850aa469cd4033061b8049
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs
new file mode 100644
index 0000000..333e51c
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs
@@ -0,0 +1,96 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+using Math = Box2DX.Common.Math;
+
+namespace Box2DX.Dynamics.Controllers
+{
+ /// This class is used to build gravity controllers
+ public class GravityControllerDef
+ {
+ /// <summary>
+ /// Specifies the strength of the gravitiation force
+ /// </summary>
+ public float G;
+
+ /// <summary>
+ /// If true, gravity is proportional to r^-2, otherwise r^-1
+ /// </summary>
+ public bool InvSqr;
+ }
+
+ public class GravityController : Controller
+ {
+ /// <summary>
+ /// Specifies the strength of the gravitiation force
+ /// </summary>
+ public float G;
+
+ /// If true, gravity is proportional to r^-2, otherwise r^-1
+ public bool InvSqr;
+
+ public GravityController(GravityControllerDef def)
+ {
+ G = def.G;
+ InvSqr = def.InvSqr;
+ }
+
+ public override void Step(TimeStep step)
+ {
+ //B2_NOT_USED(step);
+ if (InvSqr)
+ {
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body1 = i.body;
+ for (ControllerEdge j = _bodyList; j != i; j = j.nextBody)
+ {
+ Body body2 = j.body;
+ Vec2 d = body2.GetWorldCenter() - body1.GetWorldCenter();
+ float r2 = d.LengthSquared();
+ if (r2 < Settings.FLT_EPSILON)
+ continue;
+
+ Vec2 f = G / r2 / Math.Sqrt(r2) * body1.GetMass() * body2.GetMass() * d;
+ body1.ApplyForce(f, body1.GetWorldCenter());
+ body2.ApplyForce(-1.0f * f, body2.GetWorldCenter());
+ }
+ }
+ }
+ else
+ {
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body1 = i.body;
+ for (ControllerEdge j = _bodyList; j != i; j = j.nextBody)
+ {
+ Body body2 = j.body;
+ Vec2 d = body2.GetWorldCenter() - body1.GetWorldCenter();
+ float r2 = d.LengthSquared();
+ if (r2 < Settings.FLT_EPSILON)
+ continue;
+ Vec2 f = G / r2 * body1.GetMass() * body2.GetMass() * d;
+ body1.ApplyForce(f, body1.GetWorldCenter());
+ body2.ApplyForce(-1.0f * f, body2.GetWorldCenter());
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs.meta
new file mode 100644
index 0000000..b010f74
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/GravityController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: d18e2e93089bd984d9a454597208b26e
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs
new file mode 100644
index 0000000..8fb5af3
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs
@@ -0,0 +1,89 @@
+/*
+* Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+*
+* This software is provided 'as-is', without any express or implied
+* warranty. In no event will the authors be held liable for any damages
+* arising from the use of this software.
+* Permission is granted to anyone to use this software for any purpose,
+* including commercial applications, and to alter it and redistribute it
+* freely, subject to the following restrictions:
+* 1. The origin of this software must not be misrepresented; you must not
+* claim that you wrote the original software. If you use this software
+* in a product, an acknowledgment in the product documentation would be
+* appreciated but is not required.
+* 2. Altered source versions must be plainly marked as such, and must not be
+* misrepresented as being the original software.
+* 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics.Controllers
+{
+
+ /// <summary>
+ /// This class is used to build tensor damping controllers
+ /// </summary>
+ public class b2TensorDampingControllerDef
+ {
+ /// Tensor to use in damping model
+ Mat22 T;
+ /// Set this to a positive number to clamp the maximum amount of damping done.
+ float maxTimestep;
+ };
+
+ public class TensorDampingController : Controller
+ {
+
+ /// <summary>
+ /// Tensor to use in damping model
+ /// Some examples (matrixes in format (row1; row2) )
+ ///(-a 0;0 -a) Standard isotropic damping with strength a
+ ///(0 a;-a 0) Electron in fixed field - a force at right angles to velocity with proportional magnitude
+ ///(-a 0;0 -b) Differing x and y damping. Useful e.g. for top-down wheels.
+ ///By the way, tensor in this case just means matrix, don't let the terminology get you down.
+ /// </summary>
+ Mat22 T;
+
+ /// <summary>
+ /// Set this to a positive number to clamp the maximum amount of damping done.
+ /// Typically one wants maxTimestep to be 1/(max eigenvalue of T), so that damping will never cause something to reverse direction
+ /// </summary>
+ float MaxTimestep;
+
+ /// Sets damping independantly along the x and y axes
+ public void SetAxisAligned(float xDamping, float yDamping)
+ {
+ T.Col1.X = -xDamping;
+ T.Col1.Y = 0;
+ T.Col2.X = 0;
+ T.Col2.Y = -yDamping;
+ if (xDamping > 0 || yDamping > 0)
+ {
+ MaxTimestep = 1 / Math.Max(xDamping, yDamping);
+ }
+ else
+ {
+ MaxTimestep = 0;
+ }
+ }
+
+ public override void Step(TimeStep step)
+ {
+ float timestep = step.Dt;
+ if (timestep <= Settings.FLT_EPSILON)
+ return;
+ if (timestep > MaxTimestep && MaxTimestep > 0)
+ timestep = MaxTimestep;
+ for (ControllerEdge i = _bodyList; i != null; i = i.nextBody)
+ {
+ Body body = i.body;
+ if (body.IsSleeping())
+ continue;
+
+ Vec2 damping = body.GetWorldVector(Math.Mul(T, body.GetLocalVector(body.GetLinearVelocity())));
+ body.SetLinearVelocity(body.GetLinearVelocity() + timestep*damping);
+ }
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs.meta
new file mode 100644
index 0000000..a975c8f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Controllers/TensorDampingController.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c119a4aba6eaccf408daeb709363782c
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs b/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs
new file mode 100644
index 0000000..eecfd1f
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs
@@ -0,0 +1,478 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+using Box2DX.Collision;
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// This holds contact filtering data.
+ /// </summary>
+ public struct FilterData
+ {
+ /// <summary>
+ /// The collision category bits. Normally you would just set one bit.
+ /// </summary>
+ public ushort CategoryBits;
+
+ /// <summary>
+ /// The collision mask bits. This states the categories that this
+ /// shape would accept for collision.
+ /// </summary>
+ public ushort MaskBits;
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public short GroupIndex;
+ }
+
+ /// <summary>
+ /// A fixture definition is used to create a fixture. This class defines an
+ /// abstract fixture definition. You can reuse fixture definitions safely.
+ /// </summary>
+ public class FixtureDef
+ {
+ /// <summary>
+ /// The constructor sets the default fixture definition values.
+ /// </summary>
+ public FixtureDef()
+ {
+ Type = ShapeType.UnknownShape;
+ UserData = null;
+ Friction = 0.2f;
+ Restitution = 0.0f;
+ Density = 0.0f;
+ Filter.CategoryBits = 0x0001;
+ Filter.MaskBits = 0xFFFF;
+ Filter.GroupIndex = 0;
+ IsSensor = false;
+ }
+
+ /// <summary>
+ /// Holds the shape type for down-casting.
+ /// </summary>
+ public ShapeType Type;
+
+ /// <summary>
+ /// Use this to store application specific fixture data.
+ /// </summary>
+ public object UserData;
+
+ /// <summary>
+ /// The friction coefficient, usually in the range [0,1].
+ /// </summary>
+ public float Friction;
+
+ /// <summary>
+ /// The restitution (elasticity) usually in the range [0,1].
+ /// </summary>
+ public float Restitution;
+
+ /// <summary>
+ /// The density, usually in kg/m^2.
+ /// </summary>
+ public float Density;
+
+ /// <summary>
+ /// A sensor shape collects contact information but never generates a collision response.
+ /// </summary>
+ public bool IsSensor;
+
+ /// <summary>
+ /// Contact filtering data.
+ /// </summary>
+ public FilterData Filter;
+ }
+
+ /// <summary>
+ /// This structure is used to build a fixture with a circle shape.
+ /// </summary>
+ public class CircleDef : FixtureDef
+ {
+ public Vec2 LocalPosition;
+ public float Radius;
+
+ public CircleDef()
+ {
+ Type = ShapeType.CircleShape;
+ LocalPosition = Vec2.Zero;
+ Radius = 1.0f;
+ }
+ }
+
+ /// <summary>
+ /// Convex polygon. The vertices must be ordered so that the outside of
+ /// the polygon is on the right side of the edges (looking along the edge
+ /// from start to end).
+ /// </summary>
+ public class PolygonDef : FixtureDef
+ {
+ /// <summary>
+ /// The number of polygon vertices.
+ /// </summary>
+ public int VertexCount;
+
+ /// <summary>
+ /// The polygon vertices in local coordinates.
+ /// </summary>
+ public Vec2[] Vertices = new Vec2[Settings.MaxPolygonVertices];
+
+ public PolygonDef()
+ {
+ Type = ShapeType.PolygonShape;
+ VertexCount = 0;
+ }
+
+ /// <summary>
+ /// Build vertices to represent an axis-aligned box.
+ /// </summary>
+ /// <param name="hx">The half-width</param>
+ /// <param name="hy">The half-height.</param>
+ public void SetAsBox(float hx, float hy)
+ {
+ VertexCount = 4;
+ Vertices[0].Set(-hx, -hy);
+ Vertices[1].Set(hx, -hy);
+ Vertices[2].Set(hx, hy);
+ Vertices[3].Set(-hx, hy);
+ }
+
+
+ /// <summary>
+ /// Build vertices to represent an oriented box.
+ /// </summary>
+ /// <param name="hx">The half-width</param>
+ /// <param name="hy">The half-height.</param>
+ /// <param name="center">The center of the box in local coordinates.</param>
+ /// <param name="angle">The rotation of the box in local coordinates.</param>
+ public void SetAsBox(float hx, float hy, Vec2 center, float angle)
+ {
+ SetAsBox(hx, hy);
+
+ XForm xf = new XForm();
+ xf.Position = center;
+ xf.R.Set(angle);
+
+ for (int i = 0; i < VertexCount; ++i)
+ {
+ Vertices[i] = Common.Math.Mul(xf, Vertices[i]);
+ }
+ }
+ }
+
+ /// <summary>
+ /// This structure is used to build a chain of edges.
+ /// </summary>
+ public class EdgeDef : FixtureDef
+ {
+ public EdgeDef()
+ {
+ Type = ShapeType.EdgeShape;
+ }
+
+ /// <summary>
+ /// The start vertex.
+ /// </summary>
+ public Vec2 Vertex1;
+
+ /// <summary>
+ /// The end vertex.
+ /// </summary>
+ public Vec2 Vertex2;
+ }
+
+ /// <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
+ /// such as friction, collision filters, etc.
+ /// Fixtures are created via Body.CreateFixture.
+ /// @warning you cannot reuse fixtures.
+ /// </summary>
+ public class Fixture
+ {
+ protected ShapeType _type;
+ protected bool _isSensor;
+ protected UInt16 _proxyId;
+
+ internal Body _body;
+ protected Shape _shape;
+ internal Fixture _next;
+
+ /// <summary>
+ /// Contact filtering data. You must call b2World::Refilter to correct
+ /// existing contacts/non-contacts.
+ /// </summary>
+ public FilterData Filter;
+
+ /// <summary>
+ /// Is this fixture a sensor (non-solid)?
+ /// </summary>
+ public bool IsSensor { get { return _isSensor; } }
+
+ /// <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.
+ /// </summary>
+ public Shape Shape { get { return _shape; } }
+
+ /// <summary>
+ /// Get the type of this shape. You can use this to down cast to the concrete shape.
+ /// </summary>
+ public ShapeType ShapeType { get { return _type; } }
+
+ /// <summary>
+ /// Get the next fixture in the parent body's fixture list.
+ /// </summary>
+ public Fixture Next { get { return _next; } }
+
+ /// <summary>
+ /// Get the parent body of this fixture. This is NULL if the fixture is not attached.
+ /// </summary>
+ public Body Body { get { return _body; } }
+
+ /// <summary>
+ /// User data that was assigned in the fixture definition. Use this to
+ /// store your application specific data.
+ /// </summary>
+ public object UserData;
+
+ /// <summary>
+ /// Friction coefficient, usually in the range [0,1].
+ /// </summary>
+ public float Friction;
+
+ /// <summary>
+ /// Restitution (elasticity) usually in the range [0,1].
+ /// </summary>
+ public float Restitution;
+
+ /// <summary>
+ /// Density, usually in kg/m^2.
+ /// </summary>
+ public float Density;
+
+ public Fixture()
+ {
+ _proxyId = PairManager.NullProxy;
+ }
+
+ public void Create(BroadPhase broadPhase, Body body, XForm xf, FixtureDef def)
+ {
+ UserData = def.UserData;
+ Friction = def.Friction;
+ Restitution = def.Restitution;
+ Density = def.Density;
+
+ _body = body;
+ _next = null;
+
+ Filter = def.Filter;
+
+ _isSensor = def.IsSensor;
+
+ _type = def.Type;
+
+ // Allocate and initialize the child shape.
+ switch (_type)
+ {
+ case ShapeType.CircleShape:
+ {
+ CircleShape circle = new CircleShape();
+ CircleDef circleDef = (CircleDef)def;
+ circle._position = circleDef.LocalPosition;
+ circle._radius = circleDef.Radius;
+ _shape = circle;
+ }
+ break;
+
+ case ShapeType.PolygonShape:
+ {
+ PolygonShape polygon = new PolygonShape();
+ PolygonDef polygonDef = (PolygonDef)def;
+ polygon.Set(polygonDef.Vertices, polygonDef.VertexCount);
+ _shape = polygon;
+ }
+ break;
+
+ case ShapeType.EdgeShape:
+ {
+ EdgeShape edge = new EdgeShape();
+ EdgeDef edgeDef = (EdgeDef)def;
+ edge.Set(edgeDef.Vertex1, edgeDef.Vertex2);
+ _shape = edge;
+ }
+ break;
+
+ default:
+ Box2DXDebug.Assert(false);
+ break;
+ }
+
+ // Create proxy in the broad-phase.
+ AABB aabb;
+ _shape.ComputeAABB(out aabb, xf);
+
+ bool inRange = broadPhase.InRange(aabb);
+
+ // You are creating a shape outside the world box.
+ Box2DXDebug.Assert(inRange);
+
+ if (inRange)
+ {
+ _proxyId = broadPhase.CreateProxy(aabb, this);
+ }
+ else
+ {
+ _proxyId = PairManager.NullProxy;
+ }
+ }
+
+ public void Destroy(BroadPhase broadPhase)
+ {
+ // Remove proxy from the broad-phase.
+ if (_proxyId != PairManager.NullProxy)
+ {
+ broadPhase.DestroyProxy(_proxyId);
+ _proxyId = PairManager.NullProxy;
+ }
+
+ // Free the child shape.
+ _shape.Dispose();
+ _shape = null;
+ }
+
+ internal bool Synchronize(BroadPhase broadPhase, XForm transform1, XForm transform2)
+ {
+ if (_proxyId == PairManager.NullProxy)
+ {
+ return false;
+ }
+
+ // Compute an AABB that covers the swept shape (may miss some rotation effect).
+ AABB aabb1, aabb2;
+ _shape.ComputeAABB(out aabb1, transform1);
+ _shape.ComputeAABB(out aabb2, transform2);
+
+ AABB aabb = new AABB();
+ aabb.Combine(aabb1, aabb2);
+
+ if (broadPhase.InRange(aabb))
+ {
+ broadPhase.MoveProxy(_proxyId, aabb);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+ internal void RefilterProxy(BroadPhase broadPhase, XForm transform)
+ {
+ if (_proxyId == PairManager.NullProxy)
+ {
+ return;
+ }
+
+ broadPhase.DestroyProxy(_proxyId);
+
+ AABB aabb;
+ _shape.ComputeAABB(out aabb, transform);
+
+ bool inRange = broadPhase.InRange(aabb);
+
+ if (inRange)
+ {
+ _proxyId = broadPhase.CreateProxy(aabb, this);
+ }
+ else
+ {
+ _proxyId = PairManager.NullProxy;
+ }
+ }
+
+ public virtual void Dispose()
+ {
+ Box2DXDebug.Assert(_proxyId == PairManager.NullProxy);
+ Box2DXDebug.Assert(_shape == null);
+ }
+
+ /// <summary>
+ /// Compute the mass properties of this shape using its dimensions and density.
+ /// The inertia tensor is computed about the local origin, not the centroid.
+ /// </summary>
+ /// <param name="massData">Returns the mass data for this shape.</param>
+ public void ComputeMass(out MassData massData)
+ {
+ _shape.ComputeMass(out massData, Density);
+ }
+
+ /// <summary>
+ /// Compute the volume and centroid of this fixture intersected with a half plane.
+ /// </summary>
+ /// <param name="normal">Normal the surface normal.</param>
+ /// <param name="offset">Offset the surface offset along normal.</param>
+ /// <param name="c">Returns the centroid.</param>
+ /// <returns>The total volume less than offset along normal.</returns>
+ public float ComputeSubmergedArea(Vec2 normal, float offset, out Vec2 c)
+ {
+ return _shape.ComputeSubmergedArea(normal, offset, _body.GetXForm(), out c);
+ }
+
+ /// <summary>
+ /// Test a point for containment in this fixture. This only works for convex shapes.
+ /// </summary>
+ /// <param name="p">A point in world coordinates.</param>
+ public bool TestPoint(Vec2 p)
+ {
+ return _shape.TestPoint(_body.GetXForm(), p);
+ }
+
+ /// <summary>
+ /// Perform a ray cast against this shape.
+ /// </summary>
+ /// <param name="lambda">Returns the hit fraction. You can use this to compute the contact point
+ /// p = (1 - lambda) * segment.p1 + lambda * segment.p2.</param>
+ /// <param name="normal">Returns the normal at the contact point. If there is no intersection, the normal
+ /// is not set.</param>
+ /// <param name="segment">Defines the begin and end point of the ray cast.</param>
+ /// <param name="maxLambda">A number typically in the range [0,1].</param>
+ public SegmentCollide TestSegment(out float lambda, out Vec2 normal, Segment segment, float maxLambda)
+ {
+ return _shape.TestSegment(_body.GetXForm(), out lambda, out normal, segment, maxLambda);
+ }
+
+ /// <summary>
+ /// Get the maximum radius about the parent body's center of mass.
+ /// </summary>
+ public float ComputeSweepRadius(Vec2 pivot)
+ {
+ return _shape.ComputeSweepRadius(pivot);
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs.meta
new file mode 100644
index 0000000..c5f3148
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Fixture.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 121b855d9b0acd24c8362d3416dc5907
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Island.cs b/Box2d/Assets/Program/Box2d/Dynamics/Island.cs
new file mode 100644
index 0000000..0f24b8e
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Island.cs
@@ -0,0 +1,522 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+/*
+Position Correction Notes
+=========================
+I tried the several algorithms for position correction of the 2D revolute joint.
+I looked at these systems:
+- simple pendulum (1m diameter sphere on massless 5m stick) with initial angular velocity of 100 rad/s.
+- suspension bridge with 30 1m long planks of length 1m.
+- multi-link chain with 30 1m long links.
+
+Here are the algorithms:
+
+Baumgarte - A fraction of the position error is added to the velocity error. There is no
+separate position solver.
+
+Pseudo Velocities - After the velocity solver and position integration,
+the position error, Jacobian, and effective mass are recomputed. Then
+the velocity constraints are solved with pseudo velocities and a fraction
+of the position error is added to the pseudo velocity error. The pseudo
+velocities are initialized to zero and there is no warm-starting. After
+the position solver, the pseudo velocities are added to the positions.
+This is also called the First Order World method or the Position LCP method.
+
+Modified Nonlinear Gauss-Seidel (NGS) - Like Pseudo Velocities except the
+position error is re-computed for each constraint and the positions are updated
+after the constraint is solved. The radius vectors (aka Jacobians) are
+re-computed too (otherwise the algorithm has horrible instability). The pseudo
+velocity states are not needed because they are effectively zero at the beginning
+of each iteration. Since we have the current position error, we allow the
+iterations to terminate early if the error becomes smaller than b2_linearSlop.
+
+Full NGS or just NGS - Like Modified NGS except the effective mass are re-computed
+each time a constraint is solved.
+
+Here are the results:
+Baumgarte - this is the cheapest algorithm but it has some stability problems,
+especially with the bridge. The chain links separate easily close to the root
+and they jitter as they struggle to pull together. This is one of the most common
+methods in the field. The big drawback is that the position correction artificially
+affects the momentum, thus leading to instabilities and false bounce. I used a
+bias factor of 0.2. A larger bias factor makes the bridge less stable, a smaller
+factor makes joints and contacts more spongy.
+
+Pseudo Velocities - the is more stable than the Baumgarte method. The bridge is
+stable. However, joints still separate with large angular velocities. Drag the
+simple pendulum in a circle quickly and the joint will separate. The chain separates
+easily and does not recover. I used a bias factor of 0.2. A larger value lead to
+the bridge collapsing when a heavy cube drops on it.
+
+Modified NGS - this algorithm is better in some ways than Baumgarte and Pseudo
+Velocities, but in other ways it is worse. The bridge and chain are much more
+stable, but the simple pendulum goes unstable at high angular velocities.
+
+Full NGS - stable in all tests. The joints display good stiffness. The bridge
+still sags, but this is better than infinite forces.
+
+Recommendations
+Pseudo Velocities are not really worthwhile because the bridge and chain cannot
+recover from joint separation. In other cases the benefit over Baumgarte is small.
+
+Modified NGS is not a robust method for the revolute joint due to the violent
+instability seen in the simple pendulum. Perhaps it is viable with other constraint
+types, especially scalar constraints where the effective mass is a scalar.
+
+This leaves Baumgarte and Full NGS. Baumgarte has small, but manageable instabilities
+and is very fast. I don't think we can escape Baumgarte, especially in highly
+demanding cases where high constraint fidelity is not needed.
+
+Full NGS is robust and easy on the eyes. I recommend this as an option for
+higher fidelity simulation and certainly for suspension bridges and long chains.
+Full NGS might be a good choice for ragdolls, especially motorized ragdolls where
+joint separation can be problematic. The number of NGS iterations can be reduced
+for better performance without harming robustness much.
+
+Each joint in a can be handled differently in the position solver. So I recommend
+a system where the user can select the algorithm on a per joint basis. I would
+probably default to the slower Full NGS and let the user select the faster
+Baumgarte method in performance critical scenarios.
+*/
+
+/*
+Cache Performance
+
+The Box2D solvers are dominated by cache misses. Data structures are designed
+to increase the number of cache hits. Much of misses are due to random access
+to body data. The constraint structures are iterated over linearly, which leads
+to few cache misses.
+
+The _bodies are not accessed during iteration. Instead read only data, such as
+the mass values are stored with the constraints. The mutable data are the constraint
+impulses and the _bodies velocities/positions. The impulses are held inside the
+constraint structures. The body velocities/positions are held in compact, temporary
+arrays to increase the number of cache hits. Linear and angular velocity are
+stored in a single array since multiple arrays lead to multiple misses.
+*/
+
+/*
+2D Rotation
+
+R = [cos(theta) -sin(theta)]
+ [sin(theta) cos(theta) ]
+
+thetaDot = omega
+
+Let q1 = cos(theta), q2 = sin(theta).
+R = [q1 -q2]
+ [q2 q1]
+
+q1Dot = -thetaDot * q2
+q2Dot = thetaDot * q1
+
+q1_new = q1_old - dt * w * q2
+q2_new = q2_old + dt * w * q1
+then normalize.
+
+This might be faster than computing sin+cos.
+However, we can compute sin+cos of the same angle fast.
+*/
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+using Box2DX.Collision;
+
+namespace Box2DX.Dynamics
+{
+ public struct Position
+ {
+ public Vec2 x;
+ public float a;
+ }
+
+ public struct Velocity
+ {
+ public Vec2 v;
+ public float w;
+ }
+
+ public class Island : IDisposable
+ {
+ public ContactListener _listener;
+
+ public Body[] _bodies;
+ public Contact[] _contacts;
+ public Joint[] _joints;
+
+ public Position[] _positions;
+ public Velocity[] _velocities;
+
+ public int _bodyCount;
+ public int _jointCount;
+ public int _contactCount;
+
+ public int _bodyCapacity;
+ public int _contactCapacity;
+ public int _jointCapacity;
+
+ public int _positionIterationCount;
+
+ public Island(int bodyCapacity, int contactCapacity, int jointCapacity, ContactListener listener)
+ {
+ _bodyCapacity = bodyCapacity;
+ _contactCapacity = contactCapacity;
+ _jointCapacity = jointCapacity;
+ //__bodyCount = 0;
+ //_contactCount = 0;
+ //_jointCount = 0;
+
+ _listener = listener;
+
+ _bodies = new Body[bodyCapacity];
+ _contacts = new Contact[contactCapacity];
+ _joints = new Joint[jointCapacity];
+
+ _velocities = new Velocity[_bodyCapacity];
+ _positions = new Position[_bodyCapacity];
+ }
+
+ public void Dispose()
+ {
+ // Warning: the order should reverse the constructor order.
+ _positions = null;
+ _velocities = null;
+ _joints = null;
+ _contacts = null;
+ _bodies = null;
+ }
+
+ public void Clear()
+ {
+ _bodyCount = 0;
+ _contactCount = 0;
+ _jointCount = 0;
+ }
+
+ public void Solve(TimeStep step, Vec2 gravity, bool allowSleep)
+ {
+ // Integrate velocities and apply damping.
+ for (int i = 0; i < _bodyCount; ++i)
+ {
+ Body b = _bodies[i];
+
+ if (b.IsStatic())
+ continue;
+
+ // Integrate velocities.
+ b._linearVelocity += step.Dt * (gravity + b._invMass * b._force);
+ b._angularVelocity += step.Dt * b._invI * b._torque;
+
+ // Reset forces.
+ b._force.Set(0.0f, 0.0f);
+ b._torque = 0.0f;
+
+ // Apply damping.
+ // ODE: dv/dt + c * v = 0
+ // Solution: v(t) = v0 * exp(-c * t)
+ // Time step: v(t + dt) = v0 * exp(-c * (t + dt)) = v0 * exp(-c * t) * exp(-c * dt) = v * exp(-c * dt)
+ // v2 = exp(-c * dt) * v1
+ // Taylor expansion:
+ // v2 = (1.0f - c * dt) * v1
+ b._linearVelocity *= Common.Math.Clamp(1.0f - step.Dt * b._linearDamping, 0.0f, 1.0f);
+ b._angularVelocity *= Common.Math.Clamp(1.0f - step.Dt * b._angularDamping, 0.0f, 1.0f);
+ }
+
+ ContactSolver contactSolver = new ContactSolver(step, _contacts, _contactCount);
+
+ // Initialize velocity constraints.
+ contactSolver.InitVelocityConstraints(step);
+
+ for (int i = 0; i < _jointCount; ++i)
+ {
+ _joints[i].InitVelocityConstraints(step);
+ }
+
+ // Solve velocity constraints.
+ for (int i = 0; i < step.VelocityIterations; ++i)
+ {
+ for (int j = 0; j < _jointCount; ++j)
+ {
+ _joints[j].SolveVelocityConstraints(step);
+ }
+ contactSolver.SolveVelocityConstraints();
+ }
+
+ // Post-solve (store impulses for warm starting).
+ contactSolver.FinalizeVelocityConstraints();
+
+ // Integrate positions.
+ for (int i = 0; i < _bodyCount; ++i)
+ {
+ Body b = _bodies[i];
+
+ if (b.IsStatic())
+ continue;
+
+ // Check for large velocities.
+ Vec2 translation = step.Dt * b._linearVelocity;
+ if (Common.Vec2.Dot(translation, translation) > Settings.MaxTranslationSquared)
+ {
+ translation.Normalize();
+ b._linearVelocity = (Settings.MaxTranslation * step.Inv_Dt) * translation;
+ }
+
+ float rotation = step.Dt * b._angularVelocity;
+ if (rotation * rotation > Settings.MaxRotationSquared)
+ {
+ if (rotation < 0.0)
+ {
+ b._angularVelocity = -step.Inv_Dt * Settings.MaxRotation;
+ }
+ else
+ {
+ b._angularVelocity = step.Inv_Dt * Settings.MaxRotation;
+ }
+ }
+
+ // Store positions for continuous collision.
+ b._sweep.C0 = b._sweep.C;
+ b._sweep.A0 = b._sweep.A;
+
+ // Integrate
+ b._sweep.C += step.Dt * b._linearVelocity;
+ b._sweep.A += step.Dt * b._angularVelocity;
+
+ // Compute new transform
+ b.SynchronizeTransform();
+
+ // Note: shapes are synchronized later.
+ }
+
+ // Iterate over constraints.
+ for (int i = 0; i < step.PositionIterations; ++i)
+ {
+ bool contactsOkay = contactSolver.SolvePositionConstraints(Settings.ContactBaumgarte);
+
+ bool jointsOkay = true;
+ for (int j = 0; j < _jointCount; ++j)
+ {
+ bool jointOkay = _joints[j].SolvePositionConstraints(Settings.ContactBaumgarte);
+ jointsOkay = jointsOkay && jointOkay;
+ }
+
+ if (contactsOkay && jointsOkay)
+ {
+ // Exit early if the position errors are small.
+ break;
+ }
+ }
+
+ Report(contactSolver._constraints);
+
+ if (allowSleep)
+ {
+ float minSleepTime = Settings.FLT_MAX;
+
+#if !TARGET_FLOAT32_IS_FIXED
+ float linTolSqr = Settings.LinearSleepTolerance * Settings.LinearSleepTolerance;
+ float angTolSqr = Settings.AngularSleepTolerance * Settings.AngularSleepTolerance;
+#endif
+
+ for (int i = 0; i < _bodyCount; ++i)
+ {
+ Body b = _bodies[i];
+ if (b._invMass == 0.0f)
+ {
+ continue;
+ }
+
+ if ((b._flags & Body.BodyFlags.AllowSleep) == 0)
+ {
+ b._sleepTime = 0.0f;
+ minSleepTime = 0.0f;
+ }
+
+ if ((b._flags & Body.BodyFlags.AllowSleep) == 0 ||
+#if TARGET_FLOAT32_IS_FIXED
+ Common.Math.Abs(b._angularVelocity) > Settings.AngularSleepTolerance ||
+ Common.Math.Abs(b._linearVelocity.X) > Settings.LinearSleepTolerance ||
+ Common.Math.Abs(b._linearVelocity.Y) > Settings.LinearSleepTolerance)
+#else
+ b._angularVelocity * b._angularVelocity > angTolSqr ||
+ Vec2.Dot(b._linearVelocity, b._linearVelocity) > linTolSqr)
+#endif
+ {
+ b._sleepTime = 0.0f;
+ minSleepTime = 0.0f;
+ }
+ else
+ {
+ b._sleepTime += step.Dt;
+ minSleepTime = Common.Math.Min(minSleepTime, b._sleepTime);
+ }
+ }
+
+ if (minSleepTime >= Settings.TimeToSleep)
+ {
+ for (int i = 0; i < _bodyCount; ++i)
+ {
+ Body b = _bodies[i];
+ b._flags |= Body.BodyFlags.Sleep;
+ b._linearVelocity = Vec2.Zero;
+ b._angularVelocity = 0.0f;
+ }
+ }
+ }
+ }
+
+ public void SolveTOI(ref TimeStep subStep)
+ {
+ ContactSolver contactSolver = new ContactSolver(subStep, _contacts, _contactCount);
+
+ // No warm starting is needed for TOI events because warm
+ // starting impulses were applied in the discrete solver.
+
+ // Warm starting for joints is off for now, but we need to
+ // call this function to compute Jacobians.
+ for (int i = 0; i < _jointCount; ++i)
+ {
+ _joints[i].InitVelocityConstraints(subStep);
+ }
+
+ // Solve velocity constraints.
+ for (int i = 0; i < subStep.VelocityIterations; ++i)
+ {
+ contactSolver.SolveVelocityConstraints();
+ for (int j = 0; j < _jointCount; ++j)
+ {
+ _joints[j].SolveVelocityConstraints(subStep);
+ }
+ }
+
+ // Don't store the TOI contact forces for warm starting
+ // because they can be quite large.
+
+ // Integrate positions.
+ for (int i = 0; i < _bodyCount; ++i)
+ {
+ Body b = _bodies[i];
+
+ if (b.IsStatic())
+ continue;
+
+ // Check for large velocities.
+ Vec2 translation = subStep.Dt * b._linearVelocity;
+ if (Vec2.Dot(translation, translation) > Settings.MaxTranslationSquared)
+ {
+ translation.Normalize();
+ b._linearVelocity = (Settings.MaxTranslation * subStep.Inv_Dt) * translation;
+ }
+
+ float rotation = subStep.Dt * b._angularVelocity;
+ if (rotation * rotation > Settings.MaxRotationSquared)
+ {
+ if (rotation < 0.0)
+ {
+ b._angularVelocity = -subStep.Inv_Dt * Settings.MaxRotation;
+ }
+ else
+ {
+ b._angularVelocity = subStep.Inv_Dt * Settings.MaxRotation;
+ }
+ }
+
+ // Store positions for continuous collision.
+ b._sweep.C0 = b._sweep.C;
+ b._sweep.A0 = b._sweep.A;
+
+ // Integrate
+ b._sweep.C += subStep.Dt * b._linearVelocity;
+ b._sweep.A += subStep.Dt * b._angularVelocity;
+
+ // Compute new transform
+ b.SynchronizeTransform();
+
+ // Note: shapes are synchronized later.
+ }
+
+ // Solve position constraints.
+ const float k_toiBaumgarte = 0.75f;
+ for (int i = 0; i < subStep.PositionIterations; ++i)
+ {
+ bool contactsOkay = contactSolver.SolvePositionConstraints(k_toiBaumgarte);
+ bool jointsOkay = true;
+ for (int j = 0; j < _jointCount; ++j)
+ {
+ bool jointOkay = _joints[j].SolvePositionConstraints(k_toiBaumgarte);
+ jointsOkay = jointsOkay && jointOkay;
+ }
+
+ if (contactsOkay && jointsOkay)
+ {
+ break;
+ }
+ }
+
+ Report(contactSolver._constraints);
+ }
+
+ public void Add(Body body)
+ {
+ Box2DXDebug.Assert(_bodyCount < _bodyCapacity);
+ body._islandIndex = _bodyCount;
+ _bodies[_bodyCount++] = body;
+ }
+
+ public void Add(Contact contact)
+ {
+ Box2DXDebug.Assert(_contactCount < _contactCapacity);
+ _contacts[_contactCount++] = contact;
+ }
+
+ public void Add(Joint joint)
+ {
+ Box2DXDebug.Assert(_jointCount < _jointCapacity);
+ _joints[_jointCount++] = joint;
+ }
+
+ public void Report(ContactConstraint[] constraints)
+ {
+ if (_listener == null)
+ {
+ return;
+ }
+
+ for (int i = 0; i < _contactCount; ++i)
+ {
+ Contact c = _contacts[i];
+ ContactConstraint cc = constraints[i];
+ ContactImpulse impulse = new ContactImpulse();
+ for (int j = 0; j < cc.PointCount; ++j)
+ {
+ impulse.normalImpulses[j] = cc.Points[j].NormalImpulse;
+ impulse.tangentImpulses[j] = cc.Points[j].TangentImpulse;
+ }
+
+ _listener.PostSolve(c, impulse);
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Island.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Island.cs.meta
new file mode 100644
index 0000000..b73ec93
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Island.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 94208ebd7c2c8bc4187ea12969896349
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs
new file mode 100644
index 0000000..f00b664
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs
@@ -0,0 +1,277 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// 1-D constrained system
+// m (v2 - v1) = lambda
+// v2 + (beta/h) * x1 + gamma * lambda = 0, gamma has units of inverse mass.
+// x2 = x1 + h * v2
+
+// 1-D mass-damper-spring system
+// m (v2 - v1) + h * d * v2 + h * k *
+
+// C = norm(p2 - p1) - L
+// u = (p2 - p1) / norm(p2 - p1)
+// Cdot = dot(u, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// J = [-u -cross(r1, u) u cross(r2, u)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u)^2 + invMass2 + invI2 * cross(r2, u)^2
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// Distance joint definition. This requires defining an
+ /// anchor point on both bodies and the non-zero length of the
+ /// distance joint. The definition uses local anchor points
+ /// so that the initial configuration can violate the constraint
+ /// slightly. This helps when saving and loading a game.
+ /// @warning Do not use a zero or short length.
+ /// </summary>
+ public class DistanceJointDef : JointDef
+ {
+ public DistanceJointDef()
+ {
+ Type = JointType.DistanceJoint;
+ LocalAnchor1.Set(0.0f, 0.0f);
+ LocalAnchor2.Set(0.0f, 0.0f);
+ Length = 1.0f;
+ FrequencyHz = 0.0f;
+ DampingRatio = 0.0f;
+ }
+
+ /// <summary>
+ /// Initialize the bodies, anchors, and length using the world anchors.
+ /// </summary>
+ public void Initialize(Body body1, Body body2, Vec2 anchor1, Vec2 anchor2)
+ {
+ Body1 = body1;
+ Body2 = body2;
+ LocalAnchor1 = body1.GetLocalPoint(anchor1);
+ LocalAnchor2 = body2.GetLocalPoint(anchor2);
+ Vec2 d = anchor2 - anchor1;
+ Length = d.Length();
+ }
+
+ /// <summary>
+ /// The local anchor point relative to body1's origin.
+ /// </summary>
+ public Vec2 LocalAnchor1;
+
+ /// <summary>
+ /// The local anchor point relative to body2's origin.
+ /// </summary>
+ public Vec2 LocalAnchor2;
+
+ /// <summary>
+ /// The equilibrium length between the anchor points.
+ /// </summary>
+ public float Length;
+
+ /// <summary>
+ /// The response speed.
+ /// </summary>
+ public float FrequencyHz;
+
+ /// <summary>
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ /// </summary>
+ public float DampingRatio;
+ }
+
+ /// <summary>
+ /// A distance joint constrains two points on two bodies
+ /// to remain at a fixed distance from each other. You can view
+ /// this as a massless, rigid rod.
+ /// </summary>
+ public class DistanceJoint : Joint
+ {
+ public Vec2 _localAnchor1;
+ public Vec2 _localAnchor2;
+ public Vec2 _u;
+ public float _frequencyHz;
+ public float _dampingRatio;
+ public float _gamma;
+ public float _bias;
+ public float _impulse;
+ public float _mass; // effective mass for the constraint.
+ public float _length;
+
+ public override Vec2 Anchor1
+ {
+ get { return _body1.GetWorldPoint(_localAnchor1);}
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor2);}
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ return (inv_dt * _impulse) * _u;
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return 0.0f;
+ }
+
+ public DistanceJoint(DistanceJointDef def)
+ : base(def)
+ {
+ _localAnchor1 = def.LocalAnchor1;
+ _localAnchor2 = def.LocalAnchor2;
+ _length = def.Length;
+ _frequencyHz = def.FrequencyHz;
+ _dampingRatio = def.DampingRatio;
+ _impulse = 0.0f;
+ _gamma = 0.0f;
+ _bias = 0.0f;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ // Compute the effective mass matrix.
+ Vec2 r1 = Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+ _u = b2._sweep.C + r2 - b1._sweep.C - r1;
+
+ // Handle singularity.
+ float length = _u.Length();
+ if (length > Settings.LinearSlop)
+ {
+ _u *= 1.0f / length;
+ }
+ else
+ {
+ _u.Set(0.0f, 0.0f);
+ }
+
+ float cr1u = Vec2.Cross(r1, _u);
+ float cr2u = Vec2.Cross(r2, _u);
+ float invMass = b1._invMass + b1._invI * cr1u * cr1u + b2._invMass + b2._invI * cr2u * cr2u;
+ Box2DXDebug.Assert(invMass > Settings.FLT_EPSILON);
+ _mass = 1.0f / invMass;
+
+ if (_frequencyHz > 0.0f)
+ {
+ float C = length - _length;
+
+ // Frequency
+ float omega = 2.0f * Settings.Pi * _frequencyHz;
+
+ // Damping coefficient
+ float d = 2.0f * _mass * _dampingRatio * omega;
+
+ // Spring stiffness
+ float k = _mass * omega * omega;
+
+ // magic formulas
+ _gamma = 1.0f / (step.Dt * (d + step.Dt * k));
+ _bias = C * step.Dt * k * _gamma;
+
+ _mass = 1.0f / (invMass + _gamma);
+ }
+
+ if (step.WarmStarting)
+ {
+ //Scale the inpulse to support a variable timestep.
+ _impulse *= step.DtRatio;
+ Vec2 P = _impulse * _u;
+ b1._linearVelocity -= b1._invMass * P;
+ b1._angularVelocity -= b1._invI * Vec2.Cross(r1, P);
+ b2._linearVelocity += b2._invMass * P;
+ b2._angularVelocity += b2._invI * Vec2.Cross(r2, P);
+ }
+ else
+ {
+ _impulse = 0.0f;
+ }
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ if (_frequencyHz > 0.0f)
+ {
+ //There is no possition correction for soft distace constraint.
+ return true;
+ }
+
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ Vec2 d = b2._sweep.C + r2 - b1._sweep.C - r1;
+
+ float length = d.Normalize();
+ float C = length - _length;
+ C = Common.Math.Clamp(C, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
+
+ float impulse = -_mass * C;
+ _u = d;
+ Vec2 P = impulse * _u;
+
+ b1._sweep.C -= b1._invMass * P;
+ b1._sweep.A -= b1._invI * Vec2.Cross(r1, P);
+ b2._sweep.C += b2._invMass * P;
+ b2._sweep.A += b2._invI * Vec2.Cross(r2, P);
+
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+
+ return System.Math.Abs(C) < Settings.LinearSlop;
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ //B2_NOT_USED(step);
+
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ // Cdot = dot(u, v + cross(w, r))
+ Vec2 v1 = b1._linearVelocity + Vec2.Cross(b1._angularVelocity, r1);
+ Vec2 v2 = b2._linearVelocity + Vec2.Cross(b2._angularVelocity, r2);
+ float Cdot = Vec2.Dot(_u, v2 - v1);
+ float impulse = -_mass * (Cdot + _bias + _gamma * _impulse);
+ _impulse += impulse;
+
+ Vec2 P = impulse * _u;
+ b1._linearVelocity -= b1._invMass * P;
+ b1._angularVelocity -= b1._invI * Vec2.Cross(r1, P);
+ b2._linearVelocity += b2._invMass * P;
+ b2._angularVelocity += b2._invI * Vec2.Cross(r2, P);
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs.meta
new file mode 100644
index 0000000..ee77e15
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/DistanceJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 788b8ce508e4a6e47a8b05a48110d372
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs
new file mode 100644
index 0000000..7dbdf6a
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs
@@ -0,0 +1,322 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Gear Joint:
+// C0 = (coordinate1 + ratio * coordinate2)_initial
+// C = C0 - (cordinate1 + ratio * coordinate2) = 0
+// Cdot = -(Cdot1 + ratio * Cdot2)
+// J = -[J1 ratio * J2]
+// K = J * invM * JT
+// = J1 * invM1 * J1T + ratio * ratio * J2 * invM2 * J2T
+//
+// Revolute:
+// coordinate = rotation
+// Cdot = angularVelocity
+// J = [0 0 1]
+// K = J * invM * JT = invI
+//
+// Prismatic:
+// coordinate = dot(p - pg, ug)
+// Cdot = dot(v + cross(w, r), ug)
+// J = [ug cross(r, ug)]
+// K = J * invM * JT = invMass + invI * cross(r, ug)^2
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// Gear joint definition. This definition requires two existing
+ /// revolute or prismatic joints (any combination will work).
+ /// The provided joints must attach a dynamic body to a static body.
+ /// </summary>
+ public class GearJointDef : JointDef
+ {
+ public GearJointDef()
+ {
+ Type = JointType.GearJoint;
+ Joint1 = null;
+ Joint2 = null;
+ Ratio = 1.0f;
+ }
+
+ /// <summary>
+ /// The first revolute/prismatic joint attached to the gear joint.
+ /// </summary>
+ public Joint Joint1;
+
+ /// <summary>
+ /// The second revolute/prismatic joint attached to the gear joint.
+ /// </summary>
+ public Joint Joint2;
+
+ /// <summary>
+ /// The gear ratio.
+ /// @see GearJoint for explanation.
+ /// </summary>
+ public float Ratio;
+ }
+
+ /// <summary>
+ /// A gear joint is used to connect two joints together. Either joint
+ /// can be a revolute or prismatic joint. You specify a gear ratio
+ /// to bind the motions together:
+ /// coordinate1 + ratio * coordinate2 = constant
+ /// The ratio can be negative or positive. If one joint is a revolute joint
+ /// and the other joint is a prismatic joint, then the ratio will have units
+ /// of length or units of 1/length.
+ /// @warning The revolute and prismatic joints must be attached to
+ /// fixed bodies (which must be body1 on those joints).
+ /// </summary>
+ public class GearJoint : Joint
+ {
+ public Body _ground1;
+ public Body _ground2;
+
+ // One of these is NULL.
+ public RevoluteJoint _revolute1;
+ public PrismaticJoint _prismatic1;
+
+ // One of these is NULL.
+ public RevoluteJoint _revolute2;
+ public PrismaticJoint _prismatic2;
+
+ public Vec2 _groundAnchor1;
+ public Vec2 _groundAnchor2;
+
+ public Vec2 _localAnchor1;
+ public Vec2 _localAnchor2;
+
+ public Jacobian _J;
+
+ public float _constant;
+ public float _ratio;
+
+ // Effective mass
+ public float _mass;
+
+ // Impulse for accumulation/warm starting.
+ public float _impulse;
+
+ public override Vec2 Anchor1 { get { return _body1.GetWorldPoint(_localAnchor1); } }
+ public override Vec2 Anchor2 { get { return _body2.GetWorldPoint(_localAnchor2); } }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ // TODO_ERIN not tested
+ Vec2 P = _impulse * _J.Linear2;
+ return inv_dt * P;
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ // TODO_ERIN not tested
+ Vec2 r = Common.Math.Mul(_body2.GetXForm().R, _localAnchor2 - _body2.GetLocalCenter());
+ Vec2 P = _impulse * _J.Linear2;
+ float L = _impulse * _J.Angular2 - Vec2.Cross(r, P);
+ return inv_dt * L;
+ }
+
+ /// <summary>
+ /// Get the gear ratio.
+ /// </summary>
+ public float Ratio { get { return _ratio; } }
+
+ public GearJoint(GearJointDef def)
+ : base(def)
+ {
+ JointType type1 = def.Joint1.GetType();
+ JointType type2 = def.Joint2.GetType();
+
+ Box2DXDebug.Assert(type1 == JointType.RevoluteJoint || type1 == JointType.PrismaticJoint);
+ Box2DXDebug.Assert(type2 == JointType.RevoluteJoint || type2 == JointType.PrismaticJoint);
+ Box2DXDebug.Assert(def.Joint1.GetBody1().IsStatic());
+ Box2DXDebug.Assert(def.Joint2.GetBody1().IsStatic());
+
+ _revolute1 = null;
+ _prismatic1 = null;
+ _revolute2 = null;
+ _prismatic2 = null;
+
+ float coordinate1, coordinate2;
+
+ _ground1 = def.Joint1.GetBody1();
+ _body1 = def.Joint1.GetBody2();
+ if (type1 == JointType.RevoluteJoint)
+ {
+ _revolute1 = (RevoluteJoint)def.Joint1;
+ _groundAnchor1 = _revolute1._localAnchor1;
+ _localAnchor1 = _revolute1._localAnchor2;
+ coordinate1 = _revolute1.JointAngle;
+ }
+ else
+ {
+ _prismatic1 = (PrismaticJoint)def.Joint1;
+ _groundAnchor1 = _prismatic1._localAnchor1;
+ _localAnchor1 = _prismatic1._localAnchor2;
+ coordinate1 = _prismatic1.JointTranslation;
+ }
+
+ _ground2 = def.Joint2.GetBody1();
+ _body2 = def.Joint2.GetBody2();
+ if (type2 == JointType.RevoluteJoint)
+ {
+ _revolute2 = (RevoluteJoint)def.Joint2;
+ _groundAnchor2 = _revolute2._localAnchor1;
+ _localAnchor2 = _revolute2._localAnchor2;
+ coordinate2 = _revolute2.JointAngle;
+ }
+ else
+ {
+ _prismatic2 = (PrismaticJoint)def.Joint2;
+ _groundAnchor2 = _prismatic2._localAnchor1;
+ _localAnchor2 = _prismatic2._localAnchor2;
+ coordinate2 = _prismatic2.JointTranslation;
+ }
+
+ _ratio = def.Ratio;
+
+ _constant = coordinate1 + _ratio * coordinate2;
+
+ _impulse = 0.0f;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body g1 = _ground1;
+ Body g2 = _ground2;
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ float K = 0.0f;
+ _J.SetZero();
+
+ if (_revolute1!=null)
+ {
+ _J.Angular1 = -1.0f;
+ K += b1._invI;
+ }
+ else
+ {
+ Vec2 ug = Common.Math.Mul(g1.GetXForm().R, _prismatic1._localXAxis1);
+ Vec2 r = Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ float crug = Vec2.Cross(r, ug);
+ _J.Linear1 = -ug;
+ _J.Angular1 = -crug;
+ K += b1._invMass + b1._invI * crug * crug;
+ }
+
+ if (_revolute2!=null)
+ {
+ _J.Angular2 = -_ratio;
+ K += _ratio * _ratio * b2._invI;
+ }
+ else
+ {
+ Vec2 ug = Common.Math.Mul(g2.GetXForm().R, _prismatic2._localXAxis1);
+ Vec2 r = Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+ float crug = Vec2.Cross(r, ug);
+ _J.Linear2 = -_ratio * ug;
+ _J.Angular2 = -_ratio * crug;
+ K += _ratio * _ratio * (b2._invMass + b2._invI * crug * crug);
+ }
+
+ // Compute effective mass.
+ Box2DXDebug.Assert(K > 0.0f);
+ _mass = 1.0f / K;
+
+ if (step.WarmStarting)
+ {
+ // Warm starting.
+ b1._linearVelocity += b1._invMass * _impulse * _J.Linear1;
+ b1._angularVelocity += b1._invI * _impulse * _J.Angular1;
+ b2._linearVelocity += b2._invMass * _impulse * _J.Linear2;
+ b2._angularVelocity += b2._invI * _impulse * _J.Angular2;
+ }
+ else
+ {
+ _impulse = 0.0f;
+ }
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ float Cdot = _J.Compute(b1._linearVelocity, b1._angularVelocity, b2._linearVelocity, b2._angularVelocity);
+
+ float impulse = _mass * (-Cdot);
+ _impulse += impulse;
+
+ b1._linearVelocity += b1._invMass * impulse * _J.Linear1;
+ b1._angularVelocity += b1._invI * impulse * _J.Angular1;
+ b2._linearVelocity += b2._invMass * impulse * _J.Linear2;
+ b2._angularVelocity += b2._invI * impulse * _J.Angular2;
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ float linearError = 0.0f;
+
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ float coordinate1, coordinate2;
+ if (_revolute1 != null)
+ {
+ coordinate1 = _revolute1.JointAngle;
+ }
+ else
+ {
+ coordinate1 = _prismatic1.JointTranslation;
+ }
+
+ if (_revolute2 != null)
+ {
+ coordinate2 = _revolute2.JointAngle;
+ }
+ else
+ {
+ coordinate2 = _prismatic2.JointTranslation;
+ }
+
+ float C = _constant - (coordinate1 + _ratio * coordinate2);
+
+ float impulse = _mass * (-C);
+
+ b1._sweep.C += b1._invMass * impulse * _J.Linear1;
+ b1._sweep.A += b1._invI * impulse * _J.Angular1;
+ b2._sweep.C += b2._invMass * impulse * _J.Linear2;
+ b2._sweep.A += b2._invI * impulse * _J.Angular2;
+
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+
+ //TODO_ERIN not implemented
+ return linearError < Settings.LinearSlop;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs.meta
new file mode 100644
index 0000000..b761f87
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/GearJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 20f2b2bb9c28bfa4c8ff62cada5632b1
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/Joint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/Joint.cs
index 85ae672..232f98b 100644
--- a/Box2d/Assets/Program/Box2d/Dynamics/Joints/Joint.cs
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/Joint.cs
@@ -1,7 +1,316 @@
-using System.Collections;
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
-namespace Box2D
+namespace Box2DX.Dynamics
{
+ public enum JointType
+ {
+ UnknownJoint,
+ RevoluteJoint,
+ PrismaticJoint,
+ DistanceJoint,
+ PulleyJoint,
+ MouseJoint,
+ GearJoint,
+ LineJoint
+ }
+
+ public enum LimitState
+ {
+ InactiveLimit,
+ AtLowerLimit,
+ AtUpperLimit,
+ EqualLimits
+ }
+
+ public struct Jacobian
+ {
+ public Vec2 Linear1;
+ public float Angular1;
+ public Vec2 Linear2;
+ public float Angular2;
+
+ public void SetZero()
+ {
+ Linear1.SetZero(); Angular1 = 0.0f;
+ Linear2.SetZero(); Angular2 = 0.0f;
+ }
+
+ public void Set(Vec2 x1, float a1, Vec2 x2, float a2)
+ {
+ Linear1 = x1; Angular1 = a1;
+ Linear2 = x2; Angular2 = a2;
+ }
+
+ public float Compute(Vec2 x1, float a1, Vec2 x2, float a2)
+ {
+ return Vec2.Dot(Linear1, x1) + Angular1 * a1 + Vec2.Dot(Linear2, x2) + Angular2 * a2;
+ }
+ }
+
+#warning "CAS"
+ /// <summary>
+ /// A joint edge is used to connect bodies and joints together
+ /// in a joint graph where each body is a node and each joint
+ /// is an edge. A joint edge belongs to a doubly linked list
+ /// maintained in each attached body. Each joint has two joint
+ /// nodes, one for each attached body.
+ /// </summary>
+ public class JointEdge
+ {
+ /// <summary>
+ /// Provides quick access to the other body attached.
+ /// </summary>
+ public Body Other;
+
+ /// <summary>
+ /// The joint.
+ /// </summary>
+ public Joint Joint;
+
+ /// <summary>
+ /// The previous joint edge in the body's joint list.
+ /// </summary>
+ public JointEdge Prev;
+
+ /// <summary>
+ /// The next joint edge in the body's joint list.
+ /// </summary>
+ public JointEdge Next;
+ }
+
+#warning "CAS"
+ /// <summary>
+ /// Joint definitions are used to construct joints.
+ /// </summary>
+ public class JointDef
+ {
+ public JointDef()
+ {
+ Type = JointType.UnknownJoint;
+ UserData = null;
+ Body1 = null;
+ Body2 = null;
+ CollideConnected = false;
+ }
+
+ /// <summary>
+ /// The joint type is set automatically for concrete joint types.
+ /// </summary>
+ public JointType Type;
+
+ /// <summary>
+ /// Use this to attach application specific data to your joints.
+ /// </summary>
+ public object UserData;
+
+ /// <summary>
+ /// The first attached body.
+ /// </summary>
+ public Body Body1;
+
+ /// <summary>
+ /// The second attached body.
+ /// </summary>
+ public Body Body2;
+
+ /// <summary>
+ /// Set this flag to true if the attached bodies should collide.
+ /// </summary>
+ public bool CollideConnected;
+ }
+
+ /// <summary>
+ /// The base joint class. Joints are used to constraint two bodies together in
+ /// various fashions. Some joints also feature limits and motors.
+ /// </summary>
+ public abstract class Joint
+ {
+ protected JointType _type;
+ internal Joint _prev;
+ internal Joint _next;
+ internal JointEdge _node1 = new JointEdge();
+ internal JointEdge _node2 = new JointEdge();
+ internal Body _body1;
+ internal Body _body2;
+
+ internal bool _islandFlag;
+ internal bool _collideConnected;
+
+ protected object _userData;
+
+ // Cache here per time step to reduce cache misses.
+ protected Vec2 _localCenter1, _localCenter2;
+ protected float _invMass1, _invI1;
+ protected float _invMass2, _invI2;
+
+ /// <summary>
+ /// Get the type of the concrete joint.
+ /// </summary>
+ public new JointType GetType()
+ {
+ return _type;
+ }
+
+ /// <summary>
+ /// Get the first body attached to this joint.
+ /// </summary>
+ /// <returns></returns>
+ public Body GetBody1()
+ {
+ return _body1;
+ }
+
+ /// <summary>
+ /// Get the second body attached to this joint.
+ /// </summary>
+ /// <returns></returns>
+ public Body GetBody2()
+ {
+ return _body2;
+ }
+
+ /// <summary>
+ /// Get the anchor point on body1 in world coordinates.
+ /// </summary>
+ /// <returns></returns>
+ public abstract Vec2 Anchor1 { get; }
+
+ /// <summary>
+ /// Get the anchor point on body2 in world coordinates.
+ /// </summary>
+ /// <returns></returns>
+ public abstract Vec2 Anchor2 { get; }
+
+ /// <summary>
+ /// Get the reaction force on body2 at the joint anchor.
+ /// </summary>
+ public abstract Vec2 GetReactionForce(float inv_dt);
+
+ /// <summary>
+ /// Get the reaction torque on body2.
+ /// </summary>
+ public abstract float GetReactionTorque(float inv_dt);
+
+ /// <summary>
+ /// Get the next joint the world joint list.
+ /// </summary>
+ /// <returns></returns>
+ public Joint GetNext()
+ {
+ return _next;
+ }
+
+ /// <summary>
+ /// Get/Set the user data pointer.
+ /// </summary>
+ /// <returns></returns>
+ public object UserData
+ {
+ get { return _userData; }
+ set { _userData = value; }
+ }
+
+ protected Joint(JointDef def)
+ {
+ _type = def.Type;
+ _prev = null;
+ _next = null;
+ _body1 = def.Body1;
+ _body2 = def.Body2;
+ _collideConnected = def.CollideConnected;
+ _islandFlag = false;
+ _userData = def.UserData;
+ }
+
+ internal static Joint Create(JointDef def)
+ {
+ Joint joint = null;
+
+ switch (def.Type)
+ {
+ case JointType.DistanceJoint:
+ {
+ joint = new DistanceJoint((DistanceJointDef)def);
+ }
+ break;
+ case JointType.MouseJoint:
+ {
+ joint = new MouseJoint((MouseJointDef)def);
+ }
+ break;
+ case JointType.PrismaticJoint:
+ {
+ joint = new PrismaticJoint((PrismaticJointDef)def);
+ }
+ break;
+ case JointType.RevoluteJoint:
+ {
+ joint = new RevoluteJoint((RevoluteJointDef)def);
+ }
+ break;
+ case JointType.PulleyJoint:
+ {
+ joint = new PulleyJoint((PulleyJointDef)def);
+ }
+ break;
+ case JointType.GearJoint:
+ {
+ joint = new GearJoint((GearJointDef)def);
+ }
+ break;
+ case JointType.LineJoint:
+ {
+ joint = new LineJoint((LineJointDef)def);
+ }
+ break;
+ default:
+ Box2DXDebug.Assert(false);
+ break;
+ }
+
+ return joint;
+ }
+
+ internal static void Destroy(Joint joint)
+ {
+ joint = null;
+ }
+
+ internal abstract void InitVelocityConstraints(TimeStep step);
+ internal abstract void SolveVelocityConstraints(TimeStep step);
+
+ // This returns true if the position errors are within tolerance.
+ internal abstract bool SolvePositionConstraints(float baumgarte);
+ internal void ComputeXForm(ref XForm xf, Vec2 center, Vec2 localCenter, float angle)
+ {
+ xf.R.Set(angle);
+ xf.Position = center - Box2DX.Common.Math.Mul(xf.R, localCenter);
+ }
+ }
}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs
new file mode 100644
index 0000000..04b2103
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs
@@ -0,0 +1,710 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Linear constraint (point-to-line)
+// d = p2 - p1 = x2 + r2 - x1 - r1
+// C = dot(perp, d)
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
+//
+// K = J * invM * JT
+//
+// J = [-a -s1 a s2]
+// a = perp
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)
+// s2 = cross(r2, a) = cross(p2 - x2, a)
+
+
+// Motor/Limit linear constraint
+// C = dot(ax1, d)
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
+
+// Block Solver
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
+// when the mass has poor distribution (leading to large torques about the joint anchor points).
+//
+// The Jacobian has 3 rows:
+// J = [-uT -s1 uT s2] // linear
+// [-vT -a1 vT a2] // limit
+//
+// u = perp
+// v = axis
+// s1 = cross(d + r1, u), s2 = cross(r2, u)
+// a1 = cross(d + r1, v), a2 = cross(r2, v)
+
+// M * (v2 - v1) = JT * df
+// J * v2 = bias
+//
+// v2 = v1 + invM * JT * df
+// J * (v1 + invM * JT * df) = bias
+// K * df = bias - J * v1 = -Cdot
+// K = J * invM * JT
+// Cdot = J * v1 - bias
+//
+// Now solve for f2.
+// df = f2 - f1
+// K * (f2 - f1) = -Cdot
+// f2 = invK * (-Cdot) + f1
+//
+// Clamp accumulated limit impulse.
+// lower: f2(2) = max(f2(2), 0)
+// upper: f2(2) = min(f2(2), 0)
+//
+// Solve for correct f2(1)
+// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * f2(2) + K(1,1:2) * f1
+// = -Cdot(1) - K(1,2) * f2(2) + K(1,1) * f1(1) + K(1,2) * f1(2)
+// K(1,1) * f2(1) = -Cdot(1) - K(1,2) * (f2(2) - f1(2)) + K(1,1) * f1(1)
+// f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)
+//
+// Now compute impulse to be applied:
+// df = f2 - f1
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// Line joint definition. This requires defining a line of
+ /// motion using an axis and an anchor point. The definition uses local
+ /// anchor points and a local axis so that the initial configuration
+ /// can violate the constraint slightly. The joint translation is zero
+ /// when the local anchor points coincide in world space. Using local
+ /// anchors and a local axis helps when saving and loading a game.
+ /// </summary>
+ public class LineJointDef : JointDef
+ {
+ public LineJointDef()
+ {
+ Type = JointType.LineJoint;
+ localAnchor1.SetZero();
+ localAnchor2.SetZero();
+ localAxis1.Set(1.0f, 0.0f);
+ enableLimit = false;
+ lowerTranslation = 0.0f;
+ upperTranslation = 0.0f;
+ enableMotor = false;
+ maxMotorForce = 0.0f;
+ motorSpeed = 0.0f;
+ }
+
+ /// <summary>
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ /// </summary>
+ public void Initialize(Body body1, Body body2, Vec2 anchor, Vec2 axis)
+ {
+ Body1 = body1;
+ Body2 = body2;
+ localAnchor1 = body1.GetLocalPoint(anchor);
+ localAnchor2 = body2.GetLocalPoint(anchor);
+ localAxis1 = body1.GetLocalVector(axis);
+ }
+
+ /// <summary>
+ /// The local anchor point relative to body1's origin.
+ /// </summary>
+ public Vec2 localAnchor1;
+
+ /// <summary>
+ /// The local anchor point relative to body2's origin.
+ /// </summary>
+ public Vec2 localAnchor2;
+
+ /// <summary>
+ /// The local translation axis in body1.
+ /// </summary>
+ public Vec2 localAxis1;
+
+ /// <summary>
+ /// Enable/disable the joint limit.
+ /// </summary>
+ public bool enableLimit;
+
+ /// <summary>
+ /// The lower translation limit, usually in meters.
+ /// </summary>
+ public float lowerTranslation;
+
+ /// <summary>
+ /// The upper translation limit, usually in meters.
+ /// </summary>
+ public float upperTranslation;
+
+ /// <summary>
+ /// Enable/disable the joint motor.
+ /// </summary>
+ public bool enableMotor;
+
+ /// <summary>
+ /// The maximum motor torque, usually in N-m.
+ /// </summary>
+ public float maxMotorForce;
+
+ /// <summary>
+ /// The desired motor speed in radians per second.
+ /// </summary>
+ public float motorSpeed;
+ }
+
+ /// <summary>
+ /// A line joint. This joint provides one degree of freedom: translation
+ /// along an axis fixed in body1. You can use a joint limit to restrict
+ /// the range of motion and a joint motor to drive the motion or to
+ /// model joint friction.
+ /// </summary>
+ public class LineJoint : Joint
+ {
+ public Vec2 _localAnchor1;
+ public Vec2 _localAnchor2;
+ public Vec2 _localXAxis1;
+ public Vec2 _localYAxis1;
+
+ public Vec2 _axis, _perp;
+ public float _s1, _s2;
+ public float _a1, _a2;
+
+ public Mat22 _K;
+ public Vec2 _impulse;
+
+ public float _motorMass; // effective mass for motor/limit translational constraint.
+ public float _motorImpulse;
+
+ public float _lowerTranslation;
+ public float _upperTranslation;
+ public float _maxMotorForce;
+ public float _motorSpeed;
+
+ public bool _enableLimit;
+ public bool _enableMotor;
+ public LimitState _limitState;
+
+ public LineJoint(LineJointDef def)
+ : base(def)
+ {
+ _localAnchor1 = def.localAnchor1;
+ _localAnchor2 = def.localAnchor2;
+ _localXAxis1 = def.localAxis1;
+ _localYAxis1 = Vec2.Cross(1.0f, _localXAxis1);
+
+ _impulse.SetZero();
+ _motorMass = 0.0f;
+ _motorImpulse = 0.0f;
+
+ _lowerTranslation = def.lowerTranslation;
+ _upperTranslation = def.upperTranslation;
+ _maxMotorForce = Settings.FORCE_INV_SCALE(def.maxMotorForce);
+ _motorSpeed = def.motorSpeed;
+ _enableLimit = def.enableLimit;
+ _enableMotor = def.enableMotor;
+ _limitState = LimitState.InactiveLimit;
+
+ _axis.SetZero();
+ _perp.SetZero();
+ }
+
+ public override Vec2 Anchor1
+ {
+ get { return _body1.GetWorldPoint(_localAnchor1); }
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor2); }
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ return inv_dt * (_impulse.X * _perp + (_motorImpulse + _impulse.Y) * _axis);
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return 0.0f;
+ }
+
+ /// <summary>
+ /// Get the current joint translation, usually in meters.
+ /// </summary>
+ public float GetJointTranslation()
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 p1 = b1.GetWorldPoint(_localAnchor1);
+ Vec2 p2 = b2.GetWorldPoint(_localAnchor2);
+ Vec2 d = p2 - p1;
+ Vec2 axis = b1.GetWorldVector(_localXAxis1);
+
+ float translation = Vec2.Dot(d, axis);
+ return translation;
+ }
+
+ /// <summary>
+ /// Get the current joint translation speed, usually in meters per second.
+ /// </summary>
+ public float GetJointSpeed()
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Box2DX.Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DX.Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+ Vec2 p1 = b1._sweep.C + r1;
+ Vec2 p2 = b2._sweep.C + r2;
+ Vec2 d = p2 - p1;
+ Vec2 axis = b1.GetWorldVector(_localXAxis1);
+
+ Vec2 v1 = b1._linearVelocity;
+ Vec2 v2 = b2._linearVelocity;
+ float w1 = b1._angularVelocity;
+ float w2 = b2._angularVelocity;
+
+ float speed = Vec2.Dot(d, Vec2.Cross(w1, axis)) + Vec2.Dot(axis, v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1));
+ return speed;
+ }
+
+ /// <summary>
+ /// Is the joint limit enabled?
+ /// </summary>
+ public bool IsLimitEnabled()
+ {
+ return _enableLimit;
+ }
+
+ /// <summary>
+ /// Enable/disable the joint limit.
+ /// </summary>
+ public void EnableLimit(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableLimit = flag;
+ }
+
+ /// <summary>
+ /// Get the lower joint limit, usually in meters.
+ /// </summary>
+ public float GetLowerLimit()
+ {
+ return _lowerTranslation;
+ }
+
+ /// <summary>
+ /// Get the upper joint limit, usually in meters.
+ /// </summary>
+ public float GetUpperLimit()
+ {
+ return _upperTranslation;
+ }
+
+ /// <summary>
+ /// Set the joint limits, usually in meters.
+ /// </summary>
+ public void SetLimits(float lower, float upper)
+ {
+ Box2DXDebug.Assert(lower <= upper);
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _lowerTranslation = lower;
+ _upperTranslation = upper;
+ }
+
+ /// <summary>
+ /// Is the joint motor enabled?
+ /// </summary>
+ public bool IsMotorEnabled()
+ {
+ return _enableMotor;
+ }
+
+ /// <summary>
+ /// Enable/disable the joint motor.
+ /// </summary>
+ public void EnableMotor(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableMotor = flag;
+ }
+
+ /// <summary>
+ /// Set the motor speed, usually in meters per second.
+ /// </summary>
+ public void SetMotorSpeed(float speed)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _motorSpeed = speed;
+ }
+
+ /// <summary>
+ /// Set the maximum motor force, usually in N.
+ /// </summary>
+ public void SetMaxMotorForce(float force)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _maxMotorForce = Settings.FORCE_SCALE(1.0f) * force;
+ }
+
+ /// <summary>
+ /// Get the current motor force, usually in N.
+ /// </summary>
+ public float GetMotorForce()
+ {
+ return _motorImpulse;
+ }
+
+ /// <summary>
+ /// Get the motor speed, usually in meters per second.
+ /// </summary>
+ public float GetMotorSpeed()
+ {
+ return _motorSpeed;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ _localCenter1 = b1.GetLocalCenter();
+ _localCenter2 = b2.GetLocalCenter();
+
+ XForm xf1 = b1.GetXForm();
+ XForm xf2 = b2.GetXForm();
+
+ // Compute the effective masses.
+ Vec2 r1 = Box2DX.Common.Math.Mul(xf1.R, _localAnchor1 - _localCenter1);
+ Vec2 r2 = Box2DX.Common.Math.Mul(xf2.R, _localAnchor2 - _localCenter2);
+ Vec2 d = b2._sweep.C + r2 - b1._sweep.C - r1;
+
+ _invMass1 = b1._invMass;
+ _invI1 = b1._invI;
+ _invMass2 = b2._invMass;
+ _invI2 = b2._invI;
+
+ // Compute motor Jacobian and effective mass.
+ {
+ _axis = Box2DX.Common.Math.Mul(xf1.R, _localXAxis1);
+ _a1 = Vec2.Cross(d + r1, _axis);
+ _a2 = Vec2.Cross(r2, _axis);
+
+ _motorMass = _invMass1 + _invMass2 + _invI1 * _a1 * _a1 + _invI2 * _a2 * _a2;
+ Box2DXDebug.Assert(_motorMass > Settings.FLT_EPSILON);
+ _motorMass = 1.0f / _motorMass;
+ }
+
+ // Prismatic constraint.
+ {
+ _perp = Box2DX.Common.Math.Mul(xf1.R, _localYAxis1);
+
+ _s1 = Vec2.Cross(d + r1, _perp);
+ _s2 = Vec2.Cross(r2, _perp);
+
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+ float k12 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
+ float k22 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
+
+ _K.Col1.Set(k11, k12);
+ _K.Col2.Set(k12, k22);
+ }
+
+ // Compute motor and limit terms.
+ if (_enableLimit)
+ {
+ float jointTranslation = Vec2.Dot(_axis, d);
+ if (Box2DX.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
+ {
+ _limitState = LimitState.EqualLimits;
+ }
+ else if (jointTranslation <= _lowerTranslation)
+ {
+ if (_limitState != LimitState.AtLowerLimit)
+ {
+ _limitState = LimitState.AtLowerLimit;
+ _impulse.Y = 0.0f;
+ }
+ }
+ else if (jointTranslation >= _upperTranslation)
+ {
+ if (_limitState != LimitState.AtUpperLimit)
+ {
+ _limitState = LimitState.AtUpperLimit;
+ _impulse.Y = 0.0f;
+ }
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ _impulse.Y = 0.0f;
+ }
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ }
+
+ if (_enableMotor == false)
+ {
+ _motorImpulse = 0.0f;
+ }
+
+ if (step.WarmStarting)
+ {
+ // Account for variable time step.
+ _impulse *= step.DtRatio;
+ _motorImpulse *= step.DtRatio;
+
+ Vec2 P = _impulse.X * _perp + (_motorImpulse + _impulse.Y) * _axis;
+ float L1 = _impulse.X * _s1 + (_motorImpulse + _impulse.Y) * _a1;
+ float L2 = _impulse.X * _s2 + (_motorImpulse + _impulse.Y) * _a2;
+
+ b1._linearVelocity -= _invMass1 * P;
+ b1._angularVelocity -= _invI1 * L1;
+
+ b2._linearVelocity += _invMass2 * P;
+ b2._angularVelocity += _invI2 * L2;
+ }
+ else
+ {
+ _impulse.SetZero();
+ _motorImpulse = 0.0f;
+ }
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 v1 = b1._linearVelocity;
+ float w1 = b1._angularVelocity;
+ Vec2 v2 = b2._linearVelocity;
+ float w2 = b2._angularVelocity;
+
+ // Solve linear motor constraint.
+ if (_enableMotor && _limitState != LimitState.EqualLimits)
+ {
+ float Cdot = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
+ float impulse = _motorMass * (_motorSpeed - Cdot);
+ float oldImpulse = _motorImpulse;
+ float maxImpulse = step.Dt * _maxMotorForce;
+ _motorImpulse = Box2DX.Common.Math.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = _motorImpulse - oldImpulse;
+
+ Vec2 P = impulse * _axis;
+ float L1 = impulse * _a1;
+ float L2 = impulse * _a2;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+
+ float Cdot1 = Vec2.Dot(_perp, v2 - v1) + _s2 * w2 - _s1 * w1;
+
+ if (_enableLimit && _limitState != LimitState.InactiveLimit)
+ {
+ // Solve prismatic and limit constraint in block form.
+ float Cdot2 = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
+ Vec2 Cdot = new Vec2(Cdot1, Cdot2);
+
+ Vec2 f1 = _impulse;
+ Vec2 df = _K.Solve(-Cdot);
+ _impulse += df;
+
+ if (_limitState == LimitState.AtLowerLimit)
+ {
+ _impulse.Y = Box2DX.Common.Math.Max(_impulse.Y, 0.0f);
+ }
+ else if (_limitState == LimitState.AtUpperLimit)
+ {
+ _impulse.Y = Box2DX.Common.Math.Min(_impulse.Y, 0.0f);
+ }
+
+ // f2(1) = invK(1,1) * (-Cdot(1) - K(1,2) * (f2(2) - f1(2))) + f1(1)
+ float b = -Cdot1 - (_impulse.Y - f1.Y) * _K.Col2.X;
+ float f2r = b / _K.Col1.X + f1.X;
+ _impulse.X = f2r;
+
+ df = _impulse - f1;
+
+ Vec2 P = df.X * _perp + df.Y * _axis;
+ float L1 = df.X * _s1 + df.Y * _a1;
+ float L2 = df.X * _s2 + df.Y * _a2;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+ else
+ {
+ // Limit is inactive, just solve the prismatic constraint in block form.
+ float df = (-Cdot1) / _K.Col1.X;
+ _impulse.X += df;
+
+ Vec2 P = df * _perp;
+ float L1 = df * _s1;
+ float L2 = df * _s2;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+
+ b1._linearVelocity = v1;
+ b1._angularVelocity = w1;
+ b2._linearVelocity = v2;
+ b2._angularVelocity = w2;
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 c1 = b1._sweep.C;
+ float a1 = b1._sweep.A;
+
+ Vec2 c2 = b2._sweep.C;
+ float a2 = b2._sweep.A;
+
+ // Solve linear limit constraint.
+ float linearError = 0.0f, angularError = 0.0f;
+ bool active = false;
+ float C2 = 0.0f;
+
+ Mat22 R1 = new Mat22(a1), R2 = new Mat22(a2);
+
+ Vec2 r1 = Box2DX.Common.Math.Mul(R1, _localAnchor1 - _localCenter1);
+ Vec2 r2 = Box2DX.Common.Math.Mul(R2, _localAnchor2 - _localCenter2);
+ Vec2 d = c2 + r2 - c1 - r1;
+
+ if (_enableLimit)
+ {
+ _axis = Box2DX.Common.Math.Mul(R1, _localXAxis1);
+
+ _a1 = Vec2.Cross(d + r1, _axis);
+ _a2 = Vec2.Cross(r2, _axis);
+
+ float translation = Vec2.Dot(_axis, d);
+ if (Box2DX.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
+ {
+ // Prevent large angular corrections
+ C2 = Box2DX.Common.Math.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
+ linearError = Box2DX.Common.Math.Abs(translation);
+ active = true;
+ }
+ else if (translation <= _lowerTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = Box2DX.Common.Math.Clamp(translation - _lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+ linearError = _lowerTranslation - translation;
+ active = true;
+ }
+ else if (translation >= _upperTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = Box2DX.Common.Math.Clamp(translation - _upperTranslation - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection);
+ linearError = translation - _upperTranslation;
+ active = true;
+ }
+ }
+
+ _perp = Box2DX.Common.Math.Mul(R1, _localYAxis1);
+
+ _s1 = Vec2.Cross(d + r1, _perp);
+ _s2 = Vec2.Cross(r2, _perp);
+
+ Vec2 impulse;
+ float C1;
+ C1 = Vec2.Dot(_perp, d);
+
+ linearError = Box2DX.Common.Math.Max(linearError, Box2DX.Common.Math.Abs(C1));
+ angularError = 0.0f;
+
+ if (active)
+ {
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+ float k12 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
+ float k22 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
+
+ _K.Col1.Set(k11, k12);
+ _K.Col2.Set(k12, k22);
+
+ Vec2 C = new Vec2();
+ C.X = C1;
+ C.Y = C2;
+
+ impulse = _K.Solve(-C);
+ }
+ else
+ {
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+
+ float impulse1 = (-C1) / k11;
+ impulse.X = impulse1;
+ impulse.Y = 0.0f;
+ }
+
+ Vec2 P = impulse.X * _perp + impulse.Y * _axis;
+ float L1 = impulse.X * _s1 + impulse.Y * _a1;
+ float L2 = impulse.X * _s2 + impulse.Y * _a2;
+
+ c1 -= _invMass1 * P;
+ a1 -= _invI1 * L1;
+ c2 += _invMass2 * P;
+ a2 += _invI2 * L2;
+
+ // TODO_ERIN remove need for this.
+ b1._sweep.C = c1;
+ b1._sweep.A = a1;
+ b2._sweep.C = c2;
+ b2._sweep.A = a2;
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+
+ return linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;
+ }
+ }
+} \ No newline at end of file
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs.meta
new file mode 100644
index 0000000..f649ab4
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/LineJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 9817f1297db25b14d95b7c32530a3af6
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs
new file mode 100644
index 0000000..19eb83c
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs
@@ -0,0 +1,229 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// p = attached point, m = mouse point
+// C = p - m
+// Cdot = v
+// = v + cross(w, r)
+// J = [I r_skew]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// Mouse joint definition. This requires a world target point,
+ /// tuning parameters, and the time step.
+ /// </summary>
+ public class MouseJointDef : JointDef
+ {
+ public MouseJointDef()
+ {
+ Type = JointType.MouseJoint;
+ Target.Set(0.0f, 0.0f);
+ MaxForce = 0.0f;
+ FrequencyHz = 5.0f;
+ DampingRatio = 0.7f;
+ }
+
+ /// <summary>
+ /// The initial world target point. This is assumed
+ /// to coincide with the body anchor initially.
+ /// </summary>
+ public Vec2 Target;
+
+ /// <summary>
+ /// The maximum constraint force that can be exerted
+ /// to move the candidate body. Usually you will express
+ /// as some multiple of the weight (multiplier * mass * gravity).
+ /// </summary>
+ public float MaxForce;
+
+ /// <summary>
+ /// The response speed.
+ /// </summary>
+ public float FrequencyHz;
+
+ /// <summary>
+ /// The damping ratio. 0 = no damping, 1 = critical damping.
+ /// </summary>
+ public float DampingRatio;
+ }
+
+ /// <summary>
+ /// A mouse joint is used to make a point on a body track a
+ /// specified world point. This a soft constraint with a maximum
+ /// force. This allows the constraint to stretch and without
+ /// applying huge forces.
+ /// </summary>
+ public class MouseJoint : Joint
+ {
+ public Vec2 _localAnchor;
+ public Vec2 _target;
+ public Vec2 _impulse;
+
+ public Mat22 _mass; // effective mass for point-to-point constraint.
+ public Vec2 _C; // position error
+ public float _maxForce;
+ public float _frequencyHz;
+ public float _dampingRatio;
+ public float _beta;
+ public float _gamma;
+
+ public override Vec2 Anchor1
+ {
+ get { return _target; }
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor); }
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ return inv_dt * _impulse;
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return inv_dt * 0.0f;
+ }
+
+ /// <summary>
+ /// Use this to update the target point.
+ /// </summary>
+ public void SetTarget(Vec2 target)
+ {
+ if (_body2.IsSleeping())
+ {
+ _body2.WakeUp();
+ }
+ _target = target;
+ }
+
+ public MouseJoint(MouseJointDef def)
+ : base(def)
+ {
+ _target = def.Target;
+ _localAnchor = Common.Math.MulT(_body2.GetXForm(), _target);
+
+ _maxForce = def.MaxForce;
+ _impulse.SetZero();
+
+ _frequencyHz = def.FrequencyHz;
+ _dampingRatio = def.DampingRatio;
+
+ _beta = 0.0f;
+ _gamma = 0.0f;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b = _body2;
+
+ float mass = b.GetMass();
+
+ // Frequency
+ float omega = 2.0f * Settings.Pi * _frequencyHz;
+
+ // Damping coefficient
+ float d = 2.0f * mass * _dampingRatio * omega;
+
+ // Spring stiffness
+ float k = mass * (omega * omega);
+
+ // magic formulas
+ // gamma has units of inverse mass.
+ // beta has units of inverse time.
+ Box2DXDebug.Assert(d + step.Dt * k > Settings.FLT_EPSILON);
+ _gamma = 1.0f / (step.Dt * (d + step.Dt * k));
+ _beta = step.Dt * k * _gamma;
+
+ // Compute the effective mass matrix.
+ Vec2 r = Common.Math.Mul(b.GetXForm().R, _localAnchor - b.GetLocalCenter());
+
+ // 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]
+ float invMass = b._invMass;
+ float invI = b._invI;
+
+ Mat22 K1 = new Mat22();
+ K1.Col1.X = invMass; K1.Col2.X = 0.0f;
+ K1.Col1.Y = 0.0f; K1.Col2.Y = invMass;
+
+ Mat22 K2 = new Mat22();
+ K2.Col1.X = invI * r.Y * r.Y; K2.Col2.X = -invI * r.X * r.Y;
+ K2.Col1.Y = -invI * r.X * r.Y; K2.Col2.Y = invI * r.X * r.X;
+
+ Mat22 K = K1 + K2;
+ K.Col1.X += _gamma;
+ K.Col2.Y += _gamma;
+
+ _mass = K.GetInverse();
+
+ _C = b._sweep.C + r - _target;
+
+ // Cheat with some damping
+ b._angularVelocity *= 0.98f;
+
+ // Warm starting.
+ _impulse *= step.DtRatio;
+ b._linearVelocity += invMass * _impulse;
+ b._angularVelocity += invI * Vec2.Cross(r, _impulse);
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b = _body2;
+
+ Vec2 r = Common.Math.Mul(b.GetXForm().R, _localAnchor - b.GetLocalCenter());
+
+ // Cdot = v + cross(w, r)
+ Vec2 Cdot = b._linearVelocity + Vec2.Cross(b._angularVelocity, r);
+ Vec2 impulse = Box2DX.Common.Math.Mul(_mass, -(Cdot + _beta * _C + _gamma * _impulse));
+
+ Vec2 oldImpulse = _impulse;
+ _impulse += impulse;
+ float maxImpulse = step.Dt * _maxForce;
+ if (_impulse.LengthSquared() > maxImpulse * maxImpulse)
+ {
+ _impulse *= maxImpulse / _impulse.Length();
+ }
+ impulse = _impulse - oldImpulse;
+
+ b._linearVelocity += b._invMass * impulse;
+ b._angularVelocity += b._invI * Vec2.Cross(r, impulse);
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ return true;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs.meta
new file mode 100644
index 0000000..6b7075b
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/MouseJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 64a51a39bb7cd3f48b12a72161bd3199
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs
new file mode 100644
index 0000000..c6ee2cf
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs
@@ -0,0 +1,756 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Linear constraint (point-to-line)
+// d = p2 - p1 = x2 + r2 - x1 - r1
+// C = dot(perp, d)
+// Cdot = dot(d, cross(w1, perp)) + dot(perp, v2 + cross(w2, r2) - v1 - cross(w1, r1))
+// = -dot(perp, v1) - dot(cross(d + r1, perp), w1) + dot(perp, v2) + dot(cross(r2, perp), v2)
+// J = [-perp, -cross(d + r1, perp), perp, cross(r2,perp)]
+//
+// Angular constraint
+// C = a2 - a1 + a_initial
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+//
+// K = J * invM * JT
+//
+// J = [-a -s1 a s2]
+// [0 -1 0 1]
+// a = perp
+// s1 = cross(d + r1, a) = cross(p2 - x1, a)
+// s2 = cross(r2, a) = cross(p2 - x2, a)
+
+
+// Motor/Limit linear constraint
+// C = dot(ax1, d)
+// Cdot = = -dot(ax1, v1) - dot(cross(d + r1, ax1), w1) + dot(ax1, v2) + dot(cross(r2, ax1), v2)
+// J = [-ax1 -cross(d+r1,ax1) ax1 cross(r2,ax1)]
+
+// Block Solver
+// We develop a block solver that includes the joint limit. This makes the limit stiff (inelastic) even
+// when the mass has poor distribution (leading to large torques about the joint anchor points).
+//
+// The Jacobian has 3 rows:
+// J = [-uT -s1 uT s2] // linear
+// [0 -1 0 1] // angular
+// [-vT -a1 vT a2] // limit
+//
+// u = perp
+// v = axis
+// s1 = cross(d + r1, u), s2 = cross(r2, u)
+// a1 = cross(d + r1, v), a2 = cross(r2, v)
+
+// M * (v2 - v1) = JT * df
+// J * v2 = bias
+//
+// v2 = v1 + invM * JT * df
+// J * (v1 + invM * JT * df) = bias
+// K * df = bias - J * v1 = -Cdot
+// K = J * invM * JT
+// Cdot = J * v1 - bias
+//
+// Now solve for f2.
+// df = f2 - f1
+// K * (f2 - f1) = -Cdot
+// f2 = invK * (-Cdot) + f1
+//
+// Clamp accumulated limit impulse.
+// lower: f2(3) = max(f2(3), 0)
+// upper: f2(3) = min(f2(3), 0)
+//
+// Solve for correct f2(1:2)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:3) * f1
+// = -Cdot(1:2) - K(1:2,3) * f2(3) + K(1:2,1:2) * f1(1:2) + K(1:2,3) * f1(3)
+// K(1:2, 1:2) * f2(1:2) = -Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3)) + K(1:2,1:2) * f1(1:2)
+// f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+//
+// Now compute impulse to be applied:
+// df = f2 - f1
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ using Box2DXMath = Box2DX.Common.Math;
+ using SystemMath = System.Math;
+
+ /// <summary>
+ /// Prismatic joint definition. This requires defining a line of
+ /// motion using an axis and an anchor point. The definition uses local
+ /// anchor points and a local axis so that the initial configuration
+ /// can violate the constraint slightly. The joint translation is zero
+ /// when the local anchor points coincide in world space. Using local
+ /// anchors and a local axis helps when saving and loading a game.
+ /// </summary>
+ public class PrismaticJointDef : JointDef
+ {
+ public PrismaticJointDef()
+ {
+ Type = JointType.PrismaticJoint;
+ LocalAnchor1.SetZero();
+ LocalAnchor2.SetZero();
+ LocalAxis1.Set(1.0f, 0.0f);
+ ReferenceAngle = 0.0f;
+ EnableLimit = false;
+ LowerTranslation = 0.0f;
+ UpperTranslation = 0.0f;
+ EnableMotor = false;
+ MaxMotorForce = 0.0f;
+ MotorSpeed = 0.0f;
+ }
+
+ /// <summary>
+ /// Initialize the bodies, anchors, axis, and reference angle using the world
+ /// anchor and world axis.
+ /// </summary>
+ public void Initialize(Body body1, Body body2, Vec2 anchor, Vec2 axis)
+ {
+ Body1 = body1;
+ Body2 = body2;
+ LocalAnchor1 = body1.GetLocalPoint(anchor);
+ LocalAnchor2 = body2.GetLocalPoint(anchor);
+ LocalAxis1 = body1.GetLocalVector(axis);
+ ReferenceAngle = body2.GetAngle() - body1.GetAngle();
+ }
+
+ /// <summary>
+ /// The local anchor point relative to body1's origin.
+ /// </summary>
+ public Vec2 LocalAnchor1;
+
+ /// <summary>
+ /// The local anchor point relative to body2's origin.
+ /// </summary>
+ public Vec2 LocalAnchor2;
+
+ /// <summary>
+ /// The local translation axis in body1.
+ /// </summary>
+ public Vec2 LocalAxis1;
+
+ /// <summary>
+ /// The constrained angle between the bodies: body2_angle - body1_angle.
+ /// </summary>
+ public float ReferenceAngle;
+
+ /// <summary>
+ /// Enable/disable the joint limit.
+ /// </summary>
+ public bool EnableLimit;
+
+ /// <summary>
+ /// The lower translation limit, usually in meters.
+ /// </summary>
+ public float LowerTranslation;
+
+ /// <summary>
+ /// The upper translation limit, usually in meters.
+ /// </summary>
+ public float UpperTranslation;
+
+ /// <summary>
+ /// Enable/disable the joint motor.
+ /// </summary>
+ public bool EnableMotor;
+
+ /// <summary>
+ /// The maximum motor torque, usually in N-m.
+ /// </summary>
+ public float MaxMotorForce;
+
+ /// <summary>
+ /// The desired motor speed in radians per second.
+ /// </summary>
+ public float MotorSpeed;
+ }
+
+ /// <summary>
+ /// A prismatic joint. This joint provides one degree of freedom: translation
+ /// along an axis fixed in body1. Relative rotation is prevented. You can
+ /// use a joint limit to restrict the range of motion and a joint motor to
+ /// drive the motion or to model joint friction.
+ /// </summary>
+ public class PrismaticJoint : Joint
+ {
+ public Vec2 _localAnchor1;
+ public Vec2 _localAnchor2;
+ public Vec2 _localXAxis1;
+ public Vec2 _localYAxis1;
+ public float _refAngle;
+
+ public Vec2 _axis, _perp;
+ public float _s1, _s2;
+ public float _a1, _a2;
+
+ public Mat33 _K;
+ public Vec3 _impulse;
+
+ public float _motorMass; // effective mass for motor/limit translational constraint.
+ public float _motorImpulse;
+
+ public float _lowerTranslation;
+ public float _upperTranslation;
+ public float _maxMotorForce;
+ public float _motorSpeed;
+
+ public bool _enableLimit;
+ public bool _enableMotor;
+ public LimitState _limitState;
+
+ public override Vec2 Anchor1
+ {
+ get { return _body1.GetWorldPoint(_localAnchor1); }
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor2); }
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ return inv_dt * (_impulse.X * _perp + (_motorImpulse + _impulse.Z) * _axis);
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return inv_dt * _impulse.Y;
+ }
+
+ /// <summary>
+ /// Get the current joint translation, usually in meters.
+ /// </summary>
+ public float JointTranslation
+ {
+ get
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 p1 = b1.GetWorldPoint(_localAnchor1);
+ Vec2 p2 = b2.GetWorldPoint(_localAnchor2);
+ Vec2 d = p2 - p1;
+ Vec2 axis = b1.GetWorldVector(_localXAxis1);
+
+ float translation = Vec2.Dot(d, axis);
+ return translation;
+ }
+ }
+
+ /// <summary>
+ /// Get the current joint translation speed, usually in meters per second.
+ /// </summary>
+ public float JointSpeed
+ {
+ get
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Common.Math.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Common.Math.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+ Vec2 p1 = b1._sweep.C + r1;
+ Vec2 p2 = b2._sweep.C + r2;
+ Vec2 d = p2 - p1;
+ Vec2 axis = b1.GetWorldVector(_localXAxis1);
+
+ Vec2 v1 = b1._linearVelocity;
+ Vec2 v2 = b2._linearVelocity;
+ float w1 = b1._angularVelocity;
+ float w2 = b2._angularVelocity;
+
+ float speed = Vec2.Dot(d, Vec2.Cross(w1, axis)) + Vec2.Dot(axis, v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1));
+ return speed;
+ }
+ }
+
+ /// <summary>
+ /// Is the joint limit enabled?
+ /// </summary>
+ public bool IsLimitEnabled
+ {
+ get { return _enableLimit; }
+ }
+
+ /// <summary>
+ /// Enable/disable the joint limit.
+ /// </summary>
+ public void EnableLimit(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableLimit = flag;
+ }
+
+ /// <summary>
+ /// Get the lower joint limit, usually in meters.
+ /// </summary>
+ public float LowerLimit
+ {
+ get { return _lowerTranslation; }
+ }
+
+ /// <summary>
+ /// Get the upper joint limit, usually in meters.
+ /// </summary>
+ public float UpperLimit
+ {
+ get { return _upperTranslation; }
+ }
+
+ /// <summary>
+ /// Set the joint limits, usually in meters.
+ /// </summary>
+ public void SetLimits(float lower, float upper)
+ {
+ Box2DXDebug.Assert(lower <= upper);
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _lowerTranslation = lower;
+ _upperTranslation = upper;
+ }
+
+ /// <summary>
+ /// Is the joint motor enabled?
+ /// </summary>
+ public bool IsMotorEnabled
+ {
+ get { return _enableMotor; }
+ }
+
+ /// <summary>
+ /// Enable/disable the joint motor.
+ /// </summary>
+ public void EnableMotor(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableMotor = flag;
+ }
+
+ /// <summary>
+ /// Get\Set the motor speed, usually in meters per second.
+ /// </summary>
+ public float MotorSpeed
+ {
+ get { return _motorSpeed; }
+ set
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _motorSpeed = value;
+ }
+ }
+
+ /// <summary>
+ /// Set the maximum motor force, usually in N.
+ /// </summary>
+ public void SetMaxMotorForce(float force)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _maxMotorForce = Settings.FORCE_SCALE(1.0f) * force;
+ }
+
+ /// <summary>
+ /// Get the current motor force, usually in N.
+ /// </summary>
+ public float MotorForce
+ {
+ get { return _motorImpulse; }
+ }
+
+ public PrismaticJoint(PrismaticJointDef def)
+ : base(def)
+ {
+ _localAnchor1 = def.LocalAnchor1;
+ _localAnchor2 = def.LocalAnchor2;
+ _localXAxis1 = def.LocalAxis1;
+ _localYAxis1 = Vec2.Cross(1.0f, _localXAxis1);
+ _refAngle = def.ReferenceAngle;
+
+ _impulse.SetZero();
+ _motorMass = 0.0f;
+ _motorImpulse = 0.0f;
+
+ _lowerTranslation = def.LowerTranslation;
+ _upperTranslation = def.UpperTranslation;
+ _maxMotorForce = Settings.FORCE_INV_SCALE(def.MaxMotorForce);
+ _motorSpeed = def.MotorSpeed;
+ _enableLimit = def.EnableLimit;
+ _enableMotor = def.EnableMotor;
+ _limitState = LimitState.InactiveLimit;
+
+ _axis.SetZero();
+ _perp.SetZero();
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ // You cannot create a prismatic joint between bodies that
+ // both have fixed rotation.
+ Box2DXDebug.Assert(b1._invI > 0.0f || b2._invI > 0.0f);
+
+ _localCenter1 = b1.GetLocalCenter();
+ _localCenter2 = b2.GetLocalCenter();
+
+ XForm xf1 = b1.GetXForm();
+ XForm xf2 = b2.GetXForm();
+
+ // Compute the effective masses.
+ Vec2 r1 = Box2DX.Common.Math.Mul(xf1.R, _localAnchor1 - _localCenter1);
+ Vec2 r2 = Box2DX.Common.Math.Mul(xf2.R, _localAnchor2 - _localCenter2);
+ Vec2 d = b2._sweep.C + r2 - b1._sweep.C - r1;
+
+ _invMass1 = b1._invMass;
+ _invI1 = b1._invI;
+ _invMass2 = b2._invMass;
+ _invI2 = b2._invI;
+
+ // Compute motor Jacobian and effective mass.
+ {
+ _axis = Box2DX.Common.Math.Mul(xf1.R, _localXAxis1);
+ _a1 = Vec2.Cross(d + r1, _axis);
+ _a2 = Vec2.Cross(r2, _axis);
+
+ _motorMass = _invMass1 + _invMass2 + _invI1 * _a1 * _a1 + _invI2 * _a2 * _a2;
+ Box2DXDebug.Assert(_motorMass > Settings.FLT_EPSILON);
+ _motorMass = 1.0f / _motorMass;
+ }
+
+ // Prismatic constraint.
+ {
+ _perp = Box2DX.Common.Math.Mul(xf1.R, _localYAxis1);
+
+ _s1 = Vec2.Cross(d + r1, _perp);
+ _s2 = Vec2.Cross(r2, _perp);
+
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+ float k12 = i1 * _s1 + i2 * _s2;
+ float k13 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
+ float k22 = i1 + i2;
+ float k23 = i1 * _a1 + i2 * _a2;
+ float k33 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
+
+ _K.Col1.Set(k11, k12, k13);
+ _K.Col2.Set(k12, k22, k23);
+ _K.Col3.Set(k13, k23, k33);
+ }
+
+ // Compute motor and limit terms.
+ if (_enableLimit)
+ {
+ float jointTranslation = Vec2.Dot(_axis, d);
+ if (Box2DX.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
+ {
+ _limitState = LimitState.EqualLimits;
+ }
+ else if (jointTranslation <= _lowerTranslation)
+ {
+ if (_limitState != LimitState.AtLowerLimit)
+ {
+ _limitState = LimitState.AtLowerLimit;
+ _impulse.Z = 0.0f;
+ }
+ }
+ else if (jointTranslation >= _upperTranslation)
+ {
+ if (_limitState != LimitState.AtUpperLimit)
+ {
+ _limitState = LimitState.AtUpperLimit;
+ _impulse.Z = 0.0f;
+ }
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ _impulse.Z = 0.0f;
+ }
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ }
+
+ if (_enableMotor == false)
+ {
+ _motorImpulse = 0.0f;
+ }
+
+ if (step.WarmStarting)
+ {
+ // Account for variable time step.
+ _impulse *= step.DtRatio;
+ _motorImpulse *= step.DtRatio;
+
+ Vec2 P = _impulse.X * _perp + (_motorImpulse + _impulse.Z) * _axis;
+ float L1 = _impulse.X * _s1 + _impulse.Y + (_motorImpulse + _impulse.Z) * _a1;
+ float L2 = _impulse.X * _s2 + _impulse.Y + (_motorImpulse + _impulse.Z) * _a2;
+
+ b1._linearVelocity -= _invMass1 * P;
+ b1._angularVelocity -= _invI1 * L1;
+
+ b2._linearVelocity += _invMass2 * P;
+ b2._angularVelocity += _invI2 * L2;
+ }
+ else
+ {
+ _impulse.SetZero();
+ _motorImpulse = 0.0f;
+ }
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 v1 = b1._linearVelocity;
+ float w1 = b1._angularVelocity;
+ Vec2 v2 = b2._linearVelocity;
+ float w2 = b2._angularVelocity;
+
+ // Solve linear motor constraint.
+ if (_enableMotor && _limitState != LimitState.EqualLimits)
+ {
+ float Cdot = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
+ float impulse = _motorMass * (_motorSpeed - Cdot);
+ float oldImpulse = _motorImpulse;
+ float maxImpulse = step.Dt * _maxMotorForce;
+ _motorImpulse = Box2DX.Common.Math.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = _motorImpulse - oldImpulse;
+
+ Vec2 P = impulse * _axis;
+ float L1 = impulse * _a1;
+ float L2 = impulse * _a2;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+
+ Vec2 Cdot1;
+ Cdot1.X = Vec2.Dot(_perp, v2 - v1) + _s2 * w2 - _s1 * w1;
+ Cdot1.Y = w2 - w1;
+
+ if (_enableLimit && _limitState != LimitState.InactiveLimit)
+ {
+ // Solve prismatic and limit constraint in block form.
+ float Cdot2;
+ Cdot2 = Vec2.Dot(_axis, v2 - v1) + _a2 * w2 - _a1 * w1;
+ Vec3 Cdot = new Vec3(Cdot1.X, Cdot1.Y, Cdot2);
+
+ Vec3 f1 = _impulse;
+ Vec3 df = _K.Solve33(-Cdot);
+ _impulse += df;
+
+ if (_limitState ==LimitState.AtLowerLimit)
+ {
+ _impulse.Z = Box2DX.Common.Math.Max(_impulse.Z, 0.0f);
+ }
+ else if (_limitState == LimitState.AtUpperLimit)
+ {
+ _impulse.Z = Box2DX.Common.Math.Min(_impulse.Z, 0.0f);
+ }
+
+ // f2(1:2) = invK(1:2,1:2) * (-Cdot(1:2) - K(1:2,3) * (f2(3) - f1(3))) + f1(1:2)
+ Vec2 b = -Cdot1 - (_impulse.Z - f1.Z) * new Vec2(_K.Col3.X, _K.Col3.Y);
+ Vec2 f2r = _K.Solve22(b) + new Vec2(f1.X, f1.Y);
+ _impulse.X = f2r.X;
+ _impulse.Y = f2r.Y;
+
+ df = _impulse - f1;
+
+ Vec2 P = df.X * _perp + df.Z * _axis;
+ float L1 = df.X * _s1 + df.Y + df.Z * _a1;
+ float L2 = df.X * _s2 + df.Y + df.Z * _a2;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+ else
+ {
+ // Limit is inactive, just solve the prismatic constraint in block form.
+ Vec2 df = _K.Solve22(-Cdot1);
+ _impulse.X += df.X;
+ _impulse.Y += df.Y;
+
+ Vec2 P = df.X * _perp;
+ float L1 = df.X * _s1 + df.Y;
+ float L2 = df.X * _s2 + df.Y;
+
+ v1 -= _invMass1 * P;
+ w1 -= _invI1 * L1;
+
+ v2 += _invMass2 * P;
+ w2 += _invI2 * L2;
+ }
+
+ b1._linearVelocity = v1;
+ b1._angularVelocity = w1;
+ b2._linearVelocity = v2;
+ b2._angularVelocity = w2;
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 c1 = b1._sweep.C;
+ float a1 = b1._sweep.A;
+
+ Vec2 c2 = b2._sweep.C;
+ float a2 = b2._sweep.A;
+
+ // Solve linear limit constraint.
+ float linearError = 0.0f, angularError = 0.0f;
+ bool active = false;
+ float C2 = 0.0f;
+
+ Mat22 R1 = new Mat22(a1), R2 = new Mat22(a2);
+
+ Vec2 r1 = Box2DX.Common.Math.Mul(R1, _localAnchor1 - _localCenter1);
+ Vec2 r2 = Box2DX.Common.Math.Mul(R2, _localAnchor2 - _localCenter2);
+ Vec2 d = c2 + r2 - c1 - r1;
+
+ if (_enableLimit)
+ {
+ _axis = Box2DX.Common.Math.Mul(R1, _localXAxis1);
+
+ _a1 = Vec2.Cross(d + r1, _axis);
+ _a2 = Vec2.Cross(r2, _axis);
+
+ float translation = Vec2.Dot(_axis, d);
+ if (Box2DX.Common.Math.Abs(_upperTranslation - _lowerTranslation) < 2.0f * Settings.LinearSlop)
+ {
+ // Prevent large angular corrections
+ C2 = Box2DX.Common.Math.Clamp(translation, -Settings.MaxLinearCorrection, Settings.MaxLinearCorrection);
+ linearError = Box2DX.Common.Math.Abs(translation);
+ active = true;
+ }
+ else if (translation <= _lowerTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = Box2DX.Common.Math.Clamp(translation - _lowerTranslation + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+ linearError = _lowerTranslation - translation;
+ active = true;
+ }
+ else if (translation >= _upperTranslation)
+ {
+ // Prevent large linear corrections and allow some slop.
+ C2 = Box2DX.Common.Math.Clamp(translation - _upperTranslation - Settings.LinearSlop, 0.0f, Settings.MaxLinearCorrection);
+ linearError = translation - _upperTranslation;
+ active = true;
+ }
+ }
+
+ _perp = Box2DX.Common.Math.Mul(R1, _localYAxis1);
+
+ _s1 = Vec2.Cross(d + r1, _perp);
+ _s2 = Vec2.Cross(r2, _perp);
+
+ Vec3 impulse;
+ Vec2 C1 = new Vec2();
+ C1.X = Vec2.Dot(_perp, d);
+ C1.Y = a2 - a1 - _refAngle;
+
+ linearError = Box2DX.Common.Math.Max(linearError, Box2DX.Common.Math.Abs(C1.X));
+ angularError = Box2DX.Common.Math.Abs(C1.Y);
+
+ if (active)
+ {
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+ float k12 = i1 * _s1 + i2 * _s2;
+ float k13 = i1 * _s1 * _a1 + i2 * _s2 * _a2;
+ float k22 = i1 + i2;
+ float k23 = i1 * _a1 + i2 * _a2;
+ float k33 = m1 + m2 + i1 * _a1 * _a1 + i2 * _a2 * _a2;
+
+ _K.Col1.Set(k11, k12, k13);
+ _K.Col2.Set(k12, k22, k23);
+ _K.Col3.Set(k13, k23, k33);
+
+ Vec3 C = new Vec3();
+ C.X = C1.X;
+ C.Y = C1.Y;
+ C.Z = C2;
+
+ impulse = _K.Solve33(-C);
+ }
+ else
+ {
+ float m1 = _invMass1, m2 = _invMass2;
+ float i1 = _invI1, i2 = _invI2;
+
+ float k11 = m1 + m2 + i1 * _s1 * _s1 + i2 * _s2 * _s2;
+ float k12 = i1 * _s1 + i2 * _s2;
+ float k22 = i1 + i2;
+
+ _K.Col1.Set(k11, k12, 0.0f);
+ _K.Col2.Set(k12, k22, 0.0f);
+
+ Vec2 impulse1 = _K.Solve22(-C1);
+ impulse.X = impulse1.X;
+ impulse.Y = impulse1.Y;
+ impulse.Z = 0.0f;
+ }
+
+ Vec2 P = impulse.X * _perp + impulse.Z * _axis;
+ float L1 = impulse.X * _s1 + impulse.Y + impulse.Z * _a1;
+ float L2 = impulse.X * _s2 + impulse.Y + impulse.Z * _a2;
+
+ c1 -= _invMass1 * P;
+ a1 -= _invI1 * L1;
+ c2 += _invMass2 * P;
+ a2 += _invI2 * L2;
+
+ // TODO_ERIN remove need for this.
+ b1._sweep.C = c1;
+ b1._sweep.A = a1;
+ b2._sweep.C = c2;
+ b2._sweep.A = a2;
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+
+ return linearError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs.meta
new file mode 100644
index 0000000..31fdd0e
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PrismaticJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0d3c4a5269cc639479ba35c87378787f
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs
new file mode 100644
index 0000000..ab92536
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs
@@ -0,0 +1,566 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Pulley:
+// length1 = norm(p1 - s1)
+// length2 = norm(p2 - s2)
+// C0 = (length1 + ratio * length2)_initial
+// C = C0 - (length1 + ratio * length2) >= 0
+// u1 = (p1 - s1) / norm(p1 - s1)
+// u2 = (p2 - s2) / norm(p2 - s2)
+// Cdot = -dot(u1, v1 + cross(w1, r1)) - ratio * dot(u2, v2 + cross(w2, r2))
+// J = -[u1 cross(r1, u1) ratio * u2 ratio * cross(r2, u2)]
+// K = J * invM * JT
+// = invMass1 + invI1 * cross(r1, u1)^2 + ratio^2 * (invMass2 + invI2 * cross(r2, u2)^2)
+//
+// Limit:
+// C = maxLength - length
+// u = (p - s) / norm(p - s)
+// Cdot = -dot(u, v + cross(w, r))
+// K = invMass + invI * cross(r, u)^2
+// 0 <= impulse
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ using Box2DXMath = Box2DX.Common.Math;
+ using SystemMath = System.Math;
+
+ /// <summary>
+ /// Pulley joint definition. This requires two ground anchors,
+ /// two dynamic body anchor points, max lengths for each side,
+ /// and a pulley ratio.
+ /// </summary>
+ public class PulleyJointDef : JointDef
+ {
+ public PulleyJointDef()
+ {
+ Type = JointType.PulleyJoint;
+ GroundAnchor1.Set(-1.0f, 1.0f);
+ GroundAnchor2.Set(1.0f, 1.0f);
+ LocalAnchor1.Set(-1.0f, 0.0f);
+ LocalAnchor2.Set(1.0f, 0.0f);
+ Length1 = 0.0f;
+ MaxLength1 = 0.0f;
+ Length2 = 0.0f;
+ MaxLength2 = 0.0f;
+ Ratio = 1.0f;
+ CollideConnected = true;
+ }
+
+ /// Initialize the bodies, anchors, lengths, max lengths, and ratio using the world anchors.
+ public void Initialize(Body body1, Body body2,
+ Vec2 groundAnchor1, Vec2 groundAnchor2,
+ Vec2 anchor1, Vec2 anchor2,
+ float ratio)
+ {
+ Body1 = body1;
+ Body2 = body2;
+ GroundAnchor1 = groundAnchor1;
+ GroundAnchor2 = groundAnchor2;
+ LocalAnchor1 = body1.GetLocalPoint(anchor1);
+ LocalAnchor2 = body2.GetLocalPoint(anchor2);
+ Vec2 d1 = anchor1 - groundAnchor1;
+ Length1 = d1.Length();
+ Vec2 d2 = anchor2 - groundAnchor2;
+ Length2 = d2.Length();
+ Ratio = ratio;
+ Box2DXDebug.Assert(ratio > Settings.FLT_EPSILON);
+ float C = Length1 + ratio * Length2;
+ MaxLength1 = C - ratio * PulleyJoint.MinPulleyLength;
+ MaxLength2 = (C - PulleyJoint.MinPulleyLength) / ratio;
+ }
+
+ /// <summary>
+ /// The first ground anchor in world coordinates. This point never moves.
+ /// </summary>
+ public Vec2 GroundAnchor1;
+
+ /// <summary>
+ /// The second ground anchor in world coordinates. This point never moves.
+ /// </summary>
+ public Vec2 GroundAnchor2;
+
+ /// <summary>
+ /// The local anchor point relative to body1's origin.
+ /// </summary>
+ public Vec2 LocalAnchor1;
+
+ /// <summary>
+ /// The local anchor point relative to body2's origin.
+ /// </summary>
+ public Vec2 LocalAnchor2;
+
+ /// <summary>
+ /// The a reference length for the segment attached to body1.
+ /// </summary>
+ public float Length1;
+
+ /// <summary>
+ /// The maximum length of the segment attached to body1.
+ /// </summary>
+ public float MaxLength1;
+
+ /// <summary>
+ /// The a reference length for the segment attached to body2.
+ /// </summary>
+ public float Length2;
+
+ /// <summary>
+ /// The maximum length of the segment attached to body2.
+ /// </summary>
+ public float MaxLength2;
+
+ /// <summary>
+ /// The pulley ratio, used to simulate a block-and-tackle.
+ /// </summary>
+ public float Ratio;
+ }
+
+ /// <summary>
+ /// The pulley joint is connected to two bodies and two fixed ground points.
+ /// The pulley supports a ratio such that:
+ /// length1 + ratio * length2 <= constant
+ /// Yes, the force transmitted is scaled by the ratio.
+ /// The pulley also enforces a maximum length limit on both sides. This is
+ /// useful to prevent one side of the pulley hitting the top.
+ /// </summary>
+ public class PulleyJoint : Joint
+ {
+ public static readonly float MinPulleyLength = 2.0f;
+
+ public Body _ground;
+ public Vec2 _groundAnchor1;
+ public Vec2 _groundAnchor2;
+ public Vec2 _localAnchor1;
+ public Vec2 _localAnchor2;
+
+ public Vec2 _u1;
+ public Vec2 _u2;
+
+ public float _constant;
+ public float _ratio;
+
+ public float _maxLength1;
+ public float _maxLength2;
+
+ // Effective masses
+ public float _pulleyMass;
+ public float _limitMass1;
+ public float _limitMass2;
+
+ // Impulses for accumulation/warm starting.
+ public float _impulse;
+ public float _limitImpulse1;
+ public float _limitImpulse2;
+
+ public LimitState _state;
+ public LimitState _limitState1;
+ public LimitState _limitState2;
+
+ public override Vec2 Anchor1
+ {
+ get { return _body1.GetWorldPoint(_localAnchor1); }
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor2); }
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ Vec2 P = _impulse * _u2;
+ return inv_dt * P;
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return 0.0f;
+ }
+
+ /// <summary>
+ /// Get the first ground anchor.
+ /// </summary>
+ public Vec2 GroundAnchor1
+ {
+ get { return _ground.GetXForm().Position + _groundAnchor1; }
+ }
+
+ /// <summary>
+ /// Get the second ground anchor.
+ /// </summary>
+ public Vec2 GroundAnchor2
+ {
+ get { return _ground.GetXForm().Position + _groundAnchor2; }
+ }
+
+ /// <summary>
+ /// Get the current length of the segment attached to body1.
+ /// </summary>
+ public float Length1
+ {
+ get
+ {
+ Vec2 p = _body1.GetWorldPoint(_localAnchor1);
+ Vec2 s = _ground.GetXForm().Position + _groundAnchor1;
+ Vec2 d = p - s;
+ return d.Length();
+ }
+ }
+
+ /// <summary>
+ /// Get the current length of the segment attached to body2.
+ /// </summary>
+ public float Length2
+ {
+ get
+ {
+ Vec2 p = _body2.GetWorldPoint(_localAnchor2);
+ Vec2 s = _ground.GetXForm().Position + _groundAnchor2;
+ Vec2 d = p - s;
+ return d.Length();
+ }
+ }
+
+ /// <summary>
+ /// Get the pulley ratio.
+ /// </summary>
+ public float Ratio
+ {
+ get { return _ratio; }
+ }
+
+ public PulleyJoint(PulleyJointDef def)
+ : base(def)
+ {
+ _ground = _body1.GetWorld().GetGroundBody();
+ _groundAnchor1 = def.GroundAnchor1 - _ground.GetXForm().Position;
+ _groundAnchor2 = def.GroundAnchor2 - _ground.GetXForm().Position;
+ _localAnchor1 = def.LocalAnchor1;
+ _localAnchor2 = def.LocalAnchor2;
+
+ Box2DXDebug.Assert(def.Ratio != 0.0f);
+ _ratio = def.Ratio;
+
+ _constant = def.Length1 + _ratio * def.Length2;
+
+ _maxLength1 = Common.Math.Min(def.MaxLength1, _constant - _ratio * PulleyJoint.MinPulleyLength);
+ _maxLength2 = Common.Math.Min(def.MaxLength2, (_constant - PulleyJoint.MinPulleyLength) / _ratio);
+
+ _impulse = 0.0f;
+ _limitImpulse1 = 0.0f;
+ _limitImpulse2 = 0.0f;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ Vec2 p1 = b1._sweep.C + r1;
+ Vec2 p2 = b2._sweep.C + r2;
+
+ Vec2 s1 = _ground.GetXForm().Position + _groundAnchor1;
+ Vec2 s2 = _ground.GetXForm().Position + _groundAnchor2;
+
+ // Get the pulley axes.
+ _u1 = p1 - s1;
+ _u2 = p2 - s2;
+
+ float length1 = _u1.Length();
+ float length2 = _u2.Length();
+
+ if (length1 > Settings.LinearSlop)
+ {
+ _u1 *= 1.0f / length1;
+ }
+ else
+ {
+ _u1.SetZero();
+ }
+
+ if (length2 > Settings.LinearSlop)
+ {
+ _u2 *= 1.0f / length2;
+ }
+ else
+ {
+ _u2.SetZero();
+ }
+
+ float C = _constant - length1 - _ratio * length2;
+ if (C > 0.0f)
+ {
+ _state = LimitState.InactiveLimit;
+ _impulse = 0.0f;
+ }
+ else
+ {
+ _state = LimitState.AtUpperLimit;
+ }
+
+ if (length1 < _maxLength1)
+ {
+ _limitState1 = LimitState.InactiveLimit;
+ _limitImpulse1 = 0.0f;
+ }
+ else
+ {
+ _limitState1 = LimitState.AtUpperLimit;
+ }
+
+ if (length2 < _maxLength2)
+ {
+ _limitState2 = LimitState.InactiveLimit;
+ _limitImpulse2 = 0.0f;
+ }
+ else
+ {
+ _limitState2 = LimitState.AtUpperLimit;
+ }
+
+ // Compute effective mass.
+ float cr1u1 = Vec2.Cross(r1, _u1);
+ float cr2u2 = Vec2.Cross(r2, _u2);
+
+ _limitMass1 = b1._invMass + b1._invI * cr1u1 * cr1u1;
+ _limitMass2 = b2._invMass + b2._invI * cr2u2 * cr2u2;
+ _pulleyMass = _limitMass1 + _ratio * _ratio * _limitMass2;
+ Box2DXDebug.Assert(_limitMass1 > Settings.FLT_EPSILON);
+ Box2DXDebug.Assert(_limitMass2 > Settings.FLT_EPSILON);
+ Box2DXDebug.Assert(_pulleyMass > Settings.FLT_EPSILON);
+ _limitMass1 = 1.0f / _limitMass1;
+ _limitMass2 = 1.0f / _limitMass2;
+ _pulleyMass = 1.0f / _pulleyMass;
+
+ if (step.WarmStarting)
+ {
+ // Scale impulses to support variable time steps.
+ _impulse *= step.DtRatio;
+ _limitImpulse1 *= step.DtRatio;
+ _limitImpulse2 *= step.DtRatio;
+
+ // Warm starting.
+ Vec2 P1 = -(_impulse + _limitImpulse1) * _u1;
+ Vec2 P2 = (-_ratio * _impulse - _limitImpulse2) * _u2;
+ b1._linearVelocity += b1._invMass * P1;
+ b1._angularVelocity += b1._invI * Vec2.Cross(r1, P1);
+ b2._linearVelocity += b2._invMass * P2;
+ b2._angularVelocity += b2._invI * Vec2.Cross(r2, P2);
+ }
+ else
+ {
+ _impulse = 0.0f;
+ _limitImpulse1 = 0.0f;
+ _limitImpulse2 = 0.0f;
+ }
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ if (_state == LimitState.AtUpperLimit)
+ {
+ Vec2 v1 = b1._linearVelocity + Vec2.Cross(b1._angularVelocity, r1);
+ Vec2 v2 = b2._linearVelocity + Vec2.Cross(b2._angularVelocity, r2);
+
+ float Cdot = -Vec2.Dot(_u1, v1) - _ratio * Vec2.Dot(_u2, v2);
+ float impulse = _pulleyMass * (-Cdot);
+ float oldImpulse = _impulse;
+ _impulse = Box2DX.Common.Math.Max(0.0f, _impulse + impulse);
+ impulse = _impulse - oldImpulse;
+
+ Vec2 P1 = -impulse * _u1;
+ Vec2 P2 = -_ratio * impulse * _u2;
+ b1._linearVelocity += b1._invMass * P1;
+ b1._angularVelocity += b1._invI * Vec2.Cross(r1, P1);
+ b2._linearVelocity += b2._invMass * P2;
+ b2._angularVelocity += b2._invI * Vec2.Cross(r2, P2);
+ }
+
+ if (_limitState1 == LimitState.AtUpperLimit)
+ {
+ Vec2 v1 = b1._linearVelocity + Vec2.Cross(b1._angularVelocity, r1);
+
+ float Cdot = -Vec2.Dot(_u1, v1);
+ float impulse = -_limitMass1 * Cdot;
+ float oldImpulse = _limitImpulse1;
+ _limitImpulse1 = Box2DX.Common.Math.Max(0.0f, _limitImpulse1 + impulse);
+ impulse = _limitImpulse1 - oldImpulse;
+
+ Vec2 P1 = -impulse * _u1;
+ b1._linearVelocity += b1._invMass * P1;
+ b1._angularVelocity += b1._invI * Vec2.Cross(r1, P1);
+ }
+
+ if (_limitState2 == LimitState.AtUpperLimit)
+ {
+ Vec2 v2 = b2._linearVelocity + Vec2.Cross(b2._angularVelocity, r2);
+
+ float Cdot = -Vec2.Dot(_u2, v2);
+ float impulse = -_limitMass2 * Cdot;
+ float oldImpulse = _limitImpulse2;
+ _limitImpulse2 = Box2DX.Common.Math.Max(0.0f, _limitImpulse2 + impulse);
+ impulse = _limitImpulse2 - oldImpulse;
+
+ Vec2 P2 = -impulse * _u2;
+ b2._linearVelocity += b2._invMass * P2;
+ b2._angularVelocity += b2._invI * Vec2.Cross(r2, P2);
+ }
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 s1 = _ground.GetXForm().Position + _groundAnchor1;
+ Vec2 s2 = _ground.GetXForm().Position + _groundAnchor2;
+
+ float linearError = 0.0f;
+
+ if (_state == LimitState.AtUpperLimit)
+ {
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ Vec2 p1 = b1._sweep.C + r1;
+ Vec2 p2 = b2._sweep.C + r2;
+
+ // Get the pulley axes.
+ _u1 = p1 - s1;
+ _u2 = p2 - s2;
+
+ float length1 = _u1.Length();
+ float length2 = _u2.Length();
+
+ if (length1 > Settings.LinearSlop)
+ {
+ _u1 *= 1.0f / length1;
+ }
+ else
+ {
+ _u1.SetZero();
+ }
+
+ if (length2 > Settings.LinearSlop)
+ {
+ _u2 *= 1.0f / length2;
+ }
+ else
+ {
+ _u2.SetZero();
+ }
+
+ float C = _constant - length1 - _ratio * length2;
+ linearError = Box2DXMath.Max(linearError, -C);
+
+ C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+ float impulse = -_pulleyMass * C;
+
+ Vec2 P1 = -impulse * _u1;
+ Vec2 P2 = -_ratio * impulse * _u2;
+
+ b1._sweep.C += b1._invMass * P1;
+ b1._sweep.A += b1._invI * Vec2.Cross(r1, P1);
+ b2._sweep.C += b2._invMass * P2;
+ b2._sweep.A += b2._invI * Vec2.Cross(r2, P2);
+
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+ }
+
+ if (_limitState1 == LimitState.AtUpperLimit)
+ {
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 p1 = b1._sweep.C + r1;
+
+ _u1 = p1 - s1;
+ float length1 = _u1.Length();
+
+ if (length1 > Settings.LinearSlop)
+ {
+ _u1 *= 1.0f / length1;
+ }
+ else
+ {
+ _u1.SetZero();
+ }
+
+ float C = _maxLength1 - length1;
+ linearError = Box2DXMath.Max(linearError, -C);
+ C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+ float impulse = -_limitMass1 * C;
+
+ Vec2 P1 = -impulse * _u1;
+ b1._sweep.C += b1._invMass * P1;
+ b1._sweep.A += b1._invI * Vec2.Cross(r1, P1);
+
+ b1.SynchronizeTransform();
+ }
+
+ if (_limitState2 == LimitState.AtUpperLimit)
+ {
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+ Vec2 p2 = b2._sweep.C + r2;
+
+ _u2 = p2 - s2;
+ float length2 = _u2.Length();
+
+ if (length2 > Settings.LinearSlop)
+ {
+ _u2 *= 1.0f / length2;
+ }
+ else
+ {
+ _u2.SetZero();
+ }
+
+ float C = _maxLength2 - length2;
+ linearError = Box2DXMath.Max(linearError, -C);
+ C = Box2DXMath.Clamp(C + Settings.LinearSlop, -Settings.MaxLinearCorrection, 0.0f);
+ float impulse = -_limitMass2 * C;
+
+ Vec2 P2 = -impulse * _u2;
+ b2._sweep.C += b2._invMass * P2;
+ b2._sweep.A += b2._invI * Vec2.Cross(r2, P2);
+
+ b2.SynchronizeTransform();
+ }
+
+ return linearError < Settings.LinearSlop;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs.meta
new file mode 100644
index 0000000..e028585
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/PulleyJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b11c8edcbb41b7c4dba7334804b55d14
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs b/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs
new file mode 100644
index 0000000..e201e01
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs
@@ -0,0 +1,636 @@
+/*
+ Box2DX Copyright (c) 2008 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+// Point-to-point constraint
+// C = p2 - p1
+// Cdot = v2 - v1
+// = v2 + cross(w2, r2) - v1 - cross(w1, r1)
+// J = [-I -r1_skew I r2_skew ]
+// Identity used:
+// w k % (rx i + ry j) = w * (-ry i + rx j)
+
+// Motor constraint
+// Cdot = w2 - w1
+// J = [0 0 -1 0 0 1]
+// K = invI1 + invI2
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+using Box2DX.Common;
+
+namespace Box2DX.Dynamics
+{
+ using Box2DXMath = Box2DX.Common.Math;
+ using SystemMath = System.Math;
+
+ /// <summary>
+ /// Revolute joint definition. This requires defining an
+ /// anchor point where the bodies are joined. The definition
+ /// uses local anchor points so that the initial configuration
+ /// can violate the constraint slightly. You also need to
+ /// specify the initial relative angle for joint limits. This
+ /// helps when saving and loading a game.
+ /// The local anchor points are measured from the body's origin
+ /// rather than the center of mass because:
+ /// 1. you might not know where the center of mass will be.
+ /// 2. if you add/remove shapes from a body and recompute the mass,
+ /// the joints will be broken.
+ /// </summary>
+ public class RevoluteJointDef : JointDef
+ {
+ public RevoluteJointDef()
+ {
+ Type = JointType.RevoluteJoint;
+ LocalAnchor1.Set(0.0f, 0.0f);
+ LocalAnchor2.Set(0.0f, 0.0f);
+ ReferenceAngle = 0.0f;
+ LowerAngle = 0.0f;
+ UpperAngle = 0.0f;
+ MaxMotorTorque = 0.0f;
+ MotorSpeed = 0.0f;
+ EnableLimit = false;
+ EnableMotor = false;
+ }
+
+ /// <summary>
+ /// Initialize the bodies, anchors, and reference angle using the world
+ /// anchor.
+ /// </summary>
+ public void Initialize(Body body1, Body body2, Vec2 anchor)
+ {
+ Body1 = body1;
+ Body2 = body2;
+ LocalAnchor1 = body1.GetLocalPoint(anchor);
+ LocalAnchor2 = body2.GetLocalPoint(anchor);
+ ReferenceAngle = body2.GetAngle() - body1.GetAngle();
+ }
+
+ /// <summary>
+ /// The local anchor point relative to body1's origin.
+ /// </summary>
+ public Vec2 LocalAnchor1;
+
+ /// <summary>
+ /// The local anchor point relative to body2's origin.
+ /// </summary>
+ public Vec2 LocalAnchor2;
+
+ /// <summary>
+ /// The body2 angle minus body1 angle in the reference state (radians).
+ /// </summary>
+ public float ReferenceAngle;
+
+ /// <summary>
+ /// A flag to enable joint limits.
+ /// </summary>
+ public bool EnableLimit;
+
+ /// <summary>
+ /// The lower angle for the joint limit (radians).
+ /// </summary>
+ public float LowerAngle;
+
+ /// <summary>
+ /// The upper angle for the joint limit (radians).
+ /// </summary>
+ public float UpperAngle;
+
+ /// <summary>
+ /// A flag to enable the joint motor.
+ /// </summary>
+ public bool EnableMotor;
+
+ /// <summary>
+ /// The desired motor speed. Usually in radians per second.
+ /// </summary>
+ public float MotorSpeed;
+
+ /// <summary>
+ /// The maximum motor torque used to achieve the desired motor speed.
+ /// Usually in N-m.
+ /// </summary>
+ public float MaxMotorTorque;
+ }
+
+ /// <summary>
+ /// A revolute joint constrains to bodies to share a common point while they
+ /// are free to rotate about the point. The relative rotation about the shared
+ /// point is the joint angle. You can limit the relative rotation with
+ /// a joint limit that specifies a lower and upper angle. You can use a motor
+ /// to drive the relative rotation about the shared point. A maximum motor torque
+ /// is provided so that infinite forces are not generated.
+ /// </summary>
+ public class RevoluteJoint : Joint
+ {
+ public Vec2 _localAnchor1; // relative
+ public Vec2 _localAnchor2;
+ public Vec3 _impulse;
+ public float _motorImpulse;
+ public Mat33 _mass; //effective mass for p2p constraint.
+ public float _motorMass; // effective mass for motor/limit angular constraint.
+
+ public bool _enableMotor;
+ public float _maxMotorTorque;
+ public float _motorSpeed;
+
+ public bool _enableLimit;
+ public float _referenceAngle;
+ public float _lowerAngle;
+ public float _upperAngle;
+ public LimitState _limitState;
+
+ public override Vec2 Anchor1
+ {
+ get { return _body1.GetWorldPoint(_localAnchor1); }
+ }
+
+ public override Vec2 Anchor2
+ {
+ get { return _body2.GetWorldPoint(_localAnchor2); }
+ }
+
+ public override Vec2 GetReactionForce(float inv_dt)
+ {
+ Vec2 P = new Vec2(_impulse.X, _impulse.Y);
+ return inv_dt * P;
+ }
+
+ public override float GetReactionTorque(float inv_dt)
+ {
+ return inv_dt * _impulse.Z;
+ }
+
+ /// <summary>
+ /// Get the current joint angle in radians.
+ /// </summary>
+ public float JointAngle
+ {
+ get
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+ return b2._sweep.A - b1._sweep.A - _referenceAngle;
+ }
+ }
+
+
+ /// <summary>
+ /// Get the current joint angle speed in radians per second.
+ /// </summary>
+ public float JointSpeed
+ {
+ get
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+ return b2._angularVelocity - b1._angularVelocity;
+ }
+ }
+
+ /// <summary>
+ /// Is the joint limit enabled?
+ /// </summary>
+ public bool IsLimitEnabled
+ {
+ get { return _enableLimit; }
+ }
+
+ /// <summary>
+ /// Enable/disable the joint limit.
+ /// </summary>
+ public void EnableLimit(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableLimit = flag;
+ }
+
+ /// <summary>
+ /// Get the lower joint limit in radians.
+ /// </summary>
+ public float LowerLimit
+ {
+ get { return _lowerAngle; }
+ }
+
+ /// <summary>
+ /// Get the upper joint limit in radians.
+ /// </summary>
+ public float UpperLimit
+ {
+ get { return _upperAngle; }
+ }
+
+ /// <summary>
+ /// Set the joint limits in radians.
+ /// </summary>
+ public void SetLimits(float lower, float upper)
+ {
+ Box2DXDebug.Assert(lower <= upper);
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _lowerAngle = lower;
+ _upperAngle = upper;
+ }
+
+ /// <summary>
+ /// Is the joint motor enabled?
+ /// </summary>
+ public bool IsMotorEnabled
+ {
+ get { return _enableMotor; }
+ }
+
+ /// <summary>
+ /// Enable/disable the joint motor.
+ /// </summary>
+ public void EnableMotor(bool flag)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _enableMotor = flag;
+ }
+
+ /// <summary>
+ /// Get\Set the motor speed in radians per second.
+ /// </summary>
+ public float MotorSpeed
+ {
+ get { return _motorSpeed; }
+ set
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _motorSpeed = value;
+ }
+ }
+
+ /// <summary>
+ /// Set the maximum motor torque, usually in N-m.
+ /// </summary>
+ public void SetMaxMotorTorque(float torque)
+ {
+ _body1.WakeUp();
+ _body2.WakeUp();
+ _maxMotorTorque = torque;
+ }
+
+ /// <summary>
+ /// Get the current motor torque, usually in N-m.
+ /// </summary>
+ public float MotorTorque
+ {
+ get { return _motorImpulse; }
+ }
+
+ public RevoluteJoint(RevoluteJointDef def)
+ : base(def)
+ {
+ _localAnchor1 = def.LocalAnchor1;
+ _localAnchor2 = def.LocalAnchor2;
+ _referenceAngle = def.ReferenceAngle;
+
+ _impulse = new Vec3();
+ _motorImpulse = 0.0f;
+
+ _lowerAngle = def.LowerAngle;
+ _upperAngle = def.UpperAngle;
+ _maxMotorTorque = def.MaxMotorTorque;
+ _motorSpeed = def.MotorSpeed;
+ _enableLimit = def.EnableLimit;
+ _enableMotor = def.EnableMotor;
+ _limitState = LimitState.InactiveLimit;
+ }
+
+ internal override void InitVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ if (_enableMotor || _enableLimit)
+ {
+ // You cannot create a rotation limit between bodies that
+ // both have fixed rotation.
+ Box2DXDebug.Assert(b1._invI > 0.0f || b2._invI > 0.0f);
+ }
+
+ // Compute the effective mass matrix.
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ // J = [-I -r1_skew I r2_skew]
+ // [ 0 -1 0 1]
+ // r_skew = [-ry; rx]
+
+ // Matlab
+ // K = [ m1+r1y^2*i1+m2+r2y^2*i2, -r1y*i1*r1x-r2y*i2*r2x, -r1y*i1-r2y*i2]
+ // [ -r1y*i1*r1x-r2y*i2*r2x, m1+r1x^2*i1+m2+r2x^2*i2, r1x*i1+r2x*i2]
+ // [ -r1y*i1-r2y*i2, r1x*i1+r2x*i2, i1+i2]
+
+ float m1 = b1._invMass, m2 = b2._invMass;
+ float i1 = b1._invI, i2 = b2._invI;
+
+ _mass.Col1.X = m1 + m2 + r1.Y * r1.Y * i1 + r2.Y * r2.Y * i2;
+ _mass.Col2.X = -r1.Y * r1.X * i1 - r2.Y * r2.X * i2;
+ _mass.Col3.X = -r1.Y * i1 - r2.Y * i2;
+ _mass.Col1.Y = _mass.Col2.X;
+ _mass.Col2.Y = m1 + m2 + r1.X * r1.X * i1 + r2.X * r2.X * i2;
+ _mass.Col3.Y = r1.X * i1 + r2.X * i2;
+ _mass.Col1.Z = _mass.Col3.X;
+ _mass.Col2.Z = _mass.Col3.Y;
+ _mass.Col3.Z = i1 + i2;
+
+ _motorMass = 1.0f / (i1 + i2);
+
+ if (_enableMotor == false)
+ {
+ _motorImpulse = 0.0f;
+ }
+
+ if (_enableLimit)
+ {
+ float jointAngle = b2._sweep.A - b1._sweep.A - _referenceAngle;
+ if (Box2DXMath.Abs(_upperAngle - _lowerAngle) < 2.0f * Settings.AngularSlop)
+ {
+ _limitState = LimitState.EqualLimits;
+ }
+ else if (jointAngle <= _lowerAngle)
+ {
+ if (_limitState != LimitState.AtLowerLimit)
+ {
+ _impulse.Z = 0.0f;
+ }
+ _limitState = LimitState.AtLowerLimit;
+ }
+ else if (jointAngle >= _upperAngle)
+ {
+ if (_limitState != LimitState.AtUpperLimit)
+ {
+ _impulse.Z = 0.0f;
+ }
+ _limitState = LimitState.AtUpperLimit;
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ _impulse.Z = 0.0f;
+ }
+ }
+ else
+ {
+ _limitState = LimitState.InactiveLimit;
+ }
+
+ if (step.WarmStarting)
+ {
+ // Scale impulses to support a variable time step.
+ _impulse *= step.DtRatio;
+ _motorImpulse *= step.DtRatio;
+
+ Vec2 P = new Vec2(_impulse.X, _impulse.Y);
+
+ b1._linearVelocity -= m1 * P;
+ b1._angularVelocity -= i1 * (Vec2.Cross(r1, P) + _motorImpulse + _impulse.Z);
+
+ b2._linearVelocity += m2 * P;
+ b2._angularVelocity += i2 * (Vec2.Cross(r2, P) + _motorImpulse + _impulse.Z);
+ }
+ else
+ {
+ _impulse.SetZero();
+ _motorImpulse = 0.0f;
+ }
+ }
+
+ internal override void SolveVelocityConstraints(TimeStep step)
+ {
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ Vec2 v1 = b1._linearVelocity;
+ float w1 = b1._angularVelocity;
+ Vec2 v2 = b2._linearVelocity;
+ float w2 = b2._angularVelocity;
+
+ float m1 = b1._invMass, m2 = b2._invMass;
+ float i1 = b1._invI, i2 = b2._invI;
+
+ //Solve motor constraint.
+ if (_enableMotor && _limitState != LimitState.EqualLimits)
+ {
+ float Cdot = w2 - w1 - _motorSpeed;
+ float impulse = _motorMass * (-Cdot);
+ float oldImpulse = _motorImpulse;
+ float maxImpulse = step.Dt * _maxMotorTorque;
+ _motorImpulse = Box2DXMath.Clamp(_motorImpulse + impulse, -maxImpulse, maxImpulse);
+ impulse = _motorImpulse - oldImpulse;
+
+ w1 -= i1 * impulse;
+ w2 += i2 * impulse;
+ }
+
+ //Solve limit constraint.
+ if (_enableLimit && _limitState != LimitState.InactiveLimit)
+ {
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ // Solve point-to-point constraint
+ Vec2 Cdot1 = v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1);
+ float Cdot2 = w2 - w1;
+ Vec3 Cdot = new Vec3(Cdot1.X, Cdot1.Y, Cdot2);
+
+ Vec3 impulse = _mass.Solve33(-Cdot);
+
+ if (_limitState == LimitState.EqualLimits)
+ {
+ _impulse += impulse;
+ }
+ else if (_limitState == LimitState.AtLowerLimit)
+ {
+ float newImpulse = _impulse.Z + impulse.Z;
+ if (newImpulse < 0.0f)
+ {
+ Vec2 reduced = _mass.Solve22(-Cdot1);
+ impulse.X = reduced.X;
+ impulse.Y = reduced.Y;
+ impulse.Z = -_impulse.Z;
+ _impulse.X += reduced.X;
+ _impulse.Y += reduced.Y;
+ _impulse.Z = 0.0f;
+ }
+ }
+ else if (_limitState == LimitState.AtUpperLimit)
+ {
+ float newImpulse = _impulse.Z + impulse.Z;
+ if (newImpulse > 0.0f)
+ {
+ Vec2 reduced = _mass.Solve22(-Cdot1);
+ impulse.X = reduced.X;
+ impulse.Y = reduced.Y;
+ impulse.Z = -_impulse.Z;
+ _impulse.X += reduced.X;
+ _impulse.Y += reduced.Y;
+ _impulse.Z = 0.0f;
+ }
+ }
+
+ Vec2 P = new Vec2(impulse.X, impulse.Y);
+
+ v1 -= m1 * P;
+ w1 -= i1 * (Vec2.Cross(r1, P) + impulse.Z);
+
+ v2 += m2 * P;
+ w2 += i2 * (Vec2.Cross(r2, P) + impulse.Z);
+ }
+ else
+ {
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ // Solve point-to-point constraint
+ Vec2 Cdot = v2 + Vec2.Cross(w2, r2) - v1 - Vec2.Cross(w1, r1);
+ Vec2 impulse = _mass.Solve22(-Cdot);
+
+ _impulse.X += impulse.X;
+ _impulse.Y += impulse.Y;
+
+ v1 -= m1 * impulse;
+ w1 -= i1 * Vec2.Cross(r1, impulse);
+
+ v2 += m2 * impulse;
+ w2 += i2 * Vec2.Cross(r2, impulse);
+ }
+
+ b1._linearVelocity = v1;
+ b1._angularVelocity = w1;
+ b2._linearVelocity = v2;
+ b2._angularVelocity = w2;
+ }
+
+ internal override bool SolvePositionConstraints(float baumgarte)
+ {
+ // TODO_ERIN block solve with limit.
+
+ Body b1 = _body1;
+ Body b2 = _body2;
+
+ float angularError = 0.0f;
+ float positionError = 0.0f;
+
+ // Solve angular limit constraint.
+ if (_enableLimit && _limitState != LimitState.InactiveLimit)
+ {
+ float angle = b2._sweep.A - b1._sweep.A - _referenceAngle;
+ float limitImpulse = 0.0f;
+
+ if (_limitState == LimitState.EqualLimits)
+ {
+ // Prevent large angular corrections
+ float C = Box2DXMath.Clamp(angle, -Settings.MaxAngularCorrection, Settings.MaxAngularCorrection);
+ limitImpulse = -_motorMass * C;
+ angularError = Box2DXMath.Abs(C);
+ }
+ else if (_limitState == LimitState.AtLowerLimit)
+ {
+ float C = angle - _lowerAngle;
+ angularError = -C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = Box2DXMath.Clamp(C + Settings.AngularSlop, -Settings.MaxAngularCorrection, 0.0f);
+ limitImpulse = -_motorMass * C;
+ }
+ else if (_limitState == LimitState.AtUpperLimit)
+ {
+ float C = angle - _upperAngle;
+ angularError = C;
+
+ // Prevent large angular corrections and allow some slop.
+ C = Box2DXMath.Clamp(C - Settings.AngularSlop, 0.0f, Settings.MaxAngularCorrection);
+ limitImpulse = -_motorMass * C;
+ }
+
+ b1._sweep.A -= b1._invI * limitImpulse;
+ b2._sweep.A += b2._invI * limitImpulse;
+
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+ }
+
+ // Solve point-to-point constraint.
+ {
+ Vec2 r1 = Box2DXMath.Mul(b1.GetXForm().R, _localAnchor1 - b1.GetLocalCenter());
+ Vec2 r2 = Box2DXMath.Mul(b2.GetXForm().R, _localAnchor2 - b2.GetLocalCenter());
+
+ Vec2 C = b2._sweep.C + r2 - b1._sweep.C - r1;
+ positionError = C.Length();
+
+ float invMass1 = b1._invMass, invMass2 = b2._invMass;
+ float invI1 = b1._invI, invI2 = b2._invI;
+
+ // Handle large detachment.
+ float k_allowedStretch = 10.0f * Settings.LinearSlop;
+ if (C.LengthSquared() > k_allowedStretch * k_allowedStretch)
+ {
+ // Use a particle solution (no rotation).
+ Vec2 u = C; u.Normalize();
+ float k = invMass1 + invMass2;
+ Box2DXDebug.Assert(k > Settings.FLT_EPSILON);
+ float m = 1.0f / k;
+ Vec2 impulse = m * (-C);
+ float k_beta = 0.5f;
+ b1._sweep.C -= k_beta * invMass1 * impulse;
+ b2._sweep.C += k_beta * invMass2 * impulse;
+
+ C = b2._sweep.C + r2 - b1._sweep.C - r1;
+ }
+
+ Mat22 K1 = new Mat22();
+ K1.Col1.X = invMass1 + invMass2; K1.Col2.X = 0.0f;
+ K1.Col1.Y = 0.0f; K1.Col2.Y = invMass1 + invMass2;
+
+ Mat22 K2 = new Mat22();
+ K2.Col1.X = invI1 * r1.Y * r1.Y; K2.Col2.X = -invI1 * r1.X * r1.Y;
+ K2.Col1.Y = -invI1 * r1.X * r1.Y; K2.Col2.Y = invI1 * r1.X * r1.X;
+
+ Mat22 K3 = new Mat22();
+ K3.Col1.X = invI2 * r2.Y * r2.Y; K3.Col2.X = -invI2 * r2.X * r2.Y;
+ K3.Col1.Y = -invI2 * r2.X * r2.Y; K3.Col2.Y = invI2 * r2.X * r2.X;
+
+ Mat22 K = K1 + K2 + K3;
+ Vec2 impulse_ = K.Solve(-C);
+
+ b1._sweep.C -= b1._invMass * impulse_;
+ b1._sweep.A -= b1._invI * Vec2.Cross(r1, impulse_);
+
+ b2._sweep.C += b2._invMass * impulse_;
+ b2._sweep.A += b2._invI * Vec2.Cross(r2, impulse_);
+
+ b1.SynchronizeTransform();
+ b2.SynchronizeTransform();
+ }
+
+ return positionError <= Settings.LinearSlop && angularError <= Settings.AngularSlop;
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs.meta
new file mode 100644
index 0000000..bbc1350
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/Joints/RevoluteJoint.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: cb779b26e7eeeeb4f94a11a53b4f6eb2
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/World.cs b/Box2d/Assets/Program/Box2d/Dynamics/World.cs
new file mode 100644
index 0000000..7ebc5eb
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/World.cs
@@ -0,0 +1,1448 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+
+using Box2DX.Common;
+using Box2DX.Collision;
+
+namespace Box2DX.Dynamics
+{
+ public struct TimeStep
+ {
+ public float Dt; // time step
+ public float Inv_Dt; // inverse time step (0 if dt == 0).
+ public float DtRatio; // dt * inv_dt0
+ public int VelocityIterations;
+ public int PositionIterations;
+ public bool WarmStarting;
+ }
+
+ /// <summary>
+ /// The world class manages all physics entities, dynamic simulation,
+ /// and asynchronous queries.
+ /// </summary>
+ public class World : IDisposable
+ {
+ internal bool _lock;
+
+ internal BroadPhase _broadPhase;
+ private ContactManager _contactManager;
+
+ private Body _bodyList;
+ private Joint _jointList;
+ private Controllers.Controller _controllerList;
+
+ private Vec2 _raycastNormal;
+ private object _raycastUserData;
+ private Segment _raycastSegment;
+ private bool _raycastSolidShape;
+
+ // Do not access
+ internal Contact _contactList;
+
+ private int _bodyCount;
+ internal int _contactCount;
+ private int _jointCount;
+ private int _controllerCount;
+
+ private Vec2 _gravity;
+ /// <summary>
+ /// Get\Set global gravity vector.
+ /// </summary>
+ public Vec2 Gravity { get { return _gravity; } set { _gravity = value; } }
+
+ private bool _allowSleep;
+
+ private Body _groundBody;
+
+ private DestructionListener _destructionListener;
+ private BoundaryListener _boundaryListener;
+ internal ContactFilter _contactFilter;
+ internal ContactListener _contactListener;
+ private DebugDraw _debugDraw;
+
+ // This is used to compute the time step ratio to
+ // support a variable time step.
+ private float _inv_dt0;
+
+ // This is for debugging the solver.
+ private bool _warmStarting;
+
+ // This is for debugging the solver.
+ private bool _continuousPhysics;
+
+ /// <summary>
+ /// Construct a world object.
+ /// </summary>
+ /// <param name="worldAABB">A bounding box that completely encompasses all your shapes.</param>
+ /// <param name="gravity">The world gravity vector.</param>
+ /// <param name="doSleep">Improve performance by not simulating inactive bodies.</param>
+ public World(AABB worldAABB, Vec2 gravity, bool doSleep)
+ {
+ _destructionListener = null;
+ _boundaryListener = null;
+ _contactFilter = null;
+ _contactListener = null;
+ _debugDraw = null;
+
+ _bodyList = null;
+ _contactList = null;
+ _jointList = null;
+
+ _bodyCount = 0;
+ _contactCount = 0;
+ _jointCount = 0;
+
+ _warmStarting = true;
+ _continuousPhysics = true;
+
+ _allowSleep = doSleep;
+ _gravity = gravity;
+
+ _lock = false;
+
+ _inv_dt0 = 0.0f;
+
+ _contactManager = new ContactManager();
+ _contactManager._world = this;
+ _broadPhase = new BroadPhase(worldAABB, _contactManager);
+
+ BodyDef bd = new BodyDef();
+ _groundBody = CreateBody(bd);
+ }
+
+ /// <summary>
+ /// Destruct the world. All physics entities are destroyed.
+ /// </summary>
+ public void Dispose()
+ {
+ DestroyBody(_groundBody);
+ if (_broadPhase is IDisposable)
+ (_broadPhase as IDisposable).Dispose();
+ _broadPhase = null;
+ }
+
+ /// <summary>
+ /// Register a destruction listener.
+ /// </summary>
+ /// <param name="listener"></param>
+ public void SetDestructionListener(DestructionListener listener)
+ {
+ _destructionListener = listener;
+ }
+
+ /// <summary>
+ /// Register a broad-phase boundary listener.
+ /// </summary>
+ /// <param name="listener"></param>
+ public void SetBoundaryListener(BoundaryListener listener)
+ {
+ _boundaryListener = listener;
+ }
+
+ /// <summary>
+ /// Register a contact filter to provide specific control over collision.
+ /// Otherwise the default filter is used (b2_defaultFilter).
+ /// </summary>
+ /// <param name="filter"></param>
+ public void SetContactFilter(ContactFilter filter)
+ {
+ _contactFilter = filter;
+ }
+
+ /// <summary>
+ /// Register a contact event listener
+ /// </summary>
+ /// <param name="listener"></param>
+ public void SetContactListener(ContactListener listener)
+ {
+ _contactListener = listener;
+ }
+
+ /// <summary>
+ /// Register a routine for debug drawing. The debug draw functions are called
+ /// inside the World.Step method, so make sure your renderer is ready to
+ /// consume draw commands when you call Step().
+ /// </summary>
+ /// <param name="debugDraw"></param>
+ public void SetDebugDraw(DebugDraw debugDraw)
+ {
+ _debugDraw = debugDraw;
+ }
+
+ /// <summary>
+ /// Create a rigid body given a definition. No reference to the definition
+ /// is retained.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="def"></param>
+ /// <returns></returns>
+ public Body CreateBody(BodyDef def)
+ {
+ Box2DXDebug.Assert(_lock == false);
+ if (_lock == true)
+ {
+ return null;
+ }
+
+ Body b = new Body(def, this);
+
+ // Add to world doubly linked list.
+ b._prev = null;
+ b._next = _bodyList;
+ if (_bodyList != null)
+ {
+ _bodyList._prev = b;
+ }
+ _bodyList = b;
+ ++_bodyCount;
+
+ return b;
+ }
+
+ /// <summary>
+ /// Destroy a rigid body given a definition. No reference to the definition
+ /// is retained. This function is locked during callbacks.
+ /// @warning This automatically deletes all associated shapes and joints.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="b"></param>
+ public void DestroyBody(Body b)
+ {
+ Box2DXDebug.Assert(_bodyCount > 0);
+ Box2DXDebug.Assert(_lock == false);
+ if (_lock == true)
+ {
+ return;
+ }
+
+ // Delete the attached joints.
+ JointEdge jn = null;
+ if (b._jointList != null)
+ jn = b._jointList;
+ while (jn != null)
+ {
+ JointEdge jn0 = jn;
+ jn = jn.Next;
+
+ if (_destructionListener != null)
+ {
+ _destructionListener.SayGoodbye(jn0.Joint);
+ }
+
+ DestroyJoint(jn0.Joint);
+ }
+
+ //Detach controllers attached to this body
+ Controllers.ControllerEdge ce = b._controllerList;
+ while (ce != null)
+ {
+ Controllers.ControllerEdge ce0 = ce;
+ ce = ce.nextController;
+
+ ce0.controller.RemoveBody(b);
+ }
+
+ // Delete the attached fixtures. This destroys broad-phase
+ // proxies and pairs, leading to the destruction of contacts.
+ Fixture f = b._fixtureList;
+ while (f != null)
+ {
+ Fixture f0 = f;
+ f = f.Next;
+
+ if (_destructionListener != null)
+ {
+ _destructionListener.SayGoodbye(f0);
+ }
+
+ f0.Destroy(_broadPhase);
+ }
+
+ // Remove world body list.
+ if (b._prev != null)
+ {
+ b._prev._next = b._next;
+ }
+
+ if (b._next != null)
+ {
+ b._next._prev = b._prev;
+ }
+
+ if (b == _bodyList)
+ {
+ _bodyList = b._next;
+ }
+
+ --_bodyCount;
+ if (b is IDisposable)
+ (b as IDisposable).Dispose();
+ b = null;
+ }
+
+ /// <summary>
+ /// Create a joint to constrain bodies together. No reference to the definition
+ /// is retained. This may cause the connected bodies to cease colliding.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="def"></param>
+ /// <returns></returns>
+ public Joint CreateJoint(JointDef def)
+ {
+ Box2DXDebug.Assert(_lock == false);
+
+ Joint j = Joint.Create(def);
+
+ // Connect to the world list.
+ j._prev = null;
+ j._next = _jointList;
+ if (_jointList != null)
+ {
+ _jointList._prev = j;
+ }
+ _jointList = j;
+ ++_jointCount;
+
+ // Connect to the bodies' doubly linked lists.
+ j._node1.Joint = j;
+ j._node1.Other = j._body2;
+ j._node1.Prev = null;
+ j._node1.Next = j._body1._jointList;
+ if (j._body1._jointList != null)
+ j._body1._jointList.Prev = j._node1;
+ j._body1._jointList = j._node1;
+
+ j._node2.Joint = j;
+ j._node2.Other = j._body1;
+ j._node2.Prev = null;
+ j._node2.Next = j._body2._jointList;
+ if (j._body2._jointList != null)
+ j._body2._jointList.Prev = j._node2;
+ j._body2._jointList = j._node2;
+
+ // If the joint prevents collisions, then reset collision filtering.
+ if (def.CollideConnected == false)
+ {
+ // Reset the proxies on the body with the minimum number of shapes.
+ Body b = def.Body1._fixtureCount < def.Body2._fixtureCount ? def.Body1 : def.Body2;
+ for (Fixture f = b._fixtureList; f != null; f = f.Next)
+ {
+ f.RefilterProxy(_broadPhase, b.GetXForm());
+ }
+ }
+
+ return j;
+ }
+
+ /// <summary>
+ /// Destroy a joint. This may cause the connected bodies to begin colliding.
+ /// @warning This function is locked during callbacks.
+ /// </summary>
+ /// <param name="j"></param>
+ public void DestroyJoint(Joint j)
+ {
+ Box2DXDebug.Assert(_lock == false);
+
+ bool collideConnected = j._collideConnected;
+
+ // Remove from the doubly linked list.
+ if (j._prev != null)
+ {
+ j._prev._next = j._next;
+ }
+
+ if (j._next != null)
+ {
+ j._next._prev = j._prev;
+ }
+
+ if (j == _jointList)
+ {
+ _jointList = j._next;
+ }
+
+ // Disconnect from island graph.
+ Body body1 = j._body1;
+ Body body2 = j._body2;
+
+ // Wake up connected bodies.
+ body1.WakeUp();
+ body2.WakeUp();
+
+ // Remove from body 1.
+ if (j._node1.Prev != null)
+ {
+ j._node1.Prev.Next = j._node1.Next;
+ }
+
+ if (j._node1.Next != null)
+ {
+ j._node1.Next.Prev = j._node1.Prev;
+ }
+
+ if (j._node1 == body1._jointList)
+ {
+ body1._jointList = j._node1.Next;
+ }
+
+ j._node1.Prev = null;
+ j._node1.Next = null;
+
+ // Remove from body 2
+ if (j._node2.Prev != null)
+ {
+ j._node2.Prev.Next = j._node2.Next;
+ }
+
+ if (j._node2.Next != null)
+ {
+ j._node2.Next.Prev = j._node2.Prev;
+ }
+
+ if (j._node2 == body2._jointList)
+ {
+ body2._jointList = j._node2.Next;
+ }
+
+ j._node2.Prev = null;
+ j._node2.Next = null;
+
+ Joint.Destroy(j);
+
+ Box2DXDebug.Assert(_jointCount > 0);
+ --_jointCount;
+
+ // If the joint prevents collisions, then reset collision filtering.
+ if (collideConnected == false)
+ {
+ // Reset the proxies on the body with the minimum number of shapes.
+ Body b = body1._fixtureCount < body2._fixtureCount ? body1 : body2;
+ for (Fixture f = b._fixtureList; f != null; f = f.Next)
+ {
+ f.RefilterProxy(_broadPhase, b.GetXForm());
+ }
+ }
+ }
+
+ public Controllers.Controller AddController(Controllers.Controller def)
+ {
+ def._next = _controllerList;
+ def._prev = null;
+ if (_controllerList != null)
+ _controllerList._prev = def;
+ _controllerList = def;
+ ++_controllerCount;
+
+ def._world = this;
+
+ return def;
+ }
+
+ public void RemoveController(Controllers.Controller controller)
+ {
+ Box2DXDebug.Assert(_controllerCount > 0);
+ if (controller._next != null)
+ controller._next._prev = controller._prev;
+ if (controller._prev != null)
+ controller._prev._next = controller._next;
+ if (controller == _controllerList)
+ _controllerList = controller._next;
+ --_controllerCount;
+ }
+
+ /// <summary>
+ /// The world provides a single static ground body with no collision shapes.
+ /// You can use this to simplify the creation of joints and static shapes.
+ /// </summary>
+ /// <returns></returns>
+ public Body GetGroundBody()
+ {
+ return _groundBody;
+ }
+
+ /// <summary>
+ /// Get the world body list. With the returned body, use Body.GetNext to get
+ /// the next body in the world list. A null body indicates the end of the list.
+ /// </summary>
+ /// <returns>The head of the world body list.</returns>
+ public Body GetBodyList()
+ {
+ return _bodyList;
+ }
+
+ /// <summary>
+ /// Get the world joint list. With the returned joint, use Joint.GetNext to get
+ /// the next joint in the world list. A null joint indicates the end of the list.
+ /// </summary>
+ /// <returns>The head of the world joint list.</returns>
+ public Joint GetJointList()
+ {
+ return _jointList;
+ }
+
+ public Controllers.Controller GetControllerList()
+ {
+ return _controllerList;
+ }
+
+ public int GetControllerCount()
+ {
+ return _controllerCount;
+ }
+
+ /// <summary>
+ /// Re-filter a fixture. This re-runs contact filtering on a fixture.
+ /// </summary>
+ public void Refilter(Fixture fixture)
+ {
+ Box2DXDebug.Assert(_lock == false);
+ fixture.RefilterProxy(_broadPhase, fixture.Body.GetXForm());
+ }
+
+ /// <summary>
+ /// Enable/disable warm starting. For testing.
+ /// </summary>
+ public void SetWarmStarting(bool flag) { _warmStarting = flag; }
+
+ /// <summary>
+ /// Enable/disable continuous physics. For testing.
+ /// </summary>
+ public void SetContinuousPhysics(bool flag) { _continuousPhysics = flag; }
+
+ /// <summary>
+ /// Perform validation of internal data structures.
+ /// </summary>
+ public void Validate() { _broadPhase.Validate(); }
+
+ /// <summary>
+ /// Get the number of broad-phase proxies.
+ /// </summary>
+ public int GetProxyCount() { return _broadPhase._proxyCount; }
+
+ /// <summary>
+ /// Get the number of broad-phase pairs.
+ /// </summary>
+ /// <returns></returns>
+ public int GetPairCount() { return _broadPhase._pairManager._pairCount; }
+
+ /// <summary>
+ /// Get the number of bodies.
+ /// </summary>
+ /// <returns></returns>
+ public int GetBodyCount() { return _bodyCount; }
+
+ /// <summary>
+ /// Get the number joints.
+ /// </summary>
+ /// <returns></returns>
+ public int GetJointCount() { return _jointCount; }
+
+ /// <summary>
+ /// Get the number of contacts (each may have 0 or more contact points).
+ /// </summary>
+ /// <returns></returns>
+ public int GetContactCount() { return _contactCount; }
+
+ /// <summary>
+ /// Take a time step. This performs collision detection, integration,
+ /// and constraint solution.
+ /// </summary>
+ /// <param name="dt">The amount of time to simulate, this should not vary.</param>
+ /// <param name="iterations">For the velocity constraint solver.</param>
+ /// <param name="iterations">For the positionconstraint solver.</param>
+ public void Step(float dt, int velocityIterations, int positionIteration)
+ {
+ _lock = true;
+
+ TimeStep step = new TimeStep();
+ step.Dt = dt;
+ step.VelocityIterations = velocityIterations;
+ step.PositionIterations = positionIteration;
+ if (dt > 0.0f)
+ {
+ step.Inv_Dt = 1.0f / dt;
+ }
+ else
+ {
+ step.Inv_Dt = 0.0f;
+ }
+
+ step.DtRatio = _inv_dt0 * dt;
+
+ step.WarmStarting = _warmStarting;
+
+ // Update contacts.
+ _contactManager.Collide();
+
+ // Integrate velocities, solve velocity constraints, and integrate positions.
+ if (step.Dt > 0.0f)
+ {
+ Solve(step);
+ }
+
+ // Handle TOI events.
+ if (_continuousPhysics && step.Dt > 0.0f)
+ {
+ SolveTOI(step);
+ }
+
+ // Draw debug information.
+ DrawDebugData();
+
+ _inv_dt0 = step.Inv_Dt;
+ _lock = false;
+ }
+
+ /// Query the world for all shapes that potentially overlap the
+ /// provided AABB. You provide a shape pointer buffer of specified
+ /// size. The number of shapes found is returned.
+ /// @param aabb the query box.
+ /// @param shapes a user allocated shape pointer array of size maxCount (or greater).
+ /// @param maxCount the capacity of the shapes array.
+ /// @return the number of shapes found in aabb.
+ public int Query(AABB aabb, Fixture[] fixtures, int maxCount)
+ {
+ //using (object[] results = new object[maxCount])
+ {
+ object[] results = new object[maxCount];
+
+ int count = _broadPhase.Query(aabb, results, maxCount);
+
+ for (int i = 0; i < count; ++i)
+ {
+ fixtures[i] = (Fixture)results[i];
+ }
+
+ results = null;
+ return count;
+ }
+ }
+
+ /// <summary>
+ /// Query the world for all shapes that intersect a given segment. You provide a shap
+ /// pointer buffer of specified size. The number of shapes found is returned, and the buffer
+ /// is filled in order of intersection.
+ /// </summary>
+ /// <param name="segment">Defines the begin and end point of the ray cast, from p1 to p2.
+ /// Use Segment.Extend to create (semi-)infinite rays.</param>
+ /// <param name="shapes">A user allocated shape pointer array of size maxCount (or greater).</param>
+ /// <param name="maxCount">The capacity of the shapes array.</param>
+ /// <param name="solidShapes">Determines if shapes that the ray starts in are counted as hits.</param>
+ /// <param name="userData">Passed through the worlds contact filter, with method RayCollide. This can be used to filter valid shapes.</param>
+ /// <returns>The number of shapes found</returns>
+ public int Raycast(Segment segment, out Fixture[] fixtures, int maxCount, bool solidShapes, object userData)
+ {
+#warning "PTR"
+ _raycastSegment = segment;
+ _raycastUserData = userData;
+ _raycastSolidShape = solidShapes;
+
+ object[] results = new object[maxCount];
+ fixtures = new Fixture[maxCount];
+ int count = _broadPhase.QuerySegment(segment, results, maxCount, RaycastSortKey);
+
+ for (int i = 0; i < count; ++i)
+ {
+ fixtures[i] = (Fixture)results[i];
+ }
+
+ return count;
+ }
+
+ /// <summary>
+ /// Performs a raycast as with Raycast, finding the first intersecting shape.
+ /// </summary>
+ /// <param name="segment">Defines the begin and end point of the ray cast, from p1 to p2.
+ /// Use Segment.Extend to create (semi-)infinite rays.</param>
+ /// <param name="lambda">Returns the hit fraction. You can use this to compute the contact point
+ /// p = (1 - lambda) * segment.p1 + lambda * segment.p2.</param>
+ /// <param name="normal">Returns the normal at the contact point. If there is no intersection, the normal is not set.</param>
+ /// <param name="solidShapes">Determines if shapes that the ray starts in are counted as hits.</param>
+ /// <param name="userData"></param>
+ /// <returns>Returns the colliding shape shape, or null if not found.</returns>
+ public Fixture RaycastOne(Segment segment, out float lambda, out Vec2 normal, bool solidShapes, object userData)
+ {
+ int maxCount = 1;
+ Fixture[] fixture;
+ lambda = 0.0f;
+ normal = new Vec2();
+
+ int count = Raycast(segment, out fixture, maxCount, solidShapes, userData);
+
+ if (count == 0)
+ return null;
+
+ Box2DXDebug.Assert(count == 1);
+
+ //Redundantly do TestSegment a second time, as the previous one's results are inaccessible
+
+ fixture[0].TestSegment(out lambda, out normal, segment, 1);
+ //We already know it returns true
+ return fixture[0];
+ }
+
+ // Find islands, integrate and solve constraints, solve position constraints
+ private void Solve(TimeStep step)
+ {
+ // Step all controlls
+ for (Controllers.Controller controller = _controllerList; controller != null; controller = controller._next)
+ {
+ controller.Step(step);
+ }
+
+ // Size the island for the worst case.
+ Island island = new Island(_bodyCount, _contactCount, _jointCount, _contactListener);
+
+ // Clear all the island flags.
+ for (Body b = _bodyList; b != null; b = b._next)
+ {
+ b._flags &= ~Body.BodyFlags.Island;
+ }
+ for (Contact c = _contactList; c != null; c = c._next)
+ {
+ c._flags &= ~Contact.CollisionFlags.Island;
+ }
+ for (Joint j = _jointList; j != null; j = j._next)
+ {
+ j._islandFlag = false;
+ }
+
+ // Build and simulate all awake islands.
+ int stackSize = _bodyCount;
+ {
+ Body[] stack = new Body[stackSize];
+
+ for (Body seed = _bodyList; seed != null; seed = seed._next)
+ {
+ if ((seed._flags & (Body.BodyFlags.Island | Body.BodyFlags.Sleep | Body.BodyFlags.Frozen)) != 0)
+ {
+ continue;
+ }
+
+ if (seed.IsStatic())
+ {
+ continue;
+ }
+
+ // Reset island and stack.
+ island.Clear();
+ int stackCount = 0;
+ stack[stackCount++] = seed;
+ seed._flags |= Body.BodyFlags.Island;
+
+ // Perform a depth first search (DFS) on the constraint graph.
+ while (stackCount > 0)
+ {
+ // Grab the next body off the stack and add it to the island.
+ Body b = stack[--stackCount];
+ island.Add(b);
+
+ // Make sure the body is awake.
+ b._flags &= ~Body.BodyFlags.Sleep;
+
+ // To keep islands as small as possible, we don't
+ // propagate islands across static bodies.
+ if (b.IsStatic())
+ {
+ continue;
+ }
+
+ // Search all contacts connected to this body.
+ for (ContactEdge cn = b._contactList; cn != null; cn = cn.Next)
+ {
+ // Has this contact already been added to an island?
+ if ((cn.Contact._flags & (Contact.CollisionFlags.Island | Contact.CollisionFlags.NonSolid)) != 0)
+ {
+ continue;
+ }
+
+ // Is this contact touching?
+ if ((cn.Contact._flags & Contact.CollisionFlags.Touch) == (Contact.CollisionFlags)0)
+ {
+ continue;
+ }
+
+ island.Add(cn.Contact);
+ cn.Contact._flags |= Contact.CollisionFlags.Island;
+
+ Body other = cn.Other;
+
+ // Was the other body already added to this island?
+ if ((other._flags & Body.BodyFlags.Island) != 0)
+ {
+ continue;
+ }
+
+ Box2DXDebug.Assert(stackCount < stackSize);
+ stack[stackCount++] = other;
+ other._flags |= Body.BodyFlags.Island;
+ }
+
+ // Search all joints connect to this body.
+ for (JointEdge jn = b._jointList; jn != null; jn = jn.Next)
+ {
+ if (jn.Joint._islandFlag == true)
+ {
+ continue;
+ }
+
+ island.Add(jn.Joint);
+ jn.Joint._islandFlag = true;
+
+ Body other = jn.Other;
+ if ((other._flags & Body.BodyFlags.Island) != 0)
+ {
+ continue;
+ }
+
+ Box2DXDebug.Assert(stackCount < stackSize);
+ stack[stackCount++] = other;
+ other._flags |= Body.BodyFlags.Island;
+ }
+ }
+
+ island.Solve(step, _gravity, _allowSleep);
+
+ // Post solve cleanup.
+ for (int i = 0; i < island._bodyCount; ++i)
+ {
+ // Allow static bodies to participate in other islands.
+ Body b = island._bodies[i];
+ if (b.IsStatic())
+ {
+ b._flags &= ~Body.BodyFlags.Island;
+ }
+ }
+ }
+
+ stack = null;
+ }
+
+ // Synchronize shapes, check for out of range bodies.
+ for (Body b = _bodyList; b != null; b = b.GetNext())
+ {
+ if ((b._flags & (Body.BodyFlags.Sleep | Body.BodyFlags.Frozen)) != 0)
+ {
+ continue;
+ }
+
+ if (b.IsStatic())
+ {
+ continue;
+ }
+
+ // Update shapes (for broad-phase). If the shapes go out of
+ // the world AABB then shapes and contacts may be destroyed,
+ // including contacts that are
+ bool inRange = b.SynchronizeFixtures();
+
+ // Did the body's shapes leave the world?
+ if (inRange == false && _boundaryListener != null)
+ {
+ _boundaryListener.Violation(b);
+ }
+ }
+
+ // Commit shape proxy movements to the broad-phase so that new contacts are created.
+ // Also, some contacts can be destroyed.
+ _broadPhase.Commit();
+ }
+
+ // Find TOI contacts and solve them.
+ private void SolveTOI(TimeStep step)
+ {
+ // Reserve an island and a queue for TOI island solution.
+ Island island = new Island(_bodyCount, Settings.MaxTOIContactsPerIsland, Settings.MaxTOIJointsPerIsland, _contactListener);
+
+ //Simple one pass queue
+ //Relies on the fact that we're only making one pass
+ //through and each body can only be pushed/popped once.
+ //To push:
+ // queue[queueStart+queueSize++] = newElement;
+ //To pop:
+ // poppedElement = queue[queueStart++];
+ // --queueSize;
+ int queueCapacity = _bodyCount;
+ Body[] queue = new Body[queueCapacity];
+
+ for (Body b = _bodyList; b != null; b = b._next)
+ {
+ b._flags &= ~Body.BodyFlags.Island;
+ b._sweep.T0 = 0.0f;
+ }
+
+ for (Contact c = _contactList; c != null; c = c._next)
+ {
+ // Invalidate TOI
+ c._flags &= ~(Contact.CollisionFlags.Toi | Contact.CollisionFlags.Island);
+ }
+
+ for (Joint j = _jointList; j != null; j = j._next)
+ {
+ j._islandFlag = false;
+ }
+
+ // Find TOI events and solve them.
+ for (; ; )
+ {
+ // Find the first TOI.
+ Contact minContact = null;
+ float minTOI = 1.0f;
+
+ for (Contact c = _contactList; c != null; c = c._next)
+ {
+ if ((int)(c._flags & (Contact.CollisionFlags.Slow | Contact.CollisionFlags.NonSolid)) == 1)
+ {
+ continue;
+ }
+
+ // TODO_ERIN keep a counter on the contact, only respond to M TOIs per contact.
+
+ float toi = 1.0f;
+ if ((int)(c._flags & Contact.CollisionFlags.Toi) == 1)
+ {
+ // This contact has a valid cached TOI.
+ toi = c._toi;
+ }
+ else
+ {
+ // Compute the TOI for this contact.
+ Fixture s1 = c.FixtureA;
+ Fixture s2 = c.FixtureB;
+ Body b1 = s1.Body;
+ Body b2 = s2.Body;
+
+ if ((b1.IsStatic() || b1.IsSleeping()) && (b2.IsStatic() || b2.IsSleeping()))
+ {
+ continue;
+ }
+
+ // Put the sweeps onto the same time interval.
+ float t0 = b1._sweep.T0;
+
+ if (b1._sweep.T0 < b2._sweep.T0)
+ {
+ t0 = b2._sweep.T0;
+ b1._sweep.Advance(t0);
+ }
+ else if (b2._sweep.T0 < b1._sweep.T0)
+ {
+ t0 = b1._sweep.T0;
+ b2._sweep.Advance(t0);
+ }
+
+ Box2DXDebug.Assert(t0 < 1.0f);
+
+ // Compute the time of impact.
+ toi = c.ComputeTOI(b1._sweep, b2._sweep);
+ //b2TimeOfImpact(c->m_fixtureA->GetShape(), b1->m_sweep, c->m_fixtureB->GetShape(), b2->m_sweep);
+
+ Box2DXDebug.Assert(0.0f <= toi && toi <= 1.0f);
+
+ // If the TOI is in range ...
+ if (0.0f < toi && toi < 1.0f)
+ {
+ // Interpolate on the actual range.
+ toi = Common.Math.Min((1.0f - toi) * t0 + toi, 1.0f);
+ }
+
+
+ c._toi = toi;
+ c._flags |= Contact.CollisionFlags.Toi;
+ }
+
+ if (Settings.FLT_EPSILON < toi && toi < minTOI)
+ {
+ // This is the minimum TOI found so far.
+ minContact = c;
+ minTOI = toi;
+ }
+ }
+
+ if (minContact == null || 1.0f - 100.0f * Settings.FLT_EPSILON < minTOI)
+ {
+ // No more TOI events. Done!
+ break;
+ }
+
+ // Advance the bodies to the TOI.
+ Fixture f1 = minContact.FixtureA;
+ Fixture f2 = minContact.FixtureB;
+ Body b3 = f1.Body;
+ Body b4 = f2.Body;
+ b3.Advance(minTOI);
+ b4.Advance(minTOI);
+
+ // The TOI contact likely has some new contact points.
+ minContact.Update(_contactListener);
+ minContact._flags &= ~Contact.CollisionFlags.Toi;
+
+ if ((minContact._flags & Contact.CollisionFlags.Touch) == 0)
+ {
+ // This shouldn't happen. Numerical error?
+ //b2Assert(false);
+ continue;
+ }
+
+ // Build the TOI island. We need a dynamic seed.
+ Body seed = b3;
+ if (seed.IsStatic())
+ {
+ seed = b4;
+ }
+
+ // Reset island and queue.
+ island.Clear();
+
+ int queueStart = 0; // starting index for queue
+ int queueSize = 0; // elements in queue
+ queue[queueStart + queueSize++] = seed;
+ seed._flags |= Body.BodyFlags.Island;
+
+ // Perform a breadth first search (BFS) on the contact/joint graph.
+ while (queueSize > 0)
+ {
+ // Grab the next body off the stack and add it to the island.
+ Body b = queue[queueStart++];
+ --queueSize;
+
+ island.Add(b);
+
+ // Make sure the body is awake.
+ b._flags &= ~Body.BodyFlags.Sleep;
+
+ // To keep islands as small as possible, we don't
+ // propagate islands across static bodies.
+ if (b.IsStatic())
+ {
+ continue;
+ }
+
+ // Search all contacts connected to this body.
+ for (ContactEdge cEdge = b._contactList; cEdge != null; cEdge = cEdge.Next)
+ {
+ // Does the TOI island still have space for contacts?
+ if (island._contactCount == island._contactCapacity)
+ {
+ continue;
+ }
+
+ // Has this contact already been added to an island? Skip slow or non-solid contacts.
+ if ((int)(cEdge.Contact._flags & (Contact.CollisionFlags.Island | Contact.CollisionFlags.Slow | Contact.CollisionFlags.NonSolid)) != 0)
+ {
+ continue;
+ }
+
+ // Is this contact touching? For performance we are not updating this contact.
+ if ((cEdge.Contact._flags & Contact.CollisionFlags.Touch) == 0)
+ {
+ continue;
+ }
+
+ island.Add(cEdge.Contact);
+ cEdge.Contact._flags |= Contact.CollisionFlags.Island;
+
+ // Update other body.
+ Body other = cEdge.Other;
+
+ // Was the other body already added to this island?
+ if ((int)(other._flags & Body.BodyFlags.Island) == 1)
+ {
+ continue;
+ }
+
+ // March forward, this can do no harm since this is the min TOI.
+ if (other.IsStatic() == false)
+ {
+ other.Advance(minTOI);
+ other.WakeUp();
+ }
+
+ //Box2DXDebug.Assert(queueStart + queueSize < queueCapacity);
+ queue[queueStart + queueSize] = other;
+ ++queueSize;
+ other._flags |= Body.BodyFlags.Island;
+ }
+
+ for (JointEdge jEdge = b._jointList; jEdge != null; jEdge = jEdge.Next)
+ {
+ if (island._jointCount == island._jointCapacity)
+ {
+ continue;
+ }
+
+ if (jEdge.Joint._islandFlag == true)
+ {
+ continue;
+ }
+
+ island.Add(jEdge.Joint);
+
+ jEdge.Joint._islandFlag = true;
+
+ Body other = jEdge.Other;
+
+ if ((int)(other._flags & Body.BodyFlags.Island) == 1)
+ {
+ continue;
+ }
+
+ if (!other.IsStatic())
+ {
+ other.Advance(minTOI);
+ other.WakeUp();
+ }
+
+ //Box2DXDebug.Assert(queueStart + queueSize < queueCapacity);
+ queue[queueStart + queueSize] = other;
+ ++queueSize;
+ other._flags |= Body.BodyFlags.Island;
+ }
+ }
+
+ TimeStep subStep;
+ subStep.WarmStarting = false;
+ subStep.Dt = (1.0f - minTOI) * step.Dt;
+ subStep.Inv_Dt = 1.0f / subStep.Dt;
+ subStep.DtRatio = 0.0f;
+ subStep.VelocityIterations = step.VelocityIterations;
+ subStep.PositionIterations = step.PositionIterations;
+
+ island.SolveTOI(ref subStep);
+
+ // Post solve cleanup.
+ for (int i = 0; i < island._bodyCount; ++i)
+ {
+ // Allow bodies to participate in future TOI islands.
+ Body b = island._bodies[i];
+ b._flags &= ~Body.BodyFlags.Island;
+
+ if ((int)(b._flags & (Body.BodyFlags.Sleep | Body.BodyFlags.Frozen)) == 1)
+ {
+ continue;
+ }
+
+ if (b.IsStatic())
+ {
+ continue;
+ }
+
+ // Update fixtures (for broad-phase). If the fixtures go out of
+ // the world AABB then fixtures and contacts may be destroyed,
+ // including contacts that are
+ bool inRange = b.SynchronizeFixtures();
+
+ // Did the body's fixtures leave the world?
+ if (inRange == false && _boundaryListener != null)
+ {
+ _boundaryListener.Violation(b);
+ }
+
+ // Invalidate all contact TOIs associated with this body. Some of these
+ // may not be in the island because they were not touching.
+ for (ContactEdge cn = b._contactList; cn != null; cn = cn.Next)
+ {
+ cn.Contact._flags &= ~Contact.CollisionFlags.Toi;
+ }
+ }
+
+ for (int i = 0; i < island._contactCount; ++i)
+ {
+ // Allow contacts to participate in future TOI islands.
+ Contact c = island._contacts[i];
+ c._flags &= ~(Contact.CollisionFlags.Toi | Contact.CollisionFlags.Island);
+ }
+
+ for (int i = 0; i < island._jointCount; ++i)
+ {
+ // Allow joints to participate in future TOI islands.
+ Joint j = island._joints[i];
+ j._islandFlag = false;
+ }
+
+ // Commit fixture proxy movements to the broad-phase so that new contacts are created.
+ // Also, some contacts can be destroyed.
+ _broadPhase.Commit();
+ }
+
+ queue = null;
+ }
+
+ private void DrawJoint(Joint joint)
+ {
+ Body b1 = joint.GetBody1();
+ Body b2 = joint.GetBody2();
+ XForm xf1 = b1.GetXForm();
+ XForm xf2 = b2.GetXForm();
+ Vec2 x1 = xf1.Position;
+ Vec2 x2 = xf2.Position;
+ Vec2 p1 = joint.Anchor1;
+ Vec2 p2 = joint.Anchor2;
+
+ Color color = new Color(0.5f, 0.8f, 0.8f);
+
+ switch (joint.GetType())
+ {
+ case JointType.DistanceJoint:
+ _debugDraw.DrawSegment(p1, p2, color);
+ break;
+
+ case JointType.PulleyJoint:
+ {
+ PulleyJoint pulley = (PulleyJoint)joint;
+ Vec2 s1 = pulley.GroundAnchor1;
+ Vec2 s2 = pulley.GroundAnchor2;
+ _debugDraw.DrawSegment(s1, p1, color);
+ _debugDraw.DrawSegment(s2, p2, color);
+ _debugDraw.DrawSegment(s1, s2, color);
+ }
+ break;
+
+ case JointType.MouseJoint:
+ // don't draw this
+ break;
+
+ default:
+ _debugDraw.DrawSegment(x1, p1, color);
+ _debugDraw.DrawSegment(p1, p2, color);
+ _debugDraw.DrawSegment(x2, p2, color);
+ break;
+ }
+ }
+
+ private void DrawFixture(Fixture fixture, XForm xf, Color color, bool core)
+ {
+#warning "the core argument is not used, the coreColor variable is also not used"
+ Color coreColor = new Color(0.9f, 0.6f, 0.6f);
+
+ switch (fixture.ShapeType)
+ {
+ case ShapeType.CircleShape:
+ {
+ CircleShape circle = (CircleShape)fixture.Shape;
+
+ Vec2 center = Common.Math.Mul(xf, circle._position);
+ float radius = circle._radius;
+ Vec2 axis = xf.R.Col1;
+
+ _debugDraw.DrawSolidCircle(center, radius, axis, color);
+ }
+ break;
+
+ case ShapeType.PolygonShape:
+ {
+ PolygonShape poly = (PolygonShape)fixture.Shape;
+ int vertexCount = poly._vertexCount;
+ Vec2[] localVertices = poly._vertices;
+
+ Box2DXDebug.Assert(vertexCount <= Settings.MaxPolygonVertices);
+ Vec2[] vertices = new Vec2[Settings.MaxPolygonVertices];
+
+ for (int i = 0; i < vertexCount; ++i)
+ {
+ vertices[i] = Common.Math.Mul(xf, localVertices[i]);
+ }
+
+ _debugDraw.DrawSolidPolygon(vertices, vertexCount, color);
+ }
+ break;
+
+ case ShapeType.EdgeShape:
+ {
+ EdgeShape edge = (EdgeShape)fixture.Shape;
+
+ _debugDraw.DrawSegment(Common.Math.Mul(xf, edge.Vertex1), Common.Math.Mul(xf, edge.Vertex2), color);
+ }
+ break;
+ }
+ }
+
+ private void DrawDebugData()
+ {
+ if (_debugDraw == null)
+ {
+ return;
+ }
+
+ DebugDraw.DrawFlags flags = _debugDraw.Flags;
+
+ if ((flags & DebugDraw.DrawFlags.Shape) != 0)
+ {
+ bool core = (flags & DebugDraw.DrawFlags.CoreShape) == DebugDraw.DrawFlags.CoreShape;
+
+ for (Body b = _bodyList; b != null; b = b.GetNext())
+ {
+ XForm xf = b.GetXForm();
+ for (Fixture f = b.GetFixtureList(); f != null; f = f.Next)
+ {
+ if (b.IsStatic())
+ {
+ DrawFixture(f, xf, new Color(0.5f, 0.9f, 0.5f), core);
+ }
+ else if (b.IsSleeping())
+ {
+ DrawFixture(f, xf, new Color(0.5f, 0.5f, 0.9f), core);
+ }
+ else
+ {
+ DrawFixture(f, xf, new Color(0.9f, 0.9f, 0.9f), core);
+ }
+ }
+ }
+ }
+
+ if ((flags & DebugDraw.DrawFlags.Joint) != 0)
+ {
+ for (Joint j = _jointList; j != null; j = j.GetNext())
+ {
+ if (j.GetType() != JointType.MouseJoint)
+ {
+ DrawJoint(j);
+ }
+ }
+ }
+
+ if ((flags & DebugDraw.DrawFlags.Controller) != 0)
+ {
+ for (Controllers.Controller c = _controllerList; c != null; c = c.GetNext())
+ {
+ c.Draw(_debugDraw);
+ }
+ }
+
+ if ((flags & DebugDraw.DrawFlags.Pair) != 0)
+ {
+ BroadPhase bp = _broadPhase;
+ Vec2 invQ = new Vec2();
+ invQ.Set(1.0f / bp._quantizationFactor.X, 1.0f / bp._quantizationFactor.Y);
+ Color color = new Color(0.9f, 0.9f, 0.3f);
+
+ for (int i = 0; i < PairManager.TableCapacity; ++i)
+ {
+ ushort index = bp._pairManager._hashTable[i];
+ while (index != PairManager.NullPair)
+ {
+ Pair pair = bp._pairManager._pairs[index];
+ Proxy p1 = bp._proxyPool[pair.ProxyId1];
+ Proxy p2 = bp._proxyPool[pair.ProxyId2];
+
+ AABB b1 = new AABB(), b2 = new AABB();
+ b1.LowerBound.X = bp._worldAABB.LowerBound.X + invQ.X * bp._bounds[0][p1.LowerBounds[0]].Value;
+ b1.LowerBound.Y = bp._worldAABB.LowerBound.Y + invQ.Y * bp._bounds[1][p1.LowerBounds[1]].Value;
+ b1.UpperBound.X = bp._worldAABB.LowerBound.X + invQ.X * bp._bounds[0][p1.UpperBounds[0]].Value;
+ b1.UpperBound.Y = bp._worldAABB.LowerBound.Y + invQ.Y * bp._bounds[1][p1.UpperBounds[1]].Value;
+ b2.LowerBound.X = bp._worldAABB.LowerBound.X + invQ.X * bp._bounds[0][p2.LowerBounds[0]].Value;
+ b2.LowerBound.Y = bp._worldAABB.LowerBound.Y + invQ.Y * bp._bounds[1][p2.LowerBounds[1]].Value;
+ b2.UpperBound.X = bp._worldAABB.LowerBound.X + invQ.X * bp._bounds[0][p2.UpperBounds[0]].Value;
+ b2.UpperBound.Y = bp._worldAABB.LowerBound.Y + invQ.Y * bp._bounds[1][p2.UpperBounds[1]].Value;
+
+ Vec2 x1 = 0.5f * (b1.LowerBound + b1.UpperBound);
+ Vec2 x2 = 0.5f * (b2.LowerBound + b2.UpperBound);
+
+ _debugDraw.DrawSegment(x1, x2, color);
+
+ index = pair.Next;
+ }
+ }
+ }
+
+ if ((flags & DebugDraw.DrawFlags.Aabb) != 0)
+ {
+ BroadPhase bp = _broadPhase;
+ Vec2 worldLower = bp._worldAABB.LowerBound;
+ Vec2 worldUpper = bp._worldAABB.UpperBound;
+
+ Vec2 invQ = new Vec2();
+ invQ.Set(1.0f / bp._quantizationFactor.X, 1.0f / bp._quantizationFactor.Y);
+ Color color = new Color(0.9f, 0.3f, 0.9f);
+ for (int i = 0; i < Settings.MaxProxies; ++i)
+ {
+ Proxy p = bp._proxyPool[i];
+ if (p.IsValid == false)
+ {
+ continue;
+ }
+
+ AABB b = new AABB();
+ b.LowerBound.X = worldLower.X + invQ.X * bp._bounds[0][p.LowerBounds[0]].Value;
+ b.LowerBound.Y = worldLower.Y + invQ.Y * bp._bounds[1][p.LowerBounds[1]].Value;
+ b.UpperBound.X = worldLower.X + invQ.X * bp._bounds[0][p.UpperBounds[0]].Value;
+ b.UpperBound.Y = worldLower.Y + invQ.Y * bp._bounds[1][p.UpperBounds[1]].Value;
+
+ Vec2[] vs1 = new Vec2[4];
+ vs1[0].Set(b.LowerBound.X, b.LowerBound.Y);
+ vs1[1].Set(b.UpperBound.X, b.LowerBound.Y);
+ vs1[2].Set(b.UpperBound.X, b.UpperBound.Y);
+ vs1[3].Set(b.LowerBound.X, b.UpperBound.Y);
+
+ _debugDraw.DrawPolygon(vs1, 4, color);
+ }
+
+ Vec2[] vs = new Vec2[4];
+ vs[0].Set(worldLower.X, worldLower.Y);
+ vs[1].Set(worldUpper.X, worldLower.Y);
+ vs[2].Set(worldUpper.X, worldUpper.Y);
+ vs[3].Set(worldLower.X, worldUpper.Y);
+ _debugDraw.DrawPolygon(vs, 4, new Color(0.3f, 0.9f, 0.9f));
+ }
+
+ if ((flags & DebugDraw.DrawFlags.CenterOfMass) != 0)
+ {
+ for (Body b = _bodyList; b != null; b = b.GetNext())
+ {
+ XForm xf = b.GetXForm();
+ xf.Position = b.GetWorldCenter();
+ _debugDraw.DrawXForm(xf);
+ }
+ }
+ }
+
+ //Is it safe to pass private static function pointers?
+ private static float RaycastSortKey(object data)
+ {
+ Fixture fixture = data as Fixture;
+ Box2DXDebug.Assert(fixture != null);
+ Body body = fixture.Body;
+ World world = body.GetWorld();
+
+ if (world._contactFilter != null && !world._contactFilter.RayCollide(world._raycastUserData, fixture))
+ return -1;
+
+ float lambda;
+
+ SegmentCollide collide = fixture.TestSegment(out lambda, out world._raycastNormal, world._raycastSegment, 1);
+
+ if (world._raycastSolidShape && collide == SegmentCollide.MissCollide)
+ return -1;
+ if (!world._raycastSolidShape && collide != SegmentCollide.HitCollide)
+ return -1;
+
+ return lambda;
+ }
+
+ public bool InRange(AABB aabb)
+ {
+ return _broadPhase.InRange(aabb);
+ }
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/World.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/World.cs.meta
new file mode 100644
index 0000000..886be35
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/World.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 23b24b91d3d5f4142af072a2f30d996d
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs b/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs
new file mode 100644
index 0000000..4f7909b
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs
@@ -0,0 +1,240 @@
+/*
+ Box2DX Copyright (c) 2009 Ihar Kalasouski http://code.google.com/p/box2dx
+ Box2D original C++ version Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+using System;
+
+using Box2DX.Common;
+using Box2DX.Collision;
+
+namespace Box2DX.Dynamics
+{
+ /// <summary>
+ /// Joints and shapes are destroyed when their associated
+ /// body is destroyed. Implement this listener so that you
+ /// may nullify references to these joints and shapes.
+ /// </summary>
+ public abstract class DestructionListener
+ {
+ /// <summary>
+ /// Called when any joint is about to be destroyed due
+ /// to the destruction of one of its attached bodies.
+ /// </summary>
+ public abstract void SayGoodbye(Joint joint);
+
+ /// <summary>
+ /// Called when any shape is about to be destroyed due
+ /// to the destruction of its parent body.
+ /// </summary>
+ public abstract void SayGoodbye(Fixture fixture);
+ }
+
+ /// <summary>
+ /// This is called when a body's shape passes outside of the world boundary.
+ /// </summary>
+ public abstract class BoundaryListener
+ {
+ /// <summary>
+ /// This is called for each body that leaves the world boundary.
+ /// @warning you can't modify the world inside this callback.
+ /// </summary>
+ public abstract void Violation(Body body);
+ }
+
+ /// <summary>
+ /// Implement this class to provide collision filtering. In other words, you can implement
+ /// this class if you want finer control over contact creation.
+ /// </summary>
+ public class ContactFilter
+ {
+ /// <summary>
+ /// Return true if contact calculations should be performed between these two shapes.
+ /// If you implement your own collision filter you may want to build from this implementation.
+ /// @warning for performance reasons this is only called when the AABBs begin to overlap.
+ /// </summary>
+ public virtual bool ShouldCollide(Fixture fixtureA, Fixture fixtureB)
+ {
+ FilterData filterA = fixtureA.Filter;
+ FilterData filterB = fixtureB.Filter;
+
+ if (filterA.GroupIndex == filterB.GroupIndex && filterA.GroupIndex != 0)
+ {
+ return filterA.GroupIndex > 0;
+ }
+
+ bool collide = (filterA.MaskBits & filterB.CategoryBits) != 0 && (filterA.CategoryBits & filterB.MaskBits) != 0;
+ return collide;
+ }
+
+ /// <summary>
+ /// Return true if the given shape should be considered for ray intersection.
+ /// </summary>
+ public bool RayCollide(object userData, Fixture fixture)
+ {
+ //By default, cast userData as a shape, and then collide if the shapes would collide
+ if (userData == null)
+ {
+ return true;
+ }
+
+ return ShouldCollide((Fixture)userData, fixture);
+ }
+ }
+
+ /// Contact impulses for reporting. Impulses are used instead of forces because
+ /// sub-step forces may approach infinity for rigid body collisions. These
+ /// match up one-to-one with the contact points in b2Manifold.
+ public class ContactImpulse
+ {
+ public float[] normalImpulses = new float[Settings.MaxManifoldPoints];
+ public float[] tangentImpulses = new float[Settings.MaxManifoldPoints];
+ }
+
+ /// Implement this class to get contact information. You can use these results for
+ /// things like sounds and game logic. You can also get contact results by
+ /// traversing the contact lists after the time step. However, you might miss
+ /// some contacts because continuous physics leads to sub-stepping.
+ /// Additionally you may receive multiple callbacks for the same contact in a
+ /// single time step.
+ /// You should strive to make your callbacks efficient because there may be
+ /// many callbacks per time step.
+ /// @warning You cannot create/destroy Box2DX entities inside these callbacks.
+ public interface ContactListener
+ {
+ /// Called when two fixtures begin to touch.
+ void BeginContact(Contact contact);
+
+ /// Called when two fixtures cease to touch.
+ void EndContact(Contact contact);
+
+ /// This is called after a contact is updated. This allows you to inspect a
+ /// contact before it goes to the solver. If you are careful, you can modify the
+ /// contact manifold (e.g. disable contact).
+ /// A copy of the old manifold is provided so that you can detect changes.
+ /// Note: this is called only for awake bodies.
+ /// Note: this is called even when the number of contact points is zero.
+ /// Note: this is not called for sensors.
+ /// Note: if you set the number of contact points to zero, you will not
+ /// get an EndContact callback. However, you may get a BeginContact callback
+ /// the next step.
+ void PreSolve(Contact contact, Manifold oldManifold);
+
+ /// This lets you inspect a contact after the solver is finished. This is useful
+ /// for inspecting impulses.
+ /// Note: the contact manifold does not include time of impact impulses, which can be
+ /// arbitrarily large if the sub-step is small. Hence the impulse is provided explicitly
+ /// in a separate data structure.
+ /// Note: this is only called for contacts that are touching, solid, and awake.
+ void PostSolve(Contact contact, ContactImpulse impulse);
+ }
+
+ /// <summary>
+ /// Color for debug drawing. Each value has the range [0,1].
+ /// </summary>
+ public struct Color
+ {
+ public float R, G, B;
+
+ public Color(float r, float g, float b)
+ {
+ R = r; G = g; B = b;
+ }
+ public void Set(float r, float g, float b)
+ {
+ R = r; G = g; B = b;
+ }
+ }
+
+ /// <summary>
+ /// Implement and register this class with a b2World to provide debug drawing of physics
+ /// entities in your game.
+ /// </summary>
+ public abstract class DebugDraw
+ {
+ [Flags]
+ public enum DrawFlags
+ {
+ Shape = 0x0001, // draw shapes
+ Joint = 0x0002, // draw joint connections
+ CoreShape = 0x0004, // draw core (TOI) shapes // should be removed in this revision?
+ Aabb = 0x0008, // draw axis aligned bounding boxes
+ Obb = 0x0010, // draw oriented bounding boxes // should be removed in this revision?
+ Pair = 0x0020, // draw broad-phase pairs
+ CenterOfMass = 0x0040, // draw center of mass frame
+ Controller = 0x0080 // draw center of mass frame
+ };
+
+ protected DrawFlags _drawFlags;
+
+ public DebugDraw()
+ {
+ _drawFlags = 0;
+ }
+
+ public DrawFlags Flags { get { return _drawFlags; } set { _drawFlags = value; } }
+
+ /// <summary>
+ /// Append flags to the current flags.
+ /// </summary>
+ public void AppendFlags(DrawFlags flags)
+ {
+ _drawFlags |= flags;
+ }
+
+ /// <summary>
+ /// Clear flags from the current flags.
+ /// </summary>
+ public void ClearFlags(DrawFlags flags)
+ {
+ _drawFlags &= ~flags;
+ }
+
+ /// <summary>
+ /// Draw a closed polygon provided in CCW order.
+ /// </summary>
+ public abstract void DrawPolygon(Vec2[] vertices, int vertexCount, Color color);
+
+ /// <summary>
+ /// Draw a solid closed polygon provided in CCW order.
+ /// </summary>
+ public abstract void DrawSolidPolygon(Vec2[] vertices, int vertexCount, Color color);
+
+ /// <summary>
+ /// Draw a circle.
+ /// </summary>
+ public abstract void DrawCircle(Vec2 center, float radius, Color color);
+
+ /// <summary>
+ /// Draw a solid circle.
+ /// </summary>
+ public abstract void DrawSolidCircle(Vec2 center, float radius, Vec2 axis, Color color);
+
+ /// <summary>
+ /// Draw a line segment.
+ /// </summary>
+ public abstract void DrawSegment(Vec2 p1, Vec2 p2, Color color);
+
+ /// <summary>
+ /// Draw a transform. Choose your own length scale.
+ /// </summary>
+ /// <param name="xf">A transform.</param>
+ public abstract void DrawXForm(XForm xf);
+ }
+}
diff --git a/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs.meta b/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs.meta
new file mode 100644
index 0000000..ff176d9
--- /dev/null
+++ b/Box2d/Assets/Program/Box2d/Dynamics/WorldCallbacks.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 4e6c1ea8b531e954493f5e6f0509a0ed
+MonoImporter:
+ externalObjects: {}
+ serializedVersion: 2
+ defaultReferences: []
+ executionOrder: 0
+ icon: {instanceID: 0}
+ userData:
+ assetBundleName:
+ assetBundleVariant:
diff --git a/Box2d/Assets/Program/Box2d/Rope/Rope.cs b/Box2d/Assets/Program/Box2d/Rope/Rope.cs
deleted file mode 100644
index 85ae672..0000000
--- a/Box2d/Assets/Program/Box2d/Rope/Rope.cs
+++ /dev/null
@@ -1,7 +0,0 @@
-using System.Collections;
-using System.Collections.Generic;
-
-namespace Box2D
-{
-
-}