2010-06-30 3 views
11

fast jedes Mal, wenn ich Graphics.DrawRectangle oder Graphics.FillRectangle (die int Versionen) verwende Ich vermisse die Pixel am rechten und unteren Rand des Rechtecks, das ich zeichnen möchte.Pixel Verhalten von FillRectangle und DrawRectangle

Was ist die genaue Definition, welche durch

Graphics.FillRectangle(brush,x,y,width,height) 

gefüllt erhalten Pixel und

Graphics.DrawRectangle(pen,x,y,width,height) // pen is one pixel width, i.e. width=0f 

und gibt es eine logische Erklärung dafür? (So ​​kann ich erinnere mich endlich das Verhalten :) ...)

EDIT:

Mit Oleg Zhuk des wunderbaren Try GDI+ Anwendung, konnte ich einen merkwürdigen Unterschied zwischen FillRectangle und DrawRectangle finden:

FillRectangle(brush,0,0,1,1) Zeichnet einen einzelnen Punkt bei (0,0), was irgendwie verständlich ist (es ist ein Rechteck mit Breite und Höhe).

DrawRectangle(pen,0,0,1,1) auf der anderen Seite zeichnet ein kleines 2 mal 2 Pixel Rechteck.

Das gleiche Verhalten für andere Breiten-/Höhenkombinationen gezeigt ist, erstreckt sich DrawRectangle immer ein Pixel mehr nach links und nach unten (die ein wenig ärgerlich zB, wenn die ClientRectangle Eigenschaft mit einem Rahmen um eine Kontrolle zu zeichnen)

Meine erste Frage gelöst (wie zu ihnen verhalten ...) gibt es immer noch die zweite: Warum benehmen sie sich so?

+0

Entschuldigung wegen meiner gelöschten Antwort - es war spät (durch meine Körperuhr) und ich habe nicht richtig gelesen, nur voreilige Schlüsse gezogen. – Steve314

Antwort

7

Diese Methoden funktionieren ordnungsgemäß, Sie müssen nur Auswirkungen von Anti-Aliasing und Rundung berücksichtigen.

Schalten Sie dazu zunächst das Anti-Aliasing alles (nicht nur gerundete Ergebnis) zu sehen:

graphics.SmoothingMode = SmoothingMode.AntiAlias; 

Jetzt FillRectangle (10,10,10,10) wird verschwommen Ergebnis und DrawRectangle (10,10 produzieren, 10,10) wird scharf sein.

Das verschwommene Ergebnis bedeutet, dass Sie Pixelkoordinaten netzunabhängig haben.Wenn Sie anrufen müssen:

graphics.FillRectangle(9.5f, 9.5f, 10, 10); 

, um die obere linke Ecke des Rechtecks ​​auf dem Raster auszurichten.

Der DrawRectangle ist scharf, weil er einen Stift der Breite 1,0 verwendet. Die Linie beginnt also in der Mitte des Pixels und bewegt sich in beiden Richtungen um 0,5 Pixel und füllt damit genau 1 Pixel.

anzumerken, dass Höhe und Breite wird auf diese Weise berechnet:

width = (right - left) = 19.5 - 9.5 = 10 
height = (bottom - top) = ... 

Hinweis, dass 19.5 ein rechts/unten auch auf dem Gitter ausgerichtet Koordinate des Rechtecks ​​und das Ergebnis ist eine ganze Zahl.

können Sie verschiedene Formel:

width2 = (right - left + 1) 

Dies gilt aber auf gerundeten Koordinaten nur, da die kleinste Einheit 1 Pixel ist. Wenn Sie mit GDI + arbeiten, das Anti-Aliasing verwendet, beachten Sie, dass der Punkt null Größe hat und in der Mitte des Pixels liegt (es ist nicht das ganze Pixel).

+4

Antialiasing spielt keine Rolle. Der wahre Grund wird hier beschrieben: http://social.msdn.microsoft.com/Forums/en-US/a170efaf-829a-4cf1-b854-351938be24ae/drawrectangle-method-creates-oversize-rectangle?forum=vblanguage – Spook

+0

Antialiasing ist wichtig. Das hat meine Augen total geöffnet. Außerdem wurde mir klar, dass das Auffüllen des Rechtecks, das an FillRectangle mit 0,5 px übergeben wurde, oft das ist, was ich tun möchte. Der Grund, der in den Foren erwähnt wird, ist nur Konsequenz. Bei Anti-Aliasing würde das Pixel auf dem Pfad, das zweimal gezeichnet würde, zweimal mit einer Opazität von 50% gezeichnet werden, wodurch immer noch das korrekte Ergebnis erzielt wird. –

1

Das Rechteck in beiden Grafikmethoden in Ihrer Frage wird durch (x, y) oben links und (x + width - 1, y + height - 1) unten rechts begrenzt. Dies ist eine Konsequenz der Angabe von Breite und Höhe anstelle des unteren rechten Punkts.

Wenn Sie die Breite und Höhe von zwei Punkten berechnen, müssen Sie daran denken, den Ursprungspixel durch Hinzufügen von 1 zur Differenz hinzuzufügen.

Angenommen, Sie möchten ein Rechteck von Punkt (5, 5) bis Punkt (10, 20) füllen. Die Breite des Rechtecks ​​ist 6, nicht 5. Die Höhe des Rechtecks ​​ist 16, nicht 15.

+1

Danke, aber das scheint nicht die ganze Wahrheit zu sein: DrawRectangle und FillRectangle verhalten sich unterschiedlich: Bei Verwendung von FillRectangle (Pinsel, 0,0,1,1) wird ein einzelner Punkt gezeichnet, DrawRectangle (Stift, 0,0,1, 1) zeichnet ein Rechteck von 2 mal 2 px. Das ist etwas seltsam (imo) und ich frage mich, ob es einen tieferen Grund für dieses Verhalten gibt :) ... – MartinStettner

+0

Könnte in den Zeichenroutinen eine Eigenart sein. Ich habe gerade die Mathematik hinter einem Rechteck erklärt. –

-1

Der Unterschied im Verhalten ist auf die etwas entgegengesetzte Tatsache zurückzuführen, dass diese beiden Algorithmen völlig unterschiedliche Dinge tun.

DrawRectangle zeichnet vier Linien in Form einer Box. FillRectangle erzeugt eine W * H-Gruppe von aufgefüllten Pixeln. Aus diesem Grund ist es leicht, den Grund für den Unterschied im Verhalten zu sehen. Nämlich die Unrichtigkeit der Ähnlichkeitsannahme. Das Zeichnen von vier Zeilen ist ganz anders als das Erzeugen eines kastenartigen Klumpens von Pixeln.

+1

Dies beantwortet die Frage nicht. Versuchen Sie, dieses Problem in der Benutzeransicht und nicht in der Entwickleransicht anzuzeigen. Hilfe zur Graphics.DrawRectangle-Methode besagt, dass der dritte und der vierte Parameter die Breite und Höhe der resultierenden geometrischen Form sind. http://msdn.microsoft.com/en-us/library/x6hb4eba.aspx – truthseeker

+0

Punkt liegt in der Tatsache, dass mathematische Kanten durch die Mitte der Pixel gehen, wie Libor richtig darauf hingewiesen. – truthseeker