File: //usr/share/texmf/tex/generic/tex-ps/trans.tex
% ---------------------------------------------------------------------------
% TeX macros implementing a standard set of PostScript transformations
% made in BOP (1993--2001), Gda\'nsk, Poland -- public domain software
% authors: Bogus\l{}aw Jackowski, Piotr Pianowski, Piotr Strzelczyk
% e-mail contact: bop@bop.com.pl
% ---------------------------------------------------------------------------
% S Y N O P S I S
%
% In the sequel, `box' means \hbox, \vbox, \box, or \copy, `dimen' means
% a sequence of dimens to be summed up; all macros mentioned below expand
% to \hbox{...}, they can therefore be used wherever \hbox can be.
%
% 1)
% x_scale and y_scale are given in percents (>0)
% \zscale changes uniformly x_size and y_size (x_scale=y_scale=scale)
% \xscale changes only x_size (y_scale=100)
% \yscale changes only y_size (x_scale=100)
%
% \zscale{scale} followed by a box
% \xyscale{x_scale}{y_scale} followed by a box
% \yxscale{y_scale}{x_scale} followed by a box
% \xscale{x_scale} followed by a box
% \yscale{y_scale} followed by a box
%
% 2)
% \xyscaleto resizes a box uniformly such that the resulting wd=dimen
% \yxscaleto resizes a box uniformly such that the resulting ht=dimen
% \xscaleto resizes a box horizontally such that the resulting wd=dimen
% \yscaleto resizes a box verically such that the resulting ht=dimen
%
% \xyscaleto{dimen} followed by a box
% \yxscaleto{dimen} followed by a box
% \xscaleto{dimen} followed by a box
% \yscaleto{dimen} followed by a box
%
% 3)
% \revolve rotates anticlockwise the box (either \hbox or \vbox
% following the command) by 90 degree; for the resulting box
% width=height+depth of the original box, height=width
% of the original box, and the reference point is the left top corner
% of the original box; this means that revolving a box four times
% yields the original box if and only if its depth is zero;
% \revolvedir- is equivalent to \revolve, \revolvedir+ rotates
% the box clockwise
%
% \revolve followed by a box
% \revolvedir+ followed by a box
% \revolvedir- followed by a box
% \revolveleft followed by a box (equivalent to \revolvedir-)
% \revolveright followed by a box (equivalent to \revolvedir+)
% \revolvepi followed by a box (equivalent to \xflip\yflip
% but not to \revolve\revolve)
% \rotatepi followed by a box (equivalent to \revolvepi;
% cf. also plain METAFONT rotatedaround and rotatedabout macros)
% 4)
% \rotate rotates a box by an arbitrary angle, clockwise for angle>0,
% width=height=depth=0pt for the resulting box
%
% \rotate{angle} followed by a box
%
% \rotatebb rotates a box by an arbitrary angle, clockwise for angle>0;
% the result is placed in a box having the dimensions of the resulting
% bounding box, protrusion to the left is compensated by appropriate
% shifting (see the macro \put_into_bb)
%
% \rotatebb{angle} followed by a box
%
% 5)
% \xflip and \yflip flip the box horizontally and vertically,
% respectively, i.e., with respect to the vertical and horizontal
% axis of the box, without changing the dimensions of the \box
%
% \xflip followed by a box
% \yflip followed by a box
%
% 6)
% \slant slopes a box by an angle alpha such that tan(alpha)=slant,
% without changing dimensions of the \box;
%
% \slant{slant} followed a box
%
% (negative argument value means slanting to the left)
%
% \slantbb slopes a box by an angle alpha such that tan(alpha)=slant,
% the result is placed in a box having the dimensions of the resulting
% bounding box, protrusion to the left is compensated by appropriate
% shifting (see the macro \put_into_bb)
%
% \slantbb{slant} followed a box
%
% 7)
% \clipbox clips the contents of a box that follows the command;
% the macro expects three dimen parameters: the width, the height
% and the depth of the resulting box
%
% \clipbox{width}{height}{depth} followed a box
%
% Any parameter can be empty; in such a case, the respective dimension
% of the original box is used
% ---------------------------------------------------------------------------
% HISTORY:
% 18 VIII 1993 ver. 0.1
% * first release
% 30--31 VIII 1993 ver. 0.2
% * third parameter eliminated from \scale (via \afterassignment
% and \aftergroup hackery)
% * added \zscale, \xyscale, \yxscale, \xscale, and \yscale
% with scaling given in percents
% * added \scaleto, \xyscaleto, \yxscaleto, \xscaleto, and \yscaleto
% 3 IX 1993 ver. 0.21
% * \the_scale renamed to \lastscale and made global, thus it became
% available to a user
% 8 IX 1993 ver. 0.22
% * all transformations return \hbox, because of currentpoint
% positioning
% * the old version of \scale is become undefined
% * \slant and \rotate fit the new convention of parameter's
% hackery -- they are assumed to be followed by an \hbox
% or a \vbox
% 6 XII 1993 ver. 0.23
% * \revolve added
% * \rotate with \vbox patched
% 10 II 1994 ver. 0.24
% * \revolvedir+, \revolvedir-, \xflip, and \yflip added
% 20 III 2000 ver. 0.5 (pre-release)
% * total reconstruction:
% -- all macros expand to \hbox, so that it is possible to
% superpose them, e.g., \xscale{200}\yscale{50}\hbox{...};
% one must remeber, however, that \rotate yields a box having
% null dimensions, so an attempt to scale the result
% to a given dimen will produce erroneous PostScript code
% -- the possibility of changing \ht and \dp of a \vbox abolished;
% such an operation yields hardly intuitive results; try, e.g.:
% \hrule width\hsize
% \hbox{\setbox0\hbox{\vrule height1cmwidth1cm}\ht0 0mm \box0}
% \kern20mm
% \hrule width\hsize
% \hbox{\setbox0\vbox{\hrule height1cmwidth1cm}\ht0 0mm \box0}
% -- the box expected by all macros can be a TeX box expression:
% \hbox, \vbox, \box, and \copy
% -- scaling height or width to a given dimension yields exact value
% of the height or width, respectively (or both); this change is
% backward incompatible (but reasonable, one should think)
% -- all transformations store information about the position of the
% lower left corner and the upper right corner of the resulting
% bounding box (with respect to the base point of the transformed
% box) in four globally defined macros:
% \transllx, \translly, \transurx, \transury
% (a piece of funny code for vector rotation was added)
% -- \rotatebb and \slantbb added
% 25 III 2000 ver. 0.51
% * fraction multiplication improved (speedup in trigonometric
% calculations ca 30%)
% * trigonometry calculations are performed in a group (otherwise using
% them within another \loop ... \repeat would be inconvenient);
% the result is a pair of globally defined macros (instead of dimen
% registers); they expand to a series of digits (i.e., they contain
% a count representation of the resulting dimen)
% * \unhbox (introduced in order to reduce the level of box nesting)
% should be used only in \rotatebb
% * internal macro naming changed
% 27 III 2000 ver. 0.52
% * a dimen parameter can be a sequence of dimens to be summed up
% * \clipbox added
% 7--10 X 2000 ver. 0.53
% * a bug in \slant[bb] fixed: \ht and \dp were interchanged due to
% a fallacious interpretation of a slant sign (recall that in dvips
% PostScript, unlike in METAFONT, `-' denotes slanting to the right,
% `+' -- to the left, because the y-axis is directed downwards);
% actually, the problem is much more complex: relying (unconsciously)
% on dvips coordinates means, in this case, that for non-square pixels
% both rotate and slant will not work -- need to be fixed!
% 13 XI 2000 ver. 0.54
% * @ is a letter during reading trans macros (AMSTeX uses active @)
% * local macro \undtranscode renamed to \transundcode
% 9 VI 2001 ver 0.55
% * ``mnemonic'' macros added: \revolveleft, \revolveright, \revolvepi
% and \rotatepi
% ---------------------------------------------------------------------------
\def\transspecial#1{\special{ps:#1}}% driver-oriented; default is dvips
% ---
\edef\transundcode{\the\catcode`\_}\catcode`\_11
\edef\transatcode{\the\catcode`\@}\catcode`\@11
% \z@ (0pt) and \p@ (1pt) are borrowed from plain
% ---
% a pretty general macro
\def\sumto#1{\def\sum_to_what{#1}\sum_to_what=\z@\relax \sumto_}
\def\sumto_{\futurelet\sum_tok\sumto__}
\def\sumto__{\ifx\sum_tok\relax\else\expandafter\sumto___\fi}
\def\sumto___{\afterassignment\sumto_\advance\sum_to_what}
% ---
\newbox\tmp_box % temporary box register
\newdimen\tmp_dim % temporary dimen registers
\newdimen\tmp_dim_a
\newdimen\tmp_dim_b
\newdimen\tmp_dim_c
\newdimen\tmp_dim_d
\newcount\tmp_count_a % temporary count registers
\newcount\tmp_count_b
\newcount\tmp_count_c
\newif\ifput_into_bb
% ---
\def\jump_setbox{\ifvoid\tmp_box % every box is initially void
\aftergroup\after_setbox \else \after_setbox \fi}% a general trick
% ---
\def\set_std_bb{%
\xdef\transllx{\the\z@}%
\xdef\translly{\ifdim\dp\tmp_box>\z@ -\fi\the\dp\tmp_box}%
\xdef\transurx{\the\wd\tmp_box}%
\xdef\transury{\the\ht\tmp_box}%
}
\def\put_into_bb#1{% #1 = operation: \unhbox for rotation, \box for slanting
\setbox\tmp_box\hbox{\kern-\transllx\rlap{#1\tmp_box}\kern\transurx}%
\ht\tmp_box\transury \dp\tmp_box-\translly \relax
}
% ---
\def\perc_scale#1#2{% #1 -- xscale, #2 -- yscale, in percents,
% to be followed by an \hbox or a \vbox
\def\after_setbox{%
\setbox\tmp_box\hbox{%
\transspecial{gsave
currentpoint #2 100 div div exch #1 100 div div exch
currentpoint neg #2 100 div mul exch neg #1 100 div mul exch
translate #1 100 div #2 100 div scale translate}%
\box\tmp_box \transspecial{grestore}}%
\ifdim#1\p@=100\p@ \else % special treatment of special case (100%)
\tmp_dim\wd\tmp_box
\advance\tmp_dim50sp \divide\tmp_dim100 % rounding rather than floor
\wd\tmp_box#1\tmp_dim
\fi
\ifdim#2\p@=100\p@ \else % ditto
\tmp_dim\ht\tmp_box
\advance\tmp_dim50sp \divide\tmp_dim100 % ditto
\ht\tmp_box#2\tmp_dim
\tmp_dim\dp\tmp_box
\advance\tmp_dim50sp \divide\tmp_dim100 % ditto
\dp\tmp_box#2\tmp_dim
\fi
\set_std_bb
\box\tmp_box\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
% ---
\def\xyscale#1#2{\hbox\bgroup\perc_scale{#1}{#2}}
\def\zscale#1{\xyscale{#1}{#1}}
\def\yxscale#1#2{\xyscale{#2}{#1}}
\def\xscale#1{\xyscale{#1}{100}}
\def\yscale#1{\xyscale{100}{#1}}
% ---
{\catcode`\p12 \catcode`\t12 \gdef\PT_{pt}}
\def\hull_num{\expandafter\hull_num_}
\expandafter\def\expandafter\hull_num_\expandafter#\expandafter1\PT_{#1}
% ---
\def\find_scale#1#2{% #1 -- size after rescaling, #2 -- \wd or \ht
% Finds a scale (\lastscale macro) such that the box following the macro
% call would have the respective dimen (i.e., #2) equal to #1 after rescaling
% NOTE: it is assumed that prior to calling \find_scale a macro
% \extra_complete is defined
\def\after_setbox{%
\resize\tmp_dim{100\p@}{#1}{#2\tmp_box}%
\xdef\lastscale{\hull_num\the\tmp_dim}\extra_complete}%
\afterassignment\jump_setbox\setbox\tmp_box =
}
% ---
\def\scaleto#1#2#3#4{% #1 -- size of dimen #2 (\wd or \ht) after scaling
% #3 -- actual x-size, #4 -- actual y-size
\hbox\bgroup % `initial' hbox
\sumto\tmp_dim#1\relax % freeze the argument; must not be empty
\setbox\tmp_box\hbox\bgroup % one more setbox in order to control
% the specified dimen
\def\extra_complete{%
\perc_scale{#3}{#4}\box\tmp_box % finish setbox above
#2\tmp_box=\tmp_dim % force the exactness of the specified dimension
\set_std_bb
\box\tmp_box
\egroup % close `initial' hbox
}%
\find_scale{\tmp_dim}#2}
%
\def\xyscaleto#1{\scaleto{#1}\wd\lastscale\lastscale}
\def\yxscaleto#1{\scaleto{#1}\ht\lastscale\lastscale}
\def\xscaleto#1{\scaleto{#1}\wd\lastscale{100}}
\def\yscaleto#1{\scaleto{#1}\ht{100}\lastscale}
% ---
\def\slant{\hbox\bgroup \put_into_bbfalse \slant_}
\def\slantbb{\hbox\bgroup \put_into_bbtrue \slant_}
\def\slant_#1{% #1 (slant) = tan(alpha), where alpha is the slant angle,
% to be followed by a box
\def\after_setbox{%
\transspecial{gsave 0 currentpoint neg exch pop 0 currentpoint exch pop
translate [1 0 #1 1 0 0] concat translate}%
% set bounding box
\dim_x\wd\tmp_box
\ifdim#1\p@>\z@ \dim_t-#1\ht\tmp_box \advance\dim_x#1\dp\tmp_box
\else \dim_t#1\dp\tmp_box \advance\dim_x-#1\ht\tmp_box
\fi
\xdef\transllx{\the\dim_t}%
\xdef\translly{\ifdim\dp\tmp_box>\z@ -\fi\the\dp\tmp_box}%
\xdef\transurx{\the\dim_x}%
\xdef\transury{\the\ht\tmp_box}%
\ifput_into_bb \put_into_bb\box \fi
\box\tmp_box \transspecial{grestore}\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
% ---
\def\update_bb#1#2#3{% used in \rotate
\trigcompute{-#1}{#2}{#3}% clockwise vs anti-clockwise
\ifdim\transllx>\trigxresult sp\xdef\transllx{\trigxresult sp}\fi
\ifdim\translly>\trigyresult sp\xdef\translly{\trigyresult sp}\fi
\ifdim\transurx<\trigxresult sp\xdef\transurx{\trigxresult sp}\fi
\ifdim\transury<\trigyresult sp\xdef\transury{\trigyresult sp}\fi
}
\def\rotate{\hbox\bgroup \put_into_bbfalse \rotate_}
\def\rotatebb{\hbox\bgroup \put_into_bbtrue \rotate_}
\def\rotate_#1{% #1 -- angle,
% to be followed by a box
\def\after_setbox{%
\setbox\tmp_box\hbox{% otherwise does not work with \vbox
\transspecial{gsave currentpoint currentpoint translate
#1 rotate neg exch neg exch translate}%
\box\tmp_box \transspecial{grestore}}%
% set bounding box
\xdef\transllx{\the\z@}\xdef\translly{\the\z@}%
\xdef\transurx{\the\z@}\xdef\transury{\the\z@}%
\update_bb{#1}{\z@}{\ht\tmp_box}%
\update_bb{#1}{\z@}{-\dp\tmp_box}%
\update_bb{#1}{\wd\tmp_box}{\ht\tmp_box}%
\update_bb{#1}{\wd\tmp_box}{-\dp\tmp_box}%
%
\wd\tmp_box\z@ \ht\tmp_box\z@ \dp\tmp_box\z@
\ifput_into_bb \put_into_bb\unhbox \fi
\box\tmp_box\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
% ---
\def\plus_{+}
\def\minus_{-}
\def\revolvedir#1{% to be followed by a box
\hbox\bgroup
% check parameter:
\def\param_{#1}%
\ifx\param_\plus_ \else \ifx\param_\minus_
\else
\errhelp{I would rather suggest to stop immediately.}%
\errmessage{Argument to \noexpand\revolvedir should be either + or -}%
\fi\fi
\def\after_setbox{%
\tmp_dim_a\wd\tmp_box
% prepare to revolving:
\setbox\tmp_box\hbox{%
\ifx\param_\plus_\kern-\tmp_dim_a\fi
\box\tmp_box
\ifx\param_\plus_\kern\tmp_dim_a\fi}%
% compute dimensions of the box to be revolved:
\tmp_dim_a\ht\tmp_box \advance\tmp_dim_a\dp\tmp_box
\tmp_dim_b\ht\tmp_box \tmp_dim_c\dp\tmp_box
\dp\tmp_box\z@ \ht\tmp_box\wd\tmp_box \wd\tmp_box\tmp_dim_a
% revolve:
\kern \ifx\param_\plus_ \tmp_dim_c \else \tmp_dim_b \fi
\transspecial{gsave currentpoint currentpoint translate
#190 rotate neg exch neg exch translate}%
\set_std_bb
\box\tmp_box
\transspecial{grestore}%
\kern -\ifx\param_\plus_ \tmp_dim_c \else \tmp_dim_b \fi
\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
\def\revolveleft{\revolvedir-}
\def\revolveright{\revolvedir+}
\def\revolvepi{\xflip\yflip}
\let\revolve\revolveleft
\let\rotatepi\revolvepi
% ---
\def\xflip{% to be followed by a box
\hbox\bgroup
\def\after_setbox{%
\tmp_dim_a.5\wd\tmp_box
% prepare to flipping:
\setbox\tmp_box
\hbox{\kern-\tmp_dim_a \box\tmp_box \kern\tmp_dim_a}%
% flip:
\kern\tmp_dim_a
\transspecial{gsave currentpoint currentpoint translate
[-1 0 0 1 0 0] concat neg exch neg exch translate}%
\set_std_bb
\box\tmp_box
\transspecial{grestore}%
\kern-\tmp_dim_a
\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
% ---
\def\yflip{% to be followed by a box
\hbox\bgroup
\def\after_setbox{%
\tmp_dim_a\ht\tmp_box \tmp_dim_b\dp\tmp_box
\tmp_dim_c\tmp_dim_a \advance\tmp_dim_c\tmp_dim_b
\tmp_dim_c.5\tmp_dim_c
% prepare to flipping:
\setbox\tmp_box\vbox{%
\kern\tmp_dim_c\box\tmp_box\kern-\tmp_dim_c}%
% flip:
\advance\tmp_dim_c-\tmp_dim_b
\setbox\tmp_box\hbox{%
\transspecial{gsave currentpoint currentpoint translate
[1 0 0 -1 0 0] concat neg exch neg exch translate}%
\lower\tmp_dim_c\box\tmp_box
\transspecial{grestore}}%
% restore dimensions of the flipped box:
\ht\tmp_box\tmp_dim_a \dp\tmp_box\tmp_dim_b
\set_std_bb
\box\tmp_box
\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}%
% ---
% save TeX registers:
\let\clip_wd\tmp_dim_a
\let\clip_ht\tmp_dim_b
\let\clip_dp\tmp_dim_c
% ---
\def\tracingclipcmyk{1 0 0 0}
\def\clip_fix_pos#1{\transspecial{%
currentpoint /clip_#1_y exch def /clip_#1_x exch def%
}}
\def\clip_use_pos#1{clip_#1_x clip_#1_y}
\def\clip_delta#1#2{#1 #2 3 -1 roll exch sub 3 1 roll sub exch}
%
\def\do_clip{\transspecial{%
newpath
\clip_use_pos{LL} moveto
\clip_delta{\clip_use_pos{UR}}{\clip_use_pos{UL}} rlineto
\clip_delta{\clip_use_pos{UR}}{\clip_use_pos{LR}} rlineto
\clip_delta{\clip_use_pos{LL}}{\clip_use_pos{LR}} rlineto
closepath
\ifx\tracingclip\unknown \else
gsave \tracingclipcmyk\space setcmykcolor fill grestore
\fi
clip newpath%
}}
%
\def\clip_use_dim#1{% #1 = wd, ht, or dp
\ifdim\csname clip_#1\endcsname=\maxdimen \csname#1\endcsname\tmp_box
\else \csname clip_#1\endcsname\fi
}
%
\def\clip_fix_dim#1#2{%
\edef\clip_use_dim_param{#2}%
\ifx\clip_use_dim_param\empty #1\maxdimen\else
\ifx\clip_use_dim_param\space #1\maxdimen\else \sumto#1#2\relax \fi\fi
}
%
\def\clipbox#1#2#3{% desired height, width and depth to be followed by a box
\hbox\bgroup
\clip_fix_dim\clip_wd{#1}%
\clip_fix_dim\clip_ht{#2}%
\clip_fix_dim\clip_dp{#3}%
\clipbox_
}
\def\clipbox_{%
\def\after_setbox{%
\setbox\tmp_box\hbox{\box\tmp_box}%
\clip_wd\clip_use_dim{wd}% freeze dimen
\clip_ht\clip_use_dim{ht}% ditto
\clip_dp\clip_use_dim{dp}% ditto
\transspecial{gsave}%
\rlap{%
\lower \clip_dp \vbox{%
\hbox to\clip_wd{\clip_fix_pos{UL}\hss\clip_fix_pos{UR}}
\kern\clip_ht \kern\clip_dp \nointerlineskip
\hbox to\clip_wd{\clip_fix_pos{LL}\hss\clip_fix_pos{LR}}
\do_clip
}%
}%
\wd\tmp_box=\clip_wd \ht\tmp_box=\clip_ht \dp\tmp_box=\clip_dp
\set_std_bb \box\tmp_box \transspecial{grestore}\egroup}%
\afterassignment\jump_setbox\setbox\tmp_box =
}
% ---------------------------------------------------------------------------
% ``floating point arithmetic'' (excerpted from T. Rokicki):
% r y
%
% ^
% |
% |
% |
% |
% |
% 0--------------> t x
%
% save TeX registers:
\let\dim_x\tmp_dim_a % horizontal size after scaling
\let\dim_y\tmp_dim_b % vertical size after scaling
\let\dim_t\tmp_dim_c % horizontal size before scaling
\let\dim_r\tmp_dim_d % vertical size before scaling
%\tmp_dim % register for arithmetic manipulation (already declared)
% ---
\def\resize
% dimen registers:
#1% y make y such that y/r=x/t
#2% r
#3% x
#4% t
% We have a sticky problem here: TeX doesn't do floating point arithmetic!
% Our goal is to compute y = rx/t. The following loop does this reasonably
% fast, with an error of at most about 16 sp (about 1/4000 pt).
{%
% save parameters to the internal variables:
\dim_r#2\relax \dim_x#3\relax \dim_t#4\relax
\tmp_dim=\dim_r \divide\tmp_dim\dim_t
\dim_y=\dim_x \multiply\dim_y\tmp_dim
\multiply\tmp_dim\dim_t \advance\dim_r-\tmp_dim
\tmp_dim=\dim_x
\loop \advance\dim_r\dim_r \divide\tmp_dim 2
\ifnum\tmp_dim>0
\ifnum\dim_r<\dim_t\else
\advance\dim_r-\dim_t \advance\dim_y\tmp_dim \fi
\repeat
% assign result:
#1\dim_y\relax
}
% ---------------------------------------------------------------------------
% ``fixed point arithmetic'' -- fractions and trigometry, inspired by mf.web:
%
% save TeX registers:
\let\fracint\tmp_dim
\let\fracfrac\tmp_count_a
\let\fracprod\tmp_count_b
\def\fracpowlimit{30}%
\def\fracone{1073741824}% = 2^\fracpowlimit
% ---
\def\fracproduct#1#2{% #1 = fraction * 2^\fracpowlimit, #2 = integer
% result: macro \fracresult = floor(#1 * #2 / 2^\fracpowlimit + 1/2)
% expanding to the count equivalent of the respective dimen
\begingroup
\fracfrac#1\relax % \fracfrac <= 2^30
\fracint#2\relax % \fracint <= \maxdimen
\ifdim\fracint<0pt \fracint-\fracint\def\fracsign{-}\else\def\fracsign{}\fi
\ifnum\fracone=\fracfrac \fracprod\fracint \else
\advance\fracfrac\fracone % \fracfrac < 2^31
\fracprod\fracone % if \fracprod were dimen, this would yield error
\divide\fracprod2 % \fracprod = 2^29 (representation of 1/2)
\loop
\ifodd\fracfrac \advance \fracprod\fracint \fi
\divide\fracprod2 \divide\fracfrac2
\ifnum \fracfrac>1 \repeat
\fi
\xdef\fracresult{\fracsign\number\fracprod}%
\endgroup
}
% ---
\newdimen\onedegree
\onedegree16pt % this must be consistent with the table below
% save TeX registers:
\let\trigangle\tmp_dim_a
\let\trigxpart\tmp_dim_b
\let\trigypart\tmp_dim_c
\let\trigxtmp\tmp_dim
\let\trigiter\tmp_count_a
\def\triglimit{28}%
% ---
\def\trigvalarg#1{\csname argscaled:\number#1\endcsname}
\def\trigvalcos#1{\csname cosscaled:\number#1\endcsname}
\def\trigvalsin#1{\csname sinscaled:\number#1\endcsname}
\def\defspectrig#1#2#3#4{%
% #1 -- ordering number (index)
% #2 -- angle in degrees * \onedegree expressed in sp; alpha=#1*2^(-20)
% #3 -- floor(cosd(alpha)*2^30+1/2) (30=\fracpowlimit)
% #4 -- floor(sind(alpha)*2^30+1/2)
\expandafter\def\csname argscaled:#1\endcsname{#2}%
\expandafter\def\csname cosscaled:#1\endcsname{#3}%
\expandafter\def\csname sinscaled:#1\endcsname{#4}%
}
\defspectrig{1}{62914560}{536870912}{929887697} % alpha=60
\defspectrig{2}{47185920}{759250125}{759250125} % 45
\defspectrig{3}{31457280}{929887697}{536870912} % 30
\defspectrig{4}{16777216}{1032146887}{295963357} % 2^4
\defspectrig{5}{8388608}{1063292242}{149435979} % 2^3
\defspectrig{6}{4194304}{1071126243}{74900443} % 2^2
\defspectrig{7}{2097152}{1073087729}{37473049} % 2^1
\defspectrig{8}{1048576}{1073578288}{18739379} % 2^0
\defspectrig{9}{524288}{1073700939}{9370046} % 2^-1
\defspectrig{10}{262144}{1073731603}{4685068} % 2^-2
\defspectrig{11}{131072}{1073739269}{2342539} % 2^-3
\defspectrig{12}{65536}{1073741185}{1171270} % 2^-4
\defspectrig{13}{32768}{1073741664}{585635} % 2^-5
\defspectrig{14}{16384}{1073741784}{292818} % 2^-6
\defspectrig{15}{8192}{1073741814}{146409} % 2^-7
\defspectrig{16}{4096}{1073741822}{73204} % 2^-8
\defspectrig{17}{2048}{1073741823}{36602} % 2^-9
\defspectrig{18}{1024}{1073741824}{18301} % 2^-10
\defspectrig{19}{512}{1073741824}{9151} % 2^-11
\defspectrig{20}{256}{1073741824}{4575} % 2^-12
\defspectrig{21}{128}{1073741824}{2288} % 2^-13
\defspectrig{22}{64}{1073741824}{1144} % 2^-14
\defspectrig{23}{32}{1073741824}{572} % 2^-15
\defspectrig{24}{16}{1073741824}{286} % 2^-16
\defspectrig{25}{8}{1073741824}{143} % 2^-17
\defspectrig{26}{4}{1073741824}{71} % 2^-18
\defspectrig{27}{2}{1073741824}{36} % 2^-19
\defspectrig{28}{1}{1073741824}{18} % 2^-20
% ---
\def\trigcompute#1#2#3{%
% #1 angle in degrees (a)
% #2 initial xpart (x)
% #3 initial ypart (y)
% result: (x',y')=(x,y) rotated a; the pair of macros
% \trigxresult and \trigyresult contain x' and y', respectively;
% both expand to the count equivalent of the respective dimen
\begingroup
\trigangle#1\onedegree \trigxpart#2\relax \trigypart#3\relax
\loop \ifdim\trigangle<0sp \advance\trigangle360\onedegree \repeat
\loop \ifdim\trigangle>360\onedegree \advance\trigangle-360\onedegree \repeat
\ifdim\trigangle=360\onedegree \trigangle0sp \fi
\ifdim\trigangle<180\onedegree \else % >=
\trigxpart-\trigxpart \trigypart-\trigypart
\advance\trigangle-180\onedegree
\fi
\ifdim\trigangle<90\onedegree \else % >=
\trigxtmp\trigxpart \trigxpart-\trigypart \trigypart\trigxtmp
\advance\trigangle-90\onedegree
\fi
\trigiter1\relax
\loop
\ifnum\trigvalarg\trigiter>\trigangle \else % <=
\advance\trigangle-\trigvalarg\trigiter sp
\trigxtmp\trigxpart
% x=x*cos[i]-y*sin[i] :
\fracproduct{\trigvalcos\trigiter}\trigxpart
\trigxpart\fracresult sp
\fracproduct{\trigvalsin\trigiter}\trigypart
\advance\trigxpart-\fracresult sp
% y=y*cos[i]+x*sin[i] :
\fracproduct{\trigvalcos\trigiter}\trigypart
\trigypart\fracresult sp
\fracproduct{\trigvalsin\trigiter}\trigxtmp
\advance\trigypart\fracresult sp
\fi
\advance\trigiter1
\ifnum\trigangle>0 \repeat
% result in dimen registers: \trigxpart and \trigypart
\xdef\trigxresult{\number\trigxpart}%
\xdef\trigyresult{\number\trigypart}%
\endgroup
}
% ---------------------------------------------------------------------------
% restore original catcodes:
\catcode`\@\transatcode
\catcode`\_\transundcode
% ---------------------------------------------------------------------------
\endinput