(61d00a474) v0.9.7.1
This commit is contained in:
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user