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;