committed by
GitHub
20 changed files with 410 additions and 106 deletions
@ -0,0 +1,268 @@ |
|||
// ReSharper disable CompareOfFloatsByEqualityOperator
|
|||
|
|||
using System; |
|||
using Avalonia.Metadata; |
|||
|
|||
namespace Avalonia.Platform; |
|||
|
|||
/// <summary>
|
|||
/// This struct is essentially the same thing as MilRectD
|
|||
/// Unlike our "normal" Rect which is more human-readable and human-usable
|
|||
/// this struct is optimized for actual processing that doesn't really care
|
|||
/// about Width and Height but pretty much always only cares about
|
|||
/// Right and Bottom edge coordinates
|
|||
///
|
|||
/// Not having to constantly convert between Width/Height and Right/Bottom for no actual reason
|
|||
/// saves us some perf
|
|||
///
|
|||
/// This structure is intended to be mostly internal, but it's exposed as a PrivateApi type so it can
|
|||
/// be passed to the drawing backend when needed
|
|||
/// </summary>
|
|||
[PrivateApi] |
|||
public struct LtrbRect |
|||
{ |
|||
public double Left, Top, Right, Bottom; |
|||
|
|||
internal LtrbRect(double x, double y, double right, double bottom) |
|||
{ |
|||
Left = x; |
|||
Top = y; |
|||
Right = right; |
|||
Bottom = bottom; |
|||
} |
|||
|
|||
internal LtrbRect(Rect rc) |
|||
{ |
|||
rc = rc.Normalize(); |
|||
Left = rc.X; |
|||
Top = rc.Y; |
|||
Right = rc.Right; |
|||
Bottom = rc.Bottom; |
|||
} |
|||
|
|||
internal bool IsZeroSize => Left == Right && Top == Bottom; |
|||
|
|||
internal LtrbRect Intersect(LtrbRect rect) |
|||
{ |
|||
var newLeft = (rect.Left > Left) ? rect.Left : Left; |
|||
var newTop = (rect.Top > Top) ? rect.Top : Top; |
|||
var newRight = (rect.Right < Right) ? rect.Right : Right; |
|||
var newBottom = (rect.Bottom < Bottom) ? rect.Bottom : Bottom; |
|||
|
|||
if ((newRight > newLeft) && (newBottom > newTop)) |
|||
{ |
|||
return new LtrbRect(newLeft, newTop, newRight, newBottom); |
|||
} |
|||
else |
|||
{ |
|||
return default; |
|||
} |
|||
} |
|||
|
|||
internal bool Intersects(LtrbRect rect) |
|||
{ |
|||
return (rect.Left < Right) && (Left < rect.Right) && (rect.Top < Bottom) && (Top < rect.Bottom); |
|||
} |
|||
|
|||
internal Rect ToRect() => new(Left, Top, Right - Left, Bottom - Top); |
|||
|
|||
internal LtrbRect Inflate(Thickness thickness) |
|||
{ |
|||
return new LtrbRect(Left - thickness.Left, Top - thickness.Top, Right + thickness.Right, |
|||
Bottom + thickness.Bottom); |
|||
} |
|||
|
|||
public static bool operator ==(LtrbRect left, LtrbRect right)=> |
|||
left.Left == right.Left && left.Top == right.Top && left.Right == right.Right && left.Bottom == right.Bottom; |
|||
|
|||
public static bool operator !=(LtrbRect left, LtrbRect right) => |
|||
left.Left != right.Left || left.Top != right.Top || left.Right != right.Right || left.Bottom != right.Bottom; |
|||
|
|||
public bool Equals(LtrbRect other) => |
|||
other.Left == Left && other.Top == Top && other.Right == Right && other.Bottom == Bottom; |
|||
|
|||
public bool Equals(ref LtrbRect other) => |
|||
other.Left == Left && other.Top == Top && other.Right == Right && other.Bottom == Bottom; |
|||
|
|||
internal Point TopLeft => new Point(Left, Top); |
|||
internal Point TopRight => new Point(Right, Top); |
|||
internal Point BottomLeft => new Point(Left, Bottom); |
|||
internal Point BottomRight => new Point(Right, Bottom); |
|||
|
|||
internal LtrbRect TransformToAABB(Matrix matrix) |
|||
{ |
|||
ReadOnlySpan<Point> points = stackalloc Point[4] |
|||
{ |
|||
TopLeft.Transform(matrix), |
|||
TopRight.Transform(matrix), |
|||
BottomRight.Transform(matrix), |
|||
BottomLeft.Transform(matrix) |
|||
}; |
|||
|
|||
var left = double.MaxValue; |
|||
var right = double.MinValue; |
|||
var top = double.MaxValue; |
|||
var bottom = double.MinValue; |
|||
|
|||
foreach (var p in points) |
|||
{ |
|||
if (p.X < left) left = p.X; |
|||
if (p.X > right) right = p.X; |
|||
if (p.Y < top) top = p.Y; |
|||
if (p.Y > bottom) bottom = p.Y; |
|||
} |
|||
|
|||
return new LtrbRect(left, top, right, bottom); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Perform _WPF-like_ union operation
|
|||
/// </summary>
|
|||
private LtrbRect FullUnionCore(LtrbRect rect) |
|||
{ |
|||
var x1 = Math.Min(Left, rect.Left); |
|||
var x2 = Math.Max(Right, rect.Right); |
|||
var y1 = Math.Min(Top, rect.Top); |
|||
var y2 = Math.Max(Bottom, rect.Bottom); |
|||
|
|||
return new(x1, y1, x2, y2); |
|||
} |
|||
|
|||
internal static LtrbRect? FullUnion(LtrbRect? left, LtrbRect? right) |
|||
{ |
|||
if (left == null) |
|||
return right; |
|||
if (right == null) |
|||
return left; |
|||
return right.Value.FullUnionCore(left.Value); |
|||
} |
|||
|
|||
internal static LtrbRect? FullUnion(LtrbRect? left, Rect? right) |
|||
{ |
|||
if (right == null) |
|||
return left; |
|||
if (left == null) |
|||
return new(right.Value); |
|||
return left.Value.FullUnionCore(new(right.Value)); |
|||
} |
|||
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
if (obj is LtrbRect other) |
|||
return Equals(other); |
|||
return false; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hash = 17; |
|||
hash = (hash * 23) + Left.GetHashCode(); |
|||
hash = (hash * 23) + Top.GetHashCode(); |
|||
hash = (hash * 23) + Right.GetHashCode(); |
|||
hash = (hash * 23) + Bottom.GetHashCode(); |
|||
return hash; |
|||
} |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// This struct is essentially the same thing as RECT from win32 API
|
|||
/// Unlike our "normal" PixelRect which is more human-readable and human-usable
|
|||
/// this struct is optimized for actual processing that doesn't really care
|
|||
/// about Width and Height but pretty much always only cares about
|
|||
/// Right and Bottom edge coordinates
|
|||
///
|
|||
/// Not having to constantly convert between Width/Height and Right/Bottom for no actual reason
|
|||
/// saves us some perf
|
|||
///
|
|||
/// This structure is intended to be mostly internal, but it's exposed as a PrivateApi type so it can
|
|||
/// be passed to the drawing backend when needed
|
|||
/// </summary>
|
|||
[PrivateApi] |
|||
public struct LtrbPixelRect |
|||
{ |
|||
public int Left, Top, Right, Bottom; |
|||
|
|||
internal LtrbPixelRect(int x, int y, int right, int bottom) |
|||
{ |
|||
Left = x; |
|||
Top = y; |
|||
Right = right; |
|||
Bottom = bottom; |
|||
} |
|||
|
|||
internal LtrbPixelRect(PixelSize size) |
|||
{ |
|||
Left = 0; |
|||
Top = 0; |
|||
Right = size.Width; |
|||
Bottom = size.Height; |
|||
} |
|||
|
|||
internal bool IsEmpty => Left == Right && Top == Bottom; |
|||
|
|||
internal PixelRect ToPixelRect() => new(Left, Top, Right - Left, Bottom - Top); |
|||
internal LtrbPixelRect Union(LtrbPixelRect rect) |
|||
{ |
|||
if (IsEmpty) |
|||
return rect; |
|||
if (rect.IsEmpty) |
|||
return this; |
|||
var x1 = Math.Min(Left, rect.Left); |
|||
var x2 = Math.Max(Right, rect.Right); |
|||
var y1 = Math.Min(Top, rect.Top); |
|||
var y2 = Math.Max(Bottom, rect.Bottom); |
|||
|
|||
return new(x1, y1, x2, y2); |
|||
} |
|||
|
|||
internal Rect ToRectWithNoScaling() => new(Left, Top, (Right - Left), (Bottom - Top)); |
|||
|
|||
internal bool Contains(int x, int y) |
|||
{ |
|||
return x >= Left && x <= Right && y >= Top && y <= Bottom; |
|||
} |
|||
|
|||
internal static LtrbPixelRect FromRectWithNoScaling(LtrbRect rect) => |
|||
new((int)rect.Left, (int)rect.Top, (int)Math.Ceiling(rect.Right), |
|||
(int)Math.Ceiling(rect.Bottom)); |
|||
|
|||
public static bool operator ==(LtrbPixelRect left, LtrbPixelRect right)=> |
|||
left.Left == right.Left && left.Top == right.Top && left.Right == right.Right && left.Bottom == right.Bottom; |
|||
|
|||
public static bool operator !=(LtrbPixelRect left, LtrbPixelRect right) => |
|||
left.Left != right.Left || left.Top != right.Top || left.Right != right.Right || left.Bottom != right.Bottom; |
|||
|
|||
public bool Equals(LtrbPixelRect other) => |
|||
other.Left == Left && other.Top == Top && other.Right == Right && other.Bottom == Bottom; |
|||
|
|||
public override bool Equals(object? obj) |
|||
{ |
|||
if (obj is LtrbPixelRect other) |
|||
return Equals(other); |
|||
return false; |
|||
} |
|||
|
|||
public override int GetHashCode() |
|||
{ |
|||
unchecked |
|||
{ |
|||
int hash = 17; |
|||
hash = (hash * 23) + Left.GetHashCode(); |
|||
hash = (hash * 23) + Top.GetHashCode(); |
|||
hash = (hash * 23) + Right.GetHashCode(); |
|||
hash = (hash * 23) + Bottom.GetHashCode(); |
|||
return hash; |
|||
} |
|||
} |
|||
|
|||
internal Rect ToRectUnscaled() => new(Left, Top, Right - Left, Bottom - Top); |
|||
|
|||
internal static LtrbPixelRect FromRectUnscaled(LtrbRect rect) |
|||
{ |
|||
return new LtrbPixelRect((int)rect.Left, (int)rect.Top, (int)Math.Ceiling(rect.Right), |
|||
(int)Math.Ceiling(rect.Bottom)); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue