Você está na página 1de 13

02/04/2019

O que é uma Primitiva Gráfica?


Representação discreta em grade de um elemento
geométrico fundamental, e.g. Ponto, Linha, Retângulo,
Círculo, etc.
Outra Definição (Formal): “Aproximar primitivas
matemáticas (ideais) em termos de vértices (pixels) a serem
plotados em uma malha discreta e finita de elementos de
figura finitos.”
Primitivas Gráficas 2D

GBC204 – Computação Gráfica


Prof. Dr. rer. nat. Daniel Duarte Abdala

Processo para Representação Geométrica


Primitiva Gráfica - Ponto em Computador
Postulado (aceito a priori) fundamental da geometria;
Ponto – Localização única no espaço;
Não possui dimenção;
Elemento básico a partir do qual todos os outros objetos da geometria
são construídos; Geometria Discretização Rasterização
Representado gráficamente utilizando usualmente um pequeno círculo y y x
ou “marca”; P1 = ( x1 ,  y1 )
P1 = ( x1 , y1 )
Postulado da Existência: “Numa reta, bem como fora dela há infinitos
pontos. Num plano há infinitos pontos.”
Como o computador é uma máquina discreta, aproximações devem
ser feitas:
Ponto é aproximado para um pixel ou pel (picture element); P2 = ( x2 , y2 ) P2 = ( x2 ,  y2 )
x x
Menor unidade representável em um display gráfico; y
Elemento fundamental a partir do qual todas as demais primitivas
gráficas são construídas.
Postulado da Existência (CG): “Numa reta, bem como fora dela há um
número finito de pels. Num plano há um número finito de pels.”

Representação de Pontos Exemplo (python)


import sys,pygame
Pontos são realizados sob a forma de pixels, ou mais
from pygame import gfxdraw
especificamente pels;
Basicamente, altera-se o valor do respectivo elemento no pygame.init()
screen = pygame.display.set_mode((50,50))
framebuffer;
screen.fill((255,255,255))
Programacionalmente:
screen.set_at((10,10),(255,0,0))
setPixel(x,y);
screen.set_at((20,20),(0,255,0))
screen.set_at((20,10),(0,0,255))
screen.set_at(x,y,cor) pygame.display.flip()

while 1:
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()

1
02/04/2019

Primitiva Gráfica - Linhas Matematicamente ...


Postulado da Determinação: “Dois pontos distintos Equação da Reta: y = mx + b (eq. 3.1)
y
delimitam uma única reta que passa por eles.”; Isolando o termo “m”: y2
Computacionalmente lidamos com segmentos de retas, y1 = mx1 + b y2 − y1
ou seja, apenas a parte da reta delimitada pelo ponto m= (eq. 3.2)
y 2 = mx2 + b x2 − x1 y1+inc2
inicial e final; ∆y
y1
y 2 − mx2 = y1 − mx1
PROBLEMA: converter a representação matemática de x
mx1 − mx2 = y2 − y1 b = y1 − mx1 (eq. 3.3) x1 x1+inc x2
um segmento de reta definida por infinitos pontos entre m( x2 − x1 ) = ( y 2 − y1 )
∆x

os pontos inicial e final para uma representação discreta


A partir de qualquer valor de x, o incremento discreto de y pode
alinhada a grade de representação de finitos pels. ser calculado:
∆y = m∆x (eq. 3.4)
similarmente:
∆y (eq. 3.5)
∆x =
m

Algoritmo DDA – Digital Differential Analyzer DDA – C (pseudocódigo)


Algoritmo de conversão de linhas que se baseia no #define ROUND(a) ((int)(a+0.5))

cálculo de ∆x ou ∆y; void linhaDDA(int xa, int ya, int xb, int yb)
{
A linnha é amostrada em intervalos unitários int dx = xb–xa, dy = yb-ya, steps, k;
float xIncrement, yIncrement, x = xa, y = ya;
incrementais em uma coordenada (x ou y) e então se
determina o valor inteiro correspondente para a outra if (abs(dx)>abs(dy)) steps = abs(dx);
else steps = abs(dy);
coordenada; xIncrement = dx/(float)steps;
yIncrement = dy/(float)steps;
Considere um linha com inclinação positiva (m>0);
setPixel(ROUND(x), ROUND(y));
Se m ≥1 → amostragem em x (∆x=1) e os valores de for(k=0; k<steps;k++){
y serão computados utilizando a expressão a seguir: x += xIncrement;
y += yIncrement;
setPixel(ROUND(x), ROUND(y));
onde k indica a próxima iteração discreta a partir do
yk +1 = yk + m Ponto inicial. }
}

DDA - Python Exemplo


