Espiral Redux 12

2024-06-19

"""2024-06-19
Espiral Redux 12
Exercício de espirais criadas a partir de uma espiral central
png
Sketch,py5,CreativeCoding,espirais
"""

import math
from random import choice, shuffle

import numpy as np
import py5

from utils import helpers

sketch = helpers.info_for_sketch(__file__, __doc__)


def calcular_espiral(
    x0: int,
    y0: int,
    offset: int,
    n_pontos: int,
    raio_max: int,
    escala: float = 0.1,
    crescimento: float = 0.0,
) -> list[tuple[float, float, float]]:
    pontos: list[tuple[float, float, float]] = []
    crescimento = crescimento if crescimento else raio_max / n_pontos

    t = np.linspace(0, 4 * np.pi, n_pontos)
    x_a = x0 + (escala + crescimento * t) * np.cos(t + offset)
    y_a = y0 + (escala + crescimento * t) * np.sin(t + offset)
    for i in range(n_pontos):
        x = x_a[i]
        y = y_a[i]
        r = math.sqrt((x - x0) ** 2 + (y - y0) ** 2)
        pontos.append((x, y, r))
    return pontos


def desenha_espiral(
    x0: float,
    y0: float,
    offset: float,
    cores: list[int] | None = None,
    idx: int = 1,
    n_pontos: int = 200,
    raio_max: int = 600,
):
    escala = py5.random(0.05, 0.4)
    crescimento = py5.random(3, 10)
    pontos = calcular_espiral(
        x0, y0, offset, n_pontos, raio_max, escala=escala, crescimento=crescimento
    )
    for idx, (x, y, r) in enumerate(pontos):
        multiplicador = py5.sin(py5.radians(r + 0.5 * idx)) + py5.cos(
            py5.radians(idx) + (0.2 * r)
        )
        h = choice(cores) + (py5.random_int(2, 4) * multiplicador)
        s = py5.random_int(50, 60) + (1 * multiplicador * py5.sin(idx))
        b = py5.random_int(60, 80) + (0.8 * multiplicador * py5.cos(idx))
        py5.stroke(h, s, b)
        py5.fill(h, s, b)
        func = py5.square if idx % 7 == 1 else py5.circle
        func(x, y, 2 * multiplicador)


def espirais(
    x: float,
    y: float,
    cores: list[int] | None = None,
    n_pontos: int = 50,
    raio_max: int = 200,
):
    total_cores = len(cores)
    offset = 360 / total_cores
    angulo = py5.random_int(360)
    desenha_espiral(x, y, angulo, cores, idx=0, n_pontos=n_pontos, raio_max=raio_max)
    angulo -= offset


def setup():
    py5.size(helpers.LARGURA, helpers.ALTURA, py5.P3D)
    py5.color_mode(py5.HSB, 360, 100, 100)
    py5.background(360, 0, 0)
    pontos = calcular_espiral(400, 400, 0, 100, 800, escala=-5, crescimento=40)
    for x, y, r in pontos:
        cores = list(range(0, 360, 5))
        shuffle(cores)
        espirais(x, y, cores)
    helpers.write_legend(sketch=sketch, frame="#000")


def key_pressed():
    key = py5.key
    if key == " ":
        save_and_close()


def save_and_close():
    py5.no_loop()
    helpers.save_sketch_image(sketch)
    py5.exit_sketch()


if __name__ == "__main__":
    py5.run_sketch()