Digital Media

Moshell - Spring 98

Lecture 11: G Chapter 6: Hypermedia Documents
Chapter 6 contains many useful techniques. Key ideas are listed here. Chapter 7, however (next week) will actually introduce the stuff you most need for doing Lab 1. Chapter 8 (after the break) brings along the good stuff for Lab 2.

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_Homepage
to 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: The Analog Clock. Here's a much more substantial example. After we discuss it, we'll hack on it.

#!/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
/center (max_length 2 div) def
/radius center def
/hour_segment (0.50 radius mul) def
/minute_segment (0.80 radius mul) 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...>>