Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

Bruno Augusto

Buscar array...

Recommended Posts

Bruno, você já tem a composição das cores que 'te servem' e das cores 'a verificar'??

 

Mais ou menos. Eu encontrei dezenas de tabelas de cores RGB, sendo que na maior delas haviam mais de 1500 cores COM NOME.

 

Mas estavam ou embaralhadas ou organizadas entre "shades" ("categorias", digamos assim). Porém tais categorias eram, vez ou outra populadas, com cores completamente incondizentes com a categoria.

 

O que eu fiz foi manualmente (pois até então não tinha algoritimos para trabalhar) separar cada cor em sua categoria.

 

Depois que separei, fui fazer um pente-fino, com calma, e percebi várias inconsistências geradas, em parte pela tela do notebook que uso (é ridículo, um tom de azul visto de perto vira roxo visto de longe).

 

Outras vezes, mesmo à mesma distância, percebia diferenças de categorização entre quando fiz e quando refinei.

 

Pesquisei sobre e vi que esse é o comportamento natural do olho humano e que para minimizar estes efeitos deveria trabalhar com H S L/V/I

 

No fim, como cores finais tidas, estou apenas com as quase 360 puras da variação Hue, como disse acima.

 

A diferença é que não existe 256 na decomposição d, mas 256 convertido em h nos remete a uma cor válida -> 000100

 

Você diz converter um RGB (depois de decomposto) em HSL, por exemplo?

 

Porque não existe lógica em computar o valor de um canal RGB que não existe em qualquer outro ColorSpace.

 

Eu até violei propositalmente todas as exceções que meu programa dispara para ver se é possível tal conversão.

 

De fato é, mas tanto 255 quanto 256 em RGB equivale a 0.921 radianos (52.76°).

Compartilhar este post


Link para o post
Compartilhar em outros sites

Mas concorda comigo que isso é apenas metade da solução? Confesso que nunca havia ouvido falra em nada do que foi dito aqui, logo nem imaginava a solução seguindo essa lógica de pensamento.

 

Ainda não, não chegamos na metade ainda, mas estamos próximos. :D

 

Como ficaria a comparação dos canais de cor nessa árvore? Eu sei que existem "apenas" pouco menos de 360 "cores reais" (de 0 à 360° - sendo que começa e termina em vermelho)

 

Veja só:

 

Imagem Postada

 

 

Basicamente, temos 6 cores e todas as outras derivam dessas.

 

Como a AVL Tree trataria isso para, por exemplo, encontrar um marrom, que apesar de desde a pré-escola sabermos que é uma mistura de vermelho e verde, na realidade, é um descendente de vermelho?

 

Como fica fácil perceber na imagem anterior, temos uma variação de 60º para cada tonalidade e, se utilizarmos também o cálculo do chroma, teremos:

 

Imagem Postada

 

 

Voltando para nossa árvore, utilizaremos tanto a tonalidade quanto o chroma para chegar em:

 

Imagem Postada

 

Se estiver tudo bem até aqui, vamos finalizar nossa AVL para trabalhar com objetos em vez de inteiros.

 

PS: A árvore está espelhada para facilitar a visualização, a ramificação do lado esquerdo será invertida.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Depois de descobrir uma falha primária na minha linha de raciocínio, resolvi estudar a fundo o sistema de composição HSV e tive umas conclusões interessantes a respeito do sistema de angulação.

 

Tratando o croma como uma cônica, podemos posicionar qualquer cor (diferenciável a olho nu ou não) em um cone disposto no sistema de coordenadas cilíndrico.

 

O fator essencial para a existência de qualquer forma neste sistema é a existência de um raio R, representado pelo eixo polar. Quando raio não existe, R=0, não existe forma, no cilindro. Podemos, por consequência ignorar o valor do coeficiente angular φ.

 

O único valor que nos seria de interesse é o eixo longitudinal.

 

 

Podemos estabelecer algumas relações que ajudarão na aplicabilidade dos recursos (que serão destilados pelo JBN [eu é que não vou fazer!]).

 

R -> equivale à saturação

φ -> equivale ao hue

L -> equivale à luminosidade

 

Tratando o croma como um cone de base invertida (o "bico" para baixo) temos:

 

