// --------------------------------------------------------------------------

//

// 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 ) ;

}



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.

Labels: pseudo-randomness