From: asnd@msr.triumf.ca (Donald Arseneau)
Subject: Re: Wanted: the paragragh shape in TeX
News-Software: VAX/VMS VNEWS 1.41    
Organization: TRIUMF: Tri-University Meson Facility
Date: Thu, 9 Apr 1992 23:56:00 GMT

In article <1992Apr9.145118.14359@rockyd.rockefeller.edu>, wangfei@rocky8 (Fei Wang) writes...
>    Does any one who knows how to produce (in TeX) a paragragh whose shape 
>is a diamond?
>    I mean if the paragragh is big, the shape of this paragragh (diamond) 
>will be big, if the paragragh is small, the diamond will be small.

This is at least the fourth time I've seen this plea, and I am fed up with
it.  So I did it.

The macros lend themselves to various shaps, so maybe next Feb. 14 I will 
make a \heartpar version.

--- Donald Arseneau

%        D I A M O N D P A R . S T Y  or  . T E X
%
% \diamondpar{17pt} A macro to typeset paragraphs in a diamond shape.
% The size is adjusted automatically.  There is one parameter: the increment
% by which to change the indentation with every line. The command
% "\diamondpar{\baselineskip}" produces a square paragraph standing on its
% corner.  There can be no displayed math, and no "\vadjust" material, which
% includes "\vspace".  These macros work for both \LaTeX\ and plain \TeX\ .
% 
% \diamondpar{6pt} The paragraph is repeatedly formatted until the size
% and shape are right; this process can be very slow.  It is a bit faster
% with \TeX~3 because "\emergencystretch" is used for the formatting.
% If \TeX~2 is being used, the "\leftskip" and "\rightskip" are increased
% until the paragraph formats cleanly, so some ``diamonds'' might look 
% pretty bad. A short first word and a space before the final period help .
% 
% \diamondpar{30pt} Donald Arseneau Apr. 1992
% 
% 
% make file load whatever status of @
\expandafter\edef\csname D@catcode\endcsname
  {\catcode`\noexpand\@=\the\catcode`\@
  \let \csname D@catcode\endcsname \noexpand\UnDefinedButNoAt}