Quando L = 0, não há R, nem φ e a cor é preta.

 

Quando R = 0, não há φ. Temos uma escala de cinza referente a L.

 

Quando R = 1, L também é igual a 1 e dependemos exclusivamente de φ para definir uma cor, que será pura.

 

A regra acima dita que L cresce proporcionalmente a R para todo L <= R

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ah! Danado, se eu tivesse atentado esses dois gráficos na Wikipedia antes... Estava tão focado nos algoritimos de conversão inter ColorSpaces que passou batido.

 

Só não entendi o segundo. De onde veio o cubo do Chroma? Ele está "dentro" do gráfico da Matiz? Foi isso que me pareceu. Mas daí vi o branco, e como ele não pertence ao Matiz e sim à Luminosidade fiquei na dúvida.

 

Então toda "estrutura" dos nós da AVL se baseará nesses pontos-chave, definido pelas "bolinhas" sendo esses valores a base para busca, certo?

 

Agora, para o Evandro.

 

Não sei como seria possível esse Sistema no HSL. Testando minuciosamente percebi que para ser preto a cor tem ter até apenas 2% de Saturação e não única e exclusivamente zero.

 

Para ser branco tem de ter 98.5% à 100% de Luminosidade para ser branco.

 

E 50% de Saturação e 100% de Luminosidade para ser pura (cores do gráfico circular acima, de ângulos definidos)

Compartilhar este post


Link para o post
Compartilhar em outros sites

Modelo cônico de base única (como eu propus)

http://www.ncsu.edu/scivis/lessons/colormodels/hexacone-6.jpg

 

A imagem deriva δφ/δR, restando apenas a integração no eixo longitudinal ʃ(L0-L1).

 

Girando a imagem no HUE, (Integrando ʃ(φ0-φ2π) ), temos um cone invertido.

 

O modelo bicônico, citado por você presente na wikipedia, atende efetivamente ao seu questionamento sobre 50% de luminosidade e 100% de saturação (e não o contrário...

E 50% de Saturação e 100% de Luminosidade para ser pura (cores do gráfico circular acima, de ângulos definidos)

...)

 

http://upload.wikimedia.org/wikipedia/commons/thumb/b/b3/HSL_color_solid_dblcone_chroma_gray.png/197px-HSL_color_solid_dblcone_chroma_gray.png

 

Só não entendi o segundo. De onde veio o cubo do Chroma? Ele está "dentro" do gráfico da Matiz? Foi isso que me pareceu. Mas daí vi o branco, e como ele não pertence ao Matiz e sim à Luminosidade fiquei na dúvida.

Basta girar o cubo na base preto-branco e você tem o mesmo gráfico do último link que eu postei.

 

Quanto à rigorosidade das cores, varia uma porcentagem da acuidade e educação visual de quem enxerga e o tipo de mídia utilizado (qualidade do monitor, projetor, definição de impressão, etc.)

 

Quantas cores você conseguiu destilar exatamente?

 

Existe um padrão de cores p/ web chamado Websafe que se propõe a utilizar cores que possam ser utilizadas - com segurança - em qualquer tipo de mídia, limitada ou não.

 

A sua variação se dá de 51 em 51 valores na escala RGB medida em decimais. Através de algoritmos semelhantes ao que você quer chegar, os dispositivos aproximam qualquer cor de uma das 216 (6³) cores disponíveis.

 

http://en.wikipedia.org/wiki/Web_colors#Web-safe_colors

 

Note que o cone que lhe passei na primeira imagem, segue os padrões websafe.

 

O propósito disso é reduzir ainda mais a sua paleta diminuindo o número de procuras na sua árvore, além de gerar/utilizar um padrão (já existente).

 

Edit Apenas para reforçar, note como a saturação aponta para 240 enquanto a luminosidade equivale exatamente à metade (120).

http://img267.imageshack.us/img267/2591/semttulo1ae.jpg

 

É de vital importância entender essa relação no cone (seja ele duplo ou não) para fins de utilização correta do mapa.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Podemos estabelecer algumas relações que ajudarão na aplicabilidade dos recursos (que serão destilados pelo JBN [eu é que não vou fazer!]).