import sys,pygame def dda(x1,y1,x2,y2):
from pygame import gfxdraw x,y = x1,y1 x dda(2,4,4,11)
length = (x2-x1)
pygame.init() if length <= (y2-y1) 12
dx = 4 − 2 = 2, dy = 11 − 4 = 7, steps = 7
screen = pygame.display.set_mode((400,400)) length = y2 – y1 11 x 4 5 6 7 8 9 10 11
screen.fill((0,0,0)) dx = (x2-x1)/float(length) 10 yinc - 2.285 2.571 2.857 3.143 3.428 3.714 3.999
pygame.display.flip() dy = (y2-y1)/float(length) 9 y 2 2 3 3 3 3 4 4
White = (255,255,255) screen.set_at((ROUND(x),ROUND(y)),white)
8
def ROUND(n):
7
return int(n+0.5) for i in range(length):
x += dx 6
dda(2,2,12,7 )
y += dy 5 dx = 12 − 2 = 10, dy = 7 − 2 = 5, steps = 5
screen.set_at((ROUND(x),ROUND(y)),white) 4
x 2 3 4 5 6 7 8 9 10 11 12
pygame.display.flip()
3
yinc - 2.5 3 3.5 4 4.5 5 5.5 6 6.5 7
2
dda(10,10,50,50) y 2 2 3 3 4 4 5 5 6 6 7
1

while 1: y
1 2 3 4 5 6 7 8 9 10 11 12
for event in pygame.event.get():
if event.type == pygame.QUIT: sys.exit()

2
02/04/2019

Problemas com o algoritmo DDA Algoritrmo de Bresenham


( ↑ ) O algoritmo dda elimina a necessidade da Bresenham [BRE65] propôs um algoritmo consideravelmente
mais preciso e eficiente para rasterização de linhas;
multiplicação na eq. 3.1;
O algoritmo ainda apresenta a vantagem de ser adaptado para
( ↓ ) A acumulação de erros de arredondamento nas a rasterização de círculos;
adições sucessivas em ponto flutuante podem levar ao Inicialmente considera-se o caso de linhas com inclinação
cálculo de posições de pels que se distanciam do caminho positiva menor que 1 (0≤m≤1);
Neste caso, inicia-se no ponto terminador mais a esquerda
original da linha em caso de longos segmentos de retas; p1(x1,y1) e incrementa-se a coordenada x atualizando no
( ↓ ) Operação de arredondamento e aritmética de ponto frame buffer o pel que possua o valor de y mais próximo
flutuante são custosas. da linha real;
Assumindo que o pel(xk,yk) esteja no frame buffer, então
deve-se decidir qual o pel a atualizar no frame buffer na
coluna xk+1;
Há neste caso, duas possibilidades: (xk+1,yk) e (xk+1,yk+1);

Bresenham Motivação Matematicamente...


x
y = m( xk + 1) + b
12
então:
11 d1 = y − y k
10 = m( xk + 1) + b − y k
9
e:
8
yk+1 d2
d 2 = ( y k + 1) − y
7

6
yk d1 = y k + 1 − m(xk + 1) − b
5

4
d1 − d 2 = m( xk + 1) + b − yk − ( yk + 1 − m(xk + 1) − b )
xk x k+1
3 ? d1 − d 2 = m(xk + 1) + b − yk − yk − 1 + m(xk + 1) + b
2 ?
1
d1 − d 2 = 2m(xk + 1) − 2 y + 2b − 1
y
1 2 3 4 5 6 7 8 9 10 11 12

Matematicamente... Matematicamente...
Um parâmetro decisório pode ser alcançado pela manipulação da equação No passo k+1 o parâmetro de decisão avaliado pela equação anterior será:
acima de modo que apenas cálculos inteiros estejam envolvidos. pk +1 = 2∆y ⋅ xk +1 − 2 ∆x ⋅ yk +1 + c
Onde ∆x e ∆y são as separações vertical e horizontal
m = ∆x respectivamente dos pontos terminadores p1(x1,y1) e Subtraindo as duas equações, obtêm-se:
∆y
p2(x2,y2) do segmento de reta.
pk +1 − pk = 2 ∆y ( xk +1 − xk ) − 2∆x( yk +1 − yk )
∆x = x2 − x1 ∆y = y2 − y1
c = 2∆y + ∆x(2b − 1) Como xk+1=xk+1, têm-se:
pk +1 − pk = 2∆y − 2∆x( yk +1 − yk )
Note que c é independente da posição
pk = ∆x(d1 − d 2 ) do próximo pel e consequentemen- Note que o termo (yk+1-yk) será sempre 0 ou 1;
pk = 2 ∆y ⋅ xk − 2∆x ⋅ yk + c te, pode ser eliminado. O primeiro parâmetro decisório p0 avaliado na posição (x1,y1) e m avaliado
como ∆y/∆x:
p0 = 2∆y − ∆x

