using System;
using Chernobyl.Mathematics.Collision;
using Chernobyl.Mathematics.Movement;
using Chernobyl.Mathematics.Vectors;
namespace Chernobyl.Mathematics.Geometry
{
///
/// A 2D point with an X and a Y coordinate. Unlike a 2D vector
/// (), the has collision
/// capabilities and implements the and
/// interfaces.
///
public class Point2D : MatrixTransform, ICollidable2D, IEquatable
{
///
/// Initializes a new instance of the class.
///
public Point2D()
: this(Vector2.Zero)
{ }
///
/// Initializes a new instance of the class.
///
/// The (X, Y) coordinate of the point.
public Point2D(Vector2 point) : this(point.X, point.Y)
{ }
///
/// Initializes a new instance of the class.
///
/// The X coordinate of the point.
/// The Y coordinate of the point.
public Point2D(float x, float y)
{
X = x;
Y = y;
}
///
/// Explicit conversion from a vector to a Point2D. Note that an implicit
/// conversion from Point2D to Vector2 is NOT provided because data is
/// lost in that conversion.
///
/// The vector to convert from.
/// The converted Point2D.
public static explicit operator Point2D(Vector2 vector)
{
return new Point2D(vector);
}
///
/// An event that is raised when a collidable has started colliding with
/// this collidable. When the collision has ended, OnCollisionEnded will
/// be raised.
///
public event EventHandler OnCollisionStarted;
///
/// An event that is raised when the collision with a collidable has
/// ended. This will event will be raised after the invocation of
/// OnCollisionStarted
///
public event EventHandler OnCollisionEnded;
///
/// Tests for a collision between this point and the point passed in.
///
/// The point to test for collision against.
/// True if there was a collision, false if otherwise.
public bool IsColliding(Point2D point)
{
return (point.X == X && point.Y == Y);
}
///
/// Tests for a collision between this point and the Circle passed in.
///
/// The Circle to test for collision against.
/// True if there was a collision, false if otherwise.
public bool IsColliding(Circle circle)
{
// the point is inside the circle if the distance between point and
// the origin of the circle is less than the radius of the circle.
// Normally, we would use the distance equation here but there is an
// optimization we can use called the "distance squared". With this
// equation we will also have to square the radius.
Vector2 originToPointVector = new Vector2(circle.Position.X - X, circle.Position.Y - Y);
if ((originToPointVector.X * originToPointVector.X) + (originToPointVector.Y * originToPointVector.Y) < circle.Radius * circle.Radius)
return true;
return false;
}
///
/// Tests for a collision between this point and the Rectangle passed in.
///
/// The Rectangle to test for collision against.
/// True if there was a collision, false if otherwise.
public bool IsColliding(Rectangle rectangle)
{
return rectangle.IsColliding(this);
}
///
/// Called when this collidable has started colliding with another
/// collidable. This point just invokes the OnCollisionStarted event.
///
/// The object that was just hit.
public void HandleCollisionStarted(ICollidable collider)
{
if (OnCollisionStarted != null)
OnCollisionStarted(this, EventArgs.Empty);
}
///
/// Called when this collidable has stopped colliding with another
/// collidable.
///
/// The object that was just hit.
public void HandleCollisionEnded(ICollidable collider)
{
if (OnCollisionEnded != null)
OnCollisionEnded(this, EventArgs.Empty);
}
///
/// A string that contains the points position in
/// the form of {X=n, Y=n}, where 'n' is some number. For example:
/// {X=20, Y=20}.
///
///
/// A that represents this instance.
///
public override string ToString()
{
return "{X=" + X + ", Y=" + Y + "}";
}
///
/// Determines whether the specified is equal to
/// this instance. In order for two s to be equal
/// they both need to have the same ,
/// , and .
///
/// The to compare with this
/// instance.
/// True if the specified is equal to this
/// instance; otherwise, false.
///
public override bool Equals(object obj)
{
return Equals(obj as Point2D);
}
///
/// Determines whether the specified is equal to
/// this instance. In order for two s to be equal
/// they both need to have the same .
///
/// The to compare with this
/// instance.
/// True if the specified is equal to this
/// instance; otherwise, false.
///
public bool Equals(Point2D point)
{
return !ReferenceEquals(point, null) &&
(ReferenceEquals(this, point) ||
Position == point.Position);
}
///
/// Implements the equality (==) operator. In order for two
/// s to be equal they both need to have the same
/// .
///
/// The instance to compare to the
/// instance.
/// The instance to compare to the
/// instance.
/// True if the two instances are equal, false if otherwise.
public static bool operator ==(Point2D left, Point2D right)
{
return left.Equals(right);
}
///
/// Implements the not-equal (!=) operator. In order for two
/// s to be not equal they both need to have
/// different s.
///
/// The instance to compare to the
/// instance.
/// The instance to compare to the
/// instance.
/// True if the two instances are NOT equal, false if otherwise.
public static bool operator !=(Point2D left, Point2D right)
{
return !(left == right);
}
///
/// Returns a hash code for this instance.
///
///
/// A hash code for this instance, suitable for use in hashing algorithms
/// and data structures like a hash table.
///
public override int GetHashCode()
{
return Position.GetHashCode();
}
///
/// The X coordinate of the point.
///
public float X
{
get { return Position.X; }
set { Position = new Vector3(value, Y, LocalMatrix.Translation.Z); }
}
///
/// The Y coordinate of the point.
///
public float Y
{
get { return Position.Y; }
set { Position = new Vector3(X, value, LocalMatrix.Translation.Z); }
}
///
/// The largest width of the object in the object's X axis. This class
/// will always return 0 for it's Width.
///
public float Width { get { return 0; } }
///
/// The largest height of the object in the object's Y axis. This class
/// will always return 0 for it's Height.
///
public float Height { get { return 0; } }
///
/// The largest depth of the object in the object's Z axis. This class
/// will always return 0 for it's Depth.
///
public float Depth { get { return 0; } }
///
/// True if this is convex, false if it is concave.
/// A is convex if for every pair of points within
/// the object, every point on the straight line segment that joins them
/// is also within the object. A concave is the
/// opposite of this. A Point2D always returns true.
///
public bool IsConvex
{
get { return true; }
}
///
/// The amount of space taken up by an object on a flat plane in
/// square metres (m^2). This property will always return 0
/// for the .
///
public float Area
{
get { return 0; }
}
///
/// The amount of 3D space this object consumes in cubic metres (m^3).
/// If this object is 2D, then the value of this property is zero.
/// This property will always return 0 for the .
///
public float Volume
{
get { return 0; }
}
///
/// The length of the path that surrounds a shape specified in metres (m).
/// In the case of a closed curve such as a circle, this value represents
/// the circumference of the object. This property will always return 0
/// for the .
///
public float Perimeter
{
get { return 0; }
}
///
/// The minimum number of coordinates needed to specify each point
/// within this object. For example: a point has 0 dimensions, a
/// line has 1 dimension, a circle or rectangle has 2 dimensions, a
/// cube or sphere has 3 dimensions, and a moving cube or sphere has 4.
/// This property will always return 0 for the .
///
public uint Dimensions
{
get { throw new NotImplementedException(); }
}
}
}