Na verdade, Evandro, tudo o que precisamos é de um hash map.

 

A implementação de um Hash Map, normalmente, é muito mais complexa do que uma AVL devido ao algorítimo do hash e questões como resolução de colisão.

 

Porém, para nossa felicidade, não precisaremos lidar com isso nesse problema específico.

 

Um Map nada mais é que uma estrutura de dados que armazena um par K => V, onde K é a chave e V é um valor para a chave (ou uma lista de valores).

 

Em um Map, jamais teremos duas chaves que representam o mesmo valor e, exatamente nesse ponto, que está a complexidade do Hash Map que é criar um algorítimo de cálculo de hash com a menor possibilidade de colisão possível.

 

No nosso caso, precisamos do seguinte:

 

Imagem Postada

 

Como conseguimos isso ?

 

Simples, nosso hash será calculado com base no radiano da tonalidade:

 

Vejamos:

 

#B0171F http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 356

#E066FF http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 287

#6C7B8B http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 210

#00C78C http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 162

#32CD32 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 120

#FFFF00 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 60

#838B83 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 120

 

xrad = x * 180º/π

 

Nosso hash:

 

hash(x) = 6 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Se hue for indefinido (tons de cinza)

hash(x) = ( x * 180º/π ) % 6 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Se hue >= 0

 

Dessa forma:

 

0 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de vermelho

1 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de amarelo

2 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de verde

3 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de ciano

4 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de azul

5 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivados de violeta

 

Calculando:

 

#B0171F http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 356

( (x * 180º/π) % 6) => ( (356º * 180º/π) % 6) => 6.2133721370998 % 6 => 0 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Vermelho

 

 

#E066FF http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 287

( (x * 180º/π) % 6) => ( (287º * 180º/π) % 6) => 5.0090949532237 % 6 => 5 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Violeta

 

 

#6C7B8B http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 210

( (x * 180º/π) % 6) => ( (210º * 180º/π) % 6) => 3.6651914291881 % 6 => 3 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Ciano

 

 

#00C78C http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 162

( (x * 180º/π) % 6) => ( (162º * 180º/π) % 6) => 2.8274333882308 % 6 => 2 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Verde

 

 

#32CD32 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 120

#838B83 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 120

( (x * 180º/π) % 6) => ( (120º * 180º/π) % 6) => 2.0943951023932 % 6 => 2 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Verde

 

 

#FFFF00 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Hue: 60

( (x * 180º/π) % 6) => ( (60º * 180º/π) % 6) => 1.0471975511966 % 6 => 1 http://forum.imasters.com.br/public/style_emoticons/default/seta.gif Derivado de Amarelo

 

 

 

Dessa forma temos a chave do nosso Map e podemos utilizar nossa AVL para localizar rapidamente uma determinada cor em um grupo qualquer.

 

Compartilhar este post


Link para o post
Compartilhar em outros sites

Nota: Para quem estiver acompanhando o tópico, por curiosidade ou aprendizado, o operador "%" remete à sua função lógica (programação) que é o operador módulo/resto, e não à aplicação matemática (porcento), que poderia gerar confusão.

 

Estamos fazendo:

 

resto_da_divisão(x, 6);

e não

 

porcento_de(6, x);

João, muito prática a implementação. 2 Perguntas, eu tiro o HUE pelo par RGB? Existe alguma maneira de fazer 2(ou mais) AVL's convergirem para o mesmo objeto?

 

No caso, se eu compreendi corretamente, teremos 7 AVL's (Uma para cada HUE base e uma para tons de cinza). Seria possível fazer 4 AVL's primárias (CMYK like) e as ramificações das RGB se "cruzarem" no caminho, exatamente como acontece com o arco HUE?

 

Edit Utilizando apenas a escala Websafe(216), removendo os tons de cinza (6), teríamos 35 itens por árvore. Removendo o item de topo e dividindo as ramificações teríamos 17 "pra cada lado", correto?

Compartilhar este post


Link para o post
Compartilhar em outros sites

João, muito prática a implementação. 2 Perguntas, eu tiro o HUE pelo par RGB? Existe alguma maneira de fazer 2(ou mais) AVL's convergirem para o mesmo objeto?

 

