848 lines
27 KiB
C#
848 lines
27 KiB
C#
|
#region PDFsharp - A .NET library for processing PDF
|
||
|
//
|
||
|
// Authors:
|
||
|
// Stefan Lange
|
||
|
//
|
||
|
// Copyright (c) 2005-2017 empira Software GmbH, Cologne Area (Germany)
|
||
|
//
|
||
|
// http://www.pdfsharp.com
|
||
|
// http://sourceforge.net/projects/pdfsharp
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a
|
||
|
// copy of this software and associated documentation files (the "Software"),
|
||
|
// to deal in the Software without restriction, including without limitation
|
||
|
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||
|
// and/or sell copies of the Software, and to permit persons to whom the
|
||
|
// Software is furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included
|
||
|
// in all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||
|
// THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||
|
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||
|
// DEALINGS IN THE SOFTWARE.
|
||
|
#endregion
|
||
|
|
||
|
using System;
|
||
|
using System.Diagnostics;
|
||
|
using System.Globalization;
|
||
|
using System.Runtime.InteropServices;
|
||
|
#if CORE
|
||
|
#endif
|
||
|
#if GDI
|
||
|
using System.Drawing;
|
||
|
using System.Drawing.Drawing2D;
|
||
|
#endif
|
||
|
#if WPF
|
||
|
using System.Windows;
|
||
|
using System.Windows.Media;
|
||
|
using SysPoint = System.Windows.Point;
|
||
|
using SysSize = System.Windows.Size;
|
||
|
using SysRect = System.Windows.Rect;
|
||
|
#endif
|
||
|
#if NETFX_CORE
|
||
|
using Windows.UI.Xaml.Media;
|
||
|
using SysPoint = Windows.Foundation.Point;
|
||
|
using SysSize = Windows.Foundation.Size;
|
||
|
using SysRect = Windows.Foundation.Rect;
|
||
|
#endif
|
||
|
#if !EDF_CORE
|
||
|
using PdfSharp.Internal;
|
||
|
#else
|
||
|
using PdfSharp.Internal;
|
||
|
#endif
|
||
|
|
||
|
namespace PdfSharp.Drawing
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Stores a set of four floating-point numbers that represent the location and size of a rectangle.
|
||
|
/// </summary>
|
||
|
[DebuggerDisplay("{DebuggerDisplay}")]
|
||
|
[Serializable, StructLayout(LayoutKind.Sequential)] // , ValueSerializer(typeof(RectValueSerializer)), TypeConverter(typeof(RectConverter))]
|
||
|
public struct XRect : IFormattable
|
||
|
{
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(double x, double y, double width, double height)
|
||
|
{
|
||
|
if (width < 0 || height < 0)
|
||
|
throw new ArgumentException("WidthAndHeightCannotBeNegative"); //SR.Get(SRID.Size_WidthAndHeightCannotBeNegative, new object[0]));
|
||
|
_x = x;
|
||
|
_y = y;
|
||
|
_width = width;
|
||
|
_height = height;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(XPoint point1, XPoint point2)
|
||
|
{
|
||
|
_x = Math.Min(point1.X, point2.X);
|
||
|
_y = Math.Min(point1.Y, point2.Y);
|
||
|
_width = Math.Max(Math.Max(point1.X, point2.X) - _x, 0);
|
||
|
_height = Math.Max(Math.Max(point1.Y, point2.Y) - _y, 0);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(XPoint point, XVector vector)
|
||
|
: this(point, point + vector)
|
||
|
{ }
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(XPoint location, XSize size)
|
||
|
{
|
||
|
if (size.IsEmpty)
|
||
|
this = s_empty;
|
||
|
else
|
||
|
{
|
||
|
_x = location.X;
|
||
|
_y = location.Y;
|
||
|
_width = size.Width;
|
||
|
_height = size.Height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(XSize size)
|
||
|
{
|
||
|
if (size.IsEmpty)
|
||
|
this = s_empty;
|
||
|
else
|
||
|
{
|
||
|
_x = _y = 0;
|
||
|
_width = size.Width;
|
||
|
_height = size.Height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(PointF location, SizeF size)
|
||
|
{
|
||
|
_x = location.X;
|
||
|
_y = location.Y;
|
||
|
_width = size.Width;
|
||
|
_height = size.Height;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(RectangleF rect)
|
||
|
{
|
||
|
_x = rect.X;
|
||
|
_y = rect.Y;
|
||
|
_width = rect.Width;
|
||
|
_height = rect.Height;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if WPF || NETFX_CORE
|
||
|
/// <summary>
|
||
|
/// Initializes a new instance of the XRect class.
|
||
|
/// </summary>
|
||
|
public XRect(SysRect rect)
|
||
|
{
|
||
|
_x = rect.X;
|
||
|
_y = rect.Y;
|
||
|
_width = rect.Width;
|
||
|
_height = rect.Height;
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a rectangle from for straight lines.
|
||
|
/// </summary>
|
||
|
// ReSharper disable InconsistentNaming
|
||
|
public static XRect FromLTRB(double left, double top, double right, double bottom)
|
||
|
// ReSharper restore InconsistentNaming
|
||
|
{
|
||
|
return new XRect(left, top, right - left, bottom - top);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the two rectangles are equal.
|
||
|
/// </summary>
|
||
|
public static bool operator ==(XRect rect1, XRect rect2)
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
return rect1.X == rect2.X && rect1.Y == rect2.Y && rect1.Width == rect2.Width && rect1.Height == rect2.Height;
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the two rectangles are not equal.
|
||
|
/// </summary>
|
||
|
public static bool operator !=(XRect rect1, XRect rect2)
|
||
|
{
|
||
|
return !(rect1 == rect2);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether the two rectangles are equal.
|
||
|
/// </summary>
|
||
|
public static bool Equals(XRect rect1, XRect rect2)
|
||
|
{
|
||
|
if (rect1.IsEmpty)
|
||
|
return rect2.IsEmpty;
|
||
|
return rect1.X.Equals(rect2.X) && rect1.Y.Equals(rect2.Y) && rect1.Width.Equals(rect2.Width) && rect1.Height.Equals(rect2.Height);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether this instance and the specified object are equal.
|
||
|
/// </summary>
|
||
|
public override bool Equals(object o)
|
||
|
{
|
||
|
if (!(o is XRect))
|
||
|
return false;
|
||
|
return Equals(this, (XRect)o);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Determines whether this instance and the specified rect are equal.
|
||
|
/// </summary>
|
||
|
public bool Equals(XRect value)
|
||
|
{
|
||
|
return Equals(this, value);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the hash code for this instance.
|
||
|
/// </summary>
|
||
|
public override int GetHashCode()
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return 0;
|
||
|
return X.GetHashCode() ^ Y.GetHashCode() ^ Width.GetHashCode() ^ Height.GetHashCode();
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Parses the rectangle from a string.
|
||
|
/// </summary>
|
||
|
public static XRect Parse(string source)
|
||
|
{
|
||
|
XRect empty;
|
||
|
CultureInfo cultureInfo = CultureInfo.InvariantCulture;
|
||
|
TokenizerHelper helper = new TokenizerHelper(source, cultureInfo);
|
||
|
string str = helper.NextTokenRequired();
|
||
|
if (str == "Empty")
|
||
|
empty = Empty;
|
||
|
else
|
||
|
empty = new XRect(Convert.ToDouble(str, cultureInfo), Convert.ToDouble(helper.NextTokenRequired(), cultureInfo), Convert.ToDouble(helper.NextTokenRequired(), cultureInfo), Convert.ToDouble(helper.NextTokenRequired(), cultureInfo));
|
||
|
helper.LastTokenRequired();
|
||
|
return empty;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts this XRect to a human readable string.
|
||
|
/// </summary>
|
||
|
public override string ToString()
|
||
|
{
|
||
|
return ConvertToString(null, null);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts this XRect to a human readable string.
|
||
|
/// </summary>
|
||
|
public string ToString(IFormatProvider provider)
|
||
|
{
|
||
|
return ConvertToString(null, provider);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Converts this XRect to a human readable string.
|
||
|
/// </summary>
|
||
|
string IFormattable.ToString(string format, IFormatProvider provider)
|
||
|
{
|
||
|
return ConvertToString(format, provider);
|
||
|
}
|
||
|
|
||
|
internal string ConvertToString(string format, IFormatProvider provider)
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return "Empty";
|
||
|
char numericListSeparator = TokenizerHelper.GetNumericListSeparator(provider);
|
||
|
provider = provider ?? CultureInfo.InvariantCulture;
|
||
|
// ReSharper disable FormatStringProblem
|
||
|
return string.Format(provider, "{1:" + format + "}{0}{2:" + format + "}{0}{3:" + format + "}{0}{4:" + format + "}", new object[] { numericListSeparator, _x, _y, _width, _height });
|
||
|
// ReSharper restore FormatStringProblem
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the empty rectangle.
|
||
|
/// </summary>
|
||
|
public static XRect Empty
|
||
|
{
|
||
|
get { return s_empty; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets a value indicating whether this instance is empty.
|
||
|
/// </summary>
|
||
|
public bool IsEmpty
|
||
|
{
|
||
|
get { return _width < 0; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the location of the rectangle.
|
||
|
/// </summary>
|
||
|
public XPoint Location
|
||
|
{
|
||
|
get { return new XPoint(_x, _y); }
|
||
|
set
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
_x = value.X;
|
||
|
_y = value.Y;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the size of the rectangle.
|
||
|
/// </summary>
|
||
|
//[Browsable(false)]
|
||
|
public XSize Size
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return XSize.Empty;
|
||
|
return new XSize(_width, _height);
|
||
|
}
|
||
|
set
|
||
|
{
|
||
|
if (value.IsEmpty)
|
||
|
this = s_empty;
|
||
|
else
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
_width = value.Width;
|
||
|
_height = value.Height;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the X value of the rectangle.
|
||
|
/// </summary>
|
||
|
public double X
|
||
|
{
|
||
|
get { return _x; }
|
||
|
set
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
_x = value;
|
||
|
}
|
||
|
}
|
||
|
double _x;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the Y value of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Y
|
||
|
{
|
||
|
get { return _y; }
|
||
|
set
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
_y = value;
|
||
|
}
|
||
|
}
|
||
|
double _y;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the width of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Width
|
||
|
{
|
||
|
get { return _width; }
|
||
|
set
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
if (value < 0)
|
||
|
throw new ArgumentException("WidthCannotBeNegative"); //SR.Get(SRID.Size_WidthCannotBeNegative, new object[0]));
|
||
|
|
||
|
_width = value;
|
||
|
}
|
||
|
}
|
||
|
double _width;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets or sets the height of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Height
|
||
|
{
|
||
|
get { return _height; }
|
||
|
set
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotModifyEmptyRect"); //SR.Get(SRID.Rect_CannotModifyEmptyRect, new object[0]));
|
||
|
if (value < 0)
|
||
|
throw new ArgumentException("HeightCannotBeNegative"); //SR.Get(SRID.Size_HeightCannotBeNegative, new object[0]));
|
||
|
_height = value;
|
||
|
}
|
||
|
}
|
||
|
double _height;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the x-axis value of the left side of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Left
|
||
|
{
|
||
|
get { return _x; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the y-axis value of the top side of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Top
|
||
|
{
|
||
|
get { return _y; }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the x-axis value of the right side of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Right
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return double.NegativeInfinity;
|
||
|
return _x + _width;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the y-axis value of the bottom side of the rectangle.
|
||
|
/// </summary>
|
||
|
public double Bottom
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return double.NegativeInfinity;
|
||
|
return _y + _height;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the position of the top-left corner of the rectangle.
|
||
|
/// </summary>
|
||
|
public XPoint TopLeft
|
||
|
{
|
||
|
get { return new XPoint(Left, Top); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the position of the top-right corner of the rectangle.
|
||
|
/// </summary>
|
||
|
public XPoint TopRight
|
||
|
{
|
||
|
get { return new XPoint(Right, Top); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the position of the bottom-left corner of the rectangle.
|
||
|
/// </summary>
|
||
|
public XPoint BottomLeft
|
||
|
{
|
||
|
get { return new XPoint(Left, Bottom); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the position of the bottom-right corner of the rectangle.
|
||
|
/// </summary>
|
||
|
public XPoint BottomRight
|
||
|
{
|
||
|
get { return new XPoint(Right, Bottom); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the center of the rectangle.
|
||
|
/// </summary>
|
||
|
//[Browsable(false)]
|
||
|
public XPoint Center
|
||
|
{
|
||
|
get { return new XPoint(_x + _width / 2, _y + _height / 2); }
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether the rectangle contains the specified point.
|
||
|
/// </summary>
|
||
|
public bool Contains(XPoint point)
|
||
|
{
|
||
|
return Contains(point.X, point.Y);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether the rectangle contains the specified point.
|
||
|
/// </summary>
|
||
|
public bool Contains(double x, double y)
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
return false;
|
||
|
return ContainsInternal(x, y);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether the rectangle contains the specified rectangle.
|
||
|
/// </summary>
|
||
|
public bool Contains(XRect rect)
|
||
|
{
|
||
|
return !IsEmpty && !rect.IsEmpty &&
|
||
|
_x <= rect._x && _y <= rect._y &&
|
||
|
_x + _width >= rect._x + rect._width && _y + _height >= rect._y + rect._height;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Indicates whether the specified rectangle intersects with the current rectangle.
|
||
|
/// </summary>
|
||
|
public bool IntersectsWith(XRect rect)
|
||
|
{
|
||
|
return !IsEmpty && !rect.IsEmpty &&
|
||
|
rect.Left <= Right && rect.Right >= Left &&
|
||
|
rect.Top <= Bottom && rect.Bottom >= Top;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets current rectangle to the intersection of the current rectangle and the specified rectangle.
|
||
|
/// </summary>
|
||
|
public void Intersect(XRect rect)
|
||
|
{
|
||
|
if (!IntersectsWith(rect))
|
||
|
this = Empty;
|
||
|
else
|
||
|
{
|
||
|
double left = Math.Max(Left, rect.Left);
|
||
|
double top = Math.Max(Top, rect.Top);
|
||
|
_width = Math.Max(Math.Min(Right, rect.Right) - left, 0.0);
|
||
|
_height = Math.Max(Math.Min(Bottom, rect.Bottom) - top, 0.0);
|
||
|
_x = left;
|
||
|
_y = top;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the intersection of two rectangles.
|
||
|
/// </summary>
|
||
|
public static XRect Intersect(XRect rect1, XRect rect2)
|
||
|
{
|
||
|
rect1.Intersect(rect2);
|
||
|
return rect1;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets current rectangle to the union of the current rectangle and the specified rectangle.
|
||
|
/// </summary>
|
||
|
public void Union(XRect rect)
|
||
|
{
|
||
|
// ReSharper disable CompareOfFloatsByEqualityOperator
|
||
|
if (IsEmpty)
|
||
|
this = rect;
|
||
|
else if (!rect.IsEmpty)
|
||
|
{
|
||
|
double left = Math.Min(Left, rect.Left);
|
||
|
double top = Math.Min(Top, rect.Top);
|
||
|
if (rect.Width == Double.PositiveInfinity || Width == Double.PositiveInfinity)
|
||
|
_width = Double.PositiveInfinity;
|
||
|
else
|
||
|
{
|
||
|
double right = Math.Max(Right, rect.Right);
|
||
|
_width = Math.Max(right - left, 0.0);
|
||
|
}
|
||
|
|
||
|
if (rect.Height == Double.PositiveInfinity || _height == Double.PositiveInfinity)
|
||
|
_height = Double.PositiveInfinity;
|
||
|
else
|
||
|
{
|
||
|
double bottom = Math.Max(Bottom, rect.Bottom);
|
||
|
_height = Math.Max(bottom - top, 0.0);
|
||
|
}
|
||
|
_x = left;
|
||
|
_y = top;
|
||
|
}
|
||
|
// ReSharper restore CompareOfFloatsByEqualityOperator
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the union of two rectangles.
|
||
|
/// </summary>
|
||
|
public static XRect Union(XRect rect1, XRect rect2)
|
||
|
{
|
||
|
rect1.Union(rect2);
|
||
|
return rect1;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Sets current rectangle to the union of the current rectangle and the specified point.
|
||
|
/// </summary>
|
||
|
public void Union(XPoint point)
|
||
|
{
|
||
|
Union(new XRect(point, point));
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the intersection of a rectangle and a point.
|
||
|
/// </summary>
|
||
|
public static XRect Union(XRect rect, XPoint point)
|
||
|
{
|
||
|
rect.Union(new XRect(point, point));
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Moves a rectangle by the specified amount.
|
||
|
/// </summary>
|
||
|
public void Offset(XVector offsetVector)
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotCallMethod"); //SR.Get(SRID.Rect_CannotCallMethod, new object[0]));
|
||
|
_x += offsetVector.X;
|
||
|
_y += offsetVector.Y;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Moves a rectangle by the specified amount.
|
||
|
/// </summary>
|
||
|
public void Offset(double offsetX, double offsetY)
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotCallMethod"); //SR.Get(SRID.Rect_CannotCallMethod, new object[0]));
|
||
|
_x += offsetX;
|
||
|
_y += offsetY;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns a rectangle that is offset from the specified rectangle by using the specified vector.
|
||
|
/// </summary>
|
||
|
public static XRect Offset(XRect rect, XVector offsetVector)
|
||
|
{
|
||
|
rect.Offset(offsetVector.X, offsetVector.Y);
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns a rectangle that is offset from the specified rectangle by using specified horizontal and vertical amounts.
|
||
|
/// </summary>
|
||
|
public static XRect Offset(XRect rect, double offsetX, double offsetY)
|
||
|
{
|
||
|
rect.Offset(offsetX, offsetY);
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Translates the rectangle by adding the specified point.
|
||
|
/// </summary>
|
||
|
//[Obsolete("Use Offset.")]
|
||
|
public static XRect operator +(XRect rect, XPoint point)
|
||
|
{
|
||
|
return new XRect(rect._x + point.X, rect.Y + point.Y, rect._width, rect._height);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Translates the rectangle by subtracting the specified point.
|
||
|
/// </summary>
|
||
|
//[Obsolete("Use Offset.")]
|
||
|
public static XRect operator -(XRect rect, XPoint point)
|
||
|
{
|
||
|
return new XRect(rect._x - point.X, rect.Y - point.Y, rect._width, rect._height);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Expands the rectangle by using the specified Size, in all directions.
|
||
|
/// </summary>
|
||
|
public void Inflate(XSize size)
|
||
|
{
|
||
|
Inflate(size.Width, size.Height);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Expands or shrinks the rectangle by using the specified width and height amounts, in all directions.
|
||
|
/// </summary>
|
||
|
public void Inflate(double width, double height)
|
||
|
{
|
||
|
if (IsEmpty)
|
||
|
throw new InvalidOperationException("CannotCallMethod"); //SR.Get(SRID.Rect_CannotCallMethod, new object[0]));
|
||
|
_x -= width;
|
||
|
_y -= height;
|
||
|
_width += width;
|
||
|
_width += width;
|
||
|
_height += height;
|
||
|
_height += height;
|
||
|
if (_width < 0 || _height < 0)
|
||
|
this = s_empty;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the rectangle that results from expanding the specified rectangle by the specified Size, in all directions.
|
||
|
/// </summary>
|
||
|
public static XRect Inflate(XRect rect, XSize size)
|
||
|
{
|
||
|
rect.Inflate(size.Width, size.Height);
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Creates a rectangle that results from expanding or shrinking the specified rectangle by the specified width and height amounts, in all directions.
|
||
|
/// </summary>
|
||
|
public static XRect Inflate(XRect rect, double width, double height)
|
||
|
{
|
||
|
rect.Inflate(width, height);
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Returns the rectangle that results from applying the specified matrix to the specified rectangle.
|
||
|
/// </summary>
|
||
|
public static XRect Transform(XRect rect, XMatrix matrix)
|
||
|
{
|
||
|
XMatrix.MatrixHelper.TransformRect(ref rect, ref matrix);
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Transforms the rectangle by applying the specified matrix.
|
||
|
/// </summary>
|
||
|
public void Transform(XMatrix matrix)
|
||
|
{
|
||
|
XMatrix.MatrixHelper.TransformRect(ref this, ref matrix);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Multiplies the size of the current rectangle by the specified x and y values.
|
||
|
/// </summary>
|
||
|
public void Scale(double scaleX, double scaleY)
|
||
|
{
|
||
|
if (!IsEmpty)
|
||
|
{
|
||
|
_x *= scaleX;
|
||
|
_y *= scaleY;
|
||
|
_width *= scaleX;
|
||
|
_height *= scaleY;
|
||
|
if (scaleX < 0)
|
||
|
{
|
||
|
_x += _width;
|
||
|
_width *= -1.0;
|
||
|
}
|
||
|
if (scaleY < 0)
|
||
|
{
|
||
|
_y += _height;
|
||
|
_height *= -1.0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#if CORE // Internal version in CORE build.
|
||
|
#if UseGdiObjects
|
||
|
/// <summary>
|
||
|
/// Converts this instance to a System.Drawing.RectangleF.
|
||
|
/// </summary>
|
||
|
internal RectangleF ToRectangleF()
|
||
|
{
|
||
|
return new RectangleF((float)_x, (float)_y, (float)_width, (float)_height);
|
||
|
}
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Converts this instance to a System.Drawing.RectangleF.
|
||
|
/// </summary>
|
||
|
public RectangleF ToRectangleF()
|
||
|
{
|
||
|
return new RectangleF((float)_x, (float)_y, (float)_width, (float)_height);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if GDI
|
||
|
/// <summary>
|
||
|
/// Performs an implicit conversion from a System.Drawing.Rectangle to an XRect.
|
||
|
/// </summary>
|
||
|
public static implicit operator XRect(Rectangle rect)
|
||
|
{
|
||
|
return new XRect(rect.X, rect.Y, rect.Width, rect.Height);
|
||
|
}
|
||
|
|
||
|
/// <summary>
|
||
|
/// Performs an implicit conversion from a System.Drawing.RectangleF to an XRect.
|
||
|
/// </summary>
|
||
|
public static implicit operator XRect(RectangleF rect)
|
||
|
{
|
||
|
return new XRect(rect.X, rect.Y, rect.Width, rect.Height);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
#if WPF || NETFX_CORE
|
||
|
/// <summary>
|
||
|
/// Performs an implicit conversion from System.Windows.Rect to XRect.
|
||
|
/// </summary>
|
||
|
public static implicit operator XRect(SysRect rect)
|
||
|
{
|
||
|
return new XRect(rect.X, rect.Y, rect.Width, rect.Height);
|
||
|
}
|
||
|
#endif
|
||
|
|
||
|
bool ContainsInternal(double x, double y)
|
||
|
{
|
||
|
return x >= _x && x - _width <= _x && y >= _y && y - _height <= _y;
|
||
|
}
|
||
|
|
||
|
static XRect CreateEmptyRect()
|
||
|
{
|
||
|
XRect rect = new XRect();
|
||
|
rect._x = double.PositiveInfinity;
|
||
|
rect._y = double.PositiveInfinity;
|
||
|
rect._width = double.NegativeInfinity;
|
||
|
rect._height = double.NegativeInfinity;
|
||
|
return rect;
|
||
|
}
|
||
|
|
||
|
static XRect()
|
||
|
{
|
||
|
s_empty = CreateEmptyRect();
|
||
|
}
|
||
|
|
||
|
static readonly XRect s_empty;
|
||
|
|
||
|
/// <summary>
|
||
|
/// Gets the DebuggerDisplayAttribute text.
|
||
|
/// </summary>
|
||
|
/// <value>The debugger display.</value>
|
||
|
// ReSharper disable UnusedMember.Local
|
||
|
string DebuggerDisplay
|
||
|
// ReSharper restore UnusedMember.Local
|
||
|
{
|
||
|
get
|
||
|
{
|
||
|
const string format = Config.SignificantFigures10;
|
||
|
return String.Format(CultureInfo.InvariantCulture,
|
||
|
"rect=({0:" + format + "}, {1:" + format + "}, {2:" + format + "}, {3:" + format + "})",
|
||
|
_x, _y, _width, _height);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|