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

 
Bolero Box | AS220 Labs Graphics