(61d00a474) v0.9.7.1

This commit is contained in:
Regalis
2020-03-04 13:04:10 +01:00
parent 3c50efa5c9
commit 3c09ebe02f
5086 changed files with 786063 additions and 295871 deletions
@@ -1,4 +1,11 @@
/*
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -26,6 +33,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision
@@ -382,8 +390,8 @@ namespace FarseerPhysics.Collision
/// <param name="aabb">The aabb.</param>
public void Combine(ref AABB aabb)
{
LowerBound = Vector2.Min(LowerBound, aabb.LowerBound);
UpperBound = Vector2.Max(UpperBound, aabb.UpperBound);
Vector2.Min(ref LowerBound, ref aabb.LowerBound, out LowerBound);
Vector2.Max(ref UpperBound, ref aabb.UpperBound, out UpperBound);
}
/// <summary>
@@ -393,8 +401,8 @@ namespace FarseerPhysics.Collision
/// <param name="aabb2">The aabb2.</param>
public void Combine(ref AABB aabb1, ref AABB aabb2)
{
LowerBound = Vector2.Min(aabb1.LowerBound, aabb2.LowerBound);
UpperBound = Vector2.Max(aabb1.UpperBound, aabb2.UpperBound);
Vector2.Min(ref aabb1.LowerBound, ref aabb2.LowerBound, out LowerBound);
Vector2.Max(ref aabb1.UpperBound, ref aabb2.UpperBound, out UpperBound);
}
/// <summary>
@@ -434,15 +442,13 @@ namespace FarseerPhysics.Collision
/// <param name="a">The first AABB.</param>
/// <param name="b">The second AABB.</param>
/// <returns>True if they are overlapping.</returns>
public static bool TestOverlap(ref AABB a, ref AABB b)
{
if (b.LowerBound.X - a.UpperBound.X > 0.0f ||
b.LowerBound.Y - a.UpperBound.Y > 0.0f ||
a.LowerBound.X - b.UpperBound.X > 0.0f ||
a.LowerBound.Y - b.UpperBound.Y > 0.0f) return false;
return true;
return
b.LowerBound.X - a.UpperBound.X <= 0.0f &&
b.LowerBound.Y - a.UpperBound.Y <= 0.0f &&
a.LowerBound.X - b.UpperBound.X <= 0.0f &&
a.LowerBound.Y - b.UpperBound.Y <= 0.0f;
}
/// <summary>
@@ -537,16 +543,6 @@ namespace FarseerPhysics.Collision
}
}
/// <summary>
/// This holds polygon B expressed in frame A.
/// </summary>
public class TempPolygon
{
public Vector2[] Vertices = new Vector2[Settings.MaxPolygonVertices];
public Vector2[] Normals = new Vector2[Settings.MaxPolygonVertices];
public int Count;
}
/// <summary>
/// This structure is used to keep track of the best separating axis.
/// </summary>
@@ -587,9 +583,6 @@ namespace FarseerPhysics.Collision
/// </summary>
public static class Collision
{
[ThreadStatic]
private static DistanceInput _input;
/// <summary>
/// Test overlap between the two shapes.
/// </summary>
@@ -602,9 +595,9 @@ namespace FarseerPhysics.Collision
/// <returns></returns>
public static bool TestOverlap(Shape shapeA, int indexA, Shape shapeB, int indexB, ref Transform xfA, ref Transform xfB)
{
_input = _input ?? new DistanceInput();
_input.ProxyA.Set(shapeA, indexA);
_input.ProxyB.Set(shapeB, indexB);
DistanceInput _input = new DistanceInput();
_input.ProxyA = new DistanceProxy(shapeA, indexA);
_input.ProxyB = new DistanceProxy(shapeB, indexB);
_input.TransformA = xfA;
_input.TransformB = xfB;
_input.UseRadii = true;
@@ -663,8 +656,8 @@ namespace FarseerPhysics.Collision
{
manifold.PointCount = 0;
Vector2 pA = MathUtils.Mul(ref xfA, circleA.Position);
Vector2 pB = MathUtils.Mul(ref xfB, circleB.Position);
Vector2 pA = Transform.Multiply(ref circleA._position, ref xfA);
Vector2 pB = Transform.Multiply(ref circleB._position, ref xfB);
Vector2 d = pB - pA;
float distSqr = Vector2.Dot(d, d);
@@ -700,8 +693,8 @@ namespace FarseerPhysics.Collision
manifold.PointCount = 0;
// Compute circle position in the frame of the polygon.
Vector2 c = MathUtils.Mul(ref xfB, circleB.Position);
Vector2 cLocal = MathUtils.MulT(ref xfA, c);
Vector2 c = Transform.Multiply(ref circleB._position, ref xfB);
Vector2 cLocal = Transform.Divide(ref c, ref xfA);
// Find the min separating edge.
int normalIndex = 0;
@@ -902,13 +895,13 @@ namespace FarseerPhysics.Collision
Vector2 localNormal = new Vector2(localTangent.Y, -localTangent.X);
Vector2 planePoint = 0.5f * (v11 + v12);
Vector2 tangent = MathUtils.Mul(xf1.q, localTangent);
Vector2 tangent = Complex.Multiply(ref localTangent, ref xf1.q);
float normalx = tangent.Y;
float normaly = -tangent.X;
v11 = MathUtils.Mul(ref xf1, v11);
v12 = MathUtils.Mul(ref xf1, v12);
v11 = Transform.Multiply(ref v11, ref xf1);
v12 = Transform.Multiply(ref v12, ref xf1);
// Face offset.
float frontOffset = normalx * v11.X + normaly * v11.Y;
@@ -948,7 +941,7 @@ namespace FarseerPhysics.Collision
if (separation <= totalRadius)
{
ManifoldPoint cp = manifold.Points[pointCount];
cp.LocalPoint = MathUtils.MulT(ref xf2, clipPoints2[i].V);
Transform.Divide(clipPoints2[i].V, ref xf2, out cp.LocalPoint);
cp.Id = clipPoints2[i].ID;
if (flip)
@@ -984,7 +977,7 @@ namespace FarseerPhysics.Collision
manifold.PointCount = 0;
// Compute circle in frame of edge
Vector2 Q = MathUtils.MulT(ref transformA, MathUtils.Mul(ref transformB, ref circleB._position));
Vector2 Q = Transform.Divide(Transform.Multiply(ref circleB._position, ref transformB), ref transformA);
Vector2 A = edgeA.Vertex1, B = edgeA.Vertex2;
Vector2 e = B - A;
@@ -1126,24 +1119,29 @@ namespace FarseerPhysics.Collision
/// <param name="xfB">The xf B.</param>
public static void CollideEdgeAndPolygon(ref Manifold manifold, EdgeShape edgeA, ref Transform xfA, PolygonShape polygonB, ref Transform xfB)
{
EPCollider collider = new EPCollider();
collider.Collide(ref manifold, edgeA, ref xfA, polygonB, ref xfB);
EPCollider.Collide(ref manifold, edgeA, ref xfA, polygonB, ref xfB);
}
private class EPCollider
private static class EPCollider
{
private TempPolygon _polygonB = new TempPolygon();
/// <summary>
/// This holds polygon B expressed in frame A.
/// </summary>
internal struct TempPolygon
{
public Vector2[] Vertices;
public Vector2[] Normals;
public int Count;
Transform _xf;
Vector2 _centroidB;
Vector2 _v0, _v1, _v2, _v3;
Vector2 _normal0, _normal1, _normal2;
Vector2 _normal;
Vector2 _lowerLimit, _upperLimit;
float _radius;
bool _front;
internal TempPolygon(int maxPolygonVertices)
{
Vertices = new Vector2[maxPolygonVertices];
Normals = new Vector2[maxPolygonVertices];
Count = 0;
}
}
public void Collide(ref Manifold manifold, EdgeShape edgeA, ref Transform xfA, PolygonShape polygonB, ref Transform xfB)
public static void Collide(ref Manifold manifold, EdgeShape edgeA, ref Transform xfA, PolygonShape polygonB, ref Transform xfB)
{
// Algorithm:
// 1. Classify v1 and v2
@@ -1155,43 +1153,54 @@ namespace FarseerPhysics.Collision
// 7. Return if _any_ axis indicates separation
// 8. Clip
_xf = MathUtils.MulT(xfA, xfB);
TempPolygon tempPolygonB = new TempPolygon(Settings.MaxPolygonVertices);
Transform xf;
Vector2 centroidB;
Vector2 normal0 = new Vector2();
Vector2 normal1;
Vector2 normal2 = new Vector2();
Vector2 normal;
Vector2 lowerLimit, upperLimit;
float radius;
bool front;
_centroidB = MathUtils.Mul(ref _xf, polygonB.MassData.Centroid);
Transform.Divide(ref xfB, ref xfA, out xf);
_v0 = edgeA.Vertex0;
_v1 = edgeA._vertex1;
_v2 = edgeA._vertex2;
_v3 = edgeA.Vertex3;
centroidB = Transform.Multiply(polygonB.MassData.Centroid, ref xf);
Vector2 v0 = edgeA.Vertex0;
Vector2 v1 = edgeA._vertex1;
Vector2 v2 = edgeA._vertex2;
Vector2 v3 = edgeA.Vertex3;
bool hasVertex0 = edgeA.HasVertex0;
bool hasVertex3 = edgeA.HasVertex3;
Vector2 edge1 = _v2 - _v1;
Vector2 edge1 = v2 - v1;
edge1.Normalize();
_normal1 = new Vector2(edge1.Y, -edge1.X);
float offset1 = Vector2.Dot(_normal1, _centroidB - _v1);
normal1 = new Vector2(edge1.Y, -edge1.X);
float offset1 = Vector2.Dot(normal1, centroidB - v1);
float offset0 = 0.0f, offset2 = 0.0f;
bool convex1 = false, convex2 = false;
// Is there a preceding edge?
if (hasVertex0)
{
Vector2 edge0 = _v1 - _v0;
Vector2 edge0 = v1 - v0;
edge0.Normalize();
_normal0 = new Vector2(edge0.Y, -edge0.X);
convex1 = MathUtils.Cross(edge0, edge1) >= 0.0f;
offset0 = Vector2.Dot(_normal0, _centroidB - _v0);
normal0 = new Vector2(edge0.Y, -edge0.X);
convex1 = MathUtils.Cross(ref edge0, ref edge1) >= 0.0f;
offset0 = Vector2.Dot(normal0, centroidB - v0);
}
// Is there a following edge?
if (hasVertex3)
{
Vector2 edge2 = _v3 - _v2;
Vector2 edge2 = v3 - v2;
edge2.Normalize();
_normal2 = new Vector2(edge2.Y, -edge2.X);
convex2 = MathUtils.Cross(edge1, edge2) > 0.0f;
offset2 = Vector2.Dot(_normal2, _centroidB - _v2);
normal2 = new Vector2(edge2.Y, -edge2.X);
convex2 = MathUtils.Cross(ref edge1, ref edge2) > 0.0f;
offset2 = Vector2.Dot(normal2, centroidB - v2);
}
// Determine front or back collision. Determine collision normal limits.
@@ -1199,66 +1208,66 @@ namespace FarseerPhysics.Collision
{
if (convex1 && convex2)
{
_front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
if (_front)
front = offset0 >= 0.0f || offset1 >= 0.0f || offset2 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = _normal0;
_upperLimit = _normal2;
normal = normal1;
lowerLimit = normal0;
upperLimit = normal2;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal1;
_upperLimit = -_normal1;
normal = -normal1;
lowerLimit = -normal1;
upperLimit = -normal1;
}
}
else if (convex1)
{
_front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
if (_front)
front = offset0 >= 0.0f || (offset1 >= 0.0f && offset2 >= 0.0f);
if (front)
{
_normal = _normal1;
_lowerLimit = _normal0;
_upperLimit = _normal1;
normal = normal1;
lowerLimit = normal0;
upperLimit = normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal2;
_upperLimit = -_normal1;
normal = -normal1;
lowerLimit = -normal2;
upperLimit = -normal1;
}
}
else if (convex2)
{
_front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
if (_front)
front = offset2 >= 0.0f || (offset0 >= 0.0f && offset1 >= 0.0f);
if (front)
{
_normal = _normal1;
_lowerLimit = _normal1;
_upperLimit = _normal2;
normal = normal1;
lowerLimit = normal1;
upperLimit = normal2;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal1;
_upperLimit = -_normal0;
normal = -normal1;
lowerLimit = -normal1;
upperLimit = -normal0;
}
}
else
{
_front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
if (_front)
front = offset0 >= 0.0f && offset1 >= 0.0f && offset2 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = _normal1;
_upperLimit = _normal1;
normal = normal1;
lowerLimit = normal1;
upperLimit = normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal2;
_upperLimit = -_normal0;
normal = -normal1;
lowerLimit = -normal2;
upperLimit = -normal0;
}
}
}
@@ -1266,34 +1275,34 @@ namespace FarseerPhysics.Collision
{
if (convex1)
{
_front = offset0 >= 0.0f || offset1 >= 0.0f;
if (_front)
front = offset0 >= 0.0f || offset1 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = _normal0;
_upperLimit = -_normal1;
normal = normal1;
lowerLimit = normal0;
upperLimit = -normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = _normal1;
_upperLimit = -_normal1;
normal = -normal1;
lowerLimit = normal1;
upperLimit = -normal1;
}
}
else
{
_front = offset0 >= 0.0f && offset1 >= 0.0f;
if (_front)
front = offset0 >= 0.0f && offset1 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = _normal1;
_upperLimit = -_normal1;
normal = normal1;
lowerLimit = normal1;
upperLimit = -normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = _normal1;
_upperLimit = -_normal0;
normal = -normal1;
lowerLimit = normal1;
upperLimit = -normal0;
}
}
}
@@ -1301,67 +1310,67 @@ namespace FarseerPhysics.Collision
{
if (convex2)
{
_front = offset1 >= 0.0f || offset2 >= 0.0f;
if (_front)
front = offset1 >= 0.0f || offset2 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = -_normal1;
_upperLimit = _normal2;
normal = normal1;
lowerLimit = -normal1;
upperLimit = normal2;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal1;
_upperLimit = _normal1;
normal = -normal1;
lowerLimit = -normal1;
upperLimit = normal1;
}
}
else
{
_front = offset1 >= 0.0f && offset2 >= 0.0f;
if (_front)
front = offset1 >= 0.0f && offset2 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = -_normal1;
_upperLimit = _normal1;
normal = normal1;
lowerLimit = -normal1;
upperLimit = normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = -_normal2;
_upperLimit = _normal1;
normal = -normal1;
lowerLimit = -normal2;
upperLimit = normal1;
}
}
}
else
{
_front = offset1 >= 0.0f;
if (_front)
front = offset1 >= 0.0f;
if (front)
{
_normal = _normal1;
_lowerLimit = -_normal1;
_upperLimit = -_normal1;
normal = normal1;
lowerLimit = -normal1;
upperLimit = -normal1;
}
else
{
_normal = -_normal1;
_lowerLimit = _normal1;
_upperLimit = _normal1;
normal = -normal1;
lowerLimit = normal1;
upperLimit = normal1;
}
}
// Get polygonB in frameA
_polygonB.Count = polygonB.Vertices.Count;
tempPolygonB.Count = polygonB.Vertices.Count;
for (int i = 0; i < polygonB.Vertices.Count; ++i)
{
_polygonB.Vertices[i] = MathUtils.Mul(ref _xf, polygonB.Vertices[i]);
_polygonB.Normals[i] = MathUtils.Mul(_xf.q, polygonB.Normals[i]);
tempPolygonB.Vertices[i] = Transform.Multiply(polygonB.Vertices[i], ref xf);
tempPolygonB.Normals[i] = Complex.Multiply(polygonB.Normals[i], ref xf.q);
}
_radius = 2.0f * Settings.PolygonRadius;
radius = 2.0f * Settings.PolygonRadius;
manifold.PointCount = 0;
EPAxis edgeAxis = ComputeEdgeSeparation();
EPAxis edgeAxis = ComputeEdgeSeparation(ref tempPolygonB, ref normal, ref v1, front);
// If no valid normal can be found than this edge should not collide.
if (edgeAxis.Type == EPAxisType.Unknown)
@@ -1369,13 +1378,13 @@ namespace FarseerPhysics.Collision
return;
}
if (edgeAxis.Separation > _radius)
if (edgeAxis.Separation > radius)
{
return;
}
EPAxis polygonAxis = ComputePolygonSeparation();
if (polygonAxis.Type != EPAxisType.Unknown && polygonAxis.Separation > _radius)
EPAxis polygonAxis = ComputePolygonSeparation(ref tempPolygonB, ref normal, ref v1, ref v2, ref lowerLimit, ref upperLimit, radius);
if (polygonAxis.Type != EPAxisType.Unknown && polygonAxis.Separation > radius)
{
return;
}
@@ -1406,10 +1415,10 @@ namespace FarseerPhysics.Collision
// Search for the polygon normal that is most anti-parallel to the edge normal.
int bestIndex = 0;
float bestValue = Vector2.Dot(_normal, _polygonB.Normals[0]);
for (int i = 1; i < _polygonB.Count; ++i)
float bestValue = Vector2.Dot(normal, tempPolygonB.Normals[0]);
for (int i = 1; i < tempPolygonB.Count; ++i)
{
float value = Vector2.Dot(_normal, _polygonB.Normals[i]);
float value = Vector2.Dot(normal, tempPolygonB.Normals[i]);
if (value < bestValue)
{
bestValue = value;
@@ -1418,10 +1427,10 @@ namespace FarseerPhysics.Collision
}
int i1 = bestIndex;
int i2 = i1 + 1 < _polygonB.Count ? i1 + 1 : 0;
int i2 = i1 + 1 < tempPolygonB.Count ? i1 + 1 : 0;
ClipVertex c0 = ie[0];
c0.V = _polygonB.Vertices[i1];
c0.V = tempPolygonB.Vertices[i1];
c0.ID.Features.IndexA = 0;
c0.ID.Features.IndexB = (byte)i1;
c0.ID.Features.TypeA = (byte)ContactFeatureType.Face;
@@ -1429,35 +1438,35 @@ namespace FarseerPhysics.Collision
ie[0] = c0;
ClipVertex c1 = ie[1];
c1.V = _polygonB.Vertices[i2];
c1.V = tempPolygonB.Vertices[i2];
c1.ID.Features.IndexA = 0;
c1.ID.Features.IndexB = (byte)i2;
c1.ID.Features.TypeA = (byte)ContactFeatureType.Face;
c1.ID.Features.TypeB = (byte)ContactFeatureType.Vertex;
ie[1] = c1;
if (_front)
if (front)
{
rf.i1 = 0;
rf.i2 = 1;
rf.v1 = _v1;
rf.v2 = _v2;
rf.normal = _normal1;
rf.v1 = v1;
rf.v2 = v2;
rf.normal = normal1;
}
else
{
rf.i1 = 1;
rf.i2 = 0;
rf.v1 = _v2;
rf.v2 = _v1;
rf.normal = -_normal1;
rf.v1 = v2;
rf.v2 = v1;
rf.normal = -normal1;
}
}
else
{
manifold.Type = ManifoldType.FaceB;
ClipVertex c0 = ie[0];
c0.V = _v1;
c0.V = v1;
c0.ID.Features.IndexA = 0;
c0.ID.Features.IndexB = (byte)primaryAxis.Index;
c0.ID.Features.TypeA = (byte)ContactFeatureType.Vertex;
@@ -1465,7 +1474,7 @@ namespace FarseerPhysics.Collision
ie[0] = c0;
ClipVertex c1 = ie[1];
c1.V = _v2;
c1.V = v2;
c1.ID.Features.IndexA = 0;
c1.ID.Features.IndexB = (byte)primaryAxis.Index;
c1.ID.Features.TypeA = (byte)ContactFeatureType.Vertex;
@@ -1473,10 +1482,10 @@ namespace FarseerPhysics.Collision
ie[1] = c1;
rf.i1 = primaryAxis.Index;
rf.i2 = rf.i1 + 1 < _polygonB.Count ? rf.i1 + 1 : 0;
rf.v1 = _polygonB.Vertices[rf.i1];
rf.v2 = _polygonB.Vertices[rf.i2];
rf.normal = _polygonB.Normals[rf.i1];
rf.i2 = rf.i1 + 1 < tempPolygonB.Count ? rf.i1 + 1 : 0;
rf.v1 = tempPolygonB.Vertices[rf.i1];
rf.v2 = tempPolygonB.Vertices[rf.i2];
rf.normal = tempPolygonB.Normals[rf.i1];
}
rf.sideNormal1 = new Vector2(rf.normal.Y, -rf.normal.X);
@@ -1522,13 +1531,13 @@ namespace FarseerPhysics.Collision
{
float separation = Vector2.Dot(rf.normal, clipPoints2[i].V - rf.v1);
if (separation <= _radius)
if (separation <= radius)
{
ManifoldPoint cp = manifold.Points[pointCount];
if (primaryAxis.Type == EPAxisType.EdgeA)
{
cp.LocalPoint = MathUtils.MulT(ref _xf, clipPoints2[i].V);
Transform.Divide(clipPoints2[i].V, ref xf, out cp.LocalPoint);
cp.Id = clipPoints2[i].ID;
}
else
@@ -1548,16 +1557,16 @@ namespace FarseerPhysics.Collision
manifold.PointCount = pointCount;
}
private EPAxis ComputeEdgeSeparation()
private static EPAxis ComputeEdgeSeparation(ref TempPolygon polygonB, ref Vector2 normal, ref Vector2 v1, bool front)
{
EPAxis axis;
axis.Type = EPAxisType.EdgeA;
axis.Index = _front ? 0 : 1;
axis.Index = front ? 0 : 1;
axis.Separation = Settings.MaxFloat;
for (int i = 0; i < _polygonB.Count; ++i)
for (int i = 0; i < polygonB.Count; ++i)
{
float s = Vector2.Dot(_normal, _polygonB.Vertices[i] - _v1);
float s = Vector2.Dot(normal, polygonB.Vertices[i] - v1);
if (s < axis.Separation)
{
axis.Separation = s;
@@ -1567,24 +1576,24 @@ namespace FarseerPhysics.Collision
return axis;
}
private EPAxis ComputePolygonSeparation()
private static EPAxis ComputePolygonSeparation(ref TempPolygon polygonB, ref Vector2 normal, ref Vector2 v1, ref Vector2 v2, ref Vector2 lowerLimit, ref Vector2 upperLimit, float radius)
{
EPAxis axis;
axis.Type = EPAxisType.Unknown;
axis.Index = -1;
axis.Separation = -Settings.MaxFloat;
Vector2 perp = new Vector2(-_normal.Y, _normal.X);
Vector2 perp = new Vector2(-normal.Y, normal.X);
for (int i = 0; i < _polygonB.Count; ++i)
for (int i = 0; i < polygonB.Count; ++i)
{
Vector2 n = -_polygonB.Normals[i];
Vector2 n = -polygonB.Normals[i];
float s1 = Vector2.Dot(n, _polygonB.Vertices[i] - _v1);
float s2 = Vector2.Dot(n, _polygonB.Vertices[i] - _v2);
float s1 = Vector2.Dot(n, polygonB.Vertices[i] - v1);
float s2 = Vector2.Dot(n, polygonB.Vertices[i] - v2);
float s = Math.Min(s1, s2);
if (s > _radius)
if (s > radius)
{
// No collision
axis.Type = EPAxisType.EdgeB;
@@ -1596,14 +1605,14 @@ namespace FarseerPhysics.Collision
// Adjacency
if (Vector2.Dot(n, perp) >= 0.0f)
{
if (Vector2.Dot(n - _upperLimit, _normal) < -Settings.AngularSlop)
if (Vector2.Dot(n - upperLimit, normal) < -Settings.AngularSlop)
{
continue;
}
}
else
{
if (Vector2.Dot(n - _lowerLimit, _normal) < -Settings.AngularSlop)
if (Vector2.Dot(n - lowerLimit, normal) < -Settings.AngularSlop)
{
continue;
}
@@ -1682,7 +1691,7 @@ namespace FarseerPhysics.Collision
/// <param name="poly2">The poly2.</param>
/// <param name="xf2">The XF2.</param>
/// <returns></returns>
private static float EdgeSeparation(PolygonShape poly1, ref Transform xf1, int edge1, PolygonShape poly2, ref Transform xf2)
private static float EdgeSeparation(PolygonShape poly1, ref Transform xf1To2, int edge1, PolygonShape poly2)
{
List<Vector2> vertices1 = poly1.Vertices;
List<Vector2> normals1 = poly1.Normals;
@@ -1693,8 +1702,7 @@ namespace FarseerPhysics.Collision
Debug.Assert(0 <= edge1 && edge1 < poly1.Vertices.Count);
// Convert normal from poly1's frame into poly2's frame.
Vector2 normal1World = MathUtils.Mul(xf1.q, normals1[edge1]);
Vector2 normal1 = MathUtils.MulT(xf2.q, normal1World);
Vector2 normal1 = Complex.Multiply(normals1[edge1], ref xf1To2.q);
// Find support vertex on poly2 for -normal.
int index = 0;
@@ -1702,7 +1710,7 @@ namespace FarseerPhysics.Collision
for (int i = 0; i < count2; ++i)
{
float dot = Vector2.Dot(vertices2[i], normal1);
float dot = MathUtils.Dot(vertices2[i], ref normal1);
if (dot < minDot)
{
minDot = dot;
@@ -1710,9 +1718,10 @@ namespace FarseerPhysics.Collision
}
}
Vector2 v1 = MathUtils.Mul(ref xf1, vertices1[edge1]);
Vector2 v2 = MathUtils.Mul(ref xf2, vertices2[index]);
float separation = Vector2.Dot(v2 - v1, normal1World);
Vector2 v1 = Transform.Multiply(vertices1[edge1], ref xf1To2);
Vector2 v2 = vertices2[index];
float separation = MathUtils.Dot(v2 - v1, ref normal1);
return separation;
}
@@ -1730,16 +1739,18 @@ namespace FarseerPhysics.Collision
int count1 = poly1.Vertices.Count;
List<Vector2> normals1 = poly1.Normals;
var xf1To2 = Transform.Divide(ref xf1, ref xf2);
// Vector pointing from the centroid of poly1 to the centroid of poly2.
Vector2 d = MathUtils.Mul(ref xf2, poly2.MassData.Centroid) - MathUtils.Mul(ref xf1, poly1.MassData.Centroid);
Vector2 dLocal1 = MathUtils.MulT(xf1.q, d);
Vector2 c2local = Transform.Divide(poly2.MassData.Centroid, ref xf1To2);
Vector2 dLocal1 = c2local - poly1.MassData.Centroid;
// Find edge normal on poly1 that has the largest projection onto d.
int edge = 0;
float maxDot = -Settings.MaxFloat;
for (int i = 0; i < count1; ++i)
{
float dot = Vector2.Dot(normals1[i], dLocal1);
float dot = MathUtils.Dot(normals1[i], ref dLocal1);
if (dot > maxDot)
{
maxDot = dot;
@@ -1748,15 +1759,15 @@ namespace FarseerPhysics.Collision
}
// Get the separation for the edge normal.
float s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
float s = EdgeSeparation(poly1, ref xf1To2, edge, poly2);
// Check the separation for the previous edge normal.
int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1;
float sPrev = EdgeSeparation(poly1, ref xf1, prevEdge, poly2, ref xf2);
float sPrev = EdgeSeparation(poly1, ref xf1To2, prevEdge, poly2);
// Check the separation for the next edge normal.
int nextEdge = edge + 1 < count1 ? edge + 1 : 0;
float sNext = EdgeSeparation(poly1, ref xf1, nextEdge, poly2, ref xf2);
float sNext = EdgeSeparation(poly1, ref xf1To2, nextEdge, poly2);
// Find the best edge and the search direction.
int bestEdge;
@@ -1788,7 +1799,7 @@ namespace FarseerPhysics.Collision
else
edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0;
s = EdgeSeparation(poly1, ref xf1, edge, poly2, ref xf2);
s = EdgeSeparation(poly1, ref xf1To2, edge, poly2);
if (s > bestSeparation)
{
@@ -1817,7 +1828,7 @@ namespace FarseerPhysics.Collision
Debug.Assert(0 <= edge1 && edge1 < poly1.Vertices.Count);
// Get the normal of the reference edge in poly2's frame.
Vector2 normal1 = MathUtils.MulT(xf2.q, MathUtils.Mul(xf1.q, normals1[edge1]));
Vector2 normal1 = Complex.Divide(Complex.Multiply(normals1[edge1], ref xf1.q), ref xf2.q);
// Find the incident edge on poly2.
@@ -1839,7 +1850,7 @@ namespace FarseerPhysics.Collision
ClipVertex cv0 = c[0];
cv0.V = MathUtils.Mul(ref xf2, vertices2[i1]);
cv0.V = Transform.Multiply(vertices2[i1], ref xf2);
cv0.ID.Features.IndexA = (byte)edge1;
cv0.ID.Features.IndexB = (byte)i1;
cv0.ID.Features.TypeA = (byte)ContactFeatureType.Face;
@@ -1848,7 +1859,7 @@ namespace FarseerPhysics.Collision
c[0] = cv0;
ClipVertex cv1 = c[1];
cv1.V = MathUtils.Mul(ref xf2, vertices2[i2]);
cv1.V = Transform.Multiply(vertices2[i2], ref xf2);
cv1.ID.Features.IndexA = (byte)edge1;
cv1.ID.Features.IndexB = (byte)i2;
cv1.ID.Features.TypeA = (byte)ContactFeatureType.Face;
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -24,6 +29,7 @@ using System;
using System.Diagnostics;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision
@@ -32,10 +38,10 @@ namespace FarseerPhysics.Collision
/// A distance proxy is used by the GJK algorithm.
/// It encapsulates any shape.
/// </summary>
public class DistanceProxy
public struct DistanceProxy
{
internal float Radius;
internal Vertices Vertices = new Vertices();
internal Vertices Vertices;
// GJK using Voronoi regions (Christer Ericson) and Barycentric coordinates.
@@ -45,8 +51,10 @@ namespace FarseerPhysics.Collision
/// </summary>
/// <param name="shape">The shape.</param>
/// <param name="index">The index.</param>
public void Set(Shape shape, int index)
public DistanceProxy(Shape shape, int index)
{
Vertices = new Vertices();
switch (shape.ShapeType)
{
case ShapeType.Circle:
@@ -93,6 +101,7 @@ namespace FarseerPhysics.Collision
break;
default:
Radius = 0;
Debug.Assert(false);
break;
}
@@ -171,10 +180,10 @@ namespace FarseerPhysics.Collision
/// Input for Distance.ComputeDistance().
/// You have to option to use the shape radii in the computation.
/// </summary>
public class DistanceInput
public struct DistanceInput
{
public DistanceProxy ProxyA = new DistanceProxy();
public DistanceProxy ProxyB = new DistanceProxy();
public DistanceProxy ProxyA;
public DistanceProxy ProxyB;
public Transform TransformA;
public Transform TransformB;
public bool UseRadii;
@@ -241,7 +250,7 @@ namespace FarseerPhysics.Collision
internal int Count;
internal FixedArray3<SimplexVertex> V;
internal void ReadCache(ref SimplexCache cache, DistanceProxy proxyA, ref Transform transformA, DistanceProxy proxyB, ref Transform transformB)
internal void ReadCache(ref SimplexCache cache, ref DistanceProxy proxyA, ref Transform transformA, ref DistanceProxy proxyB, ref Transform transformB)
{
Debug.Assert(cache.Count <= 3);
@@ -254,8 +263,8 @@ namespace FarseerPhysics.Collision
v.IndexB = cache.IndexB[i];
Vector2 wALocal = proxyA.Vertices[v.IndexA];
Vector2 wBLocal = proxyB.Vertices[v.IndexB];
v.WA = MathUtils.Mul(ref transformA, wALocal);
v.WB = MathUtils.Mul(ref transformB, wBLocal);
v.WA = Transform.Multiply(ref wALocal, ref transformA);
v.WB = Transform.Multiply(ref wBLocal, ref transformB);
v.W = v.WB - v.WA;
v.A = 0.0f;
V[i] = v;
@@ -282,8 +291,8 @@ namespace FarseerPhysics.Collision
v.IndexB = 0;
Vector2 wALocal = proxyA.Vertices[0];
Vector2 wBLocal = proxyB.Vertices[0];
v.WA = MathUtils.Mul(ref transformA, wALocal);
v.WB = MathUtils.Mul(ref transformB, wBLocal);
v.WA = Transform.Multiply(ref wALocal, ref transformA);
v.WB = Transform.Multiply(ref wBLocal, ref transformB);
v.W = v.WB - v.WA;
v.A = 1.0f;
V[0] = v;
@@ -514,11 +523,11 @@ namespace FarseerPhysics.Collision
float d23_2 = -w2e23;
// Triangle123
float n123 = MathUtils.Cross(e12, e13);
float n123 = MathUtils.Cross(ref e12, ref e13);
float d123_1 = n123 * MathUtils.Cross(w2, w3);
float d123_2 = n123 * MathUtils.Cross(w3, w1);
float d123_3 = n123 * MathUtils.Cross(w1, w2);
float d123_1 = n123 * MathUtils.Cross(ref w2, ref w3);
float d123_2 = n123 * MathUtils.Cross(ref w3, ref w1);
float d123_3 = n123 * MathUtils.Cross(ref w1, ref w2);
// w1 region
if (d12_2 <= 0.0f && d13_2 <= 0.0f)
@@ -646,7 +655,7 @@ namespace FarseerPhysics.Collision
// Initialize the simplex.
Simplex simplex = new Simplex();
simplex.ReadCache(ref cache, input.ProxyA, ref input.TransformA, input.ProxyB, ref input.TransformB);
simplex.ReadCache(ref cache, ref input.ProxyA, ref input.TransformA, ref input.ProxyB, ref input.TransformB);
// These store the vertices of the last simplex so that we
// can check for duplicates and prevent cycling.
@@ -717,11 +726,11 @@ namespace FarseerPhysics.Collision
// Compute a tentative new simplex vertex using support points.
SimplexVertex vertex = simplex.V[simplex.Count];
vertex.IndexA = input.ProxyA.GetSupport(MathUtils.MulT(input.TransformA.q, -d));
vertex.WA = MathUtils.Mul(ref input.TransformA, input.ProxyA.Vertices[vertex.IndexA]);
vertex.IndexA = input.ProxyA.GetSupport(-Complex.Divide(ref d, ref input.TransformA.q));
vertex.WA = Transform.Multiply(input.ProxyA.Vertices[vertex.IndexA], ref input.TransformA);
vertex.IndexB = input.ProxyB.GetSupport(MathUtils.MulT(input.TransformB.q, d));
vertex.WB = MathUtils.Mul(ref input.TransformB, input.ProxyB.Vertices[vertex.IndexB]);
vertex.IndexB = input.ProxyB.GetSupport( Complex.Divide(ref d, ref input.TransformB.q));
vertex.WB = Transform.Multiply(input.ProxyB.Vertices[vertex.IndexB], ref input.TransformB);
vertex.W = vertex.WB - vertex.WA;
simplex.V[simplex.Count] = vertex;
@@ -1,4 +1,11 @@
/*
// Copyright (c) 2018 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -24,6 +31,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision
@@ -31,7 +39,7 @@ namespace FarseerPhysics.Collision
/// <summary>
/// A node in the dynamic tree. The client does not interact with this directly.
/// </summary>
internal class TreeNode<T>
internal struct TreeNode<T>
{
/// <summary>
/// Enlarged AABB
@@ -41,8 +49,12 @@ namespace FarseerPhysics.Collision
internal int Child1;
internal int Child2;
// leaf = 0, free node = -1
internal int Height;
internal int ParentOrNext;
public object Body;
internal T UserData;
internal bool IsLeaf()
@@ -85,13 +97,11 @@ namespace FarseerPhysics.Collision
// Build a linked list for the free list.
for (int i = 0; i < _nodeCapacity - 1; ++i)
{
_nodes[i] = new TreeNode<T>();
_nodes[i].ParentOrNext = i + 1;
_nodes[i].Height = 1;
_nodes[i].Height = -1;
}
_nodes[_nodeCapacity - 1] = new TreeNode<T>();
_nodes[_nodeCapacity - 1].ParentOrNext = NullNode;
_nodes[_nodeCapacity - 1].Height = 1;
_nodes[_nodeCapacity - 1].Height = -1;
_freeList = 0;
}
@@ -123,20 +133,20 @@ namespace FarseerPhysics.Collision
return 0.0f;
}
TreeNode<T> root = _nodes[_root];
float rootArea = root.AABB.Perimeter;
//TreeNode<T>* root = &_nodes[_root];
float rootArea = _nodes[_root].AABB.Perimeter;
float totalArea = 0.0f;
for (int i = 0; i < _nodeCapacity; ++i)
{
TreeNode<T> node = _nodes[i];
if (node.Height < 0)
//TreeNode<T>* node = &_nodes[i];
if (_nodes[i].Height < 0)
{
// Free node in pool
continue;
}
totalArea += node.AABB.Perimeter;
totalArea += _nodes[i].AABB.Perimeter;
}
return totalArea / rootArea;
@@ -154,16 +164,16 @@ namespace FarseerPhysics.Collision
int maxBalance = 0;
for (int i = 0; i < _nodeCapacity; ++i)
{
TreeNode<T> node = _nodes[i];
if (node.Height <= 1)
//TreeNode<T>* node = &_nodes[i];
if (_nodes[i].Height <= 1)
{
continue;
}
Debug.Assert(node.IsLeaf() == false);
Debug.Assert(_nodes[i].IsLeaf() == false);
int child1 = node.Child1;
int child2 = node.Child2;
int child1 = _nodes[i].Child1;
int child2 = _nodes[i].Child2;
int balance = Math.Abs(_nodes[child2].Height - _nodes[child1].Height);
maxBalance = Math.Max(maxBalance, balance);
}
@@ -180,7 +190,7 @@ namespace FarseerPhysics.Collision
/// <param name="aabb">The aabb.</param>
/// <param name="userData">The user data.</param>
/// <returns>Index of the created proxy</returns>
public int AddProxy(ref AABB aabb, T userData)
public int AddProxy(ref AABB aabb)
{
int proxyId = AllocateNode();
@@ -188,7 +198,6 @@ namespace FarseerPhysics.Collision
Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
_nodes[proxyId].AABB.LowerBound = aabb.LowerBound - r;
_nodes[proxyId].AABB.UpperBound = aabb.UpperBound + r;
_nodes[proxyId].UserData = userData;
_nodes[proxyId].Height = 0;
InsertLeaf(proxyId);
@@ -264,6 +273,18 @@ namespace FarseerPhysics.Collision
return true;
}
/// <summary>
/// Set proxy user data.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="proxyId">The proxy id.</param>
/// <param name="userData">The proxy user data.</param>
public void SetUserData(int proxyId, T userData, Body body)
{
_nodes[proxyId].UserData = userData;
_nodes[proxyId].Body = body;
}
/// <summary>
/// Get proxy user data.
/// </summary>
@@ -287,12 +308,75 @@ namespace FarseerPhysics.Collision
fatAABB = _nodes[proxyId].AABB;
}
/// <summary>
/// Get the fat AABB for a proxy.
/// </summary>
/// <param name="proxyId">The proxy id.</param>
/// <returns>The fat AABB.</returns>
public AABB GetFatAABB(int proxyId)
{
Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);
return _nodes[proxyId].AABB;
}
public object GetBody(int proxyId)
{
Debug.Assert(0 <= proxyId && proxyId < _nodeCapacity);
return _nodes[proxyId].Body;
}
/// <summary>
/// Test overlap of fat AABBs.
/// </summary>
/// <param name="proxyIdA">The proxy id A.</param>
/// <param name="proxyIdB">The proxy id B.</param>
public bool TestFatAABBOverlap(int proxyIdA, int proxyIdB)
{
Debug.Assert(0 <= proxyIdA && proxyIdA < _nodeCapacity);
Debug.Assert(0 <= proxyIdB && proxyIdB < _nodeCapacity);
return AABB.TestOverlap(ref _nodes[proxyIdA].AABB, ref _nodes[proxyIdB].AABB);
}
/// <summary>
/// Query an AABB for overlapping proxies. The callback class
/// is called for each proxy that overlaps the supplied AABB.
/// </summary>
/// <param name="callback">The callback.</param>
/// <param name="aabb">The aabb.</param>
public void Query(Func<int, bool> callback, ref AABB aabb, ref object body)
{
_queryStack.Clear();
_queryStack.Push(_root);
while (_queryStack.Count > 0)
{
int nodeId = _queryStack.Pop();
if (nodeId == NullNode)
{
continue;
}
//TreeNode<T>* node = &_nodes[nodeId];
if (!ReferenceEquals(_nodes[nodeId].Body, body) && AABB.TestOverlap(ref _nodes[nodeId].AABB, ref aabb))
{
if (_nodes[nodeId].IsLeaf())
{
bool proceed = callback(nodeId);
if (proceed == false)
{
return;
}
}
else
{
_queryStack.Push(_nodes[nodeId].Child1);
_queryStack.Push(_nodes[nodeId].Child2);
}
}
}
}
public void Query(Func<int, bool> callback, ref AABB aabb)
{
_queryStack.Clear();
@@ -306,11 +390,10 @@ namespace FarseerPhysics.Collision
continue;
}
TreeNode<T> node = _nodes[nodeId];
if (AABB.TestOverlap(ref node.AABB, ref aabb))
//TreeNode<T>* node = &_nodes[nodeId];
if (AABB.TestOverlap(ref _nodes[nodeId].AABB, ref aabb))
{
if (node.IsLeaf())
if (_nodes[nodeId].IsLeaf())
{
bool proceed = callback(nodeId);
if (proceed == false)
@@ -320,8 +403,8 @@ namespace FarseerPhysics.Collision
}
else
{
_queryStack.Push(node.Child1);
_queryStack.Push(node.Child2);
_queryStack.Push(_nodes[nodeId].Child1);
_queryStack.Push(_nodes[nodeId].Child2);
}
}
}
@@ -336,7 +419,8 @@ namespace FarseerPhysics.Collision
/// </summary>
/// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param>
/// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
/// <param name="collisionCategory">The collision categories of the fixtures to raycast against.</param>
public void RayCast(IBroadPhase broadPhase, Func<RayCastInput, FixtureProxy, float> callback, ref RayCastInput input, Category collisionCategory = Category.All)
{
Vector2 p1 = input.Point1;
Vector2 p2 = input.Point2;
@@ -371,31 +455,39 @@ namespace FarseerPhysics.Collision
continue;
}
TreeNode<T> node = _nodes[nodeId];
//TreeNode<T>* node = &_nodes[nodeId];
if (AABB.TestOverlap(ref node.AABB, ref segmentAABB) == false)
if (AABB.TestOverlap(ref _nodes[nodeId].AABB, ref segmentAABB) == false)
{
continue;
}
// Separating axis for segment (Gino, p80).
// |dot(v, p1 - c)| > dot(|v|, h)
Vector2 c = node.AABB.Center;
Vector2 h = node.AABB.Extents;
Vector2 c = _nodes[nodeId].AABB.Center;
Vector2 h = _nodes[nodeId].AABB.Extents;
float separation = Math.Abs(Vector2.Dot(new Vector2(-r.Y, r.X), p1 - c)) - Vector2.Dot(absV, h);
if (separation > 0.0f)
{
continue;
}
if (node.IsLeaf())
if (_nodes[nodeId].IsLeaf())
{
FixtureProxy proxy = broadPhase.GetProxy(nodeId);
if (collisionCategory != Category.All &&
//!collisionCategory.HasFlag(proxy.Fixture.CollisionCategories)
(collisionCategory & proxy.Fixture.CollisionCategories) == 0)
{
continue;
}
RayCastInput subInput;
subInput.Point1 = input.Point1;
subInput.Point2 = input.Point2;
subInput.MaxFraction = maxFraction;
float value = callback(subInput, nodeId);
float value = callback(subInput, proxy);
if (value == 0.0f)
{
@@ -408,14 +500,14 @@ namespace FarseerPhysics.Collision
// Update segment bounding box.
maxFraction = value;
Vector2 t = p1 + maxFraction * (p2 - p1);
segmentAABB.LowerBound = Vector2.Min(p1, t);
segmentAABB.UpperBound = Vector2.Max(p1, t);
Vector2.Min(ref p1, ref t, out segmentAABB.LowerBound);
Vector2.Max(ref p1, ref t, out segmentAABB.UpperBound);
}
}
else
{
_raycastStack.Push(node.Child1);
_raycastStack.Push(node.Child2);
_raycastStack.Push(_nodes[nodeId].Child1);
_raycastStack.Push(_nodes[nodeId].Child2);
}
}
}
@@ -437,11 +529,9 @@ namespace FarseerPhysics.Collision
// pointer becomes the "next" pointer.
for (int i = _nodeCount; i < _nodeCapacity - 1; ++i)
{
_nodes[i] = new TreeNode<T>();
_nodes[i].ParentOrNext = i + 1;
_nodes[i].Height = -1;
}
_nodes[_nodeCapacity - 1] = new TreeNode<T>();
_nodes[_nodeCapacity - 1].ParentOrNext = NullNode;
_nodes[_nodeCapacity - 1].Height = -1;
_freeList = _nodeCount;
@@ -675,48 +765,48 @@ namespace FarseerPhysics.Collision
{
Debug.Assert(iA != NullNode);
TreeNode<T> A = _nodes[iA];
if (A.IsLeaf() || A.Height < 2)
//TreeNode<T>* A = &_nodes[iA];
if (_nodes[iA].IsLeaf() || _nodes[iA].Height < 2)
{
return iA;
}
int iB = A.Child1;
int iC = A.Child2;
int iB = _nodes[iA].Child1;
int iC = _nodes[iA].Child2;
Debug.Assert(0 <= iB && iB < _nodeCapacity);
Debug.Assert(0 <= iC && iC < _nodeCapacity);
TreeNode<T> B = _nodes[iB];
TreeNode<T> C = _nodes[iC];
//TreeNode<T>* B = &_nodes[iB];
//TreeNode<T>* C = &_nodes[iC];
int balance = C.Height - B.Height;
int balance = _nodes[iC].Height - _nodes[iB].Height;
// Rotate C up
if (balance > 1)
{
int iF = C.Child1;
int iG = C.Child2;
TreeNode<T> F = _nodes[iF];
TreeNode<T> G = _nodes[iG];
int iF = _nodes[iC].Child1;
int iG = _nodes[iC].Child2;
//TreeNode<T>* F = &_nodes[iF];
//TreeNode<T>* G = &_nodes[iG];
Debug.Assert(0 <= iF && iF < _nodeCapacity);
Debug.Assert(0 <= iG && iG < _nodeCapacity);
// Swap A and C
C.Child1 = iA;
C.ParentOrNext = A.ParentOrNext;
A.ParentOrNext = iC;
_nodes[iC].Child1 = iA;
_nodes[iC].ParentOrNext = _nodes[iA].ParentOrNext;
_nodes[iA].ParentOrNext = iC;
// A's old parent should point to C
if (C.ParentOrNext != NullNode)
if (_nodes[iC].ParentOrNext != NullNode)
{
if (_nodes[C.ParentOrNext].Child1 == iA)
if (_nodes[_nodes[iC].ParentOrNext].Child1 == iA)
{
_nodes[C.ParentOrNext].Child1 = iC;
_nodes[_nodes[iC].ParentOrNext].Child1 = iC;
}
else
{
Debug.Assert(_nodes[C.ParentOrNext].Child2 == iA);
_nodes[C.ParentOrNext].Child2 = iC;
Debug.Assert(_nodes[_nodes[iC].ParentOrNext].Child2 == iA);
_nodes[_nodes[iC].ParentOrNext].Child2 = iC;
}
}
else
@@ -725,27 +815,27 @@ namespace FarseerPhysics.Collision
}
// Rotate
if (F.Height > G.Height)
if (_nodes[iF].Height > _nodes[iG].Height)
{
C.Child2 = iF;
A.Child2 = iG;
G.ParentOrNext = iA;
A.AABB.Combine(ref B.AABB, ref G.AABB);
C.AABB.Combine(ref A.AABB, ref F.AABB);
_nodes[iC].Child2 = iF;
_nodes[iA].Child2 = iG;
_nodes[iG].ParentOrNext = iA;
_nodes[iA].AABB.Combine(ref _nodes[iB].AABB, ref _nodes[iG].AABB);
_nodes[iC].AABB.Combine(ref _nodes[iA].AABB, ref _nodes[iF].AABB);
A.Height = 1 + Math.Max(B.Height, G.Height);
C.Height = 1 + Math.Max(A.Height, F.Height);
_nodes[iA].Height = 1 + Math.Max(_nodes[iB].Height, _nodes[iG].Height);
_nodes[iC].Height = 1 + Math.Max(_nodes[iA].Height, _nodes[iF].Height);
}
else
{
C.Child2 = iG;
A.Child2 = iF;
F.ParentOrNext = iA;
A.AABB.Combine(ref B.AABB, ref F.AABB);
C.AABB.Combine(ref A.AABB, ref G.AABB);
_nodes[iC].Child2 = iG;
_nodes[iA].Child2 = iF;
_nodes[iF].ParentOrNext = iA;
_nodes[iA].AABB.Combine(ref _nodes[iB].AABB, ref _nodes[iF].AABB);
_nodes[iC].AABB.Combine(ref _nodes[iA].AABB, ref _nodes[iG].AABB);
A.Height = 1 + Math.Max(B.Height, F.Height);
C.Height = 1 + Math.Max(A.Height, G.Height);
_nodes[iA].Height = 1 + Math.Max(_nodes[iB].Height, _nodes[iF].Height);
_nodes[iC].Height = 1 + Math.Max(_nodes[iA].Height, _nodes[iG].Height);
}
return iC;
@@ -754,29 +844,29 @@ namespace FarseerPhysics.Collision
// Rotate B up
if (balance < -1)
{
int iD = B.Child1;
int iE = B.Child2;
TreeNode<T> D = _nodes[iD];
TreeNode<T> E = _nodes[iE];
int iD = _nodes[iB].Child1;
int iE = _nodes[iB].Child2;
//TreeNode<T>* D = &_nodes[iD];
//TreeNode<T>* E = &_nodes[iE];
Debug.Assert(0 <= iD && iD < _nodeCapacity);
Debug.Assert(0 <= iE && iE < _nodeCapacity);
// Swap A and B
B.Child1 = iA;
B.ParentOrNext = A.ParentOrNext;
A.ParentOrNext = iB;
_nodes[iB].Child1 = iA;
_nodes[iB].ParentOrNext = _nodes[iA].ParentOrNext;
_nodes[iA].ParentOrNext = iB;
// A's old parent should point to B
if (B.ParentOrNext != NullNode)
if (_nodes[iB].ParentOrNext != NullNode)
{
if (_nodes[B.ParentOrNext].Child1 == iA)
if (_nodes[_nodes[iB].ParentOrNext].Child1 == iA)
{
_nodes[B.ParentOrNext].Child1 = iB;
_nodes[_nodes[iB].ParentOrNext].Child1 = iB;
}
else
{
Debug.Assert(_nodes[B.ParentOrNext].Child2 == iA);
_nodes[B.ParentOrNext].Child2 = iB;
Debug.Assert(_nodes[_nodes[iB].ParentOrNext].Child2 == iA);
_nodes[_nodes[iB].ParentOrNext].Child2 = iB;
}
}
else
@@ -785,27 +875,27 @@ namespace FarseerPhysics.Collision
}
// Rotate
if (D.Height > E.Height)
if (_nodes[iD].Height > _nodes[iE].Height)
{
B.Child2 = iD;
A.Child1 = iE;
E.ParentOrNext = iA;
A.AABB.Combine(ref C.AABB, ref E.AABB);
B.AABB.Combine(ref A.AABB, ref D.AABB);
_nodes[iB].Child2 = iD;
_nodes[iA].Child1 = iE;
_nodes[iE].ParentOrNext = iA;
_nodes[iA].AABB.Combine(ref _nodes[iC].AABB, ref _nodes[iE].AABB);
_nodes[iB].AABB.Combine(ref _nodes[iA].AABB, ref _nodes[iD].AABB);
A.Height = 1 + Math.Max(C.Height, E.Height);
B.Height = 1 + Math.Max(A.Height, D.Height);
_nodes[iA].Height = 1 + Math.Max(_nodes[iC].Height, _nodes[iE].Height);
_nodes[iB].Height = 1 + Math.Max(_nodes[iA].Height, _nodes[iD].Height);
}
else
{
B.Child2 = iE;
A.Child1 = iD;
D.ParentOrNext = iA;
A.AABB.Combine(ref C.AABB, ref D.AABB);
B.AABB.Combine(ref A.AABB, ref E.AABB);
_nodes[iB].Child2 = iE;
_nodes[iA].Child1 = iD;
_nodes[iD].ParentOrNext = iA;
_nodes[iA].AABB.Combine(ref _nodes[iC].AABB, ref _nodes[iD].AABB);
_nodes[iB].AABB.Combine(ref _nodes[iA].AABB, ref _nodes[iE].AABB);
A.Height = 1 + Math.Max(C.Height, D.Height);
B.Height = 1 + Math.Max(A.Height, E.Height);
_nodes[iA].Height = 1 + Math.Max(_nodes[iC].Height, _nodes[iD].Height);
_nodes[iB].Height = 1 + Math.Max(_nodes[iA].Height, _nodes[iE].Height);
}
return iB;
@@ -822,15 +912,15 @@ namespace FarseerPhysics.Collision
public int ComputeHeight(int nodeId)
{
Debug.Assert(0 <= nodeId && nodeId < _nodeCapacity);
TreeNode<T> node = _nodes[nodeId];
//TreeNode<T>* node = &_nodes[nodeId];
if (node.IsLeaf())
if (_nodes[nodeId].IsLeaf())
{
return 0;
}
int height1 = ComputeHeight(node.Child1);
int height2 = ComputeHeight(node.Child2);
int height1 = ComputeHeight(_nodes[nodeId].Child1);
int height2 = ComputeHeight(_nodes[nodeId].Child2);
return 1 + Math.Max(height1, height2);
}
@@ -856,16 +946,16 @@ namespace FarseerPhysics.Collision
Debug.Assert(_nodes[index].ParentOrNext == NullNode);
}
TreeNode<T> node = _nodes[index];
//TreeNode<T>* node = &_nodes[index];
int child1 = node.Child1;
int child2 = node.Child2;
int child1 = _nodes[index].Child1;
int child2 = _nodes[index].Child2;
if (node.IsLeaf())
if (_nodes[index].IsLeaf())
{
Debug.Assert(child1 == NullNode);
Debug.Assert(child2 == NullNode);
Debug.Assert(node.Height == 0);
Debug.Assert(_nodes[index].Height == 0);
return;
}
@@ -886,16 +976,16 @@ namespace FarseerPhysics.Collision
return;
}
TreeNode<T> node = _nodes[index];
//TreeNode<T>* node = &_nodes[index];
int child1 = node.Child1;
int child2 = node.Child2;
int child1 = _nodes[index].Child1;
int child2 = _nodes[index].Child2;
if (node.IsLeaf())
if (_nodes[index].IsLeaf())
{
Debug.Assert(child1 == NullNode);
Debug.Assert(child2 == NullNode);
Debug.Assert(node.Height == 0);
Debug.Assert(_nodes[index].Height == 0);
return;
}
@@ -905,13 +995,13 @@ namespace FarseerPhysics.Collision
int height1 = _nodes[child1].Height;
int height2 = _nodes[child2].Height;
int height = 1 + Math.Max(height1, height2);
Debug.Assert(node.Height == height);
Debug.Assert(_nodes[index].Height == height);
AABB AABB = new AABB();
AABB.Combine(ref _nodes[child1].AABB, ref _nodes[child2].AABB);
Debug.Assert(AABB.LowerBound == node.AABB.LowerBound);
Debug.Assert(AABB.UpperBound == node.AABB.UpperBound);
Debug.Assert(AABB.LowerBound == _nodes[index].AABB.LowerBound);
Debug.Assert(AABB.UpperBound == _nodes[index].AABB.UpperBound);
ValidateMetrics(child1);
ValidateMetrics(child2);
@@ -993,19 +1083,19 @@ namespace FarseerPhysics.Collision
int index1 = nodes[iMin];
int index2 = nodes[jMin];
TreeNode<T> child1 = _nodes[index1];
TreeNode<T> child2 = _nodes[index2];
//TreeNode<T>* child1 = &_nodes[index1];
//TreeNode<T>* child2 = &_nodes[index2];
int parentIndex = AllocateNode();
TreeNode<T> parent = _nodes[parentIndex];
parent.Child1 = index1;
parent.Child2 = index2;
parent.Height = 1 + Math.Max(child1.Height, child2.Height);
parent.AABB.Combine(ref child1.AABB, ref child2.AABB);
parent.ParentOrNext = NullNode;
//TreeNode<T>* parent = &_nodes[parentIndex];
_nodes[parentIndex].Child1 = index1;
_nodes[parentIndex].Child2 = index2;
_nodes[parentIndex].Height = 1 + Math.Max(_nodes[index1].Height, _nodes[index2].Height);
_nodes[parentIndex].AABB.Combine(ref _nodes[index1].AABB, ref _nodes[index2].AABB);
_nodes[parentIndex].ParentOrNext = NullNode;
child1.ParentOrNext = parentIndex;
child2.ParentOrNext = parentIndex;
_nodes[index1].ParentOrNext = parentIndex;
_nodes[index2].ParentOrNext = parentIndex;
nodes[jMin] = nodes[count - 1];
nodes[iMin] = parentIndex;
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -21,6 +26,7 @@
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
@@ -35,17 +41,17 @@ namespace FarseerPhysics.Collision
public int CompareTo(Pair other)
{
if (ProxyIdA < other.ProxyIdA)
if (ProxyIdB < other.ProxyIdB)
{
return -1;
}
if (ProxyIdA == other.ProxyIdA)
if (ProxyIdB == other.ProxyIdB)
{
if (ProxyIdB < other.ProxyIdB)
if (ProxyIdA < other.ProxyIdA)
{
return -1;
}
if (ProxyIdB == other.ProxyIdB)
if (ProxyIdA == other.ProxyIdA)
{
return 0;
}
@@ -109,11 +115,12 @@ namespace FarseerPhysics.Collision
/// </summary>
/// <param name="proxy">The user data.</param>
/// <returns></returns>
public int AddProxy(ref FixtureProxy proxy)
public int AddProxy(ref AABB aabb)
{
int proxyId = _tree.AddProxy(ref proxy.AABB, proxy);
int proxyId = _tree.AddProxy(ref aabb);
++_proxyCount;
BufferMove(proxyId);
return proxyId;
}
@@ -206,6 +213,11 @@ namespace FarseerPhysics.Collision
_tree.GetFatAABB(proxyId, out aabb);
}
public void SetProxy(int proxyId, ref FixtureProxy proxy)
{
_tree.SetUserData(proxyId, proxy, proxy.Body);
}
/// <summary>
/// Get user data from a proxy. Returns null if the id is invalid.
/// </summary>
@@ -224,12 +236,11 @@ namespace FarseerPhysics.Collision
/// <returns></returns>
public bool TestOverlap(int proxyIdA, int proxyIdB)
{
AABB aabbA, aabbB;
_tree.GetFatAABB(proxyIdA, out aabbA);
_tree.GetFatAABB(proxyIdB, out aabbB);
return AABB.TestOverlap(ref aabbA, ref aabbB);
return _tree.TestFatAABBOverlap(proxyIdA, proxyIdB);
}
private readonly HashSet<int> processedPairs = new HashSet<int>();
/// <summary>
/// Update the pairs. This results in pair callbacks. This can only add pairs.
/// </summary>
@@ -250,32 +261,37 @@ namespace FarseerPhysics.Collision
// We have to query the tree with the fat AABB so that
// we don't fail to create a pair that may touch later.
AABB fatAABB;
_tree.GetFatAABB(_queryProxyId, out fatAABB);
AABB fatAABB = _tree.GetFatAABB(_queryProxyId);
object body = _tree.GetBody(_queryProxyId);
// Query tree, create pairs and add them pair buffer.
_tree.Query(_queryCallback, ref fatAABB);
_tree.Query(_queryCallback, ref fatAABB, ref body);
}
// Reset move buffer
_moveCount = 0;
// Sort the pair buffer to expose duplicates.
Array.Sort(_pairBuffer, 0, _pairCount);
//Array.Sort(_pairBuffer, 0, _pairCount);
processedPairs.Clear();
// Send the pairs back to the client.
int i = 0;
while (i < _pairCount)
{
Pair primaryPair = _pairBuffer[i];
FixtureProxy userDataA = _tree.GetUserData(primaryPair.ProxyIdA);
FixtureProxy userDataB = _tree.GetUserData(primaryPair.ProxyIdB);
int pairID = primaryPair.ProxyIdA + (primaryPair.ProxyIdB << 16);
if (!processedPairs.Contains(pairID))
{
callback(primaryPair.ProxyIdA, primaryPair.ProxyIdB);
processedPairs.Add(pairID);
}
callback(ref userDataA, ref userDataB);
++i;
// Skip any duplicate pairs.
while (i < _pairCount)
/*while (i < _pairCount)
{
Pair pair = _pairBuffer[i];
if (pair.ProxyIdA != primaryPair.ProxyIdA || pair.ProxyIdB != primaryPair.ProxyIdB)
@@ -283,7 +299,7 @@ namespace FarseerPhysics.Collision
break;
}
++i;
}
}*/
}
// Try to keep the tree balanced.
@@ -310,9 +326,10 @@ namespace FarseerPhysics.Collision
/// </summary>
/// <param name="callback">A callback class that is called for each proxy that is hit by the ray.</param>
/// <param name="input">The ray-cast input data. The ray extends from p1 to p1 + maxFraction * (p2 - p1).</param>
public void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input)
/// <param name="collisionCategory">The collision categories of the fixtures to raycast against.</param>
public void RayCast(Func<RayCastInput, FixtureProxy, float> callback, ref RayCastInput input, Category collisionCategory = Category.All)
{
_tree.RayCast(callback, ref input);
_tree.RayCast(this, callback, ref input, collisionCategory);
}
public void ShiftOrigin(Vector2 newOrigin)
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
@@ -11,12 +16,14 @@ namespace FarseerPhysics.Collision
bool TestOverlap(int proxyIdA, int proxyIdB);
int AddProxy(ref FixtureProxy proxy);
int AddProxy(ref AABB aabb);
void RemoveProxy(int proxyId);
void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement);
void SetProxy(int proxyId, ref FixtureProxy proxy);
FixtureProxy GetProxy(int proxyId);
void TouchProxy(int proxyId);
@@ -25,7 +32,7 @@ namespace FarseerPhysics.Collision
void Query(Func<int, bool> callback, ref AABB aabb);
void RayCast(Func<RayCastInput, int, float> callback, ref RayCastInput input);
void RayCast(Func<RayCastInput, FixtureProxy, float> callback, ref RayCastInput input, Category collisionCategory = Category.All);
void ShiftOrigin(Vector2 newOrigin);
}
@@ -0,0 +1,276 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision
{
public class Element<T>
{
public QuadTree<T> Parent;
public AABB Span;
public T Value;
public Element(AABB span)
{
Span = span;
Value = default(T);
Parent = null;
}
}
public class QuadTree<T>
{
public int MaxBucket;
public int MaxDepth;
public List<Element<T>> Nodes;
public AABB Span;
public QuadTree<T>[] SubTrees;
public QuadTree(AABB span, int maxbucket, int maxdepth)
{
Span = span;
Nodes = new List<Element<T>>();
MaxBucket = maxbucket;
MaxDepth = maxdepth;
}
public bool IsPartitioned
{
get { return SubTrees != null; }
}
/// <summary>
/// returns the quadrant of span that entirely contains test. if none, return 0.
/// </summary>
/// <param name="span"></param>
/// <param name="test"></param>
/// <returns></returns>
private int Partition(AABB span, AABB test)
{
if (span.Q1.Contains(ref test)) return 1;
if (span.Q2.Contains(ref test)) return 2;
if (span.Q3.Contains(ref test)) return 3;
if (span.Q4.Contains(ref test)) return 4;
return 0;
}
public void AddNode(Element<T> node)
{
if (!IsPartitioned)
{
if (Nodes.Count >= MaxBucket && MaxDepth > 0) //bin is full and can still subdivide
{
//
//partition into quadrants and sort existing nodes amonst quads.
//
Nodes.Add(node); //treat new node just like other nodes for partitioning
SubTrees = new QuadTree<T>[4];
SubTrees[0] = new QuadTree<T>(Span.Q1, MaxBucket, MaxDepth - 1);
SubTrees[1] = new QuadTree<T>(Span.Q2, MaxBucket, MaxDepth - 1);
SubTrees[2] = new QuadTree<T>(Span.Q3, MaxBucket, MaxDepth - 1);
SubTrees[3] = new QuadTree<T>(Span.Q4, MaxBucket, MaxDepth - 1);
List<Element<T>> remNodes = new List<Element<T>>();
//nodes that are not fully contained by any quadrant
foreach (Element<T> n in Nodes)
{
switch (Partition(Span, n.Span))
{
case 1: //quadrant 1
SubTrees[0].AddNode(n);
break;
case 2:
SubTrees[1].AddNode(n);
break;
case 3:
SubTrees[2].AddNode(n);
break;
case 4:
SubTrees[3].AddNode(n);
break;
default:
n.Parent = this;
remNodes.Add(n);
break;
}
}
Nodes = remNodes;
}
else
{
node.Parent = this;
Nodes.Add(node);
//if bin is not yet full or max depth has been reached, just add the node without subdividing
}
}
else //we already have children nodes
{
//
//add node to specific sub-tree
//
switch (Partition(Span, node.Span))
{
case 1: //quadrant 1
SubTrees[0].AddNode(node);
break;
case 2:
SubTrees[1].AddNode(node);
break;
case 3:
SubTrees[2].AddNode(node);
break;
case 4:
SubTrees[3].AddNode(node);
break;
default:
node.Parent = this;
Nodes.Add(node);
break;
}
}
}
/// <summary>
/// tests if ray intersects AABB
/// </summary>
/// <param name="aabb"></param>
/// <returns></returns>
public static bool RayCastAABB(AABB aabb, Vector2 p1, Vector2 p2)
{
AABB segmentAABB = new AABB();
{
Vector2.Min(ref p1, ref p2, out segmentAABB.LowerBound);
Vector2.Max(ref p1, ref p2, out segmentAABB.UpperBound);
}
if (!AABB.TestOverlap(ref aabb, ref segmentAABB)) return false;
Vector2 rayDir = p2 - p1;
Vector2 rayPos = p1;
Vector2 norm = new Vector2(-rayDir.Y, rayDir.X); //normal to ray
if (norm.Length() == 0.0f)
return true; //if ray is just a point, return true (iff point is within aabb, as tested earlier)
norm.Normalize();
float dPos = Vector2.Dot(rayPos, norm);
var verts = aabb.Vertices;
float d0 = Vector2.Dot(verts[0], norm) - dPos;
for (int i = 1; i < 4; i++)
{
float d = Vector2.Dot(verts[i], norm) - dPos;
if (Math.Sign(d) != Math.Sign(d0))
//return true if the ray splits the vertices (ie: sign of dot products with normal are not all same)
return true;
}
return false;
}
public void QueryAABB(Func<Element<T>, bool> callback, ref AABB searchR)
{
Stack<QuadTree<T>> stack = new Stack<QuadTree<T>>();
stack.Push(this);
while (stack.Count > 0)
{
QuadTree<T> qt = stack.Pop();
if (!AABB.TestOverlap(ref searchR, ref qt.Span))
continue;
foreach (Element<T> n in qt.Nodes)
if (AABB.TestOverlap(ref searchR, ref n.Span))
{
if (!callback(n)) return;
}
if (qt.IsPartitioned)
foreach (QuadTree<T> st in qt.SubTrees)
stack.Push(st);
}
}
public void RayCast(Func<RayCastInput, Element<T>, float> callback, ref RayCastInput input, Category collisionCategory = Category.All)
{
Stack<QuadTree<T>> stack = new Stack<QuadTree<T>>();
stack.Push(this);
float maxFraction = input.MaxFraction;
Vector2 p1 = input.Point1;
Vector2 p2 = p1 + (input.Point2 - input.Point1) * maxFraction;
while (stack.Count > 0)
{
QuadTree<T> qt = stack.Pop();
if (!RayCastAABB(qt.Span, p1, p2))
continue;
foreach (Element<T> n in qt.Nodes)
{
if (!RayCastAABB(n.Span, p1, p2))
continue;
RayCastInput subInput;
subInput.Point1 = input.Point1;
subInput.Point2 = input.Point2;
subInput.MaxFraction = maxFraction;
float value = callback(subInput, n);
if (value == 0.0f)
return; // the client has terminated the raycast.
if (value <= 0.0f)
continue;
maxFraction = value;
p2 = p1 + (input.Point2 - input.Point1) * maxFraction; //update segment endpoint
}
if (qt.IsPartitioned)
foreach (QuadTree<T> st in qt.SubTrees)
stack.Push(st);
}
}
public void GetAllNodesR(ref List<Element<T>> nodes)
{
nodes.AddRange(Nodes);
if (IsPartitioned)
foreach (QuadTree<T> st in SubTrees) st.GetAllNodesR(ref nodes);
}
public void RemoveNode(Element<T> node)
{
node.Parent.Nodes.Remove(node);
}
public void Reconstruct()
{
List<Element<T>> allNodes = new List<Element<T>>();
GetAllNodesR(ref allNodes);
Clear();
foreach (var node in allNodes)
AddNode(node);
}
public void Clear()
{
Nodes.Clear();
SubTrees = null;
}
}
}
@@ -0,0 +1,261 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Collision
{
public class QuadTreeBroadPhase : IBroadPhase
{
private const int TreeUpdateThresh = 10000;
private int _currId;
private Dictionary<int, Element<FixtureProxy>> _idRegister;
private List<Element<FixtureProxy>> _moveBuffer;
private List<Pair> _pairBuffer;
private QuadTree<FixtureProxy> _quadTree;
private int _treeMoveNum;
/// <summary>
/// Creates a new quad tree broadphase with the specified span.
/// </summary>
/// <param name="span">the maximum span of the tree (world size)</param>
public QuadTreeBroadPhase(AABB span)
{
_quadTree = new QuadTree<FixtureProxy>(span, 5, 10);
_idRegister = new Dictionary<int, Element<FixtureProxy>>();
_moveBuffer = new List<Element<FixtureProxy>>();
_pairBuffer = new List<Pair>();
}
#region IBroadPhase Members
///<summary>
/// The number of proxies
///</summary>
public int ProxyCount
{
get { return _idRegister.Count; }
}
public void GetFatAABB(int proxyID, out AABB aabb)
{
if (_idRegister.ContainsKey(proxyID))
aabb = _idRegister[proxyID].Span;
else
throw new KeyNotFoundException("proxyID not found in register");
}
public void UpdatePairs(BroadphaseDelegate callback)
{
_pairBuffer.Clear();
foreach (Element<FixtureProxy> qtnode in _moveBuffer)
{
// Query tree, create pairs and add them pair buffer.
Query(proxyID => PairBufferQueryCallback(proxyID, qtnode.Value.ProxyId), ref qtnode.Span);
}
_moveBuffer.Clear();
// Sort the pair buffer to expose duplicates.
_pairBuffer.Sort();
// Send the pairs back to the client.
int i = 0;
while (i < _pairBuffer.Count)
{
Pair primaryPair = _pairBuffer[i];
callback(primaryPair.ProxyIdA, primaryPair.ProxyIdB);
++i;
// Skip any duplicate pairs.
while (i < _pairBuffer.Count && _pairBuffer[i].ProxyIdA == primaryPair.ProxyIdA &&
_pairBuffer[i].ProxyIdB == primaryPair.ProxyIdB)
++i;
}
}
/// <summary>
/// Test overlap of fat AABBs.
/// </summary>
/// <param name="proxyIdA">The proxy id A.</param>
/// <param name="proxyIdB">The proxy id B.</param>
/// <returns></returns>
public bool TestOverlap(int proxyIdA, int proxyIdB)
{
AABB aabb1;
AABB aabb2;
GetFatAABB(proxyIdA, out aabb1);
GetFatAABB(proxyIdB, out aabb2);
return AABB.TestOverlap(ref aabb1, ref aabb2);
}
public int AddProxy(ref AABB uaabb)
{
int proxyId = _currId++;
AABB aabb = Fatten(ref uaabb);
Element<FixtureProxy> qtnode = new Element<FixtureProxy>(aabb);
_idRegister.Add(proxyId, qtnode);
_quadTree.AddNode(qtnode);
return proxyId;
}
public void RemoveProxy(int proxyId)
{
if (_idRegister.ContainsKey(proxyId))
{
Element<FixtureProxy> qtnode = _idRegister[proxyId];
UnbufferMove(qtnode);
_idRegister.Remove(proxyId);
_quadTree.RemoveNode(qtnode);
}
else
throw new KeyNotFoundException("proxyID not found in register");
}
public void MoveProxy(int proxyId, ref AABB aabb, Vector2 displacement)
{
AABB fatAABB;
GetFatAABB(proxyId, out fatAABB);
//exit if movement is within fat aabb
if (fatAABB.Contains(ref aabb))
return;
// Extend AABB.
AABB b = aabb;
Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
b.LowerBound = b.LowerBound - r;
b.UpperBound = b.UpperBound + r;
// Predict AABB displacement.
Vector2 d = Settings.AABBMultiplier * displacement;
if (d.X < 0.0f)
b.LowerBound.X += d.X;
else
b.UpperBound.X += d.X;
if (d.Y < 0.0f)
b.LowerBound.Y += d.Y;
else
b.UpperBound.Y += d.Y;
Element<FixtureProxy> qtnode = _idRegister[proxyId];
qtnode.Value.AABB = b; //not neccesary for QTree, but might be accessed externally
qtnode.Span = b;
ReinsertNode(qtnode);
BufferMove(qtnode);
}
public void SetProxy(int proxyId, ref FixtureProxy proxy)
{
_idRegister[proxyId].Value = proxy;
}
public FixtureProxy GetProxy(int proxyId)
{
if (_idRegister.ContainsKey(proxyId))
return _idRegister[proxyId].Value;
throw new KeyNotFoundException("proxyID not found in register");
}
public void TouchProxy(int proxyId)
{
if (_idRegister.ContainsKey(proxyId))
BufferMove(_idRegister[proxyId]);
else
throw new KeyNotFoundException("proxyID not found in register");
}
public void Query(Func<int, bool> callback, ref AABB query)
{
_quadTree.QueryAABB(TransformPredicate(callback), ref query);
}
public void RayCast(Func<RayCastInput, FixtureProxy, float> callback, ref RayCastInput input, Category collisionCategory = Category.All)
{
_quadTree.RayCast(TransformRayCallback(callback), ref input, collisionCategory);
}
public void ShiftOrigin(Vector2 newOrigin)
{
//TODO
}
#endregion
private AABB Fatten(ref AABB aabb)
{
Vector2 r = new Vector2(Settings.AABBExtension, Settings.AABBExtension);
return new AABB(aabb.LowerBound - r, aabb.UpperBound + r);
}
private Func<Element<FixtureProxy>, bool> TransformPredicate(Func<int, bool> idPredicate)
{
Func<Element<FixtureProxy>, bool> qtPred = qtnode => idPredicate(qtnode.Value.ProxyId);
return qtPred;
}
private Func<RayCastInput, Element<FixtureProxy>, float> TransformRayCallback(Func<RayCastInput, FixtureProxy, float> callback)
{
Func<RayCastInput, Element<FixtureProxy>, float> newCallback =
(input, qtnode) => callback(input, qtnode.Value);
return newCallback;
}
private bool PairBufferQueryCallback(int proxyId, int baseId)
{
// A proxy cannot form a pair with itself.
if (proxyId == baseId)
return true;
Pair p = new Pair();
p.ProxyIdA = Math.Min(proxyId, baseId);
p.ProxyIdB = Math.Max(proxyId, baseId);
_pairBuffer.Add(p);
return true;
}
private void ReconstructTree()
{
//this is faster than _quadTree.Reconstruct(), since the quadtree method runs a recusive query to find all nodes.
_quadTree.Clear();
foreach (Element<FixtureProxy> elem in _idRegister.Values)
_quadTree.AddNode(elem);
}
private void ReinsertNode(Element<FixtureProxy> qtnode)
{
_quadTree.RemoveNode(qtnode);
_quadTree.AddNode(qtnode);
if (++_treeMoveNum > TreeUpdateThresh)
{
ReconstructTree();
_treeMoveNum = 0;
}
}
private void BufferMove(Element<FixtureProxy> proxy)
{
_moveBuffer.Add(proxy);
}
private void UnbufferMove(Element<FixtureProxy> proxy)
{
_moveBuffer.Remove(proxy);
}
}
}
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -63,8 +68,8 @@ namespace FarseerPhysics.Collision.Shapes
{
ShapeType = ShapeType.Chain;
_radius = Settings.PolygonRadius;
Debug.Assert(vertices != null && vertices.Count >= 2);
Debug.Assert(vertices != null && vertices.Count >= 3);
Debug.Assert(vertices[0] != vertices[vertices.Count - 1]); // FPE. See http://www.box2d.org/forum/viewtopic.php?f=4&t=7973&p=35363
for (int i = 1; i < vertices.Count; ++i)
@@ -73,7 +78,6 @@ namespace FarseerPhysics.Collision.Shapes
Vector2 v2 = vertices[i];
// If the code crashes here, it means your vertices are too close together.
Debug.Assert(Vector2.DistanceSquared(v1, v2) > Settings.LinearSlop * Settings.LinearSlop);
}
@@ -208,11 +212,11 @@ namespace FarseerPhysics.Collision.Shapes
i2 = 0;
}
Vector2 v1 = MathUtils.Mul(ref transform, Vertices[i1]);
Vector2 v2 = MathUtils.Mul(ref transform, Vertices[i2]);
Vector2 v1 = Transform.Multiply(Vertices[i1], ref transform);
Vector2 v2 = Transform.Multiply(Vertices[i2], ref transform);
aabb.LowerBound = Vector2.Min(v1, v2);
aabb.UpperBound = Vector2.Max(v1, v2);
Vector2.Min(ref v1, ref v2, out aabb.LowerBound);
Vector2.Max(ref v1, ref v2, out aabb.UpperBound);
}
protected override void ComputeProperties()
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -23,6 +28,7 @@
using System;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision.Shapes
@@ -78,7 +84,7 @@ namespace FarseerPhysics.Collision.Shapes
public override bool TestPoint(ref Transform transform, ref Vector2 point)
{
Vector2 center = transform.p + MathUtils.Mul(transform.q, Position);
Vector2 center = transform.p + Complex.Multiply(ref _position, ref transform.q);
Vector2 d = point - center;
return Vector2.Dot(d, d) <= _2radius;
}
@@ -92,7 +98,7 @@ namespace FarseerPhysics.Collision.Shapes
output = new RayCastOutput();
Vector2 position = transform.p + MathUtils.Mul(transform.q, Position);
Vector2 position = transform.p + Complex.Multiply(ref _position, ref transform.q);
Vector2 s = input.Point1 - position;
float b = Vector2.Dot(s, s) - _2radius;
@@ -128,14 +134,21 @@ namespace FarseerPhysics.Collision.Shapes
public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex)
{
Vector2 p = transform.p + MathUtils.Mul(transform.q, Position);
aabb.LowerBound = new Vector2(p.X - Radius, p.Y - Radius);
aabb.UpperBound = new Vector2(p.X + Radius, p.Y + Radius);
// OPT: Vector2 p = transform.p + Complex.Multiply(ref _position, ref transform.q);
var pX = (_position.X * transform.q.Real - _position.Y * transform.q.Imaginary) + transform.p.X;
var pY = (_position.Y * transform.q.Real + _position.X * transform.q.Imaginary) + transform.p.Y;
// OPT: aabb.LowerBound = new Vector2(p.X - Radius, p.Y - Radius);
// OPT: aabb.UpperBound = new Vector2(p.X + Radius, p.Y + Radius);
aabb.LowerBound.X = pX - Radius;
aabb.LowerBound.Y = pY - Radius;
aabb.UpperBound.X = pX + Radius;
aabb.UpperBound.Y = pY + Radius;
}
protected override sealed void ComputeProperties()
{
float area = Settings.Pi * _2radius;
float area = MathHelper.Pi * _2radius;
MassData.Area = area;
MassData.Mass = Density * area;
MassData.Centroid = Position;
@@ -148,7 +161,7 @@ namespace FarseerPhysics.Collision.Shapes
{
sc = Vector2.Zero;
Vector2 p = MathUtils.Mul(ref xf, Position);
Vector2 p = Transform.Multiply(ref _position, ref xf);
float l = -(Vector2.Dot(normal, p) - offset);
if (l < -Radius + Settings.Epsilon)
{
@@ -159,12 +172,12 @@ namespace FarseerPhysics.Collision.Shapes
{
//Completely wet
sc = p;
return Settings.Pi * _2radius;
return MathHelper.Pi * _2radius;
}
//Magic
float l2 = l * l;
float area = _2radius * (float)((Math.Asin(l / Radius) + Settings.Pi / 2) + l * Math.Sqrt(_2radius - l2));
float area = _2radius * (float)((Math.Asin(l / Radius) + MathHelper.Pi / 2) + l * Math.Sqrt(_2radius - l2));
float com = -2.0f / 3.0f * (float)Math.Pow(_2radius - l2, 1.5f) / area;
sc.X = p.X + normal.X * com;
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -21,6 +26,7 @@
*/
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision.Shapes
@@ -143,8 +149,8 @@ namespace FarseerPhysics.Collision.Shapes
output = new RayCastOutput();
// Put the ray into the edge's frame of reference.
Vector2 p1 = MathUtils.MulT(transform.q, input.Point1 - transform.p);
Vector2 p2 = MathUtils.MulT(transform.q, input.Point2 - transform.p);
Vector2 p1 = Complex.Divide(input.Point1 - transform.p, ref transform.q);
Vector2 p2 = Complex.Divide(input.Point2 - transform.p, ref transform.q);
Vector2 d = p2 - p1;
Vector2 v1 = _vertex1;
@@ -201,15 +207,43 @@ namespace FarseerPhysics.Collision.Shapes
public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex)
{
Vector2 v1 = MathUtils.Mul(ref transform, _vertex1);
Vector2 v2 = MathUtils.Mul(ref transform, _vertex2);
// OPT: Vector2 v1 = Transform.Multiply(ref _vertex1, ref transform);
float v1X = (_vertex1.X * transform.q.Real - _vertex1.Y * transform.q.Imaginary) + transform.p.X;
float v1Y = (_vertex1.Y * transform.q.Real + _vertex1.X * transform.q.Imaginary) + transform.p.Y;
// OPT: Vector2 v2 = Transform.Multiply(ref _vertex2, ref transform);
float v2X = (_vertex2.X * transform.q.Real - _vertex2.Y * transform.q.Imaginary) + transform.p.X;
float v2Y = (_vertex2.Y * transform.q.Real + _vertex2.X * transform.q.Imaginary) + transform.p.Y;
Vector2 lower = Vector2.Min(v1, v2);
Vector2 upper = Vector2.Max(v1, v2);
// OPT: aabb.LowerBound = Vector2.Min(v1, v2);
// OPT: aabb.UpperBound = Vector2.Max(v1, v2);
if (v1X < v2X)
{
aabb.LowerBound.X = v1X;
aabb.UpperBound.X = v2X;
}
else
{
aabb.LowerBound.X = v2X;
aabb.UpperBound.X = v1X;
}
if (v1Y < v2Y)
{
aabb.LowerBound.Y = v1Y;
aabb.UpperBound.Y = v2Y;
}
else
{
aabb.LowerBound.Y = v2Y;
aabb.UpperBound.Y = v1Y;
}
Vector2 r = new Vector2(Radius, Radius);
aabb.LowerBound = lower - r;
aabb.UpperBound = upper + r;
// OPT: Vector2 r = new Vector2(Radius, Radius);
// OPT: aabb.LowerBound = aabb.LowerBound - r;
// OPT: aabb.UpperBound = aabb.LowerBound + r;
aabb.LowerBound.X -= Radius;
aabb.LowerBound.Y -= Radius;
aabb.UpperBound.X += Radius;
aabb.UpperBound.Y += Radius;
}
protected override void ComputeProperties()
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
@@ -23,6 +28,7 @@
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.ConvexHull;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision.Shapes
@@ -87,7 +93,7 @@ namespace FarseerPhysics.Collision.Shapes
{
_vertices = new Vertices(value);
//Debug.Assert(_vertices.Count >= 3 && _vertices.Count <= Settings.MaxPolygonVertices);
Debug.Assert(_vertices.Count >= 3 && _vertices.Count <= Settings.MaxPolygonVertices);
if (Settings.UseConvexHullPolygons)
{
@@ -179,7 +185,7 @@ namespace FarseerPhysics.Collision.Shapes
Vector2 e1 = Vertices[i] - s;
Vector2 e2 = i + 1 < Vertices.Count ? Vertices[i + 1] - s : Vertices[0] - s;
float D = MathUtils.Cross(e1, e2);
float D = MathUtils.Cross(ref e1, ref e2);
float triangleArea = 0.5f * D;
area += triangleArea;
@@ -218,7 +224,7 @@ namespace FarseerPhysics.Collision.Shapes
public override bool TestPoint(ref Transform transform, ref Vector2 point)
{
Vector2 pLocal = MathUtils.MulT(transform.q, point - transform.p);
Vector2 pLocal = Complex.Divide(point - transform.p, ref transform.q);
for (int i = 0; i < Vertices.Count; ++i)
{
@@ -237,8 +243,8 @@ namespace FarseerPhysics.Collision.Shapes
output = new RayCastOutput();
// Put the ray into the polygon's frame of reference.
Vector2 p1 = MathUtils.MulT(transform.q, input.Point1 - transform.p);
Vector2 p2 = MathUtils.MulT(transform.q, input.Point2 - transform.p);
Vector2 p1 = Complex.Divide(input.Point1 - transform.p, ref transform.q);
Vector2 p2 = Complex.Divide(input.Point2 - transform.p, ref transform.q);
Vector2 d = p2 - p1;
float lower = 0.0f, upper = input.MaxFraction;
@@ -296,7 +302,7 @@ namespace FarseerPhysics.Collision.Shapes
if (index >= 0)
{
output.Fraction = lower;
output.Normal = MathUtils.Mul(transform.q, Normals[index]);
output.Normal = Complex.Multiply(Normals[index], ref transform.q);
return true;
}
@@ -311,19 +317,36 @@ namespace FarseerPhysics.Collision.Shapes
/// <param name="childIndex">The child shape index.</param>
public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex)
{
Vector2 lower = MathUtils.Mul(ref transform, Vertices[0]);
Vector2 upper = lower;
// OPT: aabb.LowerBound = Transform.Multiply(Vertices[0], ref transform);
var vert = Vertices[0];
aabb.LowerBound.X = (vert.X * transform.q.Real - vert.Y * transform.q.Imaginary) + transform.p.X;
aabb.LowerBound.Y = (vert.Y * transform.q.Real + vert.X * transform.q.Imaginary) + transform.p.Y;
aabb.UpperBound = aabb.LowerBound;
for (int i = 1; i < Vertices.Count; ++i)
{
Vector2 v = MathUtils.Mul(ref transform, Vertices[i]);
lower = Vector2.Min(lower, v);
upper = Vector2.Max(upper, v);
// OPT: Vector2 v = Transform.Multiply(Vertices[i], ref transform);
vert = Vertices[i];
float vX = (vert.X * transform.q.Real - vert.Y * transform.q.Imaginary) + transform.p.X;
float vY = (vert.Y * transform.q.Real + vert.X * transform.q.Imaginary) + transform.p.Y;
// OPT: Vector2.Min(ref aabb.LowerBound, ref v, out aabb.LowerBound);
// OPT: Vector2.Max(ref aabb.UpperBound, ref v, out aabb.UpperBound);
Debug.Assert(aabb.LowerBound.X <= aabb.UpperBound.X);
if (vX < aabb.LowerBound.X) aabb.LowerBound.X = vX;
else if (vX > aabb.UpperBound.X) aabb.UpperBound.X = vX;
Debug.Assert(aabb.LowerBound.Y <= aabb.UpperBound.Y);
if (vY < aabb.LowerBound.Y) aabb.LowerBound.Y = vY;
else if (vY > aabb.UpperBound.Y) aabb.UpperBound.Y = vY;
}
Vector2 r = new Vector2(Radius, Radius);
aabb.LowerBound = lower - r;
aabb.UpperBound = upper + r;
// OPT: Vector2 r = new Vector2(Radius, Radius);
// OPT: aabb.LowerBound = aabb.LowerBound - r;
// OPT: aabb.UpperBound = aabb.UpperBound + r;
aabb.LowerBound.X -= Radius;
aabb.LowerBound.Y -= Radius;
aabb.UpperBound.X += Radius;
aabb.UpperBound.Y += Radius;
}
public override float ComputeSubmergedArea(ref Vector2 normal, float offset, ref Transform xf, out Vector2 sc)
@@ -331,7 +354,7 @@ namespace FarseerPhysics.Collision.Shapes
sc = Vector2.Zero;
//Transform plane into shape co-ordinates
Vector2 normalL = MathUtils.MulT(xf.q, normal);
Vector2 normalL = Complex.Divide(ref normal, ref xf.q);
float offsetL = offset - Vector2.Dot(normal, xf.p);
float[] depths = new float[Settings.MaxPolygonVertices];
@@ -372,7 +395,7 @@ namespace FarseerPhysics.Collision.Shapes
if (lastSubmerged)
{
//Completely submerged
sc = MathUtils.Mul(ref xf, MassData.Centroid);
sc = Transform.Multiply(MassData.Centroid, ref xf);
return MassData.Mass / Density;
}
@@ -421,7 +444,7 @@ namespace FarseerPhysics.Collision.Shapes
Vector2 e1 = p2 - intoVec;
Vector2 e2 = p3 - intoVec;
float D = MathUtils.Cross(e1, e2);
float D = MathUtils.Cross(ref e1, ref e2);
float triangleArea = 0.5f * D;
@@ -437,7 +460,7 @@ namespace FarseerPhysics.Collision.Shapes
//Normalize and transform centroid
center *= 1.0f / area;
sc = MathUtils.Mul(ref xf, center);
sc = Transform.Multiply(ref center, ref xf);
return area;
}
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -225,28 +230,6 @@ namespace FarseerPhysics.Collision.Shapes
/// </summary>
protected abstract void ComputeProperties();
/// <summary>
/// Compare this shape to another shape based on type and properties.
/// </summary>
/// <param name="shape">The other shape</param>
/// <returns>True if the two shapes are the same.</returns>
public bool CompareTo(Shape shape)
{
if (shape is PolygonShape && this is PolygonShape)
return ((PolygonShape)this).CompareTo((PolygonShape)shape);
if (shape is CircleShape && this is CircleShape)
return ((CircleShape)this).CompareTo((CircleShape)shape);
if (shape is EdgeShape && this is EdgeShape)
return ((EdgeShape)this).CompareTo((EdgeShape)shape);
if (shape is ChainShape && this is ChainShape)
return ((ChainShape)this).CompareTo((ChainShape)shape);
return false;
}
/// <summary>
/// Used for the buoyancy controller
/// </summary>
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -23,6 +28,7 @@
using System;
using System.Diagnostics;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Collision
@@ -32,8 +38,8 @@ namespace FarseerPhysics.Collision
/// </summary>
public class TOIInput
{
public DistanceProxy ProxyA = new DistanceProxy();
public DistanceProxy ProxyB = new DistanceProxy();
public DistanceProxy ProxyA;
public DistanceProxy ProxyB;
public Sweep SweepA;
public Sweep SweepB;
public float TMax; // defines sweep interval [0, tMax]
@@ -76,7 +82,7 @@ namespace FarseerPhysics.Collision
[ThreadStatic]
private static SeparationFunctionType _type;
public static void Set(ref SimplexCache cache, DistanceProxy proxyA, ref Sweep sweepA, DistanceProxy proxyB, ref Sweep sweepB, float t1)
public static void Set(ref SimplexCache cache, ref DistanceProxy proxyA, ref Sweep sweepA, ref DistanceProxy proxyB, ref Sweep sweepB, float t1)
{
_localPoint = Vector2.Zero;
_proxyA = proxyA;
@@ -96,8 +102,8 @@ namespace FarseerPhysics.Collision
_type = SeparationFunctionType.Points;
Vector2 localPointA = _proxyA.Vertices[cache.IndexA[0]];
Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
_axis = pointB - pointA;
_axis.Normalize();
}
@@ -111,13 +117,13 @@ namespace FarseerPhysics.Collision
Vector2 a = localPointB2 - localPointB1;
_axis = new Vector2(a.Y, -a.X);
_axis.Normalize();
Vector2 normal = MathUtils.Mul(ref xfB.q, _axis);
Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);
_localPoint = 0.5f * (localPointB1 + localPointB2);
Vector2 pointB = MathUtils.Mul(ref xfB, _localPoint);
Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);
Vector2 localPointA = proxyA.Vertices[cache.IndexA[0]];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
float s = Vector2.Dot(pointA - pointB, normal);
if (s < 0.0f)
@@ -135,13 +141,13 @@ namespace FarseerPhysics.Collision
Vector2 a = localPointA2 - localPointA1;
_axis = new Vector2(a.Y, -a.X);
_axis.Normalize();
Vector2 normal = MathUtils.Mul(ref xfA.q, _axis);
Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);
_localPoint = 0.5f * (localPointA1 + localPointA2);
Vector2 pointA = MathUtils.Mul(ref xfA, _localPoint);
Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);
Vector2 localPointB = _proxyB.Vertices[cache.IndexB[0]];
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
float s = Vector2.Dot(pointB - pointA, normal);
if (s < 0.0f)
@@ -149,8 +155,6 @@ namespace FarseerPhysics.Collision
_axis = -_axis;
}
}
//FPE note: the returned value that used to be here has been removed, as it was not used.
}
public static float FindMinSeparation(out int indexA, out int indexB, float t)
@@ -163,8 +167,8 @@ namespace FarseerPhysics.Collision
{
case SeparationFunctionType.Points:
{
Vector2 axisA = MathUtils.MulT(ref xfA.q, _axis);
Vector2 axisB = MathUtils.MulT(ref xfB.q, -_axis);
Vector2 axisA = Complex.Divide(ref _axis, ref xfA.q);
Vector2 axisB = -Complex.Divide(ref _axis, ref xfB.q);
indexA = _proxyA.GetSupport(axisA);
indexB = _proxyB.GetSupport(axisB);
@@ -172,8 +176,8 @@ namespace FarseerPhysics.Collision
Vector2 localPointA = _proxyA.Vertices[indexA];
Vector2 localPointB = _proxyB.Vertices[indexB];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
float separation = Vector2.Dot(pointB - pointA, _axis);
return separation;
@@ -181,16 +185,16 @@ namespace FarseerPhysics.Collision
case SeparationFunctionType.FaceA:
{
Vector2 normal = MathUtils.Mul(ref xfA.q, _axis);
Vector2 pointA = MathUtils.Mul(ref xfA, _localPoint);
Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);
Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);
Vector2 axisB = MathUtils.MulT(ref xfB.q, -normal);
Vector2 axisB = -Complex.Divide(ref normal, ref xfB.q);
indexA = -1;
indexB = _proxyB.GetSupport(axisB);
Vector2 localPointB = _proxyB.Vertices[indexB];
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
float separation = Vector2.Dot(pointB - pointA, normal);
return separation;
@@ -198,16 +202,16 @@ namespace FarseerPhysics.Collision
case SeparationFunctionType.FaceB:
{
Vector2 normal = MathUtils.Mul(ref xfB.q, _axis);
Vector2 pointB = MathUtils.Mul(ref xfB, _localPoint);
Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);
Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);
Vector2 axisA = MathUtils.MulT(ref xfA.q, -normal);
Vector2 axisA = -Complex.Divide(ref normal, ref xfA.q);
indexB = -1;
indexA = _proxyA.GetSupport(axisA);
Vector2 localPointA = _proxyA.Vertices[indexA];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
float separation = Vector2.Dot(pointA - pointB, normal);
return separation;
@@ -223,8 +227,6 @@ namespace FarseerPhysics.Collision
public static float Evaluate(int indexA, int indexB, float t)
{
if (float.IsNaN(t)) return 0.0f;
Transform xfA, xfB;
_sweepA.GetTransform(out xfA, t);
_sweepB.GetTransform(out xfB, t);
@@ -236,30 +238,30 @@ namespace FarseerPhysics.Collision
Vector2 localPointA = _proxyA.Vertices[indexA];
Vector2 localPointB = _proxyB.Vertices[indexB];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
float separation = Vector2.Dot(pointB - pointA, _axis);
return separation;
}
case SeparationFunctionType.FaceA:
{
Vector2 normal = MathUtils.Mul(ref xfA.q, _axis);
Vector2 pointA = MathUtils.Mul(ref xfA, _localPoint);
Vector2 normal = Complex.Multiply(ref _axis, ref xfA.q);
Vector2 pointA = Transform.Multiply(ref _localPoint, ref xfA);
Vector2 localPointB = _proxyB.Vertices[indexB];
Vector2 pointB = MathUtils.Mul(ref xfB, localPointB);
Vector2 pointB = Transform.Multiply(ref localPointB, ref xfB);
float separation = Vector2.Dot(pointB - pointA, normal);
return separation;
}
case SeparationFunctionType.FaceB:
{
Vector2 normal = MathUtils.Mul(ref xfB.q, _axis);
Vector2 pointB = MathUtils.Mul(ref xfB, _localPoint);
Vector2 normal = Complex.Multiply(ref _axis, ref xfB.q);
Vector2 pointB = Transform.Multiply(ref _localPoint, ref xfB);
Vector2 localPointA = _proxyA.Vertices[indexA];
Vector2 pointA = MathUtils.Mul(ref xfA, localPointA);
Vector2 pointA = Transform.Multiply(ref localPointA, ref xfA);
float separation = Vector2.Dot(pointA - pointB, normal);
return separation;
@@ -280,8 +282,6 @@ namespace FarseerPhysics.Collision
public static int TOICalls, TOIIters, TOIMaxIters;
[ThreadStatic]
public static int TOIRootIters, TOIMaxRootIters;
[ThreadStatic]
private static DistanceInput _distanceInput;
/// <summary>
/// Compute the upper bound on time before two shapes penetrate. Time is represented as
@@ -292,7 +292,7 @@ namespace FarseerPhysics.Collision
/// </summary>
/// <param name="output">The output.</param>
/// <param name="input">The input.</param>
public static void CalculateTimeOfImpact(out TOIOutput output, TOIInput input)
public static void CalculateTimeOfImpact(out TOIOutput output, ref TOIInput input)
{
if (Settings.EnableDiagnostics) //FPE: We only gather diagnostics when enabled
++TOICalls;
@@ -321,10 +321,10 @@ namespace FarseerPhysics.Collision
int iter = 0;
// Prepare input for distance query.
_distanceInput = _distanceInput ?? new DistanceInput();
_distanceInput.ProxyA = input.ProxyA;
_distanceInput.ProxyB = input.ProxyB;
_distanceInput.UseRadii = false;
DistanceInput distanceInput = new DistanceInput();
distanceInput.ProxyA = input.ProxyA;
distanceInput.ProxyB = input.ProxyB;
distanceInput.UseRadii = false;
// The outer loop progressively attempts to compute new separating axes.
// This loop terminates when an axis is repeated (no progress is made).
@@ -336,11 +336,11 @@ namespace FarseerPhysics.Collision
// Get the distance between shapes. We can also use the results
// to get a separating axis.
_distanceInput.TransformA = xfA;
_distanceInput.TransformB = xfB;
distanceInput.TransformA = xfA;
distanceInput.TransformB = xfB;
DistanceOutput distanceOutput;
SimplexCache cache;
Distance.ComputeDistance(out distanceOutput, out cache, _distanceInput);
Distance.ComputeDistance(out distanceOutput, out cache, distanceInput);
// If the shapes are overlapped, we give up on continuous collision.
if (distanceOutput.Distance <= 0.0f)
@@ -359,7 +359,7 @@ namespace FarseerPhysics.Collision
break;
}
SeparationFunction.Set(ref cache, input.ProxyA, ref sweepA, input.ProxyB, ref sweepB, t1);
SeparationFunction.Set(ref cache, ref input.ProxyA, ref sweepA, ref input.ProxyB, ref sweepB, t1);
// Compute the TOI on the separating axis. We do this by successively
// resolving the deepest point. This loop is bounded by the number of vertices.
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.ConvexHull
@@ -1,4 +1,9 @@
using Microsoft.Xna.Framework;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.ConvexHull
{
@@ -53,7 +58,6 @@ namespace FarseerPhysics.Common.ConvexHull
Vector2 r = vertices[ie] - vertices[hull[m]];
Vector2 v = vertices[j] - vertices[hull[m]];
float c = MathUtils.Cross(ref r, ref v);
if (c < 0.0f)
{
@@ -83,7 +87,6 @@ namespace FarseerPhysics.Common.ConvexHull
{
result.Add(vertices[hull[i]]);
}
return result;
}
}
@@ -1,4 +1,9 @@
using Microsoft.Xna.Framework;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.ConvexHull
{
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -98,7 +103,6 @@ namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
EdgeEvent(tcx, e, node);
}
}
tcx.Update(null);
}
}
@@ -518,10 +522,7 @@ namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
{
throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet");
}
if (tcx.IsDebugEnabled)
{
Debug.WriteLine("EdgeEvent - Point on constrained edge");
}
Debug.WriteLine("EdgeEvent - Point on constrained edge");
return;
}
@@ -542,10 +543,7 @@ namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
{
throw new PointOnEdgeException("EdgeEvent - Point on constrained edge not supported yet");
}
if (tcx.IsDebugEnabled)
{
Debug.WriteLine("EdgeEvent - Point on constrained edge");
}
Debug.WriteLine("EdgeEvent - Point on constrained edge");
return;
}
@@ -600,7 +598,7 @@ namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
if (eq == tcx.EdgeEvent.ConstrainedEdge.Q
&& ep == tcx.EdgeEvent.ConstrainedEdge.P)
{
if (tcx.IsDebugEnabled) Console.WriteLine("[FLIP] - constrained edge done"); // TODO: remove
Debug.WriteLine("[FLIP] - constrained edge done"); // TODO: remove
t.MarkConstrainedEdge(ep, eq);
ot.MarkConstrainedEdge(ep, eq);
Legalize(tcx, t);
@@ -608,15 +606,13 @@ namespace FarseerPhysics.Common.Decomposition.CDT.Delaunay.Sweep
}
else
{
if (tcx.IsDebugEnabled) Console.WriteLine("[FLIP] - subedge done"); // TODO: remove
Debug.WriteLine("[FLIP] - subedge done"); // TODO: remove
// XXX: I think one of the triangles should be legalized here?
}
}
else
{
if (tcx.IsDebugEnabled)
Console.WriteLine("[FLIP] - flipping and continuing with triangle still crossing edge");
// TODO: remove
Debug.WriteLine("[FLIP] - flipping and continuing with triangle still crossing edge"); // TODO: remove
Orientation o = TriangulationUtil.Orient2d(eq, op, ep);
t = NextFlipTriangle(tcx, o, t, ot, p, op);
FlipEdgeEvent(tcx, ep, eq, t, p);
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -53,7 +58,6 @@ namespace FarseerPhysics.Common.Decomposition.CDT
public bool Terminated { get; set; }
public int StepCount { get; private set; }
public virtual bool IsDebugEnabled { get; protected set; }
public void Done()
{
@@ -69,11 +73,6 @@ namespace FarseerPhysics.Common.Decomposition.CDT
public abstract TriangulationConstraint NewConstraint(TriangulationPoint a, TriangulationPoint b);
[MethodImpl(MethodImplOptions.Synchronized)]
public void Update(string message)
{
}
public virtual void Clear()
{
Points.Clear();
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.CDT.Util
@@ -1,4 +1,9 @@
/* Poly2Tri
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/* Poly2Tri
* Copyright (c) 2009-2010, Poly2Tri Contributors
* http://code.google.com/p/poly2tri/
*
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*/
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010
*
* Original C++ Version Copyright (c) 2007 Eric Jordan
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
{
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
{
@@ -1,4 +1,9 @@
namespace FarseerPhysics.Common.Decomposition.Seidel
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
namespace FarseerPhysics.Common.Decomposition.Seidel
{
internal class Point
{
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
{
@@ -1,4 +1,9 @@
namespace FarseerPhysics.Common.Decomposition.Seidel
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
namespace FarseerPhysics.Common.Decomposition.Seidel
{
internal class Sink : Node
{
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
{
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
{
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
namespace FarseerPhysics.Common.Decomposition.Seidel
@@ -1,4 +1,9 @@
namespace FarseerPhysics.Common.Decomposition.Seidel
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
namespace FarseerPhysics.Common.Decomposition.Seidel
{
internal class XNode : Node
{
@@ -1,4 +1,9 @@
namespace FarseerPhysics.Common.Decomposition.Seidel
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
namespace FarseerPhysics.Common.Decomposition.Seidel
{
internal class YNode : Node
{
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*/
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using FarseerPhysics.Common.ConvexHull;
@@ -69,7 +74,12 @@ namespace FarseerPhysics.Common.Decomposition
public static class Triangulate
{
public static List<Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f)
/// <param name="skipSanityChecks">
/// Set this to true to skip sanity checks in the engine. This will speed up the
/// tools by removing the overhead of the checks, but you will need to handle checks
/// yourself where it is needed.
/// </param>
public static List<Vertices> ConvexPartition(Vertices vertices, TriangulationAlgorithm algorithm, bool discardAndFixInvalid = true, float tolerance = 0.001f, bool skipSanityChecks = false)
{
if (vertices.Count <= 3)
return new List<Vertices> { vertices };
@@ -79,49 +89,37 @@ namespace FarseerPhysics.Common.Decomposition
switch (algorithm)
{
case TriangulationAlgorithm.Earclip:
if (Settings.SkipSanityChecks)
if (skipSanityChecks)
Debug.Assert(!vertices.IsCounterClockWise(), "The Earclip algorithm expects the polygon to be clockwise.");
else
else if (vertices.IsCounterClockWise())
{
if (vertices.IsCounterClockWise())
{
Vertices temp = new Vertices(vertices);
temp.Reverse();
results = EarclipDecomposer.ConvexPartition(temp, tolerance);
}
else
results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
Vertices temp = new Vertices(vertices);
temp.Reverse();
vertices = temp;
}
results = EarclipDecomposer.ConvexPartition(vertices, tolerance);
break;
case TriangulationAlgorithm.Bayazit:
if (Settings.SkipSanityChecks)
if (skipSanityChecks)
Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
else
else if (!vertices.IsCounterClockWise())
{
if (!vertices.IsCounterClockWise())
{
Vertices temp = new Vertices(vertices);
temp.Reverse();
results = BayazitDecomposer.ConvexPartition(temp);
}
else
results = BayazitDecomposer.ConvexPartition(vertices);
Vertices temp = new Vertices(vertices);
temp.Reverse();
vertices = temp;
}
results = BayazitDecomposer.ConvexPartition(vertices);
break;
case TriangulationAlgorithm.Flipcode:
if (Settings.SkipSanityChecks)
if (skipSanityChecks)
Debug.Assert(vertices.IsCounterClockWise(), "The polygon is not counter clockwise. This is needed for Bayazit to work correctly.");
else
else if (!vertices.IsCounterClockWise())
{
if (!vertices.IsCounterClockWise())
{
Vertices temp = new Vertices(vertices);
temp.Reverse();
results = FlipcodeDecomposer.ConvexPartition(temp);
}
else
results = FlipcodeDecomposer.ConvexPartition(vertices);
Vertices temp = new Vertices(vertices);
temp.Reverse();
vertices = temp;
}
results = FlipcodeDecomposer.ConvexPartition(vertices);
break;
case TriangulationAlgorithm.Seidel:
results = SeidelDecomposer.ConvexPartition(vertices, tolerance);
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using FarseerPhysics.Collision;
using Microsoft.Xna.Framework;
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
@@ -24,6 +29,7 @@ using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using Microsoft.Xna.Framework;
using FarseerPhysics.Common.Maths;
namespace FarseerPhysics.Common
{
@@ -40,9 +46,11 @@ namespace FarseerPhysics.Common
}
/// Perform the cross product on two vectors.
public static Vector3 Cross(Vector3 a, Vector3 b)
public static Vector3 Cross(ref Vector3 a, ref Vector3 b)
{
return new Vector3(a.Y * b.Z - a.Z * b.Y, a.Z * b.X - a.X * b.Z, a.X * b.Y - a.Y * b.X);
return new Vector3( a.Y * b.Z - a.Z * b.Y,
a.Z * b.X - a.X * b.Z,
a.X * b.Y - a.Y * b.X);
}
public static Vector2 Cross(Vector2 a, float s)
@@ -50,11 +58,21 @@ namespace FarseerPhysics.Common
return new Vector2(s * a.Y, -s * a.X);
}
public static Vector2 Cross(float s, Vector2 a)
public static Vector2 Rot270(ref Vector2 a)
{
return new Vector2(a.Y, -a.X);
}
public static Vector2 Cross(float s, ref Vector2 a)
{
return new Vector2(-s * a.Y, s * a.X);
}
public static Vector2 Rot90(ref Vector2 a)
{
return new Vector2(-a.Y, a.X);
}
public static Vector2 Abs(Vector2 v)
{
return new Vector2(Math.Abs(v.X), Math.Abs(v.Y));
@@ -69,19 +87,7 @@ namespace FarseerPhysics.Common
{
return new Vector2(A.ex.X * v.X + A.ey.X * v.Y, A.ex.Y * v.X + A.ey.Y * v.Y);
}
public static Vector2 Mul(ref Transform T, Vector2 v)
{
return Mul(ref T, ref v);
}
public static Vector2 Mul(ref Transform T, ref Vector2 v)
{
return new Vector2(
(T.q.c * v.X - T.q.s * v.Y) + T.p.X,
(T.q.s * v.X + T.q.c * v.Y) + T.p.Y);
}
public static Vector2 MulT(ref Mat22 A, Vector2 v)
{
return MulT(ref A, ref v);
@@ -92,18 +98,6 @@ namespace FarseerPhysics.Common
return new Vector2(v.X * A.ex.X + v.Y * A.ex.Y, v.X * A.ey.X + v.Y * A.ey.Y);
}
public static Vector2 MulT(ref Transform T, Vector2 v)
{
return MulT(ref T, ref v);
}
public static Vector2 MulT(ref Transform T, ref Vector2 v)
{
float px = v.X - T.p.X;
float py = v.Y - T.p.Y;
return new Vector2(T.q.c * px + T.q.s * py, -T.q.s * px + T.q.c * py);
}
// A^T * B
public static void MulT(ref Mat22 A, ref Mat22 B, out Mat22 C)
@@ -120,26 +114,7 @@ namespace FarseerPhysics.Common
{
return v.X * A.ex + v.Y * A.ey + v.Z * A.ez;
}
// v2 = A.q.Rot(B.q.Rot(v1) + B.p) + A.p
// = (A.q * B.q).Rot(v1) + A.q.Rot(B.p) + A.p
public static Transform Mul(Transform A, Transform B)
{
Transform C = new Transform();
C.q = Mul(A.q, B.q);
C.p = Mul(A.q, B.p) + A.p;
return C;
}
// v2 = A.q' * (B.q * v1 + B.p - A.p)
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
public static void MulT(ref Transform A, ref Transform B, out Transform C)
{
C = new Transform();
C.q = MulT(A.q, B.q);
C.p = MulT(A.q, B.p - A.p);
}
public static void Swap<T>(ref T a, ref T b)
{
T tmp = a;
@@ -152,65 +127,7 @@ namespace FarseerPhysics.Common
{
return new Vector2(A.ex.X * v.X + A.ey.X * v.Y, A.ex.Y * v.X + A.ey.Y * v.Y);
}
/// Multiply two rotations: q * r
public static Rot Mul(Rot q, Rot r)
{
// [qc -qs] * [rc -rs] = [qc*rc-qs*rs -qc*rs-qs*rc]
// [qs qc] [rs rc] [qs*rc+qc*rs -qs*rs+qc*rc]
// s = qs * rc + qc * rs
// c = qc * rc - qs * rs
Rot qr;
qr.s = q.s * r.c + q.c * r.s;
qr.c = q.c * r.c - q.s * r.s;
return qr;
}
public static Vector2 MulT(Transform T, Vector2 v)
{
float px = v.X - T.p.X;
float py = v.Y - T.p.Y;
float x = (T.q.c * px + T.q.s * py);
float y = (-T.q.s * px + T.q.c * py);
return new Vector2(x, y);
}
/// Transpose multiply two rotations: qT * r
public static Rot MulT(Rot q, Rot r)
{
// [ qc qs] * [rc -rs] = [qc*rc+qs*rs -qc*rs+qs*rc]
// [-qs qc] [rs rc] [-qs*rc+qc*rs qs*rs+qc*rc]
// s = qc * rs - qs * rc
// c = qc * rc + qs * rs
Rot qr;
qr.s = q.c * r.s - q.s * r.c;
qr.c = q.c * r.c + q.s * r.s;
return qr;
}
// v2 = A.q' * (B.q * v1 + B.p - A.p)
// = A.q' * B.q * v1 + A.q' * (B.p - A.p)
public static Transform MulT(Transform A, Transform B)
{
Transform C = new Transform();
C.q = MulT(A.q, B.q);
C.p = MulT(A.q, B.p - A.p);
return C;
}
/// Rotate a vector
public static Vector2 Mul(Rot q, Vector2 v)
{
return new Vector2(q.c * v.X - q.s * v.Y, q.s * v.X + q.c * v.Y);
}
/// Inverse rotate a vector
public static Vector2 MulT(Rot q, Vector2 v)
{
return new Vector2(q.c * v.X + q.s * v.Y, -q.s * v.X + q.c * v.Y);
}
/// Get the skew vector such that dot(skew_vec, other) == cross(vec, other)
public static Vector2 Skew(Vector2 input)
{
@@ -301,6 +218,12 @@ namespace FarseerPhysics.Common
return a.X * b.X + a.Y * b.Y + a.Z * b.Z;
}
/// Perform the dot product on two vectors.
public static float Dot(Vector2 a, ref Vector2 b)
{
return a.X * b.X + a.Y * b.Y;
}
public static double VectorAngle(Vector2 p1, Vector2 p2)
{
return VectorAngle(ref p1, ref p2);
@@ -389,15 +312,6 @@ namespace FarseerPhysics.Common
#endregion
public static Vector2 Mul(ref Rot rot, Vector2 axis)
{
return Mul(rot, axis);
}
public static Vector2 MulT(ref Rot rot, Vector2 axis)
{
return MulT(rot, axis);
}
}
/// <summary>
@@ -598,7 +512,7 @@ namespace FarseerPhysics.Common
/// Returns the zero matrix if singular.
public void GetSymInverse33(ref Mat33 M)
{
float det = MathUtils.Dot(ex, MathUtils.Cross(ey, ez));
float det = MathUtils.Dot(ex, MathUtils.Cross(ref ey, ref ez));
if (det != 0.0f)
{
det = 1.0f / det;
@@ -622,108 +536,108 @@ namespace FarseerPhysics.Common
}
}
/// <summary>
/// Rotation
/// </summary>
public struct Rot
{
/// Sine and cosine
public float s, c;
/// <summary>
/// Initialize from an angle in radians
/// </summary>
/// <param name="angle">Angle in radians</param>
public Rot(float angle)
{
// TODO_ERIN optimize
s = (float)Math.Sin(angle);
c = (float)Math.Cos(angle);
}
/// <summary>
/// Set using an angle in radians.
/// </summary>
/// <param name="angle"></param>
public void Set(float angle)
{
// TODO_ERIN optimize
s = (float)Math.Sin(angle);
c = (float)Math.Cos(angle);
}
/// <summary>
/// Set to the identity rotation
/// </summary>
public void SetIdentity()
{
s = 0.0f;
c = 1.0f;
}
/// <summary>
/// Get the angle in radians
/// </summary>
public float GetAngle()
{
return (float)Math.Atan2(s, c);
}
/// <summary>
/// Get the x-axis
/// </summary>
public Vector2 GetXAxis()
{
return new Vector2(c, s);
}
/// <summary>
/// Get the y-axis
/// </summary>
public Vector2 GetYAxis()
{
return new Vector2(-s, c);
}
}
/// <summary>
/// A transform contains translation and rotation. It is used to represent
/// the position and orientation of rigid frames.
/// </summary>
public struct Transform
{
private static readonly Transform _identity = new Transform(Vector2.Zero, Complex.One);
public Complex q;
public Vector2 p;
public Rot q;
public static Transform Identity { get { return _identity; } }
/// <summary>
/// Initialize using a position vector and a rotation matrix.
/// Initialize using a position vector and a Complex rotation.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="rotation">The r.</param>
public Transform(ref Vector2 position, ref Rot rotation)
/// <param name="rotation">The rotation</param>
public Transform(Vector2 position, Complex rotation)
{
p = position;
q = rotation;
p = position;
}
/// <summary>
/// Set this to the identity transform.
/// </summary>
public void SetIdentity()
{
p = Vector2.Zero;
q.SetIdentity();
}
/// <summary>
/// Set this based on the position and angle.
/// Initialize using a position vector and a rotation.
/// </summary>
/// <param name="position">The position.</param>
/// <param name="angle">The angle.</param>
public void Set(Vector2 position, float angle)
/// <param name="angle">The rotation angle</param>
public Transform(Vector2 position, float angle)
: this(position, Complex.FromAngle(angle))
{
p = position;
q.Set(angle);
}
public static Vector2 Multiply(Vector2 left, ref Transform right)
{
return Multiply(ref left, ref right);
}
public static Vector2 Multiply(ref Vector2 left, ref Transform right)
{
// Opt: var result = Complex.Multiply(left, right.q) + right.p;
return new Vector2(
(left.X * right.q.Real - left.Y * right.q.Imaginary) + right.p.X,
(left.Y * right.q.Real + left.X * right.q.Imaginary) + right.p.Y);
}
public static Vector2 Divide(Vector2 left, ref Transform right)
{
return Divide(ref left, ref right);
}
public static Vector2 Divide(ref Vector2 left, ref Transform right)
{
// Opt: var result = Complex.Divide(left - right.p, right);
float px = left.X - right.p.X;
float py = left.Y - right.p.Y;
return new Vector2(
(px * right.q.Real + py * right.q.Imaginary),
(py * right.q.Real - px * right.q.Imaginary));
}
public static void Divide(Vector2 left, ref Transform right, out Vector2 result)
{
// Opt: var result = Complex.Divide(left - right.p, right);
float px = left.X - right.p.X;
float py = left.Y - right.p.Y;
result.X = (px * right.q.Real + py * right.q.Imaginary);
result.Y = (py * right.q.Real - px * right.q.Imaginary);
}
public static Transform Multiply(ref Transform left, ref Transform right)
{
return new Transform(
Complex.Multiply(ref left.p, ref right.q) + right.p,
Complex.Multiply(ref left.q, ref right.q));
}
public static Transform Divide(ref Transform left, ref Transform right)
{
return new Transform(
Complex.Divide(left.p - right.p, ref right.q),
Complex.Divide(ref left.q, ref right.q));
}
public static void Divide(ref Transform left, ref Transform right, out Transform result)
{
Complex.Divide(left.p - right.p, ref right.q, out result.p);
Complex.Divide(ref left.q, ref right.q, out result.q);
}
public static void Multiply(ref Transform left, Complex right, out Transform result)
{
result.p = Complex.Multiply(ref left.p, ref right);
result.q = Complex.Multiply(ref left.q, ref right);
}
public static void Divide(ref Transform left, Complex right, out Transform result)
{
result.p = Complex.Divide(ref left.p, ref right);
result.q = Complex.Divide(ref left.q, ref right);
}
}
@@ -771,10 +685,10 @@ namespace FarseerPhysics.Common
xfb.p.X = (1.0f - beta) * C0.X + beta * C.X;
xfb.p.Y = (1.0f - beta) * C0.Y + beta * C.Y;
float angle = (1.0f - beta) * A0 + beta * A;
xfb.q.Set(angle);
xfb.q.Phase = angle;
// Shift to origin
xfb.p -= MathUtils.Mul(xfb.q, LocalCenter);
xfb.p -= Complex.Multiply(ref LocalCenter, ref xfb.q);
}
/// <summary>
@@ -1,170 +0,0 @@
#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID
#region License
/*
MIT License
Copyright © 2006 The Mono.Xna Team
All rights reserved.
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#endregion License
using System;
namespace Microsoft.Xna.Framework
{
public static class MathHelper
{
public const float E = (float) Math.E;
public const float Log10E = 0.4342945f;
public const float Log2E = 1.442695f;
public const float Pi = (float) Math.PI;
public const float PiOver2 = (float) (Math.PI/2.0);
public const float PiOver4 = (float) (Math.PI/4.0);
public const float TwoPi = (float) (Math.PI*2.0);
public static float Barycentric(float value1, float value2, float value3, float amount1, float amount2)
{
return value1 + (value2 - value1)*amount1 + (value3 - value1)*amount2;
}
public static float CatmullRom(float value1, float value2, float value3, float value4, float amount)
{
// Using formula from http://www.mvps.org/directx/articles/catmull/
// Internally using doubles not to lose precission
double amountSquared = amount*amount;
double amountCubed = amountSquared*amount;
return (float) (0.5*(2.0*value2 +
(value3 - value1)*amount +
(2.0*value1 - 5.0*value2 + 4.0*value3 - value4)*amountSquared +
(3.0*value2 - value1 - 3.0*value3 + value4)*amountCubed));
}
public static float Clamp(float value, float min, float max)
{
// First we check to see if we're greater than the max
value = (value > max) ? max : value;
// Then we check to see if we're less than the min.
value = (value < min) ? min : value;
// There's no check to see if min > max.
return value;
}
public static int Clamp(int value, int min, int max)
{
// First we check to see if we're greater than the max
value = (value > max) ? max : value;
// Then we check to see if we're less than the min.
value = (value < min) ? min : value;
// There's no check to see if min > max.
return value;
}
public static float Distance(float value1, float value2)
{
return Math.Abs(value1 - value2);
}
public static float Hermite(float value1, float tangent1, float value2, float tangent2, float amount)
{
// All transformed to double not to lose precission
// Otherwise, for high numbers of param:amount the result is NaN instead of Infinity
double v1 = value1, v2 = value2, t1 = tangent1, t2 = tangent2, s = amount, result;
double sCubed = s*s*s;
double sSquared = s*s;
if (amount == 0f)
result = value1;
else if (amount == 1f)
result = value2;
else
result = (2*v1 - 2*v2 + t2 + t1)*sCubed +
(3*v2 - 3*v1 - 2*t1 - t2)*sSquared +
t1*s +
v1;
return (float) result;
}
public static float Lerp(float value1, float value2, float amount)
{
return value1 + (value2 - value1)*amount;
}
public static float Max(float value1, float value2)
{
return Math.Max(value1, value2);
}
public static float Min(float value1, float value2)
{
return Math.Min(value1, value2);
}
public static float SmoothStep(float value1, float value2, float amount)
{
// It is expected that 0 < amount < 1
// If amount < 0, return value1
// If amount > 1, return value2
float result = Clamp(amount, 0f, 1f);
result = Hermite(value1, 0f, value2, 0f, result);
return result;
}
public static float ToDegrees(float radians)
{
// This method uses double precission internally,
// though it returns single float
// Factor = 180 / pi
return (float) (radians*57.295779513082320876798154814105);
}
public static float ToRadians(float degrees)
{
// This method uses double precission internally,
// though it returns single float
// Factor = pi / 180
return (float) (degrees*0.017453292519943295769236907684886);
}
public static float WrapAngle(float angle)
{
angle = (float) Math.IEEERemainder((double) angle, 6.2831854820251465); //2xPi precission is double
if (angle <= -3.141593f)
{
angle += 6.283185f;
return angle;
}
if (angle > 3.141593f)
{
angle -= 6.283185f;
}
return angle;
}
}
}
#endif
@@ -0,0 +1,155 @@
// Copyright (c) 2017 Kastellanos Nikolaos
using System;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.Maths
{
public struct Complex
{
private static readonly Complex _one = new Complex(1, 0);
private static readonly Complex _imaginaryOne = new Complex(0, 1);
public float Real;
public float Imaginary;
public static Complex One { get { return _one; } }
public static Complex ImaginaryOne { get { return _imaginaryOne; } }
public float Phase
{
get { return (float)Math.Atan2(Imaginary, Real); }
set
{
if (value == 0)
{
this = Complex.One;
return;
}
this.Real = (float)Math.Cos(value);
this.Imaginary = (float)Math.Sin(value);
}
}
public float Magnitude
{
get { return (float)Math.Round(Math.Sqrt(MagnitudeSquared())); }
}
public Complex(float real, float imaginary)
{
Real = real;
Imaginary = imaginary;
}
public static Complex FromAngle(float angle)
{
if (angle == 0)
return Complex.One;
return new Complex(
(float)Math.Cos(angle),
(float)Math.Sin(angle));
}
public void Conjugate()
{
Imaginary = -Imaginary;
}
public void Negate()
{
Real = -Real;
Imaginary = -Imaginary;
}
public float MagnitudeSquared()
{
return (Real * Real) + (Imaginary * Imaginary);
}
public void Normalize()
{
var mag = Magnitude;
Real = Real / mag;
Imaginary = Imaginary / mag;
}
public Vector2 ToVector2()
{
return new Vector2(Real, Imaginary);
}
public static Complex Multiply(ref Complex left, ref Complex right)
{
return new Complex( left.Real * right.Real - left.Imaginary * right.Imaginary,
left.Imaginary * right.Real + left.Real * right.Imaginary);
}
public static Complex Divide(ref Complex left, ref Complex right)
{
return new Complex( right.Real * left.Real + right.Imaginary * left.Imaginary,
right.Real * left.Imaginary - right.Imaginary * left.Real);
}
public static void Divide(ref Complex left, ref Complex right, out Complex result)
{
result = new Complex(right.Real * left.Real + right.Imaginary * left.Imaginary,
right.Real * left.Imaginary - right.Imaginary * left.Real);
}
public static Vector2 Multiply(ref Vector2 left, ref Complex right)
{
return new Vector2(left.X * right.Real - left.Y * right.Imaginary,
left.Y * right.Real + left.X * right.Imaginary);
}
public static void Multiply(ref Vector2 left, ref Complex right, out Vector2 result)
{
result = new Vector2(left.X * right.Real - left.Y * right.Imaginary,
left.Y * right.Real + left.X * right.Imaginary);
}
public static Vector2 Multiply(Vector2 left, ref Complex right)
{
return new Vector2(left.X * right.Real - left.Y * right.Imaginary,
left.Y * right.Real + left.X * right.Imaginary);
}
public static Vector2 Divide(ref Vector2 left, ref Complex right)
{
return new Vector2(left.X * right.Real + left.Y * right.Imaginary,
left.Y * right.Real - left.X * right.Imaginary);
}
public static Vector2 Divide(Vector2 left, ref Complex right)
{
return new Vector2(left.X * right.Real + left.Y * right.Imaginary,
left.Y * right.Real - left.X * right.Imaginary);
}
public static void Divide(Vector2 left, ref Complex right, out Vector2 result)
{
result = new Vector2(left.X * right.Real + left.Y * right.Imaginary,
left.Y * right.Real - left.X * right.Imaginary);
}
public static Complex Conjugate(ref Complex value)
{
return new Complex(value.Real, -value.Imaginary);
}
public static Complex Negate(ref Complex value)
{
return new Complex(-value.Real, -value.Real);
}
public static Complex Normalize(ref Complex value)
{
var mag = value.Magnitude;
return new Complex(value.Real / mag, -value.Imaginary / mag);
}
public override string ToString()
{
return String.Format("{{Real: {0} Imaginary: {1} Phase: {2} Magnitude: {3}}}", Real, Imaginary, Phase, Magnitude);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
@@ -239,9 +244,6 @@ namespace FarseerPhysics.Common
Vector2.Subtract(ref a, ref b, out temp);
#if (XBOX360 || WINDOWS_PHONE)
output = new Vector2();
#endif
output.X = -temp.Y;
output.Y = temp.X;
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common.Decomposition;
@@ -90,7 +95,7 @@ namespace FarseerPhysics.Common
for (int i = 0; i < centers.Count; i++)
{
Body b = new Body(world);
Body b = world.CreateBody();
// copy the type from original body
b.BodyType = type;
@@ -120,20 +125,14 @@ namespace FarseerPhysics.Common
/// <param name="copies">The copies.</param>
/// <param name="userData">The user data.</param>
/// <returns></returns>
public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type,
int copies, object userData)
public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies, object userData = null)
{
List<Shape> shapes = new List<Shape>(1);
shapes.Add(shape);
return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, userData);
}
public static List<Body> EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type, int copies)
{
return EvenlyDistributeShapesAlongPath(world, path, shape, type, copies, null);
}
/// <summary>
/// Moves the given body along the defined path.
/// </summary>
@@ -168,7 +167,7 @@ namespace FarseerPhysics.Common
{
RevoluteJoint joint = new RevoluteJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB);
joint.CollideConnected = collideConnected;
world.AddJoint(joint);
world.Add(joint);
joints.Add(joint);
}
@@ -176,7 +175,7 @@ namespace FarseerPhysics.Common
{
RevoluteJoint lastjoint = new RevoluteJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB);
lastjoint.CollideConnected = collideConnected;
world.AddJoint(lastjoint);
world.Add(lastjoint);
joints.Add(lastjoint);
}
@@ -0,0 +1,178 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Common.Decomposition;
namespace FarseerPhysics.Common.PhysicsLogic
{
/// <summary>
/// A type of body that supports multiple fixtures that can break apart.
/// </summary>
public class BreakableBody
{
public enum BreakableBodyState
{
Unbroken,
ShouldBreak,
Broken,
}
private float[] _angularVelocitiesCache = new float[8];
private Vector2[] _velocitiesCache = new Vector2[8];
public List<Fixture> Parts = new List<Fixture>(8);
public World World { get; private set; }
public Body MainBody { get; private set; }
/// <summary>
/// The force needed to break the body apart.
/// Default: 500
/// </summary>
public float Strength = 500.0f;
public BreakableBodyState State { get; private set; }
private BreakableBody(World world)
{
World = world;
World.ContactManager.PostSolve += PostSolve;
State = BreakableBodyState.Unbroken;
}
public BreakableBody(World world, IEnumerable<Vertices> vertices, float density, Vector2 position = new Vector2(), float rotation = 0) : this(world)
{
MainBody = World.CreateBody(position, rotation, BodyType.Dynamic);
foreach (Vertices part in vertices)
{
PolygonShape polygonShape = new PolygonShape(part, density);
Fixture fixture = MainBody.CreateFixture(polygonShape);
Parts.Add(fixture);
}
}
public BreakableBody(World world, IEnumerable<Shape> shapes, Vector2 position = new Vector2(), float rotation = 0) : this(world)
{
MainBody = World.CreateBody(position, rotation, BodyType.Dynamic);
foreach (Shape part in shapes)
{
Fixture fixture = MainBody.CreateFixture(part);
Parts.Add(fixture);
}
}
public BreakableBody(World world, Vertices vertices, float density, Vector2 position = new Vector2(), float rotation = 0) : this(world)
{
MainBody = World.CreateBody(position, rotation, BodyType.Dynamic);
//TODO: Implement a Voronoi diagram algorithm to split up the vertices
List<Vertices> triangles = Triangulate.ConvexPartition(vertices, TriangulationAlgorithm.Earclip);
foreach (Vertices part in triangles)
{
PolygonShape polygonShape = new PolygonShape(part, density);
Fixture fixture = MainBody.CreateFixture(polygonShape);
Parts.Add(fixture);
}
}
private void PostSolve(Contact contact, ContactVelocityConstraint impulse)
{
if (State != BreakableBodyState.Broken)
{
if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))
{
float maxImpulse = 0.0f;
int count = contact.Manifold.PointCount;
for (int i = 0; i < count; ++i)
{
maxImpulse = Math.Max(maxImpulse, impulse.points[i].normalImpulse);
}
if (maxImpulse > Strength)
{
// Flag the body for breaking.
State = BreakableBodyState.ShouldBreak;
}
}
}
}
public void Update()
{
switch (State)
{
case BreakableBodyState.Unbroken:
CacheVelocities();
break;
case BreakableBodyState.ShouldBreak:
Decompose();
break;
}
}
// Cache velocities to improve movement on breakage.
private void CacheVelocities()
{
//Enlarge the cache if needed
if (Parts.Count > _angularVelocitiesCache.Length)
{
_velocitiesCache = new Vector2[Parts.Count];
_angularVelocitiesCache = new float[Parts.Count];
}
//Cache the linear and angular velocities.
for (int i = 0; i < Parts.Count; i++)
{
_velocitiesCache[i] = Parts[i].Body.LinearVelocity;
_angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;
}
}
private void Decompose()
{
if (State == BreakableBodyState.Broken)
throw new InvalidOperationException("BreakableBody is allready broken");
//Unsubsribe from the PostSolve delegate
World.ContactManager.PostSolve -= PostSolve;
for (int i = 0; i < Parts.Count; i++)
{
Fixture oldFixture = Parts[i];
Shape shape = oldFixture.Shape.Clone();
object fixtureTag = oldFixture.UserData;
MainBody.Remove(oldFixture);
Body body = World.CreateBody(MainBody.Position, MainBody.Rotation, BodyType.Dynamic);
body.UserData = MainBody.UserData;
Fixture newFixture = body.CreateFixture(shape);
newFixture.UserData = fixtureTag;
Parts[i] = newFixture;
body.AngularVelocity = _angularVelocitiesCache[i];
body.LinearVelocity = _velocitiesCache[i];
}
World.Remove(MainBody);
State = BreakableBodyState.Broken;
}
}
}
@@ -0,0 +1,90 @@
// Copyright (c) 2017 Kastellanos Nikolaos
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
namespace FarseerPhysics.Common.PhysicsLogic
{
[Flags]
public enum ControllerCategory
{
None = 0x00000000,
Cat01 = 0x00000001,
Cat02 = 0x00000002,
Cat03 = 0x00000004,
Cat04 = 0x00000008,
Cat05 = 0x00000010,
Cat06 = 0x00000020,
Cat07 = 0x00000040,
Cat08 = 0x00000080,
Cat09 = 0x00000100,
Cat10 = 0x00000200,
Cat11 = 0x00000400,
Cat12 = 0x00000800,
Cat13 = 0x00001000,
Cat14 = 0x00002000,
Cat15 = 0x00004000,
Cat16 = 0x00008000,
Cat17 = 0x00010000,
Cat18 = 0x00020000,
Cat19 = 0x00040000,
Cat20 = 0x00080000,
Cat21 = 0x00100000,
Cat22 = 0x00200000,
Cat23 = 0x00400000,
Cat24 = 0x00800000,
Cat25 = 0x01000000,
Cat26 = 0x02000000,
Cat27 = 0x04000000,
Cat28 = 0x08000000,
Cat29 = 0x10000000,
Cat30 = 0x20000000,
Cat31 = 0x40000000,
All = int.MaxValue,
}
public struct ControllerFilter
{
public ControllerCategory ControllerCategories;
public ControllerFilter(ControllerCategory controllerCategory)
{
this.ControllerCategories = controllerCategory;
}
/// <summary>
/// Ignores the controller. The controller has no effect on this body.
/// </summary>
/// <param name="type">The logic type.</param>
public void IgnoreController(ControllerCategory category)
{
ControllerCategories &= ~category;
}
/// <summary>
/// Restore the controller. The controller affects this body.
/// </summary>
/// <param name="category">The logic type.</param>
public void RestoreController(ControllerCategory category)
{
ControllerCategories |= category;
}
/// <summary>
/// Determines whether this body ignores the the specified controller.
/// </summary>
/// <param name="category">The logic type.</param>
/// <returns>
/// <c>true</c> if the body has the specified flag; otherwise, <c>false</c>.
/// </returns>
public bool IsControllerIgnored(ControllerCategory category)
{
return (ControllerCategories & category) != category;
}
}
}
@@ -1,4 +1,9 @@
using FarseerPhysics.Dynamics;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Common.PhysicsLogic
{
@@ -36,7 +41,7 @@ namespace FarseerPhysics.Common.PhysicsLogic
/// <returns></returns>
public virtual bool IsActiveOn(Body body)
{
if (body == null || !body.Enabled || body.IsStatic)
if (body == null || !body.Enabled || body.BodyType == BodyType.Static)
return false;
if (body.FixtureList == null)
@@ -1,66 +1,29 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Common.PhysicsLogic
{
[Flags]
public enum PhysicsLogicType
{
Explosion = (1 << 0)
}
public struct PhysicsLogicFilter
{
public PhysicsLogicType ControllerIgnores;
/// <summary>
/// Ignores the controller. The controller has no effect on this body.
/// </summary>
/// <param name="type">The logic type.</param>
public void IgnorePhysicsLogic(PhysicsLogicType type)
{
ControllerIgnores |= type;
}
/// <summary>
/// Restore the controller. The controller affects this body.
/// </summary>
/// <param name="type">The logic type.</param>
public void RestorePhysicsLogic(PhysicsLogicType type)
{
ControllerIgnores &= ~type;
}
/// <summary>
/// Determines whether this body ignores the the specified controller.
/// </summary>
/// <param name="type">The logic type.</param>
/// <returns>
/// <c>true</c> if the body has the specified flag; otherwise, <c>false</c>.
/// </returns>
public bool IsPhysicsLogicIgnored(PhysicsLogicType type)
{
return (ControllerIgnores & type) == type;
}
}
public abstract class PhysicsLogic : FilterData
{
private PhysicsLogicType _type;
public World World;
public ControllerCategory ControllerCategory = ControllerCategory.Cat01;
public World World { get; internal set; }
public PhysicsLogic(World world)
{
World = world;
}
public override bool IsActiveOn(Body body)
{
if (body.PhysicsLogicFilter.IsPhysicsLogicIgnored(_type))
if (body.ControllerFilter.IsControllerIgnored(ControllerCategory))
return false;
return base.IsActiveOn(body);
}
public PhysicsLogic(World world, PhysicsLogicType type)
{
_type = type;
World = world;
}
}
}
@@ -1,10 +1,15 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using FarseerPhysics.Collision;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.PhysicsLogic
{
@@ -98,8 +103,7 @@ namespace FarseerPhysics.Common.PhysicsLogic
private List<ShapeData> _data = new List<ShapeData>();
private RayDataComparer _rdc;
public RealExplosion(World world)
: base(world, PhysicsLogicType.Explosion)
public RealExplosion(World world) : base(world)
{
_rdc = new RayDataComparer();
_data = new List<ShapeData>();
@@ -1,8 +1,13 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using FarseerPhysics.Collision;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.PhysicsLogic
{
@@ -11,8 +16,7 @@ namespace FarseerPhysics.Common.PhysicsLogic
/// </summary>
public sealed class SimpleExplosion : PhysicsLogic
{
public SimpleExplosion(World world)
: base(world, PhysicsLogicType.Explosion)
public SimpleExplosion(World world): base(world)
{
Power = 1; //linear
}
@@ -1,8 +1,12 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using System.Diagnostics;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.PolygonManipulation
@@ -191,7 +195,7 @@ namespace FarseerPhysics.Common.PolygonManipulation
//Delete the original shape and create two new. Retain the properties of the body.
if (first.CheckPolygon() == PolygonError.NoError)
{
Body firstFixture = BodyFactory.CreatePolygon(world, first, fixtures[i].Shape.Density, fixtures[i].Body.Position);
Body firstFixture = world.CreatePolygon(first, fixtures[i].Shape.Density, fixtures[i].Body.Position);
firstFixture.Rotation = fixtures[i].Body.Rotation;
firstFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;
firstFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;
@@ -200,14 +204,14 @@ namespace FarseerPhysics.Common.PolygonManipulation
if (second.CheckPolygon() == PolygonError.NoError)
{
Body secondFixture = BodyFactory.CreatePolygon(world, second, fixtures[i].Shape.Density, fixtures[i].Body.Position);
Body secondFixture = world.CreatePolygon(second, fixtures[i].Shape.Density, fixtures[i].Body.Position);
secondFixture.Rotation = fixtures[i].Body.Rotation;
secondFixture.LinearVelocity = fixtures[i].Body.LinearVelocity;
secondFixture.AngularVelocity = fixtures[i].Body.AngularVelocity;
secondFixture.BodyType = BodyType.Dynamic;
}
world.RemoveBody(fixtures[i].Body);
world.Remove(fixtures[i].Body);
}
}
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* C# Version Ported by Matt Bettcher and Ian Qvist 2009-2010
*
* Original C++ Version Copyright (c) 2007 Eric Jordan
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
@@ -1,514 +1,519 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.PolygonManipulation
{
internal enum PolyClipType
{
Intersect,
Union,
Difference
}
public enum PolyClipError
{
None,
DegeneratedOutput,
NonSimpleInput,
BrokenResult
}
//Clipper contributed by Helge Backhaus
public static class YuPengClipper
{
private const float ClipperEpsilonSquared = 1.192092896e-07f;
public static List<Vertices> Union(Vertices polygon1, Vertices polygon2, out PolyClipError error)
internal enum PolyClipType
{
return Execute(polygon1, polygon2, PolyClipType.Union, out error);
Intersect,
Union,
Difference
}
public static List<Vertices> Difference(Vertices polygon1, Vertices polygon2, out PolyClipError error)
public enum PolyClipError
{
return Execute(polygon1, polygon2, PolyClipType.Difference, out error);
None,
DegeneratedOutput,
NonSimpleInput,
BrokenResult
}
public static List<Vertices> Intersect(Vertices polygon1, Vertices polygon2, out PolyClipError error)
//Clipper contributed by Helge Backhaus
public static class YuPengClipper
{
return Execute(polygon1, polygon2, PolyClipType.Intersect, out error);
}
private const float ClipperEpsilonSquared = 1.192092896e-07f;
/// <summary>
/// Implements "A new algorithm for Boolean operations on general polygons"
/// available here: http://liama.ia.ac.cn/wiki/_media/user:dong:dong_cg_05.pdf
/// Merges two polygons, a subject and a clip with the specified operation. Polygons may not be
/// self-intersecting.
///
/// Warning: May yield incorrect results or even crash if polygons contain collinear points.
/// </summary>
/// <param name="subject">The subject polygon.</param>
/// <param name="clip">The clip polygon, which is added,
/// substracted or intersected with the subject</param>
/// <param name="clipType">The operation to be performed. Either
/// Union, Difference or Intersection.</param>
/// <param name="error">The error generated (if any)</param>
/// <returns>A list of closed polygons, which make up the result of the clipping operation.
/// Outer contours are ordered counter clockwise, holes are ordered clockwise.</returns>
private static List<Vertices> Execute(Vertices subject, Vertices clip, PolyClipType clipType, out PolyClipError error)
{
Debug.Assert(subject.IsSimple() && clip.IsSimple(), "Non simple input!", "Input polygons must be simple (cannot intersect themselves).");
// Copy polygons
Vertices slicedSubject;
Vertices slicedClip;
// Calculate the intersection and touch points between
// subject and clip and add them to both
CalculateIntersections(subject, clip, out slicedSubject, out slicedClip);
// Translate polygons into upper right quadrant
// as the algorithm depends on it
Vector2 lbSubject = subject.GetAABB().LowerBound;
Vector2 lbClip = clip.GetAABB().LowerBound;
Vector2 translate;
Vector2.Min(ref lbSubject, ref lbClip, out translate);
translate = Vector2.One - translate;
if (translate != Vector2.Zero)
{
slicedSubject.Translate(ref translate);
slicedClip.Translate(ref translate);
}
// Enforce counterclockwise contours
slicedSubject.ForceCounterClockWise();
slicedClip.ForceCounterClockWise();
List<Edge> subjectSimplices;
List<float> subjectCoeff;
List<Edge> clipSimplices;
List<float> clipCoeff;
// Build simplical chains from the polygons and calculate the
// the corresponding coefficients
CalculateSimplicalChain(slicedSubject, out subjectCoeff, out subjectSimplices);
CalculateSimplicalChain(slicedClip, out clipCoeff, out clipSimplices);
List<Edge> resultSimplices;
// Determine the characteristics function for all non-original edges
// in subject and clip simplical chain and combine the edges contributing
// to the result, depending on the clipType
CalculateResultChain(subjectCoeff, subjectSimplices, clipCoeff, clipSimplices, clipType,
out resultSimplices);
List<Vertices> result;
// Convert result chain back to polygon(s)
error = BuildPolygonsFromChain(resultSimplices, out result);
// Reverse the polygon translation from the beginning
// and remove collinear points from output
translate *= -1f;
for (int i = 0; i < result.Count; ++i)
{
result[i].Translate(ref translate);
SimplifyTools.CollinearSimplify(result[i]);
}
return result;
}
/// <summary>
/// Calculates all intersections between two polygons.
/// </summary>
/// <param name="polygon1">The first polygon.</param>
/// <param name="polygon2">The second polygon.</param>
/// <param name="slicedPoly1">Returns the first polygon with added intersection points.</param>
/// <param name="slicedPoly2">Returns the second polygon with added intersection points.</param>
private static void CalculateIntersections(Vertices polygon1, Vertices polygon2,
out Vertices slicedPoly1, out Vertices slicedPoly2)
{
slicedPoly1 = new Vertices(polygon1);
slicedPoly2 = new Vertices(polygon2);
// Iterate through polygon1's edges
for (int i = 0; i < polygon1.Count; i++)
{
// Get edge vertices
Vector2 a = polygon1[i];
Vector2 b = polygon1[polygon1.NextIndex(i)];
// Get intersections between this edge and polygon2
for (int j = 0; j < polygon2.Count; j++)
public static List<Vertices> Union(Vertices polygon1, Vertices polygon2, out PolyClipError error)
{
Vector2 c = polygon2[j];
Vector2 d = polygon2[polygon2.NextIndex(j)];
return Execute(polygon1, polygon2, PolyClipType.Union, out error);
}
Vector2 intersectionPoint;
// Check if the edges intersect
if (LineTools.LineIntersect(a, b, c, d, out intersectionPoint))
{
// calculate alpha values for sorting multiple intersections points on a edge
float alpha;
// Insert intersection point into first polygon
alpha = GetAlpha(a, b, intersectionPoint);
if (alpha > 0f && alpha < 1f)
public static List<Vertices> Difference(Vertices polygon1, Vertices polygon2, out PolyClipError error)
{
return Execute(polygon1, polygon2, PolyClipType.Difference, out error);
}
public static List<Vertices> Intersect(Vertices polygon1, Vertices polygon2, out PolyClipError error)
{
return Execute(polygon1, polygon2, PolyClipType.Intersect, out error);
}
/// <summary>
/// Implements "A new algorithm for Boolean operations on general polygons"
/// available here: http://liama.ia.ac.cn/wiki/_media/user:dong:dong_cg_05.pdf
/// Merges two polygons, a subject and a clip with the specified operation. Polygons may not be
/// self-intersecting.
///
/// Warning: May yield incorrect results or even crash if polygons contain collinear points.
/// </summary>
/// <param name="subject">The subject polygon.</param>
/// <param name="clip">The clip polygon, which is added,
/// substracted or intersected with the subject</param>
/// <param name="clipType">The operation to be performed. Either
/// Union, Difference or Intersection.</param>
/// <param name="error">The error generated (if any)</param>
/// <returns>A list of closed polygons, which make up the result of the clipping operation.
/// Outer contours are ordered counter clockwise, holes are ordered clockwise.</returns>
private static List<Vertices> Execute(Vertices subject, Vertices clip, PolyClipType clipType, out PolyClipError error)
{
Debug.Assert(subject.IsSimple() && clip.IsSimple(), "Non simple input! Input polygons must be simple (cannot intersect themselves).");
// Copy polygons
Vertices slicedSubject;
Vertices slicedClip;
// Calculate the intersection and touch points between
// subject and clip and add them to both
CalculateIntersections(subject, clip, out slicedSubject, out slicedClip);
// Translate polygons into upper right quadrant
// as the algorithm depends on it
Vector2 lbSubject = subject.GetAABB().LowerBound;
Vector2 lbClip = clip.GetAABB().LowerBound;
Vector2 translate;
Vector2.Min(ref lbSubject, ref lbClip, out translate);
translate = Vector2.One - translate;
if (translate != Vector2.Zero)
{
int index = slicedPoly1.IndexOf(a) + 1;
while (index < slicedPoly1.Count &&
GetAlpha(a, b, slicedPoly1[index]) <= alpha)
{
++index;
}
slicedPoly1.Insert(index, intersectionPoint);
slicedSubject.Translate(ref translate);
slicedClip.Translate(ref translate);
}
// Insert intersection point into second polygon
alpha = GetAlpha(c, d, intersectionPoint);
if (alpha > 0f && alpha < 1f)
// Enforce counterclockwise contours
slicedSubject.ForceCounterClockWise();
slicedClip.ForceCounterClockWise();
List<Edge> subjectSimplices;
List<float> subjectCoeff;
List<Edge> clipSimplices;
List<float> clipCoeff;
// Build simplical chains from the polygons and calculate the
// the corresponding coefficients
CalculateSimplicalChain(slicedSubject, out subjectCoeff, out subjectSimplices);
CalculateSimplicalChain(slicedClip, out clipCoeff, out clipSimplices);
List<Edge> resultSimplices;
// Determine the characteristics function for all non-original edges
// in subject and clip simplical chain and combine the edges contributing
// to the result, depending on the clipType
CalculateResultChain(subjectCoeff, subjectSimplices, clipCoeff, clipSimplices, clipType,
out resultSimplices);
List<Vertices> result;
// Convert result chain back to polygon(s)
error = BuildPolygonsFromChain(resultSimplices, out result);
// Reverse the polygon translation from the beginning
// and remove collinear points from output
translate *= -1f;
for (int i = 0; i < result.Count; ++i)
{
int index = slicedPoly2.IndexOf(c) + 1;
while (index < slicedPoly2.Count &&
GetAlpha(c, d, slicedPoly2[index]) <= alpha)
{
++index;
}
slicedPoly2.Insert(index, intersectionPoint);
result[i].Translate(ref translate);
SimplifyTools.CollinearSimplify(result[i]);
}
}
return result;
}
}
// Check for very small edges
for (int i = 0; i < slicedPoly1.Count; ++i)
{
int iNext = slicedPoly1.NextIndex(i);
//If they are closer than the distance remove vertex
if ((slicedPoly1[iNext] - slicedPoly1[i]).LengthSquared() <= ClipperEpsilonSquared)
{
slicedPoly1.RemoveAt(i);
--i;
}
}
for (int i = 0; i < slicedPoly2.Count; ++i)
{
int iNext = slicedPoly2.NextIndex(i);
//If they are closer than the distance remove vertex
if ((slicedPoly2[iNext] - slicedPoly2[i]).LengthSquared() <= ClipperEpsilonSquared)
{
slicedPoly2.RemoveAt(i);
--i;
}
}
}
/// <summary>
/// Calculates the simplical chain corresponding to the input polygon.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static void CalculateSimplicalChain(Vertices poly, out List<float> coeff,
out List<Edge> simplicies)
{
simplicies = new List<Edge>();
coeff = new List<float>();
for (int i = 0; i < poly.Count; ++i)
{
simplicies.Add(new Edge(poly[i], poly[poly.NextIndex(i)]));
coeff.Add(CalculateSimplexCoefficient(Vector2.Zero, poly[i], poly[poly.NextIndex(i)]));
}
}
/// <summary>
/// Calculates all intersections between two polygons.
/// </summary>
/// <param name="polygon1">The first polygon.</param>
/// <param name="polygon2">The second polygon.</param>
/// <param name="slicedPoly1">Returns the first polygon with added intersection points.</param>
/// <param name="slicedPoly2">Returns the second polygon with added intersection points.</param>
private static void CalculateIntersections(Vertices polygon1, Vertices polygon2,
out Vertices slicedPoly1, out Vertices slicedPoly2)
{
slicedPoly1 = new Vertices(polygon1);
slicedPoly2 = new Vertices(polygon2);
/// <summary>
/// Calculates the characteristics function for all edges of
/// the given simplical chains and builds the result chain.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static void CalculateResultChain(List<float> poly1Coeff, List<Edge> poly1Simplicies,
List<float> poly2Coeff, List<Edge> poly2Simplicies,
PolyClipType clipType, out List<Edge> resultSimplices)
{
resultSimplices = new List<Edge>();
for (int i = 0; i < poly1Simplicies.Count; ++i)
{
float edgeCharacter = 0;
if (poly2Simplicies.Contains(poly1Simplicies[i]))
{
edgeCharacter = 1f;
}
else if (poly2Simplicies.Contains(-poly1Simplicies[i]) && clipType == PolyClipType.Union)
{
edgeCharacter = 1f;
}
else
{
for (int j = 0; j < poly2Simplicies.Count; ++j)
{
if (!poly2Simplicies.Contains(-poly1Simplicies[i]))
// Iterate through polygon1's edges
for (int i = 0; i < polygon1.Count; i++)
{
edgeCharacter += CalculateBeta(poly1Simplicies[i].GetCenter(),
poly2Simplicies[j], poly2Coeff[j]);
// Get edge vertices
Vector2 a = polygon1[i];
Vector2 b = polygon1[polygon1.NextIndex(i)];
// Get intersections between this edge and polygon2
for (int j = 0; j < polygon2.Count; j++)
{
Vector2 c = polygon2[j];
Vector2 d = polygon2[polygon2.NextIndex(j)];
Vector2 intersectionPoint;
// Check if the edges intersect
if (LineTools.LineIntersect(a, b, c, d, out intersectionPoint))
{
// calculate alpha values for sorting multiple intersections points on a edge
float alpha;
// Insert intersection point into first polygon
alpha = GetAlpha(a, b, intersectionPoint);
if (alpha > 0f && alpha < 1f)
{
int index = slicedPoly1.IndexOf(a) + 1;
while (index < slicedPoly1.Count &&
GetAlpha(a, b, slicedPoly1[index]) <= alpha)
{
++index;
}
slicedPoly1.Insert(index, intersectionPoint);
}
// Insert intersection point into second polygon
alpha = GetAlpha(c, d, intersectionPoint);
if (alpha > 0f && alpha < 1f)
{
int index = slicedPoly2.IndexOf(c) + 1;
while (index < slicedPoly2.Count &&
GetAlpha(c, d, slicedPoly2[index]) <= alpha)
{
++index;
}
slicedPoly2.Insert(index, intersectionPoint);
}
}
}
}
// Check for very small edges
for (int i = 0; i < slicedPoly1.Count; ++i)
{
int iNext = slicedPoly1.NextIndex(i);
//If they are closer than the distance remove vertex
if ((slicedPoly1[iNext] - slicedPoly1[i]).LengthSquared() <= ClipperEpsilonSquared)
{
slicedPoly1.RemoveAt(i);
--i;
}
}
for (int i = 0; i < slicedPoly2.Count; ++i)
{
int iNext = slicedPoly2.NextIndex(i);
//If they are closer than the distance remove vertex
if ((slicedPoly2[iNext] - slicedPoly2[i]).LengthSquared() <= ClipperEpsilonSquared)
{
slicedPoly2.RemoveAt(i);
--i;
}
}
}
}
if (clipType == PolyClipType.Intersect)
/// <summary>
/// Calculates the simplical chain corresponding to the input polygon.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static void CalculateSimplicalChain(Vertices poly, out List<float> coeff,
out List<Edge> simplicies)
{
if (edgeCharacter == 1f)
{
resultSimplices.Add(poly1Simplicies[i]);
}
simplicies = new List<Edge>();
coeff = new List<float>();
for (int i = 0; i < poly.Count; ++i)
{
simplicies.Add(new Edge(poly[i], poly[poly.NextIndex(i)]));
coeff.Add(CalculateSimplexCoefficient(Vector2.Zero, poly[i], poly[poly.NextIndex(i)]));
}
}
else
/// <summary>
/// Calculates the characteristics function for all edges of
/// the given simplical chains and builds the result chain.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static void CalculateResultChain(List<float> poly1Coeff, List<Edge> poly1Simplicies,
List<float> poly2Coeff, List<Edge> poly2Simplicies,
PolyClipType clipType, out List<Edge> resultSimplices)
{
if (edgeCharacter == 0f)
{
resultSimplices.Add(poly1Simplicies[i]);
}
resultSimplices = new List<Edge>();
for (int i = 0; i < poly1Simplicies.Count; ++i)
{
float edgeCharacter = 0;
if (poly2Simplicies.Contains(poly1Simplicies[i]))
{
edgeCharacter = 1f;
}
else if (poly2Simplicies.Contains(-poly1Simplicies[i]) && clipType == PolyClipType.Union)
{
edgeCharacter = 1f;
}
else
{
for (int j = 0; j < poly2Simplicies.Count; ++j)
{
if (!poly2Simplicies.Contains(-poly1Simplicies[i]))
{
edgeCharacter += CalculateBeta(poly1Simplicies[i].GetCenter(),
poly2Simplicies[j], poly2Coeff[j]);
}
}
}
if (clipType == PolyClipType.Intersect)
{
if (edgeCharacter == 1f)
{
resultSimplices.Add(poly1Simplicies[i]);
}
}
else
{
if (edgeCharacter == 0f)
{
resultSimplices.Add(poly1Simplicies[i]);
}
}
}
for (int i = 0; i < poly2Simplicies.Count; ++i)
{
float edgeCharacter = 0f;
if (!resultSimplices.Contains(poly2Simplicies[i]) &&
!resultSimplices.Contains(-poly2Simplicies[i]))
{
if (poly1Simplicies.Contains(-poly2Simplicies[i]) && clipType == PolyClipType.Union)
{
edgeCharacter = 1f;
}
else
{
edgeCharacter = 0f;
for (int j = 0; j < poly1Simplicies.Count; ++j)
{
if (!poly1Simplicies.Contains(poly2Simplicies[i]) && !poly1Simplicies.Contains(-poly2Simplicies[i]))
{
edgeCharacter += CalculateBeta(poly2Simplicies[i].GetCenter(),
poly1Simplicies[j], poly1Coeff[j]);
}
}
if (clipType == PolyClipType.Intersect || clipType == PolyClipType.Difference)
{
if (edgeCharacter == 1f)
{
resultSimplices.Add(-poly2Simplicies[i]);
}
}
else
{
if (edgeCharacter == 0f)
{
resultSimplices.Add(poly2Simplicies[i]);
}
}
}
}
}
}
}
for (int i = 0; i < poly2Simplicies.Count; ++i)
{
float edgeCharacter = 0f;
if (!resultSimplices.Contains(poly2Simplicies[i]) &&
!resultSimplices.Contains(-poly2Simplicies[i]))
/// <summary>
/// Calculates the polygon(s) from the result simplical chain.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static PolyClipError BuildPolygonsFromChain(List<Edge> simplicies, out List<Vertices> result)
{
if (poly1Simplicies.Contains(-poly2Simplicies[i]) && clipType == PolyClipType.Union)
{
edgeCharacter = 1f;
}
else
{
edgeCharacter = 0f;
for (int j = 0; j < poly1Simplicies.Count; ++j)
result = new List<Vertices>();
PolyClipError errVal = PolyClipError.None;
while (simplicies.Count > 0)
{
if (!poly1Simplicies.Contains(poly2Simplicies[i]) && !poly1Simplicies.Contains(-poly2Simplicies[i]))
{
edgeCharacter += CalculateBeta(poly2Simplicies[i].GetCenter(),
poly1Simplicies[j], poly1Coeff[j]);
}
Vertices output = new Vertices();
output.Add(simplicies[0].EdgeStart);
output.Add(simplicies[0].EdgeEnd);
simplicies.RemoveAt(0);
bool closed = false;
int index = 0;
int count = simplicies.Count; // Needed to catch infinite loops
while (!closed && simplicies.Count > 0)
{
if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeStart))
{
if (VectorEqual(simplicies[index].EdgeEnd, output[0]))
{
closed = true;
}
else
{
output.Add(simplicies[index].EdgeEnd);
}
simplicies.RemoveAt(index);
--index;
}
else if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeEnd))
{
if (VectorEqual(simplicies[index].EdgeStart, output[0]))
{
closed = true;
}
else
{
output.Add(simplicies[index].EdgeStart);
}
simplicies.RemoveAt(index);
--index;
}
if (!closed)
{
if (++index == simplicies.Count)
{
if (count == simplicies.Count)
{
result = new List<Vertices>();
Debug.WriteLine("Undefined error while building result polygon(s).");
return PolyClipError.BrokenResult;
}
index = 0;
count = simplicies.Count;
}
}
}
if (output.Count < 3)
{
errVal = PolyClipError.DegeneratedOutput;
Debug.WriteLine("Degenerated output polygon produced (vertices < 3).");
}
result.Add(output);
}
if (clipType == PolyClipType.Intersect || clipType == PolyClipType.Difference)
{
if (edgeCharacter == 1f)
{
resultSimplices.Add(-poly2Simplicies[i]);
}
}
else
{
if (edgeCharacter == 0f)
{
resultSimplices.Add(poly2Simplicies[i]);
}
}
}
return errVal;
}
}
}
/// <summary>
/// Calculates the polygon(s) from the result simplical chain.
/// </summary>
/// <remarks>Used by method <c>Execute()</c>.</remarks>
private static PolyClipError BuildPolygonsFromChain(List<Edge> simplicies, out List<Vertices> result)
{
result = new List<Vertices>();
PolyClipError errVal = PolyClipError.None;
while (simplicies.Count > 0)
{
Vertices output = new Vertices();
output.Add(simplicies[0].EdgeStart);
output.Add(simplicies[0].EdgeEnd);
simplicies.RemoveAt(0);
bool closed = false;
int index = 0;
int count = simplicies.Count; // Needed to catch infinite loops
while (!closed && simplicies.Count > 0)
/// <summary>
/// Needed to calculate the characteristics function of a simplex.
/// </summary>
/// <remarks>Used by method <c>CalculateEdgeCharacter()</c>.</remarks>
private static float CalculateBeta(Vector2 point, Edge e, float coefficient)
{
if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeStart))
{
if (VectorEqual(simplicies[index].EdgeEnd, output[0]))
float result = 0f;
if (PointInSimplex(point, e))
{
closed = true;
result = coefficient;
}
else
if (PointOnLineSegment(Vector2.Zero, e.EdgeStart, point) ||
PointOnLineSegment(Vector2.Zero, e.EdgeEnd, point))
{
output.Add(simplicies[index].EdgeEnd);
result = .5f * coefficient;
}
simplicies.RemoveAt(index);
--index;
}
else if (VectorEqual(output[output.Count - 1], simplicies[index].EdgeEnd))
{
if (VectorEqual(simplicies[index].EdgeStart, output[0]))
{
closed = true;
}
else
{
output.Add(simplicies[index].EdgeStart);
}
simplicies.RemoveAt(index);
--index;
}
if (!closed)
{
if (++index == simplicies.Count)
{
if (count == simplicies.Count)
{
result = new List<Vertices>();
Debug.WriteLine("Undefined error while building result polygon(s).");
return PolyClipError.BrokenResult;
}
index = 0;
count = simplicies.Count;
}
}
return result;
}
if (output.Count < 3)
/// <summary>
/// Needed for sorting multiple intersections points on the same edge.
/// </summary>
/// <remarks>Used by method <c>CalculateIntersections()</c>.</remarks>
private static float GetAlpha(Vector2 start, Vector2 end, Vector2 point)
{
errVal = PolyClipError.DegeneratedOutput;
Debug.WriteLine("Degenerated output polygon produced (vertices < 3).");
return (point - start).LengthSquared() / (end - start).LengthSquared();
}
result.Add(output);
}
return errVal;
}
/// <summary>
/// Needed to calculate the characteristics function of a simplex.
/// </summary>
/// <remarks>Used by method <c>CalculateEdgeCharacter()</c>.</remarks>
private static float CalculateBeta(Vector2 point, Edge e, float coefficient)
{
float result = 0f;
if (PointInSimplex(point, e))
{
result = coefficient;
}
if (PointOnLineSegment(Vector2.Zero, e.EdgeStart, point) ||
PointOnLineSegment(Vector2.Zero, e.EdgeEnd, point))
{
result = .5f * coefficient;
}
return result;
}
/// <summary>
/// Needed for sorting multiple intersections points on the same edge.
/// </summary>
/// <remarks>Used by method <c>CalculateIntersections()</c>.</remarks>
private static float GetAlpha(Vector2 start, Vector2 end, Vector2 point)
{
return (point - start).LengthSquared() / (end - start).LengthSquared();
}
/// <summary>
/// Returns the coefficient of a simplex.
/// </summary>
/// <remarks>Used by method <c>CalculateSimplicalChain()</c>.</remarks>
private static float CalculateSimplexCoefficient(Vector2 a, Vector2 b, Vector2 c)
{
float isLeft = MathUtils.Area(ref a, ref b, ref c);
if (isLeft < 0f)
{
return -1f;
}
if (isLeft > 0f)
{
return 1f;
}
return 0f;
}
/// <summary>
/// Winding number test for a point in a simplex.
/// </summary>
/// <param name="point">The point to be tested.</param>
/// <param name="edge">The edge that the point is tested against.</param>
/// <returns>False if the winding number is even and the point is outside
/// the simplex and True otherwise.</returns>
private static bool PointInSimplex(Vector2 point, Edge edge)
{
Vertices polygon = new Vertices();
polygon.Add(Vector2.Zero);
polygon.Add(edge.EdgeStart);
polygon.Add(edge.EdgeEnd);
return (polygon.PointInPolygon(ref point) == 1);
}
/// <summary>
/// Tests if a point lies on a line segment.
/// </summary>
/// <remarks>Used by method <c>CalculateBeta()</c>.</remarks>
private static bool PointOnLineSegment(Vector2 start, Vector2 end, Vector2 point)
{
Vector2 segment = end - start;
return MathUtils.Area(ref start, ref end, ref point) == 0f &&
Vector2.Dot(point - start, segment) >= 0f &&
Vector2.Dot(point - end, segment) <= 0f;
}
private static bool VectorEqual(Vector2 vec1, Vector2 vec2)
{
return (vec2 - vec1).LengthSquared() <= ClipperEpsilonSquared;
}
#region Nested type: Edge
/// <summary>Specifies an Edge. Edges are used to represent simplicies in simplical chains</summary>
private sealed class Edge
{
public Edge(Vector2 edgeStart, Vector2 edgeEnd)
{
EdgeStart = edgeStart;
EdgeEnd = edgeEnd;
}
public Vector2 EdgeStart { get; private set; }
public Vector2 EdgeEnd { get; private set; }
public Vector2 GetCenter()
{
return (EdgeStart + EdgeEnd) / 2f;
}
public static Edge operator -(Edge e)
{
return new Edge(e.EdgeEnd, e.EdgeStart);
}
public override bool Equals(Object obj)
{
// If parameter is null return false.
if (obj == null)
/// <summary>
/// Returns the coefficient of a simplex.
/// </summary>
/// <remarks>Used by method <c>CalculateSimplicalChain()</c>.</remarks>
private static float CalculateSimplexCoefficient(Vector2 a, Vector2 b, Vector2 c)
{
return false;
float isLeft = MathUtils.Area(ref a, ref b, ref c);
if (isLeft < 0f)
{
return -1f;
}
if (isLeft > 0f)
{
return 1f;
}
return 0f;
}
// If parameter cannot be cast to Point return false.
return Equals(obj as Edge);
}
public bool Equals(Edge e)
{
// If parameter is null return false:
if (e == null)
/// <summary>
/// Winding number test for a point in a simplex.
/// </summary>
/// <param name="point">The point to be tested.</param>
/// <param name="edge">The edge that the point is tested against.</param>
/// <returns>False if the winding number is even and the point is outside
/// the simplex and True otherwise.</returns>
private static bool PointInSimplex(Vector2 point, Edge edge)
{
return false;
Vertices polygon = new Vertices();
polygon.Add(Vector2.Zero);
polygon.Add(edge.EdgeStart);
polygon.Add(edge.EdgeEnd);
return (polygon.PointInPolygon(ref point) == 1);
}
// Return true if the fields match
return VectorEqual(EdgeStart, e.EdgeStart) && VectorEqual(EdgeEnd, e.EdgeEnd);
}
/// <summary>
/// Tests if a point lies on a line segment.
/// </summary>
/// <remarks>Used by method <c>CalculateBeta()</c>.</remarks>
private static bool PointOnLineSegment(Vector2 start, Vector2 end, Vector2 point)
{
Vector2 segment = end - start;
return MathUtils.Area(ref start, ref end, ref point) == 0f &&
Vector2.Dot(point - start, segment) >= 0f &&
Vector2.Dot(point - end, segment) <= 0f;
}
public override int GetHashCode()
{
return EdgeStart.GetHashCode() ^ EdgeEnd.GetHashCode();
}
private static bool VectorEqual(Vector2 vec1, Vector2 vec2)
{
return (vec2 - vec1).LengthSquared() <= ClipperEpsilonSquared;
}
#region Nested type: Edge
/// <summary>Specifies an Edge. Edges are used to represent simplicies in simplical chains</summary>
private sealed class Edge
{
public Edge(Vector2 edgeStart, Vector2 edgeEnd)
{
EdgeStart = edgeStart;
EdgeEnd = edgeEnd;
}
public Vector2 EdgeStart { get; private set; }
public Vector2 EdgeEnd { get; private set; }
public Vector2 GetCenter()
{
return (EdgeStart + EdgeEnd) / 2f;
}
public static Edge operator -(Edge e)
{
return new Edge(e.EdgeEnd, e.EdgeStart);
}
public override bool Equals(Object obj)
{
// If parameter is null return false.
if (obj == null)
{
return false;
}
// If parameter cannot be cast to Point return false.
return Equals(obj as Edge);
}
public bool Equals(Edge e)
{
// If parameter is null return false:
if (e == null)
{
return false;
}
// Return true if the fields match
return VectorEqual(EdgeStart, e.EdgeStart) && VectorEqual(EdgeEnd, e.EdgeEnd);
}
public override int GetHashCode()
{
return EdgeStart.GetHashCode() ^ EdgeEnd.GetHashCode();
}
}
#endregion
}
#endregion
}
}
@@ -1,7 +1,13 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using FarseerPhysics.Common.TextureTools;
using FarseerPhysics.Common.Maths;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common
@@ -35,14 +41,12 @@ namespace FarseerPhysics.Common
{
Vertices vertices = CreateRectangle(hx, hy);
Transform xf = new Transform();
xf.p = center;
xf.q.Set(angle);
Transform xf = new Transform(center, angle);
// Transform vertices
for (int i = 0; i < 4; ++i)
{
vertices[i] = MathUtils.Mul(ref xf, vertices[i]);
vertices[i] = Transform.Multiply(vertices[i], ref xf);
}
return vertices;
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
@@ -18,28 +23,22 @@ namespace FarseerPhysics.Common
public static class WorldSerializer
{
/// <summary>
/// Serialize the world to an XML file
/// Serialize the world to a stream in XML format
/// </summary>
/// <param name="world"></param>
/// <param name="filename"></param>
public static void Serialize(World world, string filename)
/// <param name="stream"></param>
public static void Serialize(World world, Stream stream)
{
using (FileStream fs = new FileStream(filename, FileMode.Create))
{
WorldXmlSerializer.Serialize(world, fs);
}
WorldXmlSerializer.Serialize(world, stream);
}
/// <summary>
/// Deserialize the world from an XML file
/// Deserialize the world from a stream XML
/// </summary>
/// <param name="filename"></param>
public static World Deserialize(string filename)
/// <param name="stream"></param>
public static World Deserialize(Stream stream)
{
using (FileStream fs = new FileStream(filename, FileMode.Open))
{
return WorldXmlDeserializer.Deserialize(fs);
}
return WorldXmlDeserializer.Deserialize(stream);
}
}
@@ -51,7 +50,7 @@ namespace FarseerPhysics.Common
{
_writer.WriteStartElement("Shape");
_writer.WriteAttributeString("Type", shape.ShapeType.ToString());
_writer.WriteAttributeString("Density", shape.Density.ToString());
_writer.WriteAttributeString("Density", FloatToString(shape.Density));
switch (shape.ShapeType)
{
@@ -59,7 +58,7 @@ namespace FarseerPhysics.Common
{
CircleShape circle = (CircleShape)shape;
_writer.WriteElementString("Radius", circle.Radius.ToString());
WriteElement("Radius", circle.Radius);
WriteElement("Position", circle.Position);
}
@@ -103,51 +102,50 @@ namespace FarseerPhysics.Common
_writer.WriteEndElement();
}
private static void SerializeFixture(Fixture fixture)
private static void SerializeFixture(List<Fixture> fixtures, Fixture fixture)
{
_writer.WriteStartElement("Fixture");
_writer.WriteAttributeString("Id", fixture.FixtureId.ToString());
_writer.WriteAttributeString("Id", fixtures.IndexOf(fixture).ToString());
_writer.WriteStartElement("FilterData");
_writer.WriteElementString("CategoryBits", ((int)fixture.CollisionCategories).ToString());
_writer.WriteElementString("MaskBits", ((int)fixture.CollidesWith).ToString());
_writer.WriteElementString("GroupIndex", fixture.CollisionGroup.ToString());
_writer.WriteElementString("CollisionIgnores", Join("|", fixture._collisionIgnores));
_writer.WriteEndElement();
_writer.WriteElementString("Friction", fixture.Friction.ToString());
WriteElement("Friction", fixture.Friction);
_writer.WriteElementString("IsSensor", fixture.IsSensor.ToString());
_writer.WriteElementString("Restitution", fixture.Restitution.ToString());
WriteElement("Restitution", fixture.Restitution);
if (fixture.UserData != null)
{
_writer.WriteStartElement("UserData");
_writer.WriteStartElement("Tag");
WriteDynamicType(fixture.UserData.GetType(), fixture.UserData);
_writer.WriteEndElement();
}
_writer.WriteEndElement();
}
private static void SerializeBody(List<Fixture> fixtures, List<Shape> shapes, Body body)
{
_writer.WriteStartElement("Body");
_writer.WriteAttributeString("Type", body.BodyType.ToString());
_writer.WriteElementString("Active", body.Enabled.ToString());
_writer.WriteElementString("AllowSleep", body.SleepingAllowed.ToString());
_writer.WriteElementString("Angle", body.Rotation.ToString());
_writer.WriteElementString("AngularDamping", body.AngularDamping.ToString());
_writer.WriteElementString("AngularVelocity", body.AngularVelocity.ToString());
WriteElement("Angle", body.Rotation);
WriteElement("AngularDamping", body.AngularDamping);
WriteElement("AngularVelocity", body.AngularVelocity);
_writer.WriteElementString("Awake", body.Awake.ToString());
_writer.WriteElementString("Bullet", body.IsBullet.ToString());
_writer.WriteElementString("FixedRotation", body.FixedRotation.ToString());
_writer.WriteElementString("LinearDamping", body.LinearDamping.ToString());
WriteElement("LinearDamping", body.LinearDamping);
WriteElement("LinearVelocity", body.LinearVelocity);
WriteElement("Position", body.Position);
if (body.UserData != null)
{
_writer.WriteStartElement("UserData");
_writer.WriteStartElement("Tag");
WriteDynamicType(body.UserData.GetType(), body.UserData);
_writer.WriteEndElement();
}
@@ -156,8 +154,8 @@ namespace FarseerPhysics.Common
for (int i = 0; i < body.FixtureList.Count; i++)
{
_writer.WriteStartElement("Pair");
_writer.WriteAttributeString("FixtureId", FindIndex(fixtures, body.FixtureList[i]).ToString());
_writer.WriteAttributeString("ShapeId", FindIndex(shapes, body.FixtureList[i].Shape).ToString());
_writer.WriteAttributeString("FixtureId", fixtures.IndexOf(body.FixtureList[i]).ToString());
_writer.WriteAttributeString("ShapeId", shapes.IndexOf(body.FixtureList[i].Shape).ToString());
_writer.WriteEndElement();
}
@@ -170,17 +168,17 @@ namespace FarseerPhysics.Common
_writer.WriteStartElement("Joint");
_writer.WriteAttributeString("Type", joint.JointType.ToString());
WriteElement("BodyA", FindIndex(bodies, joint.BodyA));
WriteElement("BodyB", FindIndex(bodies, joint.BodyB));
WriteElement("BodyA", bodies.IndexOf(joint.BodyA));
WriteElement("BodyB", bodies.IndexOf(joint.BodyB));
WriteElement("CollideConnected", joint.CollideConnected);
WriteElement("Breakpoint", joint.Breakpoint);
if (joint.UserData != null)
if (joint.Tag != null)
{
_writer.WriteStartElement("UserData");
WriteDynamicType(joint.UserData.GetType(), joint.UserData);
_writer.WriteStartElement("Tag");
WriteDynamicType(joint.Tag.GetType(), joint.Tag);
_writer.WriteEndElement();
}
@@ -313,15 +311,13 @@ namespace FarseerPhysics.Common
_writer.WriteStartElement("Value");
XmlSerializer serializer = new XmlSerializer(type);
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
serializer.Serialize(_writer, val, xmlnsEmpty);
serializer.Serialize(_writer, val);
_writer.WriteEndElement();
}
private static void WriteElement(string name, Vector2 vec)
{
_writer.WriteElementString(name, vec.X + " " + vec.Y);
_writer.WriteElementString(name, FloatToString(vec.X) + " " + FloatToString(vec.Y));
}
private static void WriteElement(string name, int val)
@@ -336,39 +332,17 @@ namespace FarseerPhysics.Common
private static void WriteElement(string name, float val)
{
_writer.WriteElementString(name, val.ToString());
_writer.WriteElementString(name, FloatToString(val));
}
private static int FindIndex(List<Body> list, Body item)
private static string FloatToString(float value)
{
for (int i = 0; i < list.Count; ++i)
if (list[i] == item)
return i;
return -1;
return value.ToString(System.Globalization.CultureInfo.InvariantCulture);
}
private static int FindIndex(List<Fixture> list, Fixture item)
private static String Join(List<Fixture> fixtures, IEnumerable<Fixture> values)
{
for (int i = 0; i < list.Count; ++i)
if (list[i].CompareTo(item))
return i;
return -1;
}
private static int FindIndex(List<Shape> list, Shape item)
{
for (int i = 0; i < list.Count; ++i)
if (list[i].CompareTo(item))
return i;
return -1;
}
private static String Join<T>(String separator, IEnumerable<T> values)
{
using (IEnumerator<T> en = values.GetEnumerator())
using (var en = values.GetEnumerator())
{
if (!en.MoveNext())
return String.Empty;
@@ -376,24 +350,18 @@ namespace FarseerPhysics.Common
StringBuilder result = new StringBuilder();
if (en.Current != null)
{
// handle the case that the enumeration has null entries
// and the case where their ToString() override is broken
string value = en.Current.ToString();
if (value != null)
result.Append(value);
var fixture = en.Current;
var fixtureId = fixtures.IndexOf(fixture);
result.Append(fixtureId.ToString());
}
while (en.MoveNext())
{
result.Append(separator);
if (en.Current != null)
{
// handle the case that the enumeration has null entries
// and the case where their ToString() override is broken
string value = en.Current.ToString();
if (value != null)
result.Append(value);
}
result.Append("|");
var fixture = en.Current;
var fixtureId = fixtures.IndexOf(fixture);
result.Append(fixtureId.ToString());
}
return result.ToString();
}
@@ -422,10 +390,10 @@ namespace FarseerPhysics.Common
{
foreach (Fixture fixture in body.FixtureList)
{
if (!shapes.Any(s2 => fixture.Shape.CompareTo(s2)))
if (!shapes.Contains(fixture.Shape))
{
SerializeShape(fixture.Shape);
shapes.Add(fixture.Shape);
SerializeShape(fixture.Shape);
}
}
}
@@ -437,10 +405,10 @@ namespace FarseerPhysics.Common
{
foreach (Fixture fixture in body.FixtureList)
{
if (!fixtures.Any(f2 => fixture.CompareTo(f2)))
if (!fixtures.Contains(fixture))
{
SerializeFixture(fixture);
fixtures.Add(fixture);
SerializeFixture(fixtures, fixture);
}
}
}
@@ -466,7 +434,6 @@ namespace FarseerPhysics.Common
_writer.WriteEndElement();
_writer.Flush();
_writer.Close();
}
}
@@ -483,6 +450,7 @@ namespace FarseerPhysics.Common
{
List<Body> bodies = new List<Body>();
List<Fixture> fixtures = new List<Fixture>();
List<Joint> joints = new List<Joint>();
List<Shape> shapes = new List<Shape>();
@@ -512,7 +480,7 @@ namespace FarseerPhysics.Common
throw new Exception();
ShapeType type = (ShapeType)Enum.Parse(typeof(ShapeType), element.Attributes[0].Value, true);
float density = float.Parse(element.Attributes[1].Value);
float density = ParseFloat(element.Attributes[1].Value);
switch (type)
{
@@ -526,7 +494,7 @@ namespace FarseerPhysics.Common
switch (sn.Name.ToLower())
{
case "radius":
shape.Radius = float.Parse(sn.Value);
shape.Radius = ParseFloat(sn.Value);
break;
case "position":
shape.Position = ReadVector(sn);
@@ -651,7 +619,7 @@ namespace FarseerPhysics.Common
if (element.Name.ToLower() != "fixture")
throw new Exception();
fixture.FixtureId = int.Parse(element.Attributes[0].Value);
int fixtureId = int.Parse(element.Attributes[0].Value);
foreach (XMLFragmentElement sn in element.Elements)
{
@@ -671,27 +639,20 @@ namespace FarseerPhysics.Common
case "groupindex":
fixture._collisionGroup = short.Parse(ssn.Value);
break;
case "CollisionIgnores":
string[] split = ssn.Value.Split('|');
foreach (string s in split)
{
fixture._collisionIgnores.Add(int.Parse(s));
}
break;
}
}
break;
case "friction":
fixture.Friction = float.Parse(sn.Value);
fixture.Friction = ParseFloat(sn.Value);
break;
case "issensor":
fixture.IsSensor = bool.Parse(sn.Value);
break;
case "restitution":
fixture.Restitution = float.Parse(sn.Value);
fixture.Restitution = ParseFloat(sn.Value);
break;
case "userdata":
case "tag":
fixture.UserData = ReadSimpleType(sn, null, false);
break;
}
@@ -701,15 +662,16 @@ namespace FarseerPhysics.Common
}
}
}
//Read bodies
Dictionary<Fixture, Fixture> mapFixtureClones = new Dictionary<Fixture,Fixture>();
foreach (XMLFragmentElement bodyElement in root.Elements)
{
if (bodyElement.Name.ToLower() == "bodies")
{
foreach (XMLFragmentElement element in bodyElement.Elements)
{
Body body = new Body(world);
Body body = world.CreateBody();
if (element.Name.ToLower() != "body")
throw new Exception();
@@ -729,14 +691,14 @@ namespace FarseerPhysics.Common
case "angle":
{
Vector2 position = body.Position;
body.SetTransformIgnoreContacts(ref position, float.Parse(sn.Value));
body.SetTransformIgnoreContacts(ref position, ParseFloat(sn.Value));
}
break;
case "angulardamping":
body.AngularDamping = float.Parse(sn.Value);
body.AngularDamping = ParseFloat(sn.Value);
break;
case "angularvelocity":
body.AngularVelocity = float.Parse(sn.Value);
body.AngularVelocity = ParseFloat(sn.Value);
break;
case "awake":
body.Awake = bool.Parse(sn.Value);
@@ -748,7 +710,7 @@ namespace FarseerPhysics.Common
body.FixedRotation = bool.Parse(sn.Value);
break;
case "lineardamping":
body.LinearDamping = float.Parse(sn.Value);
body.LinearDamping = ParseFloat(sn.Value);
break;
case "linearvelocity":
body.LinearVelocity = ReadVector(sn);
@@ -760,7 +722,7 @@ namespace FarseerPhysics.Common
body.SetTransformIgnoreContacts(ref position, rotation);
}
break;
case "userdata":
case "tag":
body.UserData = ReadSimpleType(sn, null, false);
break;
case "bindings":
@@ -768,8 +730,9 @@ namespace FarseerPhysics.Common
foreach (XMLFragmentElement pair in sn.Elements)
{
Fixture fix = fixtures[int.Parse(pair.Attributes[0].Value)];
fix.Shape = shapes[int.Parse(pair.Attributes[1].Value)].Clone();
fix.CloneOnto(body);
var shape = shapes[int.Parse(pair.Attributes[1].Value)].Clone();
var clone = fix.CloneOnto(body, shape);
mapFixtureClones[fix] = clone;
}
break;
}
@@ -797,7 +760,7 @@ namespace FarseerPhysics.Common
int bodyAIndex = -1, bodyBIndex = -1;
bool collideConnected = false;
object userData = null;
object jointTag = null;
foreach (XMLFragmentElement sn in n.Elements)
{
@@ -812,8 +775,8 @@ namespace FarseerPhysics.Common
case "collideconnected":
collideConnected = bool.Parse(sn.Value);
break;
case "userdata":
userData = ReadSimpleType(sn, null, false);
case "tag":
jointTag = ReadSimpleType(sn, null, false);
break;
}
}
@@ -875,11 +838,11 @@ namespace FarseerPhysics.Common
}
joint.CollideConnected = collideConnected;
joint.UserData = userData;
joint.Tag = jointTag;
joint.BodyA = bodyA;
joint.BodyB = bodyB;
joints.Add(joint);
world.AddJoint(joint);
world.Add(joint);
foreach (XMLFragmentElement sn in n.Elements)
{
@@ -891,13 +854,13 @@ namespace FarseerPhysics.Common
switch (sn.Name.ToLower())
{
case "dampingratio":
((DistanceJoint)joint).DampingRatio = float.Parse(sn.Value);
((DistanceJoint)joint).DampingRatio = ParseFloat(sn.Value);
break;
case "frequencyhz":
((DistanceJoint)joint).Frequency = float.Parse(sn.Value);
((DistanceJoint)joint).Frequency = ParseFloat(sn.Value);
break;
case "length":
((DistanceJoint)joint).Length = float.Parse(sn.Value);
((DistanceJoint)joint).Length = ParseFloat(sn.Value);
break;
case "localanchora":
((DistanceJoint)joint).LocalAnchorA = ReadVector(sn);
@@ -919,10 +882,10 @@ namespace FarseerPhysics.Common
((FrictionJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxforce":
((FrictionJoint)joint).MaxForce = float.Parse(sn.Value);
((FrictionJoint)joint).MaxForce = ParseFloat(sn.Value);
break;
case "maxtorque":
((FrictionJoint)joint).MaxTorque = float.Parse(sn.Value);
((FrictionJoint)joint).MaxTorque = ParseFloat(sn.Value);
break;
}
}
@@ -941,16 +904,16 @@ namespace FarseerPhysics.Common
((WheelJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "motorspeed":
((WheelJoint)joint).MotorSpeed = float.Parse(sn.Value);
((WheelJoint)joint).MotorSpeed = ParseFloat(sn.Value);
break;
case "dampingratio":
((WheelJoint)joint).DampingRatio = float.Parse(sn.Value);
((WheelJoint)joint).DampingRatio = ParseFloat(sn.Value);
break;
case "maxmotortorque":
((WheelJoint)joint).MaxMotorTorque = float.Parse(sn.Value);
((WheelJoint)joint).MaxMotorTorque = ParseFloat(sn.Value);
break;
case "frequencyhz":
((WheelJoint)joint).Frequency = float.Parse(sn.Value);
((WheelJoint)joint).Frequency = ParseFloat(sn.Value);
break;
case "axis":
((WheelJoint)joint).Axis = ReadVector(sn);
@@ -978,19 +941,19 @@ namespace FarseerPhysics.Common
((PrismaticJoint)joint).Axis = ReadVector(sn);
break;
case "maxmotorforce":
((PrismaticJoint)joint).MaxMotorForce = float.Parse(sn.Value);
((PrismaticJoint)joint).MaxMotorForce = ParseFloat(sn.Value);
break;
case "motorspeed":
((PrismaticJoint)joint).MotorSpeed = float.Parse(sn.Value);
((PrismaticJoint)joint).MotorSpeed = ParseFloat(sn.Value);
break;
case "lowertranslation":
((PrismaticJoint)joint).LowerLimit = float.Parse(sn.Value);
((PrismaticJoint)joint).LowerLimit = ParseFloat(sn.Value);
break;
case "uppertranslation":
((PrismaticJoint)joint).UpperLimit = float.Parse(sn.Value);
((PrismaticJoint)joint).UpperLimit = ParseFloat(sn.Value);
break;
case "referenceangle":
((PrismaticJoint)joint).ReferenceAngle = float.Parse(sn.Value);
((PrismaticJoint)joint).ReferenceAngle = ParseFloat(sn.Value);
break;
}
}
@@ -1006,10 +969,10 @@ namespace FarseerPhysics.Common
((PulleyJoint)joint).WorldAnchorB = ReadVector(sn);
break;
case "lengtha":
((PulleyJoint)joint).LengthA = float.Parse(sn.Value);
((PulleyJoint)joint).LengthA = ParseFloat(sn.Value);
break;
case "lengthb":
((PulleyJoint)joint).LengthB = float.Parse(sn.Value);
((PulleyJoint)joint).LengthB = ParseFloat(sn.Value);
break;
case "localanchora":
((PulleyJoint)joint).LocalAnchorA = ReadVector(sn);
@@ -1018,10 +981,10 @@ namespace FarseerPhysics.Common
((PulleyJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "ratio":
((PulleyJoint)joint).Ratio = float.Parse(sn.Value);
((PulleyJoint)joint).Ratio = ParseFloat(sn.Value);
break;
case "constant":
((PulleyJoint)joint).Constant = float.Parse(sn.Value);
((PulleyJoint)joint).Constant = ParseFloat(sn.Value);
break;
}
}
@@ -1043,19 +1006,19 @@ namespace FarseerPhysics.Common
((RevoluteJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxmotortorque":
((RevoluteJoint)joint).MaxMotorTorque = float.Parse(sn.Value);
((RevoluteJoint)joint).MaxMotorTorque = ParseFloat(sn.Value);
break;
case "motorspeed":
((RevoluteJoint)joint).MotorSpeed = float.Parse(sn.Value);
((RevoluteJoint)joint).MotorSpeed = ParseFloat(sn.Value);
break;
case "lowerangle":
((RevoluteJoint)joint).LowerLimit = float.Parse(sn.Value);
((RevoluteJoint)joint).LowerLimit = ParseFloat(sn.Value);
break;
case "upperangle":
((RevoluteJoint)joint).UpperLimit = float.Parse(sn.Value);
((RevoluteJoint)joint).UpperLimit = ParseFloat(sn.Value);
break;
case "referenceangle":
((RevoluteJoint)joint).ReferenceAngle = float.Parse(sn.Value);
((RevoluteJoint)joint).ReferenceAngle = ParseFloat(sn.Value);
break;
}
}
@@ -1084,7 +1047,7 @@ namespace FarseerPhysics.Common
((RopeJoint)joint).LocalAnchorB = ReadVector(sn);
break;
case "maxlength":
((RopeJoint)joint).MaxLength = float.Parse(sn.Value);
((RopeJoint)joint).MaxLength = ParseFloat(sn.Value);
break;
}
}
@@ -1096,16 +1059,16 @@ namespace FarseerPhysics.Common
switch (sn.Name.ToLower())
{
case "biasfactor":
((AngleJoint)joint).BiasFactor = float.Parse(sn.Value);
((AngleJoint)joint).BiasFactor = ParseFloat(sn.Value);
break;
case "maximpulse":
((AngleJoint)joint).MaxImpulse = float.Parse(sn.Value);
((AngleJoint)joint).MaxImpulse = ParseFloat(sn.Value);
break;
case "softness":
((AngleJoint)joint).Softness = float.Parse(sn.Value);
((AngleJoint)joint).Softness = ParseFloat(sn.Value);
break;
case "targetangle":
((AngleJoint)joint).TargetAngle = float.Parse(sn.Value);
((AngleJoint)joint).TargetAngle = ParseFloat(sn.Value);
break;
}
}
@@ -1114,19 +1077,19 @@ namespace FarseerPhysics.Common
switch (sn.Name.ToLower())
{
case "angularoffset":
((MotorJoint)joint).AngularOffset = float.Parse(sn.Value);
((MotorJoint)joint).AngularOffset = ParseFloat(sn.Value);
break;
case "linearoffset":
((MotorJoint)joint).LinearOffset = ReadVector(sn);
break;
case "maxforce":
((MotorJoint)joint).MaxForce = float.Parse(sn.Value);
((MotorJoint)joint).MaxForce = ParseFloat(sn.Value);
break;
case "maxtorque":
((MotorJoint)joint).MaxTorque = float.Parse(sn.Value);
((MotorJoint)joint).MaxTorque = ParseFloat(sn.Value);
break;
case "correctionfactor":
((MotorJoint)joint).CorrectionFactor = float.Parse(sn.Value);
((MotorJoint)joint).CorrectionFactor = ParseFloat(sn.Value);
break;
}
break;
@@ -1142,7 +1105,7 @@ namespace FarseerPhysics.Common
private static Vector2 ReadVector(XMLFragmentElement node)
{
string[] values = node.Value.Split(' ');
return new Vector2(float.Parse(values[0]), float.Parse(values[1]));
return new Vector2(ParseFloat(values[0]), ParseFloat(values[1]));
}
private static object ReadSimpleType(XMLFragmentElement node, Type type, bool outer)
@@ -1151,8 +1114,6 @@ namespace FarseerPhysics.Common
return ReadSimpleType(node.Elements[1], Type.GetType(node.Elements[0].Value), outer);
XmlSerializer serializer = new XmlSerializer(type);
XmlSerializerNamespaces xmlnsEmpty = new XmlSerializerNamespaces();
xmlnsEmpty.Add("", "");
using (MemoryStream stream = new MemoryStream())
{
@@ -1168,6 +1129,12 @@ namespace FarseerPhysics.Common
return serializer.Deserialize(XmlReader.Create(stream, settings));
}
}
private static float ParseFloat(string value)
{
return float.Parse(value, System.Globalization.CultureInfo.InvariantCulture);
}
}
#region XMLFragment
@@ -1252,13 +1219,7 @@ namespace FarseerPhysics.Common
{
Load(stream);
}
public XMLFragmentParser(string fileName)
{
using (FileStream fs = new FileStream(fileName, FileMode.Open, FileAccess.Read))
Load(fs);
}
public XMLFragmentElement RootNode
{
get { return _rootNode; }
@@ -1,3 +1,8 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
#if SILVERLIGHT
using System;
@@ -1,4 +1,9 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using FarseerPhysics.Collision;
using Microsoft.Xna.Framework;
@@ -1,9 +1,13 @@
using System.Collections.Generic;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using FarseerPhysics.Collision;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Common.PolygonManipulation;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Common.TextureTools
@@ -218,7 +222,7 @@ namespace FarseerPhysics.Common.TextureTools
{
for (int i = 0; i < _bodyMap[x, y].Count; i++)
{
World.RemoveBody(_bodyMap[x, y][i]);
World.Remove(_bodyMap[x, y][i]);
}
}
@@ -256,7 +260,7 @@ namespace FarseerPhysics.Common.TextureTools
foreach (Vertices poly in decompPolys)
{
if (poly.Count > 2)
_bodyMap[gx, gy].Add(BodyFactory.CreatePolygon(World, poly, 1));
_bodyMap[gx, gy].Add(World.CreatePolygon(poly, 1));
}
}
}
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
using Microsoft.Xna.Framework;
@@ -1,588 +0,0 @@
#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID
#region License
/*
MIT License
Copyright © 2006 The Mono.Xna Team
All rights reserved.
Authors
* Alan McGovern
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#endregion License
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.Xna.Framework
{
[StructLayout(LayoutKind.Sequential)]
public struct Vector2 : IEquatable<Vector2>
{
#region Private Fields
private static Vector2 zeroVector = new Vector2(0f, 0f);
private static Vector2 unitVector = new Vector2(1f, 1f);
private static Vector2 unitXVector = new Vector2(1f, 0f);
private static Vector2 unitYVector = new Vector2(0f, 1f);
#endregion Private Fields
#region Public Fields
public float X;
public float Y;
#endregion Public Fields
#region Properties
public static Vector2 Zero
{
get { return zeroVector; }
}
public static Vector2 One
{
get { return unitVector; }
}
public static Vector2 UnitX
{
get { return unitXVector; }
}
public static Vector2 UnitY
{
get { return unitYVector; }
}
#endregion Properties
#region Constructors
/// <summary>
/// Constructor foe standard 2D vector.
/// </summary>
/// <param name="x">
/// A <see cref="System.Single"/>
/// </param>
/// <param name="y">
/// A <see cref="System.Single"/>
/// </param>
public Vector2(float x, float y)
{
X = x;
Y = y;
}
/// <summary>
/// Constructor for "square" vector.
/// </summary>
/// <param name="value">
/// A <see cref="System.Single"/>
/// </param>
public Vector2(float value)
{
X = value;
Y = value;
}
#endregion Constructors
#region Public Methods
public static void Reflect(ref Vector2 vector, ref Vector2 normal, out Vector2 result)
{
float dot = Dot(vector, normal);
result.X = vector.X - ((2f*dot)*normal.X);
result.Y = vector.Y - ((2f*dot)*normal.Y);
}
public static Vector2 Reflect(Vector2 vector, Vector2 normal)
{
Vector2 result;
Reflect(ref vector, ref normal, out result);
return result;
}
public static Vector2 Add(Vector2 value1, Vector2 value2)
{
value1.X += value2.X;
value1.Y += value2.Y;
return value1;
}
public static void Add(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X + value2.X;
result.Y = value1.Y + value2.Y;
}
public static Vector2 Barycentric(Vector2 value1, Vector2 value2, Vector2 value3, float amount1, float amount2)
{
return new Vector2(
MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));
}
public static void Barycentric(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, float amount1,
float amount2, out Vector2 result)
{
result = new Vector2(
MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2));
}
public static Vector2 CatmullRom(Vector2 value1, Vector2 value2, Vector2 value3, Vector2 value4, float amount)
{
return new Vector2(
MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));
}
public static void CatmullRom(ref Vector2 value1, ref Vector2 value2, ref Vector2 value3, ref Vector2 value4,
float amount, out Vector2 result)
{
result = new Vector2(
MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount));
}
public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max)
{
return new Vector2(
MathHelper.Clamp(value1.X, min.X, max.X),
MathHelper.Clamp(value1.Y, min.Y, max.Y));
}
public static void Clamp(ref Vector2 value1, ref Vector2 min, ref Vector2 max, out Vector2 result)
{
result = new Vector2(
MathHelper.Clamp(value1.X, min.X, max.X),
MathHelper.Clamp(value1.Y, min.Y, max.Y));
}
/// <summary>
/// Returns float precison distanve between two vectors
/// </summary>
/// <param name="value1">
/// A <see cref="Vector2"/>
/// </param>
/// <param name="value2">
/// A <see cref="Vector2"/>
/// </param>
/// <returns>
/// A <see cref="System.Single"/>
/// </returns>
public static float Distance(Vector2 value1, Vector2 value2)
{
float result;
DistanceSquared(ref value1, ref value2, out result);
return (float) Math.Sqrt(result);
}
public static void Distance(ref Vector2 value1, ref Vector2 value2, out float result)
{
DistanceSquared(ref value1, ref value2, out result);
result = (float) Math.Sqrt(result);
}
public static float DistanceSquared(Vector2 value1, Vector2 value2)
{
float result;
DistanceSquared(ref value1, ref value2, out result);
return result;
}
public static void DistanceSquared(ref Vector2 value1, ref Vector2 value2, out float result)
{
result = (value1.X - value2.X)*(value1.X - value2.X) + (value1.Y - value2.Y)*(value1.Y - value2.Y);
}
/// <summary>
/// Devide first vector with the secund vector
/// </summary>
/// <param name="value1">
/// A <see cref="Vector2"/>
/// </param>
/// <param name="value2">
/// A <see cref="Vector2"/>
/// </param>
/// <returns>
/// A <see cref="Vector2"/>
/// </returns>
public static Vector2 Divide(Vector2 value1, Vector2 value2)
{
value1.X /= value2.X;
value1.Y /= value2.Y;
return value1;
}
public static void Divide(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X/value2.X;
result.Y = value1.Y/value2.Y;
}
public static Vector2 Divide(Vector2 value1, float divider)
{
float factor = 1/divider;
value1.X *= factor;
value1.Y *= factor;
return value1;
}
public static void Divide(ref Vector2 value1, float divider, out Vector2 result)
{
float factor = 1/divider;
result.X = value1.X*factor;
result.Y = value1.Y*factor;
}
public static float Dot(Vector2 value1, Vector2 value2)
{
return value1.X*value2.X + value1.Y*value2.Y;
}
public static void Dot(ref Vector2 value1, ref Vector2 value2, out float result)
{
result = value1.X*value2.X + value1.Y*value2.Y;
}
public override bool Equals(object obj)
{
return (obj is Vector2) ? this == ((Vector2) obj) : false;
}
public bool Equals(Vector2 other)
{
return this == other;
}
public override int GetHashCode()
{
return (int) (X + Y);
}
public static Vector2 Hermite(Vector2 value1, Vector2 tangent1, Vector2 value2, Vector2 tangent2, float amount)
{
Vector2 result = new Vector2();
Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);
return result;
}
public static void Hermite(ref Vector2 value1, ref Vector2 tangent1, ref Vector2 value2, ref Vector2 tangent2,
float amount, out Vector2 result)
{
result.X = MathHelper.Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);
result.Y = MathHelper.Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);
}
public float Length()
{
float result;
DistanceSquared(ref this, ref zeroVector, out result);
return (float) Math.Sqrt(result);
}
public float LengthSquared()
{
float result;
DistanceSquared(ref this, ref zeroVector, out result);
return result;
}
public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount)
{
return new Vector2(
MathHelper.Lerp(value1.X, value2.X, amount),
MathHelper.Lerp(value1.Y, value2.Y, amount));
}
public static void Lerp(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)
{
result = new Vector2(
MathHelper.Lerp(value1.X, value2.X, amount),
MathHelper.Lerp(value1.Y, value2.Y, amount));
}
public static Vector2 Max(Vector2 value1, Vector2 value2)
{
return new Vector2(
MathHelper.Max(value1.X, value2.X),
MathHelper.Max(value1.Y, value2.Y));
}
public static void Max(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result = new Vector2(
MathHelper.Max(value1.X, value2.X),
MathHelper.Max(value1.Y, value2.Y));
}
public static Vector2 Min(Vector2 value1, Vector2 value2)
{
return new Vector2(
MathHelper.Min(value1.X, value2.X),
MathHelper.Min(value1.Y, value2.Y));
}
public static void Min(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result = new Vector2(
MathHelper.Min(value1.X, value2.X),
MathHelper.Min(value1.Y, value2.Y));
}
public static Vector2 Multiply(Vector2 value1, Vector2 value2)
{
value1.X *= value2.X;
value1.Y *= value2.Y;
return value1;
}
public static Vector2 Multiply(Vector2 value1, float scaleFactor)
{
value1.X *= scaleFactor;
value1.Y *= scaleFactor;
return value1;
}
public static void Multiply(ref Vector2 value1, float scaleFactor, out Vector2 result)
{
result.X = value1.X*scaleFactor;
result.Y = value1.Y*scaleFactor;
}
public static void Multiply(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X*value2.X;
result.Y = value1.Y*value2.Y;
}
public static Vector2 Negate(Vector2 value)
{
value.X = -value.X;
value.Y = -value.Y;
return value;
}
public static void Negate(ref Vector2 value, out Vector2 result)
{
result.X = -value.X;
result.Y = -value.Y;
}
public void Normalize()
{
Normalize(ref this, out this);
}
public static Vector2 Normalize(Vector2 value)
{
Normalize(ref value, out value);
return value;
}
public static void Normalize(ref Vector2 value, out Vector2 result)
{
float factor;
DistanceSquared(ref value, ref zeroVector, out factor);
factor = 1f/(float) Math.Sqrt(factor);
result.X = value.X*factor;
result.Y = value.Y*factor;
}
public static Vector2 SmoothStep(Vector2 value1, Vector2 value2, float amount)
{
return new Vector2(
MathHelper.SmoothStep(value1.X, value2.X, amount),
MathHelper.SmoothStep(value1.Y, value2.Y, amount));
}
public static void SmoothStep(ref Vector2 value1, ref Vector2 value2, float amount, out Vector2 result)
{
result = new Vector2(
MathHelper.SmoothStep(value1.X, value2.X, amount),
MathHelper.SmoothStep(value1.Y, value2.Y, amount));
}
public static Vector2 Subtract(Vector2 value1, Vector2 value2)
{
value1.X -= value2.X;
value1.Y -= value2.Y;
return value1;
}
public static void Subtract(ref Vector2 value1, ref Vector2 value2, out Vector2 result)
{
result.X = value1.X - value2.X;
result.Y = value1.Y - value2.Y;
}
public static Vector2 Transform(Vector2 position, Matrix matrix)
{
Transform(ref position, ref matrix, out position);
return position;
}
public static void Transform(ref Vector2 position, ref Matrix matrix, out Vector2 result)
{
result = new Vector2((position.X*matrix.M11) + (position.Y*matrix.M21) + matrix.M41,
(position.X*matrix.M12) + (position.Y*matrix.M22) + matrix.M42);
}
public static void Transform(Vector2[] sourceArray, ref Matrix matrix, Vector2[] destinationArray)
{
throw new NotImplementedException();
}
public static void Transform(Vector2[] sourceArray, int sourceIndex, ref Matrix matrix,
Vector2[] destinationArray, int destinationIndex, int length)
{
throw new NotImplementedException();
}
public static Vector2 TransformNormal(Vector2 normal, Matrix matrix)
{
TransformNormal(ref normal, ref matrix, out normal);
return normal;
}
public static void TransformNormal(ref Vector2 normal, ref Matrix matrix, out Vector2 result)
{
result = new Vector2((normal.X*matrix.M11) + (normal.Y*matrix.M21),
(normal.X*matrix.M12) + (normal.Y*matrix.M22));
}
public static void TransformNormal(Vector2[] sourceArray, ref Matrix matrix, Vector2[] destinationArray)
{
throw new NotImplementedException();
}
public static void TransformNormal(Vector2[] sourceArray, int sourceIndex, ref Matrix matrix,
Vector2[] destinationArray, int destinationIndex, int length)
{
throw new NotImplementedException();
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(24);
sb.Append("{X:");
sb.Append(X);
sb.Append(" Y:");
sb.Append(Y);
sb.Append("}");
return sb.ToString();
}
#endregion Public Methods
#region Operators
public static Vector2 operator -(Vector2 value)
{
value.X = -value.X;
value.Y = -value.Y;
return value;
}
public static bool operator ==(Vector2 value1, Vector2 value2)
{
return value1.X == value2.X && value1.Y == value2.Y;
}
public static bool operator !=(Vector2 value1, Vector2 value2)
{
return value1.X != value2.X || value1.Y != value2.Y;
}
public static Vector2 operator +(Vector2 value1, Vector2 value2)
{
value1.X += value2.X;
value1.Y += value2.Y;
return value1;
}
public static Vector2 operator -(Vector2 value1, Vector2 value2)
{
value1.X -= value2.X;
value1.Y -= value2.Y;
return value1;
}
public static Vector2 operator *(Vector2 value1, Vector2 value2)
{
value1.X *= value2.X;
value1.Y *= value2.Y;
return value1;
}
public static Vector2 operator *(Vector2 value, float scaleFactor)
{
value.X *= scaleFactor;
value.Y *= scaleFactor;
return value;
}
public static Vector2 operator *(float scaleFactor, Vector2 value)
{
value.X *= scaleFactor;
value.Y *= scaleFactor;
return value;
}
public static Vector2 operator /(Vector2 value1, Vector2 value2)
{
value1.X /= value2.X;
value1.Y /= value2.Y;
return value1;
}
public static Vector2 operator /(Vector2 value1, float divider)
{
float factor = 1/divider;
value1.X *= factor;
value1.Y *= factor;
return value1;
}
#endregion Operators
}
}
#endif
@@ -1,648 +0,0 @@
#if !XNA && !WINDOWS_PHONE && !XBOX && !ANDROID
#region License
/*
MIT License
Copyright © 2006 The Mono.Xna Team
All rights reserved.
Authors:
* Alan McGovern
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
#endregion License
using System;
using System.Runtime.InteropServices;
using System.Text;
namespace Microsoft.Xna.Framework
{
[StructLayout(LayoutKind.Sequential)]
public struct Vector3 : IEquatable<Vector3>
{
#region Private Fields
private static Vector3 zero = new Vector3(0f, 0f, 0f);
private static Vector3 one = new Vector3(1f, 1f, 1f);
private static Vector3 unitX = new Vector3(1f, 0f, 0f);
private static Vector3 unitY = new Vector3(0f, 1f, 0f);
private static Vector3 unitZ = new Vector3(0f, 0f, 1f);
private static Vector3 up = new Vector3(0f, 1f, 0f);
private static Vector3 down = new Vector3(0f, -1f, 0f);
private static Vector3 right = new Vector3(1f, 0f, 0f);
private static Vector3 left = new Vector3(-1f, 0f, 0f);
private static Vector3 forward = new Vector3(0f, 0f, -1f);
private static Vector3 backward = new Vector3(0f, 0f, 1f);
#endregion Private Fields
#region Public Fields
public float X;
public float Y;
public float Z;
#endregion Public Fields
#region Properties
public static Vector3 Zero
{
get { return zero; }
}
public static Vector3 One
{
get { return one; }
}
public static Vector3 UnitX
{
get { return unitX; }
}
public static Vector3 UnitY
{
get { return unitY; }
}
public static Vector3 UnitZ
{
get { return unitZ; }
}
public static Vector3 Up
{
get { return up; }
}
public static Vector3 Down
{
get { return down; }
}
public static Vector3 Right
{
get { return right; }
}
public static Vector3 Left
{
get { return left; }
}
public static Vector3 Forward
{
get { return forward; }
}
public static Vector3 Backward
{
get { return backward; }
}
#endregion Properties
#region Constructors
public Vector3(float x, float y, float z)
{
X = x;
Y = y;
Z = z;
}
public Vector3(float value)
{
X = value;
Y = value;
Z = value;
}
public Vector3(Vector2 value, float z)
{
X = value.X;
Y = value.Y;
Z = z;
}
#endregion Constructors
#region Public Methods
public static Vector3 Add(Vector3 value1, Vector3 value2)
{
value1.X += value2.X;
value1.Y += value2.Y;
value1.Z += value2.Z;
return value1;
}
public static void Add(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result.X = value1.X + value2.X;
result.Y = value1.Y + value2.Y;
result.Z = value1.Z + value2.Z;
}
public static Vector3 Barycentric(Vector3 value1, Vector3 value2, Vector3 value3, float amount1, float amount2)
{
return new Vector3(
MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),
MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));
}
public static void Barycentric(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, float amount1,
float amount2, out Vector3 result)
{
result = new Vector3(
MathHelper.Barycentric(value1.X, value2.X, value3.X, amount1, amount2),
MathHelper.Barycentric(value1.Y, value2.Y, value3.Y, amount1, amount2),
MathHelper.Barycentric(value1.Z, value2.Z, value3.Z, amount1, amount2));
}
public static Vector3 CatmullRom(Vector3 value1, Vector3 value2, Vector3 value3, Vector3 value4, float amount)
{
return new Vector3(
MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),
MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));
}
public static void CatmullRom(ref Vector3 value1, ref Vector3 value2, ref Vector3 value3, ref Vector3 value4,
float amount, out Vector3 result)
{
result = new Vector3(
MathHelper.CatmullRom(value1.X, value2.X, value3.X, value4.X, amount),
MathHelper.CatmullRom(value1.Y, value2.Y, value3.Y, value4.Y, amount),
MathHelper.CatmullRom(value1.Z, value2.Z, value3.Z, value4.Z, amount));
}
public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max)
{
return new Vector3(
MathHelper.Clamp(value1.X, min.X, max.X),
MathHelper.Clamp(value1.Y, min.Y, max.Y),
MathHelper.Clamp(value1.Z, min.Z, max.Z));
}
public static void Clamp(ref Vector3 value1, ref Vector3 min, ref Vector3 max, out Vector3 result)
{
result = new Vector3(
MathHelper.Clamp(value1.X, min.X, max.X),
MathHelper.Clamp(value1.Y, min.Y, max.Y),
MathHelper.Clamp(value1.Z, min.Z, max.Z));
}
public static Vector3 Cross(Vector3 vector1, Vector3 vector2)
{
Cross(ref vector1, ref vector2, out vector1);
return vector1;
}
public static void Cross(ref Vector3 vector1, ref Vector3 vector2, out Vector3 result)
{
result = new Vector3(vector1.Y*vector2.Z - vector2.Y*vector1.Z,
-(vector1.X*vector2.Z - vector2.X*vector1.Z),
vector1.X*vector2.Y - vector2.X*vector1.Y);
}
public static float Distance(Vector3 vector1, Vector3 vector2)
{
float result;
DistanceSquared(ref vector1, ref vector2, out result);
return (float) Math.Sqrt(result);
}
public static void Distance(ref Vector3 value1, ref Vector3 value2, out float result)
{
DistanceSquared(ref value1, ref value2, out result);
result = (float) Math.Sqrt(result);
}
public static float DistanceSquared(Vector3 value1, Vector3 value2)
{
float result;
DistanceSquared(ref value1, ref value2, out result);
return result;
}
public static void DistanceSquared(ref Vector3 value1, ref Vector3 value2, out float result)
{
result = (value1.X - value2.X)*(value1.X - value2.X) +
(value1.Y - value2.Y)*(value1.Y - value2.Y) +
(value1.Z - value2.Z)*(value1.Z - value2.Z);
}
public static Vector3 Divide(Vector3 value1, Vector3 value2)
{
value1.X /= value2.X;
value1.Y /= value2.Y;
value1.Z /= value2.Z;
return value1;
}
public static Vector3 Divide(Vector3 value1, float value2)
{
float factor = 1/value2;
value1.X *= factor;
value1.Y *= factor;
value1.Z *= factor;
return value1;
}
public static void Divide(ref Vector3 value1, float divisor, out Vector3 result)
{
float factor = 1/divisor;
result.X = value1.X*factor;
result.Y = value1.Y*factor;
result.Z = value1.Z*factor;
}
public static void Divide(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result.X = value1.X/value2.X;
result.Y = value1.Y/value2.Y;
result.Z = value1.Z/value2.Z;
}
public static float Dot(Vector3 vector1, Vector3 vector2)
{
return vector1.X*vector2.X + vector1.Y*vector2.Y + vector1.Z*vector2.Z;
}
public static void Dot(ref Vector3 vector1, ref Vector3 vector2, out float result)
{
result = vector1.X*vector2.X + vector1.Y*vector2.Y + vector1.Z*vector2.Z;
}
public override bool Equals(object obj)
{
return (obj is Vector3) ? this == (Vector3) obj : false;
}
public bool Equals(Vector3 other)
{
return this == other;
}
public override int GetHashCode()
{
return (int) (X + Y + Z);
}
public static Vector3 Hermite(Vector3 value1, Vector3 tangent1, Vector3 value2, Vector3 tangent2, float amount)
{
Vector3 result = new Vector3();
Hermite(ref value1, ref tangent1, ref value2, ref tangent2, amount, out result);
return result;
}
public static void Hermite(ref Vector3 value1, ref Vector3 tangent1, ref Vector3 value2, ref Vector3 tangent2,
float amount, out Vector3 result)
{
result.X = MathHelper.Hermite(value1.X, tangent1.X, value2.X, tangent2.X, amount);
result.Y = MathHelper.Hermite(value1.Y, tangent1.Y, value2.Y, tangent2.Y, amount);
result.Z = MathHelper.Hermite(value1.Z, tangent1.Z, value2.Z, tangent2.Z, amount);
}
public float Length()
{
float result;
DistanceSquared(ref this, ref zero, out result);
return (float) Math.Sqrt(result);
}
public float LengthSquared()
{
float result;
DistanceSquared(ref this, ref zero, out result);
return result;
}
public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount)
{
return new Vector3(
MathHelper.Lerp(value1.X, value2.X, amount),
MathHelper.Lerp(value1.Y, value2.Y, amount),
MathHelper.Lerp(value1.Z, value2.Z, amount));
}
public static void Lerp(ref Vector3 value1, ref Vector3 value2, float amount, out Vector3 result)
{
result = new Vector3(
MathHelper.Lerp(value1.X, value2.X, amount),
MathHelper.Lerp(value1.Y, value2.Y, amount),
MathHelper.Lerp(value1.Z, value2.Z, amount));
}
public static Vector3 Max(Vector3 value1, Vector3 value2)
{
return new Vector3(
MathHelper.Max(value1.X, value2.X),
MathHelper.Max(value1.Y, value2.Y),
MathHelper.Max(value1.Z, value2.Z));
}
public static void Max(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result = new Vector3(
MathHelper.Max(value1.X, value2.X),
MathHelper.Max(value1.Y, value2.Y),
MathHelper.Max(value1.Z, value2.Z));
}
public static Vector3 Min(Vector3 value1, Vector3 value2)
{
return new Vector3(
MathHelper.Min(value1.X, value2.X),
MathHelper.Min(value1.Y, value2.Y),
MathHelper.Min(value1.Z, value2.Z));
}
public static void Min(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result = new Vector3(
MathHelper.Min(value1.X, value2.X),
MathHelper.Min(value1.Y, value2.Y),
MathHelper.Min(value1.Z, value2.Z));
}
public static Vector3 Multiply(Vector3 value1, Vector3 value2)
{
value1.X *= value2.X;
value1.Y *= value2.Y;
value1.Z *= value2.Z;
return value1;
}
public static Vector3 Multiply(Vector3 value1, float scaleFactor)
{
value1.X *= scaleFactor;
value1.Y *= scaleFactor;
value1.Z *= scaleFactor;
return value1;
}
public static void Multiply(ref Vector3 value1, float scaleFactor, out Vector3 result)
{
result.X = value1.X*scaleFactor;
result.Y = value1.Y*scaleFactor;
result.Z = value1.Z*scaleFactor;
}
public static void Multiply(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result.X = value1.X*value2.X;
result.Y = value1.Y*value2.Y;
result.Z = value1.Z*value2.Z;
}
public static Vector3 Negate(Vector3 value)
{
value = new Vector3(-value.X, -value.Y, -value.Z);
return value;
}
public static void Negate(ref Vector3 value, out Vector3 result)
{
result = new Vector3(-value.X, -value.Y, -value.Z);
}
public void Normalize()
{
Normalize(ref this, out this);
}
public static Vector3 Normalize(Vector3 vector)
{
Normalize(ref vector, out vector);
return vector;
}
public static void Normalize(ref Vector3 value, out Vector3 result)
{
float factor;
Distance(ref value, ref zero, out factor);
factor = 1f/factor;
result.X = value.X*factor;
result.Y = value.Y*factor;
result.Z = value.Z*factor;
}
public static Vector3 Reflect(Vector3 vector, Vector3 normal)
{
Vector3 result;
Reflect(ref vector, ref normal, out result);
return result;
}
public static void Reflect(ref Vector3 vector, ref Vector3 normal, out Vector3 result)
{
float dot = Dot(vector, normal);
result.X = vector.X - ((2f*dot)*normal.X);
result.Y = vector.Y - ((2f*dot)*normal.Y);
result.Z = vector.Z - ((2f*dot)*normal.Z);
}
public static Vector3 SmoothStep(Vector3 value1, Vector3 value2, float amount)
{
return new Vector3(
MathHelper.SmoothStep(value1.X, value2.X, amount),
MathHelper.SmoothStep(value1.Y, value2.Y, amount),
MathHelper.SmoothStep(value1.Z, value2.Z, amount));
}
public static void SmoothStep(ref Vector3 value1, ref Vector3 value2, float amount, out Vector3 result)
{
result = new Vector3(
MathHelper.SmoothStep(value1.X, value2.X, amount),
MathHelper.SmoothStep(value1.Y, value2.Y, amount),
MathHelper.SmoothStep(value1.Z, value2.Z, amount));
}
public static Vector3 Subtract(Vector3 value1, Vector3 value2)
{
value1.X -= value2.X;
value1.Y -= value2.Y;
value1.Z -= value2.Z;
return value1;
}
public static void Subtract(ref Vector3 value1, ref Vector3 value2, out Vector3 result)
{
result.X = value1.X - value2.X;
result.Y = value1.Y - value2.Y;
result.Z = value1.Z - value2.Z;
}
public override string ToString()
{
StringBuilder sb = new StringBuilder(32);
sb.Append("{X:");
sb.Append(X);
sb.Append(" Y:");
sb.Append(Y);
sb.Append(" Z:");
sb.Append(Z);
sb.Append("}");
return sb.ToString();
}
public static Vector3 Transform(Vector3 position, Matrix matrix)
{
Transform(ref position, ref matrix, out position);
return position;
}
public static void Transform(ref Vector3 position, ref Matrix matrix, out Vector3 result)
{
result =
new Vector3((position.X*matrix.M11) + (position.Y*matrix.M21) + (position.Z*matrix.M31) + matrix.M41,
(position.X*matrix.M12) + (position.Y*matrix.M22) + (position.Z*matrix.M32) + matrix.M42,
(position.X*matrix.M13) + (position.Y*matrix.M23) + (position.Z*matrix.M33) + matrix.M43);
}
public static void Transform(Vector3[] sourceArray, ref Matrix matrix, Vector3[] destinationArray)
{
throw new NotImplementedException();
}
public static void Transform(Vector3[] sourceArray, int sourceIndex, ref Matrix matrix,
Vector3[] destinationArray, int destinationIndex, int length)
{
throw new NotImplementedException();
}
public static void TransformNormal(Vector3[] sourceArray, ref Matrix matrix, Vector3[] destinationArray)
{
throw new NotImplementedException();
}
public static void TransformNormal(Vector3[] sourceArray, int sourceIndex, ref Matrix matrix,
Vector3[] destinationArray, int destinationIndex, int length)
{
throw new NotImplementedException();
}
public static Vector3 TransformNormal(Vector3 normal, Matrix matrix)
{
TransformNormal(ref normal, ref matrix, out normal);
return normal;
}
public static void TransformNormal(ref Vector3 normal, ref Matrix matrix, out Vector3 result)
{
result = new Vector3((normal.X*matrix.M11) + (normal.Y*matrix.M21) + (normal.Z*matrix.M31),
(normal.X*matrix.M12) + (normal.Y*matrix.M22) + (normal.Z*matrix.M32),
(normal.X*matrix.M13) + (normal.Y*matrix.M23) + (normal.Z*matrix.M33));
}
#endregion Public methods
#region Operators
public static bool operator ==(Vector3 value1, Vector3 value2)
{
return value1.X == value2.X
&& value1.Y == value2.Y
&& value1.Z == value2.Z;
}
public static bool operator !=(Vector3 value1, Vector3 value2)
{
return !(value1 == value2);
}
public static Vector3 operator +(Vector3 value1, Vector3 value2)
{
value1.X += value2.X;
value1.Y += value2.Y;
value1.Z += value2.Z;
return value1;
}
public static Vector3 operator -(Vector3 value)
{
value = new Vector3(-value.X, -value.Y, -value.Z);
return value;
}
public static Vector3 operator -(Vector3 value1, Vector3 value2)
{
value1.X -= value2.X;
value1.Y -= value2.Y;
value1.Z -= value2.Z;
return value1;
}
public static Vector3 operator *(Vector3 value1, Vector3 value2)
{
value1.X *= value2.X;
value1.Y *= value2.Y;
value1.Z *= value2.Z;
return value1;
}
public static Vector3 operator *(Vector3 value, float scaleFactor)
{
value.X *= scaleFactor;
value.Y *= scaleFactor;
value.Z *= scaleFactor;
return value;
}
public static Vector3 operator *(float scaleFactor, Vector3 value)
{
value.X *= scaleFactor;
value.Y *= scaleFactor;
value.Z *= scaleFactor;
return value;
}
public static Vector3 operator /(Vector3 value1, Vector3 value2)
{
value1.X /= value2.X;
value1.Y /= value2.Y;
value1.Z /= value2.Z;
return value1;
}
public static Vector3 operator /(Vector3 value, float divider)
{
float factor = 1/divider;
value.X *= factor;
value.Y *= factor;
value.Z *= factor;
return value;
}
#endregion
}
}
#endif
@@ -1,4 +1,9 @@
/*
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*/
@@ -49,10 +54,8 @@ namespace FarseerPhysics.Common
/// </summary>
SideTooSmall
}
#if !(XBOX360)
[DebuggerDisplay("Count = {Count} Vertices = {ToString()}")]
#endif
public class Vertices : List<Vector2>
{
public Vertices() { }
@@ -0,0 +1,53 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Content
{
public class FixtureTemplate
{
public Shape Shape;
public float Restitution;
public float Friction;
public string Name;
}
public class BodyTemplate
{
public List<FixtureTemplate> Fixtures;
public float Mass;
public BodyType BodyType;
public BodyTemplate()
{
Fixtures = new List<FixtureTemplate>();
}
public Body Create(World world)
{
Body body = world.CreateBody();
body.BodyType = BodyType;
foreach (FixtureTemplate fixtureTemplate in Fixtures)
{
Fixture fixture = body.CreateFixture(fixtureTemplate.Shape);
fixture.UserData = fixtureTemplate.Name;
fixture.Restitution = fixtureTemplate.Restitution;
fixture.Friction = fixtureTemplate.Friction;
}
if (Mass > 0f)
body.Mass = Mass;
return body;
}
}
public class BodyContainer : Dictionary<string, BodyTemplate> { }
}
@@ -0,0 +1,54 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
/*namespace FarseerPhysics.Content
{
public struct Polygon
{
public Vertices Vertices;
public bool Closed;
public Polygon(Vertices v, bool closed)
{
Vertices = v;
Closed = closed;
}
}
public class PolygonContainer : Dictionary<string, Polygon>
{
public bool IsDecomposed
{
get { return _decomposed; }
}
private bool _decomposed;
public void Decompose()
{
Dictionary<string, Polygon> containerCopy = new Dictionary<string, Polygon>(this);
foreach (string key in containerCopy.Keys)
{
if (containerCopy[key].Closed)
{
List<Vertices> partition = Triangulate.ConvexPartition(containerCopy[key].Vertices, TriangulationAlgorithm.Bayazit);
if (partition.Count > 1)
{
Remove(key);
for (int i = 0; i < partition.Count; i++)
{
this[key + "_" + i.ToString()] = new Polygon(partition[i], true);
}
}
_decomposed = true;
}
}
}
}
}*/
@@ -0,0 +1,94 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
//using Microsoft.Xna.Framework.Content;
/*namespace FarseerPhysics.Content
{
public class BodyContainerReader : ContentTypeReader<BodyContainer>
{
protected override BodyContainer Read(ContentReader input, BodyContainer existingInstance)
{
BodyContainer bodies = existingInstance ?? new BodyContainer();
int count = input.ReadInt32();
for (int i = 0; i < count; i++)
{
string name = input.ReadString();
BodyTemplate body = new BodyTemplate
{
Mass = input.ReadSingle(),
BodyType = (BodyType)input.ReadInt32()
};
int fixtureCount = input.ReadInt32();
for (int j = 0; j < fixtureCount; j++)
{
FixtureTemplate fixture = new FixtureTemplate
{
Name = input.ReadString(),
Restitution = input.ReadSingle(),
Friction = input.ReadSingle()
};
ShapeType type = (ShapeType)input.ReadInt32();
switch (type)
{
case ShapeType.Circle:
{
float density = input.ReadSingle();
float radius = input.ReadSingle();
CircleShape circle = new CircleShape(radius, density);
circle.Position = input.ReadVector2();
fixture.Shape = circle;
} break;
case ShapeType.Polygon:
{
Vertices verts = new Vertices(Settings.MaxPolygonVertices);
float density = input.ReadSingle();
int verticeCount = input.ReadInt32();
for (int k = 0; k < verticeCount; k++)
{
verts.Add(input.ReadVector2());
}
PolygonShape poly = new PolygonShape(verts, density);
poly.MassData.Centroid = input.ReadVector2();
fixture.Shape = poly;
} break;
case ShapeType.Edge:
{
EdgeShape edge = new EdgeShape(input.ReadVector2(), input.ReadVector2());
edge.HasVertex0 = input.ReadBoolean();
if (edge.HasVertex0)
{
edge.Vertex0 = input.ReadVector2();
}
edge.HasVertex3 = input.ReadBoolean();
if (edge.HasVertex3)
{
edge.Vertex3 = input.ReadVector2();
}
fixture.Shape = edge;
} break;
case ShapeType.Chain:
{
Vertices verts = new Vertices();
int verticeCount = input.ReadInt32();
for (int k = 0; k < verticeCount; k++)
{
verts.Add(input.ReadVector2());
}
fixture.Shape = new ChainShape(verts);
} break;
}
body.Fixtures.Add(fixture);
}
bodies[name] = body;
}
return bodies;
}
}
}*/
@@ -0,0 +1,34 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Common;
//using Microsoft.Xna.Framework.Content;
/*namespace FarseerPhysics.Content
{
public class PolygonContainerReader : ContentTypeReader<PolygonContainer>
{
protected override PolygonContainer Read(ContentReader input, PolygonContainer existingInstance)
{
PolygonContainer paths = existingInstance ?? new PolygonContainer();
int count = input.ReadInt32();
for (int i = 0; i < count; i++)
{
string name = input.ReadString();
bool closed = input.ReadBoolean();
int vertsCount = input.ReadInt32();
Vertices verts = new Vertices();
for (int j = 0; j < vertsCount; j++)
{
verts.Add(input.ReadVector2());
}
paths[name] = new Polygon(verts, closed);
}
return paths;
}
}
}*/
@@ -1,6 +1,12 @@
using System;
using FarseerPhysics.Dynamics;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using Microsoft.Xna.Framework;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Controllers
{
@@ -85,10 +91,7 @@ namespace FarseerPhysics.Controllers
/// Constructor
/// </summary>
public AbstractForceController()
: base(ControllerType.AbstractForceController)
{
Enabled = true;
Strength = 1.0f;
Position = new Vector2(0, 0);
MaximumSpeed = 100.0f;
@@ -115,7 +118,6 @@ namespace FarseerPhysics.Controllers
/// </summary>
/// <param name="mode"></param>
public AbstractForceController(TimingModes mode)
: base(ControllerType.AbstractForceController)
{
TimingMode = mode;
switch (mode)
@@ -1,8 +1,14 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections.Generic;
using Microsoft.Xna.Framework;
using FarseerPhysics.Collision;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Controllers
{
@@ -35,7 +41,7 @@ namespace FarseerPhysics.Controllers
private Vector2 _gravity;
private Vector2 _normal;
private float _offset;
private Dictionary<int, Body> _uniqueBodies = new Dictionary<int, Body>();
private ICollection<Body> _uniqueBodies = new List<Body>();
/// <summary>
/// Initializes a new instance of the <see cref="BuoyancyController"/> class.
@@ -46,7 +52,6 @@ namespace FarseerPhysics.Controllers
/// <param name="rotationalDragCoefficient">Rotational drag coefficient of the fluid</param>
/// <param name="gravity">The direction gravity acts. Buoyancy force will act in opposite direction of gravity.</param>
public BuoyancyController(AABB container, float density, float linearDragCoefficient, float rotationalDragCoefficient, Vector2 gravity)
: base(ControllerType.BuoyancyController)
{
Container = container;
_normal = new Vector2(0, 1);
@@ -71,19 +76,17 @@ namespace FarseerPhysics.Controllers
_uniqueBodies.Clear();
World.QueryAABB(fixture =>
{
if (fixture.Body.IsStatic || !fixture.Body.Awake)
if (fixture.Body.BodyType == BodyType.Static || !fixture.Body.Awake)
return true;
if (!_uniqueBodies.ContainsKey(fixture.Body.BodyId))
_uniqueBodies.Add(fixture.Body.BodyId, fixture.Body);
if (!_uniqueBodies.Contains(fixture.Body))
_uniqueBodies.Add(fixture.Body);
return true;
}, ref _container);
foreach (KeyValuePair<int, Body> kv in _uniqueBodies)
foreach (Body body in _uniqueBodies)
{
Body body = kv.Value;
Vector2 areac = Vector2.Zero;
Vector2 massc = Vector2.Zero;
float area = 0;
@@ -1,67 +1,28 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Controllers
{
[Flags]
public enum ControllerType
{
GravityController = (1 << 0),
VelocityLimitController = (1 << 1),
AbstractForceController = (1 << 2),
BuoyancyController = (1 << 3),
}
public struct ControllerFilter
{
public ControllerType ControllerFlags;
/// <summary>
/// Ignores the controller. The controller has no effect on this body.
/// </summary>
/// <param name="controller">The controller type.</param>
public void IgnoreController(ControllerType controller)
{
ControllerFlags |= controller;
}
/// <summary>
/// Restore the controller. The controller affects this body.
/// </summary>
/// <param name="controller">The controller type.</param>
public void RestoreController(ControllerType controller)
{
ControllerFlags &= ~controller;
}
/// <summary>
/// Determines whether this body ignores the the specified controller.
/// </summary>
/// <param name="controller">The controller type.</param>
/// <returns>
/// <c>true</c> if the body has the specified flag; otherwise, <c>false</c>.
/// </returns>
public bool IsControllerIgnored(ControllerType controller)
{
return (ControllerFlags & controller) == controller;
}
}
public abstract class Controller : FilterData
{
public bool Enabled;
public World World;
private ControllerType _type;
public ControllerCategory ControllerCategory = ControllerCategory.Cat01;
public Controller(ControllerType controllerType)
public bool Enabled = true;
public World World { get; internal set; }
public Controller()
{
_type = controllerType;
}
public override bool IsActiveOn(Body body)
{
if (body.ControllerFilter.IsControllerIgnored(_type))
if (body.ControllerFilter.IsControllerIgnored(ControllerCategory))
return false;
return base.IsActiveOn(body);
@@ -1,7 +1,13 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Controllers
{
@@ -14,7 +20,6 @@ namespace FarseerPhysics.Controllers
public class GravityController : Controller
{
public GravityController(float strength)
: base(ControllerType.GravityController)
{
Strength = strength;
MaxRadius = float.MaxValue;
@@ -24,7 +29,6 @@ namespace FarseerPhysics.Controllers
}
public GravityController(float strength, float maxRadius, float minRadius)
: base(ControllerType.GravityController)
{
MinRadius = minRadius;
MaxRadius = maxRadius;
@@ -52,7 +56,7 @@ namespace FarseerPhysics.Controllers
foreach (Body controllerBody in Bodies)
{
if (worldBody == controllerBody || (worldBody.IsStatic && controllerBody.IsStatic) || !controllerBody.Enabled)
if (worldBody == controllerBody || (worldBody.BodyType == BodyType.Static && controllerBody.BodyType == BodyType.Static) || !controllerBody.Enabled)
continue;
Vector2 d = controllerBody.Position - worldBody.Position;
@@ -1,4 +1,9 @@
using FarseerPhysics.Dynamics;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Controllers
@@ -1,5 +1,11 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Common.PhysicsLogic;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Controllers
@@ -24,7 +30,6 @@ namespace FarseerPhysics.Controllers
/// Sets the max angular velocity to Settings.MaxRotation
/// </summary>
public VelocityLimitController()
: base(ControllerType.VelocityLimitController)
{
MaxLinearVelocity = Settings.MaxTranslation;
MaxAngularVelocity = Settings.MaxRotation;
@@ -38,7 +43,6 @@ namespace FarseerPhysics.Controllers
/// <param name="maxLinearVelocity">The max linear velocity.</param>
/// <param name="maxAngularVelocity">The max angular velocity.</param>
public VelocityLimitController(float maxLinearVelocity, float maxAngularVelocity)
: base(ControllerType.VelocityLimitController)
{
if (maxLinearVelocity == 0 || maxLinearVelocity == float.MaxValue)
LimitLinearVelocity = false;
@@ -0,0 +1,99 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*/
using Microsoft.Xna.Framework;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics;
namespace FarseerPhysics.Diagnostics
{
/// Implement and register this class with a World to provide debug drawing of physics
/// entities in your game.
public abstract class DebugViewBase
{
protected DebugViewBase(World world)
{
World = world;
}
protected World World { get; private set; }
/// <summary>
/// Gets or sets the debug view flags.
/// </summary>
/// <value>The flags.</value>
public DebugViewFlags Flags { get; set; }
/// <summary>
/// Append flags to the current flags.
/// </summary>
/// <param name="flags">The flags.</param>
public void AppendFlags(DebugViewFlags flags)
{
Flags |= flags;
}
/// <summary>
/// Remove flags from the current flags.
/// </summary>
/// <param name="flags">The flags.</param>
public void RemoveFlags(DebugViewFlags flags)
{
Flags &= ~flags;
}
/// <summary>
/// Draw a closed polygon provided in CCW order.
/// </summary>
/// <param name="vertices">The vertices.</param>
/// <param name="count">The vertex count.</param>
/// <param name="color">The color value.</param>
//public abstract void DrawPolygon(Vector2[] vertices, int count, Color color, bool closed = true);
/// <summary>
/// Draw a solid closed polygon provided in CCW order.
/// </summary>
/// <param name="vertices">The vertices.</param>
/// <param name="count">The vertex count.</param>
/// <param name="color">The color value.</param>
//public abstract void DrawSolidPolygon(Vector2[] vertices, int count, Color color);
/// <summary>
/// Draw a circle.
/// </summary>
/// <param name="center">The center.</param>
/// <param name="radius">The radius.</param>
/// <param name="color">The color value.</param>
//public abstract void DrawCircle(Vector2 center, float radius, Color color);
/// <summary>
/// Draw a solid circle.
/// </summary>
/// <param name="center">The center.</param>
/// <param name="radius">The radius.</param>
/// <param name="axis">The axis.</param>
/// <param name="color">The color value.</param>
//public abstract void DrawSolidCircle(Vector2 center, float radius, Vector2 axis, Color color);
/// <summary>
/// Draw a line segment.
/// </summary>
/// <param name="start">The start.</param>
/// <param name="end">The end.</param>
/// <param name="color">The color value.</param>
//public abstract void DrawSegment(Vector2 start, Vector2 end, Color color);
/// <summary>
/// Draw a transform. Choose your own length scale.
/// </summary>
/// <param name="transform">The transform.</param>
//public abstract void DrawTransform(ref Transform transform);
}
}
@@ -0,0 +1,73 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*/
using System;
namespace FarseerPhysics.Diagnostics
{
[Flags]
public enum DebugViewFlags
{
/// <summary>
/// Draw shapes.
/// </summary>
Shape = (1 << 0),
/// <summary>
/// Draw joint connections.
/// </summary>
Joint = (1 << 1),
/// <summary>
/// Draw axis aligned bounding boxes.
/// </summary>
AABB = (1 << 2),
/// <summary>
/// Draw broad-phase pairs.
/// </summary>
//Pair = (1 << 3),
/// <summary>
/// Draw center of mass frame.
/// </summary>
CenterOfMass = (1 << 4),
/// <summary>
/// Draw useful debug data such as timings and number of bodies, joints, contacts and more.
/// </summary>
DebugPanel = (1 << 5),
/// <summary>
/// Draw contact points between colliding bodies.
/// </summary>
ContactPoints = (1 << 6),
/// <summary>
/// Draw contact normals. Need ContactPoints to be enabled first.
/// </summary>
ContactNormals = (1 << 7),
/// <summary>
/// Draws the vertices of polygons.
/// </summary>
PolygonPoints = (1 << 8),
/// <summary>
/// Draws the performance graph.
/// </summary>
PerformanceGraph = (1 << 9),
/// <summary>
/// Draws controllers.
/// </summary>
Controllers = (1 << 10)
}
}
@@ -1,4 +1,9 @@
using System;
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
@@ -6,76 +11,92 @@ using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Dynamics;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Factories
namespace FarseerPhysics.Dynamics
{
/// <summary>
/// An easy to use factory for creating bodies
/// </summary>
public static class FixtureFactory
public partial class Body
{
public static Fixture AttachEdge(Vector2 start, Vector2 end, Body body, object userData = null)
/// <summary>
/// Creates a fixture and attach it to this body.
/// If the density is non-zero, this function automatically updates the mass of the body.
/// Contacts are not created until the next time step.
/// Warning: This method is locked during callbacks.
/// </summary>
/// <param name="shape">The shape.</param>
/// <param name="userData">Application specific data</param>
/// <returns></returns>
public virtual Fixture CreateFixture(Shape shape)
{
Fixture fixture = new Fixture(shape);
Add(fixture);
return fixture;
}
public Fixture CreateEdge(Vector2 start, Vector2 end)
{
EdgeShape edgeShape = new EdgeShape(start, end);
return body.CreateFixture(edgeShape, userData);
return CreateFixture(edgeShape);
}
public static Fixture AttachChainShape(Vertices vertices, Body body, object userData = null)
public Fixture CreateChainShape(Vertices vertices)
{
ChainShape shape = new ChainShape(vertices);
return body.CreateFixture(shape, userData);
return CreateFixture(shape);
}
public static Fixture AttachLoopShape(Vertices vertices, Body body, object userData = null)
public Fixture CreateLoopShape(Vertices vertices)
{
ChainShape shape = new ChainShape(vertices, true);
return body.CreateFixture(shape, userData);
return CreateFixture(shape);
}
public static Fixture AttachRectangle(float width, float height, float density, Vector2 offset, Body body, object userData = null)
public Fixture CreateRectangle(float width, float height, float density, Vector2 offset)
{
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2);
rectangleVertices.Translate(ref offset);
PolygonShape rectangleShape = new PolygonShape(rectangleVertices, density);
return body.CreateFixture(rectangleShape, userData);
return CreateFixture(rectangleShape);
}
public static Fixture AttachRectangle(float width, float height, float density, float angle, Vector2 offset, Body body, object userData = null)
public Fixture CreateRectangle(float width, float height, float density, float rotation, Vector2 offset)
{
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2, Vector2.Zero, angle);
Vertices rectangleVertices = PolygonTools.CreateRectangle(width / 2, height / 2, Vector2.Zero, rotation);
rectangleVertices.Translate(ref offset);
PolygonShape rectangleShape = new PolygonShape(rectangleVertices, density);
return body.CreateFixture(rectangleShape, userData);
return CreateFixture(rectangleShape);
}
public static Fixture AttachCircle(float radius, float density, Body body, object userData = null)
public Fixture CreateCircle(float radius, float density)
{
if (radius <= 0)
throw new ArgumentOutOfRangeException("radius", "Radius must be more than 0 meters");
CircleShape circleShape = new CircleShape(radius, density);
return body.CreateFixture(circleShape, userData);
return CreateFixture(circleShape);
}
public static Fixture AttachCircle(float radius, float density, Body body, Vector2 offset, object userData = null)
public Fixture CreateCircle(float radius, float density, Vector2 offset)
{
if (radius <= 0)
throw new ArgumentOutOfRangeException("radius", "Radius must be more than 0 meters");
CircleShape circleShape = new CircleShape(radius, density);
circleShape.Position = offset;
return body.CreateFixture(circleShape, userData);
return CreateFixture(circleShape);
}
public static Fixture AttachPolygon(Vertices vertices, float density, Body body, object userData = null)
public Fixture CreatePolygon(Vertices vertices, float density)
{
if (vertices.Count <= 1)
throw new ArgumentOutOfRangeException("vertices", "Too few points to be a polygon");
PolygonShape polygon = new PolygonShape(vertices, density);
return body.CreateFixture(polygon, userData);
return CreateFixture(polygon);
}
public static Fixture AttachEllipse(float xRadius, float yRadius, int edges, float density, Body body, object userData = null)
public Fixture CreateEllipse(float xRadius, float yRadius, int edges, float density)
{
if (xRadius <= 0)
throw new ArgumentOutOfRangeException("xRadius", "X-radius must be more than 0");
@@ -85,10 +106,10 @@ namespace FarseerPhysics.Factories
Vertices ellipseVertices = PolygonTools.CreateEllipse(xRadius, yRadius, edges);
PolygonShape polygonShape = new PolygonShape(ellipseVertices, density);
return body.CreateFixture(polygonShape, userData);
return CreateFixture(polygonShape);
}
public static List<Fixture> AttachCompoundPolygon(List<Vertices> list, float density, Body body, object userData = null)
public List<Fixture> CreateCompoundPolygon(List<Vertices> list, float density)
{
List<Fixture> res = new List<Fixture>(list.Count);
@@ -98,40 +119,36 @@ namespace FarseerPhysics.Factories
if (vertices.Count == 2)
{
EdgeShape shape = new EdgeShape(vertices[0], vertices[1]);
res.Add(body.CreateFixture(shape, userData));
res.Add(CreateFixture(shape));
}
else
{
PolygonShape shape = new PolygonShape(vertices, density);
res.Add(body.CreateFixture(shape, userData));
res.Add(CreateFixture(shape));
}
}
return res;
}
public static Fixture AttachLineArc(float radians, int sides, float radius, Vector2 position, float angle, bool closed, Body body)
public Fixture CreateLineArc(float radians, int sides, float radius, bool closed)
{
Vertices arc = PolygonTools.CreateArc(radians, sides, radius);
arc.Rotate((MathHelper.Pi - radians) / 2 + angle);
arc.Translate(ref position);
return closed ? AttachLoopShape(arc, body) : AttachChainShape(arc, body);
arc.Rotate((MathHelper.Pi - radians) / 2);
return closed ? CreateLoopShape(arc) : CreateChainShape(arc);
}
public static List<Fixture> AttachSolidArc(float density, float radians, int sides, float radius, Vector2 position, float angle, Body body)
public List<Fixture> CreateSolidArc(float density, float radians, int sides, float radius)
{
Vertices arc = PolygonTools.CreateArc(radians, sides, radius);
arc.Rotate((MathHelper.Pi - radians) / 2 + angle);
arc.Translate(ref position);
arc.Rotate((MathHelper.Pi - radians) / 2);
//Close the arc
arc.Add(arc[0]);
List<Vertices> triangles = Triangulate.ConvexPartition(arc, TriangulationAlgorithm.Earclip);
return AttachCompoundPolygon(triangles, density, body);
return CreateCompoundPolygon(triangles, density);
}
}
}
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,49 @@
/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
/*
* Farseer Physics Engine:
* Copyright (c) 2012 Ian Qvist
*
* Original source Box2D:
* Copyright (c) 2006-2011 Erin Catto http://www.box2d.org
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
namespace FarseerPhysics
{
/// <summary>
/// The body type.
/// </summary>
public enum BodyType
{
/// <summary>
/// Zero velocity, may be manually moved. Note: even static bodies have mass.
/// </summary>
Static,
/// <summary>
/// Zero mass, non-zero velocity set by user, moved by solver
/// </summary>
Kinematic,
/// <summary>
/// Positive mass, non-zero velocity determined by forces, moved by solver
/// </summary>
Dynamic,
}
}
@@ -1,148 +0,0 @@
using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Dynamics.Contacts;
using FarseerPhysics.Factories;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Dynamics
{
/// <summary>
/// A type of body that supports multiple fixtures that can break apart.
/// </summary>
public class BreakableBody
{
private float[] _angularVelocitiesCache = new float[8];
private bool _break;
private Vector2[] _velocitiesCache = new Vector2[8];
private World _world;
public BreakableBody(IEnumerable<Vertices> vertices, World world, float density)
{
_world = world;
_world.ContactManager.PostSolve += PostSolve;
MainBody = new Body(_world);
MainBody.BodyType = BodyType.Dynamic;
foreach (Vertices part in vertices)
{
PolygonShape polygonShape = new PolygonShape(part, density);
Fixture fixture = MainBody.CreateFixture(polygonShape);
Parts.Add(fixture);
}
}
public BreakableBody(IEnumerable<Shape> shapes, World world)
{
_world = world;
_world.ContactManager.PostSolve += PostSolve;
MainBody = new Body(_world);
MainBody.BodyType = BodyType.Dynamic;
foreach (Shape part in shapes)
{
Fixture fixture = MainBody.CreateFixture(part);
Parts.Add(fixture);
}
}
public bool Broken;
public Body MainBody;
public List<Fixture> Parts = new List<Fixture>(8);
/// <summary>
/// The force needed to break the body apart.
/// Default: 500
/// </summary>
public float Strength = 500.0f;
private void PostSolve(Contact contact, ContactVelocityConstraint impulse)
{
if (!Broken)
{
if (Parts.Contains(contact.FixtureA) || Parts.Contains(contact.FixtureB))
{
float maxImpulse = 0.0f;
int count = contact.Manifold.PointCount;
for (int i = 0; i < count; ++i)
{
maxImpulse = Math.Max(maxImpulse, impulse.points[i].normalImpulse);
}
if (maxImpulse > Strength)
{
// Flag the body for breaking.
_break = true;
}
}
}
}
public void Update()
{
if (_break)
{
Decompose();
Broken = true;
_break = false;
}
// Cache velocities to improve movement on breakage.
if (Broken == false)
{
//Enlarge the cache if needed
if (Parts.Count > _angularVelocitiesCache.Length)
{
_velocitiesCache = new Vector2[Parts.Count];
_angularVelocitiesCache = new float[Parts.Count];
}
//Cache the linear and angular velocities.
for (int i = 0; i < Parts.Count; i++)
{
_velocitiesCache[i] = Parts[i].Body.LinearVelocity;
_angularVelocitiesCache[i] = Parts[i].Body.AngularVelocity;
}
}
}
private void Decompose()
{
//Unsubsribe from the PostSolve delegate
_world.ContactManager.PostSolve -= PostSolve;
for (int i = 0; i < Parts.Count; i++)
{
Fixture oldFixture = Parts[i];
Shape shape = oldFixture.Shape.Clone();
object userData = oldFixture.UserData;
MainBody.DestroyFixture(oldFixture);
Body body = BodyFactory.CreateBody(_world);
body.BodyType = BodyType.Dynamic;
body.Position = MainBody.Position;
body.Rotation = MainBody.Rotation;
body.UserData = MainBody.UserData;
Fixture newFixture = body.CreateFixture(shape);
newFixture.UserData = userData;
Parts[i] = newFixture;
body.AngularVelocity = _angularVelocitiesCache[i];
body.LinearVelocity = _velocitiesCache[i];
}
_world.RemoveBody(MainBody);
_world.RemoveBreakableBody(this);
}
public void Break()
{
_break = true;
}
}
}

Some files were not shown because too many files have changed in this diff Show More