Student Area

aahdee – LineExercises

 

Dashed line

Living Line

[videopack id=”773″]https://courses.ideate.cmu.edu/60-428/f2021/wp-content/uploads/2021/09/livingline.mp4[/videopack]

Spicy Line

[videopack id=”778″]https://courses.ideate.cmu.edu/60-428/f2021/wp-content/uploads/2021/09/spicyline.mp4[/videopack]

Circle

Spiral

Parallel

[videopack id=”783″]https://courses.ideate.cmu.edu/60-428/f2021/wp-content/uploads/2021/09/DwM_LineExercises-2021-09-14-23-49-37.mp4[/videopack]

Different Weights

Calligraphic

[not an svg – im having some save errors. will add later]

Continue reading “aahdee – LineExercises”

sapeck-LineExercises

A: Dashed Line

/*
* sapeck_03_A_DashedLine.pde
* A dashed line between the center and the mouse
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int DASH_INTERVAL = 20;

void setup() {
  size(640, 480);
}

void draw() {
  background(255, 255, 255);
  
  
  float d = dist(width/2, height/2, mouseX, mouseY);
  float num = d/DASH_INTERVAL;
  for (int i = 0; i <= num; i += 2) {
    float x1 = lerp(width/2, mouseX, i/num);
    float y1 = lerp(height/2, mouseY, i/num);
    float x2 = lerp(width/2, mouseX, min(1.0, (i+1)/num));
    float y2 = lerp(height/2, mouseY, min(1.0, (i+1)/num));
    line(x1, y1, x2, y2);
  }
}

void mouseClicked() {
  saveFrame("sapeck_03_A_DashedLine_####.png");
}

B: Living Line

/*
* sapeck_03_B_LivingLine.pde
* A mouse trail
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int NUM_POSITIONS = 100;

// Two 2D arrays
ArrayList x_positions = new ArrayList();
ArrayList y_positions = new ArrayList();

// One 2D Array
ArrayList<Integer[]> xy_positions = new ArrayList<Integer[]>();

// One Array of Objects (PVectors)
ArrayList pv_positions = new ArrayList();

void setup() {
  size(640, 480);
}

void mouseMoved() {
  // If there are 100 points recorded, remove the first one
  // This is a FIFO list, so the items are appended to the end
  // and removed from the beginning.
  if (x_positions.size() >= 100) {
    x_positions.remove(0);
    y_positions.remove(0);
    xy_positions.remove(0);
    pv_positions.remove(0);
  }
  
  // Add the new location
  x_positions.add(mouseX);
  y_positions.add(mouseY);
  Integer[] xy = { mouseX, mouseY };
  xy_positions.add(xy);
  PVector pv = new PVector(mouseX, mouseY);
  pv_positions.add(pv);
}

void draw() {
  background(255, 255, 255);
  
  beginShape();
  for (int i = 0; i < pv_positions.size(); i++) {
    // Loop over each item in the list and add a point
    // to the line
    PVector pv = pv_positions.get(i);
    vertex(pv.x, pv.y);
  }
  endShape();
}

void mouseClicked() {
  saveFrame("sapeck_03_B_LivingLine_####.png");
}

C: Spicy Line

/*
* sapeck_03_C_SpicyLine.pde
* A mouse trail that gets spicy
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int NUM_POSITIONS = 100;
float RANDOMNESS_START = 1;
float RANDOMNESS_RATE = 0.008;

// One Array of Objects (PVectors)
ArrayList pv_positions = new ArrayList();

float randomness = RANDOMNESS_START;

void setup() {
  size(640, 480);
}

void mouseMoved() {
  // Increase the randomness over time of movements
  randomness += RANDOMNESS_RATE;
  
  // If there are 100 points recorded, remove the first one
  // This is a FIFO list, so the items are appended to the end
  // and removed from the beginning.
  if (pv_positions.size() >= 100) pv_positions.remove(0);
  
  // Add the new location
  float x = mouseX + random(-1 * randomness, randomness);
  float y = mouseY + random(-1 * randomness, randomness);
  PVector pv = new PVector(x, y);
  pv_positions.add(pv);
}

void draw() {
  background(255, 255, 255);
  
  beginShape();
  for (int i = 0; i < pv_positions.size(); i++) {
    // Loop over each item in the list and add a point
    // to the curve
    PVector pv = pv_positions.get(i);
    vertex(pv.x, pv.y);
  }
  endShape();
}

void mouseClicked() {
  saveFrame("sapeck_03_C_SpicyLine_####.png");
}

D: One Circle, Two Ways

Sine and Cosine Points

/*
* sapeck_03_D_OneCircleTwoWays_SINCOSPoints.pde
* A circle made from sine and cosine points
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int NUM_POINTS = 20;
float CIRCLE_RADIUS = 100;

// One Array of Objects (PVectors)
PVector pv_positions[] = new PVector[NUM_POINTS];

void setup() {
  size(640, 480);
  
  for (int i = 0; i < NUM_POINTS; i++) {
    float x = CIRCLE_RADIUS * cos(i * (TWO_PI / NUM_POINTS)) + (width / 2); 
    float y = CIRCLE_RADIUS * sin(i * (TWO_PI / NUM_POINTS)) + (height / 2); 
    pv_positions[i] = new PVector(x, y);
  }
}

void draw() {
  background(255, 255, 255);
  
  beginShape();
  for (int i = 0; i < NUM_POINTS; i++) {
    // Loop over each item in the list and add a point
    // to the curve
    PVector pv = pv_positions[i];
    vertex(pv.x, pv.y);
  }
  endShape(CLOSE);
}

void mouseClicked() {
  saveFrame("sapeck_03_D_OneCircleTwoWays_SINCOSPoints_####.png");
}

Cosine and Square Root

/*
* sapeck_03_D_OneCircleTwoWays_SQRT.pde
* A circle made from cosine and square root
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int NUM_POINTS = 20;
float CIRCLE_RADIUS = 100;

// One Array of Objects (PVectors)
PVector pv_positions[] = new PVector[NUM_POINTS];

float CIRCLE_RADIUS_SQ = pow(CIRCLE_RADIUS, 2);

void setup() {
  size(640, 480);
  
  for (int i = 0; i < NUM_POINTS; i++) { float x = CIRCLE_RADIUS * cos(i * (TWO_PI / NUM_POINTS)); float x_sq = pow(x, 2); float y = sqrt(CIRCLE_RADIUS_SQ - x_sq); float x_aligned = x + (width / 2); float y_aligned = (height / 2) + y; if (i > NUM_POINTS / 2) y_aligned -= 2 * y;
    pv_positions[i] = new PVector(x_aligned, y_aligned);
  }
}

void draw() {
  background(255, 255, 255);
  
  beginShape();
  for (int i = 0; i < NUM_POINTS; i++) {
    // Loop over each item in the list and add a point
    // to the curve
    PVector pv = pv_positions[i];
    vertex(pv.x, pv.y);
  }
  endShape(CLOSE);
}

void mouseClicked() {
  saveFrame("sapeck_03_D_OneCircleTwoWays_SQRT_####.png");
}

E: Spiral

/*
* sapeck_03_E_Spiral.pde
* A spiral made from a circle with increasing radius
* Originally created by sapeck 2021-09-14
* CMU 60-428 F21 Drawing With Machines
*/

