pygame-community / pygame-ce

🐍🎮 pygame - Community Edition is a FOSS Python library for multimedia applications (like games). Built on top of the excellent SDL library.
https://pyga.me
766 stars 120 forks source link

Fix aalines overlap #2912

Open mzivic7 opened 3 weeks ago

mzivic7 commented 3 weeks ago

As seen on the picture bellow, there is a problem with draw.aalines. bad This is happening because draw.aalines require each aaline to be drawn 1px shorter (in some cases 2px - see bellow), so two connected draw_aaline are not overlapping.

What is changed and how it works: draw_aaline has 2 endpoints that needs to be disabled for draw.aalines only: First endpoint is disabled when it is first line when aalines is open. And when `from_x` value is not decimal (if it is, then line is 2px shorter). Second endpoint is disabled when it is last line when aalines is open. As a result of disabling first endpoint, now there is special case where 1px is missing between two lines, where one is steep and other line is not. This is detected in draw.aalines. And resolved in draw_aaline by drawing one px at place where end point should be. At what end point will be drawn pixel: first point when line is not inverted, second point when line is inverted.

Here are some results (might need to zoom to see the difference better): results Top line is modified. Middle line is original. Bottom line is difference.

Code used to draw this: ```py import pygame import numpy as np def curve_points(a, b, pea, t): sin_p = np.sin(pea) cos_p = np.cos(pea) x = a * np.cos(t) y = b * np.sin(t) x_rot = x * cos_p - y * sin_p y_rot = y * cos_p + x * sin_p return np.stack((x_rot, y_rot), axis=1) points1 = [[200.1, 300], [220.1, 300.1], [240.1, 300.2], [260.1, 300.4], [280.1, 300.6], [300.1, 300.8]] points2 = [[400.7, 300.1], [420.3, 300.5], [440.6, 305.1], [460.4, 315.2], [480.2, 330.5], [500.1, 360.7], [550.4, 360.5], [550.8, 400.2]] points_num = 150 t = np.linspace(-np.pi, np.pi, points_num) points3 = curve_points(250, 150, 0.3, t) + np.array([350, 350]) pygame.init() screen = pygame.display.set_mode((700, 700)) clock = pygame.time.Clock() run = True while run: for event in pygame.event.get(): if event.type == pygame.QUIT: run = False screen.fill("black") pygame.draw.aalines(screen, (150, 150, 150), False, points1) pygame.draw.aalines(screen, (150, 150, 150), False, points2) pygame.draw.aalines(screen, (150, 150, 150), False, points3) pygame.display.flip() clock.tick(60) pygame.quit() ``` Results were merged for comparison in gimp.