using System; using System.Collections.Generic; using System.Text; using System.Windows; namespace AIStudio.Wpf.DiagramDesigner.Geometrys { [Serializable] public struct PointBase : IFormattable { public static PointBase Zero { get; } = new PointBase(0, 0); public PointBase(double x, double y) { _x = x; _y = y; } /// /// 中间X /// internal double _x; public double X { get { return _x; } set { _x = value; } } /// /// 中间Y /// internal double _y; public double Y { get { return _y; } set { _y = value; } } public double Dot(PointBase other) => X * other.X + Y * other.Y; public PointBase Lerp(PointBase other, double t) => new PointBase(X * (1.0 - t) + other.X * t, Y * (1.0 - t) + other.Y * t); // Maybe just make Points mutable? public PointBase Add(double value) => new PointBase(X + value, Y + value); public PointBase Add(double x, double y) => new PointBase(X + x, Y + y); public PointBase Substract(double value) => new PointBase(X - value, Y - value); public PointBase Substract(double x, double y) => new PointBase(X - x, Y - y); public double DistanceTo(PointBase other) => Math.Sqrt(Math.Pow(X - other.X, 2) + Math.Pow(Y - other.Y, 2)); public void Deconstruct(out double x, out double y) { x = X; y = Y; } //public static PointBase operator -(PointBase a, PointBase b) //{ // return new PointBase(a.X - b.X, a.Y - b.Y); //} //public static PointBase operator +(PointBase a, PointBase b) //{ // return new PointBase(a.X + b.X, a.Y + b.Y); //} public static implicit operator PointBase(Point point) { return new PointBase(point.X, point.Y); } public static implicit operator Point(PointBase pointInfoBase) { return new Point(pointInfoBase.X, pointInfoBase.Y); } //public override string ToString() => $"PointBase(x={X}, y={Y})"; #region Statics /// /// Empty - a static property which provides an Empty rectangle. X and Y are positive-infinity /// and Width and Height are negative infinity. This is the only situation where Width or /// Height can be negative. /// public static PointBase Empty { get { return s_empty; } } #endregion Statics #region Private Methods static private PointBase CreateEmptyRect() { PointBase point = new PointBase(); // We can't set these via the property setters because negatives widths // are rejected in those APIs. point._x = Double.PositiveInfinity; point._y = Double.PositiveInfinity; return point; } #endregion Private Methods #region Private Fields private readonly static PointBase s_empty = CreateEmptyRect(); #endregion Private Fields #region Public Methods /// /// Compares two PointBase 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 PointBase instances are exactly equal, false otherwise /// /// The first PointBase to compare /// The second PointBase to compare public static bool operator ==(PointBase point1, PointBase point2) { return point1.X == point2.X && point1.Y == point2.Y; } /// /// Compares two PointBase 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 PointBase instances are exactly unequal, false otherwise /// /// The first PointBase to compare /// The second PointBase to compare public static bool operator !=(PointBase point1, PointBase point2) { return !(point1 == point2); } /// /// Compares two PointBase 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 PointBase instances are exactly equal, false otherwise /// /// The first PointBase to compare /// The second PointBase to compare public static bool Equals(PointBase point1, PointBase point2) { return point1.X.Equals(point2.X) && point1.Y.Equals(point2.Y); } /// /// Equals - compares this PointBase 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 PointBase and if it's equal to "this". /// /// The object to compare to "this" public override bool Equals(object o) { if ((null == o) || !(o is PointBase)) { return false; } PointBase value = (PointBase)o; return PointBase.Equals(this, value); } /// /// Equals - compares this PointBase 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 PointBase to compare to "this" public bool Equals(PointBase value) { return PointBase.Equals(this, value); } /// /// Returns the HashCode for this PointBase /// /// /// int - the HashCode for this PointBase /// 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 PointBase data ///// //public static PointBase Parse(string source) //{ // IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; // TokenizerHelper th = new TokenizerHelper(source, formatProvider); // PointBase value; // String firstToken = th.NextTokenRequired(); // value = new PointBase( // 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 #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 #region Public Methods /// /// Offset - update the location by adding offsetX to X and offsetY to Y /// /// The offset in the x dimension /// The offset in the y dimension public void Offset(double offsetX, double offsetY) { _x += offsetX; _y += offsetY; } /// /// Operator PointBase + Vector /// /// /// PointBase - The result of the addition /// /// The PointBase to be added to the Vector /// The Vectr to be added to the PointBase public static PointBase operator +(PointBase point, VectorBase vector) { return new PointBase(point._x + vector._x, point._y + vector._y); } /// /// Add: PointBase + Vector /// /// /// PointBase - The result of the addition /// /// The PointBase to be added to the Vector /// The Vector to be added to the PointBase public static PointBase Add(PointBase point, VectorBase vector) { return new PointBase(point._x + vector._x, point._y + vector._y); } /// /// Operator PointBase - Vector /// /// /// PointBase - The result of the subtraction /// /// The PointBase from which the Vector is subtracted /// The Vector which is subtracted from the PointBase public static PointBase operator -(PointBase point, VectorBase vector) { return new PointBase(point._x - vector._x, point._y - vector._y); } /// /// Subtract: PointBase - Vector /// /// /// PointBase - The result of the subtraction /// /// The PointBase from which the Vector is subtracted /// The Vector which is subtracted from the PointBase public static PointBase Subtract(PointBase point, VectorBase vector) { return new PointBase(point._x - vector._x, point._y - vector._y); } /// /// Operator PointBase - PointBase /// /// /// Vector - The result of the subtraction /// /// The PointBase from which point2 is subtracted /// The PointBase subtracted from point1 public static VectorBase operator -(PointBase point1, PointBase point2) { return new VectorBase(point1._x - point2._x, point1._y - point2._y); } /// /// Subtract: PointBase - PointBase /// /// /// Vector - The result of the subtraction /// /// The PointBase from which point2 is subtracted /// The PointBase subtracted from point1 public static VectorBase Subtract(PointBase point1, PointBase point2) { return new VectorBase(point1._x - point2._x, point1._y - point2._y); } /// /// Operator PointBase * Matrix /// //public static PointBase operator *(PointBase point, Matrix matrix) //{ // return matrix.Transform(point); //} /// /// Multiply: PointBase * Matrix /// //public static PointBase Multiply(PointBase point, Matrix matrix) //{ // return matrix.Transform(point); //} /// /// 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 PointBase /// /// PointBase - the PointBase to convert to a Size public static explicit operator SizeBase(PointBase point) { return new SizeBase(Math.Abs(point._x), Math.Abs(point._y)); } /// /// Explicit conversion to Vector /// /// /// Vector - A Vector equal to this PointBase /// /// PointBase - the PointBase to convert to a Vector public static explicit operator VectorBase(PointBase point) { return new VectorBase(point._x, point._y); } #endregion Public Methods } }