Bitmaps em AdvPL – Parte 04

Introdução

No post anterior, vimos como desenhar uma reta. Que tal ver por dentro como funciona um algoritmo de pintura ?

Pintura

A pintura de uma determinada área de um Bitmap parte do ponto que desejamos substituir uma determinada cor a partir de um ponto, onde todos os pontos adjacentes também tenham a sua cor substituída, se os pontos adjacentes ainda não estão da cor desejada, e são da mesma cor que o ponto inicial.

Por exemplo: Na imagem abaixo, eu quero pintar a meia-lua ou semi-círculo azul do lado esquerdo da cor branca. A imagem em azul é delimitada pelo losango em cor amarela. Logo, a cor azul somente deve ser trocada para branco dentro desta imagem, sem alterar demais pontos.

paint01

Quando usamos o Paint, e a ferramenta de pintura, selecionamos a cor branca e acionamos a pintura dentro da meia-lua azul do lado esquerdo, obtemos o seguinte resultado:

paint02

O mesmo resultado é obtido usando o método Paint() da classe ZBITMAP, informando a coordenada de um ponto qualquer dentro da área do semi-círculo, e setando a cor de pintura para branco.

Método Paint()

Sem maiores delongas, vamos ver como o algoritmo descobre o que pode e até onde pode ser mexido na imagem ao executar a pintura.

METHOD Paint(nL,nC,nColor)  CLASS ZBITMAP
Local nPColor 
Local aPaint := {}                   
Local nCurrent
Local nLNext, nCNext
Local nPL, nPC, nPColor

IF nColor = NIL 
	nColor := ::nFRColor
Endif

// Pega a cor do ponto atual 
nPColor := ::GetPixel(nL,nC)

aadd(aPaint,{nL,nC})

While len(aPaint) > 0 

	// Pega o primeiro ponto pendente
	nPL := aPaint[1][1]
	nPC := aPaint[1][2]

	// Remove das pendencias
	aDel(aPaint,1)
	aSize(aPaint,len(aPaint)-1)
	
	// Pega a cor desta coordenada
	nCurrent := ::GetPixel(nPL,nPC)
	
	If nCurrent <> nColor .and. nCurrent == nPColor

		// Se o ponto nao tem a cor final, e é da cor 
		// do ponto original, pinta ele 
		::SetPixel(nPL,nPC,nColor,1)      
		
		// ao pintar um ponto, seta os pontos adjacentes
		// como pendencias caso eles tambem precisem ser pintados
 
		// Ponto superior
		nLNext := nPL-1
		nCNext := nPC
		If nLNext >= 0 
			nCurrent := ::GetPixel(nLNext,nCNext)
			If nCurrent <> nColor .and. nCurrent == nPColor
				aadd(aPAint,{nLNext,nCNext}) 
			Endif
		Endif
		
		// Ponto inferior
		nLNext := nPL+1
		nCNext := nPC
		If nLNext < ::nHeight 
			nCurrent := ::GetPixel(nLNext,nCNext)
			If nCurrent <> nColor .and. nCurrent == nPColor
				aadd(aPaint,{nLNext,nCNext}) 
			Endif
		Endif

		// Ponto a direita
		nLNext := nPL
		nCNext := nPC+1
		If nLNext < ::nWidth
			nCurrent := ::GetPixel(nLNext,nCNext)
			If nCurrent <> nColor .and. nCurrent == nPColor
				aadd(aPaint,{nLNext,nCNext}) 
			Endif
		Endif

		// Ponto a esquerda
		nLNext := nPL
		nCNext := nPC-1
		If nLNext >= 0
			nCurrent := ::GetPixel(nLNext,nCNext)
			If nCurrent <> nColor .and. nCurrent == nPColor
				aadd(aPaint,{nLNext,nCNext}) 
			Endif
		Endif
		
	Endif

Enddo

Return

Observações

O método de pintura trabalha com uma lista de pontos pendentes de verificação. Cada ponto setado acrescenta os pontos adjacentes horizontais e verticais que são candidatos a serem setados, e cada iteração remove um ponto da pendência, pinta se necessário, e acrescenta os demais candidatos. Dessa forma, ele não ultrapassa o limite da parte da imagem a ser pintada, mesmo que a cor dos pontos desse limite sejam da mesma cor que está sendo usada na pintura.

Depois de criar o algoritmo e usá-lo, eu foi buscar e encontrei uma referência a esta técnica, chamada de “Flood Fill” — e descobri que eu implementei exatamente um pseudo-código alternativo usando lista de pendências — sem usar recursão. O pseudo-código é praticamente o que eu escrevi em AdvPL 😀 Para mais informações, veja as referências no final deste post.

Conclusão

Apenas setando um ponto, traçando retas e círculos, já podemos fazer coisas interessantes. Vai ficar mais interessante ainda quando eu acrescentar o que falta … 😀

Agradeço a todos novamente pela audiência, e desejo a todos TERABYTES DE SUCESSO !!!

Referências

 

 

Um comentário sobre “Bitmaps em AdvPL – Parte 04

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Google

Você está comentando utilizando sua conta Google. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s