Pipes. Page 103 shows an example of how a Unix process can be asked for information, in a way analogous to opening a file. The specifics of the 'w' command are not of concern to us now.
'Here' Documents. This is an abbreviated form of the 'print'
command.
print <<End_of_Homepage;This command causes everything from this print command, down to the token
End_of_Homepageto be printed. Variables are evaluated when encountered, but functions are NOT called. This mostly just saves you the hassle of typing "print" at the beginning of every line and ";" at the end. And sometimes it mysteriously doesn't work. But try it...
Dynamic Graphics. A Digital Clock is produced by Ghostscript, which is a Postscript interpreter. We will learn just a few facts about Postscript in this lesson. If you decide to do a Lab 3 involving dynamic graphics, you would need to go and learn more about Postscript.
We're going to focus on the following items in this chapter: "CGI Examples with Postscript: Digital Clock" (page 104-108); "Final Postscript Example: Analog Clock"(Pages 113-116); and the GD Graphics Library's digital clock and analog clocks (116-119 and 121-123.) We will not talk about gnuplot or pgperl.
Ghostscript accepts input in the Postscript language, and produces a GIF file as output. You can think of it as a "painting robot."
Here's the digital clock program, all pulled together.
#!/usr/local/bin/perl
$GS = "/usr/local/bin/gs";
$|=1; # perl convention: makes std.out unbuffered
print "Content-type: image/gif", "\n\n"; # This routine emits GIF!
($seconds, $minutes, $hour) = localtime (time); # three vars from one call
if ($hour>12) # Some simple minded cosmetic stuff here.
{ $hour -= 12;
$ampm = "pm";
} else
{ $ampm = "am";
}
if ($hour == 0) # Note equality test is "=="
{ $hour = 12;
}
$time = sprintf ("%02d:$02d:$02d $s", $hour, $minutes, $seconds, $ampm);
# That line formats the string to report the time.
$x = 80; $y = 15; # We want to draw an 80 pixel wide by 15 pixel high image.
############## Now for the magic. We send a command to gs.
############## GS will send its output to its standard out, which will
############## actually go to whoever called this piece of Perl.
open (GS, "|$GS -sDEVICE=gif8 -sOutputFile=- -q -g${x}x${y} - 2>/dev/null");
# Whew, that's mysterious. Let's call it magic for now (see the text, p. 106)
# Now we can write to GS and it'll get piped to the Postscript system.
print GS <<End_of_PostScript_Code;
%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 $x $y
%%EndComments
/Times-Roman findfont 14 scalefont setfont
/red {1 0 0 setrgbcolor} def
/black {0 0 0 setrgbcolor} def
black clippath fill
0 0 moveto
($time) red show
showpage
End_of_PostScript_Code
close (GS);
exit(0);Key ideas to understand:
#!/usr/local/bin/perl
#GS = "/usr/local/bin/gs";
$| = 1;
print "Content-type: image/gif", "\n\n";
($seconds, $minutes, $hour) = localtime (time);
$x = $y = 150;
open (GS, "|$GS -sDEVICE-gif8 -sOutputFile=- -q -g${x}x${y} - 2>/dev/null");
print GS <<End_of_PostScript_Code;
%!PS-Adobe-3.0 EPSP-3.0
%%BoundingBox: 0 0 $x $y
%%EndComments
/max_length $x def
/line_size 1.5 def
/marker 5 def
%% Now we define a scaleable clock
%% Definitions containing expressions must have the exp. in ()/origin (0 dup) def
/red (1 0 0 setrgbcolor) def
/green (0 1 0 setrgbcolor) def
/blue (0 0 1 setrgbcolor) def
/black (0 0 0 setrgbcolor) def
/hour_angle ($minutes seconds 60 div add 3 sub 30 mul neg) def
% which means: hour angle = - ((minutes / 60) + hour - 3) * 30
% Textbook forgot the first minus sign.
/minute_angle ($minutes $seconds 60 div add 15 sub 6 mul neg) def
% which means: minute angle = -((seconds/60) + minutes - 15) *
6
%% QUERY 11.1 (embedded in a comment, too!)
%% Write the Postscript for the angle of a sweep second hand.
%% fill rectangle with black; draw blue circular line, centered.
center dup translate
black clippath fill
line_size setlinewidth
origin radius 0 360 arc blue stroke
%% Draw tick marks around the clock at 12 places
gsave
%% Save coordinate frame; we're gonna mess with it
1 1 12
{ pop
%% remove useless loop counter
radius marker sub 0 moveto
%% move to (radius-marker,0)
marker 0 rlineto red stroke
%% draw red line to (marker,0)
30 rotate
%% rotate coordinates by 30
} for
%% well it is a stack language...
grestore
%% Return to original coordinate frame
%% And now for the moving hands of the clock!
origin moveto
hour_segment hour_angle cos mul %% (hour_segment is hand-length)
hour_segment hour_angle sin mul
%% leaves x,y values of hour hand's
tip on the stack
%% meaning: x coord = (cos
(hour angle))* radius
%% and likewise y coord=(sin (hour
angle))* radius
lineto green stroke %% AND we draw a green Hour
Hand
origin moveto
minute_segment minute_angle cos mul
minute_segment minute_angle sin mul
lineto green stroke %% AND we draw a green Minute
Hand
%% now a little red circle in the center of the clock:
origin line_size 2 mul 0 360 arc red fill
showpage
End_of_PostScript_Code
close (GS);
exit(0);
Now the obvious question is (what IS the obvious question?) Well ...
Query 11.2: Rewrite the above code so as to draw the hands' positions by rotating the coordinate system, instead of by doing all that sin and cos business. If it works for tick marks, it ought to work for the hands, eh?
<<We will have to look at the corresponding gd Graphics Library
examples, directly from the textbook. I'm outa time for note-building...>>