dinkolas – MolnarRecode

I dunno if I’m crazy, but I think the p5 svg thing breaks the pop() function, so I learned how to invert my goddang transformations.

let dosvg = true;
const edgeRoom = 30;
const Wm = 12;
const Hm = 12;
const Lm = 40;
const Sw = dosvg ? 0.8 : 0.015;

function diags(d) {
  push();
  let dangus = randomHalf();
  
  for (let i = -d + 1; i < d; i++) {
    let x0 = constrain(map(i, 0, d, 0, 1), 0, 1);
    let x1 = constrain(map(i, 0, d, 1, 2), 0, 1);
    let y0 = constrain(map(i, -d, 0, 1, 0), 0, 1);
    let y1 = constrain(map(i, 0, d, 1, 0), 0, 1);
    if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) console.log('dingus');
    strokeWeight(Sw);
    line(x0,y0,x1,y1);
  }
  unRandomHalf(dangus);
  pop();
}

function halfdiags(d) {
  push();
  let dangus = randomHalf();
  
  for (let i = 0; i < d; i++) {
    let x0 = constrain(map(i, 0, d, 0, 1), 0, 1);
    let x1 = constrain(map(i, 0, d, 1, 2), 0, 1);
    let y0 = constrain(map(i, -d, 0, 1, 0), 0, 1);
    let y1 = constrain(map(i, 0, d, 1, 0), 0, 1);
    if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) console.log('dingus');
    strokeWeight(Sw);
    line(x0,y0,x1,y1);
    
  }
  unRandomHalf(dangus);
  pop();
}

function tri(d) {
  push();
  let dangus = randomHalf();
  
  for (let i = 0; i < d; i++) {
    let x0 = constrain(map(i, 0, d, 0, 1), 0, 1);
    let x1 = constrain(map(i, 0, d, 0.5, 1), 0, 1);
    let y0 = 0; //constrain(map(i, -d, 0, 1, 0), 0, 1);
    let y1 = constrain(map(i, 0, d, 1, 0), 0, 1);
    if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) console.log('dingus');
    strokeWeight(Sw);
    line(x0,y0,x1,y1);
  }
  
  unRandomHalf(dangus);
  pop();
}

function f0() {
  diags(2);
}
function f1() {
  diags(5);
}
function f2() {
  diags(7);
}
function f3() {
  diags(11);
}

function f4() {
  halfdiags(2);
}
function f5() {
  halfdiags(5);
}
function f6() {
  halfdiags(7);
}
function f7() {
  halfdiags(11);
}

function f8() {
  halfdiags(1);
}

function f9() {
  tri(5);
}
function f10() {
  tri(7);
}

function f11() {
  diags(4);
}
function f12() {
  halfdiags(4);
}

function para(d) {
  push();
  let dangus = randomQuarter();
  
  for (let i = 1; i < d; i++) {
    let x0 = map(i, 0, d, 0, 1);
    let x1 = 1;
    let y0 = 0;
    let y1 = map(i, 0, d, 0, 1);
    if (isNaN(x0) || isNaN(x1) || isNaN(y0) || isNaN(y1)) console.log('dingus');
    strokeWeight(Sw);
    line(x0,y0,x1,y1);
  }
  
  unRandomQuarter(dangus);
  pop();
}

function f13() {
  para(3);
}
function f14() {
  para(5);
}

let sectionFunctions = [f0, f1, f1, f2, f2, f3, f4, f5, f5, f6, f6, f7, f8, f0, f1, f1, f2, f2, f3, f4, f5, f5, f6, f6, f7, f8, f9, f10, f11, f12, f0, f1, f1, f2, f2, f3, f4, f5, f5, f6, f6, f7, f8, f0, f1, f1, f2, f2, f3, f4, f5, f5, f6, f6, f7, f8, f9, f10, f11, f12, f13, f14];

function setup() {
  if (dosvg) createCanvas(2*edgeRoom + Wm*Lm, 2*edgeRoom + Hm*Lm, SVG);
  else createCanvas(2*edgeRoom + Wm*Lm, 2*edgeRoom + Hm*Lm);
  noLoop();
}

function draw() {
  drawVera();
  /*push();
  translate(10,100);
  scale(0.99,0.5);
  line(0,0,width,height);
  pop();*/
}

function drawVera() {
  //let bg = 240;
  //background(bg);
  clear();
  stroke(0);
  //strokeWeight(0.015);
  strokeWeight(Sw);
  noFill();
  for (let i = 0; i < Hm; i++) {
    for (let j = 0; j < Wm; j++) {
      /*line(edgeRoom + j*Lm, edgeRoom + i*Lm,
          edgeRoom + j*Lm + Lm*0.6, edgeRoom + i*Lm + Lm*0.8);*/
      push();
      translate(edgeRoom + j*Lm, edgeRoom + i*Lm);
      scale(Lm);
      //line(0,0,0.8,0.8);
      drawSection();
      
      scale(1/Lm);
      translate(-edgeRoom - j*Lm, -edgeRoom - i*Lm);
      pop();
    }
  }
  //fill(bg);
  //noStroke();
  //rect(0,0,edgeRoom,height);
  //rect(width - edgeRoom,0,edgeRoom,height);
}

function keyPressed() {
  saveSVG("vera.svg");
}

