Student Area

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");
}

marimonda – LineWalk

a perfectly ordered line gets tickled

I have been recently interested in space-filling structures, in particular fractals and reaction-diffusion patterns. For my project, I decided to code a Hilbert Curve and play around with its structural integrity with Perlin noise and mouse input. This way, the resulting curve was also an interactive experience.

What I found hard: finding the perfect amount of chaos and order proved to be the hardest part, I spent a really long time trying to alter each parameter.

A few more images, gifs + code  under the cut:

Continue reading “marimonda – LineWalk”

sapeck-PlotterTwitter

The most interesting things to me were the the innovative uses and color mixing. One person was painting with watercolors and even cleaning the brush and switching colors! Another was using overlapping hatching of different colors to mix colors and create different views when up-close or far back (like a printer). The disappointing pieces were the ones that were less identifiable as being drawn by a plotters. Honestly, the things with straight lines that appear the same from  a laser printer don’t look all that special. Maybe with materials and inks/drawing implements that don’t look like a laser printer would be better.

Paul Rickards (@paulrickards) created a piece by playing with mixing CMYK colors in hatching patterns. The order of the layers and closeness of the hatching pattern affect the resulting color and effect.

 

 

Krib – PlotterTwitter

I was pleasantly surprised to see a lot of different variations of the plotter drawings in this feed. From different materials to different aesthetics, it answered some of the questions I had of the limitations I thought I would have would this technique. I was particularly interested in the ones with multiple layers with colors because it feels as if they have more depth (content and visual-wise) and it just amazed me when I was reminded that they were generated by a machine. But even out of all those satisfying and “prettier” designs, this project stood out to me the most:

At first, I was intrigued by its’ photographic, hyper-realistic design, like the drawing on the right bottom corner looked like a picture of mars but when I clicked on it, it was actually like this:   That honestly blew my mind because I really didn’t expect anything like that but I loved the combination of both fine lines and more doodle-like lines in creating this project.

lsh-LineWalk


As I worked on these, I began to think of them as pinwheels. Getting the right “flutter” out was a challenge, and I also had a bug for a little where content ended up mostly off the page. I ended up trying to “weave” in the iteration by flipping whether I add or subtract it in the simplex noise for the x or y.

const Simplex = require("https://unpkg.com/simplex-noise@2.4.0/simplex-noise.js");
const simplex = new Simplex();
const width = 761;
const height = width;
// source: https://rosettacode.org/wiki/Map_range#ES6
const rangeMap = (a, b) => (s) => {
  const [a1, a2] = a;
  const [b1, b2] = b;
  // Scaling up an order, and then down, to bypass a potential,
  // precision issue with negative numbers.
  return ((((b2 - b1) * (s - a1)) / (a2 - a1)) * 10 + 10 * b1) / 10;
}

function generatePaths() {
  const start = [Math.random() * width, Math.random() * height];
  const step = 200.0;
  const path = [start];
  for (let i = 0; i < 100; i++) {
    const [px, py] = path.at(-1);
    const theta = simplex.noise2D(px * px * 10 * +i * i, py * py * 10 - i * i);
    const t = rangeMap([-1, 1], [-Math.PI, Math.PI])(theta);
    const x =
      Math.cos(t) * step + simplex.noise2D(px + i, py - i) * 100 + width / 2;
    const y =
      Math.sin(t) * step + simplex.noise2D(px - i, py + i) * 100 + height / 2;
    path.push([x, y]);
  }
  return path;
}

function draw() {
  const svg = d3.create("svg").attr("width", width).attr("height", height);
  svg
    .append("path")
    .attr("d", d3.line()(generatePaths()))
    .attr("fill", "none")
    .attr("stroke", "black");
  return svg.node();
}

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();

dinkolas – PlotterTwitter

Plotter twitter is technically quite interesting, there’s lots of cool algorithms at play, interesting glitches with pens running out of ink, experiments with different media, etc. But for me the vast majority of the work was just that – technically interesting – nothing more. As art, maybe some of the pieces made me feel awe at the precision of the lines, or dread of the task of executing the drawings which is interesting because it implies an empathy for the machines, or just aesthetic enjoyment. But again, my reaction was mostly the same as how I react to reading clever code/algorithms.

Several works by Licia He showed up in the hashtag, and I appreciate the combination of the imprecise nature of watercolor with the precision of the machine. This is also reinforced by the titles of the works, which are sort of conversational and comforting.

sweetcorn – LineWalk

I’m a big fan of Hershey fonts, particularly the script simplex one. It takes me back to being a kid and learning cursive, which is a big part of the aesthetics of early learning. I like how authoritative they are. As personal as cursive is, there are schools and standards of it. It brings me into the major tension of early learning that is being thrown into a space of both authority and care. I remember having to copy every curve of each cursive letter in a workbook. My handwriting was definitely a lot closer to the standard back then. As we get older, we deviate from that standard. At the root, still, is that standard. This project is structured around the standard of a hershey font, but deviates from it heavily. It treads the line between personal and public, illegible and legible, communicative and secret.

I’ve used Lingdong’s p5.hershey.js before, but there are several moments where the program picks up the pen. Accordingly, my first task was to make p5.hershey.js produce only one line. It was easy enough to move the beginShape(); and endShape(); calls to the string-level instead of the char-level, but it became clear that the characters had an assortment of issues (spacing issues, lines going every which way, and  disconnected bits). I had to go into p5.hershey.data.js and shift some coordinates around. One tool I did not think I’d have to use was one relating to Caesar ciphers. The contents of the data file are more or less a series of coordinates in ASCII centered at the character ‘R’. In order to fix some spacing issues, I had to shift the x coordinates by some value, which would mean turning each letter into another letter some alphabetical distance away, which is what a Caesar cipher does. This was probably the most tedious part of the project. I eventually got the majority of the kinks worked out and had made a decently functional tool for creating single lines of cursive in an SVG format. Now the question became what to do with this tool?

I remember how wild it was to hear Allison Parrish favor character- or a-few-character- level markov chains over word-level ones in her workshop. We moved beyond the word as the unit and into the character as the unit. What if we go deeper? What if words aren’t constituted by characters, but by points? We can go beyond the character level, then, in markov text generation. In order to do this, I got the coordinates of every alphabetical bigram (“aa”, “ab”, …, “zy”, “zz”) using my single-line-hershey tool. I realized this wouldn’t work as is because the x-values would be increasing and there wouldn’t be anything for the markov chain to root on to. So I turned them into a series of vectors, each pointing from the previous point to the current one. I was then able to use this array of series of coordinates in a markov chain, using an order of three coordinates (x, y, x_next).  This was another major annoyance to get to. It’s probably foolish, but I stored each bigram’s coordinates as a space-separated string. What I didn’t do was make each coordinate uniform. Some had 16 decimal places, others had none, some negative, some positive. I spent too long getting these to be uniform in order to get an actual coordinate-level markov chain functioning. I then generated a string of vectors and wrote a function to walk through them, leaving vertices behind. The result is something that looks like handwriting. Perhaps this project is better suited for the asemic writing prompt.

Below are some short-word generations (1000 coordinates or so)

… and some long-word (maybe a quick sentence) generations…

… and a gallery of some nice SVGs produced

 

… and a screenshot

My code can be found here (it’s a bit of a mess).

-xoxo

sweetcorn

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);
    }
  }
}