diff --git a/README.md b/README.md index 76476387..03714e80 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,18 @@ Hi! I'm [Alexandre Villares](https://abav.lugaralgum.com), let's see if I can ma If you enjoy this, be a [patreon](https://patreon.com/arteprog) or make a donation [here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=HCGAKACDMVNV2) +--- + +![s312](s312/s312.gif) + +312: [code](https://github.com/villares/sketch-a-day/tree/master/s312) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] + +--- + +![s311](s311b/s311.gif) + +311: [code](https://github.com/villares/sketch-a-day/tree/master/s311) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] + --- ![s310](s310/s310.gif) diff --git a/s311/s311.gif b/s311/s311.gif index 1178415d..51bef35e 100644 Binary files a/s311/s311.gif and b/s311/s311.gif differ diff --git a/s311/s311.pyde b/s311/s311.pyde index d17f6175..6eea4001 100644 --- a/s311/s311.pyde +++ b/s311/s311.pyde @@ -1,12 +1,12 @@ # Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day -SKETCH_NAME = "s311" # 20181105 +SKETCH_NAME = "s311b" # 20181105 OUTPUT = ".gif" GRID_SIZE = 12 from line_geometry import Line from line_geometry import par_hatch -add_library('gifAnimation') -from gif_exporter import gif_export +# add_library('gifAnimation') +# from gif_exporter import gif_export rule = lambda x, y: random(40) < 20 @@ -20,22 +20,23 @@ def draw(): background(200) f = frameCount/10. t = 0.5 + sin(f)/2 - stroke(0, 0, 200) + stroke(0, 0, 200, 240) for c in Cell.cells: c.plot(-t) stroke(0) - stroke(200, 0, 0) + stroke(200, 0, 0, 240) for c in Cell.cells: c.plot(+t) - stroke(0) + # stroke(0) # for c in Cell.cells: # c.plot(t) - if f < TWO_PI: - gif_export(GifMaker, SKETCH_NAME) - else: - exit() + # if f < TWO_PI: + # pass + # # gif_export(GifMaker, SKETCH_NAME) + # else: + # exit() def init_grid(grid_size): Cell.border = 125. diff --git a/s312/gif_exporter.py b/s312/gif_exporter.py new file mode 100644 index 00000000..9b48b504 --- /dev/null +++ b/s312/gif_exporter.py @@ -0,0 +1,42 @@ +""" +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 or frameCount >= 100000: + finish = True + elif frameCount >= frames: + finish = True + + if finish: + gifExporter.finish() + print("gif saved") + exit() diff --git a/s312/line_geometry.py b/s312/line_geometry.py new file mode 100644 index 00000000..e8468e59 --- /dev/null +++ b/s312/line_geometry.py @@ -0,0 +1,146 @@ + +def create_points(non_intersecting=True): + background(200) + done = False + while not done: + poly_points = [PVector(random(BORDER, width - BORDER), + random(BORDER, height - BORDER) + ) + for _ in range(NUM)] + ed = edges(poly_points) + done = True + if non_intersecting: + for p1, p2 in ed[::-1]: + for p3, p4 in ed[2::]: + # test only non consecutive edges + if (p1 != p3) and (p2 != p3) and (p1 != p4): + if line_instersect(Line(p1, p2), Line(p3, p4)): + done = False + break + return poly_points + +def is_inside(x, y, poly_points): + min_, max_ = min_max(poly_points) + if x < min_.x or y < min_.y or x > max_.x or y > max_.y: + return False + + a = PVector(x, min_.y) + b = PVector(x, max_.y) + v_lines = inter_lines(Line(a, b), poly_points) + if not v_lines: + return False + + a = PVector(min_.x, y) + b = PVector(max_.x, y) + h_lines = inter_lines(Line(a, b), poly_points) + if not h_lines: + return False + + for v in v_lines: + for h in h_lines: + if line_instersect(v, h): + return True + + return False + + +def inter_lines(L, poly_points): + inter_points = [] + for p1, p2 in edges(poly_points): + inter = line_instersect(Line(p1, p2), L) + if inter: + inter_points.append(inter) + if not inter_points: + return [] + inter_lines = [] + if len(inter_points) > 1: + inter_points.sort() + pairs = zip(inter_points[::2], inter_points[1::2]) + for p1, p2 in pairs: + if p2: + inter_lines.append(Line(PVector(p1.x, p1.y), + PVector(p2.x, p2.y))) + return inter_lines + + +class Line(): + """ I should change this to a named tuple... """ + def __init__(self, p1, p2): + self.p1 = p1 + self.p2 = p2 + + def plot(self): + line(self.p1.x, self.p1.y, self.p2.x, self.p2.y) + + def lerp(self, other, t): + p1 = PVector.lerp(self.p1, other.p1, t) + p2 = PVector.lerp(self.p2, other.p2, t) + return Line(p1, p2) + +def line_instersect(line_a, line_b): + """ + code adapted from Bernardo Fontes + https://github.com/berinhard/sketches/ + """ + + x1, y1 = line_a.p1.x, line_a.p1.y + x2, y2 = line_a.p2.x, line_a.p2.y + x3, y3 = line_b.p1.x, line_b.p1.y + x4, y4 = line_b.p2.x, line_b.p2.y + + try: + uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); + except ZeroDivisionError: + return + + if not(0 <= uA <= 1 and 0 <= uB <= 1): + return + + x = line_a.p1.x + uA * (line_a.p2.x - line_a.p1.x) + y = line_a.p1.y + uA * (line_a.p2.y - line_a.p1.y) + + return PVector(x, y) + + +def edges(poly_points): + return pairwise(poly_points) + [(poly_points[-1], poly_points[0])] + +def pairwise(iterable): + import itertools + "s -> (s0,s1), (s1,s2), (s2, s3), ..." + a, b = itertools.tee(iterable) + next(b, None) + return zip(a, b) + +def min_max(points): + points = iter(points) + try: + p = points.next() + min_x, min_y = max_x, max_y = p.x, p.y + except StopIteration: + raise ValueError, "min_max requires at least one point" + for p in points: + if p.x < min_x: + min_x = p.x + elif p.x > max_x: + max_x = p.x + if p.y < min_y: + min_y = p.y + elif p.y > max_y: + max_y = p.y + return (PVector(min_x, min_y), + PVector(max_x, max_y)) + +def par_hatch(points, divisions, *sides): + vectors = [PVector(p.x, p.y) for p in points] + lines = [] + if not sides: sides = [0] + for s in sides: + a, b = vectors[-1 + s], vectors[+0 + s] + d, c = vectors[-2 + s], vectors[-3 + s] + for i in range(1, divisions): + s0 = PVector.lerp(a, b, i/float(divisions)) + s1 = PVector.lerp(d, c, i/float(divisions)) + lines.append(Line(s0, s1)) + return lines diff --git a/s312/s312.gif b/s312/s312.gif new file mode 100644 index 00000000..c698ced8 Binary files /dev/null and b/s312/s312.gif differ diff --git a/s312/s312.pyde b/s312/s312.pyde new file mode 100644 index 00000000..e0d53b16 --- /dev/null +++ b/s312/s312.pyde @@ -0,0 +1,148 @@ +# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +SKETCH_NAME = "s312" # 20181105 +OUTPUT = ".gif" +GRID_SIZE = 12 + +from line_geometry import Line +from line_geometry import par_hatch +# add_library('gifAnimation') +# from gif_exporter import gif_export + +rule = lambda x, y: random(40) < 20 + +def setup(): + #strokeCap(SQUARE) + size(700, 700) + smooth(8) + init_grid(GRID_SIZE) + +def draw(): + noStroke() + fill(200, 10) + rect(0, 0, width, height) + #background(200) + f = frameCount/10. + t = cos(f)/3 + stroke(0, 0, 200, 100) + for c in Cell.cells: + c.plot(-t*5) + stroke(0) + stroke(200, 0, 0, 100) + for c in Cell.cells: + c.plot(+t*5) + + # stroke(0) + # for c in Cell.cells: + # c.plot(t) + + # if TWO_PI < f < TWO_PI*2: + # pass + # gif_export(GifMaker, SKETCH_NAME) + # #else: + # #noLoop() + +def init_grid(grid_size): + Cell.border = 125. + Cell.spacing = (width - Cell.border *2) / grid_size + Cell.cells = [] + randomSeed(100) + for x in range(0, grid_size, 2): + for y in range(0, grid_size, 2): + new_cell = Cell(x, y) + Cell.cells.append(new_cell) + Cell.grid[x, y] = new_cell + + randomSeed(frameCount+2) + for x in range(-1, grid_size+1, 2): + for y in range(-1, grid_size+1, 2): + Node.grid0[x, y] = Node(x, y) # extrarir do dict + Node.grid1[x, y] = Node(x, y) # extrarir do dict + + + for c in Cell.cells: + c.update_vers() + +class Node(): + grid0 = dict() + grid1 = dict() + + def __init__(self, x, y): + self.ix = x + self.iy = y + self.px = Cell.border + Cell.spacing + x * Cell.spacing + self.py = Cell.border + Cell.spacing + y * Cell.spacing + if rule(x, y): + mx, my = width/2, height/2 + self.px += (self.px - mx) * 0.15 + self.py += (self.py - my) * 0.15 + self.x = self.px + self.y = self.py + +class Cell(): + cells = [] + grid = dict() + + def __init__(self, x, y): + self.ix = x + self.iy = y + self.px = Cell.border + Cell.spacing + x * Cell.spacing + self.py = Cell.border + Cell.spacing + y * Cell.spacing + self.vers = [] + self.num_hatches = int(random(5, 12)) + self.type_hatches = random(10) + + def plot(self, t): + L0, V0 = self.lines, self.vers + L1, V1 = self.lines_f, self.vers_f + + strokeWeight(1) + for l0, l1 in zip(L0, L1): + l = l0.lerp(l1, t) + l.plot() + beginShape() + noFill() + strokeWeight(2) + for p0, p1 in zip(V0, V1): + vertex(lerp(p0.x, p1.x, t), lerp(p0.y, p1.y, t) ) + endShape(CLOSE) + + def update_vers(self): + self.v0 = Node.grid0.get((self.ix-1, self.iy-1)) + self.v1 = Node.grid0.get((self.ix-1, self.iy+1)) + self.v3 = Node.grid0.get((self.ix+1, self.iy-1)) + self.v2 = Node.grid0.get((self.ix+1, self.iy+1)) + self.vers = [self.v0, self.v1, self.v2, self.v3] + self.v0f = Node.grid1.get((self.ix-1, self.iy-1)) + self.v1f = Node.grid1.get((self.ix-1, self.iy+1)) + self.v3f = Node.grid1.get((self.ix+1, self.iy-1)) + self.v2f = Node.grid1.get((self.ix+1, self.iy+1)) + self.vers_f = [self.v0f, self.v1f, self.v2f, self.v3f] + self.hatch() + + def hatch(self): + self.lines = [] + self.lines_f = [] + n = self.num_hatches + r = self.type_hatches + if r > 2: + self.lines.extend(par_hatch(self.vers, n, 0)) + self.lines_f.extend(par_hatch(self.vers_f, n, 0)) + if r < 8: + self.lines.extend(par_hatch(self.vers, n, 1)) + self.lines_f.extend(par_hatch(self.vers_f, n, 1)) + +def keyPressed(): + if key == "n" or key == CODED: + init_grid(GRID_SIZE) + #saveFrame("###.png") + if key == "s": saveFrame("###.png") + +# print text to add to the project's README.md +def settings(): + println( +""" +![{0}]({0}/{0}{2}) + +{1}: [code](https://github.com/villares/sketch-a-day/tree/master/{0}) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] +""".format(SKETCH_NAME, SKETCH_NAME[1:], OUTPUT) + ) diff --git a/s312/s312s.gif b/s312/s312s.gif new file mode 100644 index 00000000..5663e80c Binary files /dev/null and b/s312/s312s.gif differ