The pygame drawing functions leave pixel-wide gaps. Why?
Question: After converting a piece of code (that animates a pattern of rectangles) from
Java to Python, I noticed that the animation that the code produced seemed
quite glitchy. I managed to reproduce the problem with a minimal example as
follows:

    
    
    import pygame
    SIZE = 200
    pygame.init()
    DISPLAYSURF = pygame.display.set_mode((SIZE, SIZE))
    D = 70.9
    xT = 0.3
    yT = 0
    #pygame.draw.rect(DISPLAYSURF, (255,0,0),     (0, 0, SIZE, SIZE))
    pygame.draw.rect(DISPLAYSURF, (255,255,255), (xT,   yT,   D, D))
    pygame.draw.rect(DISPLAYSURF, (255,255,255), (xT+D, yT+D, D, D))
    pygame.draw.rect(DISPLAYSURF, (0,0,0),       (xT,   yT+D, D, D))
    pygame.draw.rect(DISPLAYSURF, (0,0,0),       (xT+D, yT,   D, D))
    pygame.display.update()
    

This code generates the following image:

![](http://i.imgur.com/Qhuk4Ne.png)

Notice that the squares don't line up perfectly in the middle. Uncommenting
the commented line in the code above results in the following image, which
serves to illuminate the problem further:

![](http://i.imgur.com/jtIcO1t.png)

It seems that there are pixel-wide gaps in the black and white pattern, even
though it can be seen in the code (by the data that is passed in the calls to
pygame.draw.rect()) that this shouldn't be the case. What is the reason for
this behaviour, and how can I fix it?

(This didn't happen in Java, [here](http://pastebin.com/52PuNjEr) is a piece
of Java code corresponding to the Python code above).


Answer: Looking at the rendered picture in an image editor, the pixel distances can be
confirmed as such:

![Picture with measurements](http://i.stack.imgur.com/5gJKa.png)

Expanding the function calls (i.e. performing the additions manually), one can
see that the input arguments to draw the white rectangles are of the form

    
    
    pygame.draw.rect(DISPLAYSURF, (255,255,255), ( 0.3,    0, 70.9, 70.9))
    pygame.draw.rect(DISPLAYSURF, (255,255,255), (71.2, 70.9, 70.9, 70.9))
    

Since fractions of pixels do not make sense screen-wise, the input must be
discretized in some way. Pygame (or SDL, as mentioned in the comments to the
question) seems to choose truncating, which in practice transforms the drawing
commands to:

    
    
    pygame.draw.rect(DISPLAYSURF, (255,255,255), ( 0,  0, 70, 70))
    pygame.draw.rect(DISPLAYSURF, (255,255,255), (71, 70, 70, 70))
    

which corresponds to the dimensions in the rendered image. If AWT draws it
differently, my guess is that it uses rounding (of some sort) instead of
truncating. This could be investigated by trying different rendering inputs,
or by digging in the documentation.

If one wants pixel perfect rendering, using floating points as input is not
well defined. If one keeps to the integers, the result should be independent
of renderer, though.

* * *

**EDIT** : I expand a bit if anyone else finds this, since I couldn't find
much info on this behavior apart from the source code.

The function call in question takes the following input arguments
([documentation](http://www.pygame.org/docs/ref/draw.html#pygame.draw.rect)):

    
    
    pygame.draw.rect(Surface, color, Rect, width=0)
    

where `Rect` is a specific object defined by a top-left coordinate, a width
and a height. By design it only handles integer attributes, since it is meant
as a low-level "this is what you see on the screen" data type. The data type
handles floats by truncating:

    
    
    >>> import pygame
    >>> r = pygame.Rect((1, 1, 8, 12))
    >>> r.bottomright
    (9, 13)
    >>> r.bottomright = (9.9, 13.5)
    >>> r.bottomright
    (9, 13)
    >>> r.bottomright = (11.9, 13.5)
    >>> r.bottomright
    (11, 13)
    

i.e., a regular `(int)` cast is done.

The `Rect` object is not meant as a "store the coordinates for my sprite"
object, but as a "this is what the screen will represent" object. Floating
points are certainly useful for the former purpose, and the designer would
probably want to keep an internal list of floats to store this information.
Otherwise, incrementing a screen position by e.g. `r.left += 0.8` (where `r`
is the `Rect` object) would never move `r` at all.

The problem in the question comes from (quite reasonably) assuming that the
right `x` coordinate of the rectangle will at least be calculated as something
like `x₂ = int(x₁ + width)`, but since the function call implicitly transforms
the input tuple to a `Rect` object before proceeding, and since `Rect` will
truncate its input arguments, it will instead calculate it as `x₂ = int(x₁) +
int(width)`, which is not always the same for float input.

To create a `Rect` using rounding rules, one could e.g. define a wrapper like:

    
    
    def rect_round(x1, y1, w, h):
        """Returns pygame.Rect object after applying sane rounding rules.
    
        Args:
            x1, y1, w, h:
                (x1, y1) is the top-left coordinate of the rectangle,
                w is width,
                h is height.
    
        Returns:
            pygame.Rect object.
        """
        r_x1 = round(x1)
        r_y1 = round(y1)
        r_w = round(x1 - r_x1 + w)
        r_h = round(y1 - r_y1 + h)
        return pygame.Rect(map(int, (r_x1, r_y1, r_w, r_h)))
    

(or modified for other rounding rules) and then call the draw function as e.g.

    
    
    pygame.draw.rect(DISPLAYSURF, (255,255,255), rect_round(71.2, 70.9, 70.9, 70.9))
    

One will never bypass the fact that the pixel by definition is the smallest
addressable unit on the screen, though, so this solution might also have its
quirks.

* * *

Related thread on the Pygame mailing list from 2005: [Suggestion: make Rect
use float
coordinates](http://osdir.com/ml/python.pygame/2005-04/msg00029.html)

