Curvas de Bézier Multigrau: Fundamentos e Implementação Visual em Python

As curvas de Bézier, definidas pelos polinomiais de base de Bernstein, são ferramentas essenciais em design de interface de usuário (UI), computação gráfica e animação. A forma de uma curva de Bézier é determinada por um conjunto de pontos de controle, e sua ordem (ou grau) está diretamente ligada ao número desses pontos: um grau N requer N+1 pontos de controle. Por exemplo, uma curva de primeiro grau usa 2 pontos, uma de segundo grau usa 3, e uma de terceiro grau usa 4.

Conforme o grau aumenta, a complexidade, suavidade e capacidade de modelagem da curva também crescem. Uma curva de primeiro grau é uma linha reta (sem curvatura), uma de segundo grau é uma parábola (curvatura única), e uma de terceiro grau é uma curva de forma livre, capaz de apresentar pontos de inflexão e curvaturas mais elaboradas.

Este artigo explora as definições matemáticas, características geométricas e propriedades fundamentais das curvas de Bézier de diferentes graus. Serão fornecidos exemplos de código executáveis em Python, utilizando Matplotlib e NumPy, para visualizar a curva, seu polígono de controle, as funções de base de Bernstein e o processo dinâmico de enterpolação, ilustrando intuitivamente a lógica de geração da curva.

Conceitos Fundamentais

  1. Parâmetro da Curva: A curva é parametrizada por u ∈ [0, 1]. Quando u = 0, a curva está no primeiro ponto de controle; quando u = 1, está no último ponto de controle.
  2. Funções de Base de Bernstein: A essência das curvas de Bézier. Para uma curva de grau n, a i-ésima função de base é
    B<sub>i,n</sub>(u) = C(n, i) * u<sup>i</sup> * (1 - u)<sup>(n - i)</sup>
    onde C(n, i) = n! / (i! * (n - i)!) é o coeficiente binomial. A soma de todas as funções de base para um dado u é sempre 1, garantindo que a curva permaneça dentro do envoltório convexo de seus pontos de controle.
  3. Fórmula Geral da Curva: A equação de uma curva de Bézier é dada pela soma ponderada dos pontos de controle pelas funções de base:
    P(u) = Σ<sub>i=0</sub><sup>n</sup> B<sub>i,n</sub>(u) * P<sub>i</sub>
    onde P<sub>i</sub> são as coordenadas (2D ou 3D) do i-ésimo ponto de controle.
  4. Polígono de Controle: A sequência de segmentos de linha que conectam os pontos de controle. Ele define o envoltório convexo da curva de Bézier, dentro do qual a curva sempre reside.

Descrição Detalhada por Grau

(I) Curva de Bézier de Primeiro Grau (Linear)

Grau: 1 | Número de Pontos de Controle: 2 (P0, P1) | Formato da Curva: Segmento de linha reta (sem curvatura)

1. Definição Matemática

  • Funções de Base de Bernstein (2):
    • B<sub>0,1</sub>(u) = 1 - u
    • B<sub>1,1</sub>(u) = u
  • Equação Paramétrica da Curva (exemplo 2D, P=(x,y)):
    • P(u) = (1 - u)P<sub>0</sub> + uP<sub>1</sub> para u ∈ [0, 1]
  • Componentes Coordenados:
    • x(u) = (1 - u)x<sub>0</sub> + ux<sub>1</sub>
    • y(u) = (1 - u)y<sub>0</sub> + uy<sub>1</sub>

2. Propriedades Geométricas Principais

  • É um segmento de linha que conecta P0 e P1, sem qualquer flexão.
  • Qualquer ponto na curva para um dado u é uma interpolação linear entre P0 e P1, onde u representa a proporção da distância de P0 para P1.
  • A curva tem uma direção tangente constante (sua primeira derivada é constante): P'(u) = P<sub>1</sub> - P<sub>0</sub>.
  • Ela reside completamente dentro do envoltório convexo linear formado por P0 e P1 (que é a própria linha).

3. Aplicações Típicas