function drawSection() {
  //line(0, 0, 0.8, 0.8);
  let r = Math.random();
  let numSections = r < 0.02 ? 0 : r < 0.1 ? 1 : r < 0.8 ? 2 : 3;
  for (let s = 0; s < numSections; s++) {
    let i = Math.floor(Math.random() * sectionFunctions.length);
    let f = sectionFunctions[i];
    f();
  }
}

function randomHalf() {
  let vertical = Math.random() < 0.5 ? 1 : 0;
  let horizontal = 1 - vertical;
  let offset = Math.random() < 0.5 ? 1 : 0;
  let fh = Math.random() < 0.5; //flip horizontal
  let fv = Math.random() < 0.5; //flip vertical
  
  scale(1 - 0.5*vertical, 1 - 0.5*horizontal);
  translate(vertical * offset, horizontal * offset);
  if (fh) {
    scale(-1, 1);
    translate(-1, 0);
  }
  if (fv) {
    scale(1, -1);
    translate(0, -1);
  }
  
  return {vertical, horizontal, offset, fh, fv};
}

function unRandomHalf(dangus) {
  let {vertical, horizontal, offset, fh, fv} = dangus;
  
  if (fv) {
    translate(0, 1);
    scale(1, -1);
  }
  if (fh) {
    translate(1, 0);
    scale(-1, 1);
  }
  translate(-vertical * offset, -horizontal * offset);
  scale(1 / (1 - 0.5*vertical), 1 / (1 - 0.5*horizontal));
}

function randomQuarter() {
  let x = Math.random() < 0.5 ? 1 : 0;
  let y = Math.random() < 0.5 ? 1 : 0;
  let f1 = Math.random() < 0.5;
  let f2 = Math.random() < 0.5;
  
  scale(0.5,0.5);
  translate(x, y);
  if (f1) {
    scale(-1, 1);
    translate(-1, 0);
  }
  if (f2) {
    scale(1, -1);
    translate(0, -1);
  }
  
  return {x, y, f1, f2};
}

function unRandomQuarter(z) {
  let {x, y, f1, f2} = z;
  
  if (f2) {
    translate(0, 1);
    scale(1, -1);
  }
  if (f1) {
    translate(1, 0);
    scale(-1, 1);
  }
  translate(-x, -y);
  scale(2,2);
}

 

gabagoo-MolnarRecode

Observations: 
1. grid of equally spaced squares
2. some squares are split
3. areas are shaded by 'hatching'
4. some areas are split into a triangle
5. the hatching concentration varies
6. sometimes there is no hatching (blank area)
7. hatched areas overlap into cross-hatches
8. there stroke color is black
9. there are some inconsistencies with the hatching
10. the hatching direction is variable

^^ SVG ^^
 


^^ pixel image (from before I messed up the code) ^^


^^ I also experimented with color ^^
LIVE EXAMPLE + CODE
let rows, cols, grain = 15
let colors = ['#eb4034', '#3459eb', '#ffe019', '#404040']

function setup() {
  var SQ_SIZE = min(windowWidth, windowHeight) * .75
  createCanvas(SQ_SIZE, SQ_SIZE, SVG).position((windowWidth - width) / 2, (windowHeight - height) / 2)

  rows = int(width / grain)
  cols = int(height / grain)
  stroke(0)
  strokeWeight(map(grain, 10, 100, .1, 5))
  strokeCap(ROUND)
  noLoop()
}

function draw() {
  background(255)

  for (var i = 0; i < rows; i++) {
    for (var j = 0; j < cols; j++) {

      if (random(0, 1) < .2) {
        drawHatchedRect(i * grain, j * grain, 2 * grain, 2 * grain)
      }
      else {
        if (random(0, 1) < .5) drawHatchedRect(i * grain, j * grain, grain, 2 * grain)
        if (random(0, 1) < .5) drawHatchedRect(i * grain, j * grain, 2 * grain, grain)
      }

    }
  }
}

function drawHatchedRect(x, y, w, h) {

  let divisions = int(random(-3, 10))
  let hatch_dir = random(0, 1) < 0.5
  let sided = random(0, 1) < 0.5

  push()
  translate(x, y)
  if (hatch_dir) {
    rotate(PI/2)
    var temp = w
    w = h
    h = temp
    translate(0, -h)
  }
  
  // define points
  var top = new p5.Vector(0, 0)
  var bot = new p5.Vector(w, h)
  var rand = random(0, 1) < 0.5
  // stroke(color(random(colors)))

  for (var i = 0; i < divisions; i++) {

    var x_off = i * (w / divisions)
    var y_off = i * (h / divisions)

    if (sided) {
      if (rand) line(top.x, top.y + y_off, bot.x - x_off, bot.y)
      else line(top.x + x_off, top.y, bot.x, bot.y - y_off)
    }
    else {
      line(top.x, top.y + y_off, bot.x - x_off, bot.y)
      line(top.x + x_off, top.y, bot.x, bot.y - y_off)
    }
  }
  pop()

}

function reDraw() {
  grain = int(random(10, 50))
  setup()
  redraw()
}

function mousePressed() {reDraw()}

function keyPressed() {
  if (key == 'd') {
      save('plot.svg')
  }
}

function windowResized() {
  setup()
  reDraw()
}

lemonbear-MolnarRecode

