Here is a simple example showing how to use unlekkerLib to output and input 3D geometry in STL format.
// STLBoxes.pde - demonstrates how to use unlekkerLib to
// import / export STL geometry data.
//
// Marius Watz - http://workshop.evolutionzone.com/
import unlekker.data.*;
STL stl;
public void setup() {
size(400,400, P3D);
frameRate(25);
sphereDetail(12);
}
public void draw() {
translate(width/2,height/2);
if(frameCount==10) outputSTL();
else if(frameCount==11) readSTL();
if(frameCount<12) return;
background(0);
noStroke();
lights();
rotateY(radians(frameCount));
rotateX(radians(frameCount*0.25f));
fill(0,200,255, 128);
stl.draw();
}
public void readSTL() {
stl=new STL(this,"Boxes.stl");
stl.normalize(400); // scale object
stl.center(); // center it around world origin
}
public void outputSTL() {
float rad;
stl=(STL)beginRaw("unlekker.data.STL","Boxes.stl");
for(int i=0; i<200; i++) {
pushMatrix();
translate(random(-200,200),0,-random(400));
rotateX(((float)(int)random(6))*radians(30));
rotateY(((float)(int)random(6))*radians(30));
rad=random(5,25);
if(random(100)>5) box(rad,random(50,200),rad);
else sphere(rad);
popMatrix();
}
endRaw();
}
12:47 | September 25th, 2007 | marius watz | +del.icio.us | +digg | trackback
I’ve just uploaded a new Processing library called unlekkerLib. It is a collection of tools and code snippets I use frequently, and which I’ve now just barely cleaned up enough for other people to use. Instead of releasing them piece by piece, I’ve decided to bundle them together in a package hierarchy.
The main reason I decided to release it now is the STL export code I’ve written for my rapid prototyping projects. Several people have asked for the code, so I wanted to get it out there for you to play with. Obviously, it works as well with Processing as it does with regular Java.
Caveat emptor:There’s not much documentation but I do provide the source code. This is v.0001 - the very first release, so it’s pretty basic. See below for an idea of what the library contains. Right now the most exciting new component is the unlekker.data.STL class, which supports export and import of STL stereolithography files for rapid prototyping. Have a look at the Javadoc for more details.
Updates will appear here: http://workshop.evolutionzone.com/unlekkerlib/.
Read the rest of this entry »
19:12 | September 24th, 2007 | marius watz | +del.icio.us | +digg | trackback
After suggesting to my AHO class that they consider using RSS feeds in Processing, I realized that there is actually no built-in functionality to do so. The XML class built into Processing is too basic to handle feeds, it seems. To remedy the situation I’ve cooked up a quick hack using the ROME library for RSS / Atom syndication.
To run the code below you’ll need to download ROME and JDOM. Make a “code” subfolder in your sketch and paste “jdom.jar” and “rome-*.jar” into it, then run the code as given. The FeedReader and FeedEntry convenience classes take care of parsing the feed and returning the entries with the most common fields included. Error checking is rudimentary, however.
Code - feedParser.pde
Read the rest of this entry »
03:08 | September 24th, 2007 | marius watz | +del.icio.us | +digg | trackback
When writing realtime applications optimal code is always the goal. But it’s hard to always know exactly what is going to be “expensive” in terms of CPU time.
Java Performance Tuning is a very comprehensive optimization resource, but a bit too dense for less experienced programmers. JavaWorld has an article called Make Java fast: Optimize!, which is more accessibly and explains some basics quite well. More importantly, it provides a benchmark applet that gives an overview of the relative CPU cost of basic Java instructions.
For instance, the assignment “int x = 0″ would take 987 picoseconds to execute a certain number of times, while “x[0]=x[10]” would take 1304 picoseconds. See below for benchmark examples.
There is also the classic Jonathan Hardwick optimization tutorial, which is a bit more technical. It’s old (1998), but the basic concepts are still valid. One thing he warns against is the cost of object instantiation. Creating a new object instance can be expensive, particularly if it’s a complex object with lots of data. Try recycling complex objects rather than creating new ones.
Keep in mind that spending tons of time optimizing single lines of code is usually not worth it. Small differences in the benchmarks below would only matter if you’re doing some calculation a huge amount of times. Try using a profiler if you have the time and the need to figure out which parts of your program suck CPU cycles.
Otherwise, some basic rules of thumb should get you a long way:
- Don’t calculate values more than once. Instead, store them in a local variable for reuse.
- Avoid creating new complex objects when you could recycle old instances instead.
- If possible, use simple data structures. A one-dimensional array is faster to access than a two-dimensional one.
- If you’re doing work with Strings, consider using StringBuffer to avoid instantiating temporary String objects.
Benchmarks
Read the rest of this entry »
16:03 | September 9th, 2007 | marius watz | +del.icio.us | +digg | trackback
For two joined bezier curves to be continuous (i.e. no corners or abrupt slope changes), the control points on each side of the joining point must be colinear. This behavior is default in vector editing programs like Adobe Illustrator.
An example in Processing:
// BezierJoins.pde
// Marius Watz - http://workshop.evolutionzone.com
void setup() {
size(400,400);
}
void draw() {
background(200);
noFill();
float xD=width/2-mouseX;
float yD=height/2-mouseY;
bezier(0,0,
300,100,
width/2-xD,height/2-yD,
width/2,height/2);
bezier(width/2,height/2,
width/2+xD,height/2+yD,
400,300,
400,400);
}
11:28 | April 27th, 2007 | marius watz | +del.icio.us | +digg | trackback
[Merz Akademie workshop] Here is the code I wrote to create a 3D mesh by rotating a set of 2D points:
// 3dmesh.pde
// Marius Watz - http://workshop.evolutionzone.com
import processing.opengl.*;
int numrot;
float px[],py[],mesh[][][];
void setup() {
size(700,700, OPENGL);
// To create a mesh, first create two arrays to hold the
// X and Y coordinates of the path you will use to create it
px=new float[20];
py=new float[20];
float t=0;
for(int i=0; i< px.length; i++) {
px[i]=bezierPoint(0,130, 130, 0, t);
py[i]=bezierPoint(450,350,150,50, t);
t+=(1.0/(float)(px.length-1));
}
// use createMesh to create the mesh. createMesh takes three parameters:
// num == number of rotations
// startDeg == start degree of rotation
// endDeg == end degree of rotation
mesh=createMesh(px,py,20, -60,60);
}
void draw() {
translate(width/2,height/2);
pushMatrix();
background(0);
lights();
rotateY(radians(frameCount));
rotateX(radians(frameCount)/2);
stroke(255);
noStroke();
fill(255,120,0);
translate(0,0);
for(int i=0; i< 6; i++) {
rotateZ(radians(60));
pushMatrix();
rotateX(radians(-60));
// to draw the mesh, use drawMesh and pass your mesh variable to it
drawMesh(mesh);
popMatrix();
}
popMatrix();
}
float [][][] createMesh(float px[],float py[],int numrot,
float startDeg,float endDeg) {
float deg,x,z;
double cosval,sinval,tmp1,tmp2;
float [][][] mesh=new float[numrot][px.length][3];
endDeg-=startDeg;
int meshindex=0;
for(int i=0; i< numrot; i++) {
deg=radians(startDeg+(endDeg/(float)(numrot-1))*(float)i);
for(int j=0; j< px.length; j++) {
x=px[j];
z=0;
cosval=Math.cos(deg);
sinval=Math.sin(deg);
tmp1=x*cosval - z*sinval;
tmp2=x*sinval + z*cosval;
mesh[i][j][0]=(float)tmp1;
mesh[i][j][1]=py[j];
mesh[i][j][2]=(float)tmp2;
}
}
return mesh;
}
void drawMesh(float mesh[][][]) {
println(mesh.length+" "+mesh[0].length+" "+mesh[0][0].length);
for(int i=0; i< mesh.length-1; i++) {
beginShape(QUAD_STRIP);
for(int j=0; j< mesh[0].length; j++) {
vertex(mesh[i][j][0],mesh[i][j][1],mesh[i][j][2]);
vertex(mesh[i+1][j][0],mesh[i+1][j][1],mesh[i+1][j][2]);
}
endShape();
}
}
15:18 | April 18th, 2007 | marius watz | +del.icio.us | +digg | trackback
No, I’m not talking about Christmas ornaments. I just came up with a quick hack to turn off the window frame from inside Processing. See this thread on the Processing forums to know why this is useful.
When running in the IDE the sketch runs as an applet, so it can’t use the “–present” command line switches available to applications because init() is called instead of main(). My hack simply overrides the default init(), sets the frame to be undecorated and then calls the regular PApplet.init().
Update: Setting the location of the window needs to happen in setup(), not init().
import processing.opengl.*;
void setup(){
size(400,400,OPENGL);
background(0);
frame.setLocation(0,0); // needs to be in setup(), not init()
}
void draw(){
stroke(255);
line(0,0,200,200);
}
public void init() {
frame.setUndecorated(true); // works.
// call PApplet.init() to take care of business
super.init();
}
23:53 | January 10th, 2007 | marius watz | +del.icio.us | +digg | trackback
Creating PDFs in Processing and post-processing them in Adobe Illustrator, I frequently find myself wanting to do things like adjust global transparency levels, colors etc. So far that’s been frustrated by the rather poor color adjustment options built into Illustrator, but today I finally got impatient enough to look into a scripting solution.
Illustrator has had Javascript support since CS 1, exposing the document object model to anyone with a bit of scripting savvy. Adobe is good about publishing technical documents, perhaps a holdover from the days when they relied on PostScript to build their empire. So anyone can go to the online scripting documentation and download a complete PDF with a description of the Illustrator API.
As might be expected, coding Javascript is not without its troubles, and I found myself having dotcom flashbacks to the days when I would do client-side scripting. In particular, debugging is always been a pain with Javascript, especially when one is not intimate with the DOM and API. Fortunately, the ExtendScript Toolkit provided by Adobe functions both as a IDE and a debugger. Still, I find myself wanting a few nice details, like the possibility of displaying a progress bar when a script is executing.
To give you an idea of the oddities of coding for Illustrator, I am posting a script that allows the user to input a multiplier, which is then used to adjust the opacity of all path items in the active document. This covers for the lack of such a function in Illustrator proper. To be honest I was surprised at the speed with which I was able to accomplish my goal. I would seriously consider this as a way to do brute-force post-processing of vector files.
That said, I doubt it will ever be as fun and quirky as Scriptographer…
Source code - OpacityAdj.js
Read the rest of this entry »
21:15 | October 22nd, 2006 | marius watz | +del.icio.us | +digg | trackback
I know I mentioned putting together a image tiling Processing library, but so far I haven’t had time. To start at the wrong end, here’s the image stitching code for putting together the tiles once they’ve been generated. Hopefully that will be of use to some people.
Note that you might run into memory problems if you use huge tiles. Processing 0119 has a new “Set maximum memory” preference that easily takes care of this problem (see File > Preferences).
See the Processing forums for some sample code creating tiles, posted by user “surelyyoujest”.
Update: I’ve put together a proper class for this tiling technique. Have a look at aTileSaver.pde.
Source code - ImageStitcher.pde
Read the rest of this entry »
01:12 | October 11th, 2006 | marius watz | +del.icio.us | +digg | trackback
This is a simple variant to the built-in saveStrings() method in Processing. It allows you to write strings to a GZIP compressed file instead of a plain text file. Very useful when writing text-based data files that add up to a few megabytes.
Source code - saveStringsGZIP.pde
// saveStringsGZIP.pde
// Marius Watz - http://workshop.evolutionzone.com
//
// Code for saving an array of strings to a GZIP compressed file.
// Based on Processing's built-in saveStrings() method.
// Java classes needed for file I/O.
import java.io.*;
import java.util.zip.GZIPOutputStream;
void setup() {
String [] s=new String[2000];
for(int i=0; i< s.length; i++) s[i]=nf(i,50);
saveStringsGZIP("test.txt",s);
}
// Based on code from processing.core.PApplet, by the Processing team.
public void saveStringsGZIP(String filename, String strings[]) {
try {
String location = savePath(filename+".gz");
GZIPOutputStream fos =
new GZIPOutputStream(new FileOutputStream(location));
PrintWriter writer =
new PrintWriter(new OutputStreamWriter(fos));
for (int i = 0; i < strings.length; i++)
if(strings[i]!=null) writer.println(strings[i]);
writer.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException("saveStringsGZIP() failed: "
+ e.getMessage());
}
}
07:06 | October 7th, 2006 | marius watz | +del.icio.us | +digg | trackback