""" sketch 65 180306 - Alexandre B A Villares https://abav.lugaralgum.com/sketch-a-day """ import random as rnd import copy as cp SAVE_FRAMES, STOP = False, False def setup(): global d1, d2, d3 size(500, 500) rectMode(CENTER) noFill() d1 = Drawing(SPACING=50, MARGIN=125, COLOR=color(0, 255, 0)) d2 = Drawing(SPACING=100, MARGIN=100, COLOR=color(0, 0, 255)) d3 = Drawing(SPACING=150, MARGIN=75, COLOR=color(255, 0, 0)) def draw(): background(200) fc = frameCount % 300 - 150 if fc < 0: fase = 0 elif 0 <= fc < 149: fase = map(fc, 0, 149, 0, 1) elif fc == 149: if STOP: noLoop() fase = 0 d1.randomize() d2.randomize() d3.randomize() d1.plot(fase) d2.plot(fase) d3.plot(fase) if SAVE_FRAMES and not fc % 10: saveFrame("####.tga") def keyPressed(): global STOP if key == 'b': d1.go_back() d2.go_back() d3.go_back() STOP = True class Drawing(): def __init__(self, SPACING, MARGIN, RANGE=1, COLOR=color(255, 0, 0)): """ clears the list of nodes and creates a a new drawing appending a list of nodes/drawing elements: arrows, connecting lines and lonely nodes """ self.single_color = COLOR self.drawing = list() self.SPACING, self.MARGIN, self.RANGE = SPACING, MARGIN, RANGE for x in range(MARGIN, 1 + width - MARGIN, SPACING): for y in range(MARGIN, 1 + height - MARGIN, SPACING): self.drawing.append( D_node(x, y, self.drawing, self.single_color)) for node in self.drawing: # para cada elemento do drawing node.randomize_target(0, RANGE * SPACING) # set of random targets node.copy_target(0, -1) # backup of original targets # secondary set of random targets node.randomize_target(1, RANGE * SPACING) def randomize(self): for node in self.drawing: node.copy_target(1, 0) node.randomize_target(1, self.RANGE * self.SPACING) def go_back(self): for node in self.drawing: node.copy_target(-1, 1) # target back to the first points def plot(self, fase): # draws circles/'lines', non-arrows for node in (n for n in self.drawing if not n.is_arrow): node.plot(fase) # draws arrows for node in (n for n in self.drawing if n.is_arrow): node.plot(fase) class D_node(object): """ Drawing elements, arrows or circles that might point to another element """ def __init__(self, x, y, drawing, s_color): self.x = x self.y = y self.t_size = rnd.choice([5, 10, 15]) # t_size self.s_weight = rnd.choice([1, 2, 3]) # s_weight self.is_arrow = rnd.choice([True, False]) # current targets, next targets, initial targets self.points_to = [[], [], []] self.drawing = drawing self.single_color = s_color def plot(self, amt, other=None): strokeWeight(self.s_weight) stroke(self.s_color(amt)) for other in self.points_now(amt): if self.is_arrow: seta(self.x, self.y, other.x, other.y, # shorten amount, head size self.t_size, self.s_weight * 5, rect, self.t_size) # tail func, tail size else: line(self.x, self.y, other.x, other.y) ellipse(self.x, self.y, self.t_size, self.t_size) if not other: if self.is_arrow: other = self seta(self.x, self.y, other.x, other.y, self.t_size, self.s_weight * 5, rect, self.t_size) else: ellipse(self.x, self.y, self.t_size, self.t_size) def randomize_target(self, index, range_times_spacing): self.points_to[index][:] = [] for _ in range(3): rnd_node = rnd.choice(self.drawing) while dist(self.x, self.y, rnd_node.x, rnd_node.y) > range_times_spacing: rnd_node = rnd.choice(self.drawing) if (self.x, self.y) != (rnd_node.x, rnd_node.y) and random(10) < 5: self.points_to[index].append(PVector(rnd_node.x, rnd_node.y)) def copy_target(self, origin, destination): self.points_to[destination] = cp.deepcopy(self.points_to[origin]) def never_empty(self, points): if not points: return [PVector(self.x, self.y)] else: return points def points_now(self, amt=0): points = [] if amt in [0, 1]: return self.points_to[int(amt)] else: # for p0 in self.never_empty(self.points_to[0]): # not all interpolated arrows are shown p0 = self.never_empty(self.points_to[0])[0] for p1 in self.never_empty(self.points_to[1]): points.append(PVector(lerp(p0.x, p1.x, amt), lerp(p0.y, p1.y, amt))) return points def s_color(self, amt): if amt in [0, 1]: if not self.points_to[int(amt)]: return self.single_color elif self.is_arrow: return color(0) else: return color(255) else: return lerpColor(self.s_color(0), self.s_color(1), amt) def seta(x1, y1, x2, y2, shorter=0, head=None, tail_func=None, tail_size=None): """ Seta means arrow in Portuguese """ L = dist(x1, y1, x2, y2) if not head: head = max(L / 10, 10) with pushMatrix(): translate(x1, y1) angle = atan2(x1 - x2, y2 - y1) rotate(angle) offset = shorter / 2 strokeCap(ROUND) if L > head * 2: line(0, L - offset, -head / 3, L - offset - head) line(0, L - offset, head / 3, L - offset - head) strokeCap(SQUARE) line(0, offset, 0, L - offset) if tail_func and tail_size: tail_func(0, 0, tail_size, tail_size)