Molnar “Searching for Paul Klee” Observations:

  1. The piece is a grid of many squares
  2. The squares have different things happening inside of them
  3. Sometimes there are sub-rectangles, sub-squares, or sub-triangles within these squares, but never any other subdivisions
  4. There are only diagonal lines drawn with differing densities
  5. These diagonal lines are oriented in different directions
  6. There are also implied curves due to the fact that some of these diagonal lines will vary angles within a subspace
  7. Nearly all of the time there are 2 sub rectangles at differing orientations within a cell
  8. However, there are also (not… infrequently) triangles composing half a rectangle (these also often come in pairs).
  9. There are sometimes other triangles, like those which occupy half a square and those which are a fourth of the square, but in a different orientation
  10. Often, these half-rectangle triangles meet in the middle. I didn’t code this super well

I made the actual SVG way too big (~20 MB) to upload to WordPress, so here is the link to download it from Drive.

Here is an (almost) full pixel screenshot:

Here is a close up pixel screenshot:

I actually probably spent more time on this than my line walk (oops). I found it to be a really engaging exercise! I only wrote about 6 observations before getting bored and starting the code, and during the programming process I made way more minute observations than I did while just looking at it (my ten listed observations don’t encapsulate the full extent of everything I observed and implemented). Here is my code:

// Uses https://github.com/zenozeng/p5.js-svg to export SVG.
// noprotect
function setup() {
  createCanvas(816*4, 1056*4, SVG); 
  noLoop(); 
}

function makeSubsection(x1, y1, pixelDim, rot, type) {
  var x2 = 0;
  var y2 = 0;
  if (rot == 0) {
    //top
    x2 = x1 + pixelDim;
    y2 = y1 + pixelDim/2;
  }
  else if (rot == 1) {
    //bottom
    x2 = x1 + pixelDim;
    y1 += pixelDim/2;
    y2 = y1 + pixelDim/2;

  }
  else if (rot == 2) {
    //left
    x2 = x1 + pixelDim/2;
    y2 = y1 + pixelDim;
  }
  else if (rot == 3) {
    //right
    x1 += pixelDim/2;
    x2 = x1 + pixelDim/2;
    y2 = y1 + pixelDim;
  }
  var density = Math.floor(Math.pow(Math.random(), 1) * 12);
  var xMargin = (x2-x1+1)/density;
  var yMargin = (y2-y1+1)/density;
  if (type < .75) { //half rectangle
    var direction = Math.floor(Math.random()*2);
    // console.log(rot);
    // console.log(x1, y1, x2, y2);
    if (direction == 0) {
      for (var i = x1; i < x2; i+=xMargin) {
        for (var j = y1; j < y2; j+=yMargin) { line(i, j, i+xMargin, j+yMargin); } } } else { for (var i = x2; i > x1; i-=xMargin) {
        for (var j = y1; j < y2; j+=yMargin) {
          line(i, j, i-xMargin, j+yMargin);
        }
      }
    }
    if (rot == 3 && Math.random() < 0.1) {
      x1 -= pixelDim/2;
      y2 -= pixelDim/2;
      xMargin = (x2-x1+1)/density;
      yMargin = (y2-y1+1)/density;
      for (var n = 0; n < density; n++) {
        line(x1+n*xMargin, y1, x2-pixelDim/2, y1+(n+1)*yMargin)
      }
      x1 += pixelDim/2;
      x2 += pixelDim/2;
      for (var n = 0; n < density; n++) {
        line(x1+n*xMargin, y2, x2-pixelDim/2, y1+(n-1)*yMargin)
      }
    }
  }
  else if (type < .9) { //half triangle in half rectangle 
    var direction = Math.floor(Math.random()*4);
    if (direction == 0) {
      for (var n = 0; n < density; n++) {
        //upper-right
        line(x1+n*xMargin, y1, x2, y2-n*yMargin);
      }
    }
    else if (direction == 1) {
      for (var n = 0; n < density; n++) {
        //lower-right
        line(x1+n*xMargin, y2, x2, y1+n*yMargin);
      }
    }
    else if (direction == 2) {
      for (var n = 0; n < density; n++) {
        //lower-left
        line(x1, y1+n*yMargin, x2-n*xMargin, y2);
      }
    }
    else if (direction == 3) {
      for (var n = 0; n < density; n++) {
        //upper-left
        line(x2-n*xMargin, y1, x1, y2-n*yMargin);
      }
    }
  }
  else if (type < 1) {
    if (rot == 0) {
      for (var n = 0; n < density; n++) {
        //top
        line(x1+n*xMargin, y1, x2-pixelDim/2+n*xMargin/2, y2-n*yMargin);
      }
    }
    else if (rot == 1) {
      for (var n = 0; n < density; n++) {
        //bottom
        line(x1+n*xMargin, y2, x2-pixelDim/2+n*xMargin/2, y1+n*yMargin);
      }
    }
    else if (rot == 2) {
      for (var n = 0; n < density; n++) {
        //left
        line(x1, y1+n*yMargin, x2-n*xMargin, y2-pixelDim/2+n*yMargin/2);
      }
    }
    else if (rot == 3) {
      for (var n = 0; n < density; n++) {
        //right
        line(x2, y1+n*yMargin, x1+n*xMargin, y2-pixelDim/2+n*yMargin/2);
      }
    }  
  }
}

