# 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 ![octo_estrela](https://hackmd.io/_uploads/ByS02b6M1l.png) ```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 - ![](https://raw.githubusercontent.com/villares/sketch-a-day/main/2024/sketch_2024_11_20/sketch_2024_11_20.png) - [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 ![image](https://hackmd.io/_uploads/Bku0RL5Zye.png) ```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) ``` ![image](https://hackmd.io/_uploads/ryBZU2QGyg.png) 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) ``` ![image](https://hackmd.io/_uploads/Skb3ma7M1e.png) ```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) ``` ![octo2](https://hackmd.io/_uploads/HJTjsOXfJe.png) ![diagrama de octógono wikipedia](https://upload.wikimedia.org/wikipedia/commons/thumb/c/cc/Octagon_in_square.svg/500px-Octagon_in_square.svg.png) ```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) ``` ![image](https://hackmd.io/_uploads/Bkh1_AQfyl.png) ```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 ![sketch_2024_11_07B](https://hackmd.io/_uploads/S1ofw8qZye.png) ```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 ``` ![sketch_2024_11_07](https://hackmd.io/_uploads/Hku7vrc-Jx.png) ```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 ``` ![sketch_2024_09_02](https://hackmd.io/_uploads/H1B3T8cZyg.png) ```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():![image](https://hackmd.io/_uploads/rJiM5OQfJx.png) 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) ``` ![image](https://hackmd.io/_uploads/B1Kmbq9bkx.png) ```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) ``` ![image](https://hackmd.io/_uploads/r1Hyncqb1l.png) ```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 ![image](https://hackmd.io/_uploads/rks_xP9Wyg.png) https://github.com/villares/sketch-a-day/blob/main/2024/sketch_2024_07_16/sketch_2024_07_16.py ![image](https://hackmd.io/_uploads/Bku0RL5Zye.png) ![image](https://hackmd.io/_uploads/BkTgJP5Z1x.png) ![image](https://hackmd.io/_uploads/HJx7Jvqbyg.png) ![image](https://hackmd.io/_uploads/SkC4kw5bJx.png)