
                             [42m Learning PostScript[0m

                                 [42m ~ Part 6 ~[0m

                                 [3mBy Peter Goed[0m


[32m   <> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <>
[0m

  [33m REPEAT LOOPS
[0m
   As you all know, computers are very good at repetitive tasks - mundane
  work such as invoicing or mail-merging that can drive humans to
  distraction.  But armed with a page description language, computers can
  perform another kind of repetitive job that is unlike anything we normally
  associate with computing.

   What I am getting to is the use of PostScript repeat loops to create
  symmetrical designs that are so intricate that they would be almost
  impossible to do by hand, at least with anything approaching PostScript's
  speed and accuracy.

   Symmetrical designing is one application that can be done better with just
  a few lines of PostScript code than using the most sophisticated drawing
  software that is currently available.

   In this month's tutorial we will delve into the most creative aspect of
  the page description languages.  You will find this month's tutorial a lot
  more fun and a lot easier than the last few month's work.  I intend to
  cover the two most common types of loops: those that use the 'repeat' and
  'for' operators, and a new painting operator that makes the intriguing
  visual effects possible.


  [33m repeat
[0m
   The repeat loop below replaces a series of nine instructions in Repetition
  in tutorial 4, that were so tedious that after showing only three of the
  series to convey the idea, I used "Etc." to save time and space.

   All you require is a PostScript procedure - a set of PostScript
  instructions surrounded by braces - preceded by a number representing the
  number of times it is to be executed, and followed by the 'repeat'
  operator.

   Enclosing procedures in braces is a PostScript convention that has many
  uses, as we shall see in the following pages.

    /Times-BoldItalic findfont 72 scalefont setfont

    72 648 translate

    9 {
        0 0 moveto
        (Your Text) show
        0 -72 translate
    } repeat

    showpage

   This is the familiar "Your Text" shown at coordinates 72, 648, repeated on
  eight successive lines.  The '0 -72 translate' instruction on the last line
  of the procedure repositions each successive line every time the loop is
  repeated.


  [33m div
[0m
   In the preceding tutorial we use the 'curveto' operator to draw a 2 inch
  sinewave from the centre of the page.

    306 396 translate
    0 0 moveto
    72 72 72 -72 144 0 curveto
    stroke
    showpage

   Here, we integrate the same instructions into a repeat loop that repeats
  the sine wave 16 times around a circle.  The instruction for rotating
  around a circle uses the 'div' (divide) operator to divide the circle into
  16 equal 22.5 degree segments.

   The 'div' operator is executed at the end of each repetition of the repeat
  loop, hence the rotational effect is cumulative.  Note that the divisor is
  equal to the number of times the repeat loop is executed.

    306 396 translate

    16 {
        0 0 moveto
        72 72 72 -72 144 0 curveto
        360 16 div rotate           % 22.5 degrees each
    } repeat
    stroke

    showpage


  [33m Nested Repeat Loops
[0m
   Let us now "nest" the repeat loop from the previous exercise within a
  second repeat loop that causes the entire procedure of 16 rotations of the
  sine wave to be executed two times, but with a different twist.

   After the inside loop has been run once, producing the first series of 16
  rotated sine waves, we use the '-1 1 scale' instruction to produce a mirror
  image of the first pass, on the second time through the repeat loop
  (Negative scaling is explained in tutorial 4).  The scale operator has no
  effect when it's encountered at the end of the second pass, because all
  path construction operations are finished and we are ready to 'stroke' the
  path.

    306 396 translate

    2 {
        16 {
               0 0 moveto
               72 72 72 -72 144 0 curveto
               360 16 div rotate           % 22.5 degrees each
        } repeat
        -1 1 scale
    } repeat
    stroke

    1 setgray
    0 0 10 0 360 arc fill % add small white circle in centre

    showpage


  [33m eofill
[0m
   The instructions following are exactly the same as those in the preceding
  example except for the 'eofill' (even-odd-fill) operator, which
  alternatively fills points on the current path according to the even/odd
  rule as described in the "Red Book" pages 70-71.

   As you can see, this single operator transforms the basic design from an
  interesting line drawing into a finished symmetrical design, and we
  accomplished this with less than a dozen lines of code.

    306 396 translate

    2 {
        16 {
               0 0 moveto
               72 72 72 -72 144 0 curveto
               360 16 div rotate           % 22.5 degrees each
        } repeat
        -1 1 scale
    } repeat
    eofill

    1 setgray
    0 0 10 0 360 arc fill % add small white circle in centre

    showpage


  [33m Increasing Repetitions
[0m
   This basic design can be simply turned into a much more intricate design
  by increasing the number of repetitions of the inside loop.

   The following instructions are the same as those above, except I have
  increased the number of repetitions and the divisor for the rotations from
  16 to 32.  I also added three rings to enhance the appearance.

    306 396 translate

    2 {
        32 {
               0 0 moveto
               72 72 72 -72 144 0 curveto
               360 32 div rotate           % 11.25 degrees each
        } repeat
        -1 1 scale
    } repeat
    eofill

    0 0 150 0 360 arc stroke
    0 0 160 0 360 arc stroke
    3 setlinewidth
    0 0 155 0 360 arc stroke

    1 setgray
    0 0 10 0 360 arc fill % add small white circle in centre

    showpage

   If this sample won't execute for you, move the 'eofill' instruction to
  just below the '-1 1 scale' instruction.  The result will be different, but
  in all probability it will execute.

   If this works OK, then try increasing to 64 repeats to get an even mere
  interesting result.


 [33m  Redefining the Sine Wave
[0m
   Small changes to the basic instructions will cause a radical change to the
  finished product.  Try the following simple changes to get a vastly
  different result.

    306 396 translate

    2 {
        24 {
               0 0 moveto
               72 72 72 -72 288 0 curveto
               360 24 div rotate
        } repeat
        -1 1 scale
    } repeat
    eofill

    1 setgray
    0 0 10 0 360 arc fill

    showpage

  [33m for
[0m
   A PostScript for loop is similar to a repeat loop; it has numeric operands
  preceding a procedure enclosed in braces, followed by a PostScript 'for'
  operator.  But where the repeat loop has a single numeric operand that
  specifies the number of times the procedure id to be repeated, the 'for'
  operator requires three numeric operands that convey more precise
  information to the PostScript interpreter regarding how many times the loop
  is to be repeated.

   The following code is a simplified way to draw the Atomic Patterns from
  tutorial 5 - the portion of the instructions enclosed in left and right
  braces is exactly the same as the three instructions from tutorial 5 Atomic
  Patterns, except that the degrees of rotation for each ellipse are not
  specified.  In fact the 'rotate' operator appears to have no operand at
  all!

    306 396 translate

    -60 60 60 {
        gsave
             rotate
             0 0 144 0 360 arc
             stroke
        grestore
    } for

    showpage


  [33m For Loop Operands
[0m
   In keeping with PostScript's requirements for placing operands before the
  operator, the 'for' operator is preceded by four operands, namely; an
  initial value, an increment, a limit and finally, a procedure enclosed in
  braces.

   The preceding example was as follows.

    -60 60 60 {.....procedure....} for

   This tells the interpreter to start with an initial value of -60, repeat
  the procedure and increment this value each time by 60 until the limit of
  60 is reached, and then go to the next instruction in the page description,
  which in this case is 'showpage'.


  [33m Control Variable
[0m
   In all for loops, the PostScript interpreter uses a number called a
  "control variable" to keep track of how many times the loop has been
  repeated.  In the sample we have just done, the initial value is -60, as
  determined by the first operand, then 0, and finally 60, as the initial
  value is incremented by the second operand (the increment) each time
  through the loop.  When the control variable exceeds the third operand (the
  limit) the interpreter stops repeating the loop.

   Notice that the number (-60 then 0 then 60), which represents the value of
  the control variable each time through the loop, corresponds to the degrees
  of rotation required for the 'rotate' operator in our Atomic Patterns of
  tutorial 5.  It is this number that is used as the operand for the
  'rotate' operator each time through the loop.  The program does not supply
  the operator; it is generated by the interpreter.

   Hence, the control variable performs a second function, in addition to
  keeping track of the for loop, it is used in the logic of the page
  description - in this case, determining the degrees of rotation for each
  ellipse.


  [33m Circular Text
[0m
   In the following instructions, each new control variable becomes the
  operand for the ensuing 'rotate'.  The first loop is rotated 20 degrees,
  the second 40 degrees, and so on.  Each 'rotate' is enclosed in a
  'gsave/grestore', so the effect is not cumulative.  Notice that the limit
  is 340 degrees instead of 360, so that the last space is left for writing
  the name "on top" of the other names created in the loop.

    /Helvetica-BoldOblique findfont 48 scalefont setfont

    165 400 translate
    .5 setlinewidth

    20 20 340 {
        gsave
            rotate 0 0 moveto
            (Amiga) true charpath stroke
        grestore
    } for

    0 0 moveto
    (Amiga the Computer) true charpath
    gsave
        1 setgray
        fill
    grestore
    stroke

    200 -50 moveto
    (for Me) true charpath
    gsave
        1 setgray
        fill
    grestore
    stroke
    showpage


  [33m Designing with Text
[0m
   Here is a simple example using two characters from the keyboard, the O and
  the | (ascii 124), perhaps this will give you some ideas of your own.

    /Helvetica-BoldOblique findfont 48 scalefont setfont

    306 396 translate

    .5 setlinewidth

    10 10 360 {
        gsave
            rotate 0 0 moveto
            (OOO||||||) true charpath stroke
        grestore
    } for

    0 0 205 0 360 arc stroke
    0 0 215 0 360 arc stroke
    3 setlinewidth
    0 0 210 0 360 arc stroke

    showpage


  [33m Grid Lines
[0m
   Loops can of course be used for other than making fancy designs.  The for
  loop below creates vertical lines on a page that can be used for a display
  page grid for say a graph of some kind, in this example it will be half an
  A4 page.

   The control variable becomes the x coordinate for the ensuing 'moveto'
  instruction (0 0 moveto, 144 0 moveto, etc.).

    612 4 div 792 4 div translate
    .5 .5 scale
    .9 setgray

    0 72 612 {
        0 moveto   % Control variable is value of x)
        0 792 rlineto
        stroke
    } for

    0 setgray
    0 0 moveto
    612 0 rlineto 0 792 rlineto -612 0 rlineto
    closepath stroke
    showpage

   Note how the 'div' operator is used to initially position the lower-left
  corner of the half size grid, one quarter of a page right and up from the
  page origin.  Note also how we scale the page to half size with '.5 .5
  scale'.  Finally we draw a surrounding box from the location (0 0 moveto),
  after the vertical lines have been rendered by the loop.


[33m   exch
[0m
   The instructions for creating horizontal grid lines are identical to those
  used in the previous example for creating vertical grid lines, except in
  three respects.  The first difference is the obvious change in the limit to
  792, which represents the 11 inch top of the page.  Secondly, we use '612 0
  rlineto' to draw the horizontal lines.  The other difference is the change
  in the first line in the for loop, from '0 moveto to 0 exch moveto'.

   We use the PostScript 'exch' (exchange) operator to exchange the positions
  of the x and y values for 'moveto'.

   As a new control variable is generated by the interpreter each time
  through the loop, we exchange the position of the control variable and the
  0 used as the operands for 'moveto', so that the x/y operands are in the
  proper order - 0, 72; 0, 144; etc., instead of 72, 0; 144, 0, as they were
  in the previous example.

    612 4 div 792 4 div translate
    .5 .5 scale
    .9 setgray

    0 72 792 {
        0 exch moveto   % Exchange value of y with 0
        612 0 rlineto
        stroke
    } for

    0 setgray
    0 0 moveto
    612 0 rlineto 0 792 rlineto -612 0 rlineto
    closepath stroke
    showpage

 [33m  def
[0m
   Another way to use the PostScript control variable is to define it as a
  "named" variable using the 'def' (define) operator.

   As we saw in tutorial 2, PostScript uses a forward slash as a special
  character to define a literal name, e.g., "/Times-BoldItalic".  Here, the
  instruction "/y exch def" defines a literal name y, with a value of the
  control variable.

   Each new control variable (72, 144, etc.) becomes the value of the
  variable y each time through the loop.  This is done by exchanging the
  position of the variable name y with this value to get them in the proper
  order, and then defining the variable - /y 72 def, /y 144 def, etc., each
  time through the loop.  Each new control variable then becomes the value
  for y in each '0 y moveto', giving us a new point from which to draw each
  successive vertical grid line.

    612 4 div 792 4 div translate
    .5 .5 scale
    .9 setgray

    0 72 792 {
        /y exch def       % Define each control variable as y
        0 y moveto        % Start each line at new y value
        612 0 rlineto stroke
    } for

    0 setgray
    0 0 moveto
    612 0 rlineto 0 792 rlineto -612 0 rlineto
    closepath stroke
    showpage

   There is never a space between a slash and the next character in any
  defined name (as in /y), but it may sometimes appear to have a space when
  you see it in print.


 [33m  CVS
[0m
   Capturing the control variable provides the additional advantage of being
  able to use it for other purposes, such as showing the numerical value of
  the variable adjacent to the grid line.

   This is accomplished with the PostScript 'cvs' (convert to string)
  operator, which converts the numeric variable y to a character string so
  that we can display the string with the 'show' operator.  The 'cvs'
  operator requires two operands - the object being converted (in this case,
  the variable y), and an "empty string" into which the result of the
  conversion is placed (defined here as "str", which can hold up to four
  characters).

    612 4 div 792 4 div translate

    /str 4 string def   % Empty string 4 characters long

    /Helvetica-Bold findfont 14 scalefont setfont

    .5 .5 scale
    .9 setgray

    0 72 792 {
        y exch def
        0 y moveto 612 0 rlineto
        gsave
            -30 y moveto
            0 setgray
            y str cvs      % Convert y value to string
            show           % Show each value
        grestore
    } for

    0 setgray
    0 0 moveto
    612 0 rlineto 0 792 rlineto -612 0 rlineto
    closepath stroke
    showpage


[33m   mul
[0m
   This is the PostScript multiply operand and will be discussed in more
  detail in the next tutorial.


[33m   dup
[0m
   This is the PostScript duplicate operand and is used in conjunction with
  the multiply operand to give some startling effects as in the Mandala
  produced by the following code.

   In the following program we use the variable c to define the number of
  circles that radiate from a point on the perimeter of the mandala.  The
  radius of the mandala in the next few examples is 100, but it could be any
  size.

   The variable is used not only as the limit of the for loop, but also as
  the devisor in the first line of the loop.  The line that reads "100 c div
  mul" multiplies the control variable by the radius divided by c, to
  determine the radius of each radiating circle.

   The result of the computation determines not only the radius of each
  radiating circle each time through the loop (as c increases), but also the
  x coordinate for the ensuing 'arc' operation.  Therefore, we duplicate this
  number with 'dup'.  The '0 exch' then puts x,y and radius in the proper
  order, and the '-180 180 arc' uses these operands to draw the radiating
  circles from the perimeter of the mandala (10 0 10 -180 ... 100 0 100 -180
  180).

    306 396 translate

    /c 10 def

    -90 rotate   % Start at top

    -100 0 translate
    0 0 moveto
    1 1 c {
        100 c div mul
        dup 0 exch
        -180 180 arc
    } for
    stroke

    showpage

   Note that we use -180 180 instead of 360 360 to draw each circle from the
  perimeter.


[33m   Nested Loops
[0m
   In this example the points around the perimeter of the mandala from which
  the radiating circles are drawn are determined by a repeat loop, in which
  the for loop that executes the radiating circles is nested.

   For this "outside" repeat loop, we use the variable p to define the number
  of times the loop repeats, and the number of points along the circumference
  of the mandala.  In this case, '/p 2 def' defines two points along the
  circumference.  The last instruction in the loop, '360 p div rotate',
  locates the perimeter for each rotation - 360 divided by 2, or 180, in this
  case.

    306 396 translate

    /c 10 def
    /p 2 def

    -90 rotate   % Start at top

    p {
        -100 0 translate
        0 0 moveto
        1 1 c {
            100 c div mul
            dup 0 exch
            -180 180 arc
        } for
        100 0 translate
        360 p div rotate
    } repeat
    stroke

    showpage

   By changing the value of p from 2 to 4, to radiate circles from four
  points around the circumference of the mandala, and by changing the initial
  value of the inside loop operands from 1 to 2, to create a larger first
  circle on the perimeter, we have another interesting circular pattern.

    306 396 translate

    /c 10 def
    /p 4 def

    -90 rotate

    p {
        -100 0 translate
        0 0 moveto
        2 1 c {
            100 c div mul
            dup 0 exch
            -180 180 arc
        } for
        100 0 translate
        360 p div rotate
    } repeat
    stroke

    showpage


[33m   Finished Mandala
[0m
   Let us now create our first finished mandala, completing it with the
  'eofill' operator.  Use the code of the last example and replace the
  'stroke' operator with the 'eofill' operator to get a stunning effect.


[33m   neg
[0m
   Some of the drawings created in this tutorial result in a substantial
  number of individual line segments.  The number may exceed the limits of
  the PostScript interpreter you are using, which may then fail to print.  If
  this happens you can reduce the size of the design by reducing the radius,
  as in the following example.

   To reduce the radius we define a new variable with '/r 50 def', and
  replace the old radius of 100 with r in three separate instructions below.
  We then use the PostScript 'neg' (negative) operator, on the line that
  formerly read -100 0 translate, to change the sign of the radius to be a
  negative.

    108 648 translate

    /c 10 def
    /p 4 def
    /r 50 def

    -90 rotate

    p {
        r neg 0 translate
        0 0 moveto
        2 1 c {
            r c div mul
            dup 0 exch
            -180 180 arc
        } for
        r 0 translate
        360 p div rotate
    } repeat
    eofill

    showpage


[33m   setflat
[0m
   Another way to reduce the number of line segments is to use the 'setflat'
  operator (always enclosed within a 'gsave/grestore) This operator flattens
  curved lines, to reduce the number of line segments (see the Red book, page
  215).  Start at '20 setflat' and increase the number by 20 until you reach
  100.  If the design still will not print, then reduce the radius, or use
  'stroke' instead of 'eofill'.

    306 396 translate

    /c 8 def
    /p 6 def

    -90 rotate

    p {
        r neg 0 translate
        0 0 moveto
        2 1 c {
            r c div mul
            dup 0 exch
            -180 180 arc
        } for
        r 0 translate
        360 p div rotate
    } repeat

    gsave
        20 setflat
        eofill
    grestore

    showpage


   That's all for this month folks, next month we do some nifty work with
  procedures and text and graphics.



[32m   <> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <%> 34 <>
[0m