Sim, o cálculo é feito assim:

 

public function getHue(){
$max = max( array( $this->r , $this->g , $this->b ) );
$min = min( array( $this->r , $this->g , $this->b ) );
$diff = $max - $min;

if ( $diff != 0 ){
	switch ( $max ){
		case $this->r:
			if ( $this->g >= $this->b ){
				return 60 * ( ( $this->g - $this->b ) / $diff );
			} else {
				return 60 * ( ( $this->g - $this->b ) / $diff ) + 360;
			}
		case $this->g:
			return 60 * ( ( $this->b - $this->r ) / $diff ) + 120;
		case $this->b:
			return 60 * ( ( $this->r - $this->g ) / $diff ) + 240;
	}
} else {
	return null;
}
}

 

No caso, se eu compreendi corretamente, teremos 7 AVL's (Uma para cada HUE base e uma para tons de cinza). Seria possível fazer 4 AVL's primárias (CMYK like) e as ramificações das RGB se "cruzarem" no caminho, exatamente como acontece com o arco HUE?

 

Sim,

 

Na verdade, eu terminei a implementação de todo o código já fazem vários dias, estou postando de pouquinho para facilitar a compreensão.

 

Mas a ideia é que possamos fazer isso sim, seja utilizando CMYK ou a paleta PANTONE (por exemplo).

 

Assim que fechar a questão do Map, postarei a implementação da AVL já orientada a objetos e as interfaces para um objeto Comparable e também a implementação do Map.

 

Com essas implementações, faremos uma adaptação para busca por proximidade, que finaliza a solução do problema.

 

;)

Compartilhar este post


Link para o post
Compartilhar em outros sites

De onde veio a conclusão desse módulo 6? Testes intensivos de sua parte ou conclusões de outros trabalhos já conhecidos?

 

Sobre esse mapeamento, porque não foram incluídos o Laranja e o Rosa (que apesar de estar entre o Roxo/Violeta e a segunda aparição de vermelho, ainda possui tonalidades bem distintas)?

 

Sobre a pergunta do Evandro, do CMYK-like, apesar de o padrão CMYK não ser lá muito bem definido, tanto que há até uma citação na Wikipedia quanto a implementação de um algoritimo de conversão CMYK-RGB, qual seria o problema em, dada a cor a ser testada, convertê-la para HSL e comparar com essa mesma AVL?

 

Não será uma detecção perfeita pela própria limitação do CMYK-RGB (eu não consegui uma forma de fazer CMYK-HSL, então, passo por RGB primeiro), mas ainda assim, funcional. Ou não?

Compartilhar este post


Link para o post
Compartilhar em outros sites

De onde veio a conclusão desse módulo 6? Testes intensivos de sua parte ou conclusões de outros trabalhos já conhecidos?

 

É uma aproximação, ao meu modo de ver, bastante eficiente (pelo menos até onde quero chegar), se a margem de erro de 4.5% for grande demais para seu objetivo você pode ajustar o algorítimo.

 

Sobre esse mapeamento, porque não foram incluídos o Laranja e o Rosa (que apesar de estar entre o Roxo/Violeta e a segunda aparição de vermelho, ainda possui tonalidades bem distintas)?

 

Como eu disse para o Evandro, você pode utilizar as 6 cores que eu usei, 4 ou N cores básicas, isso é indiferente. Você decide quantas quer utilizar.

 

Estou apenas demonstrando como resolver o problema e, para facilitar os cálculos, estou utilizando essas 6 (por isso rad(x)%6).

 

EDIT:

 

Não sei se perceberam, mas essas 6 cores, na verdade, são: RGBCMY + K

Compartilhar este post


Link para o post
Compartilhar em outros sites

Não sei se perceberam, mas essas 6 cores, na verdade, são: RGBCMY + K

Perfeitamente, por isso "cunhei" o termo CMYK-like. Continuaríamos a trabalhar no formato RGB/HSL mas, como dividimos em árvores, precisaríamos de uma árvore para a escala de cinza (agiliza muito), daí a separação do blacK, gerando um sistema parecido(like) com CMYK.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, a escala de cinza fica na "posição 6" do nosso Map, qualquer cor que o Hue for indefinido (null) ele estará nessa posição.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Hmmmmm..... Interessante.

 

