# Ateliê Aberto: Geometria Árabe
## `hackmd.io/@sesc-av-paulista/geometria-arabe`
## Tesselações e padrões islâmicos com Python e py5
Para instalar ferramenta de desenho com Python que estamos usando (py5):
- https://abav.lugaralgum.com/como-instalar-py5/
## Quinta-feira 21 de novembro de 2024

```python=
formas = []
def setup():
global pos_atual, direcao
size(600, 600)
background(0) # fundo preto
no_stroke()
color_mode(HSB) # Matiz, Sat, Brilho
pos_atual = Py5Vector(0, 0) # v.x, v.y
apontar_direcao(0)
largura_octogono = 200
lado_octogono = largura_octogono / (1 + sqrt(2))
andar(lado_octogono / sqrt(2))
pontos_octogono = []
for i in range(8): # fazer 8 vezes:
andar(lado_octogono)
girar(360 / 8)
pontos_octogono.append(pos_atual)
triangulo(lado_octogono)
# desenhar estrela central
# deslocada meio octogono pra baixo e pra direita
ladinho = lado_octogono / (2 + sqrt(2)) # lado quadradinho
girar(90)
andar(largura_octogono - ladinho * sqrt(2) / 2)
girar(-90)
andar(largura_octogono / 2)
andar(ladinho)
pontos_estrela = [] # lista vazia
for i in range(16):
if i % 2 == 0: # se i é par:
girar(-90)
else: # senão:
girar(90 + 45)
andar(ladinho)
pontos_estrela.append(pos_atual)
#circle(pos_atual.x, pos_atual.y, 10)
formas.append(pontos_estrela)
for i in range(3): # 0, 1, 2
x = i * largura_octogono
for j in range(3): # 0, 1, 2
y = j * largura_octogono
desenha_todas_as_formas(x, y)
save(__file__[:-3] + '.png')
def quadradinho(lado):
pontos_quadradinho = []
for i in range(4): # repita 4 vezes:
andar(lado)
girar(90)
pontos_quadradinho.append(pos_atual)
formas.append(pontos_quadradinho)
def triangulo(lado_octogono):
ladinho = lado_octogono / (2 + sqrt(2)) # lado quadradinho
pontos_triangulo = [pos_atual]
girar(45)
andar(lado_octogono / sqrt(2))
pontos_triangulo.append(pos_atual)
#circle(pos_atual.x, pos_atual.y, 10)
quadradinho(ladinho)
girar(-90)
andar(lado_octogono / sqrt(2))
pontos_triangulo.append(pos_atual)
girar (-90-45)
#andar(lado_octogono)
andar(ladinho)
pontos_triangulo.append(pos_atual)
#circle(pos_atual.x, pos_atual.y, 10)
girar(-45)
andar(ladinho)
pontos_triangulo.append(pos_atual)
girar(90)
andar(ladinho)
pontos_triangulo.append(pos_atual)
girar(-45)
circle(pos_atual.x, pos_atual.y, 10)
pontos_triangulo.append(pos_atual)
andar(ladinho)
# fim do lado com dente
girar(180)
formas.append(pontos_triangulo)
def andar(d):
global pos_atual
pos_atual = pos_atual + Py5Vector.from_heading(direcao) * d
def apontar_direcao(deg):
global direcao
direcao = radians(deg)
def girar(deg):
global direcao
direcao += radians(deg)
def desenha_todas_as_formas(x, y):
with push_matrix():
translate(x, y)
for i, shp in enumerate(formas):
fill((i * 8) % 255, 200, 200, 200)
desenha_forma(shp)
def desenha_forma(pts):
with begin_closed_shape():
vertices(pts)
```
- Referência
- 
- [código](https://github.com/villares/sketch-a-day/blob/main/2024/sketch_2024_11_20/sketch_2024_11_20.py)
## Quinta-feira 14 de novembro de 2024

```python=
def setup():
size(600, 600)
rect_mode(CENTER) # quadrados pelo meio
fill(0, 0, 200)
square(100, 200, 100)
fill(0, 200, 0)
quadrado_girado(250, 150, 100)
def quadrado_girado(x, y, lado):
diagonal = lado * sqrt(2)
begin_shape()
vertex(x - diagonal / 2, y)
vertex(x, y - diagonal / 2)
vertex(x + diagonal / 2, y)
vertex(x, y + diagonal / 2)
end_shape(CLOSE)
```

c
```python=
import py5
SQRT2 = py5.sqrt(2)
def setup():
py5.size(600, 600)
py5.no_stroke()
composicao(200, 200, 100)
def composicao(x, y, lado):
diagonal = lado * SQRT2
w = lado / 2 + diagonal / 2
py5.rect_mode(py5.CENTER) # quadrados pelo meio
py5.fill(0, 0, 200)
py5.square(x, y, lado)
py5.fill(0, 200, 0)
quadrado_girado(x + w, y - lado / 2 , lado)
quadrado_girado(x - lado / 2, y + w , lado)
py5.fill(100, 0, 100)
quadrado_girado(x + w, y + w , diagonal)
py5.square(x + w, y + w, diagonal)
def quadrado_girado(x, y, lado):
diagonal = lado * py5.sqrt(2)
py5.begin_shape()
py5.vertex(x - diagonal / 2, y)
py5.vertex(x, y - diagonal / 2)
py5.vertex(x + diagonal / 2, y)
py5.vertex(x, y + diagonal / 2)
py5.end_shape(py5.CLOSE)
py5.run_sketch(block=False)
```

```python=
import py5
SQRT2 = py5.sqrt(2)
def setup():
py5.size(600, 600)
py5.no_fill()
menor = 200
lado_menor = menor / (1 + SQRT2)
pontos = octo_pontos(300, 300, lado_menor)
py5.begin_shape()
py5.vertices(pontos)
py5.end_shape(py5.CLOSE)
pontos = octo_pontos(300, 300, menor)
py5.begin_shape()
py5.vertices(pontos)
py5.end_shape(py5.CLOSE)
def octo_pontos(ox, oy, lado):
h = lado + SQRT2 * lado # largura!!!
return [
(ox - lado / 2, oy - h / 2),
(ox + lado / 2, oy - h / 2),
(ox + h / 2, oy -lado / 2),
(ox + h / 2, oy + lado / 2),
(ox + lado / 2, oy + h / 2),
(ox - lado / 2, oy + h / 2),
(ox - h / 2, oy + lado / 2),
(ox - h / 2, oy - lado / 2),
]
py5.run_sketch(block=False)
```


```python=
# Octógono na unha
def setup():
size(600, 600)
largura = 500
lado = largura / (1 + sqrt(2))
h = largura # lado + sqrt(2) * lado # largura!!!
ox, oy = 300, 300
pontos = [
(ox - lado / 2, oy - h / 2),
(ox + lado / 2, oy - h / 2),
(ox + h / 2, oy -lado / 2),
(ox + h / 2, oy + lado / 2),
(ox + lado / 2, oy + h / 2),
(ox - lado / 2, oy + h / 2),
(ox - h / 2, oy + lado / 2),
(ox - h / 2, oy - lado / 2),
]
begin_shape()
vertices(pontos)
end_shape(CLOSE)
```

```python!
import py5
SQRT2 = py5.sqrt(2)
def setup():
py5.size(600, 600)
py5.stroke(0)
small_octo_width = 200
small_octo_side = small_octo_width / (1 + SQRT2)
#composicao(300, 300, small_octo_width / SQRT2)
py5.no_fill()
small_octo_pts = octo_pontos(300, 300, small_octo_side)
draw_poly(small_octo_pts)
big_octo_pts = octo_pontos(300, 300, small_octo_width)
draw_poly(big_octo_pts)
py5.stroke(255)
girado_pts = quad_girado_pontos(300, 300, small_octo_width)
draw_poly(girado_pts)
quadrado_pts = quad_pontos(300, 300, small_octo_width)
draw_poly(quadrado_pts)
py5.stroke(0, 0, 100)
star_pts = []
for i, p in enumerate(small_octo_pts):
if i % 2 == 0:
star_pts.append(quadrado_pts[i // 2])
else:
star_pts.append(girado_pts[i // 2])
star_pts.append(p)
draw_poly(star_pts)
def draw_poly(pontos):
py5.begin_shape()
py5.vertices(pontos)
py5.end_shape(py5.CLOSE)
with py5.push_style():
for i, p in enumerate(pontos):
py5.fill(255, 0, 0)
py5.text_size(12)
py5.text(str(i), *p)
def composicao(cx, cy, lado):
diagonal = lado * SQRT2
w = lado / 2 + diagonal / 2
x, y = cx - w, cy - w
py5.rect_mode(py5.CENTER) # quadrados pelo meio
py5.fill(0, 0, 200)
py5.square(x, y, lado)
py5.fill(0, 200, 0)
quadrado_girado(x + w, y - lado / 2 , lado)
quadrado_girado(x - lado / 2, y + w , lado)
py5.fill(100, 0, 100)
quadrado_girado(x + w, y + w , diagonal)
py5.square(x + w, y + w, diagonal)
def quadrado_girado(x, y, lado):
diagonal = lado * py5.sqrt(2)
py5.begin_shape()
py5.vertex(x - diagonal / 2, y)
py5.vertex(x, y - diagonal / 2)
py5.vertex(x + diagonal / 2, y)
py5.vertex(x, y + diagonal / 2)
py5.end_shape(py5.CLOSE)
def octo_pontos(ox, oy, lado):
h = lado + SQRT2 * lado # largura!!!
return [
(ox - lado / 2, oy - h / 2),
(ox + lado / 2, oy - h / 2),
(ox + h / 2, oy -lado / 2),
(ox + h / 2, oy + lado / 2),
(ox + lado / 2, oy + h / 2),
(ox - lado / 2, oy + h / 2),
(ox - h / 2, oy + lado / 2),
(ox - h / 2, oy - lado / 2),
]
def quad_girado_pontos(x, y, lado):
diagonal = lado * SQRT2
return [
(x, y - diagonal / 2),
(x + diagonal / 2, y),
(x, y + diagonal / 2),
(x - diagonal / 2, y),
]
def quad_pontos(x, y, lado):
ml = lado / 2
return [
(x - ml, y - ml),
(x + ml, y - ml),
(x + ml, y + ml),
(x - ml, y + ml),
]
py5.run_sketch(block=False)
```
## Quinta-feira 7 de novembro de 2024

```python=
from itertools import product
A = radians(45 / 2)
TAN_A = tan(A)
S = 100
save_pdf = False
def setup():
size(900, 900)
rect_mode(CENTER)
no_fill()
def draw():
background(200, 240, 200)
global save_pdf
if save_pdf:
begin_record(PDF, __file__[:-3]+'.pdf')
for x, y in product(range(S // 2, width, S), repeat=2):
module(x, y, S)
if save_pdf:
end_record()
save_pdf = False
print('PDF saved.')
def module(x, y, ext):
with push_matrix():
translate(x, y)
ax, ay, bx, by = 0, ext/2, ext * TAN_A, -ext/2
gap_line(ax, ay, bx, by)
gap_line(ax, -ay, bx, -by, -1)
gap_line(ax, -ay, bx, -by, -1)
gap_line(-ax, ay, -bx, by, -1)
gap_line(-ax, -ay, -bx, -by)
gap_line(ay, -ax, by, -bx)
gap_line(-ay, -ax, -by, -bx, -1)
gap_line(ay, ax, by, bx, -1)
gap_line(-ay, ax, -by, bx)
def rot(x, y, cw=1, ang=None):
ang = ang or -A * 2 # -45 degrees by default for this sketch
return (x * cos(ang * cw) + y * sin(ang * cw),
-x * sin(ang * cw) + y * cos(ang * cw))
def gap_line(ax, ay, bx, by, cw=1):
mx, my = (ax + bx) / 2, (ay + by) / 2
line(mx, my, bx, by)
rx, ry = rot(mx, my, cw) # not always clockwise :/
line(ax, ay, rx, ry)
def key_pressed():
global save_pdf
if key == 's':
save(__file__[:-3]+'.png')
print('PNG saved.')
elif key == 'p':
save_pdf = True
```

```python=
# You'll need py5 and a use the run_sketch tool or Thonny+thonny-py5mode
# to run this py5 "imported mode" style sketch. Learn more at py5coding.org
R = 50
ROWS = 13
COLS = 12
save_pdf = False
def setup():
size(900, 900)
def draw():
background(200, 240, 240) # background not included on PDF export!
global save_pdf
if save_pdf:
begin_record(PDF, __file__[:-3]+'.pdf')
stroke_weight(2)
no_fill()
w = R * sqrt(3)
h = R * 1.5
for row in range(ROWS):
y = row * h
for col in range(COLS):
x = col * w
if row % 2 == 1:
x += w / 2
hex_unit(x, y, R)
if save_pdf:
end_record()
save_pdf = False
print('PDF saved.')
def hex_unit(xu, yu, r, pointy=False):
big_hex_radius = r * sqrt(3) / 2 * sqrt(2)
draw_hexagon(xu, yu, big_hex_radius, pointy) # big hexagon
vs = hexagon_points(xu, yu, r, not pointy) # centers for smaller hexs
for x, y in vs[2:4]: # just the third and fourth (indices 2 and 3)
draw_hexagon(x, y, r / 2, not pointy) # smaller hexagons
def draw_hexagon(x, y, r, pointy=True):
vs = regular_polygon_points(x, y, r, 6, pointy)
with begin_closed_shape():
vertices(vs)
def hexagon_points(x, y, cr, pointy=True):
# returns a list of tuples for the coords of vertices of hexagon
return regular_polygon_points(x, y, cr, 6, pointy)
def regular_polygon_points(x, y, cr, n, pointy=True):
# cr is the circumradius
ang = TAU / n
return [(x+cos(i * ang + pointy * ang / 2) * cr,
y+sin(i * ang + pointy * ang / 2) * cr)
for i in range(n)]
def key_pressed():
global save_pdf
if key == 's':
save(__file__[:-3]+'.png')
print('PNG saved.')
elif key == 'p':
save_pdf = True
```

```python=
# You'll need to install py5 and shapely
# Learn more at py5coding.org
# Press SPACE for a new palette
import py5
from shapely import Polygon
OFFSET = -2
BACKGROUND_COLOR = 0
R = 90
N = 8
palette = []
save_pdf = False
def setup():
py5.size(900, 900)
py5.no_loop()
palette.extend(py5.color(255) for _ in range(5))
def draw():
global save_pdf
if save_pdf:
py5.begin_record(py5.PDF, __file__[:-3]+'.pdf')
py5.background(BACKGROUND_COLOR)
py5.no_stroke()
w = R * py5.sqrt(3)
for j in range(N):
y = j * R * 3 / 2
for i in range(N):
x = i * w + (w / 2) * (j % 2)
hex_unit(x, y, R)
if save_pdf:
py5.end_record()
save_pdf = False
print('PDF saved.')
def hex_unit(xu, yu, ru, ang=0):
vs = regular_poly_points(xu, yu, ru / py5.sqrt(3), 6, ang)
for i, (x, y) in enumerate(vs):
tri_unit(x, y, ru / py5.sqrt(3), ang + py5.radians(60) * (i + 1),
i if py5.is_mouse_pressed else 0)
def tri_unit(x, y, r, angle=0, n=0):
evs = regular_poly_points(x, y, r, 3, angle)
ivs = regular_poly_points(x, y, r / 4, 3, angle)
py5.fill(palette[n % 2- 2])
central_triangle = Polygon(ivs).buffer(OFFSET)
draw_shapely(central_triangle)
for i in range(3):
sax, say = evs[i]
sbx, sby = evs[i - 1]
scx, scy = evs[i - 2]
a = py5.lerp(sax, sbx, 1/4), py5.lerp(say, sby, 1/4)
b = py5.lerp(sax, sbx, 3/4), py5.lerp(say, sby, 3/4)
c = ivs[i - 1]
d = ivs[i]
py5.fill(palette[(i + n) % 5])
trapezoid = Polygon((a, b, c, d)).buffer(OFFSET)
draw_shapely(trapezoid)
e = evs[i-1]
f = py5.lerp(sbx, scx, 1/4), py5.lerp(sby, scy, 1/4)
g = c
h = b
py5.fill(palette[n % 2 - 1])
diamond = Polygon((e, f, g, h)).buffer(OFFSET)
draw_shapely(diamond)
def draw_shapely(obj):
shp = py5.convert_shape(obj)
shp.disable_style()
py5.shape(shp)
def regular_poly_points(x, y, cr, n, rot=0):
# cr is the circumradius
ang = py5.TAU / n
return [(x + py5.cos(i * ang + rot) * cr,
y + py5.sin(i * ang + rot) * cr)
for i in range(n)]
def new_palette(bgd_color):
rnd_palette = [
py5.color(py5.random_int(50, 200),
py5.random_int(50, 200),
py5.random_int(50, 200))
for _ in range(5)] + [bgd_color]
palette[:] = py5.random_sample(rnd_palette * 2, 6)
def key_pressed():
global save_pdf
if py5.key == ' ':
new_palette(BACKGROUND_COLOR)
py5.redraw()
elif py5.key == 's':
py5.save(__file__[:-3]+'.png')
elif py5.key == 'p':
save_pdf = True
py5.redraw()
py5.run_sketch(block=False)
```
#### Uma função para polígonos regulares
```python
def setup():
size(500, 500)
N = 6
R = 200
a = TWO_PI / N # para N 6 é 60 graus
begin_shape()
for n in range(N):
x = 250 + R * cos(a * n + a / 2)
y = 255 + R * sin(a * n + a / 2)
vertex(x, y)
#print(n, degrees(a * n))
end_shape(CLOSE)
```

```python=
def setup():
size(500, 500)
poly(200, 200, 100, 6)
poly(400, 300, 100, 5)
poly(100, 400, 100, 4)
def poly(cx, cy, raio, lados):
a = TWO_PI / lados # para N 6 é 60 graus
begin_shape()
for n in range(lados):
x = cx + raio * cos(a * n + a / 2)
y = cy + raio * sin(a * n + a / 2)
vertex(x, y)
#print(n, degrees(a * n))
end_shape(CLOSE)
```

```python!
def setup():
size(600, 600)
poly(100, 100, 50, 8)
poly(200, 200, 50, 8)
poly(300, 300, 50, 8)
poly(400, 400, 50, 8)
poly(200, 100, 50, 8)
poly(300, 100, 50, 8)
poly(400, 100, 50, 8)
poly(100, 200, 50, 8)
poly(300, 200, 50, 8)
poly(400, 200, 50, 8)
poly(100, 300, 50, 8)
poly(200, 300, 50, 8)
poly(400, 300, 50, 8)
poly(100, 400, 50, 8)
poly(200, 400, 50, 8)
poly(300, 400, 50, 8)
poly(100, 100, 20, 4)
poly(200, 200, 20, 4)
poly(300, 300, 20, 4)
poly(400, 400, 20, 4)
poly(200, 100, 20, 4)
poly(300, 100, 20, 4)
poly(400, 100, 20, 4)
poly(100, 200, 20, 4)
poly(300, 200, 20, 4)
poly(400, 200, 20, 4)
poly(100, 300, 20, 4)
poly(200, 300, 20, 4)
poly(400, 300, 20, 4)
poly(100, 400, 20, 4)
poly(200, 400, 20, 4)
poly(300, 400, 20, 4)
poly(150, 150, 20, 8)
poly(250, 250, 20, 8)
poly(350, 350, 20, 8)
poly(450, 450, 20, 8)
poly(250, 150, 20, 8)
poly(350, 150, 20, 8)
poly(450, 150, 20, 8)
poly(150, 250, 20, 8)
poly(350, 250, 20, 8)
poly(450, 250, 20, 8)
poly(150, 350, 20, 8)
poly(250, 350, 20, 8)
poly(450, 350, 20, 8)
poly(150, 450, 20, 8)
poly(250, 450, 20, 8)
poly(350, 450, 20, 8)
def poly(cx, cy, raio, lados):
a = TWO_PI / lados # para N 6 é 60 graus
begin_shape()
for n in range(lados):
x = cx + raio * cos(a * n + a / 2)
y = cy + raio * sin (a * n + a / 2)
vertex(x , y)
#print(n, degrees(a * n))
end_shape(CLOSE)
```
### Referências
- Tudo sobre grades hexagonais https://www.redblobgames.com/grids/hexagons/
- https://vamshij.com/blog/2020-01-28-islamic-geometric-patterns/
- https://en.wikipedia.org/wiki/Girih_tiles
- https://www.youtube.com/watch?v=sJ6pMLp_IaI
- https://grail.cs.washington.edu/wp-content/uploads/2015/08/kaplan-2004-isp.pdf
- https://app.estuda.com/questoes/?id=170874
- https://archive.bridgesmathart.org/2018/bridges2018-511.pdf
- https://www.mi.sanu.ac.rs/vismath/sarhangi/index.html
- Turtle http://joshburker.blogspot.com/2013/01/turtleart-islamic-tiles.html
#### Material sobre Python
- https://abav.lugaralgum.com/material-aulas/
- https://automatetheboringstuff.com
- Pense em Python 2e
- https://greenteapress.com (vários livros)
- Avançado https://pythonfluente.com
### Mais ideias

https://github.com/villares/sketch-a-day/blob/main/2024/sketch_2024_07_16/sketch_2024_07_16.py



