using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; namespace bbiwarg.Utility { /// /// Class with represents a vector or a point in 2 dimensional space. /// public class Vector2D { /// /// length of the vector, is initialized with -1 and will only be calculated if needed and only once /// private float length = -1; /// /// the null vector or origin /// public static Vector2D Zero { get { return new Vector2D(0, 0); } } /// /// X (first) component /// public float X { get; private set; } /// /// Y (second) component /// public float Y { get; private set; } /// /// X component as integer /// public int IntX { get { return (int)X; } } /// /// Y component as integer /// public int IntY { get { return (int)Y; } } /// /// length of the vector, computed in euclidean distance (2. norm) /// public float Length { get { if (length == -1) length = (float)Math.Sqrt(X * X + Y * Y); return length; } } /// /// Standard constructor which sets the components. /// /// first component /// second component public Vector2D(float x, float y) { X = x; Y = y; } /// /// Constructor to create a Vector2D from a Point . /// /// a Point public Vector2D(Point point) { X = point.X; Y = point.Y; } /// /// Constructor to create a Vector2D from a PointF. /// /// a PointF public Vector2D(PointF point) { X = point.X; Y = point.Y; } /// /// Computes the euclidean distance between the point this vector describes and another point described by a Vector. /// /// a Point /// euclidean distance public float getDistanceTo(Vector2D point) { return (this - point).Length; } /// /// Computes the angle between this vector and another vector in radians. /// /// a vector /// angle in radians public float getAngleBetween(Vector2D vector) { return (float)Math.Acos(dotProduct(vector) / (Length * vector.Length)); } /// /// Computes whether this vector and another vector point in opposite directions, meaning the smallest angle is between 90° and 180°. /// /// a vector /// true iff the vectors point in opposite directions public bool isInOppositeDirection(Vector2D vector) { return (getAngleBetween(vector) > Math.PI / 2); } /// /// Computes the dot product of this vector and another vector. /// /// the other vector /// the dot product public float dotProduct(Vector2D vector) { return X * vector.X + Y * vector.Y; } /// /// Computes the cross product (determinant) of this vector and another vector. /// /// the other vector /// cross product of this and v public float crossProduct(Vector2D v) { return X * v.Y - Y * v.X; } /// /// Multiplies this vector component-by-component with another vector. /// /// the other vector /// the component-by-component multiplied vector public Vector2D scale(Vector2D v) { return new Vector2D(X * v.X, Y * v.Y); } /// /// Determines whether this point (vector) is inside a given box or not. /// /// first corner of the box /// second corner of the box /// true iff point is inside the box public bool isInBox(Vector2D corner1, Vector2D corner2) { float minX = Math.Min(corner1.X, corner2.X); float maxX = Math.Max(corner1.X, corner2.X); float minY = Math.Min(corner1.Y, corner2.Y); float maxY = Math.Max(corner1.Y, corner2.Y); return (minX <= X && X <= maxX && minY <= Y && Y <= maxY); } /// /// Determines whether a this point is inside the boundaries of a given image or not. /// /// a imageSize object /// true iff point is inside the image boundaries public bool isInBound(ImageSize imageSize) { return isInBound(Vector2D.Zero, imageSize.MaxPixel); } /// /// Determines whether a point is inside a box. iff bottomRight is higher or more left than topLeft the result is false. /// /// top left corner of the box /// bottom right corner of the box /// true iff point is in box public bool isInBound(Vector2D topLeft, Vector2D bottomRight) { return (X >= topLeft.X && X <= bottomRight.X && Y >= topLeft.Y && Y <= bottomRight.Y); } /// /// Moves this vector along the direction vector factor times inside the imageSize, this point won't leave the image. /// /// the imagesize /// the move direction /// the move factor /// a point inside the image public Vector2D moveWithinBound(ImageSize imageSize, Vector2D direction, float factor) { Vector2D newPosition = this + factor * direction; if (!newPosition.isInBound(imageSize)) { Vector2D inverseDirection = direction.getInverse().normalize(); while (!newPosition.isInBound(imageSize)) { newPosition += inverseDirection; } } return newPosition; } /// /// Normalizes this vector with the euclidean norm (2. norm). /// /// normalized vector public Vector2D normalize() { return new Vector2D(X / Length, Y / Length); } /// /// Computes a orthogonal vector of this vector, if side is true the X component will be switched, else the Y component. /// /// which vector /// a orthogonal vector public Vector2D getOrthogonal(bool side = true) { if (side) return new Vector2D(Y, -X); else return new Vector2D(-Y, X); } /// /// Computes the inverse vector of this vector. /// /// inverse vector public Vector2D getInverse() { return new Vector2D(-X, -Y); } /// /// Computes the absolute vector of this vector. /// /// absolute vector public Vector2D getAbsolute() { return new Vector2D(Math.Abs(X), Math.Abs(Y)); } /// /// Copies this vector (clone). /// /// this vector as new vector public Vector2D copy() { return new Vector2D(X, Y); } /// /// Creates a description of this vector. /// /// a string describing this vector public override string ToString() { return "(" + X + "|" + Y + ")"; } /// /// Multiplies this vector component-by-component with a scalar value. /// /// multiplier /// multiplicant /// multiplied vector (product) public static Vector2D operator *(float scalar, Vector2D vector) { return new Vector2D(scalar * vector.X, scalar * vector.Y); } /// /// Multiplies this vector component-by-component with a scalar value. /// /// multiplicant /// multiplier /// multiplied vector (product) public static Vector2D operator *(Vector2D vector, float scalar) { return new Vector2D(scalar * vector.X, scalar * vector.Y); } /// /// Divides this vector with a scalar value. /// /// this vector /// the value /// the divided vector public static Vector2D operator /(Vector2D vector, float scalar) { return new Vector2D(vector.X / scalar, vector.Y / scalar); } /// /// Divides on vector with another vector component-by-component. /// /// the dividend /// the divisor /// the component divided vector public static Vector2D operator /(Vector2D vector1, Vector2D vector2) { return new Vector2D(vector1.X / vector2.X, vector1.Y / vector2.Y); } /// /// Adds two vectors (component-by-component). /// /// first addend /// second addend /// sum of the vectors public static Vector2D operator +(Vector2D vector1, Vector2D vector2) { return new Vector2D(vector1.X + vector2.X, vector1.Y + vector2.Y); } /// /// Subtracts two vectors (component-by-component). /// /// the minuend /// the subtrahend /// the difference of the two vectors public static Vector2D operator -(Vector2D vector1, Vector2D vector2) { return new Vector2D(vector1.X - vector2.X, vector1.Y - vector2.Y); } /// /// Computes the mean of two vectors. /// /// second vector /// the mean vector public static Vector2D mean(List vectors) { Vector2D sumVector = Vector2D.sum(vectors); return sumVector / vectors.Count; } /// /// Sums a list of vectors (component-by-component). /// /// a list of vectors /// vector of sumed components public static Vector2D sum(List vectors) { Vector2D sumVector = new Vector2D(0, 0); foreach (Vector2D vector in vectors) sumVector += vector; return sumVector; } /// /// Casts a Vector2D to PointF. /// /// a vector /// a PointF public static implicit operator PointF(Vector2D vec) { return new PointF(vec.X, vec.Y); } /// /// Casts a Vector2D to Point. /// /// a vector /// a Point public static implicit operator Point(Vector2D vec) { return new Point(vec.IntX, vec.IntY); } } }