-
-
Notifications
You must be signed in to change notification settings - Fork 2.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
PixelRect Contains can be dangerous as implementation is not what I am expecting #14779
Comments
In addition, I am not sure that the use of Contains (inclusive) is correct in Avalonia,
should probably be ContainsExclusive? in fact I do not see any use case for Contains (inclusive)??? |
Whatever is done here should also be applied to All other frameworks I checked (Winforms, Skia, Godot, android.graphics, java.awt, and probably 95% of graphics frameworks in existence) all use an exclusive contains, which I agree is more intuitive. While it's a breaking change to change My personal opinion is that this should be changed in v12. |
@MrJul Sound good for V12 as it is a breaking change. About WPF, there is no Contains method in Int32Rect. There is a Contains method for Rect (double) but it is ok to include right/bottom point as coordinates are double. The correct implementation for PixelRect can be found in System.Drawing's Rectangle. |
This was probably copied from |
I'd be very wary to have different implementations between |
In my opinion, the Rect.Contains works as expected. If I create The problem here is the definition of PixelPoint. PixelPoint is not really a point, but a rectangle with a size of 1 by 1! If you replace PixelPoint with PixelRect with a size (1x1), then the I think it's enough to add the "size" of the pixel to the |
PixelPoint/PixelSize/PixelRect structs were intended to be used as device coordinates (i. e. as something that's not affected by transformations or DPI and maps directly to the pixel grid) with the same semantics as our normal rects. We should probably rename Rect itself will stay the same, but we might add WPF semantics for emptiness at some point (or just use |
Yes, and there's no ambiguity there, Rect2 is contained into Rect1 whichever Contains definition you use. Note that we're not talking at all about However That's why I argue that both var point = new Point(5, 1);
var blueRect = new Rect(0, 0, 5, 3);
var redRect = new Rect(point, new Size(1, 1));
Console.WriteLine("Blue contains Point? " + blueRect.Contains(point));
Console.WriteLine("Red contains Point? " + redRect.Contains(point));
Console.WriteLine("Blue contains Red? " + blueRect.Contains(redRect)); Output:
This result doesn't make much sense if the grid represents pixels (
Therefore, I strongly believe we should adjust both in the same way, either changing |
But this result is correct. Default In geometry, Point determined by the intersection of two curves. In this case, it is the intersection of a straight line (5, 0)-(5, 1) and (5, 1)-(5, 2). I.e. it is the intersection of the edges of these two rectangles. At the same time, the edges of the rectangles are part of them. I.e. the rectangles do not include each other, but both include point. The main problem is in the structure name!
You've just drawn a perfect example of a pixel grid. In your case, the red square is PixelPoint. And blue is a some of PixelRect. And I see only two ways of fix here:
public bool Contains(PixelPoint p)
{
return p.X >= X && p.X + 1 <= Right && p.Y >= Y && p.Y + 1 <= Bottom;
} That is, replace it with the code from public bool Contains(PixelPoint p)
{
return p.X >= X && p.X < Right && p.Y >= Y && p.Y < Bottom;
} But public bool Contains(PixelRect r)
{
return r.TopLeft.X >= X && r.TopLeft.X <= Right && r.TopLeft.Y >= Y && r.TopLeft.Y <= Bottom
&& r.BottomRight.X >= X && r.BottomRight.X <= Right && r.BottomRight.Y >= Y && r.BottomRight.Y <= Bottom;
} And most importantly, there is no need to change the behavior for Rect and Point.
P.S. Moreover, |
I confirm that there is no problem with Point (float) and Rect (float). |
Related, for context: #8594 |
Just found the cause of my Access Violation exception: the implementation of PixelRect Contains is not what I was expecting...
In my program I am displaying the color of the pixel at the mouse position,
and so as I always did, I get the position of the mouse, convert it to int (PixelPoint), and checked if this point is in the PixelRect of the image with image.Bounds.Contains(point) and BAM, random crashes...
After I added more checks, I found the cause:
And the existence of ContainsExclusive.
To my mind, the implementation of Contains shoud be the one of ContainsExclusive, as it is what I generally see in other frameworks.
For example in System.Drawing.Rectangle:
public readonly bool Contains(int x, int y) => X <= x && x < X + Width && Y <= y && y < Y + Height;
public readonly bool Contains(Point pt) => Contains(pt.X, pt.Y);
There is only 6 and 1 references to those methods in Avalonia so that could be a small change
Something like:
ContainsExclusive become Contains
Contains become ContainsInclusive
that would be more intuitive and safe for new users.
The text was updated successfully, but these errors were encountered: