diff --git a/2019/sketch_190502a/gif_exporter.py b/2019/sketch_190502a/gif_exporter.py new file mode 100644 index 00000000..cb6d69a2 --- /dev/null +++ b/2019/sketch_190502a/gif_exporter.py @@ -0,0 +1,40 @@ +""" +Alexandre B A Villares http://abav.lugaralgum.com - GPL v3 + +A helper for the Processing gifAnimation library https://github.com/extrapixel/gif-animation/tree/3.0 +Download from https://github.com/villares/processing-play/blob/master/export_GIF/unzip_and_move_to_libraries_GifAnimation.zip +This helper was inspired by an example by Art Simon https://github.com/APCSPrinciples/AnimatedGIF/ + +# add at the start of your sketch: + add_library('gifAnimation') + from gif_exporter import gif_export +# add at the end of draw(): + gif_export(GifMaker) +""" + +def gif_export(GifMaker, # gets a reference to the library + filename="exported", # .gif will be added + repeat=0, # 0 makes it an "endless" animation + quality=255, # quality range 0 - 255 + delay=400, # this is quick + frames=0, # 0 will stop on keyPressed or frameCount >= 100000 + finish=False): # force stop + global gifExporter + try: + gifExporter + except NameError: + gifExporter = GifMaker(this, filename + ".gif") + gifExporter.setRepeat(repeat) + gifExporter.setQuality(quality) + gifExporter.setDelay(delay) + + gifExporter.addFrame() + + if frames == 0: + if keyPressed and key == "e": + finish = True + + if finish: + gifExporter.finish() + print("gif saved") + exit() diff --git a/2019/sketch_190502a/sketch_190502a.gif b/2019/sketch_190502a/sketch_190502a.gif new file mode 100644 index 00000000..2d7f2261 Binary files /dev/null and b/2019/sketch_190502a/sketch_190502a.gif differ diff --git a/2019/sketch_190502a/sketch_190502a.pyde b/2019/sketch_190502a/sketch_190502a.pyde new file mode 100644 index 00000000..adf69a50 --- /dev/null +++ b/2019/sketch_190502a/sketch_190502a.pyde @@ -0,0 +1,157 @@ +""" +Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day + +- Unfolding piramids +""" + +# add_library('GifAnimation') +# from gif_exporter import gif_export + +CORTE = color(255, 0, 0) +DOBRA = color(0, 0, 255) + +raio_externo, raio_interno = 100, 50 +lados = 5 + +def setup(): + size(400, 600, P3D) + hint(ENABLE_DEPTH_TEST) + hint(ENABLE_DEPTH_SORT) + +def draw(): + background(240) + translate(width / 2, height / 4 + 50) + pushMatrix() + rotateX(radians(45)) + rotateZ(radians(frameCount / 3.)) + fill(255, 200) + stroke(0) + strokeWeight(2) + pontos = piramide_3D(lados, raio_externo, raio_interno) + popMatrix() + translate(0, height / 2 - 50) + piramide_desdobrada(pontos) + +def piramide_3D(np, re, ri): + # calculando os pontos + pontos = [] + n = np * 2 + for i in range(n): + ang = radians(i * 360. / n) + if i % 2 == 0: + r = ri + else: + r = re + x = sin(ang) * r + y = cos(ang) * r + pontos.append((x, y)) + # arestas da base + pontos_base = pontos[::2] + pontos_base2 = pontos_base[1:] + [pontos_base[0]] + arestas_base = zip(pontos_base, pontos_base2) + # calculo da altura + (p0x, p0y), (p1x, p1y) = pontos[0], pontos[1] + lado = dist(p0x, p0y, p1x, p1y) + h_squared = lado * lado - ri * ri + if h_squared > 0: # se a altura viavel + h = sqrt(h_squared) + for aresta in arestas_base: + p1, p2 = aresta + beginShape() + vertex(*p1) + vertex(*p2) + vertex(0, 0, h) + endShape(CLOSE) + # sempre desenha a base + beginShape() + for ponto in pontos_base: + vertex(*ponto) + endShape(CLOSE) + # devolve os pontos para usar no 2D! + return pontos + +def piramide_desdobrada(pontos): + noFill() + # dobras da base + stroke(DOBRA) + beginShape() + for ponto in pontos[::2]: + vertex(*ponto) + endShape(CLOSE) + # arestas laterais + lista_b = pontos[1:] + [pontos[0]] + arestas = zip(pontos, lista_b) + for i, aresta in enumerate(arestas): + p1, p2 = aresta + stroke(CORTE) + if i % 2 == 0: + # abas de cola + glue_tab(p2, p1, 10, ) + # dobra + stroke(DOBRA) + line(p2[0], p2[1], p1[0], p1[1]) + else: + # outra aresta cortada + line(p1[0], p1[1], p2[0], p2[1]) + +def glue_tab(p1, p2, tab_w, cut_ang=QUARTER_PI / 3): + """ + draws a trapezoidal or triangular glue tab along edge defined by p1 and p2, + with width tab_w and cut angle a + """ + al = atan2(p1[0] - p2[0], p1[1] - p2[1]) + a1 = al + cut_ang + PI + a2 = al - cut_ang + # calculate cut_len to get the right tab width + cut_len = tab_w / sin(cut_ang) + f1 = (p1[0] + cut_len * sin(a1), + p1[1] + cut_len * cos(a1)) + f2 = (p2[0] + cut_len * sin(a2), + p2[1] + cut_len * cos(a2)) + edge_len = dist(p1[0], p1[1], p2[0], p2[1]) + + if edge_len > 2 * cut_len * cos(cut_ang): # 'normal' trapezoidal tab + beginShape() + vertex(*p1) # vertex(p1[0], p1[1]) + vertex(*f1) + vertex(*f2) + vertex(*p2) + endShape() + else: # short triangular tab + fm = ((f1[0] + f2[0]) / 2, (f1[1] + f2[1]) / 2) + beginShape() + vertex(*p1) + vertex(*fm) # middle way of f1 and f2 + vertex(*p2) + endShape() + +def keyPressed(): + global raio_interno, raio_externo, lados + if keyCode == UP: + raio_externo += 5 + if keyCode == DOWN: + raio_externo -= 5 + if keyCode == LEFT: + raio_interno += 5 + if keyCode == RIGHT: + raio_interno -= 5 + if key == "+": + lados += 1 + if key == "-" and lados > 3: + lados -= 1 + + # if key == "g": + # gif_export(GifMaker, filename=SKETCH_NAME) + +def settings(): + from os import path + global SKETCH_NAME + SKETCH_NAME = path.basename(sketchPath()) + OUTPUT = ".gif" + println( + """ +![{0}]({2}/{0}/{0}{1}) + +[{0}](https://github.com/villares/sketch-a-day/tree/master/{2}/{0}) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] +""".format(SKETCH_NAME, OUTPUT, year()) + ) diff --git a/README.md b/README.md index bba3a7a3..216b52e7 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,11 @@ Get updates from my sort-of-weekly newsletter: [[sketch-mail](https://villares.o ## 2019 +--- + +![sketch_190502a](2019/sketch_190502a/sketch_190502a.gif) + +[sketch_190502a](https://github.com/villares/sketch-a-day/tree/master/2019/sketch_190502a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] ---