Preenchimento de
Áreas e de Polígonos
(Filled-Area Primitives)
Antonio L. Bajuelos
Departamento de Matemática
Universidade de Aveiro
Preenchimento de Áreas e de Polígonos
Preenchimento de áreas é o processo de coloração do
interior de uma dada área ou região
região..
Ás áreas (ou regiões) podem ser descritas ao nível do:
Pixel –
Ao nível do pixel, à área é descrita ou:
pela totalidade dos pixels que a compreendem ou,
em termos dos pixels-fronteira que a delimitam
Geométrico –
Uma região é descrita em termos de objectos, tais como segmentos de
recta, polígonos, circunferências, etc.
2
Preenchimento de Áreas e de Polígonos
A tarefa de preencher um polígono pode ser dividida em duas:
Decidir que pixels pintar para preencher o polígono
polígono..
Decidir com que valor pintar o pixel
pixel..
Em geral, a decisão sobre quais pixels preencher é feita:
varrendo (scan top-down)
interceptam a primitiva e,
linhas
sucessivas
que
preenchendo da esquerda para a direita, blocos de pixels
preenchendo,
adjacentes que estão dentro da primitiva que define a
região.
3
Preenchimento de Áreas e de Polígonos
Rectângulos
Iremos assumir que:
O rectângulo é coerente no espaço i.e. que mantém a sua figura
geométrica (forma), sem alterações internas e que a cor dos seus
pixels ao longo da figura não varia.
Esta propriedade é importante e será explorada no processo de
preenchimento de regiões.
Para preencher um rectângulo com uma única cor, pinta-se cada pixel
dentro de uma linha de varrimento da esquerda para a direita com o
mesmo valor de pixel, isto é, pode-se preencher cada "bloco" de xmin a
xmax.
Para y = ymin até ymax do rectângulo
Para x = xmin até xmax
write_pixel (x, y, valor)
{Por linha de varrimento }
{Cada pixel dentro do bloco}
4
Preenchimento de Áreas e de Polígonos
Rectângulos (cont …)
Consideremos agora dois rectângulos que compartilham um mesmo lado.
Atenção! Se preenchermos cada rectângulo isoladamente, o lado
(aresta) compartilhado pelos dois será gerado duas vezes o que não é
desejável.
Surge então o problema de definição de área pertencente a cada
primitiva, isto é, quais os pixels que pertencem a cada primitiva e
quais os pixels que não.
De forma natural, podemos definir os pixels que matematicamente se
encontram no interior de uma área definida pela primitiva, como
pertencente a ela.
Mas como podemos definir os pixels que estão
no limite da primitiva?
5
Preenchimento de Áreas e de Polígonos
Rectângulos (cont …)
Uma solução de “compromisso”:
Os pixels que estão sobre os lados (arestas) esquerdo e
inferior pertencem a primitiva e serão desenhados,
porém os lados superior e direito não pertencem a
primitiva e portanto não serão desenhados
Assim, uma aresta vertical compartilhada por dois rectângulos
pertencem ao lado que está mais a direita.
Os blocos dentro de um rectângulo representam um intervalo que é
fechado a esquerda e em baixo e aberto em cima e a direita
6
Preenchimento de Áreas e de Polígonos
Rectângulos (cont …)
Algumas considerações devem ser feitas sobre esta regra:
A regra se aplica da mesma forma a polígonos arbitrários e não
somente a rectângulos.
O vértice do canto inferior esquerdo ainda continua sendo
desenhado duas vezes.
A regra faz com que em cada bloco esteja faltando o seu pixel mais
a direita, e em cada rectângulo fique faltando o seu lado (aresta)
superior.
Os problemas apresentados nas considerações acima
demonstram que não há solução perfeita para o problema de
não escrever mais de uma vez linhas que sejam
potencialmente compartilhadas por mais de um polígono
polígono..
7
Preenchimento de Áreas e de Polígonos
Preenchimento por Gérmen
Neste tipo de métodos o utilizador
deverá indicar um pixel inicial chamado
gérmen (seed). Este gérmen deve estar
no interior do polígono.
A partir do gérmen
gérmen, o algoritmo
inspecciona os pixels adjacentes para
determinar se toda a região já foi
coberta.
O processo é repetido até que todos os
pixels do interior da região tenham sido
inspeccionados.
Este tipo de métodos de preenchimento
é indicado para aplicações interactivas.
8
Preenchimento de Áreas e de Polígonos
Preenchimento por Gérmen
Existem dois tipos básicos de preenchimento por gérmen
gérmen:
Preenchimento por Saturação (Flood
Flood--Fill
Fill))
Este método é utilizado quando a fronteira da região é
monocromática. O objectivo é, a partir do gérmen P,
determinar a maior região ligada de pontos cujo cor (valor de
pixel) é igual ao valor de P.
Preenchimento por Fronteira (Boundary
Boundary--Fill
Fill))
Este método é usualmente utilizado quando a fronteira da
região pode ser definida por primitivas policromáticas. Neste
caso o objectivo é determinar a maior região ligada de pontos
cujo cor (valor de pixel) não é igual ao valor da fronteira.
9
Preenchimento de Áreas e de Polígonos
Preenchimento por Gérmen
Os algoritmos do tipo Flood
Flood--Fill e do tipo Boundary
Boundary--Fill
podem ser implementados na versões 4 ou 8-connected
4 movimentos: N, S , E, W
8 movimentos: N, S , E, W, NE, NW, SE, SW
A versão 4-connected é mais rápida mas NÃO garante a
cobertura de todos os tipos de regiões
Estes algoritmos são altamente recursivos podendo gerar
problemas de stack overflow (utilização excessiva de
memória)
10
Preenchimento de Áreas e de Polígonos
Algoritmo Boundary
Boundary--Fill
(Versão 4-connected)
void BoundaryFill4(int x, int y, color newcolor, color edgecolor)
{
int current;
current = ReadPixel(x, y);
if(current != edgecolor && current != newcolor)
{
BoundaryFill4(x+1, y, newcolor, edgecolor);
BoundaryFill4(x-1, y, newcolor, edgecolor);
BoundaryFill4(x, y+1, newcolor, edgecolor);
BoundaryFill4(x, y-1, newcolor, edgecolor);
}
}
11
Preenchimento de Áreas e de Polígonos
Algoritmo Flood
Flood--Fill
(Versão 4-connected)
void FloodFill4(int x, int y, color newcolor, color oldColor)
{
if(ReadPixel(x, y) == oldColor)
{
FloodFill4(x+1, y, newcolor, oldColor);
FloodFill4(x-1, y, newcolor, oldColor);
FloodFill4(x, y+1, newcolor, oldColor);
FloodFill4(x, y-1, newcolor, oldColor);
}
}
* Replace a specified interior color (old color) with fill color
12
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
O algoritmo que vamos discutir a seguir é válido para
polígonos de forma arbitrário (côncavos e convexos).
Inclusive funciona para polígonos com auto-intersecções
e/ou buracos.
Este algoritmo opera determinando blocos de pixels que
estão entre os lados mais à esquerda e mais à direita do
polígono.
13
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Ideias básicas
Calcula o preenchimento sempre entre as arestas mais à
esquerda e mais à direita
Incrementalmente calcula a intersecção da linha raster
(scan line) com as arestas do polígono, a partir da
anterior linha raster
14
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Na figura: as intersecções da linha de varrimento 8 com os lados FA
e CD possuem coordenadas inteiras, enquanto as intersecções com
os lados EF e DE possuem coordenadas reais (não inteiras).
É preciso determinar que pixels da linha de varrimento estão dentro
do polígono.
No exemplo da figura: Os blocos para x = 2 até 4 e 9 até 13 com
seu valor apropriado.
15
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Algumas observações
Devemos nos preocupar com a definição dos pontos extremos do
polígono, i.e. não podemos desenhar pixels que não pertençam
verdadeiramente ao interior do polígono, pois podemos estar invadindo o
domínio de outro polígono
É preferível traçar apenas os pixels que estejam estritamente na
região definida pelo polígono, mesmo que um pixel exterior esteja
mais próximo a aresta real.
real.
16
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
O processo de preencher os polígonos pode ser dividido em
três passos:
Obter a intersecção da linha de varrimento com todos os
lados do polígono.
Ordenar os pontos de intersecção (por incremento da
coordenada x).
Preencher os pixels entre pares de pontos de intersecção
do polígono que são internos a ele. Para determinar
quais os pares que são internos ao polígono, podemos
usar a regra de Paridade
17
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Regra da Paridade
Paridade::
Iniciando com par, sempre que encontra uma intersecção inverte a
paridade.
O pixel é pintado quando a paridade é impar
O pixel NÃO é pintado quando é par.
18
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Caso I: Se a intersecção é um valor
fraccionário, como determinar qual o
pixel que deverá ser tomado para que
fique interior ao polígono?
O valor deverá ser arredondado de
forma a que o ponto fique dentro do
polígono. Passos a seguir:
Se estamos dentro do polígono
(paridade ímpar) e atingimos uma
intersecção fraccionária pela direita
(exemplo, o ponto b), arredondamos a
coordenada x da intersecção para
baixo.
Se estamos fora do polígono (paridade
par) arredondamos para cima(exemplo,
o ponto c). Isso garante que sempre
teremos um ponto dentro do polígono.
19
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Caso II: Como tratar o caso de
intersecção com coordenadas inteiras?
Pode-se utilizar o critério visto
anteriormente, para evitar conflitos
entre
lados
compartilhados
em
rectângulos. Passos a seguir:
Se a coordenada x de um pixel mais a
esquerda de um bloco (span) é inteira
ele é definido como interno (exemplo, o
ponto a).
Se a coordenada x do pixel mais a
direita de um bloco é inteira, ele é
definido como externo ao polígono
(exemplo, o ponto d).
20
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Caso III: Como tratar o caso II para
vértices que são compartilhados por mais
de uma aresta do polígono?
Usamos a técnica de paridade. Ou seja:
Contamos o vértice de ymin de um lado
para alterar a paridade, mas não
contamos o vértice de ymax, dessa forma
o vértice de ymax é desenhado somente
se ele é o vértice de ymin do lado
adjacente.
Assim ambos os lados e blocos são
tratados como intervalos que são
fechados em seu valor mínimo e
abertos em seu valor máximo.
Exemplo: Na figura, o vértice
A é contado uma vez no
cálculo de paridade porque é
o vértice de ymin para o lado
FA, mas é também o vértice
de ymax para o lado AB.
21
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Ilustração do algoritmo:
Para a linha de varrimento y = 8:
Os pixels serão preenchidos a partir do ponto
a (coordenadas (2,8)), até o primeiro pixel a
esquerda do ponto b (coordenadas (4,8));
E do primeiro pixel a direita do ponto c
(coordenadas (9,8)) até o primeiro pixel a
esquerda do ponto d (coordenadas (12,8)).
Para a linha de varrimento y = 3:
O vértice A conta uma vez porque é o vértice
de ymin do lado FA (e é também o vértice ymax
do lado AB), isto causa paridade ímpar, assim
o bloco é desenhado a partir de A até um
pixel a esquerda da intersecção com o lado
CB, onde a paridade é estabelecida como par
e o bloco é terminado.
22
Preenchimento de Áreas e de Polígonos
Preenchimento de Polígonos (ScanScan-Line Algorithm
Algorithm))
Ilustração do algoritmo (cont…):
Para a linha de varrimento y = 1
Ela passa apenas pelo vértice B, e os lados AB
e BC tem como vértice de ymin o vértice B, o
qual é dessa forma contado como paridade par.
Este vértice actua como um bloco nulo, pois a
linha de varrimento entra pelo vértice, desenha
o pixel e sai por ele mesmo.
Assim, o pixel que corresponde ao ponto B
não é pintado.
Isso acontece com a intersecção da linha de
varrimento 9 com o vértice F, compartilhado
pelos lados FA e EF. Para ambos os lados, F é
vértice ymax, e dessa forma não afecta a
paridade, que continua par.
23
Preenchimento de Áreas e de Polígonos
Slivers (tiras)
Existe um outro problema com o nosso algoritmo de
conversão matricial: polígonos com lados muito
próximos criam um sliver
Sliver - uma área poligonal tão estreita que seu interior não
contém um bloco de pixels para cada linha de varrimento
(ver figura).
Devido à regra de que são traçados apenas os pixels que
estejam no interior ou sobre arestas inferiores ou a
esquerda, podem existir muitas linhas de varrimento com
um único pixel, ou sem nenhum.
Para melhorar a aparência nesses casos, pode-se usar
técnicas de antialiasing (se tivermos múltiplos bits por
pixel).
Antialiasing implicaria em "suavizar" nossa regra de
"traçar apenas pixels que estejam no interior ou numa
aresta inferior ou à esquerda"
24
Download

Preenchimento de Áreas e de Polígonos