3
02/04/2019

Bresenham Python (1º quadrante) Exemplo Bresenham


import sys,pygame x = x1
from pygame import gfxdraw y = y1
x
pygame.init()
for i in range(dx):
if pant < 0:
bresenham(2,2,12,8)
12
screen = pygame.display.set_mode((400,400))
screen.fill((0,0,0))
screen.set_at((x+1,y),white)
pant = pant + dy2 11
dx = 12 − 2 = 10
pygame.display.flip() else:
10 dy = 8 − 2 = 6
screen.set_at((x+1,y+1),white) 9
white=(255,255,255)
pant = pant + dydx2
8
dy 2 = 2 × 6 = 12
y += 1;
#Esta funcao funciona apenas
#para o primeiro quadrante
x += 1; 7 dydx2 = 12 − 20 = −8
pygame.display.flip()
def bresenham(x1,y1,x2,y2): 6

bresenham(10,10,50,50) 5
p0 = 12 − 10 = 2
#carrega no fb o pixel (x1,y1)
screen.set_at((x1,y1),white) 4
while 1: x 2 3 4 5 6 7 8 9 10 11 12
#computa os deltas necessarios
for event in pygame.event.get(): 3
dx = x2 - x1 Pk+1 2 -6 6 -2 10 2 -6 6 -2 10 –
if event.type == pygame.QUIT: sys.exit() 2
dy = y2 - y1 y 2 3 3 4 4 5 6 6 7 7 8
dy2 = 2*dy
1
dydx2 = dy2 - 2*dx
pant = dy2 - dx y
1 2 3 4 5 6 7 8 9 10 11 12

Importância do Desempenho (Linhas) Em OpenGL (Pontos)...


Em resumo, linhas são fáceis de se calcular e plotar: A primitiva gráfica mais glBegin(GL_POINTS)
Para decidir exatamente onde um ponto recai na latice de plotagem fundamental prevista em OpenGL glVertex2f(1.0, 1.0);
basta que se resolva a equação da reta; glVertex2f(2.0, 1.0);
é o ponto; glVertex2f(2.0, 2.0);
Resultados reais podem ser discretizados por operação de Um ponto é representado por um glEnd();
arredondamento;
vértice (vertex);
No entanto: glPointSize(n);
Por definição, pontos são objetos
Cálculos em ponto flutuante são caros; glEnable(GL_POINT_SMOOTH);
de área zero. Consequentemente,
Arredondamentos são caros; glHint(GL_POINT_SMOOTH_HINT,GL_NICEST);
para se visualizar pontos
Multiplicações (não por potências de 2) e divisões são caras; individuais, deve-se especificar seu glEnable(GL_BLEND);
Em última instância: tamanho; glBrendFunc(GL_SRC_ALPHA,
A saída é bidimencional (monitores e displays); GL_ONE_MINUS_SRC_ALPHA);

Linhas e pontos são as únicas primitivas realmente plotadas;


Centenas de milhares de linhas podem ser renderizadas por frame;
Requisito Fundamental: Minimizar o custo computacional
para processamento de linhas!

Em OpenGL (Linhas)... Em OpenGL (Poligonos)...


Linhas são especificadas utilizando glBegin(GL_Lines) Qualquer polígono pode ser glBegin(GL_TRIANGLES)

a variável do ambiente GL_LINES; glVertex3f(1.0, 5.0, 0.0); desenhado em OpenGL; glVertex3f(1.0, 5.0, 0.0);
glVertex3f(1.0, 10.0, 0.0); glVertex3f(1.0, 10.0, 0.0);
Eles são “quebrados” em triângulos glVertex3f(1.0, 5.0 , 0.0);
Dois pontos são necessários para glVertex3f(1.0, 5.0 , 0.0); para plotagem;
glVertex3f(1.0, 10.0, 5.0); glEnd();
se desenhar uma linha; Por definição, vértices em um
glEnd();
Elas devem ser especificadas em polígono são desenhados no sentido
glLineWidth(n);
coordenadas 3D; contrário ao relógio;
glEnable(GL_LINE_SMOOTH);
OpenGL possui primitivas para
Para restringi-las ao plano 2D desenho de triângulos, quadriláteros e
glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
basta que a coordenada z seja glEnable(GL_BLEND);
polígonos convexos. Normalmente
zerada; estes são desenhados como sólidos glBrendFunc(GL_SRC_ALPHA,
GL_ONE_MINUS_SRC_ALPHA);
preenchidos;
Frequentemente deseja-se combinar
múltiplos triângulos para se formar
uma superfície complexa e “contínua”;
Triângulos são preferidos em
computação gráfica pois são
garantidamente planares!

