diff --git a/2019/sketch_190423a/gif_exporter.py b/2019/sketch_190423a/gif_exporter.py new file mode 100644 index 00000000..51c431df --- /dev/null +++ b/2019/sketch_190423a/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=200, # 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_190423a/polys.py b/2019/sketch_190423a/polys.py new file mode 100644 index 00000000..3ae5bf1d --- /dev/null +++ b/2019/sketch_190423a/polys.py @@ -0,0 +1,69 @@ + +class Poly(): + + text_on = False + drag = -1 + drag_hole = -1 + drag_drag_pt = -1 + x_offset = y_offset = 0 + cell_size = 10 + + def __init__(self, outer_pts, holes=[[(0, 0)]]): + self.outer_pts = outer_pts + self.holes = holes + + def plot(self, x_offset, y_offset): + Poly.x_offset, Poly.y_offset = x_offset, y_offset + pushStyle() + if len(self.outer_pts) >= 3: + fill(255) + beginShape() + for x, y in self.outer_pts: + stroke(0) + sx = (x + x_offset) * Poly.cell_size + sy = (y + y_offset) * Poly.cell_size + vertex(sx, sy) + for h in self.holes: + beginContour() + for x, y in h: + sx = (x + x_offset) * Poly.cell_size + sy = (y + y_offset) * Poly.cell_size + vertex(sx, sy) + endContour() + endShape(CLOSE) + Poly.annotate_pts(self.outer_pts, color(200, 0, 0), 5) + Poly.annotate_pts(self.holes[0], color(0, 0, 200), 5) + popStyle() + + def remove_pt(self, i, j): + for pt in self.outer_pts: + if (i, j) == pt: + self.outer_pts.remove(pt) + return True + for h in self.holes: + for pt in h: + if (i, j) == pt: + h.remove(pt) + return True + + @classmethod + def annotate_pts(cls, pts, c, scale_m=1): + if Poly.text_on: + strokeWeight(5) + textSize(16) + fill(c) + stroke(c) + for i, j in pts: + x = (i + cls.x_offset) * cls.cell_size + y = (j + cls.y_offset) * cls.cell_size + point(x, y) + text(str((i * scale_m, j * scale_m)), x, y) + + @classmethod + def grid(cls, order): + stroke(128) + noFill() + for x in range(order): + for y in range(order): + rect(x * cls.cell_size, y * cls.cell_size, + cls.cell_size, cls.cell_size) diff --git a/2019/sketch_190423a/sketch_190422a.png b/2019/sketch_190423a/sketch_190422a.png new file mode 100644 index 00000000..0b396bf1 Binary files /dev/null and b/2019/sketch_190423a/sketch_190422a.png differ diff --git a/2019/sketch_190423a/sketch_190423a.pyde b/2019/sketch_190423a/sketch_190423a.pyde new file mode 100644 index 00000000..723979c5 --- /dev/null +++ b/2019/sketch_190423a/sketch_190423a.pyde @@ -0,0 +1,121 @@ +# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +""" +A minimal poly editor +- Drag points from holes +- Remove any point with CNTRL + click +""" + +from polys import Poly +Poly.cell_size = 25 +Poly.text_on = False + +# add_library('GifAnimation') +# from gif_exporter import gif_export + +# f_pts = [map(lambda x: x / 5 - 12, pair) for pair in f_pts] +polys = [Poly([(2, 2), (2, 4), (4, 4), (4, 2)]), + Poly([(5, 5), (5, 7), (3, 3)]), + Poly([(-8, -7), (-1, 0), (1, -9)], + holes=[[(-4, -4), (-6, -6), (-1, -7)], ]), + ] + +def setup(): + global x_offset, y_offset, order + size(500, 500, P2D) + order = width / Poly.cell_size + x_offset = y_offset = int(order / 2) + strokeJoin(ROUND) + f = createFont("Fira Mono Bold", 16) + textFont(f) + +def draw(): + background(230) + # grade + Poly.grid(order) + + for p in polys: + p.plot(x_offset, y_offset) + + +def mousePressed(): + for i in range(order): + x = i * Poly.cell_size + for j in range(order): + y = j * Poly.cell_size + io, jo = i - x_offset, j - y_offset # grid origin correction + if dist(mouseX, mouseY, x, y) < Poly.cell_size / 2: + if keyPressed and keyCode == CONTROL: + for p in polys: + if p.remove_pt(io, jo): + break + else: + for ip, p in enumerate(polys): + for ipt, pt in enumerate(p.outer_pts): + if pt == (io, jo): + Poly.drag = ip + Poly.drag_pt = ipt + break + for ih, h in enumerate(p.holes): + for ipt, pt in enumerate(h): + if pt == (io, jo): + Poly.drag = ip + Poly.drag_hole = ih + Poly.drag_pt = ipt + break + +def mouseDragged(): + if Poly.drag >= 0: # a Poly point has been selected to be dragged + if Poly.drag_hole == -1: # if no hole wase selected + polys[Poly.drag].outer_pts[Poly.drag_pt] = ( + int(mouseX / Poly.cell_size) - x_offset, + int(mouseY / Poly.cell_size) - y_offset) + else: + polys[Poly.drag].holes[Poly.drag_hole][Poly.drag_pt] = ( + int(mouseX / Poly.cell_size) - x_offset, + int(mouseY / Poly.cell_size) - y_offset) + +def mouseReleased(): + Poly.drag = -1 # No poly selected + Poly.drag_hole = -1 # No hole selected + Poly.drag_pt = -1 # No point selected + +def keyPressed(): + if key == " ": + for p in polys: + p.outer_pts[:] = clockwise_sort(p.outer_pts) + for h in p.holes: + h[:] = clockwise_sort(h)[::-1] + # if key == "g": + # gif_export(GifMaker, filename=SKETCH_NAME) + if key == "s": + saveFrame(SKETCH_NAME+"#.png") + if key == "t": + Poly.text_on = not Poly.text_on + +def clockwise_sort(xy_pairs): + # https://stackoverflow.com/questions/51074984/sorting-according-to-clockwise-point-coordinates + data_len = len(xy_pairs) + if data_len > 2: + x, y = zip(*xy_pairs) + else: + return xy_pairs + centroid_x, centroid_y = sum(x) / data_len, sum(y) / data_len + xy_sorted = sorted(xy_pairs, + key=lambda p: atan2((p[1] - centroid_y), (p[0] - centroid_x))) + xy_sorted_xy = [coord for pair in list(zip(*xy_sorted)) for coord in pair] + half_len = int(len(xy_sorted_xy) / 2) + return list(zip(xy_sorted_xy[:half_len], xy_sorted_xy[half_len:])) + + +def settings(): + from os import path + global SKETCH_NAME + SKETCH_NAME = path.basename(sketchPath()) + OUTPUT = ".png" + println( + """ +![{0}](2019/{0}/{0}{1}) + +[{0}](https://github.com/villares/sketch-a-day/tree/master/2019/{0}) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] +""".format(SKETCH_NAME, OUTPUT) + ) diff --git a/README.md b/README.md index a10dd0a4..215010af 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,13 @@ Get updates from my sort-of-weekly newsletter: [[sketch-mail](https://villares.o ## 2019 --- +![sketch_190423a](2019/sketch_190423a/sketch_190423a.png) + +[sketch_190423a](https://github.com/villares/sketch-a-day/tree/master/2019/sketch_190423a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] + +Now I drag any point, inclunding of holes, and remove points. +TODO: Add points; Drag polys. + --- ![sketch_190422a](2019/sketch_190422a/sketch_190422a.png)