My problem is that I'm dealing with a dynamically changing set of points, anywhere from 0 to 64 (they correspond to coordinates from switches coming in serially from arduino) - I adapted the quickhull3d library that the Mesh lib is based on - and it works great as long as the points form a shape with a convex hull (not colinear, coincident, or coplanar) - otherwise it throws an illegal argument exception that crashes the sketch.
So, I'm wondering if there's a way to create a 3d mesh that can gracefully degrade into lines or 2d planes, or if someone can give me some pointers as to how to change the illegal argument exceptions in Java into something I can write a check method to that won't crash the program. I looked at toxiclibs, but I didn't see a way to get a mesh just through an array of points (without having faces or triangles first).
Here's version of the code that doesn't use serial input, I just use to test the software:
- /* UCube v.0x2
- * 3d modeling input device and stl export
- * No Serial communication, used for software feature building
- * by Ben Leduc-Mills
- */
- import controlP5.*;
- import unlekker.util.*;
- import unlekker.geom.*;
- import unlekker.data.*;
- import ec.util.*;
- import quickhull3d.*;
- //import processing.serial.*;
- //Serial myPort; // the serial port
- ControlP5 controlP5;
- PFont myFont; //init font for text
- STL stl; //init STL object
- FaceList poly; //FaceList object for .stl import
- QuickHull3D hull = new QuickHull3D(); //init quickhull
- Point3d[] points; //init Point3d array
- 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
- void setup() {
- // String[] fontList = PFont.list();
- // println(fontList);
- controlP5 = new ControlP5(this);
- controlP5.addButton("Refresh",0,100,100,80,19);
- controlP5.addButton("Mode", 0,100,120,80,19);
- controlP5.addButton("Export", 0,100,140,80,19);
- controlP5.addButton("Import", 0,100,160,80,19);
- myFont = createFont("FFScala", 32);
- textFont(myFont);
- size(1000, 750, P3D);
- // println(Serial.list()); // list available serial ports
- // myPort = new Serial(this, Serial.list()[0], 9600);
- // myPort.bufferUntil(' ');
- background(255); //set initial background color (just looks nicer on startup)
- genPoints(); //generate random set of points
- }
- void draw() {
- background(250);
- pushMatrix();
- translations();
- drawGrid();
- drawAxes();
- //inString = "0,0,0;0,0,2;0,2,0;0,2,2;2,0,0;2,0,2;2,2,2;2,2,0;"; //cube
- //inString = "0,0,0;0,1,0;0,2,0;0,3,0;"; //straight line
- if (poly != null) {
- drawImport();
- //poly.draw(this);
- }
- if (inString != null) {
- //make acive points more visible
- strokeWeight(8);
- stroke(255, 0, 0);
- //trim whitespace
- 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) {
- showShape();
- }
- } //end if inString!=null
- popMatrix();
- } //end draw
- 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 Import (int theValue) {
- importSTL();
- }
- public void importSTL() {
- String loadPath = selectInput(); // Opens file chooser
- if (loadPath == null) {
- // If a file was not selected
- println("No file was selected...");
- }
- else {
- inString = null;
- // If a file was selected, print path to file
- println(loadPath);
- stl = new STL(this, loadPath);
- poly = stl.getPolyData();
- int faces = poly.num;
- if (poly != null) {
- //poly.normalize(150);
- //poly.calcBounds();
- //poly.center();
- for( int i = 0; i < faces; i++) {
- poly.f[i].translate(width/2,height/2,650);
- }
- }
- }
- }
- public void drawImport() {
- beginShape(TRIANGLE_STRIP);
- stroke(255,0,0);
- strokeWeight(1);
- int offset = 0;
- for (int i = 0; i < poly.f.length; i++) {
- //println(poly.f[i]);
- vertex(poly.f[i].v[3] + offset, poly.f[i].v[4] + offset, poly.f[i].v[5] + offset);
- vertex(poly.f[i].v[6] + offset, poly.f[i].v[7] + offset, poly.f[i].v[8] + offset);
- vertex(poly.f[i].v[9] + offset, poly.f[i].v[10] + offset, poly.f[i].v[11] + offset);
- }
- endShape(CLOSE);
- }
- public void Export(int theValue) {
- outputSTL();
- }
- void outputSTL() {
- //function to output STL file
- //make sure we have at least 4 points or an imported stl
- //(can't have a 3d shape with less)
- if(poly != null) { //we have an import
- stl=(STL)beginRaw("unlekker.data.STL", selectOutput());
- beginShape(TRIANGLE_STRIP);
- for (int i = 0; i < poly.f.length; i++) {
- //println(poly.f[i]);
- vertex(poly.f[i].v[3], poly.f[i].v[4], poly.f[i].v[5]);
- vertex(poly.f[i].v[6], poly.f[i].v[7], poly.f[i].v[8]);
- vertex(poly.f[i].v[9], poly.f[i].v[10], poly.f[i].v[11]);
- }
- endShape(CLOSE);
- endRaw();
- }
- else if (points.length > 3) {
- //compute the convex hull
- hull.build(points);
- //get an array of the vertices so we can get the faces
- Point3d[] vertices = hull.getVertices();
- //start writing the stl file - file should appear in your sketch folder
- //stl=(STL)beginRaw("unlekker.data.STL","convexhull" + month() + day() + "-" + second()+ millis() + ".stl");
- stl=(STL)beginRaw("unlekker.data.STL", selectOutput());
- //different beginShape() modes may affect the shape produced
- beginShape(TRIANGLE_STRIP);
- fill(255);
- 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);
- //println(x + "," + y + "," + z);
- }
- }
- endShape(CLOSE);
- endRaw();
- }
- }
- public void Mode(int theValue) {
- counter++;
- println(counter);
- showShape();
- }
- public void showShape() {
- //brute force inefficiency
- beginShape(TRIANGLE_STRIP);
- strokeWeight(1);
- fill(0);
- int numPoints = points.length;
- for (int j = 0; j < 4800; j++) {
- int i = int(random(0,numPoints));
- float x = (float)points[i].x;
- float y = (float)points[i].y;
- float z = (float)points[i].z;
- vertex(x,y,z);
- }
- endShape(CLOSE);
- }
- public void Refresh (int theValue) {
- genPoints();
- if (poly != null) {
- poly = null;
- }
- }
- public void genPoints() {
- //setup1
- String c000 = "0,0,0;";
- String c010 = "0,1,0;";
- String c020 = "0,2,0;";
- String c030 = "0,3,0;";
- //setup2
- String c001 = "0,0,1;";
- String c011 = "0,1,1;";
- String c021 = "0,2,1;";
- String c031 = "0,3,1;";
- //setup3
- String c002 = "0,0,2;";
- String c012 = "0,1,2;";
- String c022 = "0,2,2;";
- String c032 = "0,3,2;";
- //setup4
- String c003 = "0,0,3;";
- String c013 = "0,1,3;";
- String c023 = "0,2,3;";
- String c033 = "0,3,3;";
- //setup5
- String c100 = "1,0,0;";
- String c110 = "1,1,0;";
- String c120 = "1,2,0;";
- String c130 = "1,3,0;";
- //setup6
- String c101 = "1,0,1;";
- String c111 = "1,1,1;";
- String c121 = "1,2,1;";
- String c131 = "1,3,1;";
- //setup7
- String c102 = "1,0,2;";
- String c112 = "1,1,2;";
- String c122 = "1,2,2;";
- String c132 = "1,3,2;";
- //setup8
- String c103 = "1,0,3;";
- String c113 = "1,1,3;";
- String c123 = "1,2,3;";
- String c133 = "1,3,3;";
- //setup9
- String c200 = "2,0,0;";
- String c210 = "2,1,0;";
- String c220 = "2,2,0;";
- String c230 = "2,3,0;";
- //setup10
- String c201 = "2,0,1;";
- String c211 = "2,1,1;";
- String c221 = "2,2,1;";
- String c231 = "2,3,1;";
- //setup11
- String c202 = "2,0,2;";
- String c212 = "2,1,2;";
- String c222 = "2,2,2;";
- String c232 = "2,3,2;";
- //setup12
- String c203 = "2,0,3;";
- String c213 = "2,1,3;";
- String c223 = "2,2,3;";
- String c233 = "2,3,3;";
- //setup13
- String c300 = "3,0,0;";
- String c310 = "3,1,0;";
- String c320 = "3,2,0;";
- String c330 = "3,3,0;";
- //setup14
- String c301 = "3,0,1;";
- String c311 = "3,1,1;";
- String c321 = "3,2,1;";
- String c331 = "3,3,1;";
- //setup15
- String c302 = "3,0,2;";
- String c312 = "3,1,2;";
- String c322 = "3,2,2;";
- String c332 = "3,3,2;";
- //setup16
- String c303 = "3,0,3;";
- String c313 = "3,1,3;";
- String c323 = "3,2,3;";
- String c333 = "3,3,3;";
- String coord[] = {
- c000, c010, c020, c030, //setup1
- c001, c011, c021, c031, //setup2
- c002, c012, c022, c032, //setup3
- c003, c013, c023, c033, //setup4
- c100, c110, c120, c130, //setup5
- c101, c111, c121, c131, //setup6
- c102, c112, c122, c132, //setup7
- c103, c113, c123, c133, //setup8
- c200, c210, c220, c230, //setup9
- c201, c211, c221, c231, //setup10
- c202, c212, c222, c232, //setup11
- c203, c213, c223, c233, //setup12
- c300, c310, c320, c330, //setup13
- c301, c311, c321, c331, //setup14
- c302, c312, c322, c332, //setup15
- c303, c313, c323, c333 //setup16
- };
- int numCoords = int(random(1,32));
- String[] c = new String[numCoords];
- for (int i = 0; i < numCoords; i++) {
- c[i] = coord[int(random(64))];
- }
- inString = join(c, "");
- }
Thanks in advance for any suggestions.
-b
1