Mam nadzieję, że jestem zdezorientowany w jakiś sposób. Otrzymuję niespójne zachowanie z TRect.Intersect
i TRect.IntersectsWith
. Oto kod, który demonstruje problem.TRekt.Intersect and TRect.IntersectsWith Inconsistencies
program RectCheck;
{$APPTYPE CONSOLE}
{$R *.res}
uses
System.SysUtils,
System.Types,
Vcl.Dialogs;
var
rect1: TRect;
rect2: TRect;
combinedRect: TRect;
begin
Rect1 := Rect(0,0,200,101);
Rect2 := Rect(0,100,200,200);
if Rect1.IntersectsWith(Rect2) then
begin
// We have interesected, get the combined rect
combinedRect := TRect.Intersect(Rect1, Rect2);
if not combinedRect.IsEmpty then
ShowMessage(Format('Our new rect (%d, %d), (%d, %d)',
[combinedRect.Left, combinedRect.Top, combinedRect.Right, combinedRect.Bottom]))
else
raise Exception.Create('They were supposed to intersect!');
end;
Rect1 := Rect(0,0,200,100);
Rect2 := Rect(0,100,200,200);
if Rect1.IntersectsWith(Rect2) then
begin
// We have interesected, get the combined rect
combinedRect := TRect.Intersect(Rect1, Rect2);
if not combinedRect.IsEmpty then
ShowMessage(Format('Our new rect (%d, %d), (%d, %d)',
[combinedRect.Left, combinedRect.Top, combinedRect.Right, combinedRect.Bottom]))
else
raise Exception.Create('They were supposed to intersect!');
end;
end.
Drugi wyjątek został zgłoszony. TRect.IntersectsWith
wskazuje, że rects przecinają się, ale kiedy zadzwonię pod numer TRect.Intersect
, aby uzyskać nowy przecięty prostokąt, to zwraca on pusty rect.
Kod w PrzecięcieWith (który nie jest napisany bardzo wyraźnie) zwraca true w drugim przypadku, ponieważ Self.BottomRight.Y = R.TopLeft.Y (100).
function TRect.IntersectsWith(const R: TRect): Boolean;
begin
Result := not ((Self.BottomRight.X < R.TopLeft.X) or
(Self.BottomRight.Y < R.TopLeft.Y) or
(R.BottomRight.X < Self.TopLeft.X) or
(R.BottomRight.Y < Self.TopLeft.Y));
end;
Problemem jest to, że IsRectEmpty
który jest nazywany przez Intersect
sprawdza, czy zarówno górna i dolna część rect lub w lewo i na prawo od rect mają te same wartości, a gdy to przechodzi Intersect
ustawia wynik pusty rect.
function IsRectEmpty(const Rect: TRect): Boolean;
begin
Result := (Rect.Right <= Rect.Left) or (Rect.Bottom <= Rect.Top);
end;
Czy jest to oczekiwane zachowanie, a jeśli nie to, co należy zmienić. Rozumiem, że TRects wyklucza dolną i prawą "krawędź", a jeśli tak, to czy nie powinien wyglądać tak?
function TRect.IntersectsWith(const R: TRect): Boolean;
begin
Result := not ((Self.BottomRight.X <= R.TopLeft.X) or
(Self.BottomRight.Y <= R.TopLeft.Y) or
(R.BottomRight.X <= Self.TopLeft.X) or
(R.BottomRight.Y <= Self.TopLeft.Y));
end;
Dzięki, dodałem QC z niektórymi z twoich informacji (http://qc.embarcadero.com/wc/qcmain.aspx?d=127696) – Graymatter
Hmmm ... Dwa puste reks są identyczne, więc oczywiście przecinają się, IMO. Przecięcie to oczywiście pusty rect. Ale 'Rect (0, 0, 100, 200)' i 'Rect (0, 100, 200, 200)' nie powinny się przecinać, IMO, nawet jeśli mają nominalnie wspólny punkt '(0, 100)' (ale nie w rzeczywistości, ponieważ ten punkt w systemie Windows nie jest częścią pierwszego recta). –
@Rudy - Pusty rect to rect, który nie jest. Nie może przecinać się z niczym, nie ma nawet wnętrza/obszaru. –