Quanto a aproximação, sem problemas, era só curiosidade mesmo.

 

So far, so good...

Compartilhar este post


Link para o post
Compartilhar em outros sites

Ok Bruno,

 

Lamento novamente pela demora, muita correria por aqui.

 

Vejamos,

 

IObject.php

 

 

<?php
/**
* Interface para definição de um objeto
*/
interface IObject {
/**
 * Recupera a representação do objeto como string
 * @return string
 */
public function __toString();

/**
 * Verifica se um objeto é igual a outro
 * @return boolean
 */
public function equals( IObject $object );

/**
 * @return ReflectionObject
 * @see IObject::getClass()
 */
public function getClass();

/**
 * Recupera um hash para o objeto
 * @return integer
 * @see IObject::hashCode()
 */
public function hashCode();
}

 

 

Object.php

 

 

<?php
/**
* Implementação de um objeto simples
*/
class Object implements IObject {
/**
 * Recupera a representação do objeto como string
 * @return string
 * @see IObject::__toString()
 */
public function __toString(){
	return sprintf( '%s@%s' , $this->getClass()->getName() , $this->hashCode() );
}

/**
 * Verifica se um objeto é igual a outro
 * @return boolean
 * @see IObject::equals()
 */
public function equals( IObject $object ){
	return $this === $object;
}

/**
 * @return ReflectionObject
 * @see IObject::getClass()
 */
public function getClass(){
	return new ReflectionObject( $this );
}

/**
 * Recupera um hash para o objeto
 * @return integer
 * @see IObject::hashCode()
 */
public function hashCode(){
	return hexdec( spl_object_hash( $this ) );
}
}

 

 

Comparable

 

 

<?php
/**
* Interface para criação de um objeto comparável
*/
interface Comparable extends IObject {
/**
 * Compara um objeto com este objeto
 * @param $b IObject
 * @return integer
 */
public function compare( IObject $b );
}

 

 

NodeBalance.php

 

 

<?php
/**
* Constantes para identificação do tipo de balanceamento dos nós
*/
interface NodeBalance {
/**
 * O nó está pesado do lado direito
 */
const RIGHT_HEAVY = -1;

/**
 * O nó está balanceado
 */
const BALANCED = 0;

/**
 * O nó está pesado do lado esquerdo
 */
const LEFT_HEAVY = 1;
}

 

 

Node.php

 

 

<?php
/**
* Interface para definição de um nó em uma árvore de busca binária
*/
interface Node extends Countable, IObject {
/**
 * Insere um valor qualquer no nó
 * @param $value IObject
 */
public function insert( Comparable $value );

/**
 * Procura um determinado valor
 * @param $value Comparable
 * @return boolean
 */
public function search( Comparable $value );
}

 

 

AVLNode.php

 

 

