using System;
using System.Collections.Generic;
using FarseerPhysics.Collision.Shapes;
using FarseerPhysics.Common;
using FarseerPhysics.Common.Decomposition;
using FarseerPhysics.Dynamics;
using FarseerPhysics.Dynamics.Joints;
using Microsoft.Xna.Framework;
namespace FarseerPhysics.Factories
{
///
/// An easy to use manager for creating paths.
///
public static class PathManager
{
#region LinkType enum
public enum LinkType
{
Revolute,
Slider
}
#endregion
//Contributed by Matthew Bettcher
///
/// Convert a path into a set of edges and attaches them to the specified body.
/// Note: use only for static edges.
///
/// The path.
/// The body.
/// The subdivisions.
public static void ConvertPathToEdges(Path path, Body body, int subdivisions)
{
Vertices verts = path.GetVertices(subdivisions);
if (path.Closed)
{
LoopShape loop = new LoopShape(verts);
body.CreateFixture(loop);
}
else
{
for (int i = 1; i < verts.Count; i++)
{
body.CreateFixture(new EdgeShape(verts[i], verts[i - 1]));
}
}
}
///
/// Convert a closed path into a polygon.
/// Convex decomposition is automatically performed.
///
/// The path.
/// The body.
/// The density.
/// The subdivisions.
public static void ConvertPathToPolygon(Path path, Body body, float density, int subdivisions)
{
if (!path.Closed)
throw new Exception("The path must be closed to convert to a polygon.");
List verts = path.GetVertices(subdivisions);
List decomposedVerts = EarclipDecomposer.ConvexPartition(new Vertices(verts));
//List decomposedVerts = BayazitDecomposer.ConvexPartition(new Vertices(verts));
foreach (Vertices item in decomposedVerts)
{
body.CreateFixture(new PolygonShape(item, density));
}
}
///
/// Duplicates the given Body along the given path for approximatly the given copies.
///
/// The world.
/// The path.
/// The shapes.
/// The type.
/// The copies.
///
///
public static List EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable shapes,
BodyType type, int copies, object userData)
{
List centers = path.SubdivideEvenly(copies);
List bodyList = new List();
for (int i = 0; i < centers.Count; i++)
{
Body b = new Body(world);
// copy the type from original body
b.BodyType = type;
b.Position = new Vector2(centers[i].X, centers[i].Y);
b.Rotation = centers[i].Z;
foreach (Shape shape in shapes)
{
b.CreateFixture(shape, userData);
}
bodyList.Add(b);
}
return bodyList;
}
public static List EvenlyDistributeShapesAlongPath(World world, Path path, IEnumerable shapes,
BodyType type, int copies)
{
return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, null);
}
///
/// Duplicates the given Body along the given path for approximatly the given copies.
///
/// The world.
/// The path.
/// The shape.
/// The type.
/// The copies.
/// The user data.
///
public static List EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type,
int copies, object userData)
{
List shapes = new List(1);
shapes.Add(shape);
return EvenlyDistributeShapesAlongPath(world, path, shapes, type, copies, userData);
}
public static List EvenlyDistributeShapesAlongPath(World world, Path path, Shape shape, BodyType type,
int copies)
{
return EvenlyDistributeShapesAlongPath(world, path, shape, type, copies, null);
}
//TODO: Comment better
///
/// Moves the body on the path.
///
/// The path.
/// The body.
/// The time.
/// The strength.
/// The time step.
public static void MoveBodyOnPath(Path path, Body body, float time, float strength, float timeStep)
{
Vector2 destination = path.GetPosition(time);
Vector2 positionDelta = body.Position - destination;
Vector2 velocity = (positionDelta / timeStep) * strength;
body.LinearVelocity = -velocity;
}
///
/// Attaches the bodies with revolute joints.
///
/// The world.
/// The bodies.
/// The local anchor A.
/// The local anchor B.
/// if set to true [connect first and last].
/// if set to true [collide connected].
public static List AttachBodiesWithRevoluteJoint(World world, List bodies,
Vector2 localAnchorA,
Vector2 localAnchorB, bool connectFirstAndLast,
bool collideConnected)
{
List joints = new List(bodies.Count + 1);
for (int i = 1; i < bodies.Count; i++)
{
RevoluteJoint joint = new RevoluteJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB);
joint.CollideConnected = collideConnected;
world.AddJoint(joint);
joints.Add(joint);
}
if (connectFirstAndLast)
{
RevoluteJoint lastjoint = new RevoluteJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA,
localAnchorB);
lastjoint.CollideConnected = collideConnected;
world.AddJoint(lastjoint);
joints.Add(lastjoint);
}
return joints;
}
///
/// Attaches the bodies with revolute joints.
///
/// The world.
/// The bodies.
/// The local anchor A.
/// The local anchor B.
/// if set to true [connect first and last].
/// if set to true [collide connected].
/// Minimum length of the slider joint.
/// Maximum length of the slider joint.
///
public static List AttachBodiesWithSliderJoint(World world, List bodies, Vector2 localAnchorA,
Vector2 localAnchorB, bool connectFirstAndLast,
bool collideConnected, float minLength,
float maxLength)
{
List joints = new List(bodies.Count + 1);
for (int i = 1; i < bodies.Count; i++)
{
SliderJoint joint = new SliderJoint(bodies[i], bodies[i - 1], localAnchorA, localAnchorB, minLength,
maxLength);
joint.CollideConnected = collideConnected;
world.AddJoint(joint);
joints.Add(joint);
}
if (connectFirstAndLast)
{
SliderJoint lastjoint = new SliderJoint(bodies[0], bodies[bodies.Count - 1], localAnchorA, localAnchorB,
minLength, maxLength);
lastjoint.CollideConnected = collideConnected;
world.AddJoint(lastjoint);
joints.Add(lastjoint);
}
return joints;
}
}
}