pygame.draw.polygon handles x and y direction inconsistently

Issue #234 new
donLorenzo
created an issue

Reported by Florian Krause on the pygame mailing list:

Hi there,

I think I found another bug. When drawing a cross, defined as:

pygame.draw.polygon(screen, [255,0,0], [[11, 0], [11, 9], [20, 9], [20, 11], [11, 11], [11, 20], [9, 20], [9, 11], [0, 11], [0, 9], [9, 9], [9, 0]], 0)

the result will show a cross with 2 pixel thickness in the vertical direction, but 3 pixels thickness in the horizontal direction. Which one is "correct" is probably debatable, but Pygame should at least treat both directions equal, shouldn't it?

note that the simple example:

import pygame
pygame.init()
screen = pygame.display.set_mode((100,100))
pygame.draw.polygon(screen, [255,0,0], [[0, 0], [3, 0], [3, 3], [0, 3]], 0)
pygame.display.update()

yields a 4x4 rect

Comments (6)

  1. donLorenzo reporter

    I guess the first step in resolving this issue is to clarify what the desired behaviour is.

    For example: Should the polygon ([0, 0], [3, 0], [3, 3], [0, 3]) really be a 4x4 square or should it be 3x3 ?

    IMHO it should be 3x3 which would be analogue to how C for-loops or python ranges handle their bounds and the same arguments apply. Mainly, that two polygons sharing an edge should not overlap.

    Any opinions?

  2. Jason Marshall

    If I were designing pygame.draw.polygon, I would make it fill in every point that I pass to it when the width argument is 0. This is what pygame.draw.polygon does when the width argument is 1. So, I would expect the polygon ([0, 0], [3, 0], [3, 3], [0, 3]) to always be 4x4. (The analogy with C for-loops and Python ranges stops making sense to me when I consider polygons that aren't rectangular.)

    However, it is much more important that it draw consistently in both the x direction and the y direction. Whether that polygon is 3x3 or 4x4 is just a personal preference.

    pygame.gfxdraw.filled_polygon draws in the same way as pygame.draw.polygon (with a width argument of 0).

    I made the following little script to play with the polygon functions. It may be useful to somebody.

    import pygame
    import pygame.gfxdraw
    from pygame.locals import *
    
    cross = [[2, 0],
             [4, 0],
             [4, 2],
             [6, 2],
             [6, 4], 
             [4, 4],
             [4, 6],
             [2, 6],
             [2, 4],
             [0, 4],
             [0, 2],
             [2, 2]]
    
    PIXEL_SCALE = 20
    PIXELS_X = max(point[0] for point in cross) + 1
    PIXELS_Y = max(point[1] for point in cross) + 1
    RESOLUTION = (PIXELS_X * PIXEL_SCALE, PIXELS_Y * PIXEL_SCALE)
    SCALED_MID_PIXEL_POINTS = [[PIXEL_SCALE / 2 + PIXEL_SCALE * point[0],
                                PIXEL_SCALE / 2 + (PIXEL_SCALE * point[1])]
                               for point in cross]
    
    def main():
        pygame.display.init()
        screen = pygame.display.set_mode(RESOLUTION)
        draw_surf = pygame.Surface((PIXELS_X, PIXELS_Y))
    
        Clock = pygame.time.Clock()
        running = True
        point_idx = 0
        while running:
    
            screen.fill(Color('black'))
            draw_surf.fill(Color('black'))
    
            # Draw cross
            if point_idx % 2:
                pygame.gfxdraw.filled_polygon(draw_surf, cross, Color('red'))
            else:
                pygame.draw.polygon(draw_surf, Color('red'), cross)
            pygame.transform.scale(draw_surf, RESOLUTION, screen)
    
            # Draw pixel grid 
            for x in range(0, RESOLUTION[0], PIXEL_SCALE):
                pygame.draw.line(screen,
                                 Color('gray'),
                                 [x, 0],
                                 [x, RESOLUTION[1]])
            for y in range(0, RESOLUTION[1], PIXEL_SCALE):
                pygame.draw.line(screen,
                                 Color('gray'),
                                 [0, y],
                                 [RESOLUTION[0], y])
    
            # Highlight points sequentially
            point = cross[point_idx]
            pygame.draw.rect(screen,
                             Color('yellow'),
                             Rect(PIXEL_SCALE / 2 + PIXEL_SCALE * point[0] - 3,
                                  PIXEL_SCALE / 2 + PIXEL_SCALE * point[1] - 3,
                                  8 - 1,
                                  8 - 1),
                             2)
            point_idx += 1
            if point_idx == len(cross):
                point_idx = 0
    
            # Connect the points with a white line        
            pygame.draw.polygon(screen,
                                Color('white'),
                                SCALED_MID_PIXEL_POINTS,
                                2)
    
            # Keys are Space, Tab, and Shift+Tab
            for e in pygame.event.get():
                if e.type == QUIT:
                    running = False
    
            Clock.tick(3)
    
            pygame.display.flip()
    
        pygame.quit()
    
    if __name__ == "__main__":
        main()
    

    polygon_cross.png

  3. Log in to comment