Post Scriptum language

// Example 5
// Original Adobe example uses global variables 
// interprocedural communication. Post Scriptum does not
// support global variables, but one can use
// global dictionary.

// declare dictionary with global variables :
glo = [ yfirst:0, xfirst:0, ymoveto:0, xmoveto:0, dist:0 ];


procedure pathlength() {
        // The four callback functions are defined as local routines.
	procedure move( x, y ) { 
		glo.yfirst = y;
	        glo.xfirst = x;	
		glo.ymoveto = y; 
		glo.xmoveto = x;
	}

	procedure line( x, y ) {
	       	xnext = x;
		ynext = y;

		yy = (ynext-glo.yfirst) * (ynext-glo.yfirst);
		xx = (xnext-glo.xfirst) * (xnext-glo.xfirst);

		glo.dist = glo.dist + sqrt( xx + yy );
		glo.xfirst = xnext;
		glo.yfirst = ynext;
	}

	procedure curve( x1, y1, x2, y2, x3, y3 ) {
	}

	procedure close() {
		xnext = glo.xmoveto;
		ynext = glo.ymoveto;
		yy = (ynext-glo.yfirst) * (ynext-glo.yfirst);
		xx = (xnext-glo.xfirst) * (xnext-glo.xfirst);
		glo.dist = glo.dist + sqrt(xx + yy);
		glo.xfirst = xnext;
		glo.yfirst = ynext;
	}
	flattenpath();
	glo.dist = 0;

        // This built-in PostScript operator takes
        // four procedures as parameters.
        // This example shows that post scriptum procedures
        // can be used as parameters to built-in operators.
	pathforall( move, line, curve, close );

	return glo.dist;
}

procedure centerdash( pattern ) {
	pathlen = pathlength();
	patternlength = 0;
	
        // This is the other form of post scriptum loop, iteration over an array:
	for ( x in pattern )
		patternlength = patternlength + x;
	
        // Post Scriptum has not integer arithmetic operations,
        // we use PostScript built-in functions
	if ( mod( length(pattern), 2 ) != 0 )
		patternlength = 2*patternlength;

	first = pattern[0];
	last = patternlength-first;
	n = idiv( cvi( pathlen - last ), patternlength );
        
	endpart = (pathlen - patternlength*n - last)/2;

	offset = first - endpart;
	setdash( pattern, offset );
}

setlinewidth( 5 );

newpath();
moveto( 72, 500 );
lineto( 378, 500 );
centerdash( [30] );
stroke();

newpath();
moveto( 72, 400 );
lineto( 378, 400 );
centerdash( [30, 50] );
stroke();

newpath();
moveto( 72, 300 );
lineto( 378, 300 );
centerdash( [30, 10, 5, 10] );
stroke();

newpath();
moveto( 72, 200 );
lineto( 378, 200 );
centerdash( [30, 15, 10] );
stroke();

newpath();
arc( 225, 390, 300, 240, 300 );
centerdash( [40, 10] );
stroke();


showpage();