4
02/04/2019

Faixa (Strip) de Triângulos Faixa (Strip) de Triângulos


Repetir vértices comuns é laborioso e desnecessário; Desta forma, a relação entre número de vértices e
Uma faixa de triângulos usa os dois últimos pontos para triângulos é dada pela relação:
especificar o triângulo; Onde:
nt = nv − 2, ∀nv > 3 nt : número de triângulos
nv : número de vértices
V1 V2 V3 V4 V5 V6 V7 No caso de GL_TRIANGLES, a relação é dada por:
nt = nv / 3, ∀i / nv = 3i ∧ i ∈ Ν
Triângulo 1
nv = 3nt , ∀nt > 1 ∧ nt ∈ N
Triângulo 2
Uma forma alternativa para se especificar superfícies seria
Triângulo 3 utilizar GL_TRIANGLE_FAN
Triângulo 4

Triângulo 5

Formas de Renderização de Triângulos Em OpenGL (Quadirláteros)...


OpenGL permite que quadriláteros glBegin(GL_QUADS)
5 6 5 sejam desenhados; glVertex3f(1.0, 1.0, 0.0);
glVertex3f(1.0, 5.0, 0.0);
Na realidade ele os quebra em dois glVertex3f(5.0, 5.0 , 0.0);
6 4 triângulos; glVertex3f(5.0, 1.0 , 0.0);
5 4 6 4
Processo similar ao adotado para glEnd();
2 3 triângulos simples;
3 2 1 3
8 7 7 8

1 1 2
5 6
GL_TRIANGLES GL_TRIANGLE_STRIP GL_TRIANGLE_FAN 5 6

4 3
3 4

1 2 1 2

GL_QUAD GL_QUAD_STRIP

Primitivas Gráficas – Círculos Primitivas Gráficas – Círculos


Um círculo é definido como o conjunto de Problemas:
pontos, todos localizados a uma distância r O método aritmético tradicional requer considerável poder
de um ponto central c; computacional, em cada passo;
Esta relação de distância pode ser expressa O Espaço entre pixels a serem plotados não é regular;
pelo teorema de pitágoras, como segue: Círculo(0,0,5) 6
5

y = ± r 2 − x2 
( x − cx ) 2 + ( y − c y ) 2 = r 2 4
3
x 1 2 3 4 5
Para identificar todos os pontos do círculo, usando o eixo 2

 25 − x 
1
2 4.89 4.58 4 3 E
x como referência, tem-se: 0
-1
-2
y 4 4 4 3

y = c y ± r 2 − ( cx − x ) 2 -3
-4
No entanto, claramente este não é um método eficiente -5
-6
para geração dos pontyos do círculo; -6 -5 -4 -3 -2 -1 0 1 2 3 4 5 6

5
02/04/2019

Outro Exemplo Círculo(0,0,17) Simetria de Octetos


Devido a simetria do círculo, não é necessário que as
coordenadas de todos os pixels do círculo sejam calculadas;
Basta que apenas 1/8 do círculo seja calculado e os demais 7/8
dos pixels podem ser calculados de maneira não custosa
unicamente por espelhamentos.

(-x,y) (x,y)

(-y,x) (y,-x)

(-y,-x) (y,-x)

(-x,-y) (x,-y)

Coordenadas Polares
Uma forma de se abordar o problema do espaçamento x 16.99 16.88 16.73 16.5 16.27 15.95 15.57 15.15 14.67

irregular seria calcular as coordenadas dos pontos da y 0.99 1.99 2.98 3.96 4.92 5.88 6.8 7.7 8.58

borda circular usando para tal coordenadas polares: θ 1/r 2/r 3/r 4/r 5/r 6/r 7/r 8/r 9/r

 x = cx + r cosθ
 θ = 1r
x 14.14 13.56 12.93 12.26 11.55 10.8 10.01 9.18 8.33

 y = c y + r sin θ
y 9.43 10.24 11.02 11.76 12.47 13.13 13.74 14.3 14.82

Este método resolve parcialmente o problema de


10/r 11/r 12/r 13/r 14/r 15/r 16/r 17/r 18/r
θ
espaçamento;
No entanto também é caro computacionalmente: x 7.44 6.53 5.59 4.64 3.67 2.69 1.7 0.7

O custo pode ser atenuado, ajustando o tamanho do passo, y 15.28 15.69 16.05 16.35 16.59 16.78 16.91 16.98

