/*
Eliza Pratt
Section E
elpratt@andrew.cmu.edu
Project 11
*/
var face = 5; //face size
var faceY = 100; //starting y coordinate for face
var w = 2; //stroke weight
var eye = {LX: 0, LY: 0, RX: 0, RY: 0}; // eye coordinates
var lipX; // lip x position
var lipY; //lip y position
function setup() {
createCanvas(480, 360);
frameRate(10);
}
function draw() {
background("beige");
for (var i = 0; i < 3; i++) {
var turt = makeTurtle(90 + i * 150, faceY);
turt.penDown();
turt.setColor("black");
//draw face features
faceBrowsNose(turt);
eyes(turt);
glasses(turt);
lips(turt);
}
noLoop();
}
//redraw face when the mouse is pressed
function mousePressed() {
draw();
}
//draws face, eyebrows and nose
function faceBrowsNose(ttl) {
//FACE
for (var i = 0; i < 180; i++) {
turtlepressure(ttl);
ttl.right(360 / 100 + random(-2.5, 2.5));
ttl.forward(face + random(-face / 3, face / 3));
}
ttl.left(20);
//LEFT EYEBROW
for (var i = 0; i < 50; i++) {
turtlepressure(ttl);
ttl.right(360 / 100);
ttl.forward(2 + random(-2, 2));
//save coordinates at top of brow to assign eye position
if (i == 25) {
eye.LX = ttl.x;
eye.LY = ttl.y + random(10, 25);
}
}
//LEFT NOSE
for (var i = 0; i < 10; i++) {
turtlepressure(ttl);
ttl.right(random(-0.5, .5));
ttl.forward(1);
}
//BOTTOM NOSE
for (var i = 0; i < 50; i++) {
turtlepressure(ttl);
ttl.left(360 / 100);
ttl.forward(0.5 + random(-1, 1));
//save bottom of nose coordinates for lip position
if (i == 25)
lipY = ttl.y + random (20, 30);
lipX = ttl.x + random (-30, 10);
}
//RIGHT NOSE
for (var i = 0; i < 10; i++) {
turtlepressure(ttl);
ttl.right(random(-0.5, .5));
ttl.forward(1);
}
//RIGHT EYEBROW
for (var i = 0; i < 50; i++) {
turtlepressure(ttl);
ttl.right(360 / 100);
ttl.forward(2 + random(-2, 2));
if (i == 25) {
eye.RX = ttl.x;
eye.RY = ttl.y + random(10, 25);
}
}
}
//draws eyes
function eyes(ttl) {
ttl.penUp();
ttl.goto(eye.LX, eye.LY);
ttl.penDown();
//left eye
for (var i = 0; i < 100; i++) {
turtlepressure(ttl);
ttl.right(360 / 50);
ttl.forward(.5 + random(-0.75, 0.75));
}
ttl.penUp();
ttl.goto(eye.RX, eye.RY);
ttl.penDown();
//right eye
for (var i = 0; i < 100; i++) {
turtlepressure(ttl);
ttl.right(360 / 50);
ttl.forward(.5 + random(-0.75, 0.75));
}
}
//draws glasses
function glasses(ttl) {
ttl.penUp();
ttl.goto(eye.LX + random(10, 18), eye.LY);
ttl.penDown();
//lens 1
ttl.face(90);
for (var i = 0; i < 100; i++) {
turtlepressure(ttl);
ttl.right(360 / 50 + random(-4, 4));
ttl.forward(2 + random(-0.75, 0.75));
}
ttl.penUp();
ttl.goto(eye.RX - random(10, 18), eye.RY);
ttl.face(330);
ttl.penDown();
//lens 2
ttl.face(270);
for (var i = 0; i < 100; i++) {
turtlepressure(ttl);
ttl.right(360 / 50 + random(-4, 4));
ttl.forward(2 + random(-0.75, 0.75));
}
}
//draws lips
function lips(ttl) {
ttl.penUp();
ttl.goto(lipX, lipY);
ttl.penDown();
ttl.face(310);
//TOP LEFT
for (var i = 0; i < 20; i++) {
turtlepressure(ttl);
ttl.right(360 / 100);
ttl.forward(1 + random(-1, 1));
}
ttl.left(50);
//TOP RIGHT
for (var i = 0; i < 20; i++) {
turtlepressure(ttl);
ttl.right(360 / 100);
ttl.forward(1 + random(-1, 1));
}
ttl.face(180);
//LINE
for (var i = 0; i < 30; i++) {
turtlepressure(ttl);
ttl.forward(1);
ttl.right(random(-2, 2));
}
ttl.face(90);
//BOTTOM LIP
for (var i = 0; i < 50; i++) {
turtlepressure(ttl);
ttl.left(360 / 100);
ttl.forward(1 + random(-1, 1));
}
}
//varies stroke weight to create "hand drawn" effect
function turtlepressure(turtle) {
w += random(-0.4, 0.4);
if (w <=0) w = 0.4;
else if (w>= 3) w = 2.7;
turtle.setWeight(w);
}
/////////////////////////////////////////////////////////////////
function turtleLeft(d) {
this.angle -= d;
}
function turtleRight(d) {
this.angle += d;
}
function turtleForward(p) {
var rad = radians(this.angle);
var newx = this.x + cos(rad) * p;
var newy = this.y + sin(rad) * p;
this.goto(newx, newy);
}
function turtleBack(p) {
this.forward(-p);
}
function turtlePenDown() {
this.penIsDown = true;
}
function turtlePenUp() {
this.penIsDown = false;
}
function turtleGoTo(x, y) {
if (this.penIsDown) {
stroke(this.color);
strokeWeight(this.weight);
line(this.x, this.y, x, y);
}
this.x = x;
this.y = y;
}
function turtleDistTo(x, y) {
return sqrt(sq(this.x - x) + sq(this.y - y));
}
function turtleAngleTo(x, y) {
var absAngle = degrees(atan2(y - this.y, x - this.x));
var angle = ((absAngle - this.angle) + 360) % 360.0;
return angle;
}
function turtleTurnToward(x, y, d) {
var angle = this.angleTo(x, y);
if (angle < 180) {
this.angle += d;
} else {
this.angle -= d;
}
}
function turtleSetColor(c) {
this.color = c;
}
function turtleSetWeight(w) {
this.weight = w;
}
function turtleFace(angle) {
this.angle = angle;
}
function makeTurtle(tx, ty) {
var turtle = {x: tx, y: ty,
angle: 0.0,
penIsDown: true,
color: color(128),
weight: 1,
left: turtleLeft, right: turtleRight,
forward: turtleForward, back: turtleBack,
penDown: turtlePenDown, penUp: turtlePenUp,
goto: turtleGoTo, angleto: turtleAngleTo,
turnToward: turtleTurnToward,
distanceTo: turtleDistTo, angleTo: turtleAngleTo,
setColor: turtleSetColor, setWeight: turtleSetWeight,
face: turtleFace};
return turtle;
}
Ever since our second variable face assignment where we saw examples of Moka’s generative faces, I’ve wanted to code doodles that look blind contours! I had a lot of fun playing with the turtles and got some pretty great results from randomizing different things. Also, by randomizing the stroke weight for each point I was able to make my own “brush” of sorts. It was challenging to have any control over the randomness factor, but here are some of the beautiful creations that came out of it before I decided to do multiple faces: