Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Programmieren allgemein (https://www.delphipraxis.net/40-programmieren-allgemein/)
-   -   Bug: IntersectRect liefert falsche Resultate (https://www.delphipraxis.net/189059-bug-intersectrect-liefert-falsche-resultate.html)

Amateurprofi 29. Apr 2016 09:11


Bug: IntersectRect liefert falsche Resultate
 
Ich hatte kürzlich in einem Programm unerwartete Fehler registriert und dann festgestellt, dass die Funktionen IntersectRect und Rect.IntersectsWith, beide in System.Types, falsche Resultate liefern, wenn die beiden Rechtecke direkt aneinander grenzen.
Beide Funktionen betrachten Rect.Right und Rect.Bottom als innerhalb der Fläche des Rechtecks.
Tatsächlich liegen Rect.Right und Rect.Bottom außerhalb der Fläche des Rechtecks.
Oder mache ich da einen Denkfehler?

Beschreibung aus OH
TRect definiert ein Rechteck.

TRect repräsentiert die Abmessungen eines Rechtecks. Die Koordinaten werden entweder als vier einzelne Integerwerte angegeben, die den linken, oberen, rechten und unteren Rand definieren, oder als zwei Punkte, die die Position der linken, oberen sowie der rechten, unteren Ecke angeben.

Normalerweise repräsentieren TRect-Werte Pixel-Positionen, wobei der Ursprung des Koordinatensystems in der oberen, linken Ecke des Bildschirms (Bildschirmkoordinaten) oder in der oberen, linken Ecke des Client-Bereichs (Client-Koordinaten) eines Steuerelements liegt. Wenn ein TRect-Wert ein Rechteck auf dem Bildschirm darstellt, liegen die oberen und die linken Ecken konventionsgemäß innerhalb des Rechtecks und die unteren und rechten Ecken außerhalb des Rechtecks. Durch diese Konvention kann die Breite des Rechtecks mit Right – Left und die Höhe mit Bottom – Top ermittelt werden.

Delphi-Quellcode:
function IntersectRect(const Rect1, Rect2: TRect): Boolean;
begin
  Result := (Rect1.Left <= Rect2.Right) and
            (Rect1.Right >= Rect2.Left) and
            (Rect1.Top <= Rect2.Bottom) and
            (Rect1.Bottom >= Rect2.Top);
end;
Delphi-Quellcode:
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;
Korrekt wäre es m.E. zum Beispiel so
Delphi-Quellcode:
FUNCTION MyIntersectRect(const A,B:TRect):Boolean;
begin
  Result:=(A.Left<B.Right) and (A.Right>B.Left) and (A.Top<B.Bottom) and (A.Bottom>B.Top);
end;

gammatester 29. Apr 2016 09:22

AW: Bug: IntersectRect liefert falsche Resultate
 
Zitat:

Zitat von Amateurprofi (Beitrag 1337037)
Korrekt wäre es m.E. zum Beispiel so
Delphi-Quellcode:
FUNCTION MyIntersectRect(const A,B:TRect):Boolean;
begin
  Result:=(A.Left<B.Right) and (A.Right>B.Left) and (A.Top<B.Bottom) and (A.Bottom>B.Top);
end;

Das kann nicht richtig sein. Wenn z.B. (A.Left=B.Right) ist, schneiden sich die Rechtecke.

Bei Dir wird false geliefert: Irgendwo müssen auch <= bzw >= im Vergleich auftauchen. Im Original wird das durch das not erschlagen.

Amateurprofi 29. Apr 2016 12:03

AW: Bug: IntersectRect liefert falsche Resultate
 
Liste der Anhänge anzeigen (Anzahl: 1)
Zitat:

Zitat von gammatester (Beitrag 1337040)
Zitat:

Zitat von Amateurprofi (Beitrag 1337037)
Korrekt wäre es m.E. zum Beispiel so
Delphi-Quellcode:
FUNCTION MyIntersectRect(const A,B:TRect):Boolean;
begin
  Result:=(A.Left<B.Right) and (A.Right>B.Left) and (A.Top<B.Bottom) and (A.Bottom>B.Top);
end;

Das kann nicht richtig sein. Wenn z.B. (A.Left=B.Right) ist, schneiden sich die Rechtecke.

Bei Dir wird false geliefert: Irgendwo müssen auch <= bzw >= im Vergleich auftauchen. Im Original wird das durch das not erschlagen.

Nein, gerade das ist ja der Fehler in den Funktionen.
Im anhängenden Bild ist
A=Rect(35,5,65,35)
B=Rect(5,5,35,35)
A.Left = B.Right
Und wo überschneiden sich die Rechtecke?
Bedenke: B.Right liegt außerhalb der Fläche des Rechtecks B.
So ist nun einmal TRect definiert.
Left und Top liegen innerhalb der Fläche.
Right und Bottom liegen außerhalb der Fläche.

stahli 29. Apr 2016 12:41

AW: Bug: IntersectRect liefert falsche Resultate
 
Ich denke, dass Du Recht hast (und frage mich, warum mir das nicht aufgefallen war - vielleicht ist das in XE3 schon gefixt? Ich schaue das heute Abend mal nach.)

Uwe Raabe 29. Apr 2016 13:14

AW: Bug: IntersectRect liefert falsche Resultate
 
Zitat:

Zitat von Amateurprofi (Beitrag 1337037)
Korrekt wäre es m.E. zum Beispiel so
Delphi-Quellcode:
FUNCTION MyIntersectRect(const A,B:TRect):Boolean;
begin
  Result:=(A.Left<B.Right) and (A.Right>B.Left) and (A.Top<B.Bottom) and (A.Bottom>B.Top);
end;

Das entspricht auch der aktuellen Implementierung in Delphi 10 Seattle und Delphi 10.1 Berlin (ältere habe ich gerade nicht zur Hand).

gammatester 29. Apr 2016 13:32

AW: Bug: IntersectRect liefert falsche Resultate
 
Zitat:

Zitat von Amateurprofi (Beitrag 1337076)
Nein, gerade das ist ja der Fehler in den Funktionen.

Beispiel: Nimm ein Rechteck, teile es senkrecht in der Mitte, nenne den linken Teil B, den rechten A. Dann haben A und B eine Seite gemeinsam und damit einen nicht-leeren Durchschnitt. Es ist B.Right=A.Left, also gerade nicht B.Right < A.Left und damit der gesamte Ausdruck mit and falsch und Deine Funktion liefert ein falsches Ergebnis.

stahli 29. Apr 2016 14:05

AW: Bug: IntersectRect liefert falsche Resultate
 
Liste der Anhänge anzeigen (Anzahl: 1)
Das gelbe Rect1 ist Left=2 und Right=5.
Der Bereich ist dann real 2..4.

Das blaue Rect2 ist dann Left=5 und Right=8.
Der Bereich ist dann real 5..7.

Die beiden Rects grenzen nur aneinander, aber es gibt keine Überschneidung.

Dass die Rects Left und Top den realen Wert widerspiegeln und Right und Bottom 1 Pixel weiter außerhalb liegen hat mich auch schon einige graue Haare gekostet (trage jetzt Glatze ;-))

Uwe Raabe 29. Apr 2016 14:25

AW: Bug: IntersectRect liefert falsche Resultate
 
Zitat:

Zitat von gammatester (Beitrag 1337105)
Beispiel: Nimm ein Rechteck, teile es senkrecht in der Mitte, nenne den linken Teil B, den rechten A. Dann haben A und B eine Seite gemeinsam und damit einen nicht-leeren Durchschnitt. Es ist B.Right=A.Left, also gerade nicht B.Right < A.Left und damit der gesamte Ausdruck mit and falsch und Deine Funktion liefert ein falsches Ergebnis.

Die Defintion von
Delphi-Quellcode:
TRect
besagt aber gerade, daß die so geteilten Rechtecke eben nicht eine Seite gemeinsam haben. Die Trennlinie beschreibt zwar die rechte Kante des linken Rechtecks, gehört aber per Definition nicht dazu.

Anders ausgedrückt würde eine Schleife über die X-Werte eines Rechtecks so lauten:
Delphi-Quellcode:
for I := A.Left to A.Right - 1 do


Wie schon erwähnt, ist dies in späteren Delphi-Versionen gefixt.

Amateurprofi 29. Apr 2016 18:00

AW: Bug: IntersectRect liefert falsche Resultate
 
Zitat:

Zitat von gammatester (Beitrag 1337105)
Zitat:

Zitat von Amateurprofi (Beitrag 1337076)
Nein, gerade das ist ja der Fehler in den Funktionen.

Beispiel: Nimm ein Rechteck, teile es senkrecht in der Mitte, nenne den linken Teil B, den rechten A. Dann haben A und B eine Seite gemeinsam und damit einen nicht-leeren Durchschnitt. Es ist B.Right=A.Left, also gerade nicht B.Right < A.Left und damit der gesamte Ausdruck mit and falsch und Deine Funktion liefert ein falsches Ergebnis.

Ich sprach (schrieb) nicht über EIN Rechteck, das wie auch immer durch eine Linie geteilt ist sondern über ZWEI aneinander grenzende Rechtecke.
Bleiben wir trotzdem bei Deinem Beispiel.
Wir haben also ein Rechteck.
Der obere linke Eckpunkt soll bei 5,5 liegen und es soll 60 Pixel breit und 30 Pixel hoch sein.
Nun trennen wir es in der Mitte durch eine senkrechte Linie und nennen den linken Teil B und den rechten Teil A.
Da wir die beiden Rechtecke ja nicht nur denken sondern auch zeichnen wollen, brauchen wir die Koordinaten von A und B.
Wenn wir die haben, zeichnen wir beide Rechtecke mit Canvas.Rectangle, wobei beide Rechtecke einen 1 Pixel breiten Rahmen haben sollen und die Rechtecke und Rahmen sichtbar unterschiedliche Farben haben sollen, damit wir genau sehen wo welches Rechteck beginnt und wo welches endet.
Liefere du bitte die Koordinaten der beiden TRects A und B.

stahli 29. Apr 2016 18:54

AW: Bug: IntersectRect liefert falsche Resultate
 
Wenn man in der Mitte eine Linie zieht und diese beide Rects begrenzt überschneiden sich beide tatsächlich um ein Pixel.
Man muss also das rechte Rect noch um ein Pixel nach rechts verschieben und erhält die gegebene Situation (und in der Mitte eine 2 Pixel breite Linie).

Ich sehe gerade, in XE3 ist die Funktion auch noch falsch und ich hatte auch eine eigene geschrieben. :roteyes:


Alle Zeitangaben in WEZ +1. Es ist jetzt 09:55 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz