Code in 2008

Drawbot Bézier helper tool

When I was asked to modify the drawbot to do portraits of people at our annual Fools Ball party, I came up with a "police sketch"-style interface:

2625164392_49a7cab7c5.jpg

People could set their facial attributes using the 6 analog and 4 digitial inputs, hit the "Draw!" button and get their own custom portrait:

The sketch required a bunch of graphics primitives that could be scaled and positioned depending on the inputs and the relative position of the other elements of the face. The graphics primitives (i.e., a female eye, a male mouth, a moustache, etc.) are an array of points in the form (x1, y1, controlx1, controly1, x2, y2, etc...). This array is used to draw the Bezier curves that make up the primitve.

I wanted to be able to draw the shapes by hand on the computer, so I whipped up a Processing sketch that would let you draw a continuous shape and spit out the list of points when you hit the Shift key.

int MaxPoints = 1000;
String[] lines;
PrintWriter output;
int[] x = new int[MaxPoints];
int[] y= new int[MaxPoints];
int state=-1;
int grabbed = -1;

void setup() {
  size(500, 500);
  smooth(); 
  fill(255,0);
  strokeWeight(4.0);
  //lines = loadStrings("drawbot_object.txt");
  if (lines != null) {
    state = lines.length-1;
    for (int i = 0; i < lines.length; i++) {
       String[] pieces = split(lines[i], '\t');
       x[i]=int(pieces[0]);
       y[i]=int(pieces[1]);
    }
  }
}

void mousePressed() {
  if (keyPressed  == true) {
    if (keyCode == CONTROL) {
       for (int i=0; i<=state; i++) {
         if ((x[i] >= (mouseX-10)) && (x[i] <=(mouseX+10)) &&
             (y[i] >= (mouseY-10)) && (y[i] <=(mouseY+10))) {
               grabbed=i;
             }
       }
    }

    if (keyCode == 18) {
       for (int i=0; i<=state; i++) {
         if ((x[i] >= (mouseX-10)) && (x[i] <=(mouseX+10)) &&
             (y[i] >= (mouseY-10)) && (y[i] <=(mouseY+10))) {
                for (int j=i+1; j<=state; j++) {
                   x[j-1]=x[j];
                   y[j-1]=y[j];
                }
                state--;
               }
             }
       }

    if (keyCode  == SHIFT) {
       output = createWriter("drawbot_object.txt");
       println("// X coordinates for object");
       print("int object_n = ");
       print(state+1);
       println(";");
       println("int object_x[] = {");
       for (int i=0; i<=state; i++) {
         print(x[i]);
         output.print(x[i]);         
         output.print('\t');
         output.println(y[i]);
         if (i<state) {
           print(", ");
         }
       }
       println("};");
       println("// Y coordinates for object");
       println("int object_y[] = {");
       for (int i=0; i<=state; i++) {
         print(y[i]);
         if (i<state) {
           print(", ");
         }
       }
        println("};");
        output.flush(); 
        output.close();
    }
  } else {
    state++;
    x[state] = mouseX;
    y[state] = mouseY;

    if (state>=MaxPoints) {
        state=0;
    }
  }
}

void mouseReleased() {
  grabbed = -1;
}

void keyPressed() {

}

void draw() {
  int cx1 = 0;
  int cy1 = 0;
  int cx2 = 0;
  int cy2 = 0;
  background(226);
  if (state>=0) {
   for (int i=0; i<=state; i++) {
    ellipse(x[i],y[i],10,10);
   }
   if ((state%2)>0) {
         // hack this to approximate quadratic bezier
      bezier(x[state-1], y[state-1], x[state], y[state], x[state],y[state], 
                mouseX, mouseY);
   }
   if (grabbed >=0) {
     x[grabbed]=mouseX;
     y[grabbed]=mouseY;
   }
   for (int i=0; i<=state; i++) {
     if (((i%2)==0)&&(i>0)) {
       bezier(x[i-2], y[i-2], x[i-1], y[i-1], x[i-1],y[i-1], x[i], y[i]);
      }
   }
  }
}

The AS220 drawbot uses quadratic Bezier curves (one control point, like Flash), while Processing uses cubic Bezier curves (two control points). The sketch should be easy to hack to approximate the difference between the two.

BezierDraw.png

AS220 Labs Graphics | Hair and Balanced

Shawn Wallace