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(); } } } }