Recentemente, inserido num projecto extenso – e não quero falar sobre isso! – uma das fases consistia em dividir um círculo em fatias, de forma dinâmica. O grafismo é relativamente simples, basta usar uns lineTo’s e uns curveTo’s, tudo pintalgado com uns fills, e a coisa ia fluida. Quanto à matemática inerente, também me parecia bastante simples, basicamente é dividir um círculo completo pelo número de fatias.

O Actionscript, como quase todas as linguagens de programação, trabalha em radianos, o que acaba por ser, até, intuitivo. Aprende-se para aí no 7º ano que um círculo são 2 x PI, que corresponde aos 360 graus. Posto isto, o código era, aparentemente, trivial e croquetes:

// gráfico onde vamos desenhar as fatias
var gfx:Graphics = container.graphics;
// raio da tarte
var raio:Number = oMeuRaio;
// angulo de cada fatia
var angulo:Number = (Math.PI * 2) / numFatias;

// i é incrementado o angulo correspondente às fatias a cada passagem
for(var i:Number = 0; i < (Math.PI * 2); i += angulo)
{
    // mover para o centro do círculo
    gfx.moveTo(0, 0);
    // linha até ao limite da tarte
    gfx.lineTo(raio * Math.cos(i), raio * Math.sin(i));
}

Parece bastante simples e intuitivo, certo? Durante algumas horas, a coisa rolou maravilhosamente. Até que reparei que, nalgumas situações, era desenhada uma fatia extra por cima da primeira. Uma das situações onde isso acontecia era quando a quantidade de fatias era igual a seis. Alguns trace’s mais tarde, dei com o gato e, depois de praguejar durante alguns minutos contra a Adobe, a solução foi feita com um mínimo de esforço. Mas vamos ao gatinho primeiro…

Acontece que o Actionscript só tem um tipo de dados capaz de aguentar números com vírgula flutuante, o tipo Number. E também acontece que o tipo Number, tal como foi implementado, usa 64 bits, mas apenas 52 dos quais para os algarismos significativos, estando reservados 11 para um possível expoente (o outro bit que falta é o do sinal). Isto é, para inteiros é excelente e com um alcance fantástico, para números precisos… nem por isso. Além disso, e sendo PI uma constante estática da classe Math, o número está guardado como Number, pelo que a sua precisão é, evidentemente, limitada. Não esquecer que PI, até prova em contrário, é uma dízima infinita. Então, a representação de PI é 3,141592653589793. Reparem como é extremamente limitada.

No nosso caso em concreto, e para que se possa ver precisamente em que poço caí, a tabela de atribuições foi a seguinte, para 6 fatias (reparem na precisão dos números, devido ao tipo Number):

Passagem i += 1,0471975511965976 i < 6,283185307179586
1 0 sim
2 1,0471975511965976 sim
3 2,0943951023931953 sim
4 3,141592653589793 sim
5 4,1887902047863905 sim
6 5,235987755982988 sim
7 6,283185307179585 sim

Ups! Quando tinha tudo para bater certo, a precisão do Number fintou-nos! Mesmo no último algarismo significativo, pimba. Moral da história: não usarás o tipo Number quando precisares de precisão. No caso concreto, a solução foi extremamente simples, como poderão ver abaixo. Para outros casos, o Actionscript pode ser um grande ninho de cobras. Beware.

// gráfico onde vamos desenhar as fatias
var gfx:Graphics = container.graphics;
// raio da tarte
var raio:Number = oMeuRaio;
// angulo de cada fatia
var angulo:Number = (Math.PI * 2) / numFatias;

// i é incrementado por número de fatias
for(var i:int= 0; i < numFatias; i ++)
{
    // mover para o centro do círculo
    gfx.moveTo(0, 0);
    // linha até ao limite da tarte
    gfx.lineTo(raio * Math.cos(i * angulo), raio * Math.sin(i * angulo));
}
Partilhar no Sapo Links Partilhar no del.icio.us Partilhar no Digg Partilhar no Twitter Partilhar no StumbleUpon Partilhar no MySpace Partilhar no Facebook

Comentários Deixar um comentário

 Categorias
 Arquivo
 Projectos em Destaque
 Últimas Postas no Blog
 Últimos Comentários do Blog