/// <summary> /// Clamps point coordinate according to the specified size (rect.X, rect.Y, rect.Right, rect.Bottom). /// </summary> /// <param name="point">The point to clamp.</param> /// <param name="rect">The valid region.</param> /// <returns>Clamped point.</returns> public static PointF Clamp(this PointF point, RectangleF rect) { return new PointF { X = System.Math.Min(System.Math.Max(rect.X, point.X), rect.Right), Y = System.Math.Min(System.Math.Max(rect.Y, point.Y), rect.Bottom) }; }
/// <summary> /// Randomizes rectangle position and scale and returns randomized rectangles. /// </summary> /// <param name="rect">Rectangle.</param> /// <param name="locationOffset">Minimum location offset for horizontal and vertical direction respectively.</param> /// <param name="sizeOffset">Minimum size offset for horizontal and vertical direction respectively.</param> /// <param name="nRandomizedRectangles">Number of randomized rectangles to generate.</param> /// <param name="rand">Random generator. If null the instance will be generated.</param> /// <returns>Randomized rectangles.</returns> /// <example> /// var img = new Image<Bgr, byte>(640, 480); /// /// var rect = new RectangleF(50, 50, 100, 50); /// /// var locationOffsets = new Range(-0.05f, +0.05f); /// var sizeOffsets = new Range(0.9f, 1.1f); /// var randomizedRects = rect.Randomize(new Pair<Range>(locationOffsets, locationOffsets), new Pair<Range>(sizeOffsets, sizeOffsets), 5); /// randomizedRects = randomizedRects.Select(x => x.SetScaleTo(rect.Size)); /// /// img.Draw(rect, Bgr8.Red, 3); /// /// foreach (var randomizedRect in randomizedRects) /// { /// img.Draw(randomizedRect, Bgr8.Green, 1); /// } /// /// ImageBox.Show(img.ToBitmap(), PictureBoxSizeMode.AutoSize); /// return; /// </example> public static IEnumerable<RectangleF> Randomize(this RectangleF rect, Pair<RangeF> locationOffset, Pair<RangeF> sizeOffset, int nRandomizedRectangles, Random rand = null) { rand = rand ?? new Random(); for (int i = 0; i < nRandomizedRectangles; i++) { var randRect = new RectangleF { X = rect.X + rect.Width * (float)rand.NextDouble(locationOffset.First.Min, locationOffset.First.Max), Y = rect.Y + rect.Height * (float)rand.NextDouble(locationOffset.Second.Min, locationOffset.Second.Max), Width = rect.Width * (float)rand.NextDouble(sizeOffset.First.Min, sizeOffset.First.Max), Height = rect.Height * (float)rand.NextDouble(sizeOffset.Second.Min, sizeOffset.Second.Max) }; yield return randRect; } }
/// <summary> /// Converts the specified RectangleF to a Rectangle by truncating the RectangleF values. /// </summary> /// <param name="value">The RectangleF to be converted.</param> /// <returns>A rectangle.</returns> public static Rectangle Truncate(RectangleF value) { int x, y, w, h; checked { x = (int)value.X; y = (int)value.Y; w = (int)value.Width; h = (int)value.Height; } return new Rectangle(x, y, w, h); }
/// <summary> /// Converts the specified RectangleF to a Rectangle by rounding the RectangleF values to the nearest integer values. /// </summary> /// <param name="value">The RectangleF to be converted.</param> /// <returns>A rectangle.</returns> public static Rectangle Round(RectangleF value) { int x, y, w, h; checked { x = (int)Math.Round(value.X); y = (int)Math.Round(value.Y); w = (int)Math.Round(value.Width); h = (int)Math.Round(value.Height); } return new Rectangle(x, y, w, h); }
/// <summary> /// Inflates the rectangle by specified width and height (can be negative) and automatically clamps rectangle coordinates. /// </summary> /// <param name="rect">Rectangle to inflate.</param> /// <param name="widthScale">Horizontal scale.</param> /// <param name="heightScale">Vertical scale.</param> /// <param name="constrainedArea">If specified rectangle region will be clamped.</param> /// <returns>Inflated rectangle.</returns> public static RectangleF Inflate(this RectangleF rect, double widthScale, double heightScale, SizeF constrainedArea = default(SizeF)) { RectangleF newRect = new RectangleF { X = (float)(rect.X - rect.Width * widthScale / 2), Y = (float)(rect.Y - rect.Height * heightScale / 2), Width = (float)(rect.Width + rect.Width * widthScale), Height = (float)(rect.Height + rect.Height * heightScale) }; if (constrainedArea.IsEmpty == false) newRect.Intersect(new RectangleF(new PointF(), constrainedArea)); return newRect; }
/// <summary> /// Gets intersection percent of two rectangles. /// </summary> /// <param name="rect1">First rectangle.</param> /// <param name="rect2">Second rectangle.</param> /// <returns>Intersection percent (1 - full intersection, 0 - no intersection).</returns> public static float IntersectionPercent(this RectangleF rect1, RectangleF rect2) { float rect1Area = rect1.Width * rect1.Height; float rect2Area = rect2.Width * rect2.Height; RectangleF interesectRect = RectangleF.Intersect(rect1, rect2); float intersectRectArea = interesectRect.Width * interesectRect.Height; float minRectArea = System.Math.Min(rect1Area, rect2Area); return (float)intersectRectArea / minRectArea; }
/// <summary> /// Changes rectangle's location in order to fit the specified area. /// </summary> /// <param name="rect">Rectangle.</param> /// <param name="area">Valid bounding box.</param> /// <param name="translatedRectangle">Translated rectangle.</param> /// <returns>True if the translation exist, false otherwise.</returns> public static bool MoveToFit(this RectangleF rect, SizeF area, out RectangleF translatedRectangle) { var leftOffset = (rect.X < 0) ? -rect.X : 0; var topOffset = (rect.Y < 0) ? -rect.Y : 0; rect.X += leftOffset; rect.Y += topOffset; var rightOffset = (rect.Right > area.Width) ? (area.Width - rect.Right) : 0; var bottomOffset = (rect.Bottom > area.Height) ? (area.Height - rect.Bottom) : 0; rect.X += rightOffset; rect.Y += bottomOffset; translatedRectangle = rect; if (rect.X < 0 || rect.Y < 0 || rect.Right > area.Width || rect.Bottom > area.Height) return false; return true; }
/// <summary> /// Creates new structure from area and angle. /// </summary> /// <param name="rect">Area.</param> /// <param name="angle">Angle in degrees.</param> public Box2D(RectangleF rect, float angle) : this(rect.Center(), rect.Size, angle) { }
private bool intersectsWithInclusive(RectangleF r) { return !((Left > r.Right) || (Right < r.Left) || (Top > r.Bottom) || (Bottom < r.Top)); }
/// <summary> /// Determines if this rectangle intersects with <paramref name="rect"/>. /// </summary> /// <param name="rect">The rectangle to test.</param> /// <returns>This method returns true if there is any intersection, otherwise false.</returns> public bool IntersectsWith(RectangleF rect) { return !((Left >= rect.Right) || (Right <= rect.Left) || (Top >= rect.Bottom) || (Bottom <= rect.Top)); }
/// <summary> /// Replaces this rectangle with the intersection of itself and the specified rectangle. /// </summary> /// <param name="rect">The rectangle with which to intersect.</param> public void Intersect(RectangleF rect) { this = RectangleF.Intersect(this, rect); }
/// <summary> /// Determines if the rectangular region represented by <paramref name="rect"/> is entirely contained within this RectangleF structure. /// </summary> /// <param name="rect">The Rectangle to test.</param> /// <returns>This method returns true if the rectangular region represented by <paramref name="rect"/> is entirely contained within this RectangleF structure; otherwise false.</returns> public bool Contains(RectangleF rect) { return (rect == Intersect(this, rect)); }
/// <summary> /// Gets a RectangleF structure that contains the union of two RectangleF structures. /// </summary> /// <param name="a">A rectangle to union.</param> /// <param name="b">A rectangle to union.</param> /// <returns>A RectangleF structure that bounds the union of the two RectangleF structures.</returns> public static RectangleF Union(RectangleF a, RectangleF b) { return FromLTRB(Math.Min(a.Left, b.Left), Math.Min(a.Top, b.Top), Math.Max(a.Right, b.Right), Math.Max(a.Bottom, b.Bottom)); }
/// <summary> /// Returns a third RectangleF structure that represents the intersection of two other RectangleF structures. /// If there is no intersection, an empty Rectangle is returned. /// </summary> /// <param name="a">A rectangle to intersect.</param> /// <param name="b">A rectangle to intersect.</param> /// <returns>A rectangle that represents the intersection of a and b.</returns> public static RectangleF Intersect(RectangleF a, RectangleF b) { // MS.NET returns a non-empty rectangle if the two rectangles // touch each other if (!a.intersectsWithInclusive(b)) return Empty; return FromLTRB( Math.Max(a.Left, b.Left), Math.Max(a.Top, b.Top), Math.Min(a.Right, b.Right), Math.Min(a.Bottom, b.Bottom)); }
/// <summary> /// Creates and returns an enlarged copy of the specified RectangleF structure. /// The copy is enlarged by the specified amount. /// The original RectangleF structure remains unmodified. /// </summary> /// <param name="rect">The RectangleF with which to start. This rectangle is not modified.</param> /// <param name="x">The amount to inflate this rectangle horizontally.</param> /// <param name="y">The amount to inflate this rectangle vertically.</param> /// <returns>The enlarged rectangle.</returns> public static RectangleF Inflate(RectangleF rect, float x, float y) { RectangleF ir = new RectangleF(rect.X, rect.Y, rect.Width, rect.Height); ir.Inflate(x, y); return ir; }