2010-06-30 3 views
11

presque chaque fois que j'utilise Graphics.DrawRectangle ou Graphics.FillRectangle (les versions int) il me semble manquer les pixels sur les bordures droite et inférieure du rectangle que je veux dessiner.Comportement des pixels de FillRectangle et DrawRectangle

Quelle est la définition exacte dont les pixels se remplir par

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

et

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

et est-il une explication logique à cela? (Donc je peux enfin rappeler le comportement :) ...)

EDIT:

En utilisant l'application merveilleuse Try GDI+ Oleg Zhuk, j'ai pu trouver une différence curieuse entre FillRectangle et DrawRectangle:

FillRectangle(brush,0,0,1,1) dessine un seul point à (0,0) qui est en quelque sorte compréhensible (c'est un rectangle avec une largeur et une hauteur après tout). D'autre part, dessine un petit rectangle de 2 x 2 pixels.

Le même comportement est montré pour d'autres combinaisons de largeur/hauteur, DrawRectangle étend toujours un pixel plus à gauche et la partie inférieure (qui est un peu comme gênant lors de l'utilisation de la propriété ClientRectangle pour dessiner un cadre autour d'un témoin)

Ma première question résolue (comment à se comporter ...) il reste encore le deuxième: Pourquoi se comportent-ils de cette façon?

+0

Désolé pour ma réponse supprimée - il était en retard (par mon horloge biologique) et je ne lisais pas correctement, juste sauter aux conclusions. – Steve314

Répondre

7

Ces méthodes fonctionnent correctement, il suffit de prendre en compte les effets anti-aliasing et arrondi.

D'abord, allumer l'anti-aliasing pour tout voir (non seulement de résultat arrondi):

graphics.SmoothingMode = SmoothingMode.AntiAlias; 

maintenant FillRectangle (10,10,10,10) produira résultat flou et DrawRectangle (10,10, 10,10) sera net. Le résultat flou signifie que vous avez coordonnées de pixel hors réseau.Si vous devez appeler:

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

d'aligner le coin supérieur gauche du rectangle sur la grille. Le DrawRectangle est net car il utilise un stylo de largeur 1.0. Ainsi, la ligne commence au centre du pixel et passe à 0,5 pixel dans les deux directions, remplissant ainsi exactement 1 pixel.

On notera que la largeur et la hauteur sont calculées de cette façon:

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

Notez que 19,5 est une droite/bas de coordonnées du rectangle également alignée sur la grille et le résultat est un nombre entier.

Vous pouvez utiliser différentes formules:

width2 = (right - left + 1) 

Mais cela vaut le coordonnées arrondies que, puisque la plus petite unité est de 1 pixel. Lorsque vous travaillez avec GDI + qui utilise l'anti-aliasing, sachez que le point a une taille nulle et se trouve au centre du pixel (ce n'est pas le pixel entier).

+4

L'antialiasing n'a pas d'importance. La vraie raison est décrite ici: http://social.msdn.microsoft.com/Forums/en-US/a170efaf-829a-4cf1-b854-351938be24ae/drawrectangle-method-creates-oversize-rectangle?forum=vblanguage – Spook

+0

Antialiasing Est-ce important? Cela a complètement ouvert mes yeux. En outre, cela m'a fait réaliser que gonfler le rectangle passé à FillRectangle par .5px est souvent ce que je veux faire. La raison mentionnée sur les forums est juste une conséquence. Avec l'anti-aliasing, le pixel sur le chemin qui serait dessiné deux fois serait dessiné deux fois à 50% d'opacité rendant ainsi toujours le bon résultat. –

1

Le rectangle dans les deux méthodes graphiques de votre question est délimité par (x, y) en haut à gauche et (x + width - 1, y + height - 1) en bas à droite. C'est une conséquence de spécifier la largeur et la hauteur, plutôt que le point inférieur droit. Lorsque vous calculez la largeur et la hauteur à partir de deux points, n'oubliez pas d'inclure le pixel d'origine en ajoutant 1 à la différence. Par exemple, disons que vous voulez remplir un rectangle du point (5, 5) au point (10, 20). La largeur du rectangle est 6, pas 5. La hauteur du rectangle est 16, pas 15.

+1

Merci, mais cela ne semble pas être toute la vérité: DrawRectangle et FillRectangle se comportent différemment: Lorsque vous utilisez FillRectangle (pinceau, 0,0,1,1), un seul point est dessiné, DrawRectangle (stylo, 0,0,1, 1) dessine un rectangle de 2 par 2 px. Ceci est quelque peu étrange (imo) et je me demande, s'il y a une raison plus profonde pour ce comportement :) ... – MartinStettner

+0

Pourrait être une bizarrerie dans les routines de dessin. Je viens d'expliquer les maths derrière un rectangle. –

-1

La différence de comportement est due au fait quelque peu contre-intuitif que ces deux algorithmes font des choses complètement différentes. DrawRectangle dessine quatre lignes ayant la forme d'une boîte. FillRectangle produit un bloc W * H rempli de pixels. De cela, il est facile de voir la raison de la différence de comportement. À savoir la fausseté de l'hypothèse de similitude. Dessiner quatre lignes est assez différent de la production d'un amas de pixels en forme de boîte.

+1

Cela ne répond pas à la question. Essayez d'afficher ce problème à partir de l'affichage de l'utilisateur au lieu de celui du développeur. L'aide à la méthode Graphics.DrawRectangle indique que les troisième et quatrième paramètres sont la largeur et la hauteur de la forme géométrique résultante. http://msdn.microsoft.com/fr-fr/library/x6hb4eba.aspx – truthseeker

+0

Le point réside dans le fait que les arêtes mathématiques traversent le centre des pixels comme l'indique correctement le Libor. – truthseeker

Questions connexes