int POINTS_PER_ROTATION = 10;
int NUM_POINTS = 50;
float RADIUS_GROWTH_PER_POINT = 4;

// One Array of Objects (PVectors)
PVector pv_positions[] = new PVector[NUM_POINTS];

float radius = 0;

void setup() {
  size(640, 480);
  
  for (int i = 0; i < NUM_POINTS; i++) {
    float theta = i * (TWO_PI / POINTS_PER_ROTATION);
    float x = radius * cos(theta) + (width / 2);
    float y = radius * sin(theta) + (height / 2);
    pv_positions[i] = new PVector(x, y);
    radius += RADIUS_GROWTH_PER_POINT;
  }
}

void draw() {
  background(255, 255, 255);
  
  beginShape();
  for (int i = 0; i < NUM_POINTS; i++) {
    // Loop over each item in the list and add a point
    // to the curve
    PVector pv = pv_positions[i];
    curveVertex(pv.x, pv.y);
  }
  endShape();
}

void mouseClicked() {
  saveFrame("sapeck_03_E_Spiral_####.png");
}

F: Parallel Polyline

For this one, I used vsketch, vpype, and shapely. It’s as simple as installing these Python packages and then running “vsk run” and it will bring a viewer, auto-reload your code, and save an SVG for you when you click the “LIKE!”button.

