Skip to content

Commit

Permalink
Add anti-aliasing to the line drawing algorithm
Browse files Browse the repository at this point in the history
  • Loading branch information
bennett-nguyen committed Sep 14, 2024
1 parent 2a0abd6 commit 79f136c
Show file tree
Hide file tree
Showing 2 changed files with 54 additions and 15 deletions.
57 changes: 47 additions & 10 deletions src/app_state/states/rendering.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from typing import Optional, Any
from collections import deque
from math import atan2, cos, degrees, radians, sin

import pygame as pg
from pygame import gfxdraw
Expand Down Expand Up @@ -266,7 +267,7 @@ def _draw_circles(self, node: Node, outline_clr: pg.Color):
theme = self.current_theme
pg.draw.circle(pygame_window.screen, theme.NODE_FILLINGS_CLR, node.coordinates, const.NODE_CIRCLE_RADIUS-const.LINE_THICKNESS)

for depth in range(const.NODE_CIRCLE_RADIUS-const.LINE_THICKNESS, const.NODE_CIRCLE_RADIUS):
for depth in range(const.NODE_CIRCLE_RADIUS-const.CIRCLE_OUTLINE_THICKNESS, const.NODE_CIRCLE_RADIUS):
gfxdraw.aacircle(pygame_window.screen, *node.coordinates, depth, outline_clr)
gfxdraw.aacircle(pygame_window.screen, *node.coordinates, depth, outline_clr)

Expand All @@ -285,22 +286,21 @@ def _draw_lines(self, node: Node):
if node.is_leaf():
return

pg.draw.line(
pygame_window.screen,
theme.LINE_CLR,
self._draw_antialiased_thick_line(
node.coordinates,
node.left.coordinates,
const.LINE_THICKNESS,
)

pg.draw.line(
pygame_window.screen,
theme.LINE_CLR,
const.LINE_THICKNESS
)

self._draw_antialiased_thick_line(
node.coordinates,
node.right.coordinates,
const.LINE_THICKNESS,
theme.LINE_CLR,
const.LINE_THICKNESS
)


def _draw_node_data(self, node: Node, display_data_clr: pg.Color):
"""
Displays the data value of the specified node in the user interface. This method
Expand All @@ -315,3 +315,40 @@ def _draw_node_data(self, node: Node, display_data_clr: pg.Color):
node_display_data, node_display_data_rect = self.render_text(self.node_data_font, f"{node.data}", display_data_clr)
node_display_data_rect.center = node.coordinates
pygame_window.screen.blit(node_display_data, node_display_data_rect)

def _draw_antialiased_thick_line(self, point_start: tuple[int, int], point_end: tuple[int, int], line_color: pg.Color, line_thickness: float):
"""
Draw an antialiased polygon that resembles a line.
The idea behind this algorithm can be found here: https://stackoverflow.com/a/30599392
This function implements the more readable solution that's also in the same post: https://stackoverflow.com/a/67509308
Summary:
- Define the center point of the polygon from the starting point and ending point of the line.
- Find the slope of the line.
- Using the slope and the shape parameters to calculate the coordinates of the box ends.
- Draw a polygon using those coordinates and finally fill it.
Args:
point_start (tuple[int, int]): The starting point of the line
point_end (tuple[int, int]): The ending point of the line
line_color (pg.Color): The color of the line
line_thickness (float): The thickness of the line
"""

slope = degrees(atan2(point_start[1] - point_end[1], point_start[0] - point_end[0]))

vertices = [
self._move(slope-90, line_thickness, point_start),
self._move(slope+90, line_thickness, point_start),
self._move(slope+90, line_thickness, point_end),
self._move(slope-90, line_thickness, point_end)
]

gfxdraw.aapolygon(pygame_window.screen, vertices, line_color)
gfxdraw.filled_polygon(pygame_window.screen, vertices, line_color)

def _move(self, rotation: float, steps: int, position: tuple[int, int]) -> tuple[float, float]:
xPosition = cos(radians(rotation)) * steps + position[0]
yPosition = sin(radians(rotation)) * steps + position[1]
return (xPosition, yPosition)
12 changes: 7 additions & 5 deletions src/utils/constants.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
from src.utils import kay_typing

# - General
DEFAULT_SCREEN_OCCUPATION_PERCENTAGE: float = 80 / 100

ACTIVE_FPS: int = 48
IDLE_FPS: int = 1
VERSION: str = "0.8.0-prealpha"
VERSION: str = "0.8.1-prealpha"

# -- Array viewer and hovered node viewer's constants
MAX_X_PER_LINE: int = 500
Expand All @@ -20,16 +21,17 @@

# - RT's algo constants
# -- Scalar
SCALE: int = 200
VERTICAL_SCALE: int = 150
SCALE: int = 240
VERTICAL_SCALE: int = 160

# -- Offset
DEPTH_OFFSET: float = 1
ROOT_DEPTH: int = 0

# -- Shape's properties
LINE_THICKNESS: int = 4
NODE_CIRCLE_RADIUS: int = 40
CIRCLE_OUTLINE_THICKNESS: int = 4
LINE_THICKNESS: float = CIRCLE_OUTLINE_THICKNESS / 2.0
NODE_CIRCLE_RADIUS: int = 45

# -- Distance between nodes and subtrees
NODE_DISTANCE: float = 0.7
Expand Down

0 comments on commit 79f136c

Please sign in to comment.