Pattern & Grid 01

2026-02-07

"""2026-02-07
Pattern & Grid 01
Grade de padrões geométricos
ericof.com|https://openprocessing.org/sketch/1726494
png
Sketch,py5,CreativeCoding
"""

from sketches.utils.draw import canvas
from sketches.utils.draw.cores.paletas import gera_paleta
from sketches.utils.draw.grade import cria_grade
from sketches.utils.helpers import sketches as helpers

import py5


sketch = helpers.info_for_sketch(__file__, __doc__)

cor_fundo = py5.color(0)

PALETAS = [
    gera_paleta("op-1726494-01"),
    gera_paleta("op-1726494-02"),
    gera_paleta("op-1726494-03"),
    gera_paleta("op-1726494-04"),
    gera_paleta("op-1726494-05"),
    gera_paleta("op-1726494-06"),
    gera_paleta("op-1726494-07"),
    gera_paleta("op-1726494-08"),
]

CELULAS = 6
MULT_CELULA = 0.85
MULT_FORMA = 0.8
REPET_FORMA = 8


def form(x: float, y: float, d: float, palette):
    r = d / 2
    hr = r / 2
    aa = py5.TAU / REPET_FORMA

    size = max(2, int(r))
    pg = py5.create_graphics(size, size)
    mg = py5.create_graphics(size, size)

    colors = list(palette)

    # --- draw texture tile ---
    with pg.begin_draw():
        pg.rect_mode(py5.CENTER)
        pg.background(py5.color(colors[0]))
        pg.no_stroke()

        c = int(py5.random(3, 5))
        w = pg.width / c
        t = int(py5.random(2))

        for i in range(c):
            for j in range(c):
                col = colors[1 + int(py5.random(len(colors) - 1))]
                pg.fill(py5.color(col))
                func = pg.square if t == 0 else pg.circle
                func(i * w + w / 2, j * w + w / 2, w * py5.random(0.5, 1))

    # --- build mask (white = keep, black = cut) ---
    with mg.begin_draw():
        mg.background(255)
        mg.no_stroke()
        mg.fill(0)

        with mg.begin_shape():
            step = py5.TAU / 180
            a = -aa
            while a < py5.PI:
                mg.vertex(
                    mg.width / 2 + hr * py5.cos(a),
                    mg.height / 2 + hr * py5.sin(a),
                )
                a += step

            a = aa * 2
            while a > 0:
                mg.vertex(
                    hr * py5.cos(-aa) + hr * py5.cos(a),
                    mg.height / 2 + hr * py5.sin(-aa) + hr * py5.sin(a),
                )
                a -= step

    # --- apply mask directly to PGraphics ---
    pg.mask(mg)

    # --- draw n rotated copies ---
    with py5.push_matrix():
        py5.translate(x, y)
        for _ in range(REPET_FORMA):
            py5.image(pg, r * 0.5, 0, pg.width + 1, pg.height + 1)
            py5.rotate(py5.TAU / REPET_FORMA)


def setup():
    py5.size(*helpers.DIMENSOES.external, py5.P3D)
    py5.rect_mode(py5.CENTER)
    py5.image_mode(py5.CENTER)
    py5.color_mode(py5.HSB, 360, 100, 100)
    py5.background(cor_fundo)
    largura, altura = helpers.DIMENSOES.internal
    celula_x = largura // CELULAS
    celula_y = altura // CELULAS
    meia_celula_x = celula_x / 2
    meia_celula_y = celula_y / 2
    grade = cria_grade(
        largura=largura,
        altura=altura,
        margem_x=0,
        margem_y=0,
        celula_x=celula_x,
        celula_y=celula_y,
        alternada=False,
    )
    with py5.push():
        py5.translate(*helpers.DIMENSOES.pos_interno, -10)
        for xb, yb in grade:
            x, y = xb + meia_celula_x, yb + meia_celula_y
            paleta = py5.random_choice(PALETAS)
            py5.fill(py5.color(py5.random_choice(paleta)))
            tamanho = celula_x * MULT_CELULA
            py5.square(x, y, tamanho)
            tamanho = celula_x * MULT_FORMA
            form(x, y, tamanho, paleta)
    # Credits and go
    canvas.sketch_frame(
        sketch,
        cor_fundo,
        "large_transparent_white",
        "transparent_white",
        version=2,
    )


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


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


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