Code

/*
+ + + 3D Filippo + + + 
 un homenaje a Filippo Brunelleschi, inventor de la perspectiva gráfica
 por Herbert Spencer, Nov 2006
 
 VIEWS
 + (F)ront
 + (T)op
 + (L)eft
 + (R)ight
 + (B)ottom
 + bac(K)
 + SPACEBAR switches to free rotation mode
 
 MODEL TRANSLATION (relative to mouseX and screen.width/2)
 + (1) While pressed, translates the drawinng in X
 + (2) While pressed, translates the drawinng in Y
 + (3) While pressed, translates the drawinng in Z
 
 MODEL ROTATION
 + (X) increases the rotation angle in X
 + (x) decreases the rotation angle in X
 + (Y) increases the rotation angle in Y
 + (y) decreases the rotation angle in Y
 + (Z) increases the rotation angle in Z
 + (z) decreases the rotation angle in Z
 
 EXPORT
 + (P) exports a PDF of the current view
 + (D) exports a DXF of the 3D model
 
 OTHER
 + (A)xis turn ON/OFF
 + (E)rase the drawing
 + (0)pacity control, lines are filled with white and lights are turned on
 
 */

import processing.opengl.*;
import processing.pdf.*;
import processing.dxf.*;


//fullscreen

/*
static public void main(String args[]) {
  PApplet.main(new String[] { 
    "--display=1", "--present", "filippo3d"                         }
  );
} 
*/

void setup(){
  size(800, 700, OPENGL);
  helv = loadFont("helv.vlw");
  loxica = loadFont("loxica.vlw");
  filippo = loadFont("filippo.vlw");
  pencil = loadImage("draw.gif");
  select = loadImage("select.gif");
  quit = loadImage("quit.gif");
  trazo = new Vector(100);
  trazos = new Vector(100);
  ux = 0;
  uy = 0;
  uz = 0;
  nx = 0;
  ny = 0;
  nz = 0;
}

void mouseReleased(){
  trazos.add(trazo);
  trazo = new Vector();
}

void draw(){

  CURRENTSTROKE = trazos.size();
  CURRENTPOINT = trazo.size();

  background(255);

  if (freerotate){
    int difx = mouseX - pmouseX;
    int dify = mouseY - pmouseY;
    uy -= difx*0.0045;
    ux -= dify*0.0045;
    drawattention(122,0,width,30);
    textFont(loxica,16);
    fill(200,0,0);
    text("Free Rotate ON, press SPACE to fix viewport",135,20);
  }
  controls();
  axisCube();
  drawing();
  checkview();
  if(!drawmode){
    selectstroke();
  }

  if (mousePressed){
    if(drawmode){
      addPoint();
    }
  }
  keyboardinput();

}


void addPoint(){
  if ((mouseX > 122) || (mouseY > 130)){
    cx = cos(ux);
    sx = sin(ux);
    cy = cos(uy);
    sy = sin(uy);
    cz = cos(uz);
    sz = sin(uz);

    x = mouseX-width*0.5;
    y = mouseY-height*0.5;
    z = 0;

    // rotation around x
    xy = cx*y + sx*z;
    xz = -sx*y + cx*z;

    // rotation around y
    yz = cy*xz + sy*x;
    yx = -sy*xz + cy*x;

    // rotation around z
    zx = cz*yx + sz*xy;
    zy = -sz*yx + cz*xy;

    Point3d p = new Point3d(zx, zy, yz);
    trazo.addElement (p);
  }
}

//============================MAKE=DRAWING=SPACE==============================
void drawing(){
  pushMatrix();
  {
    translate(width*0.5,height*0.5);
    rotateX(ux);
    rotateY(uy);
    rotateZ(uz);
    if (showaxis){
      drawaxis();
    }
    if (exportDXF) {
      beginRaw(DXF, "DXF/model-#####.dxf");
    }
    createTrazos();
    if (exportDXF) {
      endRaw();
      exportDXF = false;
    }
  }
  popMatrix();
  if(instructions){
    displayInstructions();
  }
}