que em última instância, refere-se ao ângulo θ de amostragem. θ 19/r 20/r 21/r 22/r 23/r 24/r 25/r 26/r

Algoritmo do Círculo Baseado na


Problemas com o Método de Coord. Polares Modelagem do Ponto Médio
Mesmo computando apenas 1/8 de todos os pontos que Midpoint Circle Algorithm
comporão a curva, o algoritmo ainda assim é muito caro; Baseado no algoritmo de Breseham para linhas
*, /, sin e cos Algoritmo guloso – a cada passo deve-se decidir entre um de dois
possíveis pixels;
Passos grandes gerarão buracos na rasterização;
Passos pequenos farão com q pontos sejam computados mais Utiliza a simetria de octetos
de uma vez; Extremamente rápido!
A regra de passo definido como 1/r é uma aproximação;
Em alguns casos, dependendo do tamanho do passo, o mesmo
ponto pode ser computado mais de uma vez;

6
02/04/2019

Midpoint Circle Algorithm - Bresenham Exemplo


void midpointCircle(int r, int value) void plotaOcteto(int x, int y, int value)
{ {
int x = 0; setPixel( x, y, value);
int y = r; setPixel(-x, y, value); x y d
int d = 1 – r; setPixel(-y, x, value);
setPixel(-y, -x, value); 0 10 -9
plotaOcteto (x, y, value); setPixel(-x, -y, value);
setPixel( x, -y, value); 1 10 -6
while( y > x ) setPixel( y, -x, value);
{ setPixel( y, x, value); 2 10 -1
if( d < 0 ) //selecione E }
d += ( 2 * x ) + 3; 3 10 6
else { //selecione SE
d += 2 * ( x – y ) + 5; 4 9 -8
y--;
} 5 9 3
x++;
plotaOcteto(x, y, value); 6 8 -5
}
} x 7 8 12

Análise de Complexidade Primitiva Gráfica - Curvas


Apenas aritmética inteira; Matematicamente, curvas são representadas
A determinação de N não é automática; tradicionalmente utilizando equações tais como:
Função de r, ou seja, o número de pixels a serem processados y=x2+2x+3
depende do raio do círculo (obviamente); y=x4+3x3+2x2+1
Seguramente N < r; x2+y2 = r
Algoritmo linear; Os problemas relacionados com essas representações
Multiplicações por 2 podem ser substituidas por deslocamento são:
a esquerda (uma casa apenas); Difícil encontrar a equação exata para a curva desejada
Rasterizar tais curvas pode ser computacionalmente caro;
A solução: Utilizar curvas paramétricas!

Código Exemplo (Matlab) Curvas Paramétricas


%define o num. de subdivisões for allp = 1: size(x,2) - 1
subdiv = 10 sumx = floor((x(allp) + x(allp+1) )/2); Curvas 3D são representadas usando representação
colorInc = 1/(subdiv+1); sumy = floor((y(allp) + y(allp+1) )/2); paramétrica, introduzindo assim uma nova variável “t”;
%define um conjunto inicial de três pontos newx(allp+1) = sumx;
%subplot(subdiv+1,1,1); newy(allp+1) = sumy; Q(t) = |x(t) y(t) z(t)|
end;%for
x = [50 250 400] newx(size(x,2)+1) = x(size(x,2));
Note que x,y e z são independentes entre si, sendo
y = [50 450 300] newy(size(x,2)+1) = y(size(x,2)); dependentes apenas em t (que é a variável livre da eq.);
plot(x,y,'-o','Color',[0,0,1]) x = newx;
origx = x; y = newy; Pense acerca de “t” como a progressão do tempo
origy = y; figure; durante o desenho sequencial da curva;
hold on
for count = 1: subdiv %subplot(subdiv+1,1,count+1); t = [0,1]
newx = []; plot(origx,origy,'-o','Color',[0,0,1])
newy = []; plot(x,y,'-o','Color',[0, 0, colorInc*count]); http://www.inf.ed.ac.uk/teaching/courses/cg/d3/hermite.ht
newx(1) = x(1); end;%for ml
newy(1) = y(1);

7
02/04/2019

Metáfora do Lápis Continuidade de Curvas


Critérios: Continuidade Geométrica
Controle local da forma; Uma curva pode ser descrita como tendo continuidade Gn, n
tempo
Suavidade e Continuidade; sendo uma medida de suavidade;
Capacidade de se avaliar G0 – As curvas tocam no ponto de junção;
Ponto
Final t=1
derivadas; G1 – As curvas também compartilham uma direção tangente
Ponto x(t), y(t) Estabilidade; comum ao ponto de junção;
Inicial t=0
Facilidade de renderização; G2 – As curvas também compartilham um centro de curvatura
comum no ponto de junção.

Continuidade de Curvas Curvas Paramétricas


Continuidade Paramétrica Utilizam-se polinômios de terceira ordem;
C0 – Curvas são conectadas; Porquê?
C1 – As primeiras derivadas são iguais; Curvas de mais baixa ordem não podem ser unidas suavemente;
C2 – As primeiras e segundas derivadas são iguais; Curvas de mais alta ordem introduzem oscilações, e são
matematicamente mais complexas;
Cn – As primeiras n-ésimas derivadas são iguais.
Ordem 3 é necessário e suficiente!

Matematicamente ... Matematicamente ...


Q(t ) = x (t ) y (t ) z (t ) d dt Q (t ) = [d dt x(t ), d dt y (t ), d dt z (t )]
 x(t ) = a xt 3 + bxt 2 + cxt + d x  d dt Q (t ) x = 3axt 2 + 2bxt + cx
 3 2 
 y (t ) = a yt + byt + c yt + d y 2
d dt Q (t ) y = 3a yt + 2byt + c y
 z (t ) = a t 3 + b t 2 + c t + d  d dt Q (t ) = 3a t 2 + 2b t + c
 z z z z
 z z z z

 ax ay az  d dtQ(t) = [3t 2 ,2t,1,0]⋅ C


b by bz 
[ ] C=
3 2 x T T T
T = t , t , t ,1 Q (t ) = C ⋅ T
 cx cy cz 
 
 d x dy d z 

Note que a derivada de Q(t) é sua tangente

8
02/04/2019

Curva de Hermite Curva de Hermite


Curvas que se juntem de maneira suave são desejadas; Olhando apenas para a coordenada x ...
Curvas são especificadas provendo-se: Q(t ) x = axt 3 + bxt 2 + cxt + d x
Os pontos terminadores; e sua derivada
As primeiras derivadas dos pontos terminadores; d dt Q(t ) x = 3axt 2 + 2bxt + cx
Dada a equação Q(t)=T∙C: Sendo assim, reescrevendo de forma linear, tem-se:
Podemos fatorar a matriz C em duas outras matrizes C=G∙M;  Q ( 0 ) x  0 0 0 1   ax 
G – matriz da geometria;  Q (1)  1 1 1 1   bx 
 x 
= ⋅
M – matriz de base; Q (0)'x  0 0 1 0  c x 
G representa as restrições geométricas da curva (pontos      
 Q (1)'x  3 2 1 0  d x 
terminadores e derivadas), ao passo que M será constante
para todas as curvas de Hermite.

Curva de Hermite Curva de Hermite


−1
 a x  0 0 0 1  Q ( 0) x  Q (t ) = C ⋅ T =
 b  1 1 1 1  Q (1) 
 x =  T ⋅ M ⋅ [Q (0), Q (1), Q (0)' , Q (1)' ] =
⋅
x 

 c x  0 0 1 0 Q (0)'x 
      T ⋅ M ⋅ [ P1 , P4 , R1, R4 ]
d x  3 2 1 0  Q (1)'x 
 ax   2 − 2 1 1   Q (0) x  Uma vez que M e T são conhecidos, pode-se escrever
 b  − 3 3 − 2 − 1  Q (1) x  uma polinomial cúbica por inspeção simples.
 x =  ⋅
 cx   0 0 1 0  Q (0)'x 
     
d x   1 0 0 0   Q (1)'x 
O mesmo desenvolvimento matemático segue para y e z.
Então...

Exemplos Curvas de Bezier


Outra forma para se especificar curvas foi formulada por
Bezier, em meados de 1972;
Ela requer que quatro pontos (p1, p2, p3, p4) sejam
especificados:
O primeiro e o último pontos (p1, p2) são os pontos
terminadores da curva (na curva);
Os pontos intermediários (p3, p4) são chamados pontos de
controle e residem fora da curva.
A curvatura é controlada pelos vetores (p1, p2) e (p3, p4).

9
02/04/2019

Binômio de Newton Exemplo


Como expandir expressões do tipo (x+y)n? 4
4
( x + y )4 = ∑   ⋅ x 4− k y k
1 k =0  k 
( x + y) = x + y
 4  4  4  4  4
( x + y )2 = ( x + y)( x + y ) = x 2 + 2 xy + y 2 =   ⋅ x 4−0 y 0 +  ⋅ x 4−1 y1+  ⋅ x 4−2 y 2 +  ⋅ x 4−3 y 3 +  ⋅ x 4−4 y 4
 0 1  2  3  4
( x + y )3 = (( x + y )( x + y ) )( x + y ) = x 4 + 4 x 3 y + 6 x 2 y 2 +4 xy 3+ y 4
= ( x 2 + 2 xy + y 2 )( x + y )
= x3 + 2 x 2 y + xy 2 + x 2 y + 2 xy 2 + y 3
( x + y )7 = ( x + y)( x + y)( x + y )( x + y )( x + y )( x + y )( x + y )

n – grau do binômio
n
 n
( x + y )n = ∑   ⋅ x n−k y k n
*

  – coeficiente binomial
k =0  k  k 

* Número de combinações de n elementos tomados k a k.

Triângulo de Pascal Curva de Bezier Linear


l\c 0 1 2 3 4 5 6
Caso mais simples;
0 1 Equação paramétrica do segmento de reta;
0:
1 1 1 B (t ) = (1 − t ) B0 + tB1 , t ∈ [0,1]
1:
2 1 2 1
2: 1
1
B (t ) = ∑   ⋅ (1 − t )1− k t kBk
Pontos de controle
3 1 3 3 1
3: k =0  k 
4 1 4 6 4 1 1 1
4:
=   ⋅ (1 − t )1−0 t 0B0 +   ⋅ (1 − t )1−1 t1B1 = (1 − t ) B0 + tB1
5 1 5 10 10 5 1
5:  0 1
6 1 6 15 20 15 6 1
6: Casos extremos (t=0 e t=1) são fáceis de calcular;
tl ,c = tl −1,c + tl ,c−1 Caso t=0.5:

Curva de Bezier Linear Curva de Bezier Quadrática


Caso mais simples; B (t ) = (1 − t ) 2 B0 + 2t (1 − t ) B1 + t 2 B2 , t ∈ [0,1]
Equação paramétrica do segmento de reta; 2
2
B (t ) = ∑   ⋅ (1 − t ) 2−k t kBk
p0 k =0  k 
B (0.5) = 0.5B0 + 0.5 B1  2  2  2
1  5   0.5   2.5   3  =   ⋅ (1 − t )2−0 t 0B0 +   ⋅ (1 − t ) 2−1 t1B1 +   ⋅ (1 − t ) 2−2 t 2B2 = (1 − t ) 2 B0 + 2t (1 − t ) B1 + t 2 B2
= 0.5  + 0.5  =   +   =   0 1  2
t=0.5  6  1   3   0.5   3.5 
p1 p1

p1

p0 p2 p0 p2

10
02/04/2019

Curva de Bezier Cúbica Algoritmo BezierIngênuo


import sys,pygame x = round(x,0)
3 2 2 3
B (t ) = (1 − t ) B0 + 3t (1 − t ) B1 + 3(1 − t )t B3 + t B4 , t ∈ [0,1] from pygame import gfxdraw y = round(y,0)

3
 3 pygame.init() screen.set_at((x,y), white)

B (t ) = ∑   ⋅ (1 − t )3−k t kBk screen = pygame.display.set_mode((400,400))


screen.fill((0,0,0))
pygame.display.flip()

k =0  k  pygame.display.flip() bezierIngenuo(10,10,50,50)

 3  3  3  3 white=(255,255,255) while 1:
=   ⋅ (1 − t )3−0 t 0B0 +   ⋅ (1 − t )3−1t1B1 +   ⋅ (1 − t )3−2 t 2B2 +   ⋅ (1 − t )3−3 t 3B3 for event in pygame.event.get():
 0 1  2  3 #Esta funcao funciona apenas if event.type == pygame.QUIT: sys.exit()
#para o primeiro quadrante
def bezierIngenuo(p1,p2,p3,p4):
for t in xrange(0,1,0.01):

p1 p1 omt = 1-t
omt2 = omt*omt
omt3 = omt2*omt
t2 = t*t
t3 = t2*t
x = omt3 * p1[0] + ((3*omt2)*t*p1[0]) +
(3*omt*t2*p3[0])+t3*p4[0]
y = omt3 * p1[1] + ((3*omt2)*t*p1[1]) +
(3*omt*t2*p3[1])+t3*p4[1]
p0 p2 p0 p2

Hermite ↔ Bezier Hermite ↔ Bezier


As curvas são equivalentes;
Tangentes nos pontos terminadores
É possível formular curvas de Bezier de maneira linear;
p4 R4=3(p4-p3) são definidas por pontos Primeiro, relacionamos a geometria de uma curva de Hermite
p3 com a geometria de uma curva de Bezier:
intermediários;
Porque “3”? Porque não R1=(p2-p1);
 P1   1 0 00  P1 
Pense em 4 pontos espaçados P   0 0 01   P2 
R3=3(p2-p1) igualmente em uma linha! GH =  4  =  ⋅
 R1  − 3 3 0 0  P3 
     
 R4   0 0 − 3 3  P4 
p2
p1 p2 p3 p4 GH = M HBGB
p1

Hermite ↔ Bezier Hermite ↔ Bezier


Q (t ) = TM H GH  2 −2 1 1 1 0 0 0  − 1 3 − 3 1
GH = [ P1 , P4 , R1 , R4 ]T , T = [t 3 , t 2 , t ,1]  − 3 3 − 2 − 1  0 0 0 1   3 − 6 3 0
M B = M H M HB =  ⋅ =
 2 −2 1 1 0 0 1 0  − 3 3 0 0  − 3 3 0 0
     
− 3 3 − 2 − 1 1 0 0 0 0 0 −3 3  1 0 0 0
MH =  
0 0 1 0 Q (t ) = TM BGB
 
1 0 0 0
( ) ( ) (
 − t 3 + 3t 2 − 3t + 1 x1 + 3t − 6t 2 + 3t 3 x2 + 3t 2 − 3t 3 x3 + t 3 x4 )

Q (t ) = TM H M HBGB ( ) ( ) (
Q (t ) =  − t 3 + 3t 2 − 3t + 1 y1 + 3t − 6t 2 + 3t 3 y2 + 3t 2 − 3t 3 y3 + t 3 y4 )
 − t 3 + 3t 2 − 3t + 1 z + 3t − 6t 2 + 3t 3 z + 3t 2 − 3t 3 z + t 3 z
( ) ( ) ( )
 1 2 3 4

( ) ( ) (
Q (t ) = P1 − t 3 + 3t 2 − 3t + 1 + P2 3t 3 − 6t 2 + 3t + P3 − 3t 3 + 3t 2 + P4t 3 )

11
02/04/2019

O que mais há em relação a curvas? Splines


Usando o algoritmo de Casteljau, curvas de Hermite e Curvas de facto usadas em pacotes de 3D;
finalmente curvas de Bezier, é possível modelar qualquer Splines Cúbicas Naturais são curvas polinomiais
curva; cúbicas com continuidades C0, C1 e C2;
De fato, curvas de Bezier podem ser encontradas em Possuem um grau de continuidade a mais que as curvas de
muitos softwares, como por exemplo o pacote MS-Office; Bezier e Hermite!
Três fatos nos entanto motivam a busca de novas formas As curvas passam pelos pontos de controle!
de representar curvas: São consideradas mais suaves como elemento de
1. Curvas são computacionalmente caras de se computar; interpolação.
2. Pontos de controle residem fora da curva; O preço a ser pago: Os coeficientes das splines cúbicas
3. A alteração de um ponto de controle implica em possível naturais são dependentes de todos os n (4) pontos de
alterações em todos os pontos da curva. controle;

B-Splines (Basis Splines) B-Spline


Segmentos de curva cujo comportamento depende O segmento i da B-Spline é definido como:
apenas de alguns poucos pontos de controle; Qi (t ) = Ti M BS GBSi
As B-Splines são tratadas de forma um pouco diferente O vetor de geometria que aproxima o segmento Qi
das curvas de Bezier ou Hermite; (definido pelos pontos Pi-3 – Pi)
 Pi −3 
B-Splines são curvas com muitos pontos de controle, mas P 
que são tratadas como uma sequência de segmentos de GBSi =  i −2  ,3 ≤ i ≤ m
 Pi −1 
ordem cúbica;  
 Pi 
BS = P0 P1 ⋅ ⋅ ⋅ Pm , m ≥ 3
A matriz B-Spline base é definida por:
Possui m-2 segmentos. Cada segmentos é denotado por −1 3 − 3 1
Q3 a Qm;  3 −6 3 0
M BS = 1 
6 − 3 0 3 0
Cada um dos m-2 segmentos de curva da B-Spline é  
definido por quatro dos m+1 pontos de controle. 1 4 1 0

B-Spline – Funções de Mistura Exemplos


Blend = TM BS

−1 3 − 3 1
 3 −6 3 0
Blend = t [ 3
t 2
t 11 
]
6 − 3 0 3 0
 
1 4 1 0

( )
B0 = 1 − t 3 + 3t 2 − 3t + 1 Pi = − 1 (t − 1)3 Pi
6 6
(
B1 = 1 3t 3 − 6t 2 + 4 Pi+1
6
)
(
B2 = 1 3t 3 + 3t 2 + 3t + 1 Pi + 2
6
)
B3 = 1 t 3 Pi +3
6

12
02/04/2019

Exemplos Referências
[BRE65] Bresenham, J. E. “Algorithm for Computer Control
of a Digital Plotter,” IBM Systems Journal, 4(1), 1965, 25-30.

13

Você também pode gostar