summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/generic/pdf-trans
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2006-01-12 23:46:03 +0000
committerKarl Berry <karl@freefriends.org>2006-01-12 23:46:03 +0000
commit873660d1a83ece926fe7206288dda9c36b349c1b (patch)
treea48f77125c309a355b5d0eb58d6b24446abe9d62 /Master/texmf-dist/tex/generic/pdf-trans
parent2939242967231097459df0fc3150fabc2f639111 (diff)
generic 1
git-svn-id: svn://tug.org/texlive/trunk@613 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/generic/pdf-trans')
-rw-r--r--Master/texmf-dist/tex/generic/pdf-trans/pdf-trans.tex1460
1 files changed, 1460 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/pdf-trans/pdf-trans.tex b/Master/texmf-dist/tex/generic/pdf-trans/pdf-trans.tex
new file mode 100644
index 00000000000..cca00c7d7d1
--- /dev/null
+++ b/Master/texmf-dist/tex/generic/pdf-trans/pdf-trans.tex
@@ -0,0 +1,1460 @@
+%%% A set of macros for various transformations of TeX boxes.
+%%% (bases on plain and pdfeTeX primitives)
+%
+% Version: 2.2
+% Author: Pawe/l Jackowski (P.Jackowski@gust.org.pl)
+% Public Domain
+%
+% The macro provides a bunch of TeX box transformations. It was initially
+% inspired by trans.tex (BOP, bop@bop.com.pl), remade to work with pdfeTeX.
+% This standalone code gathers parts of pdfeplay macro package.
+%
+% Files:
+% pdf-trans.tex
+% example.tex
+%
+% History:
+% 05.2004, v1.0b
+% * first embryo
+% 11.2004, v1.0
+% * modified, released
+% 08.2005, v2.0
+% * general rework;
+% - fraction-based trigonometry
+% - pdfliteral dimensions rounding
+% - some other small changes
+% 09.2005, v2.1
+% * some adds;
+% - \setbpround <0..4> sets pdf dimen rounding precision
+% - \boxgobble <box> macro swallows <box> and returns \hbox{}
+% 10.2005, v2.2
+% * rework;
+% - \bboxtrans vs \cboxtrans switches
+% - \boxext* stuff; yet another scaling approach
+%
+
+\def\starttrans{%
+ \xdef\endtrans{%
+ \catcode`\noexpand\@=\the\catcode`\@
+ \catcode`\noexpand\:=\the\catcode`\:
+ }\catcode`\@=11 \catcode`\:=11 }
+
+\starttrans
+
+% Each transformation macro defined below expands to (h)box. Thus, can be used
+% whenever (h)box can. Each must be followed by the box that is to be
+% transformed. This scheme allows to cumulate transformations, that are applied
+% from right to left. For instance,
+% \boxrotatebb{30}\boxscale{300}\hbox{Aqq}
+% first enlarges boxed `Aqq' three times, then rotates it 30 degrees. Thanks
+% to \transboxcheck trick (see below), \copy and \box can be used as well as
+% \hbox, \vbox, \vtop. However, the consequence is that the transformed box
+% can't be void (\boxinfo definition is an exception here). \transbox register
+% contains the box being transformed.
+
+\newbox\transbox
+
+% Whenever we perform relative dimension scaling, a number provided as a macro
+% parameter is divided by \transfactor. Default is percentage (ie. 75 -> 0.75).
+% One may notice, that we often perform the same operation (ie. division)
+% several times instead of defining \transfactor as a float-like string. In
+% example, if there are two dimens, \X and \Y, and both are to be scaled by
+% 0.23, we always say `\numexpr\X*23/\transfactor' and
+% `\numexpr\Y*23/\transfactor' instead of 0.23\X 0.23\Y. In some cases it gives
+% significant preciseness improvement.
+
+\newcount\transfactor
+\transfactor=100
+
+% plus some internal variables
+
+\newdimen\trans:dim
+\newdimen\trans:dim:a
+\newdimen\trans:dim:b
+\newdimen\trans:dim:c
+\newdimen\trans:dim:d
+
+\newcount\trans:count
+
+\def\trans:def{}
+\def\trans:def:a{}
+\def\trans:def:b{}
+\def\trans:def:c{}
+\def\trans:def:d{}
+
+% Here the main trick starts. Each macro usually expands to \hbox\bgroup...,
+% defines \transboxtodo procedure, assigns the following box, then performs
+% \transboxtodo and ends with \egroup. If the box being transformed is generic
+% `\hbox{', TeX finishes the assignment just after opening `{', while the box being
+% assigned (\transbox) is still void. Thus, we check \ifvoid\transbox, and if
+% so, we put \transboxtodo on \aftergroup stack to let TeX finish box
+% assignment. Obviously it crashes, if one tries to transform a void box.
+% So, if you see 'Missing } inserted' error, you are probably trying to transform
+% a void box. You can use \boxinfo to check the situation.
+
+\def\transboxini{%
+ \afterassignment\transboxcheck
+ \setbox\transbox}
+
+\def\transboxcheck{%
+ \ifvoid\transbox
+ \expandafter\aftergroup
+ \fi\transboxtodo}
+
+% When some macro changes box dimensions directly (i.e. \ht\transbox=0pt),
+% we may need to be sure that transformed box behaves like \hbox.
+
+\def\transhboxini{%
+ \afterassignment\transhboxcheck
+ \setbox\transbox}
+
+\def\transhboxcheck{%
+ \ifvoid\transbox
+ \expandafter\aftergroup\expandafter\transhboxwrap
+ \else
+ \expandafter\transhboxwrap
+ \fi}
+
+\def\transhboxwrap{%
+ \ifvbox\transbox
+ \setbox\transbox\hbox{\box\transbox}%
+ \fi
+ \transboxtodo}
+
+\long\def\transboxdef#1\transboxend{%
+ \bgroup\def\transboxtodo{#1\egroup}\transboxini}
+
+\long\def\transhboxdef#1\transboxend{%
+ \bgroup\def\transboxtodo{#1\egroup}\transhboxini}
+
+% Sometimes we need to keep bounding box untouched and transform box content
+% only (or vice versa). Each transformation that affects both the bounding box
+% (via resizing \ht|\wd|\dp) and the box content itself (via \pdfliteral)
+% checks \iftransbbox and \iftranscbox flags. No practical reasons to affect
+% \boxrotatebb by this feature, however.
+
+\newif\iftransbbox
+\newif\iftranscbox
+\transbboxtrue
+\transcboxtrue
+
+\long\def\transbcboxdef#1\transbboxdef#2\transcboxdef#3\transboxend{%
+ \bgroup\edef\transboxtodo{%
+ \unexpanded{#1}%
+ \iftransbbox\unexpanded{#2}\fi
+ \iftranscbox\unexpanded{#3}\else\box\transbox\fi
+ \egroup}\transhboxini}
+
+\def\bboxtranson{%
+ \hbox\bgroup\transbboxtrue
+ \def\transboxtodo{\box\transbox\egroup}\transboxini}
+
+\def\bboxtransoff{%
+ \hbox\bgroup\transbboxfalse
+ \def\transboxtodo{\box\transbox\egroup}\transboxini}
+
+\def\cboxtranson{%
+ \hbox\bgroup\transcboxtrue
+ \def\transboxtodo{\box\transbox\egroup}\transboxini}
+
+\def\cboxtransoff{%
+ \hbox\bgroup\transcboxfalse
+ \def\transboxtodo{\box\transbox\egroup}\transboxini}
+
+\long\def\bboxtrans#1{\iftranscbox\cboxtransoff#1\cboxtranson\else#1\fi}
+\long\def\cboxtrans#1{\iftransbbox\bboxtransoff#1\bboxtranson\else#1\fi}
+
+% User-defined operation on \transbox. Remember, that \transboxcheck assumes
+% initially void \transbox, so #1 should contain something like \box\tranbox,
+% \unvbox\tranbox, \setbox\transbox\voidb@x etc.
+
+\def\hboxtrans{\hbox\transboxdef}
+\def\vboxtrans{\vbox\transboxdef}
+\def\vtoptrans{\vtop\transboxdef}
+\let\boxtrans\hboxtrans
+
+% flip
+
+\def\boxflipx{%
+ \hbox\transboxdef
+ \savebp\trans:def\wd\transbox
+ \pdfliteral{q -1 0 0 1 \trans:def\space 0 cm}%
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxflipy{%
+ \hbox\transboxdef
+ \savebp\trans:def\wd\transbox
+ \pdfliteral{q 1 0 0 -1 0 \tobp{\ht\transbox-\dp\transbox} cm}%
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxflipxy{%
+ \hbox\transboxdef
+ \savebp\trans:def\wd\transbox
+ \pdfliteral{q -1 0 0 -1 \trans:def\space \tobp{\ht\transbox-\dp\transbox} cm}%
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\let\boxflip\boxflipxy
+
+% \boxflipy plus \ht\transbox <-> \dp\transbox exchange
+
+\def\boxflipbase{%
+ \hbox\transbcboxdef
+ \transbboxdef
+ \trans:dim=\ht\transbox
+ \ht\transbox=\dp\transbox
+ \dp\transbox=\trans:dim
+ \transcboxdef
+ \pdfliteral{q 1 0 0 -1 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+% scale by factor
+
+\def\boxscalexy#1#2{%
+ \hbox\transbcboxdef
+ \transbboxdef
+ \wd\transbox=\dimexpr\wd\transbox*(#1)/\transfactor\relax
+ \ht\transbox=\dimexpr\ht\transbox*(#2)/\transfactor\relax
+ \dp\transbox=\dimexpr\dp\transbox*(#2)/\transfactor\relax
+ \transcboxdef
+ \edef\trans:def:a{\fdivide{#1}\transfactor}%
+ \edef\trans:def:b{\fdivide{#2}\transfactor}%
+ \pdfliteral{q \trans:def:a\space 0 0 \trans:def:b\space 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxscale#1{\boxscalexy{#1}{#1}}
+\def\boxscalex#1{\boxscalexy{#1}\transfactor}
+\def\boxscaley#1{\boxscalexy\transfactor{#1}}
+\let\boxscalez\boxscale
+
+% scale to dimen
+
+\def\boxscaleto#1#2#3#4{%
+ \hbox\transbcboxdef
+ \trans:dim:a=\dimexpr#1\relax
+ \trans:dim:b=\dimexpr#2\relax
+ \trans:dim:c=\dimexpr#3\relax
+ \trans:dim:d=\dimexpr#4\relax
+ \transbboxdef
+ \wd\transbox=\dimexpr\wd\transbox*\trans:dim:a/\trans:dim:b\relax
+ \ht\transbox=\dimexpr\ht\transbox*\trans:dim:c/\trans:dim:d\relax
+ \dp\transbox=\dimexpr\dp\transbox*\trans:dim:c/\trans:dim:d\relax
+ \transcboxdef
+ \edef\trans:def:a{\fdivide\trans:dim:a\trans:dim:b}%
+ \edef\trans:def:b{\fdivide\trans:dim:c\trans:dim:d}%
+ \pdfliteral{q \trans:def:a\space 0 0 \trans:def:b\space 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxscalexyto#1#2{\boxscaleto{#1}{\wd\transbox}{#2}{\ht\transbox+\dp\transbox}}
+\def\boxscalexto#1{\boxscaleto{#1}{\wd\transbox}{1sp}{1sp}}
+\def\boxscaleyto#1{\boxscaleto{1sp}{1sp}{#1}{\ht\transbox+\dp\transbox}}
+\def\boxscalehtto#1{\boxscaleto{1sp}{1sp}{#1}{\ht\transbox}}
+\def\boxscaledpto#1{\boxscaleto{1sp}{1sp}{#1}{\dp\transbox}}
+\let\boxscalewdto\boxscalexto
+
+% scale \wd|\ht|\dp to dimen, others uniformly
+
+\def\boxuniscaleto#1#2{%
+ \hbox\transbcboxdef
+ \trans:dim:a=\dimexpr#1\relax
+ \trans:dim:b=\dimexpr#2\relax
+ \transbboxdef
+ \wd\transbox=\dimexpr\wd\transbox*\trans:dim:a/\trans:dim:b\relax
+ \ht\transbox=\dimexpr\ht\transbox*\trans:dim:a/\trans:dim:b\relax
+ \dp\transbox=\dimexpr\dp\transbox*\trans:dim:a/\trans:dim:b\relax
+ \transcboxdef
+ \edef\trans:def:a{\fdivide\trans:dim:a\trans:dim:b}%
+ \pdfliteral{q \trans:def:a\space 0 0 \trans:def:a\space 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxuniscalexto#1{\boxuniscaleto{#1}{\wd\transbox}}
+\def\boxuniscaleyto#1{\boxuniscaleto{#1}{\ht\transbox+\dp\transbox}}
+\def\boxuniscalehtto#1{\boxuniscaleto{#1}{\ht\transbox}}
+\def\boxuniscaledpto#1{\boxuniscaleto{#1}{\dp\transbox}}
+\let\boxuniscalewdto\boxuniscalexto
+
+% yet another scaling approach; extend \wd|\ht|\dp do dimen, scale accordingly
+
+\def\boxextscaleto#1#2#3{%
+ \hbox\transbcboxdef
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\dimexpr#1\relax
+ \trans:dim:c=\dimexpr\ht\transbox+\dp\transbox\relax
+ \trans:dim:d=\dimexpr#2+#3\relax
+ \trans:dim=\dp\transbox
+ \transbboxdef
+ \wd\transbox=\trans:dim:b
+ \ht\transbox=\dimexpr#2\relax
+ \dp\transbox=\dimexpr#3\relax
+ \transcboxdef
+ \edef\trans:def:a{\fdivide\trans:dim:b\trans:dim:a}%
+ \edef\trans:def:b{\fdivide\trans:dim:d\trans:dim:c}%
+ \savebp\trans:def:c\dimexpr-\dp\transbox+(\dp\transbox+\ht\transbox)*\trans:dim/\trans:dim:c\relax
+ \pdfliteral{q \trans:def:a\space 0 0 \trans:def:b\space 0 \trans:def:c\space cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxextscale#1#2#3{\boxextscaleto{\wd\transbox+#1}{\ht\transbox+#2}{\dp\transbox+#3}}
+
+% resizing; the result may be different for hboxes and vboxes;
+% since we have \boxextscaleto plus \iftransbbox and \iftranscbox flags,
+% the following two macros are obsolete by now
+
+\def\boxresizeto#1#2#3{%
+ \hbox\transboxdef
+ \ifx\relax#1\relax\else \wd\transbox=\dimexpr#1\relax \fi
+ \ifx\relax#2\relax\else \ht\transbox=\dimexpr#2\relax \fi
+ \ifx\relax#3\relax\else \dp\transbox=\dimexpr#3\relax \fi
+ \box\transbox
+ \transboxend}
+
+\def\boxresize#1#2#3{%
+ \hbox\transboxdef
+ \ifx\relax#1\relax\else \wd\transbox=\dimexpr\wd\transbox+#1\relax \fi
+ \ifx\relax#2\relax\else \ht\transbox=\dimexpr\ht\transbox+#2\relax \fi
+ \ifx\relax#3\relax\else \dp\transbox=\dimexpr\dp\transbox+#3\relax \fi
+ \box\transbox
+ \transboxend}
+
+% extents; to keep things consistent for negative extents, \dp\transbox becomes 0pt
+
+\def\boxextents#1#2#3#4{% <left> <right> <top> <bottom>
+ \hbox\transboxdef
+ \kern\dimexpr#1\relax
+ \vbox{%
+ \kern\dimexpr#3\relax
+ \box\transbox
+ \kern\dimexpr#4\relax
+ }%
+ \kern\dimexpr#2\relax
+ \transboxend}
+
+\def\boxhextent#1#2{\boxextents{#1}{#2}\z@\z@}
+\def\boxvextent#1#2{\boxextents\z@\z@{#1}{#2}}
+\def\boxextent#1{\boxextents{#1}{#1}{#1}{#1}}
+
+% and yet another approach; append extents to box content
+
+\def\boxexts#1#2#3#4{% <left> <right> <top> <bottom>
+ \hbox\transboxdef
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\dimexpr\trans:dim:a+#1+#2\relax
+ \trans:dim:c=\dimexpr\ht\transbox+\dp\transbox\relax
+ \trans:dim:d=\dimexpr\trans:dim:c+#3+#4\relax
+ \edef\trans:def:a{\fdivide\trans:dim:b\trans:dim:a}%
+ \edef\trans:def:b{\fdivide\trans:dim:d\trans:dim:c}%
+ \savebp\trans:def:c-\dimexpr#1\relax
+ \savebp\trans:def:d\dimexpr-#4+(#3+#4)*\dp\transbox/\trans:dim:c\relax
+ \pdfliteral{q \trans:def:a\space 0 0 \trans:def:b\space
+ \trans:def:c\space \trans:def:d\space cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxhext#1#2{\boxexts{#1}{#2}\z@\z@}
+\def\boxvext#1#2{\boxexts\z@\z@{#1}{#2}}
+\def\boxext#1{\boxexts{#1}{#1}{#1}{#1}}
+
+% raw translation
+
+\def\boxtranslate#1#2{%
+ \hbox\transboxdef
+ \pdfliteral{q 1 0 0 1 \tobp{#1} \tobp{#2} cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+% heuristic rotation by 90 degrees (left and right variants)
+
+\def\boxrevolveleft{%
+ \hbox\transbcboxdef
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\ht\transbox
+ \transbboxdef
+ \wd\transbox=\dimexpr\ht\transbox+\dp\transbox\relax
+ \ht\transbox=\trans:dim:a
+ \dp\transbox=\z@
+ \transcboxdef
+ \pdfliteral{q 0 1 -1 0 \tobp{\trans:dim:b} 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxrevolveright{%
+ \hbox\transbcboxdef
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\dp\transbox
+ \transbboxdef
+ \wd\transbox=\dimexpr\ht\transbox+\dp\transbox\relax
+ \ht\transbox=\trans:dim:a
+ \dp\transbox=\z@
+ \transcboxdef
+ \pdfliteral{q 0 -1 1 0 \tobp{\trans:dim:b} \tobp{\trans:dim:a} cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\let\boxrevolvepi\boxflipxy
+
+% clockwise rotation relative to base point
+
+\def\boxrotate#1{%
+ \hbox\transboxdef
+ \floatsincos\trans:def:a\trans:def:b{#1}%
+ \pdfliteral{q \trans:def:b\space
+ \negbp\trans:def:a\space % clockwise
+ \trans:def:a\space % vs anti clockwise
+ \trans:def:b\space
+ 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+% clockwise rotation relative to base point translated (x,y)
+
+\def\boxrotatexy#1#2#3{%
+ \hbox\transboxdef
+ \floatsincos\trans:def:a\trans:def:b{#1}%
+ \savebp\trans:def:c\dimexpr#2\relax
+ \savebp\trans:def:d\dimexpr#3\relax
+ \pdfliteral{q \trans:def:b\space
+ \negbp\trans:def:a\space
+ \trans:def:a\space
+ \trans:def:b\space
+ \trans:def:c\space
+ \trans:def:d\space cm
+ 1 0 0 1 \negbp\trans:def:c\space
+ \negbp\trans:def:d\space cm}% ?
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\def\boxrotatec#1{\boxrotatexy{#1}{\wd\transbox/2}{(\ht\transbox-\dp\transbox)/2}}
+\def\boxrotatell#1{\boxrotatexy{#1}\z@{-\dp\transbox}}
+\def\boxrotatelr#1{\boxrotatexy{#1}{\wd\transbox}{-\dp\transbox}}
+\def\boxrotateul#1{\boxrotatexy{#1}\z@{\ht\transbox}}
+\def\boxrotateur#1{\boxrotatexy{#1}{\wd\transbox}{\ht\transbox}}
+
+% bbox-wise rotation (left and right variants)
+
+\newif\ifbboxright
+
+\def\box:rotate:bb#1{%
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\ht\transbox
+ \trans:dim:c=\dp\transbox
+ \trans:dim:d=\dimexpr\ht\transbox+\dp\transbox\relax
+ \trans:count=\reducetrigangle{#1}\fractperiod\relax
+ \ifcase\fracttrigfourth\trans:count\relax
+ \fr@ct:sin:cos:i\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr\fr@ct:mul\trans:dim:a\trans:def:b
+ +\fr@ct:mul\trans:dim:d\trans:def:a\relax
+ \ht\transbox=\dimexpr\fr@ct:mul\trans:dim:b\trans:def:b\relax
+ \dp\transbox=\dimexpr\fr@ct:mul\trans:dim:a\trans:def:a
+ +\fr@ct:mul\trans:dim:c\trans:def:b\relax
+ \savebp\trans:def:c=\dimexpr\fr@ct:mul\trans:dim:c\trans:def:a\relax
+ \or
+ \fr@ct:sin:cos:ii\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr-\fr@ct:mul\trans:dim:a\trans:def:b
+ +\fr@ct:mul\trans:dim:d\trans:def:a\relax
+ \ht\transbox=\dimexpr-\fr@ct:mul\trans:dim:c\trans:def:b\relax
+ \dp\transbox=\dimexpr-\fr@ct:mul\trans:dim:b\trans:def:b
+ +\fr@ct:mul\trans:dim:a\trans:def:a\relax
+ \savebp\trans:def:c=\dimexpr-\fr@ct:mul\trans:dim:a\trans:def:b
+ +\fr@ct:mul\trans:dim:c\trans:def:a\relax
+ \or
+ \fr@ct:sin:cos:iii\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr-\fr@ct:mul\trans:dim:a\trans:def:b
+ -\fr@ct:mul\trans:dim:d\trans:def:a\relax
+ \ht\transbox=\dimexpr-\fr@ct:mul\trans:dim:a\trans:def:a
+ -\fr@ct:mul\trans:dim:c\trans:def:b\relax
+ \dp\transbox=\dimexpr-\fr@ct:mul\trans:dim:b\trans:def:b\relax
+ \savebp\trans:def:c=\dimexpr-\fr@ct:mul\trans:dim:a\trans:def:b
+ -\fr@ct:mul\trans:dim:b\trans:def:a\relax
+ \or
+ \fr@ct:sin:cos:iv\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr\fr@ct:mul\trans:dim:a\trans:def:b
+ -\fr@ct:mul\trans:dim:d\trans:def:a\relax
+ \ht\transbox=\dimexpr\fr@ct:mul\trans:dim:b\trans:def:b
+ -\fr@ct:mul\trans:dim:a\trans:def:a\relax
+ \dp\transbox=\dimexpr\fr@ct:mul\trans:dim:c\trans:def:b\relax
+ \savebp\trans:def:c=\dimexpr-\fr@ct:mul\trans:dim:b\trans:def:a\relax
+ \fi
+ \ifbboxright
+ \trans:dim:d=\dimexpr\fr@ct:mul\trans:dim:a\trans:def:a\relax
+ \ht\transbox=\dimexpr\ht\transbox+\trans:dim:d\relax
+ \dp\transbox=\dimexpr\dp\transbox-\trans:dim:d\relax
+ \savebp\trans:def:d\trans:dim:d
+ \else
+ \def\trans:def:d{0}%
+ \fi
+ \edef\trans:def:a{\fr@ct:div\trans:def:a}%
+ \edef\trans:def:b{\fr@ct:div\trans:def:b}%
+ \pdfliteral{q \trans:def:b\space
+ \negbp\trans:def:a\space
+ \trans:def:a\space
+ \trans:def:b\space
+ \trans:def:c\space
+ \trans:def:d\space cm}%
+ \savebp\trans:def=\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}}
+
+\def\boxrotatebbl#1{%
+ \hbox\transboxdef
+ \bboxrightfalse
+ \box:rotate:bb{#1}%
+ \transboxend}
+
+\def\boxrotatebbr#1{%
+ \hbox\transboxdef
+ \bboxrighttrue
+ \box:rotate:bb{#1}%
+ \transboxend}
+
+% the default is left variant
+
+\bboxrightfalse
+
+\def\boxrotatebb#1{%
+ \hbox\transboxdef
+ \box:rotate:bb{#1}%
+ \transboxend}
+
+% slanting; \boxslantx{<x>}\boxslanty{<y>} is NOT equivalent to \boxslantxy{<x>}{<y>}
+
+\def\boxslant#1#2{%
+ \hbox\transboxdef
+ \fractsincos\trans:def:a\trans:def:b{#1}%
+ \fractsincos\trans:def:c\trans:def:d{#2}%
+ \edef\trans:def:a{\fdivide\trans:def:a\trans:def:b}%
+ \edef\trans:def:c{\fdivide\trans:def:c\trans:def:d}%
+ \pdfliteral{q 1 \trans:def:c\space \trans:def:a\space 1 0 0 cm}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+\let\boxslantxy\boxslant
+\def\boxslantx#1{\boxslant{#1}{0}} % not \z@!!
+\def\boxslanty#1{\boxslant{0}{#1}}
+
+% bounding box wise slanting (left and right variant)
+
+\def\box:slant:bb#1#2{%
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\ht\transbox
+ \trans:dim:c=\dp\transbox
+ \trans:dim:d=\dimexpr\ht\transbox+\dp\transbox\relax
+ \trans:count=\reducetrigangle{#1}{2*\fractfourth}\relax
+ \ifcase\fracttrigfourth\trans:count\relax
+ \fr@ct:sin:cos:i\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr\trans:dim:a+\trans:dim:d*\trans:def:a/\trans:def:b\relax
+ \savebp\trans:def:c=\dimexpr\trans:dim:c*\trans:def:a/\trans:def:b\relax
+ \or
+ \fr@ct:sin:cos:ii\trans:def:a\trans:def:b\trans:count
+ \wd\transbox=\dimexpr\trans:dim:a-\trans:dim:d*\trans:def:a/\trans:def:b\relax
+ \savebp\trans:def:c=\dimexpr-\trans:dim:b*\trans:def:a/\trans:def:b\relax
+ \fi
+ \edef\trans:def{\fdivide\trans:def:a\trans:def:b}%
+ \trans:count=\reducetrigangle{#2}{2*\fractfourth}\relax
+ \ifcase\fracttrigfourth\trans:count\relax
+ \fr@ct:sin:cos:i\trans:def:a\trans:def:b\trans:count
+ \ht\transbox=\dimexpr\trans:dim:b+\trans:dim:a*\trans:def:a/\trans:def:b\relax
+ \or
+ \fr@ct:sin:cos:ii\trans:def:a\trans:def:b\trans:count
+ \dp\transbox=\dimexpr\trans:dim:c-\trans:dim:a*\trans:def:a/\trans:def:b\relax
+ \fi
+ \ifbboxright
+ \trans:dim:d=\dimexpr-\trans:dim:a*\trans:def:a/\trans:def:b\relax
+ \ht\transbox=\dimexpr\ht\transbox+\trans:dim:d\relax
+ \dp\transbox=\dimexpr\dp\transbox-\trans:dim:d\relax
+ \savebp\trans:def:d\trans:dim:d
+ \else
+ \def\trans:def:d{0}%
+ \fi
+ \edef\trans:def:a{\fdivide\trans:def:a\trans:def:b}%
+ \pdfliteral{q 1
+ \trans:def:a\space
+ \trans:def\space
+ 1
+ \trans:def:c\space
+ \trans:def:d\space cm}%
+ \savebp\trans:def=\wd\transbox
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}}
+
+\def\boxslantbbl#1#2{%
+ \hbox\transboxdef
+ \bboxrightfalse
+ \box:slant:bb{#1}{#2}%
+ \transboxend}
+
+\def\boxslantbbr#1#2{%
+ \hbox\transboxdef
+ \bboxrighttrue
+ \box:slant:bb{#1}{#2}%
+ \transboxend}
+
+\def\boxslantbb#1#2{%
+ \hbox\transboxdef
+ \box:slant:bb{#1}{#2}%
+ \transboxend}
+
+\def\boxslantbbx#1{\boxslantbb{#1}{0}} % not \z@!!
+\def\boxslantbby#1{\boxslantbb{0}{#1}}
+\def\boxslantbbry#1{\boxslantbbr{0}{#1}}
+\def\boxslantbbly#1{\boxslantbbl{0}{#1}}
+
+% on-fly conversion to XObject (\pdfxform)
+
+\def\boxxform{%
+ \hbox\transboxdef
+ \immediate\pdfxform\transbox
+ \pdfrefxform\pdflastxform
+ \transboxend}
+
+\def\boxxformspec#1\boxxform{%
+ \hbox\transboxdef
+ \immediate\pdfxform#1\transbox
+ \pdfrefxform\pdflastxform
+ \transboxend}
+
+% Some previous version of pdftrans had \boxclip defined as \boxpath{}{W n}. This didn't
+% work properly since \boxpath restores the graphic state before placing the box itself
+% (see below).
+
+% clipping
+
+\def\boxclip{%
+ \hbox\transboxdef
+ \savebp\trans:def\wd\transbox
+ \pdfliteral{q 0 \tobp{-\dp\transbox} \trans:def\space
+ \tobp{\ht\transbox+\dp\transbox} re W n}%
+ \box\transbox
+ \pdfliteral{Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+% up and down
+
+\def\boxraise#1{%
+ \hbox\transboxdef
+ \raise\dimexpr#1\relax\box\transbox
+ \transboxend}
+
+\def\boxlower#1{%
+ \hbox\transboxdef
+ \lower\dimexpr#1\relax\box\transbox
+ \transboxend}
+
+\let\boxbaselineup\boxlower
+\let\boxbaselinedown\boxraise
+
+\def\boxbaselineat#1{% baseline at #1 of the total box vdim
+ \hbox\transboxdef
+ \lower\dimexpr(\ht\transbox+\dp\transbox)*(#1)/\transfactor-\dp\transbox\relax
+ \box\transbox
+ \transboxend}
+
+\def\boxmoveleft#1{%
+ \vbox\transboxdef
+ \moveleft\dimexpr#1\relax\box\transbox
+ \transboxend}
+
+\def\boxmoveright#1{%
+ \vbox\transboxdef
+ \moveright\dimexpr#1\relax\box\transbox
+ \transboxend}
+
+% rule-like spec of the box size (risky hack)
+
+\def\b@x:rule#1#2#{%
+ #1\transboxdef
+ \setbox0\hbox{\vrule width\wd\transbox height\ht\transbox depth\dp\transbox #2}%
+ \wd\transbox=\wd0
+ \ht\transbox=\ht0
+ \dp\transbox=\dp0
+ \box\transbox
+ \transboxend#1}
+
+\def\hboxr{\b@x:rule\hbox}
+\def\vboxr{\b@x:rule\vbox}
+\def\vtopr{\b@x:rule\vtop}
+\let\boxr\hboxr
+
+% reboxing; restore box natural dimensions (without shrink or stretch).
+
+\def\revbox{%
+ \vbox\transboxdef
+ \unvbox\transbox
+ \transboxend}
+
+\def\revtop{%
+ \vtop\transboxdef
+ \unvbox\transbox
+ \transboxend}
+
+\def\rehbox{%
+ \hbox\transboxdef
+ \unhbox\transbox
+ \transboxend}
+
+% just wrap
+
+\def\hboxwrap{%
+ \hbox\transboxdef
+ \box\transbox
+ \transboxend}
+
+\def\vboxwrap{%
+ \vbox\transboxdef
+ \box\transbox
+ \transboxend}
+
+\def\vtopwrap{%
+ \vtop\transboxdef
+ \box\transbox
+ \transboxend}
+
+% show boxes
+
+\def\boxshow#1#2#3{%
+ \hbox\transboxdef
+ \savebp\trans:def:a\wd\transbox
+ \savebp\trans:def:b\dimexpr\ht\transbox+\dp\transbox\relax
+ \savebp\trans:def:c\dp\transbox
+ \box\transbox
+ \pdfliteral{%
+ q #1
+ 1 0 0 1 \negbp\trans:def:a\space 0 cm
+ 0 \negbp\trans:def:c\space \trans:def:a\space \trans:def:b\space re S
+ #2
+ 0 0 m
+ \trans:def:a\space 0 l S #3 Q}%
+ \transboxend}
+
+\def\boxsh{\boxshow{0 0 1 RG}{0 0 .8 RG [2 2]1 d}{}}
+
+% box painted according to graphic state parameters (ie. on layer).
+
+\def\boxgs#1#2{%
+ \hbox\transboxdef
+ \pdfliteral{q #1}%
+ \savebp\trans:def\wd\transbox
+ \box\transbox
+ \pdfliteral{#2 Q 1 0 0 1 \trans:def\space 0 cm}%
+ \transboxend}
+
+% markers around the box
+
+\def\boxmarkers#1#2#3{%
+ \hbox\transboxdef
+ \copy\transbox
+ \trans:dim:a=\dimexpr#1\relax
+ \trans:dim:b=\dimexpr#2\relax
+ \pdfliteral{q #3}%
+ \savebp\trans:def-\dp\transbox
+ \box:markers:h
+ \savebp\trans:def\ht\transbox
+ \box:markers:h
+ \savebp\trans:def-\wd\transbox
+ \box:markers:v
+ \savebp\trans:def\z@
+ \box:markers:v
+ \pdfliteral{S Q}%
+ \setbox\transbox\box\voidb@x
+ \transboxend}
+
+\def\box:markers:h{%
+ \savebp\trans:def:a\trans:dim:a
+ \savebp\trans:def:b\trans:dim:b
+ \pdfliteral{%
+ \trans:def:a\space\trans:def\space m \trans:def:b\space\trans:def\space l}%
+ \savebp\trans:def:a\dimexpr-\wd\transbox-\trans:dim:a\relax
+ \savebp\trans:def:b\dimexpr-\wd\transbox-\trans:dim:b\relax
+ \pdfliteral{%
+ \trans:def:a\space\trans:def\space m \trans:def:b\space\trans:def\space l}}
+
+\def\box:markers:v{%
+ \savebp\trans:def:a\dimexpr-\dp\transbox-\trans:dim:a\relax
+ \savebp\trans:def:b\dimexpr-\dp\transbox-\trans:dim:b\relax
+ \pdfliteral{%
+ \trans:def\space \trans:def:a\space m \trans:def\space \trans:def:b\space l}%
+ \savebp\trans:def:a\dimexpr\ht\transbox+\trans:dim:a\relax
+ \savebp\trans:def:b\dimexpr\ht\transbox+\trans:dim:b\relax
+ \pdfliteral{%
+ \trans:def\space \trans:def:a\space m \trans:def\space \trans:def:b\space l}}
+
+% for sake of compatibility...
+
+\def\boxm#1#2{\boxmarkers{#1}{#2}{}}
+\let\boxmarks\boxmarkers
+
+% simple phantom
+
+\def\boxphantom{%
+ \hbox\transboxdef
+ \hbox to\wd\transbox
+ {\vrule width\z@ height\ht\transbox depth\dp\transbox\hss}%
+ \transboxend}
+
+% simple smash
+
+\def\boxsmash{%
+ \hbox\transhboxdef
+ \wd\transbox=\z@
+ \ht\transbox=\z@
+ \dp\transbox=\z@
+ \box\transbox
+ \transboxend}
+
+\def\hboxsmash{%
+ \hbox\transhboxdef
+ \wd\transbox=\z@
+ \box\transbox
+ \transboxend}
+
+\def\vboxsmash{%
+ \vbox\transhboxdef
+ \ht\transbox=\z@
+ \dp\transbox=\z@
+ \box\transbox
+ \transboxend}
+
+\def\boxgobble{%
+ \hbox\transboxdef
+% \global\setbox\transbox=\box\voidb@x
+ \transboxend}
+
+% say something about the following box (this one can be followed void box)
+
+\def\box:about#1{%
+ \hbox\bgroup
+ \def\transboxtodo{%
+ \trans:dim:a=\wd\transbox
+ \trans:dim:b=\ht\transbox
+ \trans:dim:c=\dp\transbox
+ \box\transbox
+ \hbox to\z@{\hss
+ \hbox to\trans:dim:a{\hss
+ \lower\trans:dim:c\vbox to\z@{\vss
+ \vbox to\dimexpr\trans:dim:b+\trans:dim:c{\vss\tt
+ #1\vbox{\vskip1ex
+ \halign{\hskip1ex plus 1fil####&####\hskip1ex plus 1fil\cr
+ \trans:def\span\cr
+ wd & \the\trans:dim:a\cr
+ ht & \the\trans:dim:b\cr
+ dp & \the\trans:dim:c\cr}%
+ \vskip1ex
+ }%
+ \vss}%
+ }%
+ \hss}%
+ }%
+ \egroup}\def\trans:def{}\def\trans:def:a{}\box:@bout}
+
+\def\box:@bout#1{%
+ \ifcase
+ \ifx#1\hbox 0 \else
+ \ifx#1\vbox 1 \else
+ \ifx#1\vtop 2 \else
+ \ifx#1\box 3 \else
+ \ifx#1\copy 4 \else 5 \fi\fi\fi\fi\fi
+ \edef\trans:def{\trans:def\string\hbox}\expandafter\transboxini\or
+ \edef\trans:def{\trans:def\string\vbox}\expandafter\transboxini\or
+ \edef\trans:def{\trans:def\string\vtop}\expandafter\transboxini\or
+ \edef\trans:def{\trans:def\string\box}\expandafter\boxabout:register\or
+ \edef\trans:def{\trans:def\string\copy}\expandafter\boxabout:register\or
+ \ifx#1\trans:def:a\errmessage{`#1' is not a box}\fi\let\trans:def:a#1% endless loop otherwise
+ \edef\trans:def{\trans:def\string#1->}\expandafter\expandafter\expandafter\box:@bout\fi
+ #1}
+
+\def\boxabout:register#1{%
+ \let\trans:def:a#1%
+ \afterassignment\boxabout:r@gister\trans:count}
+
+\def\boxabout:r@gister{%
+ \edef\trans:def{\trans:def\the\trans:count\space
+ (\ifvoid\trans:count void\else
+ \ifhbox\trans:count hbox\else
+ \ifvbox\trans:count vbox\fi\fi\fi)}%
+ \afterassignment\transboxtodo
+ \setbox\transbox\trans:def:a\trans:count}
+
+\def\boxinfo{\box:about{\boxpath{.3 w 0 G 0 0 .3 0 k}{B}}}
+\def\boxabout#1{\box:about{\boxgs{#1}{}}}
+
+% paint box path as a background of the box
+
+\def\boxpath#1#2{%
+ \hbox\transboxdef
+ \savebp\trans:def:a\wd\transbox
+ \savebp\trans:def:b\dimexpr\ht\transbox+\dp\transbox\relax
+ \savebp\trans:def:c\dp\transbox
+ \pdfliteral{q #1
+ 0
+ \negbp\trans:def:c\space
+ \trans:def:a\space
+ \trans:def:b\space re #2 Q}%
+ \box\transbox
+ \transboxend}
+
+\def\boxroundpath#1#2#3{%
+ \hbox\transboxdef
+ \savebp\trans:def:a\wd\transbox
+ \savebp\trans:def:b\ht\transbox
+ \savebp\trans:def:c\dp\transbox
+ \trans:dim:d=\dimexpr#1\relax
+ \savebp\trans:def:d\trans:dim:d
+ \pdfliteral{q #2}%
+ \pdfliteral{0 \trans:def:d\space m}%
+ \savebp\trans:def\dimexpr\ht\transbox-\trans:dim:d \relax
+ \pdfliteral{%
+ 0 \trans:def\space l 0 \trans:def:b\space \trans:def:d\space \trans:def:b\space y}%
+ \savebp\trans:def\dimexpr\wd\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def\space \trans:def:b\space l}%
+ \savebp\trans:def\dimexpr\ht\transbox-\trans:dim:d \relax
+ \pdfliteral{%
+ \trans:def:a\space \trans:def:b\space \trans:def:a\space \trans:def\space y}%
+ \savebp\trans:def\dimexpr\dp\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def:a\space \negbp\trans:def\space l}%
+ \savebp\trans:def\dimexpr\wd\transbox-\trans:dim:d \relax
+ \pdfliteral{%
+ \trans:def:a\space \negbp\trans:def:c\space \trans:def\space \negbp\trans:def:c\space y
+ \trans:def:d\space \negbp\trans:def:c\space l}%
+ \savebp\trans:def\dimexpr\dp\transbox-\trans:dim:d \relax
+ \pdfliteral{%
+ 0 \negbp\trans:def:c\space 0 \negbp\trans:def\space y 0 \trans:def:d\space l}%
+ \pdfliteral{h #3 Q}%
+ \box\transbox
+ \transboxend}
+
+\def\boxedgypath#1#2#3{%
+ \hbox\transboxdef
+ \savebp\trans:def:a\wd\transbox
+ \savebp\trans:def:b\ht\transbox
+ \savebp\trans:def:c\dp\transbox
+ \trans:dim:d=\dimexpr#1\relax
+ \savebp\trans:def:d\trans:dim:d
+ \pdfliteral{q #2}%
+ \pdfliteral{0 \trans:def:d\space m}%
+ \savebp\trans:def\dimexpr\ht\transbox-\trans:dim:d \relax
+ \pdfliteral{0 \trans:def\space l \trans:def:d\space \trans:def:b\space l}%
+ \savebp\trans:def\dimexpr\wd\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def\space \trans:def:b\space l}%
+ \savebp\trans:def\dimexpr\ht\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def:a\space \trans:def\space l}%
+ \savebp\trans:def\dimexpr\dp\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def:a\space \negbp\trans:def\space l}%
+ \savebp\trans:def\dimexpr\wd\transbox-\trans:dim:d \relax
+ \pdfliteral{\trans:def\space \negbp\trans:def:c\space l
+ \trans:def:d\space \negbp\trans:def:c\space l}%
+ \savebp\trans:def\dimexpr\dp\transbox-\trans:dim:d \relax
+ \pdfliteral{0 \negbp\trans:def\space l 0 \trans:def:d\space l}%
+ \pdfliteral{h #3 Q}%
+ \box\transbox
+ \transboxend}
+
+% obsolete
+
+\let\boxsquarepath\boxedgypath
+
+%%% ARITHMETIC
+
+% some shortcuts
+
+\def\expandnumberafter#1#2{\expandafter#1\expandafter{\number#2}}
+
+\def\expandtwonumbersafter#1#2#3{%
+ \expandafter#1\expandafter
+ {\number#2\expandafter}\expandafter
+ {\number#3}}
+
+\def\expandthreenumbersafter#1#2#3#4{%
+ \expandafter#1\expandafter
+ {\number#2\expandafter}\expandafter
+ {\number#3\expandafter}\expandafter
+ {\number#4}}
+
+\def\expandnumexprafter#1#2{\expandafter#1\expandafter{\number\numexpr#2}}
+
+\def\expandtwonumexprafter#1#2#3{%
+ \expandafter#1\expandafter
+ {\number\numexpr#2\expandafter}\expandafter
+ {\number\numexpr#3}}
+
+\def\expandthreenumexprafter#1#2#3#4{%
+ \expandafter#1\expandafter
+ {\number\numexpr#2\expandafter}\expandafter
+ {\number\numexpr#3\expandafter}\expandafter
+ {\number\numexpr#4}}
+
+\def\expanddimexprafter#1#2{\expandafter#1\expandafter{\the\dimexpr#2}}
+
+% Whenever we write a dimen into PDF code, we need to convert it from TeX units
+% to Postscript big points. We handle that as precise as possible, using the
+% fact that eTeX handles 64bit numbers as temporary results of expressions such
+% as A*B/C. A is dimension in points, B is \pt:f@ctor and C is \bp:f@ctor. Note
+% that factor 100pt/100bp is more precise than 1pt/1bp or 10pt/10bp, but NOT
+% less precise than 1000pt/1000bp. Thus, 100 is the optimum.
+
+\edef\pt:f@ctor{\number\dimexpr100pt} % NOT \dimexpr100\p@!
+\edef\bp:f@ctor{\number\dimexpr100bp} %
+
+\begingroup
+ \catcode`\P=12
+ \catcode`\T=12
+ \lccode`P=`p
+ \lccode`T=`t
+ \lowercase{\gdef\with@ut:pt#1PT{#1}}
+\endgroup
+
+\def\withoutpt{\expandafter\with@ut:pt}
+\def\big:p@ints#1#2{#1\the\dimexpr#2*\pt:f@ctor/\bp:f@ctor\relax}
+\def\negbp#1{\withoutpt\the\dimexpr-#1pt\relax}
+
+% If we assume that \pdfdecimaldigits never exceeds possible range (0..4),
+% we can implement PDF dimens rounding in the following way:
+
+\def\t@bp{\big:p@ints\withoutpt}
+
+\def\roundbp#1{%
+ \expandafter\expandafter
+ \csname r@und:bp:\romannumeral\pdfdecimaldigits\expandafter\endcsname
+ \expandafter\with@ut:pt\the\dimexpr(#1)*\pt:f@ctor/\bp:f@ctor\relax0000\relax}
+
+\def\r@und:bp: #1.#2#3\relax{\number\numexpr#1#2/10\relax}
+\def\r@und:bp:i #1.#2#3#4\relax{\roundbponce{#1}{#2#3}\relax}
+\def\r@und:bp:ii #1.#2#3#4#5\relax{\roundbponce{#1}{#2#3#4}\relax}
+\def\r@und:bp:iii #1.#2#3#4#5#6\relax{\roundbponce{#1}{#2#3#4#5}\relax}
+\def\r@und:bp:iv #1.#2#3#4#5#6#7\relax{\roundbponce{#1}{#2#3#4#5#6}\relax}
+
+% To speed-up things one may say
+
+\def\setbpround#1{% 0..4
+ \edef\roundbp##1{%
+ \unexpanded{\expandafter\expandafter\expandafter}\expandafter\noexpand
+ \csname r@und:bp:\romannumeral#1\endcsname
+ \unexpanded{\expandafter\with@ut:pt\the}%
+ \dimexpr(##1)*\unexpanded{\pt:f@ctor/\bp:f@ctor}\relax0000\relax}}
+
+\def\roundbponce#1#2{%
+ \number\numexpr#1\ifnum#1<0-\else+\fi
+ (\m@ne+\expandafter\r@und:bp:once\number\numexpr1#2/10\relax}
+
+\def\r@und:bp:once#1#2\relax{#1)\relax\ifnum#2>0.#2\fi}
+
+\def\savebp#1{%
+ \def\s@vebp{%
+ \edef#1{\tobp{\bp:dim@n}}}%
+ \afterassignment\s@vebp\bp:dim@n}
+
+\newdimen\bp:dim@n
+
+\def\disablebpround{\let\tobp\t@bp}
+\def\enablebpround{\let\tobp\roundbp}
+
+%\disablebpround
+\enablebpround
+
+% Lets play with basic arithmetic operations. To make things consistent, each
+% function expands to \numexpr|\dimexpr, even if could be easily expanded to
+% digits. This approach ensures predictable behaviour whenever a \function is
+% followed by \expandafter or \relax. To avoid evaluating the same expressions
+% twice or more, each function expands its parameters before performing the
+% final operation. This scheme makes temporary macros reusable.
+
+% absolute value
+
+\def\absint{\expandnumexprafter\absoluteint}
+\def\absoluteint#1{\numexpr\ifnum#1<\z@-\fi#1}
+\def\absdim{\expanddimexprafter\absolutedim}
+\def\absolutedim#1{\dimexpr\ifdim#1<\z@-\fi#1}
+
+% Various approaches to integer division:
+% floor(a/b) -- the largest integer LOWER than a/b
+% ceil(a/b) -- the lowest integer HIGHER than a/b
+% int(a/b) -- the integer part (floor for a/b>=0 and ceil for a/b<0)
+% nint(a/b) -- rounding (the nearest integer)
+
+\def\expanddivisionafter#1#2#3{%
+ \expandnumexprafter#1{#2/#3}{#2}{#3}}
+
+\def\divfloor{\expandtwonumexprafter\dividefloor}
+\def\dividefloor{\expanddivisionafter\divide:fl@@r}
+\def\divide:fl@@r#1#2#3{%
+ \numexpr#1%
+ \ifcase\ifnum#2<0 \ifnum#3<0 1 \else 0 \fi
+ \else \ifnum#3<0 1 \else 0 \fi \fi
+ \ifnum\numexpr#1*#3>#2-\@ne\fi\or
+ \ifnum\numexpr#1*#3<#2-\@ne\fi\fi}
+
+\def\divceil{\expandtwonumexprafter\divideceil}
+\def\divideceil{\expanddivisionafter\divide:c@il}
+\def\divide:c@il#1#2#3{%
+ \numexpr#1%
+ \ifcase\ifnum#2<0 \ifnum#3<0 1 \else 0 \fi
+ \else \ifnum#3<0 1 \else 0 \fi \fi
+ \ifnum\numexpr#1*#3<#2+\@ne\fi\or
+ \ifnum\numexpr#1*#3>#2+\@ne\fi\fi}
+
+\def\divint{\expandtwonumexprafter\divideint}
+\def\divideint{\expanddivisionafter\divide:int}
+\def\divide:int#1#2#3{%
+ \numexpr#1%
+ \ifcase\ifnum#2<0 \ifnum#3<0 3 \else 1 \fi
+ \else \ifnum#3<0 2 \else 0 \fi \fi
+ \ifnum\numexpr#1*#3>#2-\@ne\fi\or
+ \ifnum\numexpr#1*#3<#2+\@ne\fi\or
+ \ifnum\numexpr#1*#3>#2+\@ne\fi\or
+ \ifnum\numexpr#1*#3<#2-\@ne\fi\fi}
+
+\def\divnint{\expandtwonumexprafter\dividenint}
+\def\dividenint#1#2{\numexpr#1/#2}
+
+% modulo
+
+\def\mod{\expandtwonumexprafter\modulo}
+\def\modulo{\expanddivisionafter\do:m@dulo}
+\def\do:m@dulo#1#2#3{\numexpr#2-#3*\divide:fl@@r{#1}{#2}{#3}\relax}
+
+% If we don't divide (by) negative numbers, the following macros works
+% a bit faster.
+
+\def\divfloorpos{\expandtwonumexprafter\dividefloorpos}
+\def\dividefloorpos{\expanddivisionafter\divide:fl@@r:pos}
+\def\divide:fl@@r:pos#1#2#3{\numexpr#1\ifnum\numexpr#1*#3>#2-\@ne\fi}
+
+\def\divceilpos{\expandtwonumexprafter\divideceilpos}
+\def\divideceilpos{\expanddivisionafter\divide:c@il:pos}
+\def\divide:c@il:pos#1#2#3{\numexpr#1\ifnum\numexpr#1*#3<#2+\@ne\fi}
+
+\let\divintpos\divfloorpos
+\let\divideintegerpos\dividefloorpos
+
+\def\modpos{\expandtwonumexprafter\modulopos}
+\def\modulopos{\expanddivisionafter\modulo:p@s}
+\def\modulo:p@s#1#2#3{\numexpr#2-#3*\divide:fl@@r:pos{#1}{#2}{#3}\relax}
+
+% One sticky problem in all the division related macros above... We always
+% check if some rounding is present using the formula
+% \divident/\divisor*\divisor <=> \divident
+% It works fine if one say (2\maxdimen)/\maxdimen, but arithmetic overflow
+% occurs for (2\maxdimen)/(\maxdimen+1) or (2\maxdimen)/2. Thus, can be used
+% for reasonably small numbers.
+
+% Having an integer division we can round float-like strings
+
+\def\floatround#1{\divnint{\dimexpr#1pt}\p@}
+\def\floatfloor#1{\divfloor{\dimexpr#1pt}\p@}
+\def\floatceil#1{\divceil{\dimexpr#1pt}\p@}
+\def\floatint#1{\divint{\dimexpr#1pt}\p@}
+\def\floatnint#1{\divnint{\dimexpr#1pt}\p@}
+
+% Now lets implement integer by integer division with float-like result. The
+% following approach is quite fast and precise enough for most practical
+% purposes, but resulting floats are limited to \maxdimen expressed in points
+% (16383.99998).
+
+\def\fdivide{\expandtwonumexprafter\flo@t:divide}
+\def\flo@t:divide#1#2{\withoutpt\the\dimexpr\numexpr#1*\p@/#2\relax sp\relax}
+
+% Note, that \fdivide produce a float-like string that can be used as a factor
+% preceding a dimen (i.e \hsize=\fdivide{2}{7}\hsize). For sake of preciseness
+% however, internally we always use \dimexpr\hsize*2/7 in such cases (see
+% pdftrans.tex).
+
+% Yet another approach to division with float-like result. \divfloat produce a
+% float-like string with fixed precision. There is still numeric overflow risk
+% mentioned above. No preciseness and result limitation, however.
+
+\def\divfloat{% <divisor> <divident> <preciseness>
+ \expandthreenumexprafter\dividefloat}
+
+\def\dividefloat#1#2#3{%
+ \expandnumberafter\divide:flo@t % \absoluteint returns \numexpr
+ {\absoluteint{\divideint{#1}{#2}}}{#1}{#2}{#3}}
+
+\def\divide:flo@t#1#2#3{% it is not enough to check the sign of #1
+ \ifnum#2<0 \ifnum#3>0 -\fi\else
+ \ifnum#2>0 \ifnum#3<0 -\fi\fi\fi
+ #1.\expandthreenumexprafter\divide:fl@@t
+ {#1}{\absoluteint{#2}}{\absoluteint{#3}}}
+
+\def\divide:fl@@t#1#2#3{%
+ \expandnumexprafter\divide:flo@t:modulo{#2-#1*#3}{#3}}
+
+\def\divide:flo@t:modulo#1#2{%
+ \ifnum#1<214748365
+ \expandtwonumbersafter\divide:flo@t:result{#10}{#2\expandafter}%
+ \else
+ \expandtwonumexprafter\divide:flo@t:modulo{#1/2}{#2/2\expandafter}%
+ \fi}
+
+\def\divide:flo@t:result#1#2#3{%
+ \ifnum#3>1
+ \expandtwonumexprafter\divide:flo@t:repeat
+ {#3-\@ne}{\dividefloorpos{#1}{#2}\expandafter}%
+ \else
+ \number\divide:flo@t:last{#1}{#2}\relax
+ \expandafter\gobbletwo
+ \fi{#1}{#2}}
+
+\def\divide:flo@t:repeat#1#2#3#4{%
+ #2\expandnumexprafter\divide:flo@t:modulo{#3-#2*#4}{#4}{#1}}
+
+\newcount\floatprecision
+\floatprecision=6
+
+\def\roundlast{\let\divide:flo@t:last\dividenint}
+\def\floorlast{\let\divide:flo@t:last\divideint}
+\roundlast
+
+% One may say \let\tobp\roundfixedbp to enable alternative (fixed) rounding.
+
+\def\tofixedbp#1{\divfloat{\dimexpr#1}\b@\floatprecision}
+\def\roundfixedbp#1{\divfloat{\dimexpr#1}\b@\pdfdecimaldigits}
+
+% And now comes a real challenge -- trigonometry. In the first approach, values
+% of trigonometric functions were predefined for angles of range 0..90. Real
+% angle values were not supported. Now things are a bit slower, but much more
+% precise. In particular, we handle real angles values. The trigonometry
+% implementation is excerpted from trans.tex and originally was inspired by
+% mf.web. The clue is that any angle value (not only integer) can be
+% represented as a series of predefined ,,coins''. Trigonometric functions can
+% be then recursively calculated as follows:
+%
+% sin(a+b) = sin(a)cos(b) + sin(b)cos(a)
+% cos(a+b) = cos(a)cos(b) - sin(a)sin(b)
+%
+% Big thanks for BOP team for encourage.
+
+\def\fractdegree#1{\numexpr16*\dimexpr#1pt} % 2^20sp = 16pt = 1degree
+\edef\fractfactor{\number\numexpr\maxdimen+\@ne} % 2^30
+\edef\fractfourth{\number\numexpr90*\fractdegree\@ne} % 90 degrees
+\edef\fractperiod{\number\numexpr4*\fractfourth} % 360 degrees
+
+\def\reducefractangle#1{% reduce to 0..#2
+ \expandnumberafter\reduce:fr@ct:angle{\fractdegree{#1}}}
+
+\def\reduce:fr@ct:angle#1#2{%
+ \ifnum#1<0
+ \numexpr#2-\modpos{-#1}{#2}\relax
+ \else
+ \modpos{#1}{#2}%
+ \fi}
+
+% For sake of backward compatibility we leave a hook for integer angles
+
+\def\reduceintangle#1#2{%
+ \expandtwonumexprafter\reduce:int:@ngle{#1}{#2/\fractdegree\@ne}}
+
+\def\reduce:int:@ngle#1#2{\fractdegree{\reduce:fr@ct:angle{#1}{#2}}}
+
+\def\enablefractangle{\let\reducetrigangle\reducefractangle}
+\def\disablefractangle{\let\reducetrigangle\reduceintangle}
+\enablefractangle
+
+% some macro shortcuts
+
+\def\fracttrigfourth#1{% returns 0..3 (quarter)
+ \dividefloorpos{#1}\fractfourth}
+
+\def\fr@ct:mul#1#2{#1*#2/\fractfactor}
+\def\fr@ct:div#1{\fdivide{#1}\fractfactor}
+
+% constant fractions
+
+\def\fr@ct:angle#1{\ifcase\numexpr#1\relax
+62914560\or % 60
+47185920\or % 45
+31457280\or % 30
+16777216\or % 2^4
+ 8388608\or % 2^3
+ 4194304\or % 2^2
+ 2097152\or % 2^1
+ 1048576\or % 2^0
+ 524288\or % 2^-1
+ 262144\or % 2^-2
+ 131072\or % 2^-3
+ 65536\or % 2^-4
+ 32768\or % 2^-5
+ 16384\or % 2^-6
+ 8192\or % 2^-7
+ 4096\or % 2^-8
+ 2048\or % 2^-9
+ 1024\or % 2^-10
+ 512\or % 2^-11
+ 256\or % 2^-12
+ 128\or % 2^-13
+ 64\or % 2^-14
+ 32\or % 2^-15
+ 16\or % 2^-16
+ 8\or % 2^-17
+ 4\or % 2^-18
+ 2\or % 2^-19
+ 1\fi}% 2^-20
+
+\def\fr@ct:sin#1{\ifcase\numexpr#1\relax
+929887697\or % 60
+759250125\or % 45
+536870912\or % 30
+295963357\or % 2^4
+149435979\or % 2^3
+ 74900443\or % 2^2
+ 37473049\or % 2^1
+ 18739379\or % 2^0
+ 9370046\or % 2^-1
+ 4685068\or % 2^-2
+ 2342539\or % 2^-3
+ 1171270\or % 2^-4
+ 585635\or % 2^-5
+ 292818\or % 2^-6
+ 146409\or % 2^-7
+ 73204\or % 2^-8
+ 36602\or % 2^-9
+ 18301\or % 2^-10
+ 9151\or % 2^-11
+ 4575\or % 2^-12
+ 2288\or % 2^-13
+ 1144\or % 2^-14
+ 572\or % 2^-15
+ 286\or % 2^-16
+ 143\or % 2^-17
+ 71\or % 2^-18
+ 36\or % 2^-19
+ 18\fi}% 2^-20
+
+\def\fr@ct:cos#1{\ifcase\numexpr#1\relax
+ 536870912\or % 60
+ 759250125\or % 45
+ 929887697\or % 30
+1032146887\or % 2^4
+1063292242\or % 2^3
+1071126243\or % 2^2
+1073087729\or % 2^1
+1073578288\or % 2^0
+1073700939\or % 2^-1
+1073731603\or % 2^-2
+1073739269\or % 2^-3
+1073741185\or % 2^-4
+1073741664\or % 2^-5
+1073741784\or % 2^-6
+1073741814\or % 2^-7
+1073741822\or % 2^-8
+1073741823\or % 2^-9
+1073741824\or % 2^-10
+1073741824\or % 2^-11
+1073741824\or % 2^-12
+1073741824\or % 2^-13
+1073741824\or % 2^-14
+1073741824\or % 2^-15
+1073741824\or % 2^-16
+1073741824\or % 2^-17
+1073741824\or % 2^-18
+1073741824\or % 2^-19
+1073741824\fi}% 2^-20
+
+% I like \ifcase...\or...\fi acting as arrays because of its readability.
+% For sake of speed however, we say:
+
+\trans:count=0
+\loop
+ \expandafter\edef\csname
+ fractangle:\the\trans:count\endcsname{\fr@ct:angle\trans:count}
+ \expandafter\edef\csname
+ fractsinvalue:\the\trans:count\endcsname{\fr@ct:sin\trans:count}
+ \expandafter\edef\csname
+ fractcosvalue:\the\trans:count\endcsname{\fr@ct:cos\trans:count}
+ \ifnum\trans:count<27
+ \advance\trans:count by1
+\repeat
+\def\fr@ct:angle#1{\csname fractangle:\number#1\endcsname}
+\def\fr@ct:sin#1{\csname fractsinvalue:\number#1\endcsname}
+\def\fr@ct:cos#1{\csname fractcosvalue:\number#1\endcsname}
+
+% Here the main loop starts.
+
+\def\fracttrig#1{% <angle> -> <sine> <cosine> <command>
+ \expandnumexprafter\fr@ct:trig{\reducetrigangle{#1}\fractperiod}}
+
+\def\fr@ct:trig#1{%
+ \csname fr@ct:trig:\romannumeral\fracttrigfourth{#1}+\@ne\endcsname
+ {#1}}
+
+\def\fr@ct:trig:i#1#2#3{% <angle> <sine> <cosine>
+ \expandthreenumexprafter\fr@ct:trig:cont{#1}{#2}{#3}\z@}
+
+\def\fr@ct:trig:ii#1#2#3{%
+ \expandthreenumexprafter\fr@ct:trig:cont{#1-\fractfourth}{#3}{-#2}\z@}
+
+\def\fr@ct:trig:iii#1#2#3{%
+ \expandthreenumexprafter\fr@ct:trig:cont{#1-2*\fractfourth}{-#2}{-#3}\z@}
+
+\def\fr@ct:trig:iv#1#2#3{%
+ \expandthreenumexprafter\fr@ct:trig:cont{#1-3*\fractfourth}{-#3}{#2}\z@}
+
+\def\fr@ct:trig:cont#1#2#3#4{% <angle> <sine> <cosine> <index>
+ \ifcase
+ \ifnum#1>0 \ifnum#1<\fr@ct:angle{#4} 0 \else 1 \fi \else 2 \fi
+ \expandafter\fr@ct:trig:cont\expandafter
+ {\number#1\expandafter}\expandafter
+ {\number#2\expandafter}\expandafter
+ {\number#3\expandafter}\expandafter
+ {\number\numexpr#4+\@ne\expandafter}\or
+ \expandafter\fr@ct:trig:cont\expandafter
+ {\number\numexpr#1-\fr@ct:angle{#4}\expandafter}\expandafter
+ {\number\numexpr\fr@ct:mul{#2}{\fr@ct:cos{#4}}%
+ +\fr@ct:mul{#3}{\fr@ct:sin{#4}}\expandafter}\expandafter
+ {\number\numexpr\fr@ct:mul{#3}{\fr@ct:cos{#4}}%
+ -\fr@ct:mul{#2}{\fr@ct:sin{#4}}\expandafter}\expandafter
+ {\number\numexpr#4+\@ne\expandafter}\or
+ \fracttrigend{#2}{#3}\fi}
+
+% ...and finally, execute the next command with two first parameters being
+% scaled sine and cosine.
+
+\def\fracttrigend#1#2\fi#3{\fi#3{#1}{#2}}
+
+\def\fractsincos#1#2#3{\fracttrig{#3}\z@\fractfactor\fr@ct:sin:cos#1#2}
+\def\fr@ct:sin:cos#1#2#3#4{\def#3{#1}\def#4{#2}}
+
+% In pdftrans we use the following shortcuts
+
+\def\fr@ct:sin:cos:i#1#2#3{\fr@ct:trig:i{#3}\z@\fractfactor\fr@ct:sin:cos#1#2}
+\def\fr@ct:sin:cos:ii#1#2#3{\fr@ct:trig:ii{#3}\z@\fractfactor\fr@ct:sin:cos#1#2}
+\def\fr@ct:sin:cos:iii#1#2#3{\fr@ct:trig:iii{#3}\z@\fractfactor\fr@ct:sin:cos#1#2}
+\def\fr@ct:sin:cos:iv#1#2#3{\fr@ct:trig:iv{#3}\z@\fractfactor\fr@ct:sin:cos#1#2}
+
+\def\floatsincos#1#2#3{\fracttrig{#3}\z@\fractfactor\flo@t:sin:c@s#1#2}
+\def\flo@t:sin:c@s#1#2#3#4{%
+ \edef#3{\fr@ct:div{#1}}%
+ \edef#4{\fr@ct:div{#2}}}
+
+\endtrans
+\endinput