Interpolação linear básica, desenho de caminhos retos, animações simples de deslocamento linear.

4. Representação Visual

A representação visual desta curva mostra um segmento de linha reta vermleha que coincide perfeitamente com o polígono de controle. As funções de base são duas linhas que se cruzam linearmente, sem qualquer curvatura aparente, validando sua natureza linear.

(II) Curva de Bézier de Segundo Grau (Quadrática)

Grau: 2 | Número de Pontos de Controle: 3 (P0, P1, P2) | Formato da Curva: Segmento de parábola (curva suave com uma direção de curvatura, sem pontos de inflexão)

1. Definição Matemática

  • Funções de Base de Bernstein (3):
    • B<sub>0,2</sub>(u) = (1 - u)²
    • B<sub>1,2</sub>(u) = 2u(1 - u)
    • B<sub>2,2</sub>(u) = u²
  • Equação Paramétrica da Curva (exemplo 2D):
    • P(u) = (1 - u)²P<sub>0</sub> + 2u(1 - u)P<sub>1</sub> + u²P<sub>2</sub> para u ∈ [0, 1]
  • Componentes Coordenados:
    • x(u) = (1 - u)²x<sub>0</sub> + 2u(1 - u)x<sub>1</sub> + u²x<sub>2</sub>
    • y(u) = (1 - u)²y<sub>0</sub> + 2u(1 - u)y<sub>1</sub> + u²y<sub>2</sub>

2. Propriedades Geométricas Principais

  1. A curva é um segmento de uma parábola, exibindo um único centro de curvatura e direção de curvatura constante, sem pontos de inflexão.
  2. As tangentes nos pontos de extremidade: A curva é tangente ao segmento de linha P0P1 em P0 e ao segmento de linha P1P2 em P2. Suas primeiras derivadas são: P'(0) = 2(P<sub>1</sub> - P<sub>0</sub>) e P'(1) = 2(P<sub>2</sub> - P<sub>1</sub>).
  3. O ponto de controle P1 é um ponto de controle (não um ponto de interpolação); ele influencia o grau de curvatura e a direção da curva, mas a curva não passa por P1.
  4. A curva sempre permanece dentro do triângulo convexo formado por P0, P1 e P2.
  5. A segunda derivada é constante (P''(u) = 2(P<sub>2</sub> - 2P<sub>1</sub> + P<sub>0</sub>)), indicando uma curvatura fixa em magnitude e direção.

3. Aplicações Típicas

Design de cantos arredondados simples (botões de UI, bordas), caminhos de curva 2D básicos, segmentos fundamentais de contornos de fontes.

4. Representação Visual

A visualização para a curva de Bézier de segundo grau revela uma parábola verde. Ela é tangente ao segmento P0P1 em P0 e ao segmento P1P2 em P2, estando contida dentro do envoltório convexo triangular e sem apresentar pontos de inflexão.

(III) Curva de Bézier de Terceiro Grau (Cúbica)

Grau: 3 | Número de Pontos de Controle: 4 (P0, P1, P2, P3) | Formato da Curva: Curva suave de forma livre (pode apresentar pontos de inflexão, curvatura dupla; a ordem mais comum em engenharia e design)

1. Definição Matemática

  • Funções de Base de Bernstein (4):
    • B<sub>0,3</sub>(u) = (1 - u)³
    • B<sub>1,3</sub>(u) = 3u(1 - u)²
    • B<sub>2,3</sub>(u) = 3u²(1 - u)
    • B<sub>3,3</sub>(u) = u³
  • Equação Paramétrica da Curva (exemplo 2D):
    • P(u) = (1 - u)³P<sub>0</sub> + 3u(1 - u)²P<sub>1</sub> + 3u²(1 - u)P<sub>2</sub> + u³P<sub>3</sub> para u ∈ [0, 1]
  • Componentes Coordenados:
    • x(u) = (1 - u)³x<sub>0</sub> + 3u(1 - u)²x<sub>1</sub> + 3u²(1 - u)x<sub>2</sub> + u³x<sub>3</sub>
    • y(u) = (1 - u)³y<sub>0</sub> + 3u(1 - u)²y<sub>1</sub> + 3u²(1 - u)y<sub>2</sub> + u³y<sub>3</sub>

