using System;
using System.Collections.Generic;
using System.Drawing;
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 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;
}
}
///
/// X (first) component
///
public float X { get; private set; }
///
/// Y (second) component
///
public float Y { get; private set; }
///
/// 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;
}
///
/// Casts a Vector2D to Point.
///
/// a vector
/// a Point
public static implicit operator Point(Vector2D vec)
{
return new Point(vec.IntX, vec.IntY);
}
///
/// Casts a Vector2D to PointF.
///
/// a vector
/// a PointF
public static implicit operator PointF(Vector2D vec)
{
return new PointF(vec.X, vec.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;
}
///
/// 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);
}
///
/// Multiplies this vector component-by-component with a scalar value.
///
/// the multiplier
/// the multiplicand
/// 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.
///
/// the multiplicand
/// the 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);
}
///
/// Sums a list of vectors (component-by-component).
///
/// a list of vectors
/// vector of summed components
public static Vector2D sum(List vectors)
{
Vector2D sumVector = new Vector2D(0, 0);
foreach (Vector2D vector in vectors)
sumVector += vector;
return sumVector;
}
///
/// Copies this vector (clone).
///
/// this vector as new vector
public Vector2D copy()
{
return new Vector2D(X, 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;
}
///
/// 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 absolute vector of this vector.
///
/// absolute vector
public Vector2D getAbsolute()
{
return new Vector2D(Math.Abs(X), Math.Abs(Y));
}
///
/// 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 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 inverse vector of this vector.
///
/// inverse vector
public Vector2D getInverse()
{
return new Vector2D(-X, -Y);
}
///
/// 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);
}
///
/// 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;
}
///
/// 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;
}
///
/// 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);
}
///
/// Moves this vector along the direction vector factor times inside the imageSize, this point won't leave the image.
///
/// the size of the image
/// 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);
}
///
/// 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);
}
///
/// Creates a description of this vector.
///
/// a string describing this vector
public override string ToString()
{
return "(" + X + "|" + Y + ")";
}
}
}