Mapas v2: Origem

2025-12-02

"""2025-12-02
Mapas v2: Origem
Mapa do bairro da Mooca, São Paulo, SP, Brasil
ericof.com|Poly data (c) OpenStreetMap contributors|https://www.openstreetmap.org/copyright
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
from sketches.utils.mapas import v2 as mv2

import py5


sketch = helpers.info_for_sketch(__file__, __doc__)

FORMA: py5.Py5Shape | None = None
FUNDO = None

zpt = {"x": -37, "y": 1089, "scale": 1, "amount": 0}  # zoom & pan transformation values


def escala(geodata: mv2.t.GeoDataV2) -> tuple[float, float, float, float, float, float]:
    x_min, y_min, x_max, y_max = geodata.boundary
    map_w, map_h = (x_max - x_min), (y_max - y_min)
    x_scale, y_scale = py5.width / map_w, py5.height / map_h
    return x_min, y_min, x_max, y_max, x_scale, y_scale


def cria_forma(geodata: mv2.t.GeoDataV2, camadas: dict, caminhos: dict) -> py5.Py5Shape:
    x_min, y_min, x_max, y_max, x_scale, y_scale = escala(geodata)
    forma = py5.create_shape(py5.GROUP)

    for name, camada in camadas.items():
        feature = geodata.features[name]
        gdf = feature.gdf
        paleta = camada["paleta"]
        mv2.translate_and_scale_gdf(gdf, -x_min, -y_min, x_scale, -y_scale)
        for g in gdf.geometry:
            cor = paleta[0]
            py5.fill(cor)
            py5.no_stroke()
            forma.add_child(py5.convert_shape(g))
            paleta.rotate(1)

    for name, camada in caminhos.items():
        feature = geodata.networks[name]
        gdf = feature.gdf
        paleta = camada["paleta"]
        mv2.translate_and_scale_gdf(gdf, -x_min, -y_min, x_scale, -y_scale)
        for g in gdf.geometry:
            cor = paleta[0]
            py5.no_fill()
            py5.stroke(cor)
            forma.add_child(py5.convert_shape(g))
            paleta.rotate(1)
    return forma


def setup():
    global FORMA, FUNDO
    py5.size(*helpers.DIMENSOES.external, py5.P3D)
    paleta = gera_paleta("pastel", True)
    FUNDO = paleta.pop()
    py5.background(FUNDO)
    # Inicializa OSMnx
    mv2.d_utils.inicializa_osmnx(log_console=False)
    camadas = {
        "amenity": {"tag": {"amenity": True}, "paleta": paleta},
        "building": {"tag": {"building": True}, "paleta": paleta},
        "water": {"tag": {"water": True}, "paleta": deque(["#0000FF"])},
        "green": {
            "tag": {"leisure": ["pitch", "park", "playground"], "landuse": ["grass"]},
            "paleta": deque(["#00AA00"]),
        },
    }
    caminhos = {
        "roads": {"tag": {"highway": True}, "paleta": deque(["#CCCCCC"])},
        "rail": {"tag": {"railway": True}, "paleta": deque(["#888888"])},
    }
    limite = "São Paulo, São Paulo, Brazil"
    endereco = "Mooca, São Paulo, São Paulo, Brazil"
    print(f"Obtendo dados OSMnx para {endereco}...")
    geodata = mv2.obtem_dados_osmnx(
        pasta=sketch.path,
        limite=limite,
        endereco=endereco,
        distancia=4500,
        camadas=camadas,
        caminhos=caminhos,
    )
    print(f"Obtendo dados OSMnx para {endereco}... concluído.")
    FORMA = cria_forma(geodata, camadas, caminhos)


def draw():
    global FUNDO
    if FUNDO and FORMA:
        py5.background(FUNDO)
        with py5.push():
            py5.translate(zpt["x"], zpt["y"], -2)
            py5.scale(zpt["scale"])
            FORMA.set_stroke_weight(1 / zpt["scale"])
            py5.shape(FORMA)
    py5.window_title(f"Sketch - Frame {zpt['x'], zpt['y'], zpt['scale']}")
    cor_fundo = py5.color(0)
    # Credits and go
    canvas.sketch_frame(
        sketch, cor_fundo, "large_transparent_white", "transparent_white"
    )


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


def mouse_wheel(e):
    xrd = (py5.mouse_x - zpt["x"]) / zpt["scale"]
    yrd = (py5.mouse_y - zpt["y"]) / zpt["scale"]
    zpt["amount"] -= e.get_count()
    zpt["scale"] = 1.1 ** zpt["amount"]
    zpt["x"] = int(py5.mouse_x - xrd * zpt["scale"])
    zpt["y"] = int(py5.mouse_y - yrd * zpt["scale"])


def mouse_dragged():
    zpt["x"] += py5.mouse_x - py5.pmouse_x
    zpt["y"] += py5.mouse_y - py5.pmouse_y


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


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