2014-09-19 9 views
9

Spero di essere confuso in qualche modo. Sto ottenendo alcuni comportamenti incoerenti con TRect.Intersect e TRect.IntersectsWith. Ecco un codice che dimostra il problema.TRect.Intersect e TRect.IntersectsWith Incoistenze

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. 

La seconda eccezione viene sollevata. TRect.IntersectsWith indica che i rects si intersecano ma quando chiamo TRect.Intersect per ottenere il nuovo rect intersecato, restituisce un rect vuoto.

Il codice in IntersectsWith (che non è scritto in modo molto chiaro) restituisce true nel secondo caso perché 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; 

Il problema è che IsRectEmpty quale è invocato Intersect verifica se sia nella parte superiore e inferiore del rettangolo o sinistra e destra del rettangolo hanno gli stessi valori e quando passa Intersect imposta il risultato un rect vuoto.

function IsRectEmpty(const Rect: TRect): Boolean; 
begin 
    Result := (Rect.Right <= Rect.Left) or (Rect.Bottom <= Rect.Top); 
end; 

È questo il comportamento previsto e, in caso contrario, quello che dovrebbe essere modificato. La mia comprensione è che i TRects escludono i "bordi" inferiori e quelli giusti e, in tal caso, non dovrebbe essere lo TRect.IntersectsWith simile a questo?

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; 

risposta

6

È un bug; questo non può essere il comportamento previsto. Nell'implementazione corrente, RTL ritiene che due intersezioni vuote possano intersecare (ad esempio (0,0,0,0), (0,0,0,0) o un rect non vuoto con uno vuoto), il che non ha alcun senso.

Assert(Rect(0, 0, 0, 0).IntersectsWith(Rect(0, 0, 0, 0))); 

L'affermazione di cui sopra non ha esito negativo.

Inoltre, non funziona in conformità con Windows API. La seguente asserzione fallisce: winapi pensa che (0,0,200,100) e (0,100,200,200) non si intersecano.

Assert(winapi.windows.IntersectRect(OutRect, Rect(0,0,200,100), Rect(0,100,200,200))); 

Il sovraccarico di System.Types.IntersectRect() che restituisce un valore booleano è ugualmente rotto.

+0

Grazie, ho aggiunto un controllo di qualità con alcune delle tue informazioni (http://qc.embarcadero.com/wc/qcmain.aspx?d=127696) – Graymatter

+0

Hmmm ... Due recs vuoti sono identici, quindi ovviamente si intersecano, IMO. L'intersezione è, ovviamente, il rect vuoto. Ma 'Rect (0, 0, 100, 200)' e 'Rect (0, 100, 200, 200)' non dovrebbero intersecare, IMO, anche se, nominalmente, hanno il punto '(0, 100)' in comune (ma non in realtà, poiché quel punto è, in Windows, non parte del primo rect). –

+0

@Rudy - Un rect vuoto è un rect che non lo è. Non può intersecare nulla, non ha nemmeno un interno/area. –