AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Programmieren allgemein Bug: IntersectRect liefert falsche Resultate
Thema durchsuchen
Ansicht
Themen-Optionen

Bug: IntersectRect liefert falsche Resultate

Ein Thema von Amateurprofi · begonnen am 29. Apr 2016 · letzter Beitrag vom 30. Apr 2016
Antwort Antwort
Seite 1 von 2  1 2      
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.064 Beiträge
 
Delphi XE2 Professional
 
#1

Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 10:11
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;
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#2

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 10:22
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.
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.064 Beiträge
 
Delphi XE2 Professional
 
#3

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 13:03
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.
Angehängte Grafiken
 
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli
Online

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#4

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 13:41
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.)
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#5

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 14:14
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).
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
gammatester

Registriert seit: 6. Dez 2005
999 Beiträge
 
#6

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 14:32
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.

Geändert von gammatester (29. Apr 2016 um 14:34 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli
Online

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#7

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 15:05
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 )
Miniaturansicht angehängter Grafiken
ir.png  
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)

Geändert von stahli (29. Apr 2016 um 15:30 Uhr)
  Mit Zitat antworten Zitat
Benutzerbild von Uwe Raabe
Uwe Raabe

Registriert seit: 20. Jan 2006
Ort: Lübbecke
11.453 Beiträge
 
Delphi 12 Athens
 
#8

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 15:25
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 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:
for I := A.Left to A.Right - 1 do

Wie schon erwähnt, ist dies in späteren Delphi-Versionen gefixt.
Uwe Raabe
Certified Delphi Master Developer
Embarcadero MVP
Blog: The Art of Delphi Programming
  Mit Zitat antworten Zitat
Amateurprofi

Registriert seit: 17. Nov 2005
Ort: Hamburg
1.064 Beiträge
 
Delphi XE2 Professional
 
#9

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 19:00
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.
Gruß, Klaus
Die Titanic wurde von Profis gebaut,
die Arche Noah von einem Amateur.
... Und dieser Beitrag vom Amateurprofi....
  Mit Zitat antworten Zitat
Benutzerbild von stahli
stahli
Online

Registriert seit: 26. Nov 2003
Ort: Halle/Saale
4.343 Beiträge
 
Delphi 11 Alexandria
 
#10

AW: Bug: IntersectRect liefert falsche Resultate

  Alt 29. Apr 2016, 19:54
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.
Stahli
http://www.StahliSoft.de
---
"Jetzt muss ich seh´n, dass ich kein Denkfehler mach...!?" Dittsche (2004)
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 1 von 2  1 2      


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:36 Uhr.
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