using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace Base { /// /// Class for a 2-Dimensional Vector /// public class Vector2 { /// /// A new Vector with a value of zero /// public static readonly Vector2 Zero = new Vector2(Point.Empty); double x_unchecked = 0; double y_unchecked = 0; public object Tag; void check() { if (!bounds.IsEmpty) { if (bounds_wrap) { if (!(bounds.X == 0 && bounds.Width == 0)) { if (bounds.Width == 0) x_unchecked = bounds.X; else { if (bounds.Width < 0) throw new ArgumentException("bounds.Width must be greater than or equal to 0"); while (x_unchecked > bounds.X + bounds.Width) x_unchecked -= bounds.Width; while (x_unchecked < bounds.X) x_unchecked += bounds.Width; } } if (!(bounds.Y == 0 && bounds.Height == 0)) { if (bounds.Height == 0) y_unchecked = bounds.Y; else { if (bounds.Height < 0) throw new ArgumentException("bounds.Height must be greater than or equal to 0"); while (y_unchecked > bounds.Y + bounds.Height) y_unchecked -= bounds.Height; while (y_unchecked < bounds.Y) y_unchecked += bounds.Height; } } } else { x_unchecked = Math.Min(Math.Max(x_unchecked, bounds.X), bounds.X + bounds.Width); y_unchecked = Math.Min(Math.Max(y_unchecked, bounds.Y), bounds.Y + bounds.Height); } } } /// /// X-Coordinate of the Vector /// public double X { get { check(); return x_unchecked; } set { x_unchecked = value; check(); } } /// /// Y-Coordinate of the Vector /// public double Y { get { check(); return y_unchecked; } set { y_unchecked = value; check(); } } /// /// Bounds of the Vector, set both values for a axis to zero to ignore it /// public Rectangle bounds; /// /// Set to true if you want the Vector to wrap instead of 'cutting' when reaching the bound /// public bool bounds_wrap = false; /// /// Create a new Vector /// /// X coordinate /// Y coordinate public Vector2(double x = 0, double y = 0) { X = x; Y = y; } /// /// Create a new Vector /// /// Point to copy data from public Vector2(Point from) { X = from.X; Y = from.Y; } /// /// Create a new Vector /// /// Point to copy data from public Vector2(PointF from) { X = from.X; Y = from.Y; } /// /// Create a new Vector /// /// Size to copy data from public Vector2(Size from) { X = from.Width; Y = from.Height; } /// /// Create a new Vector /// /// Size to copy data from public Vector2(SizeF from) { X = from.Width; Y = from.Height; } /// /// Copy data from the Vector to a new one /// /// Vector to copy data from /// Set to true to copy bounds etc public Vector2(Vector2 from, bool useProperties = false) { X = from.X; Y = from.Y; if (useProperties) { Tag = from.Tag; bounds = from.bounds; bounds_wrap = from.bounds_wrap; } } /// /// Copy the Vectors axis to a point /// /// The new Point public Point toPoint() => new Point(Misc.d2i(X), Misc.d2i(Y)); /// /// Copy the Vectors axis to a point /// /// The new Point public PointF toPointF() => new PointF(Misc.d2f(X), Misc.d2f(Y)); /// /// Get the squared distance between this Vector and the other /// /// The other Vector /// Distance public double distanceFromSquared(Vector2 other) => Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2); /// /// Get the distance between this Vector and the other /// /// The other Vector /// Distance public double distanceFrom(Vector2 other) => Math.Sqrt(distanceFromSquared(other)); public double distanceToRectSquared(Rect rect) { if (X < rect.X) { if (Y < rect.Bottom) return distanceFromSquared(rect.bottomLeftPoint); else if (Y > rect.Top) return distanceFromSquared(rect.topLeftPoint); else return Math.Pow(rect.Left - X, 2); } else if (X > rect.X + rect.Width) { if (Y < rect.Bottom) return distanceFromSquared(rect.bottomRightPoint); else if (Y > rect.Top) return distanceFromSquared(rect.topRightPoint); else return Math.Pow(X - rect.Right, 2); } else { if (Y < rect.Bottom) return Math.Pow(rect.Bottom - Y, 2); else if (Y > rect.Top) return Y - rect.Top; else return 0d; } } public double distanceToRect(Rect rect) => Math.Sqrt(distanceToRectSquared(rect)); /// /// Provided for compatibility with some methods for other Vector implementations /// public double magnitude { get { return distanceFrom(Zero); } } /// /// Provided for compatibility with some methods for other Vector implementations /// public double sqrMagnitude { get { return distanceFromSquared(Zero); } } /// /// Move the Vector in the direction /// /// The angle in radians /// Distance to move the Vector public void moveInDirection(double radians = 0, double distance = 1) { X += Math.Cos(radians) * distance; Y += Math.Sin(radians) * distance; } /// /// Get the angle inbetween the X-Axis and a line between two poins /// /// The other point for the line /// Angle in Radians public double getDirection(Vector2 other) => Math.Atan((other.X - X) / (other.Y - Y)); /// /// Move the Vector towards the other Vector /// /// The other Vector /// The distance to move /// Whether to stop at the target or to go through it public void moveTowards(Vector2 other, double distance = 1, bool stopAtTarget = true) { double dist = distanceFrom(other); if (stopAtTarget & distance >= dist) { X = other.X; Y = other.Y; } else { double k = distance / dist; double localX = other.X - X; double localY = other.Y - Y; X = localX * k + X; Y = localY * k + Y; } } Vector2 addTag(object Tag) { this.Tag = Tag; return this; } Vector2 addBounds(Rectangle bounds) { this.bounds = bounds; return this; } Vector2 addBoundsW(bool bounds_wrap) { this.bounds_wrap = bounds_wrap; return this; } Vector2 addData(object Tag, Rectangle bounds, bool bounds_wrap) => addTag(Tag).addBounds(bounds).addBoundsW(bounds_wrap); public override string ToString() => "{X=" + X.ToString() + ", Y=" + Y.ToString() + "}"; public static Vector2 operator +(Vector2 left, Vector2 right) => new Vector2(left.X + right.X, left.Y + right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator +(Vector2 left, Point right) => new Vector2(left.X + right.X, left.Y + right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator +(Vector2 left, PointF right) => new Vector2(left.X + right.X, left.Y + right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator -(Vector2 left, Vector2 right) => new Vector2(left.X - right.X, left.Y - right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator -(Vector2 left, Point right) => new Vector2(left.X - right.X, left.Y - right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator -(Vector2 left, PointF right) => new Vector2(left.X - right.X, left.Y - right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator *(Vector2 left, double right) => new Vector2(left * new Vector2(right, right)).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator *(Vector2 left, Vector2 right) => new Vector2(left.X * right.X, left.Y * right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator *(Vector2 left, Point right) => new Vector2(left.X * right.X, left.Y * right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator *(Vector2 left, PointF right) => new Vector2(left.X * right.X, left.Y * right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator /(Vector2 left, double right) => new Vector2(left / new Vector2(right, right)).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator /(Vector2 left, Vector2 right) => new Vector2(left.X / right.X, left.Y / right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator /(Vector2 left, Point right) => new Vector2(left.X / right.X, left.Y / right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator /(Vector2 left, PointF right) => new Vector2(left.X / right.X, left.Y / right.Y).addData(left.Tag, left.bounds, left.bounds_wrap); public static Vector2 operator ^(Vector2 left, double right) => new Vector2(Math.Pow(left.X, right), Math.Pow(left.Y, right)).addData(left.Tag, left.bounds, left.bounds_wrap); } }