//==============================MAKELINES=====================================
void createTrazos(){
  strokeWeight(1);
  stroke(0);
  noFill();
  
  // draw all strokes but current
  for (int i=0; i < trazos.size(); i++){
    Vector vec = (Vector) trazos.elementAt(i);
    stroke(0);
    beginShape();
    for (int j=0; j < vec.size(); j++){
      Point3d p = (Point3d) vec.elementAt(j);
      vertex(p.x, p.y, p.z);
    }
    endShape();
  }
  // draw current stroke
  stroke(255,0,0);
  beginShape();
  for (int i=0; i< trazo.size(); i++){
    Point3d p = (Point3d) trazo.elementAt(i);
    vertex(p.x, p.y, p.z);
  }
  endShape();
}
//==================================POINT=====================================
class Point3d {
  float x,y,z;
  Point3d (float a, float b, float c){
    x = a;
    y = b;
    z = c;
  }
}
//================================EXPORT=PDF==================================
void exportPDF(){
  pushMatrix();
  {
    translate(width*0.5,height*0.5);
    rotateX(ux);
    rotateY(uy);
    rotateZ(uz);

    beginRecord(PDF, "PDF/frame-####.pdf");
    for (int i=0; i < trazos.size(); i++){
      Vector vec = (Vector) trazos.elementAt(i);
      stroke(0);
      strokeWeight(0.2);
      noFill();
      beginShape();
      for (int j=0; j < vec.size(); j++){
        Point3d p = (Point3d) vec.elementAt(j);
        curveVertex(screenX(p.x, p.y, p.z),screenY(p.x, p.y, p.z));
      }
      endShape();
    }
    strokeWeight(1);
    endRecord();
  }
  popMatrix();
}

//================================EXPORT=PDF=360==============================
void export360(){
  int frameNum = 37;
  for (float turn=0; turn<TWO_PI; turn += TWO_PI/frameNum){
    textFont(helv,24);
    fill(200);
    int num = (int)(turn/(TWO_PI/frameNum));

      text("Remaining frames: "+(TWO_PI/turn), 300, height*0.5);
    pushMatrix();
    {
      translate(width*0.5,height*0.5);
      rotateX(ux);
      rotateY(uy+turn);
      rotateZ(uz);
      beginRecord(PDF, "PDF/"+num+".pdf"); 
      for (int i=0; i < trazos.size(); i++){
        Vector vec = (Vector) trazos.elementAt(i);
        stroke(0);
        strokeWeight(0.2);
        noFill();
        beginShape();
        for (int j=0; j < vec.size(); j++){
          Point3d p = (Point3d) vec.elementAt(j);
          vertex(screenX(p.x, p.y, p.z),screenY(p.x, p.y, p.z));
        }
        endShape();
      }
      strokeWeight(1);
      endRecord();
    }
    popMatrix();
  }
}


