[comp.text] pic/ditroff "bug" + FIX

stevens@hsi.UUCP (Richard Stevens) (01/25/89)

About 8 months ago I posted a query to this group about a pic
problem that I was having with its drawing of arrow heads.
The problem is quite widespread - look at any of the UNIX
books that have used pic/ditroff to draw arrows: the latest
Kernighan and Ritchie (p. 144), Bach's "The Design of the UNIX
Op. Sys." (this is the worst, see pp. 347-348 especially),
the AWK book (p. 131, p. 173), and on and on ...

Anyway, I didn't get any positive responses, so I finally spent a
day and tracked the problem down.  It is an interesting problem,
with many potential "fixes".  First consider a typical arrow head:

	     E:|
	       |
	       |
      A:\      |      /:C
	 \     |     /
	  \    |    /
	   \   |   /
	    \  |  /
           B:\F| /:D

Now the goal is to have the three lines AB, CD and EF all end
at the same point (that is, the three points B, D and F should
be the same).  Unfortunately they sometimes aren't.

(1)  The pic output is fine, however, pic deals in floating point
coordinates.  This is the start of the problem, since ditroff
converts the floating point inch values into machine units.
I think another part of the problem is the way pic draws an arrow
with a head.  First it draws the line EF, from E going a specified
distance to F.  Then it draws the line AB, starting at A and going
a specified distance in both x and y.  Then it draws CD, again starting
at C and going a specified distance in x and y.  If pic were to
start all three line segments at a single point (B=D=F) and draw
from there, the problem might be solved, but I'm not positive.

(2)  ditroff converts the floating point inch values into machine
units, using its own atol() function and using the number of
machine units per inch (ditroff's "Inch" variable), which depends
on the typesetter.  I'm using Adobe's TranScript package which
uses a value of 576 units/inch for the PostScript device.
Since machine units are integer values for ditroff, this conversion
can cause problems since any fractional part is truncated.  There
is no rounding.

(3)  Even though three floating point numbers satisfy x+y=z, you don't
have int(x)+int(y)=int(z), and this indeed is the problem.  pic deals
in floating point inches and ditroff deals in integral machine units
and the conversion between the two isn't perfect.

The problem is that the ends of the three lines above can all be off
by 1 unit in both the x and y directions.  Visually I find it hard to
distinguish some of the "error" output, on our LaserWriter, but you
can sure pick it out in typeset books.  My guess is that the error
of 1 machine unit (1/567-inch) doesn't always correspond to a
different dot at 300 dots/inch, but corresponds to multiple dots
at the higher typesetter resolutions.  Perhaps the authors of these
books did all their proofing on a 300 dpi laser printer and only
noticed the problem when running the final typeset copy, when it
was too late to fix ?

My solution is two-fold:

(1)  First, I now set my own pic defaults and any other pic sizes,
so that the chosen floating point value in inches corresponds to an
exact number of machine units.  For example, I set

	arrowwid = 0.0625i
	arrowht  = 0.125i

This is because 0.0625/2 * 576 equals 18 units exactly.  There is 
no truncation performed by ditroff when it converts it.  (The divide
by 2 is because the arrowwid value is the total distance between
the starts of the two arrow heads, and pic needs the distance from
the start of the arrow head to the line.)
This means I'll have to change these values if I use another post-
processor that uses a value other than 576, but I figure the Adobe
PostScript values will be all I need for a while.  The default values
used by pic (0.05 and 0.1) are unsuitable since they'll cause the
truncation errors when ditroff converts them.

(2)  Second, I modified our pic source code so that it outputs 5
digits to the right of the decimal point, instead of its default
of 3.  This is so that it maintains the complete floating point
values that I give it.  Without this change, using the values I
show above, the 0.0625/2=0.03125 gets output by pic as 0.031
and this is then truncated by ditroff, which I don't want to
happen.


	Richard Stevens
	Health Systems International, New Haven, CT
	   stevens@hsi.com
           ... { uunet | yale } ! hsi ! stevens

/* FLAME ON. */

Please no comments from all the troff vendors saying "hey fool,
if you'd have only bought our complete troff package we fixed
this years ago ...".

/* FLAME OFF. */