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
Hints for drawing, in nine easy steps (-;
If you wish to print it out, feel free to use something like include_run to roll the run files in.
line_drawing.ps - Line Drawing in PostScript
%!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
The following subroutines are available: longcurveto, longcurve, reversecurve, pointdef, pointadd, pointdup, interpolate2, interpolate3, fuzzygraystroke, fuzzygrayfill, fuzzyrgbstroke and fuzzyrgbfill.
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.
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
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.
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
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
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
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.
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.
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.
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.
This is just a synonym for 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.
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.
Peter J Billam www.pjb.com.au/comp/contact.html
See also
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 . . .