//=============================CLEAR=EVERYTHING================================
void clearstrokes(){
  trazo.clear();
  trazos.clear();
}
//===================================UNDO======================================
void undo(){
  int curr = trazos.size() - 1;
  trazos.removeElementAt(curr);
}
void controls(){
  strokeWeight(1);
  textFont(filippo,8);
  fill(200,0,0);
  text("3D",20,26);
  fill(0);
  text("FILIPPO",40,36);
  stroke(0,30);
  noFill();

  // rotation controls
  rect(0,0,122,height);
  for(int i=1; i<4; i++){
    stroke(0,40);
    noFill();
    rect(20, 30+25*i, 80, 15);
    stroke(0,150);
    rect(20, 30+25*i, 15, 15);
    rect(85, 30+25*i, 15, 15);
  }
  textFont(loxica,16);
  fill(0);
  textAlign(CENTER);
  text(degrees(ux), 60, 66);
  text(degrees(uy), 60, 92);
  text(degrees(uz), 60, 116);
  textAlign(LEFT);
  fill(0,150);
  text("-                    +",25,67);
  text("-                    +",25,92);
  text("-                    +",25,116);
  fill(200,0,0,200);
  text("X", 105,66);
  fill(0,200,0,200);
  text("Y", 105,91);
  fill(0,0,200,200);
  text("Z", 105,116);
  fill(0,150);

  noFill();
  stroke(0);
  // squares of the unfolded cube
  rect(43,240,20,20);
  rect(23,240,20,20);
  rect(43,220,20,20);
  rect(43,260,20,20);
  rect(63,240,20,20);
  rect(83,240,20,20);
  // keys
  fill(0);
  text("T",50,235);
  text("L",30,254);
  text("R",70,254);
  text("K",90,254);
  text("B",50,274);

  drawquit();
  pushMatrix();
  { 
    translate(0,height-100);
    text("STROKE # " + CURRENTSTROKE,20, 0);
    text("POINT # " + CURRENTPOINT,20, 15);

    text("X = " + mouseX,20, 30);
    text("Y = " + mouseY,20, 45);

    fill(255,0,0);
    text("press (I) por INFO",20,75);
  }
  popMatrix();
  fill(255,10,10,150);
  text("F",50,254);

  if (mousePressed == true) {
    noStroke();
    fill(255,10,10,150);
    if ((mouseX >= 20) && (mouseX <=35) && (mouseY >=55) && (mouseY <=70)){
      ux -= 0.01;
      rect(20,55,15,15);
    }
    if ((mouseX >= 85) && (mouseX <=100) && (mouseY >=55) && (mouseY <=70)){
      ux += 0.01;
      rect(85,55,15,15);
    } 
    if ((mouseX >= 20) && (mouseX <=35) && (mouseY >=80) && (mouseY <=95)){
      uy -= 0.01;
      rect(20,80,15,15);
    } 
    if ((mouseX >= 85) && (mouseX <=100) && (mouseY >=80) && (mouseY <=95)){
      uy += 0.01 % TWO_PI;
      rect(85,80,15,15);
    }     
    if ((mouseX >= 20) && (mouseX <=35) && (mouseY >=105) && (mouseY <=120)){
      uz -= 0.01;
      rect(20,105,15,15);
    }     
    if ((mouseX >= 85) && (mouseX <=100) && (mouseY >=105) && (mouseY <=120)){
      uz += 0.01;
      rect(85,105,15,15);
    } 
  }
}

void axisCube(){
  ux = ux%TWO_PI;
  uy = uy%TWO_PI;
  uz = uz%TWO_PI;
  noFill();
  stroke(0);
  pushMatrix();
  {
    translate(61, 170);
    rotateX(ux);
    rotateY(uy);
    rotateZ(uz);
    box(40);
    noStroke();
    fill(255,10,10,150);
    beginShape();
    vertex(5,-10,20);
    vertex(5,-15,20);
    vertex(-15,-15,20);
    vertex(-15,15,20);
    vertex(-10,15,20);
    vertex(-10,5,20);
    vertex(0,5,20);
    vertex(0,0,20);
    vertex(-10,0,20);
    vertex(-10,-10,20);
    endShape(CLOSE);
  }
  popMatrix();
}

void checkview(){
  float difx, dify, difz, dif;
  dif = 5.0;
  if (running) {

    difx = abs(nx - ux);
    dify = abs(ny - uy);
    difz = abs(nz - uz);

    ux = ux + ((nx - ux) / dif);
    uy = uy + ((ny - uy) / dif);
    uz = uz + ((nz - uz) / dif);

    if ((difx <= 0.0001)&&(dify <= 0.0001)&&(difz <= 0.0001)){
      ux = nx;
      uy = ny;
      uz = nz;
      running = false;
    }
  }
}

void keyboardinput(){
  if (keyPressed){
    if(key == 'X'){
      ux += 0.01;
    }
    if(key == 'Y'){
      uy += 0.01;
    }
    if(key == 'Z'){
      uz += 0.01;
    }
    if(key == 'x'){
      ux -= 0.01;
    }
    if(key == 'y'){
      uy -= 0.01;
    }
    if(key == 'z'){
      uz -= 0.01;
    }
    if(key == '1'){
      modifyX();
    }
    if(key == '2'){
      modifyY();
    }
    if(key == '3'){
      modifyZ();
    }
  }
}

