Last active
April 19, 2019 23:15
-
-
Save yuigoto/4f836af7c159905f20d44e40ec375f86 to your computer and use it in GitHub Desktop.
[Processing : Pi com Montecarlo] Minha versão para Processing (3.x) do algoritmo para estimar o valor de PI, do vídeo do canal Yarquen.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* ESTIMANDO PI COM MONTECARLO | |
* ============================================================ | |
* | |
* Baseado no vídeo e no sketch P5.js feitos pelo Guilherme Rey | |
* (Yarquen) em https://www.youtube.com/watch?v=VQvw3u-zSZg. | |
* | |
* Assista! É importante para entender bem o que acontece aqui! | |
* | |
* Apesar do P5.js ser uma versão do processing, pelo fato de | |
* ser em JavaScript, algumas coisas funcionam um pouco diferente. | |
* | |
* Este é o meu take de como estimar o valor de PI, de acordo com | |
* o vídeo. Tem algumas peculiaridades do Processing que tentei | |
* explicar, mas podem estar meio mal escritas, portanto: RTFM! :P | |
* | |
* @author Fabio Y. Goto <lab@yuiti.com.br> | |
*/ | |
// GLOBAIS | |
// ============================================================ | |
/** | |
* Raio da circunferência. | |
*/ | |
int r = 500; | |
/** | |
* Total de pontos dentro da circunferência. | |
*/ | |
int n_in = 0; | |
/** | |
* Máximo de pontos a serem criados. | |
*/ | |
int n_max = 50000; | |
/** | |
* Framerate do sketch, diminua isso e a quantidade de pontos se | |
* tiver problemas de performance. | |
*/ | |
int fps = 60; | |
/** | |
* Array para armazenar pontos. | |
*/ | |
Point[] points; | |
// CLASSES | |
// ============================================================ | |
/** | |
* Um objeto de ponto. | |
* | |
* Possui apenas três atributos: x, y e is_in, que indica se | |
* o ponto está dentro, ou não, da circunferência. | |
*/ | |
class Point { | |
float x; | |
float y; | |
boolean is_in; | |
/** | |
* Construtor da classe. | |
* | |
* @var {float} x | |
* @var {float} y | |
*/ | |
Point(float x, float y) { | |
this.x = x; | |
this.y = y; | |
} | |
} | |
// FUNÇÕES AUXILIARES | |
// ============================================================ | |
/** | |
* Adiciona um ponto ao array. | |
*/ | |
void addPoint() { | |
Point coord = getRandomPoint(); | |
boolean is_in = isPointIn(coord); | |
n_in += (is_in) ? 1 : 0; | |
coord.is_in = is_in; | |
// Para adicionar itens ao array no Procesing, você precisa | |
// usar append e, ainda, indicar o tipo de dado. | |
points = (Point[]) append(points, coord); | |
} | |
/** | |
* Desenha a elipse utilizada no vídeo. | |
*/ | |
void drawEllipse() { | |
fill(#009900); | |
noStroke(); | |
ellipse(0, 0, r * 2, r * 2); | |
} | |
/** | |
* Retorna um novo ponto, com uma posição (pseudo-)aleatória. | |
* | |
* @return {Point} | |
*/ | |
Point getRandomPoint() { | |
float _x = random(0, r); | |
float _y = random(0, r); | |
return new Point(_x, _y); | |
} | |
/** | |
* Verifica se um ponto está dentro, ou fora, da circunferência. | |
* | |
* @var {Point} pt | |
* @return {boolean} | |
*/ | |
boolean isPointIn(Point pt) { | |
float square_x = pow(pt.x, 2); | |
float square_y = pow(pt.y, 2); | |
// Hipotenusa é menor ou igual ao raio? | |
return (sqrt(square_x + square_y) <= r); | |
} | |
// EXECUÇÃO | |
// ============================================================ | |
/** | |
* Setup do Processing. | |
*/ | |
void setup() { | |
/** | |
* Definimos o tamanho do canvas aqui, usando o P2D como | |
* renderer, embora seu uso seja opcional, visto que é | |
* o renderer padrão. | |
*/ | |
size(500, 500, P2D); | |
// Define framerate | |
frameRate(fps); | |
// Cria o array (importante fazer isso aqui!) | |
// O "0" é pra criar um array vazio, PRECISA ser declarado! | |
points = new Point[0]; | |
} | |
/** | |
* Update + Desenha. | |
*/ | |
void draw() { | |
// Define fundo + desenha elipse | |
background(0); | |
drawEllipse(); | |
// Vamos adicionar pontos ao array, enquanto possível | |
if (points.length < n_max) { | |
for (int a = 0; a < 100; a++) { | |
addPoint(); | |
} | |
} | |
// Adicionou o ponto? Ótimo, vamos desenhar e tirar estimativa! | |
strokeWeight(3); | |
// Vamos apenas desenhar e testar se length > 0 | |
for (int i = 0; i < points.length; i++) { | |
if (points[i].is_in) { | |
// Tá dentro? | |
stroke(255, 255, 0); | |
} else { | |
// Ou tá fora? | |
stroke(255, 0, 0); | |
} | |
point(points[i].x, points[i].y); | |
} | |
/** | |
* Note que, antes de dividir o valor pelo comprimento do array, | |
* multiplicamos o comprimento por "1.0". | |
* | |
* O motivo? É simples, se você simplesmente dividir (4 * n_in) | |
* pelo valor do comprimento do array, ele "arredonda" o resultado | |
* final para baixo (fica 3.0), visto que points.length é um int. | |
* | |
* Coisa do Processing. :P | |
*/ | |
float pi_value = (4 * n_in) / (points.length * 1.0); | |
println(pi_value); | |
// Desenhando o texto na tela com COMIC SANS, pois TODOS GOSTAM | |
PFont font = createFont("Comic Sans MS", 40, true); | |
textFont(font, 40); | |
fill(0); | |
int text_x = 30; | |
int text_y = 60; | |
// Desenhando uma borda para o texto, já que strokeWidth não funciona. | |
// Deve haver meios melhores que este. :P | |
for (int yy = -2; yy <= 2; yy++) { | |
for (int xx = -2; xx <= 2; xx++) { | |
text("PI: " + pi_value, text_x + xx, text_y + yy); | |
} | |
} | |
fill(0, 255, 255); | |
text("PI: " + pi_value, text_x, text_y); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment