UCube v08 – now with OpenGL and Toxiclibs!

Significant code upgrade in UCube v08 – I switched graphics libraries from P3D to OpenGL, and — more importantly — stabilized the .stl file export by switching to toxiclibs – now pretty much any .stl file will be able to print straightaway, no sliceform errors, no adjustments necessary!  Plus the graphics just look a lot smoother.

Evidence:

UCUbe v08   
/* UCube v.08
 * 3d modeling input device and stl export
 * now using toxiclibs and opengl
 * Manual rotation, shape mode toggle, and export button
 * by Ben Leduc-Mills - 2.10.11
 */
 
import processing.opengl.*;
import newhull.*;
import java.awt.event.*;
import toxi.geom.*;
import toxi.geom.mesh.*;
import toxi.processing.*;
import controlP5.*;
import processing.serial.*;
 
import javax.media.opengl.GL;
 
ControlP5 controlP5;
//Nav3D nav; // camera controller
 
QuickHull3D hull = new QuickHull3D(); //init quickhull
Point3d[] points; //init Point3d array
Point3d[] savedPoints;
 
ToxiclibsSupport gfx;
Mesh3D mesh = new TriangleMesh();
Vec3D[] vectors;
 
Serial myPort; // the serial port
 
float rotX, rotY; //for manual roatation
int gridSize = 4; //size of grid (assumes all dimensions are equal)
int spacing = 50; //distance between points
int counter = 0; //wireframe toggle
String inString; //string of coordinates from arduino
String oldString;
boolean reDraw = true;
PFont myFont; //init font for text
 
PGraphicsOpenGL pgl;
GL gl;
 
void setup() {
 
  size(1400,850,OPENGL);
  frameRate(13);
  gfx=new ToxiclibsSupport(this); // initialize ToxiclibsSupport
  //background(255); 
 
  pgl = (PGraphicsOpenGL) g; //processing graphics object
  gl = pgl.beginGL(); //begin opengl
  gl.setSwapInterval(1); //set vertical sync on
  pgl.endGL(); //end opengl
 
  controlP5 = new ControlP5(this);
  controlP5.addButton("Mode", 0,100,120,80,19);
  controlP5.addButton("Export", 0,100,140,80,19);
 
  myFont = createFont("FFScala", 32);
  textFont(myFont);
 
  println(Serial.list()); // list available serial ports
  myPort = new Serial(this, Serial.list()[0], 19200);
  myPort.bufferUntil('\n');
 
} 
 
void draw() {
 
  //}
 
  //void serialEvent(Serial myPort) {
 
  if (myPort.available() > 0) {
  background(255);
  smooth();
  // because we want controlP5 to be drawn on top of everything
  // else we need to disable OpenGL's depth testing at the end
  // of draw(). that means we need to turn it on again here.
  hint(ENABLE_DEPTH_TEST);
 
  pushMatrix();
  //lights();
  translations();
  drawGrid();
  drawAxes();
 
  String inString = myPort.readStringUntil('\n');
  //String m1[] = match(inString, "[0-3]");
 
  //TODO: compare inString to oldString to see if coords changed
 
  //if a coordinate string is coming in from arduino
  if (inString != null) {
    //make acive points more visible
    strokeWeight(8);
    stroke(255, 0, 0); 
 
    if (inString != oldString) {
      reDraw = true;
      oldString = inString;
    }
 
    inString = trim(inString);
    //split string of mutliple coordinates into coordinate-sized chuncks
    String coord[] = split(inString, ';');
 
    //init point3d array equal to number of activated points
    points = new Point3d[coord.length-1]; 
 
    //put the xyz coordinates into the point3d array and draw them
    for(int p3d = 0; p3d < coord.length-1; p3d++) {
 
      int subCoord[] = int(split(coord[p3d], ','));
      points[p3d] = new Point3d(subCoord[0] * spacing, subCoord[1] * spacing, subCoord[2] * spacing);
      point(subCoord[0] * spacing, subCoord[1] * spacing, subCoord[2] * spacing );
    }
 
    if (counter%2 != 0) {
      drawHull();
    }
  } //end if inString!=null
  popMatrix();
  // turn off depth test so the controlP5 GUI draws correctly
  hint(DISABLE_DEPTH_TEST);
  }
}
 
public void controlEvent(ControlEvent theEvent) {
  println(theEvent.controller().name());
}
 