function draw() {

  var squaresWide = 8.5*4;
  var squaresHigh = 11*4;
  
  var pixelDim = width/squaresWide;

  for (var x = 0; x < squaresHigh; x++) {
    for (var y = 0; y < squaresWide; y++) {
      var rot1 = Math.floor(Math.random() * 4);
      var rot2 = (rot1 + Math.floor(Math.random() * 3) + 1)%4;
      console.log(rot1, rot2);
      var type = (Math.random());
      makeSubsection(x*pixelDim, y*pixelDim, pixelDim, rot1, type);
      makeSubsection(x*pixelDim, y*pixelDim, pixelDim, rot2, type);
      
    }
  } 
  // saveSVG("molnar_redraw_v3.svg");
}

lsh-MolnarRecode

1. Some of the lines are orthogonal to each other.
2. Some of the lines make a triangle filling half of the cell.
3. Some lines seem to be darker than the others.
4. Some of the patterns seem to have the same “scale” but less distance between lines.
5. There seems to be multiple scales of grids interacting.
6. Some cells overlap creating a cross hatch.
7. Some angles made a “wide” diamond, while others make a “tall” diamond.
8. Several of the interactions near the center almost form a curve.
9. The largest shape seems to be “16” small blocks (4 big blocks) in the top left corner.
10. It “feels” like there is more void than line.


I think I spent too much time working at a small scale in this work. In the end I don’t feel like I captured the general feel because I focused on little segments. I also spent a lot of time fighting with texturesjs, which was probably time I should have spent in a tool with which I was more familiar. Overall this drawing feels too heavy and I don’t think I captured the angles or interactions all that well.

const width = 761;
const height = width;

function generateRandomNumbers({ num_squares, N }) {
  const m = new Map();
  const out = [];
  while (out.length  d[0]))
  .range([0, width]);
const sy = d3
  .scaleBand()
  .domain(idx.map((d) => d[1]))
  .range([height, 0]);

const t1 = textures.lines().size(5).strokeWidth(1).orientation("2/8");
const t2 = textures.lines().size(5).strokeWidth(1).orientation("6/8");
const t3 = textures.lines().size(25).strokeWidth(1).orientation("7/8");
const t4 = textures.lines().size(25).strokeWidth(1).orientation("1/8");
const t5 = textures.lines().size(50).strokeWidth(1).orientation("5/8");
const t6 = textures.lines().size(50).strokeWidth(1).orientation("3/8");


