Agora que já sabemos iterar por uma estrutura de dados, podemos usar as coordenadas das tuplas na lista que vimos anteriormente para desenhar um polígono ou mais genericamente um 'forma' PShape:
def setup():
size(400, 400)
pontos = [(50, 50), (300, 370), (200, 50), (150, 150)]
beginShape()
for x, y in pontos:
vertex(x, y)
endShape(CLOSE)
Podemos criar furos dentro de formas PShape
pendindo uma sequência de vértices, comvertex()
, entre as funções beginContour()
e endContour()
, que por sua vez precisam estar entre beginShape()
e endShape()
.
Note que é preciso que a direção dos pontos da forma interna, do furo, seja contrária a da forma externa.
No exemplo a seguir vamos descrever com uma lista de tuplas 3 vértices em sentido horário, e os vértices do furo no mesmo sentido. Para funcionar corretamente o furo, no segundo laço for
os pontos do furo tem sua ordem invertida com pontos_furo[::-1]
. Experimente remover essa inversão para ver o resultado!
def setup():
size(400, 400)
# fill(200, 100, 100)
# rect(50, 50, 300, 300) # retângulo rosa pra destacar furo
pontos_shape = [(20, 20), (330, 50), (300, 370)]
pontos_furo = [(100, 40), (300, 60), (290, 300)]
fill(255)
beginShape()
for x, y in pontos_shape:
vertex(x, y)
beginContour()
for x, y in pontos_furo[::-1]:
vertex(x, y)
endContour()
endShape(CLOSE)
Desafio: Você conseguiria encapsular em uma função a parte do código que faz o desenho do polígono?
Resposta: Uma função que desenha polígonos a partir de sequências de pontos.
def setup():
size(400, 400)
pontos_shape = [(20, 20), (330, 50), (300, 370)]
draw_poly(pontos_shape)
def draw_poly(pts, closed=True):
"""
Aceita como pontos sequencias de tuplas, lista ou vetores com (x, y) ou (x, y, z).
Por default faz um polígono fechado.
"""
beginShape() # inicia o PShape
for p in pts:
vertex(p[0], p[1]) # ou use `vertex(*p)` para aceitar pontos em 3D
# encerra o PShape
if closed:
endShape(CLOSE)
else:
endShape()
Avançado: Agora imagine uma função que desenha um PShape com furos se mandarmos uma lista de pontos, mais uma lista de furos com polígonos dentro.
Resposta: Uma função que desenha polígonos com furos.
def setup():
size(400, 400)
pontos_shape = [(20, 20), (330, 50), (300, 370)]
pontos_furo = [(290, 300), (300, 60), (100, 40)]
poly_and_holes(pontos_shape, [pontos_furo])
# poly_and_holes(pontos_shape, pontos_furo) # tabém funciona
saveFrame('contour_furo.png')
def poly_and_holes(points, holes=None, closed=True):
"""
Aceita como pontos sequencias de tuplas, lista ou vetores com (x, y) ou (x, y, z).
Note que `holes` espera uma sequencias de sequencias ou uma única sequencia de
pontos. Por default faz um polígono fechado.
"""
def depth(seq):
"""
usada para checar se temos um furo ou vários
devolve 2 para um só furo, 3 para vários furos
"""
if (isinstance(seq, list) or
isinstance(seq, tuple) or
isinstance(seq, PVector)):
return 1 + max(depth(item) for item in seq)
else:
return 0
beginShape() # inicia o PShape
for p in points:
if len(p) == 2:
vertex(p[0], p[1])
else:
vertex(*p) # desempacota pontos em 3d
# tratamento dos furos, se houver
holes = holes or [] # equivale a: holes if holes else []
if holes and depth(holes) == 2: # sequência única de pontos
holes = (holes,) # envolve em um tupla
for hole in holes: # para cada furo
beginContour() # inicia o furo
for p in hole:
if len(p) == 2:
vertex(p[0], p[1])
else:
vertex(*p)
endContour() # final e um furo
# encerra o PShape
if closed:
endShape(CLOSE)
else:
endShape()