using System; using System.Windows; namespace AIStudio.Wpf.DiagramDesigner.Geometrys { [Serializable] public struct SizeBase : IFormattable { public static SizeBase Zero { get; } = new SizeBase(0, 0); public SizeBase(double width, double height) { if (width < 0 || height < 0) { throw new System.ArgumentException("Size_WidthAndHeightCannotBeNegative"); } _width = width; _height = height; } public bool IsEmpty { get { return _width < 0; } } internal double _width; public double Width { get { return _width; } set { if (IsEmpty) { throw new System.InvalidOperationException("Size_CannotModifyEmptySize"); } if (value < 0) { throw new System.ArgumentException("Size_WidthCannotBeNegative"); } _width = value; } } internal double _height; public double Height { get { return _height; } set { if (IsEmpty) { throw new System.InvalidOperationException("Size_CannotModifyEmptySize"); } if (value < 0) { throw new System.ArgumentException("Size_HeightCannotBeNegative"); } _height = value; } } public SizeBase Add(double value) => new SizeBase(Width + value, Height + value); public SizeBase Add(double width, double height) => new SizeBase(Width + width, Height + height); //public bool Equals(Size size) => size != null && Width == size.Width && Height == size.Height; //public override string ToString() => $"Size(width={Width}, height={Height})"; public static implicit operator SizeBase(Size size) { return new SizeBase(size.Width, size.Height); } public static implicit operator Size(SizeBase sizebase) { return new Size(sizebase.Width, sizebase.Height); } #region Statics /// /// Empty - a static property which provides an Empty size. Width and Height are /// negative-infinity. This is the only situation /// where size can be negative. /// public static SizeBase Empty { get { return s_empty; } } #endregion Statics #region Public Methods /// /// Compares two Size 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 Size instances are exactly equal, false otherwise /// /// The first Size to compare /// The second Size to compare public static bool operator ==(SizeBase size1, SizeBase size2) { return size1.Width == size2.Width && size1.Height == size2.Height; } /// /// Compares two Size 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 Size instances are exactly unequal, false otherwise /// /// The first Size to compare /// The second Size to compare public static bool operator !=(SizeBase size1, SizeBase size2) { return !(size1 == size2); } /// /// Compares two Size 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 Size instances are exactly equal, false otherwise /// /// The first Size to compare /// The second Size to compare public static bool Equals(SizeBase size1, SizeBase size2) { if (size1.IsEmpty) { return size2.IsEmpty; } else { return size1.Width.Equals(size2.Width) && size1.Height.Equals(size2.Height); } } /// /// Equals - compares this Size 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 Size and if it's equal to "this". /// /// The object to compare to "this" public override bool Equals(object o) { if ((null == o) || !(o is SizeBase)) { return false; } SizeBase value = (SizeBase)o; return SizeBase.Equals(this, value); } /// /// Equals - compares this Size 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 Size to compare to "this" public bool Equals(SizeBase value) { return SizeBase.Equals(this, value); } /// /// Returns the HashCode for this Size /// /// /// int - the HashCode for this Size /// public override int GetHashCode() { if (IsEmpty) { return 0; } else { // Perform field-by-field XOR of HashCodes return Width.GetHashCode() ^ Height.GetHashCode(); } } /// /// Parse - returns an instance converted from the provided string using /// the culture "en-US" /// string with Size data /// //public static Size Parse(string source) //{ // IFormatProvider formatProvider = System.Windows.Markup.TypeConverterHelper.InvariantEnglishUS; // TokenizerHelper th = new TokenizerHelper(source, formatProvider); // Size value; // String firstToken = th.NextTokenRequired(); // // The token will already have had whitespace trimmed so we can do a // // simple string compare. // if (firstToken == "Empty") // { // value = Empty; // } // else // { // value = new Size( // 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 Public Operators /// /// Explicit conversion to Vector. /// /// /// Vector - A Vector equal to this Size /// /// Size - the Size to convert to a Vector public static explicit operator VectorBase(SizeBase size) { return new VectorBase(size._width, size._height); } /// /// Explicit conversion to PointBase /// /// /// PointBase - A PointBase equal to this Size /// /// Size - the Size to convert to a PointBase public static explicit operator PointBase(SizeBase size) { return new PointBase(size._width, size._height); } #endregion Public Operators #region Private Methods static private SizeBase CreateEmptySize() { SizeBase size = new SizeBase(); // We can't set these via the property setters because negatives widths // are rejected in those APIs. size._width = Double.NegativeInfinity; size._height = Double.NegativeInfinity; return size; } #endregion Private Methods #region Private Fields private readonly static SizeBase s_empty = CreateEmptySize(); #endregion Private Fields #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) { if (IsEmpty) { return "Empty"; } // Helper to get the numeric list separator for a given culture. char separator = ','; return String.Format(provider, "{1:" + format + "}{0}{2:" + format + "}", separator, _width, _height); } #endregion Internal Properties } }