PFont fontsmall, fontbig, fontmedium; final int PLANE_SIZE = 150; float scale = 15; float rotX = -0.1, rotY = -0.17, rotZ = 0, stretch = 0; HashSet objects; Shape shape; String buff = ""; String title = "3-d co-ordinate drawer"; String label = "Press 'h' for help"; String helpText = "Enter comma-delimited co-ordinates in the white box (e.g. 1,2,3) and press return/enter.\n"+ "Press 'c' to clear.\n" + "Press 'Z' and 'z' to zoom in and out.\n" + "Click and drag to rotate axes.\n" + "To enter a plane of the form Ax+By+Cz+D=0 type a p followed by A B C and D (e.g. p1,2,3,-4)\n" + "Press 'h' again to close this window."; boolean helpMe = false; void setup() { size(600,600,P3D); background(200); fontsmall = loadFont("ArialMT-12.vlw"); fontbig = loadFont("Didot-28.vlw"); textFont(fontsmall, 12); shape = new Shape(); objects = new HashSet(); objects.add(shape); } void draw() { if (key != 'w') background(#DDDDCC); textMode(SCREEN); textFont(fontbig); fill(0); text(title,width/2-textWidth(title)/2,30); textFont(fontsmall); if (helpMe) { stroke(0); fill(255); rectMode(CORNERS); rect(40,10,width-40,height-10); fill(0); text(helpText,45,27); return; } text(label,5,height-60); pushMatrix(); translate(10,height-50,0); fill(255); stroke(0); rectMode(CORNERS); rect(0,0,200,30); fill(0); textMode(MODEL); text(buff,2,21); translate(0,-20,0); for (int i = 0; i < shape.numVertices(); i ++) { translate(0,-14,0); fill(150,100,100); text(shape.getVertex(i).toString(),2,0); } popMatrix(); textMode(MODEL); translate(width/2, height/2,0); // scale(0,0,stretch); rotateX(-rotX); rotateY(rotY); rotateZ(rotZ); fill(255); stroke(0); drawAxis("x"); pushMatrix(); rotateZ(-HALF_PI); drawAxis("y"); popMatrix(); pushMatrix(); rotateY(-HALF_PI); drawAxis("z"); popMatrix(); for (Iterator i = objects.iterator(); i.hasNext();) { Object3D obj = (Object3D) i.next(); obj.display(); } } void drawAxis(String name) { pushMatrix(); line(0,0,0,200,0,0); for (int i = 0; i < 200; i+=10) { line(-i,0,0,-(i+2),0,0); } int notchFreq = 1; int bigNotch = 5; while (scale * notchFreq < 10) { notchFreq ++; } for (int i = notchFreq; i*scale < 200; i += notchFreq) { if (i%(bigNotch*notchFreq) == 0) { line(i*scale,5,0,i*scale,-5,0); textMode(SCREEN); fill(0); //text(i,i*scale-textWidth(i + "")/2,18); text(i,screenX(i*scale-textWidth(i + "")/2,18),screenY(i*scale-textWidth(i + "")/2,18)); } else { line(i*scale,2,0,i*scale,-2,0); } } fill(0); textMode(SCREEN); textFont(fontsmall); // text(name,200,10); text(name,screenX(200,0,0),screenY(200,0,0)-5); popMatrix(); } void mouseDragged() { rotY = (TWO_PI + rotY + TWO_PI/width*(mouseX-pmouseX))%TWO_PI; rotX = (TWO_PI + rotX + TWO_PI/width*(mouseY-pmouseY))%TWO_PI; } void keyPressed() { char k; k = (char)key; switch(k){ case 8: if(buff.length()>0){ buff = buff.substring(0,buff.length()-1); } break; /* case 'a': annaAxes(); break; case 'x': xavierAxes(); break;*/ case 'h': helpMe = !helpMe; break; case 'c': shape = new Shape(); objects.clear(); objects.add(shape); break; case 'Z': scale *= 1.25; break; case 'z': scale *= 0.75; break; case 13: // Avoid special keys case 10: parse(buff); buff = ""; break; case 65535: case 127: case 27: break; default: buff+= k; break; } } /*void annaAxes() { stretch = -100; }*/ void parse(String s) { if (s.charAt(0) == 'v') { s = s.substring(1); float[] coords = float(split(s,",")); if (coords.length < 3) return; objects.add(new XVector(coords[0],coords[1],coords[2])); } else if (s.charAt(0) == 'p') { s = s.substring(1); objects.add(new Plane(s)); } else { float[] coords = float(split(s,",")); if (coords.length < 3) return; shape.addVertex(coords[0],coords[1],coords[2]); } } class Shape implements Object3D { ArrayList vertices; color c = color(255,0,0,150); Shape() { vertices = new ArrayList(); } void addVertex(Point3D p) { vertices.add(p); } void addVertex(float x, float y, float z) { vertices.add(new Point3D(x,y,z)); } void setColor(color c) { this.c = c; } Point3D getVertex(int index) { return (Point3D) vertices.get(index); } int numVertices() { return vertices.size(); } void display() { stroke(0); fill(c); beginShape(TRIANGLE_STRIP); for (int i = 0; i < vertices.size(); i++) { Point3D p = (Point3D) vertices.get(i); stroke(0); vertex(p.x*scale,-p.y*scale,p.z*scale); } endShape(); for (int i = 0; i < vertices.size(); i++) { Point3D p = (Point3D) vertices.get(i); pushMatrix(); translate(p.x*scale,-p.y*scale,p.z*scale); noStroke(); fill(0); box(2); popMatrix(); } } } class XVector implements Object3D { float dx, dy, dz; XVector (float dx, float dy, float dz) { this.dx = dx; this.dy = dy; this.dz = dz; } void display() { stroke(0); line(0,0,0,dx*scale,-dy*scale,dz*scale); pushMatrix(); translate(dx*scale,-dy*scale,dz*scale); fill(0); box(3); popMatrix(); } } class Point3D { float x, y, z; Point3D(float x, float y, float z) { this.x = x; this.y = y; this.z = z; } String toString() { return x + ", " + y + ", " + z; } } class Plane implements Object3D { float a,b,c,d; float rotY,rotX,translateZ; color col = color(50,80,200,150); Plane(String s) { String[] coords = s.split(","); if (coords.length < 4) return; col=color(random(255),random(255),random(255),150); // A plane in the form ax+by+cz+D=0. a = 0; b = 0; c = 0; d = 0; try { a = Float.parseFloat(coords[0]); b = Float.parseFloat(coords[1]); c = Float.parseFloat(coords[2]); d = Float.parseFloat(coords[3]); } catch (NumberFormatException e) { return; } rotY = -acos(a/dist(0,0,c,a))+HALF_PI; translateZ = -(d/sqrt(c*c+a*a)); float dee = (d != 0)?d:1; float dist = (d!=0)?translateZ:-(dee/sqrt(c*c+a*a)); rotX = HALF_PI-atan((-dee/b)/dist); } void display() { pushMatrix(); noStroke(); fill(col); // Special Case, line is parallel to xz axis if (a == 0 && c == 0) { rotateX(HALF_PI); translate(0,0,-d/b*scale); rectMode(CENTER); rect(PLANE_SIZE); popMatrix(); return; } rotateY(rotY); translate(0,0,translateZ*scale); rotateX(rotX); rectMode(CENTER); rect(PLANE_SIZE); popMatrix(); } } void rect(float f) { rect(0,0,f,f); } interface Object3D { void display(); }