How Can I Make a Thicker Bezier in Pygame?

Question:

I’m building a specialized node editor in Pygame. Each node will be connected with a bezier curve. This curve is built by clicking on a node first. A bezier is drawn between the mouse cursor and the node and once you click on a second node, the bezier line is fixed. My code can already draw the curve and follow the mouse cursor. My problem is that the curve is too thin. Does anyone know of a way to easily specify width in pygame.gfxdraw.bezier? Also, I have no idea what the argument "6" corresponds to; I only know the code won’t function without it.

# This draws the bezier curve for the node editor
x, y = pygame.mouse.get_pos()
b_points = [(380,390),(410,385),(425,405), (425, y), (x, y)]
pygame.gfxdraw.bezier(screen, b_points, 6, blue)
Asked By: user1932489

||

Answers:

Simple answer: You cant’t, at least not with pygame.gfxdraw
or pygame.draw. You have to do it yourself.
Compute points along the curve and connect them with pygame.draw.lines.

See Finding a Point on a Bézier Curve: De Casteljau’s Algorithm and create a function that draw a bezier curve piont, by point:

import pygame

def ptOnCurve(b, t):
    q = b.copy()
    for k in range(1, len(b)):
        for i in range(len(b) - k):
            q[i] = (1-t) * q[i][0] + t * q[i+1][0], (1-t) * q[i][1] + t * q[i+1][1]
    return round(q[0][0]), round(q[0][1])

def bezier(surf, b, samples, color, thickness):
    pts = [ptOnCurve(b, i/samples) for i in range(samples+1)]
    pygame.draw.lines(surf, color, False, pts, thickness)

Minimal example:

import pygame, pygame.gfxdraw

def ptOnCurve(b, t):
    q = b.copy()
    for k in range(1, len(b)):
        for i in range(len(b) - k):
            q[i] = (1-t) * q[i][0] + t * q[i+1][0], (1-t) * q[i][1] + t * q[i+1][1]
    return round(q[0][0]), round(q[0][1])

def bezier(surf, b, samples, color, thickness):
    pts = [ptOnCurve(b, i/samples) for i in range(samples+1)]
    pygame.draw.lines(surf, color, False, pts, thickness)

pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False 

    x, y = pygame.mouse.get_pos()
    b_points = [(380,390), (410,385), (425,405), (425, y), (x, y)]

    screen.fill(0)
    bezier(screen, b_points, 20, (255, 255, 0), 6)
    pygame.draw.lines(screen, (255, 255, 255), False, b_points, 1)
    pygame.gfxdraw.bezier(screen, b_points, 6, (255, 0, 0))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
Answered By: Rabbid76
Categories: questions Tags: , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.