\catcode`\@=11

% Define variables.  Use LaTeX names for some.
\newbox\D@boxa
\newbox\D@boxb
\ifx\@tempdima\@undefined \newdimen\@tempdima \fi
\ifx\@tempdimb\@undefined \newdimen\@tempdimb \fi
\ifx\@tempcnta\@undefined \newcount\@tempcnta \fi
\ifx\@tempcntb\@undefined \newcount\@tempcntb \fi
\newdimen\D@pd
\newdimen\D@step
\newcount\D@gcount

% Take a square root of counter \sqrtcount using Newton's method.
\newcount\sqrtcount
\def\sqrtofcount{\@tempcnta\sqrtcount \sqrtcount=20 \squiterate}
\def\squiterate{\@tempcntb\@tempcnta \divide\@tempcntb\sqrtcount
   \advance\sqrtcount\@tempcntb \divide\sqrtcount\tw@
   \advance \@tempcntb -\sqrtcount
   \ifnum \ifnum \@tempcntb<\z@ -\fi \@tempcntb>3 % approximate, use 1 for exact
   \expandafter \squiterate \fi}

\def\diamondpar#1{%  #1 = distance to step indentation at every line.
\par \D@step#1\relax \D@pd\prevdepth
\setbox\D@boxa\vbox\bgroup
 \parindent\z@ \leftskip\z@ \rightskip\z@ 
 \parfillskip\z@ plus 1fill \begingroup
 \let\par\D@endpar \hsize\maxdimen \pretolerance\m@ne 
 \ifx\textwidth\@undefined\else \textwidth\hsize \linewidth\hsize\fi
 \def\vadjust{{\def\D@dm{special vertical material}\the\everydisplay}}%
 \everydisplay{\errhelp{Press RETURN, and only the text following
     the error will be printed.}\errmessage{Diamond Paragraph Error: 
     \D@dm\space is illegal in a diamond paragraph}}%
 \ignorespaces}

\def\D@endpar{\endgraf \endgroup \unskip\unkern\unpenalty 
  \setbox\D@boxa\lastbox
  \setbox\D@boxa\hbox{\unhbox\D@boxa\unskip\unskip\unpenalty}%
  \@tempdima\wd\D@boxa \divide\@tempdima\D@step \sqrtcount\@tempdima 
  \sqrtofcount % guess num lines
  \advance\sqrtcount\tw@ \global\D@gcount\sqrtcount 
  \begingroup 
  \ifx\emergencystretch\@undefined % TeX 2, ugly
    \tolerance\@M \spaceskip .333333emplus1.66666emminus1.11111em
    \hfuzz4\D@step
  \else % TeX 3, nicer
    \tolerance\@m \emergencystretch 2in\relax
  \fi \hbadness\@M % avoid error messages
  \global\let\D@again\D@tryparshape  \D@tryparshape}

\def\D@tryparshape{% try a diamond parshape with \D@gcount lines
  \@tempcntb\D@gcount \advance\@tempcntb\@ne
  \edef\D@parshape{\parshape\the\@tempcntb\space}\def\D@shapepar{\z@.5\maxdimen}%
  \@tempcntb\@ne
  \@tempdimb\D@step \@tempdima.5\hsize \advance\@tempdima-.5\D@step
  \loop % construct the \parshape command
    \ifnum\@tempcntb<\D@gcount
    \edef\D@parshape{\D@parshape\the\@tempdima\the\@tempdimb\space}%
    \edef\D@shapepar{\the\@tempdima\the\@tempdimb\space\D@shapepar}%
    \advance\@tempdima-\D@step \advance\@tempdimb2\D@step
    \advance\@tempcntb\tw@
  \repeat
  \global\setbox\D@boxb\vbox{%
  \D@parshape \ifodd\D@gcount \the\@tempdima\the\@tempdimb\fi \D@shapepar 
  \noindent\unhcopy\D@boxa\endgraf
  \ifnum\prevgraf=\D@gcount % right size, done
    \global\advance\D@gcount\m@ne \aftergroup\D@done
  \else\ifnum\prevgraf>\D@gcount % text too long, do again
    \global\advance\D@gcount\@ne \global\let\D@again\D@done 
    \aftergroup\D@tryparshape
  \else % too small; if was too big before, then done, otherwise do again
    \global\advance\D@gcount\m@ne \aftergroup\D@again
  \fi\fi}}

\def\D@done{\global\advance\D@gcount\tw@
  \leftskip\z@ plus2ptminus2pt \rightskip\z@ plus2ptminus2pt 
  \parfillskip.5\maxdimen % this will drag text to the bottom point.
  \D@reform % reformat paragraph 
  \endgroup\egroup % back to the outer page list
  \D@pd\dp\D@boxb \unvbox\D@boxb \prevdepth\D@pd
}

\def\D@reform{\global\setbox\D@boxb\vbox\bgroup
  \D@parshape \ifodd\D@gcount\else \the\@tempdima\the\@tempdimb\fi \D@shapepar 
  %% get prevdepth from outside, penalty puts \parskip and favors breaks
  \prevdepth\D@pd \ifdim\D@pd>-\@m\p@ \penalty-50 \fi
  \noindent\unhcopy\D@boxa\unskip\unskip\unpenalty\strut
  \penalty-\@m\hbox{\kern\hfuzz}\endgraf
  \ifnum\prevgraf=\D@gcount % good, it worked.
    \setbox\D@boxa\lastbox \unskip\unpenalty %remove mongo last box
    \egroup 
  \else \egroup \multiply\leftskip\tw@ \multiply\rightskip\tw@ 
    \expandafter \D@reform 
  \fi}

\def\D@dm{displayed math}

\D@catcode % restore catcode of @ to starting value

%
% Send problem reports to asnd@triumfcl.bitnet or asnd@Jack.TRIUMF.CA
%
% test integrity:
% brackets: round, square, curly, angle:   () [] {} <>
% backslash, slash, vertical, hat, tilde:   \ / | ^ ~