Search code examples
graphicspostscript

Shading a triangle in postscript


I want to write some postscript code that will shade a triangle. Here is some code I have cobbled together from a couple of google searches that produces a shaded square:


%!PS-Adobe-3.0 EPSF-3.0
%%BoundingBox: 0 0 400 400

/square{
 0 0 40 40 rectclip
 << /ShadingType 2
    /ColorSpace [ /DeviceRGB ]
    /Coords [ 0 0 40 40 ]
    /Function <<
      /FunctionType 2
      /Domain [ 0 1 ]
      /C0 [ 0.9 0.2 0.0 ]
      /C1 [ 0.0 0.2 0.9 ]
      /N 1
    >>
 >>
} bind def
save gsave
200 200 translate 45 rotate
square shfill
grestore restore    
100 100 translate  300 rotate
square shfill showpage  

Now, if I create a plain text file with this code and give it the filename shade.ps --- the important thing being the .ps --- and double click to open on a mac then the Apple Preview app will open the file and produce a picture with two copies of the shaded square. Great!

But now I want to shade a triangle in a similar way. My goal is to have a few lines of code in the spirit of the above that produces a shaded triangle.

Can anyone help? Is this even the right forum to be asking this question?

Note added 16 Jan 2023: I removed the redundant line of code mentioned in the answer below.

My goal is to draw a Penrose tiling with thin and thick rhombuses and then shade the rhombuses to help give the appearance that they are sloping rooves in the spirit of John Conway's city named Penrasia.


Solution

  • The part that describes the square is this line:

    0 0 40 40 rectclip
    

    To change it into a triangle, you'll need to write a function that creates a triangular path and then calls clip on it. This may be easier to understand if you look at an expanded version of rectclip which would look something like this:

    /rectclip {
      4 dict
        /height exch def
        /width exch def
        /y exch def
        /x exch def
        x y moveto
        width 0 rlineto
        0 height rlineto
        width neg 0 rlineto
        closepath
        clip
      end
    } def
    

    For a triangle, you'll need to do something more like this, depending upon how you want to describe the triangle:

    /triclip {
      4 dict
        /height exch def
        /width exch def
        /y exch def
        /x exch def
        x y moveto
        width  0  rlineto
        width 2 div neg  height  rlineto
        closepath
        clip
      end
    } def
    

    And you'd call this function the same way that rectclip is called in the original.

    0 0 40 40 triclip
    

    A more idiomatic way to write the function in PostScript would use stack manipulation to avoid the need for a local dictionary.

    /triclip { % x y width height  .  -   ;sets clippath
      4 2 roll        % |- width height x y
      moveto          % |- width height
      exch dup 0      % |- height width width 0
      rlineto         % |- height width
      2 div neg exch  % |- -width/2 height
      rlineto         % |-
      closepath clip
    } def
    

    With practice you can start to "read" the stack manipulation part and treat the code instead as several statements and break the lines differently:

    /triclip { % x y width height  .  -   ;sets clippath
      4 2 roll moveto  % width height
      exch dup 0 rlineto  % height width
      2 div neg exch rlineto % -
      closepath clip
    } def
    

    The important part is the calls to moveto, lineto, closepath, and clip, and the rest is just the "syntax" of PostScript.