Complex 3D output using PDF in Processing.
Sample code for PDF output of complex geometries from Processing, with a 3D shape using lines and polygons being written correctly to PDF. Uses beginRaw() / endRaw() and should probably be used with revision 0115 or later due to recent bug fixes.
Source code – pdf_complex.pde
// pdf_complex.pde - workshop.evolutionzone.com - Marius Watz
// Example using PDF to output complex 3D geometry for print.
// Press "s" to save a PDF.
import processing.opengl.*;
import processing.pdf.*;
// Trig lookup tables borrowed from Toxi. Cryptic but effective
public static final float sinLUT[];
public static final float cosLUT[];
public static final float SINCOS_PRECISION=1f;
public static final int SINCOS_LENGTH= (int) (360f/SINCOS_PRECISION);
static {
sinLUT=new float[SINCOS_LENGTH];
cosLUT=new float[SINCOS_LENGTH];
for (int i=0; i< SINCOS_LENGTH; i++) {
sinLUT[i]= (float)Math.sin(i*DEG_TO_RAD*SINCOS_PRECISION);
cosLUT[i]= (float)Math.cos(i*DEG_TO_RAD*SINCOS_PRECISION);
}
}
// System data
boolean dosave=false;
int num;
float pt[];
int style[];
void setup() {
size(600, 600, OPENGL);
framerate(24);
background(255);
num=150;
pt=new float[6*num]; // rotx, roty, deg, rad, w, speed
style=new int[2*num]; // color, render style
// Set up arc shapes
int index=0;
float prob;
for(int i=0; i< num; i++) {
pt[index++]=random(PI*2); // Random X axis rotation
pt[index++]=random(PI*2); // Random Y axis rotation
pt[index++]=random(60,80); // Short to quarter-circle arcs
if(random(100)>90) pt[index]=(int)random(8,27)*10;
pt[index++]=(int)random(2,50)*5; // Radius. Space them out nicely
pt[index++]=random(4,32); // Width of band
if(random(100)>90) pt[index]=random(40,60); // Width of band
pt[index++]=radians(random(5,30))/5; // Speed of rotation
// get colors
prob=random(100);
if(prob<30) style[i*2]=colorBlended(random(1),
255,0,100, 255,0,0, 210);
else if(prob<70) style[i*2]=colorBlended(random(1),
0,153,255, 170,225,255, 210);
else if(prob<90) style[i*2]=colorBlended(random(1),
200,255,0, 150,255,0, 210);
else style[i*2]=color(255,255,255, 220);
if(prob<50) style[i*2]=colorBlended(random(1),
200,255,0, 50,120,0, 210);
else if(prob<90) style[i*2]=colorBlended(random(1),
255,100,0, 255,255,0, 210);
else style[i*2]=color(255,255,255, 220);
style[i*2+1]=(int)(random(100))%3;
}
}
void draw() {
if(dosave) {
// set up PGraphicsPDF for use with beginRaw()
PGraphicsPDF pdf=(PGraphicsPDF)beginRaw(PDF, "pdf_complex_out.pdf");
// set default Illustrator stroke styles and paint background rect.
pdf.strokeJoin(MITER);
pdf.strokeCap(SQUARE);
pdf.fill(0);
pdf.noStroke();
pdf.rect(0,0, width,height);
}
background(0);
int index=0;
translate(width/2,height/2,0);
rotateX(PI/6);
rotateY(PI/6);
for(int i=0; i< num; i++) {
pushMatrix();
rotateX(pt[index++]);
rotateY(pt[index++]);
if(style[i*2+1]==0) {
stroke(style[i*2]);
noFill();
strokeWeight(1);
arcLine(0,0, pt[index++],pt[index++],pt[index++]);
}
else if(style[i*2+1]==1) {
fill(style[i*2]);
noStroke();
arcLineBars(0,0, pt[index++],pt[index++],pt[index++]);
}
else {
fill(style[i*2]);
noStroke();
arc(0,0, pt[index++],pt[index++],pt[index++]);
}
// increase rotation
pt[index-5]+=pt[index]/10;
pt[index-4]+=pt[index++]/20;
popMatrix();
}
if(dosave) {
endRaw();
dosave=false;
}
}
// Get blend of two colors
public int colorBlended(float fract,
float r, float g, float b,
float r2, float g2, float b2, float a) {
r2 = (r2 - r);
g2 = (g2 - g);
b2 = (b2 - b);
return color(r + r2 * fract, g + g2 * fract, b + b2 * fract, a);
}
// Draw arc line
public void arcLine(float x,float y,float deg,float rad,float w) {
int a=(int)(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
int numlines=(int)(w/2);
for(int j=0; j< numlines; j++) {
beginShape(LINE_STRIP);
for(int i=0; i< a; i++) vertex(cosLUT[i]*rad+x,sinLUT[i]*rad+y);
endShape();
rad+=2;
}
}
// Draw arc line with bars
public void arcLineBars(float x,float y,float deg,float rad,float w) {
int a=(int)(min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1));
a/=4;
beginShape(QUADS);
for(int i=0; i< a; i+=4) {
vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
vertex(cosLUT[i+2]*(rad+w)+x,sinLUT[i+2]*(rad+w)+y);
vertex(cosLUT[i+2]*(rad)+x,sinLUT[i+2]*(rad)+y);
}
endShape();
}
// Draw solid arc
public void arc(float x,float y,float deg,float rad,float w) {
int a=(int)min (deg/SINCOS_PRECISION,SINCOS_LENGTH-1);
beginShape(QUAD_STRIP);
for(int i=0; i< a; i++) {
vertex(cosLUT[i]*(rad)+x,sinLUT[i]*(rad)+y);
vertex(cosLUT[i]*(rad+w)+x,sinLUT[i]*(rad+w)+y);
}
endShape();
}
void keyPressed() {
if(key=='s') dosave=true;
}
void mouseReleased() {
background(255);
}






i will try it soon TNX marius!
Great example yet again, Marius! It’s got me finally digging into this PDF stuff. Thanks!
This example really saved me in a bind, thanks!
Hope you won’t mind… I’ve borrowed this wonderful sketch as a “torture test” for exporting to POV-Ray and published the results (credit given to the original of course) here: http://www.davebollinger.com/works/hyphae/ (though I may move it off that unrelated project page and onto a specifically pov-ray export page eventually)
Dave, you are more than welcome. POV-Ray was the first tool I ever used, and I’ve been toying with the idea of trying to write an export library for it. Your biggest problem will likely be stroked lines, since that concept doesn’t really exist in 3D space.
This doesn’t work in the current processing any chance of updating it ?
This example is included in the Processing distribution, under “Examples > Libraries > PDF Export > Complex3D”. It works just fine under 0148.