## Sesc Av. Paulista - quartas-feiras de 8 de março a 28 de junho # Ateliê aberto de fabricação digital para programação criativa ## `hackmd.io/@villares/sesc-atelie-fab-prog` - **Ferramenta de programação e desenho com Python**: - Como instalar o ambiente: [Thonny IDE + py5](https://abav.lugaralgum.com/como-instalar-py5/) - https://hackmd.io/@villares/processing-python - Editor online https://tinyurl/python-mam - [Referência rápida do vocabulário do py5](https://github.com/villares/processing.py-cheat-sheet/blob/pt-br/py5/py5_cc.pdf) - [Referência completa py5coding.org/reference](http://py5coding.org/reference/) - [Material didático aberto sobre Python + desenho](https://abav.lugaralgum.com/material-aulas) - **Referências de arte computacional** - Frieder Nake - http://dada.compart-bremen.de/item/agent/68 - Georg Nees - http://dada.compart-bremen.de/item/agent/15 - Schotter - Vera Molnar - http://dada.compart-bremen.de/item/agent/14 - https://www.labiennale.org/en/art/2022/collateral-events/vera-moln%C3%A1r-ic%C3%B4ne-2020 - encontro do dia 15/03/2023 > ![](https://lugaralgum.com/hackmd/HUTPFZP.png) > primeira tentativa > ![](https://lugaralgum.com/hackmd/rJQgYWHLh.png) > usando fator 15 de bagunça > ```python BAGUNCA = 15 def setup(): size(800, 600) frame_rate(1) def trapezio(x, y, w, h, varia=0): vy = random(-varia, varia) / 5 x1, y1 = x + random(-varia, varia), y + vy x2, y2 = x + random(-varia, varia) + w, y + vy x3, y3 = x + random(-varia, varia)+ w, y + h + vy x4, y4 = x + random(-varia, varia), y + h + vy quad(x1, y1, x2, y2, x3, y3, x4, y4) def grade(margem, esp, largura, altura): for x in range(margem, largura - margem , esp): for y in range(margem, altura - margem, esp): trapezio(x, y, esp / 2, esp / 2, BAGUNCA) def draw(): background(0, 0, 200) # Red, Greed, Blue 0-255 grade(100, 100, 800, 600) # global BAGUNCA # BAGUNCA = mouse_x # print(mouse_x) ``` ### Encontro 22/3 ![](https://lugaralgum.com/hackmd/6l7YGV0.png) https://tinyurl.com/schotter-py ```python= def setup(): size(500, 500) frame_rate(2) def draw(): background(200) no_fill() i = 0 for y in range(50, 450, 25): for x in range(50, 450, 25): limite = i / 10 push_matrix() offset_x = random(-limite, limite) / 5 offset_y = random(-limite, limite) / 5 translate(x + offset_x, y + offset_y) rotate(radians(random(-limite, limite))) rect(-10, -10, 25, 25) pop_matrix() i += 1 ``` ### Encontro 29/3 [Pincel Post-it](https://abav.lugaralgum.com/pyp5js/py5mode/?sketch=JTBEJTBBJTBEJTBBZGVmJTIwc2V0dXAoKSUzQSUwRCUwQSUyMCUyMCUyMCUyMHNpemUoNjAwJTJDJTIwNjAwKSUwRCUwQSUyMCUyMCUyMCUyMGJhY2tncm91bmQoMTAwJTJDJTIwMCUyQyUyMDEwMCklMEQlMEElMjAlMjAlMjAlMjAlMEQlMEFkZWYlMjBkcmF3KCklM0ElMEQlMEElMjAlMjAlMjAlMjBpZiUyMGlzX21vdXNlX3ByZXNzZWQlM0ElMEQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjB2eCUyMCUzRCUyMHJhbmRvbSgtMTAlMkMlMjAxMCklMEQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBxdWFkKC01MCUyMCUyQiUyMG1vdXNlX3glMkMlMjAlMjBtb3VzZV95JTJDJTBEJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwbW91c2VfeCUyQyUyMG1vdXNlX3klMkMlMEQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjBtb3VzZV94JTIwJTJCJTIwdnglMkMlMjA1MCUyMCUyQiUyMG1vdXNlX3klMkMlMEQlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAtNTAlMjAlMkIlMjBtb3VzZV94JTJDJTIwNTAlMjAlMkIlMjBtb3VzZV95KSUwRCUwQSUwRCUwQWRlZiUyMGtleV9wcmVzc2VkKCklM0ElMEQlMEElMjAlMjAlMjAlMjBiYWNrZ3JvdW5kKDEwMCUyQyUyMDAlMkMlMjAxMDApJTBEJTBBJTBEJTBB) ```python= def setup(): size(800, 600) svg_output = create_graphics(int(width), int(height), SVG, "arquivo.svg") begin_record(svg_output) background(0, 0, 200) # Red, Greed, Blue 0-255 grade(100, 100, 800, 600) end_record() def trapezio(x, y, w, h, varia=0): vy = 0 #random(-varia, varia) / 5 x1, y1 = x + random(-varia, varia), y + vy x2, y2 = x + random(-varia, varia) + w, y + vy x3, y3 = x + random(-varia, varia)+ w, y + h + vy x4, y4 = x + random(-varia, varia), y + h + vy quad(x1, y1, x2, y2, x3, y3, x4, y4) def grade(margem, esp, largura, altura): for x in range(margem, largura - margem , esp): for y in range(margem, altura - margem, esp): trapezio(x, y, esp / 2, esp / 2, 20) ``` ### Exemplo shapely Gerador de mandalas com simetria radial ```python= # Desenhos simétricos - 2019-2022 Alexandre Villares - code under GPL v3.0 # Using py5coding.org (Processing + Python) and shapely # you'll need to install py5 and shapely from shapely.geometry import Polygon, MultiPolygon from shapely.ops import unary_union segments = [] # press "a" to erase all segments next_seg_preview = [] seg_limit = 8 start_w = 10 # segment (starting) width end_w = 10 # ... ending width (for trapezoidal segs) divisions = 5 # Use "+" and "-" to change save_pdf = False # Use "p" to save a PDF mirror = True # Use "m" to toggle # press <backspace> to remove last segment/click def setup(): global mh, mv size(500, 500) mh, mv = width / 2, height / 2 def draw(): background(0, 128, 32) # it's better to leave the background out! global save_pdf if save_pdf: begin_record(PDF, "####.pdf") translate(mh, mv) bars = [] for num in range(divisions): angle = radians(360.0 / divisions) * num fill(255) for segment in segments: x1, y1, x2, y2 = segment pts = bar_points(x1, y1, x2, y2, start_w, end_w) rotated_points = [rot((x, y), angle) for x, y in pts] bars.append(Polygon(rotated_points)) if mirror: bars.append(Polygon([(x, -y) for x, y in rotated_points])) if len(bars) > 1: result = unary_union(bars) draw_poly(result) if save_pdf: end_record() save_pdf = False preview_bars() def draw_poly(poly): if isinstance(poly, MultiPolygon): for p in poly.geoms: draw_poly(p) elif isinstance(poly, Polygon): begin_shape() for x, y in poly.exterior.coords: vertex(x, y) for hole in poly.interiors: begin_contour() for x, y in hole.coords: vertex(x, y) end_contour() end_shape(CLOSE) else: begin_shape() for x, y in poly: vertex(x, y) end_shape(CLOSE) def mouse_pressed(): if len(segments) < seg_limit: if next_seg_preview: px, py = next_seg_preview segments.append((px, py, mouse_x - mh, mouse_y - mv)) if mouse_button == LEFT: next_seg_preview[:] = mouse_x - mh, mouse_y - mv elif mouse_button == RIGHT: next_seg_preview[:] = [] def key_pressed(): global save_pdf, divisions, mirror if key == "m": mirror = not mirror if key == "a": segments[:] = [] # erase all segments next_seg_preview[:] = [] if key == "g": saveFrame("#####.png") print("saving PNG") if key == "p": save_pdf = True print("saving PDF") if key == BACKSPACE and segments: segments.pop() # remove last segment if key == "-" and divisions > 2: divisions -= 1 if key == "+" or key == "=" and divisions < 12: divisions += 1 def preview_bars(): if next_seg_preview and len(segments) < seg_limit: p1x, p1y = next_seg_preview p2x, p2y = mouse_x - mh, mouse_y - mv push() for num in range(divisions): rotate(radians(360 / divisions)) fill(255, 100) draw_poly(bar_points(p1x, p1y, p2x, p2y, start_w, end_w)) if mirror: draw_poly(bar_points(p1x, -p1y, p2x, -p2y, start_w, end_w)) pop() def bar_points(p1x, p1y, p2x, p2y, w1, w2=None, o=0): """ trapezoid, draws a rotated quad with axis starting at (p1x, p1y) ending at (p2x, p2y) where w1 and w2 are the starting and ending side widths. """ if w2 is None: w2 = w1 d = dist(p1x, p1y, p2x, p2y) angle = atan2(p1x - p2x, p2y - p1y) + HALF_PI unrotated_points = ( (p1x - o, p1y - w1 / 2), (p1x - o, p1y + w1 / 2), (p1x + d + o, p1y + w2 / 2), (p1x + d + o, p1y - w2 / 2) ) return [rot(pt, angle, center=(p1x, p1y)) for pt in unrotated_points] def rot(pt, angle, center=None): xp, yp = pt x0, y0 = center or (0, 0) x, y = xp - x0, yp - y0 # translate to origin xr = x * cos(angle) - y * sin(angle) yr = y * cos(angle) + x * sin(angle) return (xr + x0, yr + y0) ``` ### Demo Shapely ```python from shapely import Point, LineString, Polygon from shapely import MultiPoint, MultiLineString, MultiPolygon def setup(): size(600, 600) def draw(): background(200) ls = LineString( [(100, 50), (100, 200), (200, 50)] ) draw_shapely(ls.buffer(30)) def draw_shapely(shp): if isinstance(shp, MultiPolygon): for p in shp.geoms: draw_poly(p) elif isinstance(shp, Polygon): begin_shape() for x, y in shp.exterior.coords: vertex(x, y) for hole in shp.interiors: begin_contour() for x, y in shp.coords: vertex(x, y) end_contour() end_shape(CLOSE) elif isinstance(shp, LineString): with push_style(): no_fill() begin_shape() for x, y in shp.coords: vertex(x, y) end_shape() else: print(f"não consigo desenhar: {shp}") ``` ![](https://lugaralgum.com/hackmd/YjXk8FQ.png) ```python from shapely.geometry import Polygon, MultiPolygon from shapely.ops import unary_union pontos1 = [(300, 100), (20, 100), (200, 300)] pontos2 = [(400, 100), (120, 100), (300, 300)] pontos3 = [(100, 280), (400, 280), (400, 400), (100, 400)] def setup(): size(600, 600) p1 = Polygon(pontos1) p2 = Polygon(pontos2) p3 = Polygon(pontos3) uniao = unary_union([p1, p2, p3]) begin_record(SVG, 'desenho.svg') background(200, 0, 0) # R, G, B 0-255 begin_shape() #desenha_poligono(p1) #desenha_poligono(pontos2) fill(0, 0, 200) desenha_poligono(uniao.buffer(5)) fill(0, 200, 0) desenha_poligono(uniao) # for peca in [p1, p2, p3]: # desenha_poligono(peca) end_record() def desenha_poligono(poligono): if isinstance(poligono, Polygon): begin_shape() for x, y in poligono.exterior.coords: vertex(x, y) for buraco in poligono.interiors: begin_contour() for x, y in buraco.coords: vertex(x, y) end_contour() end_shape() else: begin_shape() for x, y in poligono: vertex(x, y) end_shape(CLOSE) ``` ### versão final para o corte ![](https://lugaralgum.com/hackmd/TJrasIE.png) ```python= from shapely.geometry import Polygon, MultiPolygon from shapely.ops import unary_union pontos1 = [(300, 100), (20, 100), (200, 300)] pontos2 = [(400, 100), (120, 100), (300, 300)] pontos3 = [(100, 280), (400, 280), (400, 400), (100, 400)] #pontos4 = reversed([(120, 300), (380, 300), (380, 380), (120, 380)]) pontos4 = [(120, 300), (380, 300), (380, 380), (120, 380)] def setup(): size(600, 600) p1 = Polygon(pontos1) p2 = Polygon(pontos2) p3 = Polygon(pontos3) uniao = unary_union([p1, p2, p3]) #uniao = Polygon(pontos3, holes=[pontos4]) uniao = uniao.difference(Polygon(pontos4)) begin_record(SVG, 'desenho.svg') no_fill() #background(200, 0, 0) # R, G, B 0-255 begin_shape() #desenha_poligono(p1) #desenha_poligono(pontos2) #fill(0, 0, 200) desenha_poligono(uniao.buffer(5)) #fill(0, 200, 0) #desenha_poligono(uniao) # for peca in [p1, p2, p3]: # desenha_poligono(peca) end_record() def desenha_poligono(poligono): if isinstance(poligono, Polygon): begin_shape() for x, y in poligono.exterior.coords: vertex(x, y) for buraco in poligono.interiors: begin_contour() # começa buraco for x, y in buraco.coords: vertex(x, y) end_contour() # termina buraco end_shape() else: begin_shape() for x, y in poligono: vertex(x, y) end_shape(CLOSE) ``` #### 3/5/2023 Estudos com SVG. Convertendo o exemplo do mapa dos EUA do Processing. Basics > Shape > GetChild (pasta data usa-wikipedia.svg) ![](https://lugaralgum.com/hackmd/LDmOL8Q.png) ```python= def setup(): global usa, michigan, ohio size(640, 360) usa = load_shape("usa-wikipedia.svg") michigan = usa.get_child("MI") ohio = usa.get_child("OH") def draw(): background(255) # Draw the full map shape(usa, -600, -180) # Disable the colors found in the SVG file #michigan.disable_style() # Set our own coloring fill(0, 51, 102) no_stroke() # Draw a single state michigan.set_fill(color(0, 255, 0)) # não usar disable_style() shape(michigan, -600, -180) # Wolverines! # Disable the colors found in the SVG file ohio.disable_style() # Set our own coloring fill(153, 0, 0) no_stroke() # Draw a single state shape(ohio, -600, -180) # Buckeyes! ``` # exemplo module mode (estilo com import py5) ```python= import py5 def setup(): global desenhos py5.size(640, 360) desenhos = py5.load_shape("desenhos.svg") desenhos.disable_style() def draw(): global g1 py5.background(255) g1 = desenhos.get_child("g1") c2 = desenhos.get_child("c2") r2 = desenhos.get_child("r2") try: py5.shape(g1, 0, 0) except: print('nao deu') if c2 is not None: py5.shape(c2, 0, 0) py5.run_sketch(block=False) ``` #### Teste com P2D ```python= import py5 def setup(): global desenhos, g1, c2, r2 py5.size(640, 640, py5.P2D) desenhos = py5.load_shape("desenhos.svg") g1 = desenhos.get_child("g1") c2 = desenhos.get_child("c2") r2 = desenhos.get_child("r2") #g1.scale(3) #c2.scale(3) desenhos.disable_style() c2.disable_style() def draw(): py5.background(255) py5.fill(0, 0, 255) py5.shape(desenhos, 0, 0) py5.fill(255, 0, 0) py5.shape(g1, 10, 10) py5.fill(0, 255, 0) py5.shape(c2, 10, 10) py5.run_sketch() ``` ### 10 de maio - Retícula de imagem Primeira grade ![](https://lugaralgum.com/hackmd/r1K2yvFE3.png) ```python= from random import choice diametros = (6, 12, 24) def setup(): size(500, 500) fill(0) # preenchimento preto #stroke(255, 0, 0) # traço vermelho no_stroke() # sem traço tamanho = 26 for y in range(int(tamanho / 2), width, tamanho): for x in range(int(tamanho / 2), height, tamanho): #diametro = random(tamanho * 0.1, tamanho * 0.9) diametro = choice(diametros) circle(x, y, diametro) ``` reticula legal ![](https://hackmd.io/_uploads/B1ZiDPYE2.png) ```python= def setup(): size(300, 300) #no_smooth() # desliga antialias (tem que ser logo após size()) background(255) # fundo branco rect_mode(CENTER) img = load_image('MASP-PB.jpg') print(img.width, img.height) #image(img, 0, 0, 500, 500) fill(0) # preenchimento preto #stroke(255, 0, 0) # traço vermelho (demo) no_stroke() # sem traço tamanho = 5 for y in range(int(tamanho / 2), width, tamanho): for x in range(int(tamanho / 2), height, tamanho): xi, yi = tela_para_imagem(x, y, img) c = img.get_pixels(xi, yi) b = brightness(c) diametro = remap(b, 0, 255, tamanho, 0) if diametro > 2: circle(x, y, diametro) def tela_para_imagem(x, y, img): x_img = int(remap(x, 0, width, 0, img.width)) y_img = int(remap(y, 0, width, 0, img.height)) return x_img, y_img ``` Cortamos um estêncil do Avida Dollars! ![](https://hackmd.io/_uploads/BkDRxdYE3.png) ## 17 de maio "2 turnos" - Primeiro turno mandalas - Segundo turno random walker com simetria radial ### Desenhador de mandalas com barras ```python= # Desenhos simétricos - 2019-2022 Alexandre Villares - code under GPL v3.0 # Using py5coding.org (Processing + Python) and shapely # you'll need to install py5 and shapely from shapely.geometry import Polygon, MultiPolygon from shapely.geos import TopologicalError from shapely.ops import unary_union segments = [] # press "a" to erase all segments next_seg_preview = [] seg_limit = 8 start_w = 10 # segment (starting) width end_w = 10 # ... ending width (for trapezoidal segs) divisions = 5 # Use "+" and "-" to change save_pdf = False # Use "p" to save a PDF mirror = True # Use "m" to toggle # press <backspace> to remove last segment/click def setup(): global mh, mv size(500, 500) mh, mv = width / 2, height / 2 def draw(): background(0, 128, 32) # it's better to leave the background out! global save_pdf if save_pdf: begin_record(PDF, "####.pdf") translate(mh, mv) bars = [] for num in range(divisions): angle = radians(360.0 / divisions) * num fill(255) for segment in segments: x1, y1, x2, y2 = segment pts = bar_points(x1, y1, x2, y2, start_w, end_w) rotated_points = [rot((x, y), angle) for x, y in pts] bars.append(Polygon(rotated_points)) if mirror: bars.append(Polygon([(x, -y) for x, y in rotated_points])) if len(bars) > 1: result = unary_union(bars) draw_poly(result) if save_pdf: end_record() save_pdf = False preview_bars() def draw_poly(poly): if isinstance(poly, MultiPolygon): for p in poly.geoms: draw_poly(p) elif isinstance(poly, Polygon): begin_shape() for x, y in poly.exterior.coords: vertex(x, y) for hole in poly.interiors: begin_contour() for x, y in hole.coords: vertex(x, y) end_contour() end_shape(CLOSE) else: begin_shape() for x, y in poly: vertex(x, y) end_shape(CLOSE) def mouse_pressed(): if len(segments) < seg_limit: if next_seg_preview: px, py = next_seg_preview segments.append((px, py, mouse_x - mh, mouse_y - mv)) if mouse_button == LEFT: next_seg_preview[:] = mouse_x - mh, mouse_y - mv elif mouse_button == RIGHT: next_seg_preview[:] = [] def key_pressed(): global save_pdf, divisions, mirror if key == "m": mirror = not mirror if key == "a": segments[:] = [] # erase all segments next_seg_preview[:] = [] if key == "g": saveFrame("#####.png") print("saving PNG") if key == "p": save_pdf = True print("saving PDF") if key == BACKSPACE and segments: segments.pop() # remove last segment if key == "-" and divisions > 2: divisions -= 1 if key == "+" or key == "=" and divisions < 12: divisions += 1 def preview_bars(): if next_seg_preview and len(segments) < seg_limit: p1x, p1y = next_seg_preview p2x, p2y = mouse_x - mh, mouse_y - mv push() for num in range(divisions): rotate(radians(360 / divisions)) fill(255, 100) draw_poly(bar_points(p1x, p1y, p2x, p2y, start_w, end_w)) if mirror: draw_poly(bar_points(p1x, -p1y, p2x, -p2y, start_w, end_w)) pop() def bar_points(p1x, p1y, p2x, p2y, w1, w2=None, o=0): """ trapezoid, draws a rotated quad with axis starting at (p1x, p1y) ending at (p2x, p2y) where w1 and w2 are the starting and ending side widths. """ if w2 is None: w2 = w1 d = dist(p1x, p1y, p2x, p2y) angle = atan2(p1x - p2x, p2y - p1y) + HALF_PI unrotated_points = ( (p1x - o, p1y - w1 / 2), (p1x - o, p1y + w1 / 2), (p1x + d + o, p1y + w2 / 2), (p1x + d + o, p1y - w2 / 2) ) return [rot(pt, angle, center=(p1x, p1y)) for pt in unrotated_points] def rot(pt, angle, center=None): xp, yp = pt x0, y0 = center or (0, 0) x, y = xp - x0, yp - y0 # translate to origin xr = x * cos(angle) - y * sin(angle) yr = y * cos(angle) + x * sin(angle) return (xr + x0, yr + y0) ``` ### Random walker ![](https://hackmd.io/_uploads/r1cognGBh.png) ```python= divisoes = 6 margem = 150 vx, vy = 4, 3 pincel_x, pincel_y = 200, 200 def setup(): size(600, 600) no_stroke() color_mode(HSB) # matiz, saturação, brilho def draw(): global pincel_x, pincel_y, vx, vy angulo = radians(360 / divisoes) translate(width / 2, height / 2) # move 0, 0 para o meio da tela for i in range(divisoes): # repete "divisoes" vezes rotate(angulo) fill(frame_count % 255, 200, 200) circle(pincel_x - width / 2, pincel_y - height / 2, 10) vx = vx + random(-0.5, 0.5) vy = vy + random(-0.5, 0.5) if abs(vx) > 5: vx = 0 if abs(vy) > 5: vy = 0 pincel_x = pincel_x + vx pincel_y = pincel_y + vy print(pincel_x, pincel_y) if pincel_x > (width - margem) or pincel_x < margem: vx = -vx if pincel_y > (height - margem) or pincel_y < margem: vy = -vy ``` # 24 de maio Gerador de Kirigami ![](https://hackmd.io/_uploads/H11ImjjHh.png) ```python # Uncomment lines 26 to 35 for "automatic" Perlin noise + random version modo_3D = True # toggle 3D pressing '3' save_pdf = False # to save press 's' seed = 5465 # lock random and noise s = 0.005 # noise scale def setup(): size(600, 600, P3D) print('seed: {}'.format(seed)) def draw(): global save_pdf background(10) # "Manual" hard-coded tuples of 4 elements elements = [ # [(x, el_width, el_height, el_depth), ... ] (50, 60, 200, 30), (110, 60, 50, 100), (220, 160, 80, 60), (380, 60, 180, 40), ] margin = elements[0][0] # "Automatic" Perlin noise based # random_seed(seed) # noise_seed(seed) # elements = [] # ((x, ew, eh, ed), ) # x = margin = 50 # while x < 580 - margin: # ew = max(20, min(random(20, 60), 600 - margin - x)) # eh = 300 * noise(1000 + x * s) # ed = 300 * noise(x * s) # elements.append((x, ew, eh, ed)) # x += ew # Drawing part if modo_3D and not save_pdf: stroke(0) fill(255) lights() push() translate(width / 2, height / 4, -height) rotate_x(QUARTER_PI) rotate_z(QUARTER_PI / 2) translate(-width / 4, height / 2, 0) # -height / 2, 0) rect_base(0, 0, 600, 400, *[(x, 0, w, b) for x, w, a, b in elements]) for x, w, a, b in elements: rect_h(x, 0, w, b, z=a) rotate_x(HALF_PI) rect_base(0, 0, 600, 400, *[(x, 0, w, a) for x, w, a, b in elements]) for x, w, a, b in elements: rect_h(x, 0, w, a, z=-b) pop() else: background(255) no_fill() if save_pdf: begin_record(PDF, 'output###.pdf') rect(0, 0, 600, 600) last_x = 0 for x, w, a, b in elements: if x != last_x: stroke(0, 0, 200) line(last_x, height / 2, x, height / 2) y = 300 stroke(200, 0, 0) line(x, y - a, x, y + b) line(x + w, y - a, x + w, y + b) stroke(0, 0, 200) line(x, y - a, x + w, y - a) line(x, y - a + b, x + w, y - a + b) line(x, y + b, x + w, y + b) last_x = x + w stroke(0, 0, 200) line(last_x, height / 2, width, height / 2) if save_pdf: end_record() save_pdf = False def rect_h(x, y, w, h, z): with push_matrix(): translate(0, 0, z) rect(x, y, w, h) def rect_base(x, y, w, h, *furos): if furos: begin_shape() vertex(x, y) vertex(x + w, y) vertex(x + w, y + h) vertex(x, y + h) for furo in furos: rect_base(*furo) end_shape(CLOSE) else: begin_contour() vertex(x, y) vertex(x, y + h) vertex(x + w, y + h) vertex(x + w, y) end_contour() def key_pressed(): global modo_3D, save_pdf, seed if key == ' ': seed = int(random(10000)) noise_seed(seed) print('seed: {}'.format(seed)) elif key == 's': save_pdf = True print('Salvando PDF') elif key == '3': modo_3D = not modo_3D ``` #### animação ![](https://hackmd.io/_uploads/Bys2d0sBh.png) ```python def setup(): size(400, 400) rect_mode(CENTER) def draw(): background(0, 0, 200) print(frame_count % 200) push_matrix() translate(width / 2, height / 2) rotate(radians(frame_count)) rect(0, 0, 100, 200) pop_matrix() rect(100, 100, frame_count % 200, 50) d = 100 + 50 * sin(radians(frame_count)) circle(300, 300, d) ``` # 31 de maio ```python= from random import choice grade = [] # grade é uma lista de células (grade_celulas) def setup(): size(600, 600) largura = 60 for i in range(10): x = largura / 2 + i * largura for j in range(10): y = largura / 2 + j * largura celula = Celula(x, y, largura, [modulo1, modulo2]) grade.append(celula) def draw(): background(200) for celula in grade: celula.desenha() def mouse_pressed(): for celula in grade: if celula.sob_mouse(mouse_x, mouse_y): if is_key_pressed and key_code == SHIFT: celula.muda_desenho() elif is_key_pressed and key_code == CONTROL: celula.espelha() else: celula.gira() print(celula.x, celula.y) def key_pressed(): if key == 'r': for celula in grade: opcoes = (0, 1, 2, 3) celula.gira(choice(opcoes)) elif key == 'm': for i, celula in enumerate(grade): celula.gira(i % 4) if i % 2 == 0: celula.muda_desenho() elif key == 'i': # Tecla 'i' para salvar PNG save_frame('#####.png') # o ##### vira número do frame def modulo1(x, y, lado): lado -= 2 rect_mode(CENTER) no_stroke() fill(255) #rect(x, y, lado, lado) stroke(0) stroke_weight(2) no_fill() xcse = x - lado / 2 ycse = y - lado / 2 qcirculo(xcse, ycse, lado / 3, INF_DIR) qcirculo(xcse, ycse, 2 * lado / 3, INF_DIR) xcid = x + lado / 2 ycid = y + lado / 2 qcirculo(xcid, ycid, lado / 3, SUP_ESQ) qcirculo(xcid, ycid, 2 * lado / 3, SUP_ESQ) INF_DIR, INF_ESQ, SUP_ESQ, SUP_DIR = 0, 1, 2, 3 def qcirculo(x, y, radius, rot): start_ang = rot * HALF_PI # rotação * 90 graus end_ang = HALF_PI + rot * HALF_PI d = radius * 2 arc(x, y, d, d, start_ang, end_ang) def modulo2(x, y, lado): lado -= 2 # lado = lado - 2 no_stroke() fill(255) #rect(x, y, lado, lado) stroke(0) stroke_weight(2) no_fill() xcse = x - lado / 2 ycse = y - lado / 2 qcirculo(xcse, ycse, lado / 3, INF_DIR) xcid = x + lado / 2 ycid = y + lado / 2 qcirculo(xcid, ycid, lado / 3, SUP_ESQ) xcsd = x + lado / 2 ycsd = y - lado / 2 qcirculo(xcsd, ycsd, lado / 3, INF_ESQ) xcie = x - lado / 2 ycie = y + lado / 2 qcirculo(xcie, ycie, lado / 3, SUP_DIR) class Celula: """ nova = Celula(x, y, largura, [func_desenho0, func_desenho1, ...]) --- métodos (funções do objetos) .desenha() desenha celula na sua posição .gira() gira 90 graus .sob_mouse(mouse_x, mouse_y) devolve True ou False quando sob mouse .espelha() Inverte espelhamento .muda_desenho() Muda função de desenho para a próxima --- atributos .espelhada Estado atual de espelhamento .rot Rotação atual .func_ativa Índice da função de desenho atual """ def __init__(self, x, y, largura, funcs): self.x, self.y = x, y self.largura = largura self.funcs = funcs self.func_ativa = 0 self.rot = 0 self.espelhada = False def desenha(self): push_matrix() translate(self.x, self.y) if self.espelhada: scale(-1, 1) rotate(HALF_PI * self.rot) funcao_desenho = self.funcs[self.func_ativa] funcao_desenho(0, 0, self.largura) pop_matrix() def sob_mouse(self, x, y): return (self.x - self.largura / 2 < x < self.x + self.largura / 2 and self.y - self.largura / 2 < y < self.y + self.largura / 2) def gira(self, rot=None): if rot is None: self.rot = (self.rot + 1) % 4 else: self.rot = rot def muda_desenho(self, i=None): if i is None: self.func_ativa = (self.func_ativa + 1) % len(self.funcs) else: self.func_ativa = i def espelha(self): self.espelhada = not self.espelhada ``` ## 7 de junho Linha interrompida FTW! ![](https://hackmd.io/_uploads/rkMgCrRI2.png) ```python= def setup(): size(600, 600) def draw(): x1, y1 = 50, 250 x2, y2 = mouse_x, mouse_y linha_interrompida (x1, y1, x2, y2) def linha_interrompida(x1, y1, x2, y2): vx, vy = (x2 - x1) / 11, (y2 - y1) / 11 line(x1, y1, x1 + 3 * vx, y1 + 3 * vy) line(x1 + 4 * vx, y1 + 4 * vy, x1 + 7 * vx, y1 + 7 * vy) line(x1 + 8 * vx, y1 + 8 * vy, x2, y2) ``` ![](https://hackmd.io/_uploads/B1UA5IRLn.png) ```python= polilinhas = [[]] # lista com uma lista vazia dentro def setup(): size(600, 600) def draw(): background(200, 0, 0) stroke_weight(10) stroke('#FFFFFF') for polilinha in polilinhas: for i, pt in enumerate(polilinha[:-1]): x, y = pt px, py = polilinha[i + 1] linha_interrompida (x, y, px, py) if polilinhas[-1]: x, y = polilinhas[-1][-1] stroke(0) line(x, y, mouse_x, mouse_y) def mouse_pressed(): if mouse_button == LEFT: polilinhas[-1].append((mouse_x, mouse_y)) elif mouse_button == RIGHT: polilinhas[-1].append((mouse_x, mouse_y)) polilinhas.append([]) def key_pressed(): if key == BACKSPACE: #print('Backspace') if polilinhas[-1]: polilinhas[-1].pop() elif len(polilinhas) > 1: polilinhas.pop() def linha_interrompida(x1, y1, x2, y2): vx, vy = (x2 - x1) / 11, (y2 - y1) / 11 line(x1, y1, x1 + 3 * vx, y1 + 3 * vy) line(x1 + 4 * vx, y1 + 4 * vy, x1 + 7 * vx, y1 + 7 * vy) line(x1 + 8 * vx, y1 + 8 * vy, x2, y2) ``` ### 14 de junho de 2023 Catálogo da Communidade Processing https://archive.org/details/processing-community-catalog-2021/page/n291/mode/2up #### Interrupções de tamanho fixo (GAP) ![](https://hackmd.io/_uploads/r1x7y5Pwh.png) ```python= polilinhas = [[]] # lista com uma lista vazia dentro LINE_THICKNESS = 10 GAP = LINE_THICKNESS * 2 # tamanho da interrupção da linha def setup(): size(600, 600) def draw(): background(0, 0, 200) # R G B 0-255 (azul) stroke_weight(LINE_THICKNESS) stroke('#FFFFFF') # cor hexadecimal #RRGGBB for polilinha in polilinhas: for i, pt in enumerate(polilinha[:-1]): x, y = pt px, py = polilinha[i + 1] linha_interrompida(x, y, px, py) if polilinhas[-1]: x, y = polilinhas[-1][-1] stroke(0) line(x, y, mouse_x, mouse_y) def mouse_pressed(): if mouse_button == LEFT: polilinhas[-1].append((mouse_x, mouse_y)) elif mouse_button == RIGHT: polilinhas[-1].append((mouse_x, mouse_y)) polilinhas.append([]) def key_pressed(): if key == BACKSPACE: #print('Backspace') if polilinhas[-1]: polilinhas[-1].pop() elif len(polilinhas) > 1: polilinhas.pop() def linha_interrompida(x1, y1, x2, y2): d = dist(x1, y1, x2, y2) if d < 2 * GAP: line(x1, y1, x2, y2) elif d < 5 * GAP: # else if ux, uy = (x2 - x1) / d, (y2 - y1) / d # vetor unitario mx, my = (x2 - x1) / 2, (y2 - y1) / 2 # vetor de 1 terço x1g = x1 + mx - ux * GAP / 2 y1g = y1 + my - uy * GAP / 2 x2g = x1 + mx + ux * GAP / 2 y2g = y1 + my + uy * GAP / 2 line(x1, y1, x1g, y1g) line(x2g, y2g, x2, y2) else: ux, uy = (x2 - x1) / d, (y2 - y1) / d # vetor unitario tx, ty = (x2 - x1) / 3, (y2 - y1) / 3 # vetor de 1 terço x1g = x1 + tx - ux * GAP / 2 y1g = y1 + ty - uy * GAP / 2 x2g = x1 + tx + ux * GAP / 2 y2g = y1 + ty + uy * GAP / 2 x3g = x1 + 2 * tx - ux * GAP / 2 y3g = y1 + 2 * ty - uy * GAP / 2 x4g = x1 + 2 * tx + ux * GAP / 2 y4g = y1 + 2 * ty + uy * GAP / 2 line(x1, y1, x1g, y1g) line(x2g, y2g, x3g, y3g) line(x4g, y4g, x2, y2) ``` ### Versão com exportação SVG ```python """ Draw interrupted stencil-ready lines with py5. Left-click to add vertex. Right-click to stop polyline. Backspace to remove last vertex. 'e' to erase everything. 's' to save SVG. Use the mouse wheel to change line thickness. """ import py5 from shapely.geometry import Polygon, MultiPolygon, GeometryCollection, LineString, Point from shapely.ops import unary_union MIN_GAP = 12 MIN_LT = 5 # minimum line thickness SVG_SUFIX = 'output.svg' save_svg = False line_thickness = 10 polilinhas = [[]] # lista com uma lista vazia dentro def setup(): py5.size(600, 600) def draw(): global save_svg py5.background(0, 0, 200) # R G B 0-255 (azul) py5.stroke('#FFFFFF') # cor hexadecimal #RRGGBB py5.fill(0, 100) if save_svg: out = py5.create_graphics(py5.width, py5.height, py5.SVG, f'{py5.frame_count}-{SVG_SUFIX}') py5.begin_record(out) poligonos = [] for polilinha in polilinhas: for i, pt in enumerate(polilinha[:-1]): x, y = pt px, py = polilinha[i + 1] poligonos.extend(linha_interrompida(x, y, px, py)) draw_shapely_objs(unary_union(poligonos)) if save_svg: save_svg = False py5.end_record() print(f'saved {py5.frame_count}-{SVG_SUFIX}.') if polilinhas[-1]: x, y = polilinhas[-1][-1] py5.stroke(0) draw_shapely_objs(linha_interrompida(x, y, py5.mouse_x, py5.mouse_y)) def mouse_pressed(): if py5.mouse_button == py5.LEFT: polilinhas[-1].append((py5.mouse_x, py5.mouse_y)) elif py5.mouse_button == py5.RIGHT: polilinhas[-1].append((py5.mouse_x, py5.mouse_y)) polilinhas.append([]) def key_pressed(): global save_svg if py5.key == py5.BACKSPACE: #print('Backspace') if polilinhas[-1]: polilinhas[-1].pop() elif len(polilinhas) > 1: polilinhas.pop() elif py5.key == 's': save_svg = True elif py5.key == 'e': polilinhas[:] = [[]] def mouse_wheel(e): global line_thickness line_thickness += e.get_count() line_thickness = max(MIN_LT, line_thickness) def linha_interrompida(x1, y1, x2, y2): resultado = [] gap = max(MIN_GAP, line_thickness * 2) # tamanho da interrupção da linha d = py5.dist(x1, y1, x2, y2) if d > 0: ux, uy = (x2 - x1) / d, (y2 - y1) / d # vetor unitario else: return [] if d < gap * 2: pass elif d < gap * 3: x1g = x1 + ux * gap y1g = y1 + uy * gap x2g = x2 - ux * gap y2g = y2 - uy * gap resultado.append(LineString([(x1g, y1g), (x2g, y2g)])) elif d < 5 * gap: # else if mx, my = (x2 - x1) / 2, (y2 - y1) / 2 # vetor do meio x1g = x1 + mx - ux * gap / 2 y1g = y1 + my - uy * gap / 2 x2g = x1 + mx + ux * gap / 2 y2g = y1 + my + uy * gap / 2 resultado.append(LineString([(x1, y1), (x1g, y1g)])) resultado.append(LineString([(x2g, y2g), (x2, y2)])) else: tx, ty = (x2 - x1) / 3, (y2 - y1) / 3 # vetor de 1 terço x1g = x1 + tx - ux * gap / 2 y1g = y1 + ty - uy * gap / 2 x2g = x1 + tx + ux * gap / 2 y2g = y1 + ty + uy * gap / 2 x3g = x1 + 2 * tx - ux * gap / 2 y3g = y1 + 2 * ty - uy * gap / 2 x4g = x1 + 2 * tx + ux * gap / 2 y4g = y1 + 2 * ty + uy * gap / 2 resultado.append(LineString([(x1, y1), (x1g, y1g)])) resultado.append(LineString([(x2g, y2g), (x3g, y3g)])) resultado.append(LineString([(x4g, y4g), (x2, y2)])) resultado_final = [lin.buffer(line_thickness / 2) for lin in resultado] return resultado_final def draw_shapely_objs(element): """ With py5, draw some shapely object (or a list of objects). """ if isinstance(element, (MultiPolygon, GeometryCollection)): for p in element.geoms: draw_shapely_objs(p) elif isinstance(element, Polygon): with py5.begin_closed_shape(): if element.exterior.coords: py5.vertices(element.exterior.coords) for hole in element.interiors: with py5.begin_contour(): py5.vertices(hole.coords) elif isinstance(element, list): for i, p in enumerate(element): draw_shapely_objs(p) elif isinstance(element, LineString): (xa, ya), (xb, yb) = element.coords py5.line(xa, ya, xb, yb) elif isinstance(element, Point): with push_style(): x, y = element.coords[0] py5.point(x, y) else: print(f"I can't draw {element}.") py5.run_sketch() ``` ### dia 21 de junho Demo de desenho 3D com combinatória (`itertools.combinations`) ![](https://hackmd.io/_uploads/HJZ2-Rxd3.png) ```python from itertools import product, combinations import py5 W = 80 def setup(): global combos py5.size(600, 600, py5.P3D) #py5.pixel_density(2) xy = product(range(-1, 3, 1), repeat=2) # -1, 0, 1, 2 grid = [(x * W - W / 2, y * W - W / 2) for x, y in xy] combos = list(combinations(grid, 2)) print(len(combos)) # 120 for combos of 16 positions, 2 at a time py5.frame_rate(10) py5.color_mode(py5.HSB) def draw(): py5.translate(py5.width / 2, py5.height / 2) #py5.ortho() py5.rotate_x(-py5.atan(py5.sin(py5.radians(45)))) py5.rotate_y(py5.radians(45)) py5.background(0) f = (py5.frame_count - 1) % len(combos) combos_extended = combos + combos[:11] # combos plus 11 from start combo_positions = combos_extended[f:f+11] # slice 11 combos start at f #combo_positions = [combos[(i + f) % len(combos)] for i in range(11)] for positions, z in zip(combo_positions, range(100, -101, -20)): py5.fill((255 + z - f * 20) % 255, 200, 200) for pos in positions: element(pos + (z,), W) if py5.frame_count < len(combos) + 1: py5.save_frame('###.png') def element(pos, w): x, y, z = pos with py5.push_matrix(): py5.translate(x, z, y) # note the inversion py5.box(w, w / 10, w) py5.run_sketch() ``` ### 28 de junho ![](https://hackmd.io/_uploads/BkL90bqu2.png) [animação porta](https://abav.lugaralgum.com/pyp5js/py5mode/?sketch=ZGVmJTIwc2V0dXAoKSUzQSUwQSUyMCUyMCUyMCUyMHNpemUoODAwJTJDJTIwODAwKSUyMCUyM3RhbWFuaG8lMjBkYSUyMCVDMyVBMXJlYSUyMGRlJTIwZGVzZW5obyUwQSUyMCUyMCUyMCUyMCUwQWRlZiUyMGRyYXcoKSUzQSUwQSUyMCUyMCUyMCUyMGJhY2tncm91bmQoNTApJTBBJTIwJTIwJTIwJTIwJTIzdHJhbnNsYXRlKDI1MCUyQyUyMDI1MCklMEElMjAlMjAlMjAlMjBmaWxsKDI1NSUyQyUyMDUwJTJDJTIwMTAwKSUwQSUyMCUyMCUyMCUyMHhwJTJDJTIweXAlMjAlM0QlMjBmcmFtZV9jb3VudCUyMCUyRiUyMDIlMkMlMjAxMDAlMEElMjAlMjAlMjAlMjBscCUyQyUyMGFwJTIwJTNEJTIwMTAwJTJDJTIwMjAwJTBBJTIwJTIwJTIwJTIwcmVjdCh4cCUyQyUyMHlwJTJDJTIwbHAlMkMlMjBhcCklMjAlMjAlMjMlMjB4JTJDJTIweSUyQyUyMGxhcmd1cmElMkMlMjBhbHR1cmElMEElMEElMjAlMjAlMjAlMjBmaWxsKDIwMCklMEElMjAlMjAlMjAlMjBxdWFkKHhwJTJDJTIweXAlMjAlMkIlMjBhcCUyQyUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHhwJTIwJTJCJTIwbHAlMkMlMjB5cCUyMCUyQiUyMGFwJTJDJTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwd2lkdGglMkMlMjBoZWlnaHQlMkMlMEElMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAlMjAwJTJDJTIwaGVpZ2h0JTBBJTIwJTIwJTIwJTIwJTIwJTIwJTIwJTIwKSUwQSUyMCUyMCUyMCUyMCUyMyUyMG51bWVyZW8lMjB2aXNpdmVsJTBBJTIwJTIwJTIwJTIwZmlsbCgwKSUwQSUyMCUyMCUyMCUyMHRleHQoc3RyKG1vdXNlX3kpJTJDJTIwNTAlMkMlMjAxMDApJTBBJTIwJTIwJTIwJTIwbm9fZmlsbCgpJTBBJTIwJTIwJTIwJTIwZm9yJTIwZCUyMGluJTIwcmFuZ2UoNTAwKSUzQSUyMCUyMCUyMyUyMGQlMjB2YWklMjBkZSUyMDAlMjBhdCVDMyVBOSUyMDI5OSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMHN0cm9rZSgyNTUlMkMlMjAyNTUlMkMlMjAwJTJDJTIwMjAwJTIwLSUyMGQlMjAqJTIwMC4zKSUwQSUyMCUyMCUyMCUyMCUyMCUyMCUyMCUyMGNpcmNsZShtb3VzZV94JTJDJTIwbW91c2VfeSUyQyUyMGQp)