function generate() {
  const svg = d3.create("svg").attr("width", width).attr("height", height);
  [t1, t2, t3, t4, t5, t6].forEach((t) => svg.call(t));

  svg.select(`pattern#${t4.id()}`).attr("patternTransform", "translate(3)");

  svg
    .selectAll(".rect38")
    .data(generateRandomNumbers({ num_squares, N: 500 }))
    .join("rect")
    .attr("fill", t1.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect78")
    .data(generateRandomNumbers({ num_squares, N: 500 }))
    .join("rect")
    .attr("fill", t2.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect2x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t3.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect22x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t4.url())
    .attr("x", ([x, _]) => sx(x))
    .attr("y", ([_, y]) => sy(y))
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect4x")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t5.url())
    .attr("x", ([x, _]) => sx(x) * 2)
    .attr("y", ([_, y]) => sy(y) * 2)
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  svg
    .selectAll(".rect4x2")
    .data(generateRandomNumbers({ num_squares, N: 300 }))
    .join("rect")
    .attr("fill", t6.url())
    .attr("x", ([x, _]) => sx(x) * 2)
    .attr("y", ([_, y]) => sy(y) * 2)
    .attr("width", sx.bandwidth())
    .attr("height", sy.bandwidth());

  return svg.node();
}

generate();

grape – MolnarRecode

Closeup:

My observations:

  1. The painting is 68 x 68 grid of square cubes.
  2. There are three-four tiers of line drawings, one that spans the 68×68 grid, and one that spans the 34×34 grid, drawing over the grid of smaller cubes
  3. There are at most three types of lines on any square in the grid
  4. One “lining” either occupies a 1×1, 2×1, 1×2, 1×3 or 2×2 rectangle
  5. the 1×1 cubes are a line from one corner to the center of the square
  6. 1×3 rectangles can be one of two patterns. The first of which is composed of two identical 1×1 squares, the left of which has (up to) 4 lines from the top-most side which connect halfway up the adjacent right side of the square. There is also probability of the presence or absence of a single 1/2 length line on the right side. The right square diagonally mirrors the pattern of the left square. Between these identical squares is a 1×1 square which, (for the half to the left of the diagonal) depending on the n number of lines used in the left and right squares maps n equidistant lines from the bottom 1/2 of the square to the to the top of the square, giving  a tilted appearance. The lines in the middle square are always diagonal lines reaching from the bottom left corner to the upper right. The second pattern is composed of an obtuse triangle, whose obtuse angle is located in between the middle and rightmost square. the shortest side is along a diagonal on the rightmost square while the longest side connects the bottom left corner of the leftmost square with the top right corner of the rightmost square. There are lines running parallel to the longest leg varying from 1 to 10 (i think…but it’s blurry) that exclude the diagonal.
  7. 2×1 and 1×2 rectangles can be parallel lines that take up the entire rectangle, parallel lines that take up a right triangle/diagonal half of the rectangle, or only an isosceles triangle amount of the rectangle (where the single side of non equal length is 2) and can vary in number of lines from 1 to 12, though some of these 1×2 or 2×1 rectangles are left blank.
  8. Similar to rule 7, 2×2 rectangles are either parallel lines that take up the entire rectangle or parallel lines that take up a diagonal half of the rectangle, with lines that vary from 1 to 11. 2×2 rectangles that cover the entire rectangle are completely unobstructed(or at least have a lower probability of being covered up) – they don’t have additional lines over top (other than probability for larger stroke weight for the middle diagonal line), but 2×2 rectangles that only cover a diagonal half can have additional lines.
  9. To keep in line with the previous rules regarding pattern size, I amend my first observation; the piece is actually 68×70 squares, but the leftmost and rightmost columns have been cut out, such that there appears to be two 68×1 patterns on the edge. There is no such rule for the top and bottom rows, and 2×2 and 1×2 square patterns can be seen in its entirety on the top and bottom rows (excluding the leftmost and rightmost entries)
  10. Some of the diagonals through 2×1, 1×2, and 2×2 regions look thicker, indicating a possible fifth tier to add in a larger stroke weight…and there’s no white border.

Code:

Overall this experience was pretty annoying because there were so many different types of shapes. Also, even though I had counted the number of lines per shape in the original work, I inevitably had to scale down the number of lines in each shape because they blended together in the resulting svg (e.g. 12 lines down to 7). I think the components are similar to Molnar’s work but I just gave up tweaking the probabilities to make it super accurate. I spent 5 ish hours (which is way too long) on this assignment because I was too obsessed with getting all the shapes. smh.


import processing.svg.*;

int dim = 768;
int xCells = 36;
int yCells = 35;
// dimension of a single 1x1 square
float sDim = dim/(34 * 2);
int[] square;

void settings() {
  size(dim, dim);
}

void setup() {
  square = new int[5];
  noLoop(); // Just execute once!
}

void draw() {
  background(255);
  beginRecord(SVG, "paul-klee-molnar.svg");

  stroke(0);
  noFill(); // Don't create duplicate shapes!
  for (int row =0; row<xCells; row++) {
    for (int col =0; col<yCells; col++) {
      float section = random(1.0);
      if(section<0.2){ //zero items
         // do nothing
      }else if(section <0.2){ // one item
        drawRand(row, col, 1);
      }else if(section < 0.8){ // two items drawRand(row, col, 2); }else{ // three items drawRand(row, col, 3); } if(random(1,0)>0.5){
        if(random(1.0) < 0.5){
          drawDiag(1, row, col,1,2,int(random(0, 2)));
        }else{
          drawDiag(1, row, col,2,int(random(1,3)),int(random(0, 2)));
        }
      }
    }
  }
  endRecord();
}


void drawUniqueDiag(int posX, int posY, int items){
  int x = int(random(1, 3));
  float bias = 0.4;
  if(items ==1) bias = 0.0;
  if(random(1.0)< 0.33){
    int dir = int(random(0, 2));
    if(square[dir] ==0){
      drawDiag(int(random(1, 9)), posX, posY, 1, 2, dir);
      square[dir] = 1;
    }else drawUniqueDiag(posX,posY,items);
  }else {
    if((random(1.0) + bias) < 0.5){
      drawDiag(int(random(1, 9)), posX, posY, 2, 2, int(random(0, 2)));
    }else{
      int dir = int(random(2, 4));
      if(square[dir] ==0){
        drawDiag(int(random(1, 9)), posX, posY, 2, 1, dir-2);
        square[dir] = 1;
      }else drawUniqueDiag(posX,posY,items);
    }
  }
}


void drawRand(int posX, int posY, int items){
  for(int i = 0; i<5; i++){
    square[i] = 0;
  }
  for(int i = 0; i<items;i++){
    float shape = random(1.0);
    if(shape<0.04){ //Obtuse Triangle
      drawObtuse(posX, posY, int(random(1,6)));
    }else if(shape <0.08){ // Fan Thingy
      drawFan(posX, posY, int(random(1,4)));
    }else if(shape < 0.75){ // Diagonal, Half & Full 
      drawUniqueDiag(posX, posY, items);
    }else if(shape < 0.96){ // Isoceles Triangle
      drawTriangle(posX, posY, int(random(1, 7)));
    }else{ // Chord
      drawChord(posX,posY);
    }
  }
}


void drawLine(float posXa, float posYa, float posXb, float posYb) {
  // assert that posXa < posXb
  float xa = posXa - sDim;
  float ya = posYa;
  float xb = posXb - sDim;
  float yb = posYb;
  if(xb < 0 || xa >= width){
    //do nothing
  }else{
    if(xa < 0){ float slope = (posYb-posYa)/(posXb-posXa); ya = ya + slope*(-xa); xa = 0; } if(xb > width){
      float slope = (posYb-posYa)/(posXb-posXa);
      yb = yb - slope*(xb-width);
      xb = width;
    }
    line(xa,ya,xb,yb);
  }
}


void drawDiag(int numLines, int posX, int posY, int w, int h, int quad) {
  /* draws diagonal lines for some contraints hxw box
   *
   * numLines are the max number of lines touching a side of the rect
   * posX and poxY indicate square in grid
   */
  float wDist = sDim * w;
  float hDist = sDim * h;
  float wInc = wDist/numLines;
  float hInc = hDist/numLines;
  float baseX = posX*sDim*2;
  float baseY = posY*sDim*2;
  if(h == 1 && quad==1) baseY = baseY + sDim;
  if(w == 1 && quad==1) baseX = baseX + sDim;
  // if dir ==1, then diag goes from bottom left to top right
  boolean dir = boolean(int(random(0, 2)));
  int shape = int(random(0,3));
  if (dir) { // bottom left to top right
    for (int i=0; i<numLines; i++) {
      if(shape == 0){
        // bottom triangle
        drawLine(baseX+(i*wInc), baseY+hDist, baseX+wDist, baseY + (i*hInc));
      }else if(shape ==1){
        // top triangle
        drawLine(baseX, baseY+((i+1)*hInc), baseX+((i+1)*wInc), baseY);
      }else{
        // bottom triangle
        drawLine(baseX+(i*wInc), baseY+hDist, baseX+wDist, baseY + (i*hInc));
        // top triangle
        drawLine(baseX, baseY+((i+1)*hInc), baseX+((i+1)*wInc), baseY);
      }
      
    }
  } else { // top left to bottom right
    for (int i=0; i<numLines; i++) {
      if(shape ==0){
        // top triangle
        drawLine(baseX+(i*wInc), baseY, baseX + wDist, baseY + (hDist - (i*hInc)));
      }else if(shape ==1){
        // bottom triangle
        drawLine(baseX, baseY + (i*hInc), baseX+(wDist - (i*wInc)), baseY + hDist);
      }else{
        // top triangle
        drawLine(baseX+(i*wInc), baseY, baseX + wDist, baseY + (hDist - (i*hInc)));
        // bottom triangle
        drawLine(baseX, baseY + (i*hInc), baseX+(wDist - (i*wInc)), baseY + hDist);
      }  
    }
  }
}


void drawObtuse(int posX, int posY, int numLines) {
  int divider = numLines+1;
  float wInc = (sDim * 2)/divider;
  float hInc = sDim/divider;
  float baseX = posX*sDim*2;
  float baseY = posY*sDim*2;
  for (int i = 1; i <= numLines; i++) {
    drawLine(baseX + (wInc*i), baseY + (sDim*2), baseX+(sDim * 3) - (hInc*i), baseY + sDim + (hInc*i));
  }
}


void drawFan(int posX, int posY, int numLines) {
  int divider = numLines+1;
  float horizSpace = sDim/divider;
  float vertSpace = horizSpace/2;
  float baseX = posX*sDim*2;
  float baseY = posY*sDim*2;
  // terrible code, but I have to separate the three components to satisfy the assert in drawLine
  for (int i = 1; i <= numLines; i++) {
    drawLine(baseX + (horizSpace * i), baseY, baseX + sDim, baseY + (vertSpace * i));
    drawLine(baseX + (2*sDim), baseY + sDim - (i * vertSpace), baseX + (3*sDim) - (i* horizSpace), baseY + sDim);
  }
  for (int i = 1; i<=numLines; i++) {
    drawLine(baseX+sDim, baseY + (sDim/2) + (i*vertSpace), baseX + sDim + (i*horizSpace), baseY);
    drawLine(baseX + sDim + (i*horizSpace), baseY + sDim, baseX + (2* sDim), baseY + (i*vertSpace));
  }
  // diagonal
  drawLine(baseX + sDim, baseY + sDim, baseX + (2*sDim), baseY);
  if (int(random(0, 2)) < 1) {
    drawLine(baseX + sDim, baseY, baseX + sDim, baseY+(sDim/2));
    drawLine(baseX + (2*sDim), baseY + (sDim/2), baseX + (2*sDim), baseY + sDim);
  }
}


void drawChord(int posX, int posY){
  float baseX = posX*sDim*2;
  float baseY = posY*sDim*2;
  if(random(1.0)<0.5){
    drawLine(baseX, baseY + sDim, baseX+(sDim/2), baseY + ((sDim*3)/2));
  }else{
    drawLine(baseX+ ((sDim*3)/2), baseY + ((sDim*3)/2), baseX+(2*sDim), baseY + sDim);
  }
}


void drawTriangle(int posX, int posY, int numLines) {
  int divider = numLines + 1;
  float hInc = (sDim*2)/divider; // hypotenuse, over length 2*sdim
  float dInc = sDim/divider; // shorter legs that rest on the diagonal of the grid
  float baseX = posX*sDim*2;
  float baseY = posY*sDim*2;
  int position = int(random(0, 4));
  if (position==0) { //up down triangles
    int dir = int(random(0, 2));
    for (int i = 1; i <= numLines; i++) {// 0 top, 1 bottom
      float ax = i*hInc;
      float ay = dir*2*sDim;
      float bx = sDim + (i*dInc);
      float by = sDim + (((2*dir)-1)*dInc*i);
      drawLine(baseX + ax, baseY + ay, baseX + bx, baseY + by);
    }
  } else if (position==1) { //up down triangles
    int dir = int(random(0, 2));
    for (int i = 1; i <= numLines; i++) {// 0 top, 1 bottom
      float ax = i*dInc;
      float ay = sDim + ((2*dir)-1)*(sDim -(dInc*i));
      float bx = i*hInc;
      float by = dir*2*sDim;
      drawLine(baseX + ax, baseY +ay, baseX + bx, baseY + by);
    }
  } else if (position==2) { //left right triangles
    int dir = int(random(0, 2));
    for (int i = 1; i <= numLines; i++) { // 0 left, 1 right
      float ax = dir * (sDim + (i*dInc));
      float ay = (-dir+1)*i*hInc + dir*(sDim+(i*dInc));
      float bx = (-dir+1)*(sDim - (i*dInc)) + dir*2*sDim;
      float by = (-dir+1)*(sDim + (i*dInc)) + dir*i*hInc;
      drawLine(baseX + ax, baseY + ay, baseX + bx, baseY + by);
    }
  } else { // left right triangles
    int dir = int(random(0, 2));
    for (int i = 1; i <= numLines; i++) { // 0 left, 1 right
      float ax = dir*(sDim + (i*dInc));
      float ay = (-dir+1)*i*hInc + (dir*(sDim+(i*dInc)));
      float bx = (-dir+1)*i*dInc + dir*2*sDim;
      float by = (-dir+1)*i*dInc + dir*i*hInc;
      drawLine(baseX + ax, baseY + ay, baseX + bx, baseY + by);
    }
  }
}

 

miniverse – MolnarRecode

  1. the piece is composed mostly of diagonals across rectangles
  2. the rectangles are 1:2
  3. there are no squares
  4. most diagonal sections are parallel lines spaced equally apart
  5. here are some exceptions
    1. (I was lazy and did not implement these)
  6. As seen in image one the middle line is thicker than the neighbouring ones in part probably due to rounding errors
  7. Some of the diagonals across rectangles fill up to the half the space
  8. the space between the lines selected per rectangle
  9. The code was potentially run twice as the rectangles overlap
  10. there are multiple orientations for the lines. They either run left top to right bottom or right top corner to left bottom corner

here’s what I generated

My work I feel is sort of close to the artists. However, I didn’t implement those small exceptions because I was lazy and tired. This work was hard to make because it took me a while just to generate the individual component of a random rectangle section and on top of that the math to produce the diagonals within it. Easily took me 5 hours because of that.

My code

https://editor.p5js.org/miniverse/sketches/gV2HWWueA

/* export SVG
DDF 2019
need to have p5.svg.js in project and in index.html
see -https://github.com/zenozeng/p5.js-svg
this will save an SVG file in your download folder
*/

function setup() {
  createCanvas(800, 800, SVG);
  strokeWeight(1); // do 0.1 for laser
  stroke(0, 0, 0); // red is good for laser
  nSquares = 20;
  strokeWeight(0.4)
  noFill(); // better not to have a fill for laser
}


function distance(x1, y1, x2, y2){
  return (y1 - y2)*(y1 - y2) + (x1 - x2)*(x1 - x2)
}

function fillSquare(squareW, startX,startY,  box1, box2, percentOptions){
  orientation = random([0, 1])
  percent = random(percentOptions)
  threshold = squareW * 7 * percent;
  if(orientation){
    point1 = [(box1[0] * squareW) + startX, (box1[1] * squareW) +startY]
    point2 = [(box2[0] * squareW) + startX, (box2[1] * squareW) +startY]
    
    spacingX = abs(point1[0] - point2[0]) * percent;
    spacingY = abs(point1[1] - point2[1]) * percent;
    if(random() < 0.7){ while(distance(point1[0], point1[1], point2[0], point2[1]) > threshold ){
        line( point1[0], point1[1], point2[0], point2[1]);
        point1 = [point1[0] + spacingX, point1[1]]
        point2 = [point2[0], point2[1] - spacingY]
      }
    }
    point1 = [(box1[0] * squareW) + startX, (box1[1] * squareW) +startY]
    point2 = [(box2[0] * squareW) + startX, (box2[1] * squareW) +startY]
    if(random() < 0.9){ while(distance(point1[0], point1[1], point2[0], point2[1]) > threshold ){
        point1 = [point1[0], point1[1] + spacingY]
        point2 = [point2[0] - spacingX, point2[1]]
        line( point1[0], point1[1], point2[0], point2[1]);
      }
    }
    return;
  }
  
  point1 = [(box2[0] * squareW) + startX, (box1[1] * squareW) +startY]
  point2 = [(box1[0] * squareW) + startX, (box2[1] * squareW) +startY]
  
  spacingX = abs(point1[0] - point2[0]) * percent;
  spacingY = abs(point1[1] - point2[1]) * percent;

  while(distance(point1[0], point1[1], point2[0], point2[1]) > threshold ){
    line( point1[0], point1[1], point2[0], point2[1]);
    point1 = [point1[0] - spacingX, point1[1]]
    point2 = [point2[0], point2[1] - spacingY]

  }
  point1 = [(box2[0] * squareW) + startX, (box1[1] * squareW) +startY]
  point2 = [(box1[0] * squareW) + startX, (box2[1] * squareW) +startY]
  if(random() < 0.7){ while(distance(point1[0], point1[1], point2[0], point2[1]) > threshold ){
      
      point1 = [point1[0], point1[1] + spacingY]
      point2 = [point2[0] + spacingX, point2[1]]
      line( point1[0], point1[1], point2[0], point2[1]);
    }
  }
}
function makeGrid(percentOptions){
  squareW = width / nSquares;
  for (var r = 0; r < nSquares; r++ ) {
    for (var c = 0; c < nSquares; c++) {
      box1 = random([[0, 0.0, 0.0], [1, 0.5, 0.0], [2, 0, 0.5]])
      if(box1[0] == 0){
        box2 = random([[ 1.0, 0.5], [0.5, 1.0]])
      }
      if(box1[0] == 1 || box1[0] == 2){
        box2 = [1.0, 1.0]
      }
      box1 = [box1[1], box1[2]]
      fillSquare(squareW, r * squareW, c * squareW, box1, box2, percentOptions);
    }
  }
}
function draw() {
  makeGrid([0.1, 0.2, 0.5]);
  makeGrid([0.1, 0.2, 0.5]);
  makeGrid([ 0.2, 0.5]);
  save("mySVG.svg"); // give file name
  print("saved svg");
  noLoop(); // we just want to export once
}

aahdee – MolnarRecode

Observations:

  1. The artwork seems to consist of a mixture of square and rectangular cells, but at closer inspection it is composed of square cells with subdivisions.
  2. Each square cell has one or two rectangular subdivisions that are hatched with lines.
  3. The subdivisions are chosen out of a pool of 4 – top, bottom, left, or right. There is no restriction on which subdivisions can be paired with each other – some have top and bottom, right and bottom, top and left, etc.
  4. Most cells have two subdivisions, only a select few have one.
  5. Sometimes a subdivision has two different patterns in it.
  6. The patterns use the same pen weight throughout the print.
  7. On rare occasions the subdivision rule is broken for the following pattern:
  8. The aforementioned pattern breaks the subdivision and cells rule. It bleeds into neighboring cells.
  9. Occasionally, a cell will generate a diagonal line that starts at a corner and ends at a midpoint of an opposing wall or the opposing corner.
  10. Because of the aforementioned rule, some diagonal lines that bisect a subdivision appear to be thicker that others. This is because they are drawn twice in the same place by the plotter. Below is a good example of this:

Recreation

SVG:

Screenshot:

I got a bit too invested in this task. It took me about 3 hours of work in Processing and I definitely got pretty close. The most difficult part was creating the triangle line pattern and reversing it for more variety in my output. I was going to recreate the pattern mentioned in observation 7 but I had gassed out at that point. My code is below the read more.

Continue reading “aahdee – MolnarRecode”

sweetcorn – MolnarRecode

Assertions
1. The artwork is square
2. A grid of axis-aligned squares underlies the artwork
3. A rectangle can be created out of multiple squares
4. The squares used to create rectangles can be shared
5. Each rectangle can either be shaded, unshaded, or half-shaded along a diagonal
6. If a rectangle is half-shaded, its other half is unshaded
7. Equally spaced lines parallel to one of the rectangle’s 2 diagonals create shading
8. The strokes are all of uniform weight and color
9. The number of lines per rectangle is variable
10. There are more shaded squares than unshaded squares

I’m not sure what it is exactly, but my recreation doesn’t have the same simplicity and elegance as Molnár’s. I think I allow too much overlap, which makes the final a bit too busy. Molnár has only a touch of overlap which isn’t too distracting. It was fun trying to imagine the underlying structure of Molnár’s work, and to imagine the possibilities of future artwork with similar underlying structures as well.

var numEdges = 50;

function setup() {
     createCanvas(816, 816, SVG).position((windowWidth-width)/2, (windowHeight-height)/2);

     noSmooth();
     noFill();
     stroke(0);

     var squares= [];
     for(i=0; i<numEdges; i++){
          for(j=0; j<numEdges; j++){
               squares.push(new structure_square(i, j));
          }
     }

     save("plot.svg");
}

class structure_square {
     constructor(i, j) {
          self.index_x=i;
          self.index_y=j;
          var spread_max=1;
          var spread_n=ceil(random(spread_max));
          var spread_s=ceil(random(spread_max));
          var spread_e=ceil(random(spread_max));
          var spread_w=ceil(random(spread_max));

          if(j==0){
               spread_n=0;
          } else if(j == numEdges-1){
               spread_s=0;
          }

         if(i==0){
               spread_e=0;
         } else if(i == numEdges-1){
               spread_w=0;
         }

         newstructure_rectangle(i-spread_e, j-spread_n, i+spread_w, j+spread_s);
     }
}

class structure_rectangle {
     constructor(i_0, j_0, i_1, j_1) {
         let rect_w= (i_1-i_0) *width/numEdges;
         let rect_h= (j_1-j_0) *width/numEdges;
         let x_0=i_0*width/numEdges;
         let y_0=j_0*width/numEdges;

         stroke(0);
         strokeWeight(0.5);

         let max_shade_lines=12;
         let num_shade_lines=ceil(random(max_shade_lines));
         let h_space=rect_w/num_shade_lines;
         let v_space=rect_h/num_shade_lines;

         if(random() <0.5){
              if(random() <0.25) {
                   for(varline_num=0; line_num<num_shade_lines; line_num++) {
                        line(x_0+line_num*h_space, y_0, x_0+rect_w, y_0+rect_h-line_num*v_space);
                   }
              }
         if(random() <0.25) {
              for(varline_num=0; line_num<num_shade_lines; line_num++){
                   line(x_0, y_0+line_num*v_space, x_0+rect_w-line_num*h_space, y_0+rect_h);
              }
         }
       } else {
         if(random() <0.25) {
              for(varline_num=0; line_num<num_shade_lines; line_num++){
                   line(x_0+line_num*h_space, y_0, x_0+rect_w, y_0-rect_h+line_num*v_space);
              }
         }
         if(random() <0.25) {
              for(varline_num=0; line_num<num_shade_lines; line_num++){
                   line(x_0, y_0-line_num*v_space, x_0+rect_w-line_num*h_space, y_0-rect_h);
              }
         }
       }
     }
}