<?php
/**
* Implementação de um nó de uma árvore auto-balanceada
*/
class AVLNode extends Object implements Node {
/**
 * Nó filho da esquerda
 * @var AVLNode
 */
private $left;

/**
 * Nó pai
 * @var AVLNode
 */
private $parent;

/**
 * Nó da esquerda
 * @var AVLNode
 */
private $right;

/**
 * Valor do nó
 * @var IObject
 */
private $value;

/**
 * Fila de prioridade
 * @var SplPriorityQueue
 */
private static $queue;

/**
 * Constroi o objeto do nó
 * @param $value IObject Um valor qualquer
 */
public function __construct( IObject $value , AVLNode $parent = null ){
	if ( $value->getClass()->implementsInterface( 'Comparable' ) ){
		$this->value = $value;

		if ( $parent !== null ){
			$this->parent = $parent;
		}
	} else {
		throw new UnexpectedValueException( 'O objeto precisa implementar a interface Comparable' );
	}
}

/**
 * Recupera a quantidade de itens do nó
 * @return integer
 * @see Countable::count()
 */
public function count(){
	$ret = 1;

	if ( $this->left !== null ) $ret += $this->left->count();
	if ( $this->right !== null ) $ret += $this->right->count();

	return $ret;
}

/**
 * Recupera a altura do nó
 * @return integer
 */
private function getHeight(){
	$left = $this->left == null ? 0 : $this->left->getHeight();
	$right = $this->right == null ? 0 : $this->right->getHeight();

	return 1 + max( array( $left , $right ) );
}

/**
 * Recupera o fator de balanceamento do nó
 * @return integer
 */
private function getBalance(){
	$left = $this->left == null ? 0 : $this->left->getHeight();
	$right = $this->right == null ? 0 : $this->right->getHeight();

	return $left - $right;
}

/**
 * Insere um valor qualquer
 * @param $value Comparable
 * @see Node::insert()
 */
public function insert( Comparable $value ){
	$cmp = $value->compare( $this->value );

	if ( $cmp == 0 ) return false;

	if ( $cmp < 0 ){
		if ( $this->left == null ) $this->left = new AVLNode( $value , $this );
		else $this->left->insert( $value );

		if ( $this->getBalance() >= NodeBalance::LEFT_HEAVY ){
			if ( $this->left->getBalance() < NodeBalance::BALANCED ){
				$this->left->leftRotation();
			}

			$this->rightRotation();
		}
	} else {
		if ( $this->right == null ) $this->right = new AVLNode( $value , $this );
		else $this->right->insert( $value );

		if ( $this->getBalance() <= NodeBalance::RIGHT_HEAVY ){
			if ( $this->right->getBalance() > NodeBalance::BALANCED ){
				$this->right->rightRotation();
			}

			$this->leftRotation();
		}
	}

	return true;
}

/**
 * Efetua uma rotação a esquerda
 */
private function leftRotation(){
	$parent = $this->parent;

	$right = clone $this->right;
	$this->right = $right->left == null ? null : clone $right->left;
	$right->left = clone $this;
	$right->left->parent = $right;
	$right->parent = $parent;

	foreach ( $right as $property => $value ){
		$this->$property = $value;
	}
}

/**
 * Efetua uma rotação a direita
 */
private function rightRotation(){
	$parent = $this->parent;

	$left = clone $this->left;
	$this->left = $left->right == null ? null : clone $left->right;
	$left->right = clone $this;
	$left->right->parent = $left;
	$left->parent = $parent;

	foreach ( $left as $property => $value ){
		$this->$property = $value;
	}
}

/**
 * Procura um determinado valor
 * @param $value Comparable
 * @return Comparable O item encontrado
 * @see Node::search()
 */
private function realSearch( Comparable $value ){
	$cmp = $value->compare( $this->value );

	if ( $cmp == 0 ) {
		return $this->value;
	} else {
		self::$queue->insert( $this->value , 255 - ( $value->getHue() == null ? -$this->value->getValue() : $this->value->getChroma() ) );

		if ( $cmp < 0 && $this->left != null ) return $this->left->search( $value );
		elseif ( $cmp > 0 && $this->right != null ) return $this->right->search( $value );

		return self::$queue->current();
	}
}

/**
 * Procura um determinado valor
 * @return Comparable O item encontrado
 * @see Node::search()
 */
public function search( Comparable $value ){
	self::$queue = new SplPriorityQueue();

	return $this->realSearch( $value );
}
}

 

 

AVLTree.php

 

 

/**
* Implementação da uma árvore auto-balanceada
*/
class AVLTree extends AVLNode {
/**
 * Nó raiz
 * @var AVLNode
 */
private $root;

/**
 * Constroi a árvore
 */
public function __construct(){}

/**
 * Recupera a quantidade de elementos da árvore
 * @return integer
 * @see Countable::count()
 */
public function count(){
	if ( $this->root == null ) return 0;
	else return $this->root->count();
}

/**
 * Insere um valor qualquer no nó
 * @param $value Comparable
 * @see Node::insert()
 */
public function insert( Comparable $value ){
	if ( $this->root == null ) $this->root = new AVLNode( $value );
	else return $this->root->insert( $value );

	return true;
}

/**
 * Procura um determinado valor
 * @param $value Comparable
 * @return Comparable
 * @see Node::search()
 */
public function search( Comparable $value ){
	if ( $this->root !== null ) return $this->root->search( $value );
	else return false;
}
}

 

 

Color.php

 

 

