Gráfico - Experimentos em Programação Criativa - 2
Essa é mais uma tentativa de reproduzir uma imagem utilizando computação criativa, puramente para aprender coisas novas e passar o tempo. Esses artigos são principalmente criados como uma forma de catalogar o processo de implementação para referencia futura quando eu estiver desenvolvendo novas coisas.
Inspiração
A imagem que tentei replicar através de código desta vez é a seguinte:
E o meu resultado é o seguinte:
Bastante diferente do original, minha ideia era de fazer algo que a cada atualização mudasse o estilo, com quadrados e pontos maiores ou menores aleatóriamente.
Implementação
Usarei novamento o editor do p5 para essa implementação.
Passo 1
Começando de forma simples, vamos apenas adicionar a borda. Adicionei um cógigo boilerplate de início, definindo as corees do fundo e stroke, o tamanho da margem.
1 | let strokeColor = 10 |
Passo 2
O segundo passo foi adicionar os pontos dentro do quadro. Criei primeiro uma função para gerar os pontos, utilizando alguns parâmetros para configurar os posicionamentos e tamanho dos pontos.
1 | let padding // distância entre o quadro e os pontos |
E com esses pontos, podemos fácilmente desenhá-los na tela. Adicionei também um parâmetro para definir se os círculos devem ser preenchidos ou não.
1 | let shouldFill // os pontos devem ser preenchidos? |
Assim podemos ter alguns resultados diferentes, como os seguintes
Passo 3
O terceiro e último passo é desenhar a linha que atravessa o centro do quadro. O algoritmo para esse foi algo bem simples:
- Primeiro encontramos o centro da tela e selecionamos o ponto da primeira coluna;
- Enquanto tiver uma coluna a direita, escolhemos aleatóriamente um ponto acima ou abaixo;
- Desenhamos uma linha entre os dois pontos
O código para isso pode ser visto abaixo
1 | let lineRadius // largura da linha |
Próximos passos
Algumas outras ideias para evoluir essa brincadeira seriam:
- Adicionar fendas ou laços como na imagem original, onde aleatóriamente poderiams quebrar a linha
- Usar uma biblioteca, como o dat.gui para configurar as variáveis em tempo real, sem precisar executar o algoritmo múltiplas vezes para novos resultados
Código completo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115let strokeColor = 10
let backgroundColor = 245
let frameMargin // distância entre o quadro e a borda do canvas
let padding // distância entre o quadro e os pontos
let dotRadius // tamanho dos pontos
let dotPadding // distância entre os ponto
let shouldFill // os pontos devem ser vazados?
let lineRadius // largura da linha
function setup() {
createCanvas(windowWidth, windowHeight)
frameMargin = round(random(50, 150))
padding = round(random(-100, 100))
dotRadius = random(0.1, 10)
dotPadding = round(random(15, 30))
shouldFill = random() > 0.5
lineRadius = random(1, 20)
}
function draw() {
background(backgroundColor)
const frameBorders = drawFrame()
const dots = getDots(frameBorders)
drawDots(dots)
drawWalker(dots)
noLoop()
}
function drawFrame() {
noFill()
strokeWeight(4)
stroke(strokeColor)
const startAt = [frameMargin, frameMargin]
const size = [windowWidth - frameMargin * 2, windowHeight - frameMargin * 2]
rect(...startAt, ...size)
return [startAt, size]
}
function getDots(frameBorders) {
const startAt = [
frameBorders[0][0] + padding,
frameBorders[0][1] + padding
]
const endAt = [
frameBorders[0][0] + frameBorders[1][0] - padding,
frameBorders[0][1] + frameBorders[1][1] - padding
]
let curLine = startAt[0]
let col = startAt[1]
const dots = []
while (curLine < endAt[0]) {
const columns = []
while (col < endAt[1]) {
const x = curLine + dotRadius / 2
const y = col + dotRadius / 2
columns.push(createVector(x, y))
col += dotPadding
}
curLine += dotPadding
col = startAt[1]
dots.push(columns)
}
return dots
}
function drawDots(dots) {
if (shouldFill) fill(strokeColor)
for (let i = 0; i < dots.length; i++) {
for (let j = 0; j < dots[i].length; j++) {
circle(dots[i][j].x, dots[i][j].y, dotRadius)
}
}
}
function drawWalker(dots, startAtLine) {
stroke(strokeColor)
noFill()
strokeWeight(lineRadius)
strokeCap(ROUND) // para evitar que a linha fique com as pontas quadradas
strokeJoin(ROUND) // para evitar que a linha fique com as juntas quadradas
const middle = Math.round(dots[0].length / 2)
let selectedLine = middle
let selectedCol = 0
let previousLine = middle
beginShape()
while (selectedCol < dots.length) {
if (!dots[selectedCol] || !dots[selectedCol][selectedLine]) break
const dot = dots[selectedCol][selectedLine]
if (previousLine !== selectedLine) {
const prevDot = dots[selectedCol][previousLine]
vertex(prevDot.x, prevDot.y)
}
vertex(dot.x, dot.y)
previousLine = selectedLine
const next = Math.round(random(-3, 3))
selectedLine += next
if (selectedLine < 0) selectedLine = 0
if (selectedLine === dots[0].length) selectedLine = dots[0].length -1
selectedCol++
}
endShape()
}