Primeira vez aqui? Seja bem vindo e cheque o FAQ!
x

Arte generativa

+2 votos
27 visitas
perguntada Set 19 em Ciência da Computação por Felipe Yudi (21 pontos)  
editado Set 20 por Felipe Yudi

O exercício pede para que reproduzamos as seguintes figuras:

A imagem será apresentada aqui.

A imagem será apresentada aqui.

A imagem será apresentada aqui.

Compartilhe
comentou Set 20 por danielcajueiro (5,726 pontos)  
Felipe, vc colocou a pergunta e tb a respondeu no mesmo lugar.
comentou Set 20 por Felipe Yudi (21 pontos)  
Problema corrigido

1 Resposta

+2 votos
respondida Set 20 por Felipe Yudi (21 pontos)  

Para isso vamos utilizar o Python e um módulo chamado turtle, que é usado para fazer desenhos.

Exploremos as funções básicas do turtle:
Para desenhar uma linha reta, basta usar o código:

import turtle 
turtle.forward(200)

Que gerou:
A imagem será apresentada aqui.
Onde forward indica a direção para a qual o ponteiro anda e (200) é a distância que ele percorre.

Você deve ter percebido que a velocidade com que o ponteiro se move foi relativamente lenta e que o desenho desapareceu! Para evitar isso, utilize os códigos:

turtle.speed("fastest")

e

turtle.done()

Respectivamente no início e no final de seu script.
Vamos agora fazer algo mais complexo, como um quadrado. Para isso, devemos instruir o ponteiro a se mover para frente e depois virar 90 graus quatro vezes seguidas:

import turtle

turtle.forward(200)
turtle.left(90)
turtle.forward(200)
turtle.left(90)
turtle.forward(200)
turtle.left(90)
turtle.forward(200)

turtle.done()

A imagem será apresentada aqui.

Note também que é possível utilizar um loop for para desenhar o mesmo quadrado:

import turtle

for i in range(1,5):
    turtle.forward(200)
    turtle.left(90)

turtle.done()

Ótimo! Estamos prontos agora para começar a reproduzir as imagens.
Note que cada imagem é a rotação de uma reta acrescida de alguns efeitos. O seguinte código servirá de base para construírmos as figuras:

import turtle

turtle.speed("fastest")

for angle in range(0, 361, 1):
    turtle.pencolor() #ajusta a cor do traço. É preta caso não haja nenhum argumento.
    turtle.pensize(1) #ajusta a largura da linha.
    turtle.setheading(angle) #posiciona o ponteiro no ângulo definido no loop.
    turtle.forward(200)  #desenha uma linha no sentido do ângulo definido no loop.
    turtle.backward(200) #desenha uma linha no sentido oposto à linha anterior.


turtle.done()

Ele gera a figura:
A imagem será apresentada aqui.

O Código acima desenha uma figura semelhante a um círculo. Na verdade, o que estamos fazendo é tomar um intervalo de 0 a 360 graus e pedindo ao Python para que ele ajuste o ponteiro no ângulo 0, desenhe uma linha com tamanho 200 e depois desenhe outra linha de mesmo comprimento na direção oposta (isso faz com que o ponteiro volte ao lugar de origem). O Python repete então essa tarefa para todos os ângulos até 360.

Vamos começar agora a desenhar as figuras:

Figura 4.12:
O desafio aqui é dar o efeito degradê à figura.
Podemos facilmente modificar a cor de uma linha com o turtle. Para isso, basta digitar o nome de uma cor (entre aspas) em turtle.pencolor().
Por exemplo:

import turtle

turtle.speed("fastest")

turtle.pencolor("red")
turtle.forward(200)

turtle.done()

Deve produzir uma linha vermelha:
A imagem será apresentada aqui.

Há várias maneiras de representar cores e seus tons. Felizmente, já existem 100 tonalidades da cor cinza (e apenas da cor cinza) embutidas no Python. São elas grey0 (a mais escura) até grey100 (a mais clara). Vamos fazer uso dessa vantagem e de um loop para conseguirmos o efeito degradê.

O código que replica a imagem 4.12 é o seguinte:

import turtle
turtle.speed(0)

for angle in range(0, 181, 1): 
    n=str(int(angle/2)) #criando a escala de cinza
    cinzas="grey"+n

    turtle.pencolor(cinzas)
    turtle.pensize(1)

    turtle.setheading(angle+5) #posiciona o ponteiro em um ângulo 5 graus acima do ângulo do loop e “inclina” a figura.
    turtle.forward(300)
    turtle.backward(300)

    turtle.setheading(angle+185) #desenha uma linha idêntica a anterior na direção oposta.
    turtle.forward(300)
    turtle.backward(300)

turtle.done()

E o resultado final é:
A imagem será apresentada aqui.

A estratégia aqui foi utilizar o próprio ângulo definido no loop para fazer a mudança de cores. Em primeiro lugar, definimos um intervalo de 0 a 180 para os ângulos. Depois, dividimos o ângulo por dois e convertemos para um inteiro e depois para uma string. Isso gera um número n (que na verdade é uma string) que vai de 0 a 90. Convertemos primeiro para inteiro porque o Python não aceitaria a cor grey2.0, por exemplo, mas aceita a cor grey2. Além disso, é preciso que o nome da cor seja uma string. Daí a necessidade de converter n para tal formato.
Criamos então uma escala de cores que vai do grey0 até o grey90 utilizando o próprio ângulo do loop!
O restante do código apenas pede para que o programa desenhe uma linha com base no ângulo e na cor definidas no loop. Note que isso é feito duas vezes em um mesmo loop: da primeira vez, desenha-se uma linha de comprimento 300, volta-se a posição original e após isso desenha-se outra linha na posição oposta.