2. Propriedades Geométricas Principais

  • A curva é uma forma cúbica, capaz de exibir pontos de inflexão (onde a curvatura muda de direção) e curvatura dupla, oferecendo maior flexibilidade de design.
  • As tangentes nos pontos de extremidade: A curva é tangente ao segmento P0P1 em P0 e ao segmento P2P3 em P3.
  • Os pontos P1 e P2 são pontos de controle (não pontos de interpolação); eles puxam a curva em suas direções, permitindo um controle intrincado sobre sua forma.
  • A curva sempre reside dentro do envoltório convexo formado pelos quatro pontos de controle.
  • A curvatura varia continuamente ao longo da curva, permitindo mudanças de direção e a criação de formas complexas.

3. Aplicações Típicas

Design de UI (caminhos complexos, curvas de suavização de animação), modelagem CAD fundamental, design de fontes (TrueType/OpenType), caminhos de movimento de personagens em jogos, manipulação de imagem (transformações de imagem).

4. Representação Visual

A curva de Bézier de terceiro grau é uma curva livre magenta, destacando um ponto de inflexão marcado com uma estrela vermelha (indicando uma mudança na direção da curvatura). É tangente ao segmento P0P1 em P0 e ao segmento P2P3 em P3, e está contida dentro do envoltório convexo quadrangular. Isso demonstra a capacidade de modelagem central das curvas cúbicas.

Implementação em Python com Matplotlib

1. Funcionalidades da Implementação

Este código Python implementa as curvas de Bézier de primeiro, segundo e terceiro graus, permitindo as seguintes visualizações:

  • Geração e exibição das curvas em três subplots distintos para comparação.
  • Marcação dos pontos de controle (com numeração) e desenho do polígono de controle.
  • Plotagem das curvas das funções de base de Bernstein, que ajudam a entender a ponderação de cada ponto de controle.
  • Indicação da direção da tangente nos pontos de extremidade da curva, ilustrando as propriedades de tangência.
  • Geração de gráficos vetoriais de alta resolução, prontos para uso.

2. Ambiente Necessário

Para executar o código, certifique-se de ter as bibliotecas NumPy e Matplotlib instaladas. Elas podem ser instaladas via pip:

pip install numpy matplotlib scipy

3. Código Completo Executável


import numpy as np
import matplotlib.pyplot as plt
from matplotlib.patches import FancyArrowPatch
from scipy.special import comb # Mover import para o topo para melhor prática

# Configurações globais de estilo: alta resolução, fonte em português, tamanho da legenda/rótulo
plt.rcParams['figure.dpi'] = 150
plt.rcParams['font.sans-serif'] = ['DejaVu Sans', 'SimHei'] # Preferir 'DejaVu Sans' para caracteres padrão
plt.rcParams['axes.unicode_minus'] = False # Permite o uso de sinal de menos em fontes Unicode
plt.rcParams['font.size'] = 10
plt.rcParams['legend.fontsize'] = 8

# Função para calcular a base de Bernstein
def calcular_base_bernstein(grau, indice, t_param):
   """
   Calcula o valor da i-ésima função de base de Bernstein para uma curva de grau 'grau'.
   :param grau: Grau da curva de Bézier (n)
   :param indice: Índice da função de base (i, de 0 a n)
   :param t_param: Parâmetro t ∈ [0,1]
   :return: Valor da função de base
   """
   return comb(grau, indice) * (t_param ** indice) * ((1 - t_param) ** (grau - indice))

# Função para calcular os pontos da curva de Bézier
def calcular_curva_bezier(pontos_controle, t_param):
   """
   Calcula as coordenadas da curva de Bézier para os parâmetros t_param fornecidos.
   :param pontos_controle: Array de pontos de controle, shape=(n+1, 2)
   :param t_param: Parâmetro t ∈ [0,1], escalar ou array
   :return: Coordenadas da curva, shape=(len(t_param), 2)
   """
   grau = pontos_controle.shape[0] - 1  # Grau = número de pontos - 1
   t_param = np.atleast_1d(t_param) # Garante que t_param seja um array
   pontos_curva = np.zeros((len(t_param), 2))
   for i in range(grau + 1):
       base_bernstein = calcular_base_bernstein(grau, i, t_param)[:, np.newaxis]
       pontos_curva += base_bernstein * pontos_controle[i]
   return pontos_curva

# Função para desenhar setas de tangente nos pontos de extremidade
def desenhar_tangente(eixo, ponto_inicial, ponto_direcao, cor, rotulo, escala=0.5):
   """
   Desenha uma seta representando a direção tangente em um ponto da curva.
   :param eixo: Objeto do subplot Matplotlib
   :param ponto_inicial: Coordenadas do ponto onde a tangente é desenhada
   :param ponto_direcao: Coordenadas do ponto de controle adjacente para definir a direção
   :param cor: Cor da seta
   :param rotulo: Rótulo para a legenda da seta
   :param escala: Fator de escala para o comprimento da seta
   """
   vetor_direcao = (ponto_direcao - ponto_inicial) * escala
   seta = FancyArrowPatch(ponto_inicial, ponto_inicial + vetor_direcao, 
                           color=cor, arrowstyle='->', 
                           mutation_scale=8, label=rotulo)
   eixo.add_patch(seta)

# Geração de pontos de amostragem para o parâmetro t (amostragem densa para curvas suaves)
parametros_t = np.linspace(0, 1, 200)

# ===================== Definição dos pontos de controle por grau =====================
# Curva de Bézier de primeiro grau (2 pontos)
pontos_grau1 = np.array([[0, 0], [2, 3]])  # P0, P1
# Curva de Bézier de segundo grau (3 pontos)
pontos_grau2 = np.array([[0, 0], [1, 3], [3, 1]])  # P0, P1, P2
# Curva de Bézier de terceiro grau (4 pontos, com ponto de inflexão para demonstrar capacidade de modelagem)
pontos_grau3 = np.array([[0, 0], [1, 3], [3, -1], [4, 2]])  # P0, P1, P2, P3

# ===================== Cálculo das curvas de Bézier para cada grau =====================
curva_grau1 = calcular_curva_bezier(pontos_grau1, parametros_t)  # Curva linear
curva_grau2 = calcular_curva_bezier(pontos_grau2, parametros_t)  # Curva quadrática
curva_grau3 = calcular_curva_bezier(pontos_grau3, parametros_t)  # Curva cúbica

# ===================== Desenho dos subplots (3 linhas, 1 coluna) =====================
fig, (ax_grau1, ax_grau2, ax_grau3) = plt.subplots(3, 1, figsize=(8, 10), tight_layout=True)
fig.suptitle('Comparativo de Curvas de Bézier: Grau 1, 2 e 3', fontsize=14, fontweight='bold')

# -------------------- Subplot 1: Curva de Bézier de Primeiro Grau --------------------
ax_grau1.set_title('Curva de Bézier de Primeiro Grau (Linear, 2 Pontos de Controle)', fontsize=12)
# Desenha o polígono de controle
ax_grau1.plot(pontos_grau1[:, 0], pontos_grau1[:, 1], 'k--', lw=1, label='Polígono de Controle')
# Desenha a curva de Bézier
ax_grau1.plot(curva_grau1[:, 0], curva_grau1[:, 1], 'r-', lw=2, label='Curva de Bézier de 1º Grau')
# Desenha os pontos de controle (com numeração)
for i, (x, y) in enumerate(pontos_grau1):
   ax_grau1.scatter(x, y, c='blue', s=30, zorder=5)
   ax_grau1.text(x + 0.05, y + 0.05, f'P{i}', fontsize=9)
