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