<?php
interface Color {
public function getChroma();
public function getHue();
}

 

 

RGB.php

 

 

<?php
class RGB extends Object implements Color, Comparable {
private $r = 0;
private $g = 0;
private $b = 0;
private $max = 0;
private $min = 0;
private $name;

public function __construct( $r , $g , $b , $name = null ){
	$this->r = (int) $r;
	$this->g = (int) $g;
	$this->b = (int) $b;

	$this->max = max( array( $this->r , $this->g , $this->b ) );
	$this->min = min( array( $this->r , $this->g , $this->b ) );

	$this->name = $name;
}

/**
 * Recupera a representação hexadecimal da cor
 * @return string
 * @see Object::__toString()
 */
public function __toString(){
	return sprintf( '#%02X%02X%02X' , $this->r , $this->g , $this->b );
}

/**
 * Compara um objeto com este objeto
 * @param $b IObject
 * @return integer
 */
public function compare( IObject $b ){
	$ca = $this->getChroma();
	$cb = $b->getChroma();

	if ( $ca != 0 && $cb != 0 ){
		return $ca - $cb;
	} else {
		return $b->getValue() - $this->getValue();
	}
}

/**
 * Cria um objeto RGB utilizando a representação hexadecimal da cor
 * @param $hex string
 * @throws InvalidArgumentException
 */
public static function createFromHexcode( $hex , $name = null ){
	if ( isset( $hex[ 0 ] ) && $hex[ 0 ] == '#' ) $hex = substr( $hex , 1 );

	if ( isset( $hex[ 5 ] ) ){
		$rgb = array_map( 'hexdec' , str_split( $hex , 2 ) );

		$obj = new RGB( $rgb[ 0 ] , $rgb[ 1 ] , $rgb[ 2 ] , $name );

		return $obj;
	} else {
		throw new InvalidArgumentException( 'O código da cor deve ter os 3 pares hexadecimais.' );
	}
}

public function getChroma(){
	return $this->max - $this->min;
}

public function getHue(){
	$chroma = $this->getChroma();

	if ( $chroma != 0 ){
		switch ( $this->max ){
			case $this->r:
				if ( $this->g >= $this->b ){
					return 60 * ( ( $this->g - $this->b ) / $chroma );
				} else {
					return 60 * ( ( $this->g - $this->b ) / $chroma ) + 360;
				}
			case $this->g:
				return 60 * ( ( $this->b - $this->r ) / $chroma ) + 120;
			case $this->b:
				return 60 * ( ( $this->r - $this->g ) / $chroma ) + 240;
		}
	} else {
		return null;
	}
}

public function getSaturation(){
	if ( $this->max != 0 ){
		return $this->getChroma() / $this->max;
	} else {
		return 0;
	}
}

public function getValue(){
	return $this->max;
}

public function getName(){
	return $this->name;
}

public function getRed(){
	return (int) $this->r;
}

public function getGreen(){
	return (int) $this->g;
}

public function getBlue(){
	return (int) $this->b;
}

/**
 * Recupera o hash do objeto
 * @return integer
 * @see Object::hashCode()
 */
public function hashCode(){
	$h = ( (int) $this->getHue() ) + 360;
	$c = $this->getChroma();
	$s = $this->getSaturation();
	$v = $this->getValue();

	return ($h << 8) + ($c << 4) + ($s << 2) + $v;
}
}

 

 

Shade.php

 

 

<?php
class Shade extends AVLTree {
private $name;
private $hash;

public function __construct( $name , $hue = null ){
	static $PI = null;

	if ( $PI == null ) $PI = pi();

	$this->name = $name;
	$this->hash = $hue === null ? 6 : ( (int) ( $hue * $PI / 180 ) ) % 6;
}

public function getName(){
	return $this->name;
}

public function hashCode(){
	return $this->hash;
}
}

 

 

Shades.php

 

 