void keyPressed() {
  if((key == 'f') || (key == 'F')){
    running = true;
    freerotate = false;
    nx = 0;
    ny = 0;
    nz = 0;
  }
  if((key == 'r') || (key == 'R')){
    running = true;
    freerotate = false;
    nx = 0;
    ny = -HALF_PI;
    nz = 0;
  }
  if((key == 'l') || (key == 'L')){
    running = true;
    freerotate = false;
    nx = 0;
    ny = HALF_PI;
    nz = 0;
  }
  if((key == 't') || (key == 'T')){
    running = true;
    freerotate = false;
    nx = -HALF_PI;
    ny = 0;
    nz = 0;
  }
  if((key == 'b') || (key == 'B')){
    running = true;
    freerotate = false;
    nx = HALF_PI;
    ny = 0;
    nz = 0;
  }
  if((key == 'k') || (key == 'K')){
    running = true;
    freerotate = false;
    nx = 0;
    ny = PI;
    nz = 0;
  }
  if ( key == ' ') {
    freerotate = !freerotate;
  }
  if (key =='p'){
    exportPDF();
  }
  if (key =='P'){
    export360();
  }
  if ((key =='d') || (key == 'D')){
    exportDXF = !exportDXF;
  }
  if ((key =='e') || (key == 'E')){
    freerotate = false;
    clearstrokes();
    setup();
  }
  if ((key =='a') || (key == 'A')){
    showaxis = !showaxis;
  }
  if ((key =='o') || (key == 'O')){
    fillstrokes = !fillstrokes;
  }
  if ((key =='i') || (key == 'I')){
    instructions = !instructions;
  }
  if ((key =='m') || (key == 'M')){
    drawmode =!drawmode;
  }
  if ((key =='u') || (key == 'U')){
    undo();
  }  
  if ((key =='q') || (key == 'Q')){
    exit();
  }
}
//==============================DRAW=AXIS======================================
void drawaxis() {
  int EXTENT = 10000;
  for (int i = -EXTENT; i <= EXTENT; i+=10){
    stroke(200,0,0,200);
    line(i,0,0,i+5,0,0);
    stroke(0,200,0,200);
    line(0,i,0,0,i+5,0);
    stroke(0,0,200,200);
    line(0,0,i,0,0,i+5);
  }
}
//==============================MODIFY==X======================================
void modifyX(){
  freerotate = false;
  {
    drawattention(122,0,width,30);
    textFont(loxica,16);
    fill(200,0,0);
    text("Translating in X dimention, move the MOUSE HORIZONTALLY to adjust translation",135,20);
  }

  for (int i=0; i < trazos.size(); i++){
    Vector vec = (Vector) trazos.elementAt(i);
    for (int j=0; j < vec.size(); j++){
      Point3d p3d = (Point3d) vec.elementAt(j);
      p3d.x += (mouseX-width*0.5)*0.03;
    }
  }
  for (int i=0; i< trazo.size(); i++){
    Point3d p3d = (Point3d) trazo.elementAt(i);
    p3d.x += (mouseX-width*0.5)*0.03;
  }

}