# Desenha as funções de base de Bernstein
for i in range(2):
   b = calcular_base_bernstein(1, i, parametros_t)
   ax_grau1.plot(parametros_t * 2, b * 3, '--', lw=1.5, label=f'B{i},1(t)')
# Configurações do subplot
ax_grau1.set_xlabel('X')
ax_grau1.set_ylabel('Y')
ax_grau1.legend(loc='best')
ax_grau1.grid(True, alpha=0.3)
ax_grau1.axis('equal')

# -------------------- Subplot 2: Curva de Bézier de Segundo Grau --------------------
ax_grau2.set_title('Curva de Bézier de Segundo Grau (Parabólica, 3 Pontos de Controle)', fontsize=12)
# Desenha o polígono de controle
ax_grau2.plot(pontos_grau2[:, 0], pontos_grau2[:, 1], 'k--', lw=1, label='Polígono de Controle')
# Desenha a curva de Bézier
ax_grau2.plot(curva_grau2[:, 0], curva_grau2[:, 1], 'g-', lw=2, label='Curva de Bézier de 2º Grau')
# Desenha os pontos de controle (com numeração)
for i, (x, y) in enumerate(pontos_grau2):
   ax_grau2.scatter(x, y, c='blue', s=30, zorder=5)
   ax_grau2.text(x + 0.05, y + 0.05, f'P{i}', fontsize=9)
# Desenha tangentes nos pontos de extremidade
desenhar_tangente(ax_grau2, pontos_grau2[0], pontos_grau2[1], 'orange', 'Tangente em P0')
desenhar_tangente(ax_grau2, pontos_grau2[-1], pontos_grau2[-2], 'purple', 'Tangente em P2')
# Desenha as funções de base de Bernstein
for i in range(3):
   b = calcular_base_bernstein(2, i, parametros_t)
   ax_grau2.plot(parametros_t * 3, b * 3, '--', lw=1.5, label=f'B{i},2(t)')
# Configurações do subplot
ax_grau2.set_xlabel('X')
ax_grau2.set_ylabel('Y')
ax_grau2.legend(loc='best')
ax_grau2.grid(True, alpha=0.3)
ax_grau2.axis('equal')

# -------------------- Subplot 3: Curva de Bézier de Terceiro Grau --------------------
ax_grau3.set_title('Curva de Bézier de Terceiro Grau (Curva Livre, 4 Pontos de Controle, com Ponto de Inflexão)', fontsize=12)
# Desenha o polígono de controle
ax_grau3.plot(pontos_grau3[:, 0], pontos_grau3[:, 1], 'k--', lw=1, label='Polígono de Controle')
# Desenha a curva de Bézier
ax_grau3.plot(curva_grau3[:, 0], curva_grau3[:, 1], 'm-', lw=2, label='Curva de Bézier de 3º Grau')
# Desenha os pontos de controle (com numeração)
for i, (x, y) in enumerate(pontos_grau3):
   ax_grau3.scatter(x, y, c='blue', s=30, zorder=5)
   ax_grau3.text(x + 0.05, y + 0.05, f'P{i}', fontsize=9)
# Desenha tangentes nos pontos de extremidade
desenhar_tangente(ax_grau3, pontos_grau3[0], pontos_grau3[1], 'orange', 'Tangente em P0')
desenhar_tangente(ax_grau3, pontos_grau3[-1], pontos_grau3[-2], 'purple', 'Tangente em P3')
# Desenha as funções de base de Bernstein
for i in range(4):
   b = calcular_base_bernstein(3, i, parametros_t)
   ax_grau3.plot(parametros_t * 4, b * 3, '--', lw=1.5, label=f'B{i},3(t)')
# Marca um ponto de inflexão (típico de curvas cúbicas)
# Nota: Este é um exemplo simplificado de marcação de "inflexão" em uma das coordenadas extremas.
# Um cálculo preciso de pontos de inflexão requer análise da segunda derivada.
ax_grau3.scatter(curva_grau3[np.argmin(curva_grau3[:,1]),0], curva_grau3[np.argmin(curva_grau3[:,1]),1], 
           c='red', s=40, marker='*', label='Ponto de Inflexão (Exemplo)', zorder=6)