#!/usr/bin/env python3
#
# sapeck_03_F_ParallelPolyline.py
# Draw a teardrop-like shape with inner and outer offset lines
# Originally created by sapeck 2021-09-15
# CMU 60-428 F21 Drawing With Machines
#

from math import cos, sin

from shapely.geometry import LineString, MultiLineString
import vsketch

PI = 3.14159

class Sapeck03FParallelpolylineVskSketch(vsketch.SketchClass):
    CIRCLE_POINTS = 100
    RADIUS = 2

    def draw(self, vsk: vsketch.Vsketch) -> None:
        vsk.size("letter", landscape=False)
        vsk.scale("in")

        # This makes a teardrop-like shape
        points = [(0, 0)]
        for i in range(0, self.CIRCLE_POINTS):
          x = self.RADIUS * cos(i * (PI / self.CIRCLE_POINTS))
          y = self.RADIUS * sin(i * (PI / self.CIRCLE_POINTS)) + self.RADIUS + 1
          points.append((x, y))
        points.append((0, 0))
        
        # points is just an array of (x, y) points
        line = LineString(points)
        vsk.stroke(1)
        vsk.geometry(line)
        
        # Now make the inner and outer offsets
        vsk.stroke(2)
        offset0 = line.parallel_offset(1, 'left',  join_style=2, mitre_limit=10.0) # inner offset
        offset1 = line.parallel_offset(1, 'right', join_style=2, mitre_limit=10.0) # outer offset
        vsk.geometry(offset0)
        vsk.geometry(offset1)

    def finalize(self, vsk: vsketch.Vsketch) -> None:
        # We can automatically apply vpype settings here too!
        vsk.vpype("linemerge linesimplify reloop linesort")


if __name__ == "__main__":
    Sapeck03FParallelpolylineVskSketch.display()

G: Lines of Different Weights

#!/usr/bin/env python3
#
# sapeck_03_G_LinesOfDifferentWeights.py
# Draw different weight lines using offset curves
# Originally created by sapeck 2021-09-15
# CMU 60-428 F21 Drawing With Machines
#

from math import cos, sin

from shapely.geometry import LineString, MultiLineString
import vsketch

PI = 3.14159

class Sapeck03GLinesofdifferentweightsSketch(vsketch.SketchClass):
    CIRCLE_POINTS = 100
    RADIUS = 2
    OFFSET_AMOUNT = 0.0025
    OFFSET_NUM = 10

    def draw(self, vsk: vsketch.Vsketch) -> None:
        vsk.size("letter", landscape=False)
        vsk.scale("in")

        # This makes a teardrop-like shape
        points = [(0, 0)]
        for i in range(0, self.CIRCLE_POINTS):
          x = self.RADIUS * cos(i * (PI / self.CIRCLE_POINTS))
          y = self.RADIUS * sin(i * (PI / self.CIRCLE_POINTS)) + self.RADIUS + 1
          points.append((x, y))
        points.append((0, 0))
        
        # points is just an array of (x, y) points
        line = LineString(points)
        vsk.stroke(1)
        vsk.geometry(line)
        
        # Now make the inner offsets
        vsk.stroke(2)
        for i in range(0, self.OFFSET_NUM):
          offset = line.parallel_offset(i * self.OFFSET_AMOUNT, 'left',  join_style=2, mitre_limit=10.0) # inner offset
          vsk.geometry(offset)

    def finalize(self, vsk: vsketch.Vsketch) -> None:
        vsk.vpype("linemerge linesimplify reloop linesort")


if __name__ == "__main__":
    Sapeck03GLinesofdifferentweightsSketch.display()

H: Calligraphic Polyline

