Wednesday, January 06, 2010

The Ikea Lillabo Processing code

By popular demand... here's the code, written in Processing that actually draws the train sets. I hadn't released it because I didn't think it was very interesting, but you are welcome to it.
// --------------------------------------------------------------------------
//
// Small program to draw pictures of Ikea Lillabo track layouts using
// instructions derived from my Perl program.
//
// Written by John Graham-Cumming (http://www.jgc.org/)
//
// Released under the General Public License, version 2
//
// --------------------------------------------------------------------------

// This is the cursor position (x, y) coordinates and angle to the
// horizontal

float x, y, a;

// The length in pixels of a single straight piece

float len = 40;

// See the Perl program for a full explanation, but there are 8 curves
// in a circle and from that the radians of curve arc, the length of the
// straight line between the curve ends and the curve angle to the
// horizontal can be calculated.

float curves_in_circle = 8;
float radians_in_curve = 2 * PI / curves_in_circle;
float curve_angle = radians_in_curve / 2;
float curve_length = len * 2 * cos(PI/2 - radians_in_curve/2);

// The Processing equivalent of main()
void setup() {

// Set up the basic parameters for the drawing: a 1000x1000 canvas,
// with a white background. None of the elements drawn will be filled
// and the lines will be four pixels wide.

size(1000,1000);
background(255,255,255);
strokeWeight(4);
noFill();

// These are the nine possible layouts discovered by the Perl program
// and were copy/pasted here. Clearly this would be better done
// dynamically with this program reading the Perl program's output.

int layouts = 9;
String s[] = new String[layouts];

s[0] = "AAAACCAAAASSAAB";
s[1] = "CCCCCCSSAAAAAAB";
s[2] = "CAAAAACASSAAAAB";
s[3] = "CAAAAASCASAAAAB";
s[4] = "CAAAAASSCAAAAAB";
s[5] = "AAACAACAAASSAAB";
s[6] = "ACAAAASACSAAAAB";
s[7] = "ACAAAASSACAAAAB";
s[8] = "AACAAASSAACAAAB";

// (row, col) is the row and column position of the next layout to draw
// starting from the top left of the canvas. Since we know there are
// 9 the loop below lays them out 3x3. h is the height of space
// reserved for a layout.

int row = 0;
int col = 0;
int h = 250;
int w = h + 50;

for ( int j = 0; j < layouts; j++ ) {

// Start 200 pixels from the top left corner and with an initial
// angle of 0

a = 0;
x = 200 + w * col;
y = 200 + h * row;
col++;

if ( col == 3 ) {
col = 0;
row++;
}

for ( int i = 0; i < s[j].length(); i++ ) {
switch(s[j].charAt(i)) {
case 'B':
bridge();
break;

case 'C':
clockwise();
break;

case 'A':
anticlockwise();
break;

case 'S':
straight();
break;
}
}
}
}

// Function to draw a piece and update (x, y) and a
void draw_piece( float l, // Length of piece to be drawn
float ang ) // The angular change due to the piece
{
// If the ang is zero then this is a straight piece so use line(), if
// non-zero then it's a curve and so use arc()

if ( ang == 0 ) {

// (dx, dy) is the end of the piece truncated (the 0.8 multiplier)
// to leave a little gap between pieces.

float dx = x + l * 0.8 * cos(a + ang);
float dy = y + l * 0.8 * sin(a + ang);
line( x, y, dx, dy );
} else {
int h = (ang<0)?-1:1;

// (ox, oy) is the location of the centre of the circle on which the
// arc we are drawing lies. s and e are the starting and ending angles
// of arc to draw. Note that s must be less than e. Note the 1.5 here
// is used to shorten the arc to leave a small gap between pieces.

float ox = x - h * len * cos(PI/2-a);
float oy = y + h * len * sin(PI/2-a);
float s = a;
float e = a + ang * 1.5;
if ( s > e ) {
float t = e;
e = s;
s = t;
}

// The PI/2 adjustment here is needed because the angles in s and e are
// derived from a which is to the horizontal and the arc() function needs
// angles to the vertical

ellipseMode(CENTER);
arc( ox, oy, len*2, len*2, s - h * PI/2, e - h * PI/2 );
}

// Update (x,y) and a to be at the end of the new piece that's been
// added and with the correct orientation.

x += l * cos(a + ang);
y += l * sin(a + ang);
a += 2 * ang;
}

// Four functions to draw the four pieces giving them different colours.

void bridge()
{
stroke(255,0,0);
draw_piece(2*len,0);
}

void straight()
{
stroke(0,255,0);
draw_piece(len,0);
}

void clockwise()
{
stroke(255,0,255);
draw_piece(curve_length,curve_angle);
}

void anticlockwise()
{
stroke(0,0,255);
draw_piece(curve_length,-curve_angle);
}

Labels:

If you enjoyed this blog post, you might enjoy my travel book for people interested in science and technology: The Geek Atlas. Signed copies of The Geek Atlas are available.

<$BlogCommentBody$>

<$BlogCommentDateTime$> <$BlogCommentDeleteIcon$>

Post a Comment

Links to this post:

<$BlogBacklinkControl$> <$BlogBacklinkTitle$> <$BlogBacklinkDeleteIcon$>
<$BlogBacklinkSnippet$>
Create a Link

<< Home