Waves V

2024-04-01

"""2024-04-01
Waves V
Série de ondas, em tons de verde, criadas com funções trigonométricas.
png
Sketch,py5,CreativeCoding,waves
"""

from collections import defaultdict
from typing import List, Tuple

import numpy as np
import py5

from utils import helpers

sketch = helpers.info_for_sketch(__file__, __doc__)

MARGEM = 100


def calcula_circulo(
    largura: int, altura: int, margem: int
) -> List[Tuple[float, float]]:
    """Calcula circulo que toque as margens."""
    raio_x = (largura - (2 * margem)) / 2
    raio_y = (altura - (2 * margem)) / 2
    x0 = margem + raio_x
    y0 = margem + raio_y
    pontos = []
    for angulo in range(0, 360):
        angulo_radianos = py5.radians(angulo)
        x = x0 + (py5.cos(angulo_radianos) * raio_x)
        y = y0 + (py5.sin(angulo_radianos) * raio_y)
        pontos.append((x, y))
    return pontos


def setup():
    py5.size(helpers.LARGURA, helpers.ALTURA, py5.P3D)
    py5.background(252, 249, 230)
    py5.color_mode(py5.HSB, 360, 100, 100)
    py5.no_fill()
    py5.stroke_weight(2)
    circulo = calcula_circulo(py5.width, py5.height, MARGEM)
    pontos_y = defaultdict(set)
    h = 160
    with py5.push_style():
        py5.stroke_weight(6)
        py5.stroke(h, 60, 60)
        for x, y in circulo:
            py5.point(x, y)
            pontos_y[int(y)].add(x)
    limites_y = {k: (min(v), max(v)) for k, v in pontos_y.items()}
    passos = 22
    lx = py5.width - MARGEM
    ly = py5.height - MARGEM
    x = np.linspace(MARGEM, lx, endpoint=False, num=lx - MARGEM)
    y = np.linspace(MARGEM, ly, endpoint=False, num=passos)
    base_multi = np.logspace(0.4, 1.6, num=int(passos / 2), endpoint=False)
    multiplicadores = sorted(base_multi) + sorted(base_multi, reverse=True)
    pesos = np.linspace(4, 2, num=passos, endpoint=False)
    y = zip(y, multiplicadores, pesos)
    for yb, mult_b, peso in y:
        y0 = None
        ybi = int(yb)
        limites = None
        for diff in (0, -1, 1, -2, 2, -3, 3):
            limites = limites_y[ybi + diff] if ybi + diff in limites_y else None
            if limites:
                break
        xi = limites[0]
        x0 = xi
        xf = limites[1]
        py5.stroke_weight(peso)
        s = py5.remap(mult_b, 0, 40, 60, 100)
        for x1 in x:
            if x1 < xi or x1 > xf:
                continue
            xd = py5.remap(x1, 0, 800, -60, 60)
            mult = mult_b * py5.cos(py5.radians(xd))
            y1 = yb + (
                mult * (abs(py5.cos(py5.radians(x0 + (4.1 * yb))) * py5.sin(1.4 * x1)))
            )
            b = py5.remap(xd, -60, 60, 80, 60)
            py5.stroke(h, s, b)
            if y0 is None:
                y0 = y1
            py5.line(x0, y0, x1, y1)
            x0, y0 = x1, y1
    helpers.write_legend(sketch=sketch, cor=py5.color(h, s, b))


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()