/* * Farseer Physics Engine based on Box2D.XNA port: * Copyright (c) 2010 Ian Qvist * * Box2D.XNA port of Box2D: * Copyright (c) 2009 Brandon Furtwangler, Nathan Furtwangler * * Original source Box2D: * Copyright (c) 2006-2009 Erin Catto http://www.gphysics.com * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * 3. This notice may not be removed or altered from any source distribution. */ using FarseerPhysics.Common; using Microsoft.Xna.Framework; namespace FarseerPhysics.Collision.Shapes { /// /// A line segment (edge) Shape. These can be connected in chains or loops /// to other edge Shapes. The connectivity information is used to ensure /// correct contact normals. /// public class EdgeShape : Shape { public bool HasVertex0, HasVertex3; /// /// Optional adjacent vertices. These are used for smooth collision. /// public Vector2 Vertex0; /// /// Optional adjacent vertices. These are used for smooth collision. /// public Vector2 Vertex3; /// /// Edge start vertex /// private Vector2 _vertex1; /// /// Edge end vertex /// private Vector2 _vertex2; internal EdgeShape() : base(0) { ShapeType = ShapeType.Edge; _radius = Settings.PolygonRadius; } public EdgeShape(Vector2 start, Vector2 end) : base(0) { ShapeType = ShapeType.Edge; _radius = Settings.PolygonRadius; Set(start, end); } public override int ChildCount { get { return 1; } } /// /// These are the edge vertices /// public Vector2 Vertex1 { get { return _vertex1; } set { _vertex1 = value; ComputeProperties(); } } /// /// These are the edge vertices /// public Vector2 Vertex2 { get { return _vertex2; } set { _vertex2 = value; ComputeProperties(); } } /// /// Set this as an isolated edge. /// /// The start. /// The end. public void Set(Vector2 start, Vector2 end) { _vertex1 = start; _vertex2 = end; HasVertex0 = false; HasVertex3 = false; ComputeProperties(); } public override Shape Clone() { EdgeShape edge = new EdgeShape(); edge._radius = _radius; edge._density = _density; edge.HasVertex0 = HasVertex0; edge.HasVertex3 = HasVertex3; edge.Vertex0 = Vertex0; edge._vertex1 = _vertex1; edge._vertex2 = _vertex2; edge.Vertex3 = Vertex3; edge.MassData = MassData; return edge; } /// /// Test a point for containment in this shape. This only works for convex shapes. /// /// The shape world transform. /// a point in world coordinates. /// True if the point is inside the shape public override bool TestPoint(ref Transform transform, ref Vector2 point) { return false; } /// /// Cast a ray against a child shape. /// /// The ray-cast results. /// The ray-cast input parameters. /// The transform to be applied to the shape. /// The child shape index. /// True if the ray-cast hits the shape public override bool RayCast(out RayCastOutput output, ref RayCastInput input, ref Transform transform, int childIndex) { // p = p1 + t * d // v = v1 + s * e // p1 + t * d = v1 + s * e // s * e - t * d = p1 - v1 output = new RayCastOutput(); // Put the ray into the edge's frame of reference. Vector2 p1 = MathUtils.MultiplyT(ref transform.R, input.Point1 - transform.Position); Vector2 p2 = MathUtils.MultiplyT(ref transform.R, input.Point2 - transform.Position); Vector2 d = p2 - p1; Vector2 v1 = _vertex1; Vector2 v2 = _vertex2; Vector2 e = v2 - v1; Vector2 normal = new Vector2(e.Y, -e.X); normal.Normalize(); // q = p1 + t * d // dot(normal, q - v1) = 0 // dot(normal, p1 - v1) + t * dot(normal, d) = 0 float numerator = Vector2.Dot(normal, v1 - p1); float denominator = Vector2.Dot(normal, d); if (denominator == 0.0f) { return false; } float t = numerator / denominator; if (t < 0.0f || 1.0f < t) { return false; } Vector2 q = p1 + t * d; // q = v1 + s * r // s = dot(q - v1, r) / dot(r, r) Vector2 r = v2 - v1; float rr = Vector2.Dot(r, r); if (rr == 0.0f) { return false; } float s = Vector2.Dot(q - v1, r) / rr; if (s < 0.0f || 1.0f < s) { return false; } output.Fraction = t; if (numerator > 0.0f) { output.Normal = -normal; } else { output.Normal = normal; } return true; } /// /// Given a transform, compute the associated axis aligned bounding box for a child shape. /// /// The aabb results. /// The world transform of the shape. /// The child shape index. public override void ComputeAABB(out AABB aabb, ref Transform transform, int childIndex) { Vector2 v1 = MathUtils.Multiply(ref transform, _vertex1); Vector2 v2 = MathUtils.Multiply(ref transform, _vertex2); Vector2 lower = Vector2.Min(v1, v2); Vector2 upper = Vector2.Max(v1, v2); Vector2 r = new Vector2(Radius, Radius); aabb.LowerBound = lower - r; aabb.UpperBound = upper + r; } /// /// Compute the mass properties of this shape using its dimensions and density. /// The inertia tensor is computed about the local origin, not the centroid. /// public override void ComputeProperties() { MassData.Centroid = 0.5f * (_vertex1 + _vertex2); } public override float ComputeSubmergedArea(Vector2 normal, float offset, Transform xf, out Vector2 sc) { sc = Vector2.Zero; return 0; } public bool CompareTo(EdgeShape shape) { return (HasVertex0 == shape.HasVertex0 && HasVertex3 == shape.HasVertex3 && Vertex0 == shape.Vertex0 && Vertex1 == shape.Vertex1 && Vertex2 == shape.Vertex2 && Vertex3 == shape.Vertex3); } } }