summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/tex-ps/trans.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/generic/tex-ps/trans.tex')
-rw-r--r--Master/texmf-dist/tex/generic/tex-ps/trans.tex653
1 files changed, 653 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/tex-ps/trans.tex b/Master/texmf-dist/tex/generic/tex-ps/trans.tex
new file mode 100644
index 00000000000..a3869832f6c
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/tex-ps/trans.tex
@@ -0,0 +1,653 @@
+% ---------------------------------------------------------------------------
+% 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
+