# Configurações do subplot
ax_grau3.set_xlabel('X')
ax_grau3.set_ylabel('Y')
ax_grau3.legend(loc='best')
ax_grau3.grid(True, alpha=0.3)
ax_grau3.axis('equal')

# Salva a imagem (opcional, vetor de alta resolução)
# plt.savefig('Comparativo_Curvas_Bezier.png', dpi=300, bbox_inches='tight')
plt.show()


Tabela Comparativa Essencial das Curvas de Bézier

Para uma referência rápida, a tabela abaixo resume as características-chave de cada grau de curva de Bézier:

Característica Bézier de Primeiro Grau Bézier de Segundo Grau Bézier de Terceiro Grau
Grau 1 2 3
Nº de Pontos de Controle 2 (P0, P1) 3 (P0, P1, P2) 4 (P0, P1, P2, P3)
Formato da Curva Segmento de linha reta (sem curvatura) Parabólica (curvatura única) Curva livre (pode ter pontos de inflexão)
Grau Polinomial da Base de Bernstein Polinômio de primeiro grau Polinômio de segundo grau Polinômio de terceiro grau
Tangência nos Pontos de Extremidade N/A (é uma linha) P0 tangente a P0P1, P2 tangente a P1P2 P0 tangente a P0P1, P3 tangente a P2P3
Variação da Curvatura Curvatura zero (constante) Curvatura constante Curvatura varia continuamente (pode inverter)
Capacidade de Modelagem Muito limitada (apenas linhas) Limitada (apenas curvas simples) Média a alta (ideal para engenharia)
Dificuldade de Controle Nenhuma Simples Moderada
Aplicações Típicas Interpolação linear, caminhos retos Cantos arredondados de UI, curvas simples Caminhos complexos, design de fontes, modelagem CAD

É importante notar que curvas de Bézier de grau 4 ou superior raramente são usadas diretamente em sistemas de engenharia ou gráficos devido à sua baixa praticidade. Elas tendem a introduzir problemas significativos. A indústria geralmente opta por "curvas de Bézier de baixo grau segmentadas" (especialmente cúbicas) como alternativa a curvas de alto grau.

Considerações Finais

  • Propriedade do Envoltório Convexo: Todas as curvas de Bézier, independentemente do grau, sempre residem dentro do envoltório convexo de seus pontos de controle. Esta propriedade garante que a curva seja previsível e controlável; ajustar um ponto de controle não causará desvios irregulares da curva.
  • Interpolação vs. Controle: As curvas de Bézier interpolam apenas os pontos de controle inicial e final. Os pontos de controle intermediários são "pontos de controle" (influenciam a forma, mas a curva não passa por eles). Este é um dos principais diferenciais em relação às curvas B-spline.
  • Princípios de Seleção do Grau: Na prática, as curvas de Bézier de terceiro grau são as mais utilizadas. Curvas de primeiro e segundo graus são insuficientes para modelagem complexa. Já curvas de quarto grau ou superior apresentam um número excessivo de pontos de controle, onde a alteração de um único ponto afeta drasticamente toda a curva (falta de controle local), tornando o controle exponencialmente mais difícil.
  • Concatenação de Segmentos: Se uma única curva de Bézier de terceiro grau não for suficiente para atender às necessidades de modelagem complexa, múltiplos segmentos de curvas de Bézier cúbicas podem ser concatenados. Assegurando a continuidade C1 (tangência) ou C2 (curvatura) nos pontos de junção, é possível obter curvas complexas e suaves.
  • B-splines: Embora as curvas de Bézier resolvam muitos problemas de aproximação de splines, elas têm uma desvantagem notável: a modificação de um único ponto de controle afeta toda a curva. Para resolver isso, as curvas B-spline oferecem controle local, onde a influência de cada ponto de controle é restrita a uma parte específica da curva.

Tags: Curvas de Bézier matplotlib NumPy modelagem geométrica computação gráfica

Publicado em 10-31 18:20