using System; using System.Collections.Generic; using System.Text; namespace AIStudio.Wpf.DiagramDesigner.Geometrys { [Serializable] public struct VectorBase : IFormattable { #region Constructors /// /// Constructor which sets the vector's initial values /// /// double - The initial X /// double - THe initial Y public VectorBase(double x, double y) { _x = x; _y = y; } #endregion Constructors #region Public Methods /// /// Length Property - the length of this Vector /// public double Length { get { return Math.Sqrt(_x * _x + _y * _y); } } /// /// LengthSquared Property - the squared length of this Vector /// public double LengthSquared { get { return _x * _x + _y * _y; } } /// /// Normalize - Updates this Vector to maintain its direction, but to have a length /// of 1. This is equivalent to dividing this Vector by Length /// public void Normalize() { // Avoid overflow this /= Math.Max(Math.Abs(_x), Math.Abs(_y)); this /= Length; } /// /// CrossProduct - Returns the cross product: vector1.X*vector2.Y - vector1.Y*vector2.X /// /// /// Returns the cross product: vector1.X*vector2.Y - vector1.Y*vector2.X /// /// The first Vector /// The second Vector public static double CrossProduct(VectorBase vector1, VectorBase vector2) { return vector1._x * vector2._y - vector1._y * vector2._x; } /// /// AngleBetween - the angle between 2 vectors /// /// /// Returns the the angle in degrees between vector1 and vector2 /// /// The first Vector /// The second Vector public static double AngleBetween(VectorBase vector1, VectorBase vector2) { double sin = vector1._x * vector2._y - vector2._x * vector1._y; double cos = vector1._x * vector2._x + vector1._y * vector2._y; return Math.Atan2(sin, cos) * (180 / Math.PI); } #endregion Public Methods #region Public Operators /// /// Operator -Vector (unary negation) /// public static VectorBase operator -(VectorBase vector) { return new VectorBase(-vector._x, -vector._y); } /// /// Negates the values of X and Y on this Vector /// public void Negate() { _x = -_x; _y = -_y; } /// /// Operator Vector + Vector /// public static VectorBase operator +(VectorBase vector1, VectorBase vector2) { return new VectorBase(vector1._x + vector2._x, vector1._y + vector2._y); } /// /// Add: Vector + Vector /// public static VectorBase Add(VectorBase vector1, VectorBase vector2) { return new VectorBase(vector1._x + vector2._x, vector1._y + vector2._y); } /// /// Operator Vector - Vector /// public static VectorBase operator -(VectorBase vector1, VectorBase vector2) { return new VectorBase(vector1._x - vector2._x, vector1._y - vector2._y); } /// /// Subtract: Vector - Vector /// public static VectorBase Subtract(VectorBase vector1, VectorBase vector2) { return new VectorBase(vector1._x - vector2._x, vector1._y - vector2._y); } /// /// Operator Vector + PointBase /// public static PointBase operator +(VectorBase vector, PointBase point) { return new PointBase(point._x + vector._x, point._y + vector._y); } /// /// Add: Vector + PointBase /// public static PointBase Add(VectorBase vector, PointBase point) { return new PointBase(point._x + vector._x, point._y + vector._y); } /// /// Operator Vector * double /// public static VectorBase operator *(VectorBase vector, double scalar) { return new VectorBase(vector._x * scalar, vector._y * scalar); } /// /// Multiply: Vector * double /// public static VectorBase Multiply(VectorBase vector, double scalar) { return new VectorBase(vector._x * scalar, vector._y * scalar); } /// /// Operator double * Vector /// public static VectorBase operator *(double scalar, VectorBase vector) { return new VectorBase(vector._x * scalar, vector._y * scalar); } /// /// Multiply: double * Vector /// public static VectorBase Multiply(double scalar, VectorBase vector) { return new VectorBase(vector._x * scalar, vector._y * scalar); } /// /// Operator Vector / double /// public static VectorBase operator /(VectorBase vector, double scalar) { return vector * (1.0 / scalar); } /// /// Multiply: Vector / double /// public static VectorBase Divide(VectorBase vector, double scalar) { return vector * (1.0 / scalar); } /// /// Operator Vector * Matrix /// //public static Vector operator *(Vector vector, Matrix matrix) //{ // return matrix.Transform(vector); //} /// /// Multiply: Vector * Matrix /// //public static Vector Multiply(Vector vector, Matrix matrix) //{ // return matrix.Transform(vector); //} /// /// Operator Vector * Vector, interpreted as their dot product /// public static double operator *(VectorBase vector1, VectorBase vector2) { return vector1._x * vector2._x + vector1._y * vector2._y; } /// /// Multiply - Returns the dot product: vector1.X*vector2.X + vector1.Y*vector2.Y /// /// /// Returns the dot product: vector1.X*vector2.X + vector1.Y*vector2.Y /// /// The first Vector /// The second Vector public static double Multiply(VectorBase vector1, VectorBase vector2) { return vector1._x * vector2._x + vector1._y * vector2._y; } /// /// Determinant - Returns the determinant det(vector1, vector2) /// /// /// Returns the determinant: vector1.X*vector2.Y - vector1.Y*vector2.X /// /// The first Vector /// The second Vector public static double Determinant(VectorBase vector1, VectorBase vector2) { return vector1._x * vector2._y - vector1._y * vector2._x; } /// /// Explicit conversion to Size. Note that since Size cannot contain negative values, /// the resulting size will contains the absolute values of X and Y /// /// /// Size - A Size equal to this Vector /// /// Vector - the Vector to convert to a Size public static explicit operator SizeBase(VectorBase vector) { return new SizeBase(Math.Abs(vector._x), Math.Abs(vector._y)); } /// /// Explicit conversion to PointBase /// /// /// PointBase - A PointBase equal to this Vector /// /// Vector - the Vector to convert to a PointBase public static explicit operator PointBase(VectorBase vector) { return new PointBase(vector._x, vector._y); } #endregion Public Operators //------------------------------------------------------ // // Public Methods // //------------------------------------------------------ #region Public Methods /// /// Compares two Vector instances for exact equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which are logically equal may fail. /// Furthermore, using this equality operator, Double.NaN is not equal to itself. /// /// /// bool - true if the two Vector instances are exactly equal, false otherwise /// /// The first Vector to compare /// The second Vector to compare public static bool operator ==(VectorBase vector1, VectorBase vector2) { return vector1.X == vector2.X && vector1.Y == vector2.Y; } /// /// Compares two Vector instances for exact inequality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which are logically equal may fail. /// Furthermore, using this equality operator, Double.NaN is not equal to itself. /// /// /// bool - true if the two Vector instances are exactly unequal, false otherwise /// /// The first Vector to compare /// The second Vector to compare public static bool operator !=(VectorBase vector1, VectorBase vector2) { return !(vector1 == vector2); } /// /// Compares two Vector instances for object equality. In this equality /// Double.NaN is equal to itself, unlike in numeric equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which /// are logically equal may fail. /// /// /// bool - true if the two Vector instances are exactly equal, false otherwise /// /// The first Vector to compare /// The second Vector to compare public static bool Equals(VectorBase vector1, VectorBase vector2) { return vector1.X.Equals(vector2.X) && vector1.Y.Equals(vector2.Y); } /// /// Equals - compares this Vector with the passed in object. In this equality /// Double.NaN is equal to itself, unlike in numeric equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which /// are logically equal may fail. /// /// /// bool - true if the object is an instance of Vector and if it's equal to "this". /// /// The object to compare to "this" public override bool Equals(object o) { if ((null == o) || !(o is VectorBase)) { return false; } VectorBase value = (VectorBase)o; return VectorBase.Equals(this, value); } /// /// Equals - compares this Vector with the passed in object. In this equality /// Double.NaN is equal to itself, unlike in numeric equality. /// Note that double values can acquire error when operated upon, such that /// an exact comparison between two values which /// are logically equal may fail. /// /// /// bool - true if "value" is equal to "this". /// /// The Vector to compare to "this" public bool Equals(VectorBase value) { return VectorBase.Equals(this, value); } /// /// Returns the HashCode for this Vector /// /// /// int - the HashCode for this Vector /// public override int GetHashCode() { // Perform field-by-field XOR of HashCodes return X.GetHashCode() ^ Y.GetHashCode(); } /// /// Parse - returns an instance converted from the provided string using /// the culture "en-US" /// string with Vector data /// //public static Vector Parse(string source) //{ // IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; // TokenizerHelper th = new TokenizerHelper(source, formatProvider); // Vector value; // String firstToken = th.NextTokenRequired(); // value = new Vector( // Convert.ToDouble(firstToken, formatProvider), // Convert.ToDouble(th.NextTokenRequired(), formatProvider)); // // There should be no more tokens in this string. // th.LastTokenRequired(); // return value; //} #endregion Public Methods //------------------------------------------------------ // // Public Properties // //------------------------------------------------------ #region Public Properties /// /// X - double. Default value is 0. /// public double X { get { return _x; } set { _x = value; } } /// /// Y - double. Default value is 0. /// public double Y { get { return _y; } set { _y = value; } } #endregion Public Properties //------------------------------------------------------ // // Protected Methods // //------------------------------------------------------ #region Protected Methods #endregion ProtectedMethods //------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods #endregion Internal Methods //------------------------------------------------------ // // Internal Properties // //------------------------------------------------------ #region Internal Properties /// /// Creates a string representation of this object based on the current culture. /// /// /// A string representation of this object. /// public override string ToString() { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, null /* format provider */); } /// /// Creates a string representation of this object based on the IFormatProvider /// passed in. If the provider is null, the CurrentCulture is used. /// /// /// A string representation of this object. /// public string ToString(IFormatProvider provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(null /* format string */, provider); } /// /// Creates a string representation of this object based on the format string /// and IFormatProvider passed in. /// If the provider is null, the CurrentCulture is used. /// See the documentation for IFormattable for more information. /// /// /// A string representation of this object. /// string IFormattable.ToString(string format, IFormatProvider provider) { // Delegate to the internal method which implements all ToString calls. return ConvertToString(format, provider); } /// /// Creates a string representation of this object based on the format string /// and IFormatProvider passed in. /// If the provider is null, the CurrentCulture is used. /// See the documentation for IFormattable for more information. /// /// /// A string representation of this object. /// internal string ConvertToString(string format, IFormatProvider provider) { // Helper to get the numeric list separator for a given culture. char separator = ','; return String.Format(provider, "{1:" + format + "}{0}{2:" + format + "}", separator, _x, _y); } #endregion Internal Properties //------------------------------------------------------ // // Dependency Properties // //------------------------------------------------------ #region Dependency Properties #endregion Dependency Properties //------------------------------------------------------ // // Internal Fields // //------------------------------------------------------ #region Internal Fields internal double _x; internal double _y; #endregion Internal Fields #region Constructors //------------------------------------------------------ // // Constructors // //------------------------------------------------------ #endregion Constructors } }