line_drawing.ps Manual


line_drawing.ps README

This module implements various routines to do in PostScript what an artist does when sketching with, say, pencil and paper.

The artist thinks something like "well, starting at this point, first there's about this distance of that curvature to the left, then about that distance of a much tighter curvature to the left, then a much longer listance of this fairly gentle curve to the right, etc, etc, ending up finally at that point." The main subroutine longcurveto implements that process in PostScript.

Using line_drawing.ps is of course much slower than sketching with pencil and paper, it's closer to some of the older print-making techniques like mezzotint (as used by Escher) offering complete control of greyscale, extremely fine detail, and perfect reproducibility.

To install: go to www.pjb.com.au/comp/free/line_drawing.ps.txt and save the file to your local disc. Rename it to line_drawing.ps and move it into some appropriate directory such as ~/ps/lib . . .

Peter J Billam    www.pjb.com.au


line_drawing.ps Tutorial

Hints for drawing, in nine easy steps (-;

  1. at each junction of 3 colours, put a Point (eg "nosetip", "brow")
  2. at each boundary of 2 colours, put a Curve (eg "nosetip2brow")
  3. define at least 3 Points in x,y (eg "/brow { 67 mm 200 mm } def")
  4. define the Curves (eg "/nosetip2brow { 10 20 60 1 /bridge 15 -45 } def")
  5. define any remaining Points by interpolate2, interpolate3 and pointadd
  6. define any Colours ("/darkskin paleorange .4 brown .6 rgbmix rgbdef")
  7. run all the Curves and interpolations to calculate all Point positions (eg "nosetip moveto [ nosetip2brow ] brow longcurveto")
  8. make closedpaths round areas; clip, fill, fuzzystroke & fuzzyfill in them
  9. run the Curves again, and this time stroke or fuzzystroke them
As examples, see sample1.ps.txt and sample2.ps.txt and sample3.ps.txt . . . Save the file to your local disc, rename it to sample1.ps or sample2.ps or sample3.ps and edit it so that the run statement(s) near the beginning point to the directory where line_drawing.ps and colours.ps are installed on your system. Then use GhostView or equivalent to view it.

If you wish to print it out, feel free to use something like include_run to roll the run files in.


Name

line_drawing.ps - Line Drawing in PostScript


Synopsis

 %!PS-Adobe-2.0
 %%EndComments
 %%BeginProlog
 (/home/wherever/ps/lib/line_drawing.ps) run
 (/home/wherever/ps/lib/colours.ps) run
 %%EndProlog
 %%Page: 1 1
 /brow { 67 mm 200 mm } def   % define some Points in x,y
 /nose { 34 mm 100 mm } def
 /ear { 124 mm 145 mm } def
 /nose2brow { 10 20 60 1 /bridge 15 -65 15 50 60 5 } def   % define the Curves
 /brow2ear  { 10 20 60 1 /bridge 15 -45 } def
 /eye brow nose .4 brow .4 ear .2 interpolate3 pointdef
 /darkskin paleorange .4 brown .6 rgbmix rgbdef  % mix some Colours
 newpath nosetip moveto  % run the Curves ...
 [ nose2brow ] brow longcurveto [ brow2ear ] ear longcurveto
 % make closedpaths round areas; clip, fill, fuzzystroke & fuzzyfill
 closepath darkskin setrgbcolor fill
 % run the Curves again, and this time stroke or fuzzystroke them
 black setrgbcolor
 newpath nose moveto [ nose2brow ] brow longcurveto stroke
 showpage
 %%EOF

Subroutines

The following subroutines are available: longcurveto, longcurve, reversecurve, pointdef, pointadd, pointdup, interpolate2, interpolate3, fuzzygraystroke, fuzzygrayfill, fuzzyrgbstroke and fuzzyrgbfill.

[ l c l c (pushxy) l c /apoint l c ] xto yto longcurveto

Where the arguments are:
l is the nominal length of the segment in mm (will be scaled !)
c is the rightwards curvature of the segment in Radians/Metre (ditto)
pushxy causes the x,y at that point to be left on the stack; afterwards it can be used for example by moveto
/apoint any nametype (e.g. /thispoint) causes that name to be defined, as in a pointdef
xto, yto cause the curve to be scaled and rotated to end at position xto, yto

longcurveto starts at the current point. Firstly, without affecting the currentpath, it draws the curve as specified, i.e. this distance at this curvature, that distance at that curvature, and so on; it then notes the point at which it ends up, and scales and rotates so as to transform this into the desired endpoint xto yto. Then, secondly, it redraws the curve, adding it to the currentpath, and defining points such as /apoint as it goes. It leaves the currentpoint at xto yto.

longcurveto, longcurve and reversecurve can, unfortunately, not be used to create a userpath; they append to the currentpath. See the PostScript Language Reference Manual for more about userpaths.

angle [ l c l c l c (pushxy) l c l c ] longcurve

Where the arguments are:
the curve starts at angle angle from the current point
l is the length of the segment in mm
c is the rightwards curvature of the segment in Radians per Metre
pushxy causes the x,y at that point to be left on the stack afterwards
any nametype (e.g. /thispoint) causes it to be defined as in a pointdef

[ l1 c1 l2 c2 /name l3 c3 ] reversecurve

The above invocation leaves [ l3 -c3 /name l2 -c2 l1 -l1 ] on the stack. When a path (as used by longcurveto has been defined, it is often useful to be able to use it in either direction; e.g. once in outlining the area to one side of it, and once in outlining the area to the other side. reversecurve offers an easy way to reverse a path.

/name_of_point x y pointdef

The above invocation leaves name_of_point defined as { x y } so it's like a two-dimensional version of def. For example,
  /point_name currentpoint pointdef

x1 y1 x2 y2 pointadd

The above invocation leaves x1_plus_x2 y1_plus_y2 on the stack, and is often useful to place a second point at a known increment away from a first. It's like a two-dimensional version of add

x y pointdup

The above invocation leaves x y x y on the stack, and is handy if a point needs to be used now but also left on the stack to come back to later. It's like a two-dimensional version of dup

x1 y1 weight1 x2 y2 weight2 interpolate2

The above invocation leaves on the stack, ready for moveto or pointdef, the x y of a point which is on the straight line between x1 y1 and x2 y2. If weight1 and weight2 are both 0.5 then the interpolated point will be half way, but if weight1 is 0.9 and weight2 is 0.1 then the interpolated point will be much closer to x1 y1.

The weights don't have to add up to one, they get normalised to total 1.0 automatically.

x1 y1 weight1 x2 y2 weight2 x3 y3 weight3 interpolate3

The above invocation leaves on the stack, ready for moveto or pointdef, the x y of a point which is in the area between x1 y1 and x2 y2 and x3 y3. If weight1 and weight2 and weight3 are all 0.333 then the interpolated point will be in the middle, but if weight1 is 0.7 and weight2 is 0.2 and weight2 is 0.1 then the interpolated point will be much closer to x1 y1.

The weights don't have to add up to one, they get normalised to total 1.0 automatically.

innergray outgray inwidth outwidth fuzzygraystroke

The above invocation strokes a fuzzy grey line along the currentpath. At its centre, the line will be of a innergray greyness, and this shade will be of width inwidth. At its outer fuzzy edges, which will be of width outwidth, the line will be of a outgray greyness; so that will usually be chosen to be the same shade as the background. This subroutine is useful for shading.

innergray outergray fuzzwidth fuzzygrayfill

The above invocation fills the currentpath with innergray. Outside the currentpath, the greyness fades, over the width fuzzwidth, into an outgray greyness; so that will usually be chosen to be the same shade as the background. This subroutine is also useful for shading.

fuzzystroke

This is just a synonym for fuzzyrgbstroke.

incolour outcolour inwidth outwidth fuzzyrgbstroke

The above invocation strokes a fuzzy coloured line along the currentpath. At its centre, the line will be of a incolour rgb colour, and this shade will be of width inwidth. At its outer fuzzy edges, which will be of width outwidth, the line will be of a outcolour colour; so that will usually be chosen to be the same colour as the background. This subroutine is useful for shading in colour. See also colours.ps.

innercolour outercolour fuzzwidth fuzzyrgbfill

The above invocation fills the currentpath with innercolour. Outside the currentpath, this colour shades, over the width fuzzwidth, into outcolour; so that will usually be chosen to be the same colour as the background. This subroutine is also useful for shading in colour. See also colours.ps.


Author

Peter J Billam www.pjb.com.au/comp/contact.html


See Also

See also


line_drawing.ps Changes

20001208 Line-Drawing PS Library (smooth+longcurve)
20001209 more consistent calling syntax
20001211 fuzzystroke, fuzzyfill, longcurveto
20001211 fixed various bugs in pointdef
20001212 /names allowed in longcurve arrays
20001212 copyright notice
20001214 fuzzyrgbfill fuzzyrgbstroke & colours.ps
20001216 add reversecurve
20001218 rgb is now the default, not gray
20001221 /name first in pointdef and rgbdef
20001224 add interpolate2
20010108 move gray0..gray9 defs in
20010116 add subroutine pointdup
20030313 roll some stuff out to colours.ps
20031122 in longcurve, prevent div by 0 if curvature=0

Back to P J B Computing or to www.pjb.com.au . . .