<?php
class Shades extends Object implements Node {
private static $PI;
private $hashmap = array();

public function __construct(){
	if ( is_null( self::$PI ) ){
		self::$PI = pi();
	}
}

public function count(){
	$ret = 0;

	foreach ( $this->hashmap as $shade ){
		$ret += $shade->count();
	}

	return $ret;
}

public function map( Shade $shade ){
	$this->hashmap[ $shade->hashCode() ] = $shade;
}

public function insert( Comparable $item ){
	if ( $item instanceof Color ){
		$hue = $item->getHue();
		$key = $hue === null ? 6 : ( (int) ( $hue * self::$PI / 180 ) ) % 6;

		if ( isset( $this->hashmap[ $key ] ) ){
			printf( "Inserindo %s como %s\n" , $item , $this->hashmap[ $key ]->getName() );
			$this->hashmap[ $key ]->insert( $item );
		} else {
			throw new UnexpectedValueException( 'Não existe uma cor base para essa cor' );
		}
	} else {
		throw new InvalidArgumentException( 'Esperávamos uma instância de Color' );
	}
}

public function search( Comparable $item ){

}
}

 

 

 

Usando

<?php
$list = array(
new RGB( 0 , 0 , 0 , 'Black' ),
new RGB( 128 , 0 , 0 , 'Dark Red' ),
new RGB( 255 , 0 , 0 , 'Red' ),
new RGB( 255 , 0 , 255 , 'Pink' ),
new RGB( 0 , 128 , 128 , 'Teal' ),
new RGB( 0 , 128 , 0 , 'Green' ),
new RGB( 0 , 255 , 0 , 'Bright Green' ),
new RGB( 0 , 255 , 255 , 'Turquoise' ),
new RGB( 0 , 0 , 128 , 'Dark Blue' ),
new RGB( 128 , 0 , 128 , 'Violete' ),
new RGB( 0 , 0 , 255 , 'Blue' ),
new RGB( 192 , 192 , 192 , 'Gray 25%' ),
new RGB( 128 , 128 , 128 , 'Gray 50%' ),
new RGB( 128 , 128 , 0 , 'Dark Yellow' ),
new RGB( 255 , 255 , 0 , 'Yellow' ),
new RGB( 255 , 255 , 255 , 'White' ),
);

$shades = new Shades();
$shades->map( new Shade( 'vermelho'	,	0 ) );
$shades->map( new Shade( 'amarelo'	, 60 ) );
$shades->map( new Shade( 'verde'	, 123 ) );
$shades->map( new Shade( 'ciano'	, 180 ) );
$shades->map( new Shade( 'azul'		, 240 ) );
$shades->map( new Shade( 'violeta'	, 300 ) );
$shades->map( new Shade( 'cinza'	, null ) );

foreach ( $list as $rgb ){
$shades->insert( $rgb );
}

 

Saída

Inserindo #000000 como cinza
Inserindo #800000 como vermelho
Inserindo #FF0000 como vermelho
Inserindo #FF00FF como violeta
Inserindo #008080 como ciano
Inserindo #008000 como verde
Inserindo #00FF00 como verde
Inserindo #00FFFF como ciano
Inserindo #000080 como azul
Inserindo #800080 como violeta
Inserindo #0000FF como azul
Inserindo #C0C0C0 como cinza
Inserindo #808080 como cinza
Inserindo #808000 como amarelo
Inserindo #FFFF00 como amarelo
Inserindo #FFFFFF como cinza

A partir desse momento, se tudo tiver sido compreendido, começamos a discutir o algorítimo para melhorar a busca por proximidade e escreveremos nosso próprio heap.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Bom, demorei para postar por estar terminando outra etapa tão importante quanto do sistema.

 

Analisei todos os codigos e surgiram um monte algumas dúvidas. Vou listá-las:

 

No Construtor de AVLNode, o tipo de $value poderia ser Countable, tornando desnecesária a Exception manualmente disparada?

 

Não entendi muito bem os métodos de rotação.

 

Em RGB::compare(), o tipo do parâmetro não deveria ser Color?

 

Em Shade, o que seria static $PI dentro do construtor?

 

Em Shades::insert(), vale a mesma da primeira pergunta, mas sendo o tipo Color

 

Por fim, porquê Shades::search() está vazio? É temporário (próxima etapa)?

 

Sobre as saídas, visualmente algumas cores não batem, como por exemplo #FF00FF

(fuchsia, rosa ou magenta).

 

Para resolver isso possa adicionar novas Shades, com outros ângulos?

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.