diff --git a/s303/line_geometry.py b/s303/line_geometry.py new file mode 100644 index 00000000..92b4ea47 --- /dev/null +++ b/s303/line_geometry.py @@ -0,0 +1,140 @@ + +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 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): + lines = [] + if not sides: sides = [0] + for s in sides: + a, b = points[-1 + s].v, points[+0 + s].v + d, c = points[-2 + s].v, points[-3 + s].v + 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/s303/s303.png b/s303/s303.png new file mode 100644 index 00000000..1e9144f8 Binary files /dev/null and b/s303/s303.png differ diff --git a/s303/s303.pyde b/s303/s303.pyde new file mode 100644 index 00000000..ad80d3dc --- /dev/null +++ b/s303/s303.pyde @@ -0,0 +1,123 @@ +# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +SKETCH_NAME = "s303" # 20181028 +OUTPUT = ".png" +GRID_SIZE = 24 + +from line_geometry import Line +from line_geometry import par_hatch + +rule = lambda x, y: (x - y) % 3 == 0 + +def setup(): + global xo, yo + size(500, 500) + smooth(8) + init_grid(GRID_SIZE) + +def draw(): + background(0) + stroke(255) + for c in Cell.cells: + c.plot() + +def init_grid(grid_size): + Cell.border = 50. + Cell.spacing = (width - Cell.border *2) / grid_size + Cell.cells = [] + + 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 + + Node.nodes = [] + for x in range(-1, grid_size+1, 2): + for y in range(-1, grid_size+1, 2): + new_node = Node(x, y) + #Cell.cells.append(new_node) # mudar! + Cell.grid[x, y] = new_node # extrarir do dict + + for c in Cell.cells: + c.update_vers() + +class Node(): + nodes = [] + 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 + if rule(x, y): + self.px += random(-10, 10) + self.py += random(-10, 10) + self.x = self.px + self.y = self.py + self.v = PVector(self.x, self.y) + +class Cell(): + cells = [] + grid = dict() + vers = [] + + 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 = [] + + def plot(self): + strokeWeight(1) + for l in self.lines: + l.plot() + beginShape() + noFill() + for p in self.vers: + if rule(p.ix, p.iy): + ellipse(p.x, p.y, 10, 10) + strokeWeight(2) + for p in self.vers: + vertex(p.x, p.y) + endShape(CLOSE) + + def update_vers(self): + self.v0 = Cell.grid.get((self.ix-1, self.iy-1)) + self.v1 = Cell.grid.get((self.ix-1, self.iy+1)) + self.v3 = Cell.grid.get((self.ix+1, self.iy-1)) + self.v2 = Cell.grid.get((self.ix+1, self.iy+1)) + # if random(10) > 2: + self.vers = [self.v0, self.v1, self.v2, self.v3] + # elif random(2) > 1: + # self.vers = [self.v0, self.v1, self.v1, self.v3] + # else: + # self.vers = [self.v0, self.v2, self.v2, self.v3] + self.hatch() + + def hatch(self): + poly_points = self.vers + # min_, max_ = min_max(poly_points) + self.lines = [] + n = int(random(5, 12)) + r = random(10) + if r > 5: + self.lines.extend(par_hatch(poly_points, n, 0)) + if r < 6: + self.lines.extend(par_hatch(poly_points, n, 1)) + +def keyPressed(): + if key == "n": + init_grid(GRID_SIZE) + 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) + )