#!/usr/bin/env python3
#
# sapeck_03_H_CalligraphicPolyline.py
# Draw a calligraphic sine wave
# Originally created by sapeck 2021-09-15
# CMU 60-428 F21 Drawing With Machines
#

from math import cos, dist, sin

import numpy as np
from shapely.geometry import LineString, MultiLineString, Point
from shapely.ops import unary_union
import vsketch

PI = 3.14159

class Sapeck03HCalligraphicpolylineSketch(vsketch.SketchClass):
    CIRCLE_POINTS = 1000
    RADIUS = 3
    #OFFSET_AMOUNT = 0.0025
    OFFSET_AMOUNT = 0.0025
    OFFSET_MULTIPLIER = 600
    BLEED_OVER = 1

    def draw(self, vsk: vsketch.Vsketch) -> None:
        vsk.size("letter", landscape=True)
        vsk.scale("in")

        # This makes a teardrop-like shape
        points = []
        for i in range(0, self.CIRCLE_POINTS):
          x = i * (2 * PI / self.CIRCLE_POINTS)
          y = self.RADIUS * sin(x)
          points.append((x, y))
        
        last = None
        for point_i in range(0, len(points) - 1):
          prev_point = points[len(points) - 1] if point_i == 0 else points[point_i - 1]
          point = points[point_i]
          next_point = points[0] if point_i == len(points) - 1 else points[point_i + 1]
          change = dist(point, next_point)
          if change == 0:
            continue
          weight = 1 / (change * self.OFFSET_MULTIPLIER) # width of line
          num_lines = int(change / self.OFFSET_AMOUNT)
          orig = LineString([point, next_point])
          for i in range(1, num_lines + self.BLEED_OVER):
            next_point_shortened = orig.interpolate(i / num_lines, normalized=True)
            orig_short = LineString([Point(point[0], point[1]), next_point_shortened])
            # find perpendicular https://stackoverflow.com/a/57072678
            left = orig_short.parallel_offset(weight / 2, 'left')
            right = orig_short.parallel_offset(weight / 2, 'right')
            c = left.boundary[1]
            d = right.boundary[0]  # note the different orientation for right offset
            last = d
            vsk.geometry(LineString([c, d]))
          
          

    def finalize(self, vsk: vsketch.Vsketch) -> None:
        vsk.vpype("linemerge linesimplify reloop linesort")


if __name__ == "__main__":
    Sapeck03HCalligraphicpolylineSketch.display()

miniverse Lostritto

I agree with the author that computers cannot draw. When drawing with a stylus, the holder of the stylus is presumed as the intelligent creator. Unless the computer has a say in what is on the page, then they are not drawing. I would only consider a drawing produced by an algorithm which learns without observation as the drawer. The author makes an interesting point on replication and how that affects perception. If a machine can draw, then where does the drawing lie on the spectrum of uniqueness? Do we classify it as something completely special to that computer or do we see it as something replicable because it was made by a computer? Even for an AI drawing machine, cloning the algorithm on a different computer should produce the same results. So how unique is the uniqueness?

spingbing-LostrittoReading

Something that struck me in the Lostritto reading was that there were several factors that differentiated and constrained the definition of a drawing and that there were many that I didn’t completely agree with. For one, I considered the undo button as the digital perfection of the eraser on traditional pieces, but here he refers to them as completely different functions. The “A computer cannot draw” section also states that a drawing must be intended by the creator’s mind to be a drawing in order for it to be a drawing. More generally, this list leads me to believe that there can be art pieces that exist on separate incremental levels; for example, if a piece cannot be edited, was drawn with the intent of it being a drawing, and final, would that be closer to the sphere of drawing than one that also could not be edited, but was drawn without the intent of being a drawing, and final? Or, is everything that does not satisfy all the requirements on the same plane?

frog-PlotterSkimming

These takeaways come from Tyler Hobbs and Licia He

  1. I didn’t really consider the potential challenges of making a large drawing – Hobbs points out that breaking down a drawing into smaller drawings like tiles can allow for the creation of something large.
  2. I’m really interested in the mechanics of paint plotting. It seems that Licia’s methodology is to just immerse herself in the work and be as prolific as possible. She makes a lot of experiments with her materials.