void mouseDragged() {
  float x1 = mouseX-pmouseX;
  float y1 = mouseY-pmouseY;
  rotX = (mouseY * -0.01);
  rotY = (mouseX * 0.01);
}
 
void translations() {
  translate(width/2, height/2);
  rotateX(rotX);
  rotateY(rotY);
}
 
void drawGrid() {
 
  //draw rest of grid
  //(spacing * (gridSize -1) * -1) /2 = center around 0
  int xpos = 0;
  int ypos = 0;
  int zpos = 0;
 
  for (int i = 0; i < gridSize; i++) {
    for (int j = 0; j < gridSize; j++) {
      for( int k = 0; k < gridSize; k++) {
        stroke(100);
        strokeWeight(2);
        point(xpos, ypos, zpos);
        //println(xpos + "," + ypos + "," + zpos);
        xpos += spacing;
      }
      xpos = 0;
      ypos += spacing;
    }
    xpos = 0;
    ypos = 0;
    zpos += spacing;
  }
}
 
void drawAxes() {
 
  stroke(255,0,255);
  line(0,0,0, 100,0,0);
  fill(255,0,255);
  text("X", 200, 0);
  stroke(0,255,0);
  line(0,0,0, 0,-100,0);
  fill(0,255,0);
  text("Y", 0, -200);
  stroke(0,0,255);
  line(0,0,0, 0,0,100);
  fill(0,0, 255);
  text("Z", 0, 0, 200);
  fill(0,0,0);
}
 
public void Mode(int theValue) {
  counter++;
  println(counter);
  drawHull();
}
 
public void Export(int theValue) {
  outputSTL();
}
 
void outputSTL() {
 
  TriangleMesh mySTL = new TriangleMesh();
 
  for(int i = 0; i < vectors.length; i+=3) {
 
    mesh.addFace(vectors[i], vectors[i+1], vectors[i+2]);
   // println(vectors[i] + " " + vectors[i+1] + " " + vectors[i+2]);
  }
 
  mySTL.addMesh(mesh);
  mySTL.saveAsSTL(selectOutput());
}
 
void drawHull() {
 
  int numPoints = points.length;
  //check that our hull is valid
 
  if(hull.myCheck(points, numPoints) == false) {
 
    //brute force inefficiency
    beginShape(TRIANGLE_STRIP);
    strokeWeight(1);
    fill(0);
 
    for (int j = 0; j < numPoints; j++) {
 
      float x = (float)points[j].x;
      float y = (float)points[j].y;
      float z = (float)points[j].z;
      vertex(x,y,z);
    }
 
    endShape(CLOSE);
  }
 
  else if (hull.myCheck(points, numPoints) == true) {  
 
    if(reDraw == true) {
      //print("redraw = true");
      hull.build(points);
      hull.triangulate();
      //get an array of the vertices so we can get the faces
      Point3d[] vertices = hull.getVertices();
      savedPoints = new Point3d[0];
      vectors = new Vec3D[0];
 
      beginShape(TRIANGLE_STRIP);
      strokeWeight(1);
      //noFill();
      int[][] faceIndices = hull.getFaces();
      for (int i = 0; i < faceIndices.length; i++) {
        for (int k = 0; k < faceIndices[i].length; k++) {
 
          //get points that correspond to each face
          Point3d pnt2 = vertices[faceIndices[i][k]];
          float x = (float)pnt2.x;
          float y = (float)pnt2.y;
          float z = (float)pnt2.z;
          vertex(x,y,z);
          Vec3D tempVect = new Vec3D(x,y,z);
          //println(x + "," + y + "," + z + " " + k);
          savedPoints = (Point3d[])append(savedPoints, pnt2);
          vectors = (Vec3D[])append(vectors, tempVect);
          //savedPoints[k] = new Point3d(pnt2);
          //println(savedPoints[k]);
 
          //println(x + "," + y + "," + z);
        }
      }
      endShape(CLOSE);
      reDraw = false;
    }
 
    else if(reDraw == false) {
      // print("redraw = false");
      beginShape(TRIANGLE_STRIP);
      strokeWeight(1);
      //noFill();
      for(int i = 0; i < savedPoints.length; i++) {
 
        float x = (float)savedPoints[i].x;
        float y = (float)savedPoints[i].y;
        float z = (float)savedPoints[i].z;
        vertex(x,y,z);
      }
      endShape(CLOSE);
    }
  }
}