diff --git a/2019/sketch_190707a/sketch_190707a.png b/2019/sketch_190707a/sketch_190707a.png new file mode 100644 index 00000000..deed8884 Binary files /dev/null and b/2019/sketch_190707a/sketch_190707a.png differ diff --git a/2019/sketch_190707a/sketch_190707a.pyde b/2019/sketch_190707a/sketch_190707a.pyde new file mode 100644 index 00000000..b1dd4b17 --- /dev/null +++ b/2019/sketch_190707a/sketch_190707a.pyde @@ -0,0 +1,99 @@ +# Alexandre B A Villares - https://abav.lugaralgum.com/sketch-a-day +# More explorations of inerpolated combinations in grids + +from random import shuffle +from itertools import product, combinations, permutations, combinations_with_replacement +from var_bar import var_bar + +space, border = 40, 0 +position = 0 # initial position + + +def setup(): + global line_combos, W, H, position, num + size(820, 460) + frameRate(1) + rectMode(CENTER) + strokeWeight(2) + grid = product(range(-1, 1), repeat=2) # 2X2 + # all line combinations on a grid + lines = permutations(grid, 2) + # allow only some lines + possible_lines = [] + for l in lines: + (x0, y0), (x1, y1) = l[0], l[1] + if dist(x0, y0, x1, y1) < 2: # rule defined here... + possible_lines.append(l) + num_possible_lines = len(possible_lines) + println("Number of possible lines: {}".format(num_possible_lines)) + # main stuff + line_combos = list(combinations(possible_lines, 3)) + # shuffle(line_combos) # ucomment to shuffle! + num = len(line_combos) + println("Number of combinations: {}".format(num)) + W = (width - border * 2) // space + H = (height - border * 2) // space + println("Cols: {} Rows: {} Visible grid: {}".format(W, H, W * H)) + + +def draw(): + global position + background(240) + i = position + for y in range(H): + for x in range(W): + if i < len(line_combos): + pushMatrix() + # B option + # translate(border / 2 + space + space * x, + # border / 2 + space + space * y) + translate(border + space + space * x, + border + space + space * y) + draw_combo(i) + popMatrix() + i += 1 + if i < len(line_combos): + # gif_export(GifMaker, SKETCH_NAME) + # gif_export(GifMaker, SKETCH_NAME[:-1] + "b") # B option + position += H * W + +def draw_combo(n): + colorMode(HSB) + blendMode(MULTIPLY) + noStroke() + siz = space / 2. # B option + line_combo = line_combos[n] + combo_len = len(line_combo) + for i, single_line in enumerate(line_combo): + ni = (i + 1) % combo_len + next_line = line_combo[ni] + for j in range(4): + c = lerpColor(color(i * 64, 128, 128), color(ni * 64, 128, 128), j) + fill(c) + (x0, y0), (x1, y1) = lerp_poly(single_line, next_line, j / 3.) + var_bar(x0 * siz, y0 * siz, x1 * siz, y1 * siz, siz / 16, siz / 8) + +def keyPressed(): + global W, H + if key == "s": + saveFrame("####.png") + +def lerp_poly(p0, p1, t): + pts = [] + for sp0, sp1 in zip(p0, p1): + pts.append((lerp(sp0[0], sp1[0], t), + lerp(sp0[1], sp1[1], t))) + return pts + +def settings(): + from os import path + global SKETCH_NAME + SKETCH_NAME = path.basename(sketchPath()) + OUTPUT = ".png" + println( + """ +![{0}]({2}/{0}/{0}{1}) + +[{0}](https://github.com/villares/sketch-a-day/tree/master/{2}/{0}) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] +""".format(SKETCH_NAME, OUTPUT, year()) + ) diff --git a/2019/sketch_190707a/var_bar.py b/2019/sketch_190707a/var_bar.py new file mode 100644 index 00000000..3b6818bf --- /dev/null +++ b/2019/sketch_190707a/var_bar.py @@ -0,0 +1,100 @@ +def var_bar(p1x, p1y, p2x, p2y, r1, r2=None): + """ + Tangent/tangent shape on 2 circles of arbitrary radius + """ + if r2 is None: + r2 = r1 + #line(p1x, p1y, p2x, p2y) + d = dist(p1x, p1y, p2x, p2y) + ri = r1 - r2 + if d > abs(ri): + rid = (r1 - r2) / d + if rid > 1: + rid = 1 + if rid < -1: + rid = -1 + beta = asin(rid) + HALF_PI + with pushMatrix(): + translate(p1x, p1y) + angle = atan2(p1x - p2x, p2y - p1y) + rotate(angle + HALF_PI) + x1 = cos(beta) * r1 + y1 = sin(beta) * r1 + x2 = cos(beta) * r2 + y2 = sin(beta) * r2 + #print((d, beta, ri, x1, y1, x2, y2)) + beginShape() + b_arc(0, 0, r1 * 2, r1 * 2, + -beta - PI, beta - PI, mode=2) + b_arc(d, 0, r2 * 2, r2 * 2, + beta - PI, PI - beta, mode=2) + endShape(CLOSE) + + else: + ellipse(p1x, p1y, r1 * 2, r1 * 2) + ellipse(p2x, p2y, r2 * 2, r2 * 2) + +def b_arc(cx, cy, w, h, start_angle, end_angle, mode=0): + """ + A bezier approximation of an arc + using the same signature as the original Processing arc() + mode: 0 "normal" arc, using beginShape() and endShape() + 1 "middle" used in recursive call of smaller arcs + 2 "naked" like normal, but without beginShape() and endShape() + for use inside a larger PShape + """ + theta = end_angle - start_angle + # Compute raw Bezier coordinates. + if mode != 1 or theta < HALF_PI: + x0 = cos(theta / 2.0) + y0 = sin(theta / 2.0) + x3 = x0 + y3 = 0 - y0 + x1 = (4.0 - x0) / 3.0 + if y0 != 0: + y1 = ((1.0 - x0) * (3.0 - x0)) / (3.0 * y0) # y0 != 0... + else: + y1 = 0 + x2 = x1 + y2 = 0 - y1 + # Compute rotationally-offset Bezier coordinates, using: + # x' = cos(angle) * x - sin(angle) * y + # y' = sin(angle) * x + cos(angle) * y + bezAng = start_angle + theta / 2.0 + cBezAng = cos(bezAng) + sBezAng = sin(bezAng) + rx0 = cBezAng * x0 - sBezAng * y0 + ry0 = sBezAng * x0 + cBezAng * y0 + rx1 = cBezAng * x1 - sBezAng * y1 + ry1 = sBezAng * x1 + cBezAng * y1 + rx2 = cBezAng * x2 - sBezAng * y2 + ry2 = sBezAng * x2 + cBezAng * y2 + rx3 = cBezAng * x3 - sBezAng * y3 + ry3 = sBezAng * x3 + cBezAng * y3 + # Compute scaled and translated Bezier coordinates. + rx, ry = w / 2.0, h / 2.0 + px0 = cx + rx * rx0 + py0 = cy + ry * ry0 + px1 = cx + rx * rx1 + py1 = cy + ry * ry1 + px2 = cx + rx * rx2 + py2 = cy + ry * ry2 + px3 = cx + rx * rx3 + py3 = cy + ry * ry3 + # Debug points... comment this out! + # stroke(0) + # ellipse(px3, py3, 15, 15) + # ellipse(px0, py0, 5, 5) + # Drawing + if mode == 0: # 'normal' arc (not 'middle' nor 'naked') + beginShape() + if mode != 1: # if not 'middle' + vertex(px3, py3) + if theta < HALF_PI: + bezierVertex(px2, py2, px1, py1, px0, py0) + else: + # to avoid distortion, break into 2 smaller arcs + b_arc(cx, cy, w, h, start_angle, end_angle - theta / 2.0, mode=1) + b_arc(cx, cy, w, h, start_angle + theta / 2.0, end_angle, mode=1) + if mode == 0: # end of a 'normal' arc + endShape() diff --git a/README.md b/README.md index 9797b4f1..08606e3a 100644 --- a/README.md +++ b/README.md @@ -17,6 +17,11 @@ You may also support my artistic work, open teaching resources and research with --- ## 2019 +--- + +![sketch_190707a](2019/sketch_190707a/sketch_190707a.png) + +[sketch_190707a](https://github.com/villares/sketch-a-day/tree/master/2019/sketch_190707a) [[Py.Processing](https://villares.github.io/como-instalar-o-processing-modo-python/index-EN)] ---