-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy path__main__.py
More file actions
155 lines (127 loc) · 4.62 KB
/
Copy path__main__.py
File metadata and controls
155 lines (127 loc) · 4.62 KB
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
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
"""2026-07-08
Recursive Squares 06
Desenha quadrados recursivamente
ericof.com
png
Sketch,py5,CreativeCoding
"""
from collections import deque
from sketches.utils.draw import canvas
from sketches.utils.draw.cores.paletas import gera_paleta
from sketches.utils.helpers import sketches as helpers
import py5
sketch = helpers.info_for_sketch(__file__, __doc__)
paleta = gera_paleta("mandarin-redux")
grade_n = 3
tamanho_quadrado = 250
def constroi_areas() -> list[tuple[float, float, int, list[str | int], int]]:
"""Monta a grade ``grade_n`` x ``grade_n`` de areas centradas nas celulas.
Cada area recebe o centro da sua celula no painel interno e o tamanho base
``tamanho_quadrado``. Posicionar pelo centro da celula mantem a grade valida
para qualquer ``grade_n``. A celula exatamente no centro -- que so existe em
grades impares, em ``col == lin == grade_n // 2`` -- recebe ``z_sinal = -1``
para empilhar na direcao oposta em z; as demais recebem ``1``.
:returns: Lista de ``(cx, cy, tamanho_quadrado, paleta, z_sinal)`` por celula.
"""
largura, altura = helpers.DIMENSOES.internal
meio = grade_n // 2
return [
(
largura * (col + 0.5) / grade_n,
altura * (lin + 0.5) / grade_n,
tamanho_quadrado,
paleta,
-1 if grade_n % 2 and col == meio and lin == meio else 1,
)
for lin in range(grade_n)
for col in range(grade_n)
]
areas = constroi_areas()
cor_fundo = py5.color(0)
z_base = -28
z_divisor = 2
z_passo = 8
rotacao_x = 45
traco = 4
def setup():
py5.size(*helpers.DIMENSOES.external, py5.P3D)
py5.color_mode(py5.HSB, 360, 100, 100)
py5.rect_mode(py5.CENTER)
def desenha_quadrados(
cx: float, cy: float, tamanho_base: float, paleta: deque[int], z_sinal: int
) -> None:
# Espelhamento pela POSICAO no painel (nao por idx): areas a direita do
# centro giram no sentido oposto (reflexo horizontal) e areas abaixo do
# centro sao refletidas verticalmente via scale(1, -1). Chavear por posicao
# evita o bug de ``idx // 2`` agrupar pela diagonal e misturar as linhas de
# cima e de baixo. O tamanho usa a magnitude do angulo (loop 0->70), entao
# espelho e reflexo so mudam a orientacao -- o tamanho aparente fica identico.
centro_x = helpers.DIMENSOES.internal[0] / 2
centro_y = helpers.DIMENSOES.internal[1] / 2
reflete_h = 1 if cx < centro_x else -1
reflete_v = cy > centro_y
z = -40
for ida, angulo in enumerate(range(0, 75, 3)):
tamanho = tamanho_base * (1 - (angulo / 70)) if ida else tamanho_base
cor = paleta[0]
paleta.rotate()
z = z_base + ((ida // z_divisor) * z_passo * z_sinal)
with py5.push():
py5.translate(cx, cy, z)
if reflete_v:
py5.scale(1, -1)
py5.rotate(py5.radians(reflete_h * angulo))
py5.stroke(cor)
py5.square(0, 0, tamanho)
def draw() -> None:
py5.background(cor_fundo)
py5.no_fill()
py5.stroke_weight(traco)
with py5.push():
py5.translate(*helpers.DIMENSOES.pos_interno, -420)
py5.rotate_x(py5.radians(rotacao_x))
for cx, cy, tamanho_base, paleta, z_sinal in areas:
paleta_deque: deque[int] = deque(paleta)
desenha_quadrados(cx, cy, tamanho_base, paleta_deque, z_sinal)
msg = (
f"grade: {grade_n}x{grade_n} | tam: {tamanho_quadrado} | "
f"z_base: {z_base} | z_divisor: {z_divisor} | "
f"z_passo: {z_passo} | traco: {traco}"
)
# Credits and go
canvas.sketch_frame(
sketch,
cor_fundo,
"large_transparent_white",
"transparent_white",
version=2,
msg=msg,
)
def key_pressed():
global z_base, z_divisor, z_passo, traco, grade_n, tamanho_quadrado, areas
key = py5.key
match key:
case "w" | "s":
z_base += 2 if key == "w" else -2
case "a" | "d":
z_passo += 1 if key == "d" else -1
case ">" | "<":
if key == "<" and z_divisor <= 1:
return
z_divisor += 1 if key == ">" else -1
case "+" | "-":
traco += 1 if key == "+" else -1
case "g" | "h":
grade_n = max(1, grade_n + (1 if key == "g" else -1))
areas = constroi_areas()
case "o" | "l":
tamanho_quadrado = max(10, tamanho_quadrado + (10 if key == "o" else -10))
areas = constroi_areas()
case " ":
save_and_close()
def save_and_close():
py5.no_loop()
canvas.save_sketch_image(sketch)
py5.exit_sketch()
if __name__ == "__main__":
py5.run_sketch()