diff --git a/README.md b/README.md index 0d7c6135..37aac448 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,14 @@ If you enjoy this, be a [patreon](https://patreon.com/arteprog) or make a donati Feel free to [contact me](http://contato.lugaralgum.com) regarding licenses to use my work, teaching opportunities, consulting or other projects. + +--- + +![s332](s332/s332.png) + +332: [code](https://github.com/villares/sketch-a-day/tree/master/s332) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] + + --- ![s331](s331/s331.png) diff --git a/s332/gif_exporter.py b/s332/gif_exporter.py new file mode 100644 index 00000000..9b48b504 --- /dev/null +++ b/s332/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/s332/line_geometry.py b/s332/line_geometry.py new file mode 100644 index 00000000..4e116ea5 --- /dev/null +++ b/s332/line_geometry.py @@ -0,0 +1,146 @@ + +def create_points(num, border=0, 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/s332/s332.png b/s332/s332.png new file mode 100644 index 00000000..edae0d21 Binary files /dev/null and b/s332/s332.png differ diff --git a/s332/s332.pyde b/s332/s332.pyde new file mode 100644 index 00000000..e532c4b9 --- /dev/null +++ b/s332/s332.pyde @@ -0,0 +1,60 @@ + +# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +SKETCH_NAME = "s332" # 20181126 +OUTPUT = ".png" +NUM = 5 +BORDER = 50 + +from line_geometry import * + +#add_library('pdf') +# add_library('gifAnimation') +# from gif_exporter import gif_export + +def setup(): + size(500, 500) + smooth(8) + init_points(NUM, BORDER) + background(200) + print edges(points) + #beginRecord(PDF, SKETCH_NAME + ".pdf") + +def draw(): + background(200) + stroke(0, 100) + strokeWeight(0.1) + for pair in edges(points): + l = Line(*pair) + l.plot() + strokeWeight(0.5) + noFill() + for p in points: + ellipse(p.x, p.y, 7, 7) + + +def keyPressed(): + if key == "n" or key == CODED: + init_points(NUM, BORDER) + background(200) + #saveFrame("###.png") + if key == "s": saveFrame(SKETCH_NAME + ".png") + if key == "z": + for pair in edges(points): + p = PVector.lerp(pair[0], pair[1], randomGaussian()/4 ) + points.append(p) + l = Line(*pair) + l.plot() + +def init_points(grid_size, border=0): + global points + points = create_points(grid_size, border) + +# 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) + )