//============================MODIFY==Y========================================
void modifyY(){
  freerotate = false;
  {
    drawattention(122,0,width,30);
    textFont(loxica,16);
    fill(200,0,0);
    text("Translating in Y dimention, move the MOUSE HORIZONTALLY to adjust translation",135,20);
  }

  for (int i=0; i < trazos.size(); i++){
    Vector vec = (Vector) trazos.elementAt(i);
    for (int j=0; j < vec.size(); j++){
      Point3d p3d = (Point3d) vec.elementAt(j);
      p3d.y += (mouseX-width*0.5)*0.03;
    }
  }
  for (int i=0; i< trazo.size(); i++){
    Point3d p3d = (Point3d) trazo.elementAt(i);
    p3d.y += (mouseX-width*0.5)*0.03;
  }
}
//=============================MODIFY==Z=======================================
void modifyZ(){
  freerotate = false;
  {
    drawattention(122,0,width,30);
    textFont(loxica,16);
    fill(200,0,0);
    text("Translating in Z dimention, move the MOUSE HORIZONTALLY to adjust translation",135,20);
  }

  for (int i=0; i < trazos.size(); i++){
    Vector vec = (Vector) trazos.elementAt(i);
    for (int j=0; j < vec.size(); j++){
      Point3d p3d = (Point3d) vec.elementAt(j);
      p3d.z += (mouseX-width*0.5)*0.03;
    }
  }
  for (int i=0; i< trazo.size(); i++){
    Point3d p3d = (Point3d) trazo.elementAt(i);
    p3d.z += (mouseX-width*0.5)*0.03;
  }

}
void drawattention(float x, float y, float w, float h){
  color poing = color(200,0,0,((sin(millis()*0.01)*120)+130));
  fill(poing);
  noStroke();
  rect(x,y,w,h);
}
//============================INSTRUCTIONS=====================================
void displayInstructions(){
  int ww = 500;
  int wh = 360;
  pushMatrix();
  {
    translate(int(width/2-(ww/2)),int(height/2-(wh/2)));
    stroke(200,0,0,200);
    fill(255,100);
    rect(0,0,ww,wh);
    textFont(filippo,8);
    fill(200,0,0);
    text("3D FILIPPO",20,20);
    textFont(loxica,16);
    text("Press (I) again to close this window",20,350);
    fill(0);
    text("VIEWS\n\n+ (F)ront\n+ (T)op\n+ (L)eft\n+ (R)ight\n+ (B)ottom\n+ bac(K)\n+ SPACEBAR switches to\n    Free Rotation Mode",20,60);
    text("MODEL TRANSLATION*\n\n+ (1) Translation in X\n+ (2) Translation in Y\n+ (3) Translation in Z\n\n*relative to mouseX\nand screen.width/2)",360,60);
    text("MODEL ROTATION\n\n+ (X) Positive rotation in X\n+ (x) Negative rotation in X\n+ (Y) Positive rotation in Y\n+ (y) Negative rotation in Y\n+ (Z) Positive rotation in Z\n+ (z) Negative rotation in Z",180,60);
    text("EXPORT\n\n+ (p) exports a PDF, (P) exports a sequence of PDFs rotation im Y \n+ (D) exports a DXF of the 3D model",20,250);
    text("OTHER\n\n+ (A)xis turn ON/OFF\n+ (E)rase the drawing\n+ (O)pacity control, strokes are turnes into\n     surfaces through the 'fill' method\n+ (U) Undo", 260,250);
  }
  popMatrix();
}

void drawquit(){
  image(quit, width-20,3);
  if((mouseX>(width-20))&&(mouseY<20)){
    fill(255,10,10,150);
    rect(width-20,4,15,15);
    if(mousePressed){
      exit();
    }
  }
}

void selectstroke(){
  strokeWeight(1);
  int tolerance = 4;
  float pointX, pointY, difX, difY;
  for (int i=0; i < trazos.size(); i++){
    Vector vec = (Vector) trazos.elementAt(i);
    stroke(0);
    for (int j=0; j < vec.size(); j++){
      Point3d p = (Point3d) vec.elementAt(j);
      pointX = screenX(p.x, p.y, p.z);
      pointY = screenY(p.x, p.y, p.z);
      difX = (mouseX-width*0.5)-pointX;
      difY = (mouseY-width*0.5)-pointY;
      if ((difX<tolerance)&&(difY<tolerance)){
        strokeWeight(2);
        pushMatrix();
        {
          translate(width*0.5,height*0.5);
          rotateX(ux);
          rotateY(uy);
          rotateZ(uz);
          beginShape();
          for (int k=0; k < vec.size(); k++){
            Point3d q = (Point3d) vec.elementAt(k);
            vertex(q.x,q.y,q.z);
          }
          endShape();
        }
        popMatrix();
      }
    }
  }
}
// the vector of a line
Vector trazo;

// the vector of lines
Vector trazos;

// 'u' for UNIVERSAL, l for LOCAL and 'n' for NEXT
float ux, uy, uz, lx, ly, lz, nx, ny, nz;
float cx, sx, cy, sy, cz, sz;
float x, y, z, xy, xz, yz, yx, zx, zy;
float dbp = 10.0;

//fonts
PFont helv;
PFont loxica;
PFont filippo;

//switches
boolean running = false;
boolean showaxis = true;
boolean freerotate = false;
boolean exportDXF = false;
boolean fillstrokes = false;
boolean instructions = false;
boolean rightdistance = true;
boolean drawmode = true;

int CURRENTSTROKE;
int CURRENTPOINT;

//images
PImage select;
PImage pencil;
PImage quit;


--- Final Project v.2: Intermediate Tests:


3d drawing tool

hide statement