BillyKeyes-13-9-65

by Billy @ 1:23 am 24 January 2012

Press SPACE to generate a new image.

/**
 * 13/9/65 on 23/1/12 
 *
 * Interactive Art and Computational Design
 * Billy Keyes, 2012
 * 
 * A generator of images similar to "13/9/65 Nr. 2" by Frieder Nake
 */
 
final int NUM_LINES = 9;
final int SEGMENTS = 6;
 
ArrayList lines;
 
void setup() {
  size(650, 650);
  smooth();
  noLoop();
 
  stroke(0);
  strokeWeight(1.25);
 
  lines = new ArrayList(NUM_LINES + 2);
}
 
void draw() {
  background(240);
 
  // Draw horizontal lines
  lines.add(drawSegmentedLine(SEGMENTS, 50, 0, 0));
  for (int i = 1; i < NUM_LINES; i++) {
    lines.add(drawSegmentedLine(SEGMENTS, 50, i * height / NUM_LINES, 40)); 
  }
  lines.add(drawSegmentedLine(SEGMENTS, 50, height, 0));
 
  // Draw vertical "connecting" lines
  for (int i = 0; i < lines.size() - 1; i++) {
    float[][] t = lines.get(i);
    float[][] b = lines.get(i+1);
    // Prefer higher numbers of connections between two given rows
    int connections = int(sqrt(random(1, 49)));
    for (int j = 0; j < connections; j++) {
      // Choose a segment to connect
      int seg = int(random(SEGMENTS));
      if (random(1) < 0.5) {
        drawStraightConnectingLines(new float[][]{t[seg], t[seg+1]}, 
                                    new float[][]{b[seg], b[seg+1]},
                                    int(random(3, 9)), random(0.2, 0.6), random(0.25, 1.0));
      } else {
        drawDiagConnectingLines(new float[][]{t[seg], t[seg+1]}, 
                                new float[][]{b[seg], b[seg+1]},
                                int(random(3, 9)), random(0.2, 0.6));
      }
    }
  }
 
  // Draw circles
  ellipseMode(CENTER);
  noFill();
  for (int i = 0; i < NUM_LINES; i++) {
    for (int j = 0; j < SEGMENTS; j++) {
      if (random(1) < 0.1) {
         float hf = (float) height;
         float wf = (float) width;
         float side = sqrt(random(16, sq(hf / (NUM_LINES - 3))));
         ellipse(wobble(wf / (SEGMENTS * 2) + j * wf / SEGMENTS, wf / SEGMENTS),
                 wobble(hf / (NUM_LINES * 2) + i * hf / NUM_LINES, hf / NUM_LINES),
                 side, side);
      }
    }
  }
}
 
 
/**
 * @param segs  The number of segments to draw
 * @param dx    The amount of x variation in segment endpoints
 * @param y     The base y coordinate of segment endpoints
 * @param dy    The amount of y variation in segment endpoints
 */
float[][] drawSegmentedLine(int segs, float dx, float y, float dy) {
  float[][] points = new float[segs + 1][2];
  points[0][0] = 0;
  points[0][1] = wobble(y, dy);
 
  for (int i = 1; i <= segs; i++) {
    points[i][0] = (i == segs) ? width : wobble(i * width / segs, dx);
    points[i][1] = wobble(y, dy);
    line(points[i - 1][0], points[i - 1][1], points[i][0], points[i][1]);
  }
  return points;
}
 
 
/**
 * @param top       The top set of segments
 * @param bottom    The bottom set of segments
 * @param density   Approximately the number of clusters to draw
 * @param cluster   Influences how many lines are in each cluster (greater than 0.25)
 * @param spread    How much of the segment is filled with lines (between 0.0 and 1.0)
 */
void drawStraightConnectingLines(float[][] top, float[][] bottom, int density, float cluster, float spread) {
  for (int i = 0; i < top.length; i += 2) {
    float xl = max(top[i][0], bottom[i][0]);
    float xr = min(top[i+1][0], bottom[i+1][0]);
    float diff = spread * (xr - xl);
    float base = random(xl, xr - diff);
 
    density = density + int(random(0, 2));
    for (int j = 1; j < density; j++) {
      for (int k = 0; k < cluster * 4; k++) {
        float x = base + wobble(j * diff / density, cluster * diff / density);
        float yt = ylerp(top, i, x);
        float yb = ylerp(bottom, i, x);
        line(x, yt, x, yb);
      }
    }
  }
}
 
 
/**
 * @param top       The top set of segments
 * @param bottom    The bottom set of segments
 * @param density   Approximately the number of clusters to draw
 * @param cluster   Influences how many lines are in each cluster (greater than 0.25)
 */
void drawDiagConnectingLines(float[][] top, float[][] bottom, int density, float cluster) {
  for (int i = 0; i < top.length; i += 2) {
    float[][] src, dest;
    if (random(1) < 0.5) {
      src = top;
      dest = bottom;
    } else {
      src = bottom;
      dest = top;
    }
 
    float diff = src[i+1][0] - src[i][0];
    density = density + int(random(0, 2));
    for (int j = 1; j < density; j++) {
      for (int k = 0; k < cluster * 4; k++) {
        float xs = src[i][0] + wobble(j * diff / density, cluster * diff / (density + 1));
        float xd = random(dest[i][0], dest[i+1][0]);
        float ys = ylerp(src, i, xs);
        float yd = ylerp(dest, i, xd);
        line(xs, ys, xd, yd);
      }
    }
  }
}
 
 
/**
 * Produces a random value at most dv/2 away from the given value.
 */
float wobble(float v, float dv) {
  return v + random(-dv / 2, dv / 2);
}
 
 
/**
 * Linear interpolation to find the y coordinate on the degment for the
 * given x coordinate.
*/ 
float ylerp(float[][] points, int i, float x) {
  return lerp(points[i][1], points[i+1][1], (x - points[i][0]) / (points[i+1][0] - points[i][0])); 
}
 
 
void keyPressed() {
  if (key == ' ') {
    lines.clear();
    redraw();
  }
}

Download (PDF, 17KB)

This work is licensed under a Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License.
(c) 2023 Interactive Art and Computational Design, Spring 2012 | powered by WordPress with Barecity