Figura 4.13:

Reproduzir a figura 4.13 exigirá que utilizemos um tipo especial de ruído conhecido como Ruído de Perlin. Ao contrário de um ruído tradicional, o Ruído de Perlin pode ser utilizado para criar estruturas aleatórias, mas que aparentam ser mais naturais e/ou onduladas.

A imagem será apresentada aqui.
A imagem acima foi extraída da página
https://medium.com/@yvanscher/playing-with-perlin-noise-generating-realistic-archipelagos-b59f004d8401
A figura da esquerda foi criada utilizando um ruído tradicional e a da direita o Ruído de Perlin.

Para utilizar o Ruído de Perlin em Python e necessário baixar o módulo noise, que contém a função pnoise1.
Caso tenha problemas ao baixar o módulo, siga as instruções contidas no link abaixo:
https://www.scivision.dev/python-windows-visual-c-14-required/

A função pnoise1 leva quatro parâmetros:
1- Escala: determina a “distância” da qual se verá a figura.
2- Oitavos: quantidade de detalhes que o ruído terá. Cada oitavo é uma camada de detalhe. Quanto mais oitavos, mais detalhado será o ruído.
3- Lacunosidade: determina quanto detalhe é adicionado ou removido em cada oitavo. Se a lacunosidade for maior que 1, cada oitavo adicionará mais detalhes. Se for igual a um, cada oitavo adiciona o mesmo nível de detalhe. Se for menor que um, cada oitavo fica cada vez mais suave.
4- Persistência: o quanto cada oitavo contribui para o formato da figura. Uma persistência maior que 1 faz com que nos aproximemos de um ruído convencional.

O código que reproduz a figura 4.13 é:

import turtle
import noise

turtle.speed("fastest")

for angle in range(0, 361, 2): 
    turtle.pencolor("black")
    turtle.pensize(1)

    n=noise.pnoise1(-1*angle+100, 7, 10, 0.5) #gera um número de perlin a partir do ângulo

    turtle.setheading(angle) 
    turtle.forward(200+n*100) #ao adicionar n aqui, conseguimos modificar o tamanho de cada linha.
    turtle.backward(200+n*100)

    turtle.setheading(angle+181) 
    turtle.forward(200+n*100)
    turtle.backward(200+n*100)


turtle.done()

E gera uma figura similar a:
A imagem será apresentada aqui.

Aqui utilizamos o ângulo do loop para modificar o parâmetro da escala na função pnoise1. Os outros parâmetros foram testados a fim de suavizar as curvas da borda da figura. Note também que o código desenha dois círculos, pois desta vez definimos um intervalo de 0 a 360 graus, o que foi feito para atingir um efeito parecido ao da figura original.
É importante ressaltar que por se tratar de um ruído, seria improvável que conseguíssemos atingir exatamente o mesmo resultado da figura 4.13.

Figura 4.14:

A figura 4.14 pode ser reproduzida combinando as estratégias usadas nas duas figuras anteriores. Desta vez, vamos adicionar o efeito degradê e vamos gerar outro Ruído de Perlin para que possamos modificar o ângulo em que o ponteiro é posicionado em cada loop. Isso permite que o ponteiro “vá e volte”, produzindo um efeito de torsão.
O código é:

import turtle
import noise

turtle.speed("fastest")

for angle in range(2, 401, 1): 

    c=str(int(angle/4)) #Note que estamos dividindo por 4 para que obtenhamos uma escala de cinzas de 0 a 100, uma vez que definimos um intervamo de 0 a 400
    cinzas="grey"+c
    turtle.pencolor(cinzas)
    turtle.pensize(1)


    n=noise.pnoise1(-1*angle+100, 10, 5, 0.5) #gera um número de perlin a partir do ângulo 
    m=noise.pnoise1(angle*10, 10, 5, 0.5) #gera um outro número de Perlin com uma escala diferente, que fornece mais detalhes.

    turtle.setheading(angle*n) #n modifica o posicionamento do ponteiro a cada loop
    turtle.forward(200+m*100)  #m modifica o comprimento da linha a cada loop
    turtle.backward(200+m*100)

    turtle.setheading(angle*n+181) 
    turtle.forward(200+m*100)
    turtle.backward(200+m*100)

turtle.done()

A figura gerada deve aparentar:

A imagem será apresentada aqui.

Novamente, os outros parâmetros da função pernil1 foram ajustados para que o efeito fosse o visto na figura acima.

comentou Out 1 por Gustavo Medeiros (11 pontos)  
Muito boa resposta Felipe, bem detalhada e explicativa. Fui refazendo passo a passo sua solução e aprendi esse comando para acelerar o desenho do módulo Turtle, isso vai facilitar muito minha vida daqui pra frente. Não consegui pensar em alguma maneira alternativa para solucionar o problema. Apenas um observação: acredito que os links estão quebrados pois não consegui acessá-los.
...