Skip to content
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

IntersectRect bug #77

Open
PatmanSan opened this issue May 15, 2019 · 5 comments
Open

IntersectRect bug #77

PatmanSan opened this issue May 15, 2019 · 5 comments

Comments

@PatmanSan
Copy link

Currently InterSectRect allows an empty rect to pass as valid (Right = Left, Bottom = Top):
Result := (Dst.Right >= Dst.Left) and (Dst.Bottom >= Dst.Top);

Should be
Result := (Dst.Right > Dst.Left) and (Dst.Bottom > Dst.Top);
or
Result := not IsRectEmpty(Dst);

@PatmanSan
Copy link
Author

Sorry for the bug in the title. Might as well be a feature required by the library. [Humbled]

@PatmanSan PatmanSan reopened this May 16, 2019
@andersmelander
Copy link
Member

The > vs >= doesn't matter. The result is the same.
The missing check for an empty rect however is unfortunate since this alone means the behavior is different from the standard RTL function.

It is unclear however what the correct behavior is. The RTL function originally mirrored the Win32 function of the same name and in this function the handling of empty rects is undefined - or at least undocumented.

One can of course argue that if one of the rects are empty, then any intersection must also be empty. But I guess it could also be argued that even though the intersection of two empty rects is an empty rect, they do in fact intersect. I don't know. I guess that's a question for the philosophers :-)

Anyhow, although I would love to bring the function into line with the Delphi RTL implementation, I'm hesitant to change such a low level function that has had this flaw for a very long time. We might break peoples code by doing so.

I'll have to investigate the history of this function a bit more before I take a stand.

Btw, I think it's a bug. If this was a feature request I would decline it on grounds of the preservation of backward compatibility.

@CuriousKit
Copy link
Contributor

Looking at this logically...

If the two input rects do not intersect at all, then Dst has at least one negative dimension and this is caught by the Result := (Dst.Right >= Dst.Left) and (Dst.Bottom >= Dst.Top); line. This also holds for two distinct empty rects (two empty rects that coincide will produce an empty rect in Dst).

On the other hand, if two rects touch on one of their edges, then the intersecting rect is a degenerate line (if they touch by a shared corner, then it's a degenerate point). Whether this should count as an intersection or not is up for debate. For the purposes of collision detection, for example, counting this as an intersection would be preferred.

However, let us look at another degenerate case... an empty rect inside a non-empty rect, or what is essentially a degenerate point or line inside a rect. Logically, this is a perfectly valid intersection; however, changing the criteria to Result := (Dst.Right > Dst.Left) and (Dst.Bottom > Dst.Top); would cause IntersectRect to return False in this case.

Long story short, my personal stand is "keep as is" due to the above.

@andersmelander
Copy link
Member

It's good to get a second opinion on this. FWIW, I don't think there really is a good solution.

As far as I can tell the function was originally introduced as a native (and thus faster) alternative to the Delphi RTL function which at that point was a call to the Win32 API function. Since then Delphi has gotten its own implementation(s) and if the behavior of the two had been identical then I would just have deprecated Graphic32's in favor of Delphi's.

I'm mostly leaning towards renaming or marking it deprecated to avoid the ambiguity. That at least would be hard-breaking change (meaning the compiler would fail or warn on it) which would force the developer to decide, case by case, if the RTL IntersectRect was a suitable replacement.

@CuriousKit
Copy link
Contributor

That's fine by me. As long as the behaviour is well-defined or at least well-documented for this function, that's all that matters in the end. Edge cases are always fun!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants