This is a simple example of how I create diagrams in postscript. It makes heavy use of dmmlib, my personal postscript library, as well as some ad-hoc functions. A certain amount of existing postscript knowledge is helpful to understand it but if you know that it's a stack-based language for drawing text and images on a page, and that % is the comment marker and that { } creates a block, you can probably make sense of it.
The image is meaningless, created when "doodling" in ps for fun.
%!
(dmmlib/base.ps) run
(dmmlib/lines.ps) run
%
% I have defined "circle" and "spcircle" as taking the arguments x y rad.
% This takes that plus one argument, so that tcircle and hcircle below
% can provide n and then match the signature of circle.
%
% arg = exch def. Handy way to pull arguments off the stack.
% I've started tucking the arguments to functions and for-loops here.
/ncircle { /n arg /rad arg /y arg /x arg
% My spcircle has thick points at 0 and 180. For the orientation and
% symmetry of this design, I wanted a thick point at 90 and 3 or 6
% points total.
x y translate
% n block circrepeat = repeat with a 360/n rotate after each block.
% Everything happens in the current reference frame and rotates back
% around, so I can add to the current path and then closepath to make
% symmetrical shapes and such.
n {
% sparc is a drop-in replacement for arc that does its own spline
% calculation, which matters when using cstroke.
% The built-in arc makes a new spline every 90 degrees.
0 0 rad 90 dup 360 n div add sparc
} circrepeat
closepath
x neg y neg translate
} def
/tcircle { 3 ncircle } def
/hcircle { 6 ncircle } def
%
% cstroke is a changeable alias to brushystroke, defined in lines.ps.
% brushystroke is thick along the path where a new spline or line
% starts or ends.
% I'm defining hstroke here as a tiny replacement for cstroke to set
% a hue based on an angle to make it easier to see what each section does.
/hstroke {
360 div 1 0.7 sethsbcolor cstroke 0 setgray
} def
/HexaSomething {
gsave
% I like using powers of 2 for line thickness and 0.03125 is a pain.
32 recip setlinewidth
0 0 0.5 tcircle 0 hstroke
0 0 1 tcircle 30 hstroke
% Using circrepeat provides automatic triangular rotational symmetry.
3 {
gsave
0 -1 translate
0 0 1 hcircle 60 hstroke
% hmirror - run the block with and without a horizontal flip.
% hmirror _does_ act inside a gsave block.
% there is also a vmirror defined.
{ 0.5 -0.5 goto 0.5 -1.25 goto 90 hstroke } hmirror
grestore
} circrepeat
% I actually intended to make this a rounded hexagon but got
% the rotation direction wrong (-3 {foo} circrepeat would have worked)
% and I liked this accident better.
3 { 0 -1 1.5 -60 -120 arcn } circrepeat
closepath 120 hstroke
3 {
0 1 1.5 60 120 arc
0 1 goto
closepath
150 hstroke
0 2 0.5 tcircle 180 hstroke
} circrepeat
6 { 0 2 goto } circrepeat closepath 210 hstroke
%
% dot is just a filled circle that's 3 times as thick as the current
% line width, which I've found to harmonize well.
6 { 2.250 0 dot } circrepeat
6 { 0 2.5 goto 0 2.75 goto 240 hstroke } circrepeat
0 0 2.75 hcircle 270 hstroke
0 0 3 hcircle 300 hstroke
grestore
} def
%%EndProlog
% I've defined "softscale" to scale by the given number in both dimensions,
% and to divide the current line width by the same amount.
% I usually work at one unit per inch, and start in the center of the page.
72 softscale
4.25 5.5 translate
% for the printed version I want this to fill up more of the page.
1.25 softscale
HexaSomething
showpage
hexasomething.ps
hexasomething.pdf
This page and these graphics by Denis Moskowitz. Last modified Tuesday December 6, 2022.