From 873660d1a83ece926fe7206288dda9c36b349c1b Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Thu, 12 Jan 2006 23:46:03 +0000 Subject: generic 1 git-svn-id: svn://tug.org/texlive/trunk@613 c570f23f-e606-0410-a88d-b1316a301751 --- .../texmf-dist/tex/generic/pdf-trans/pdf-trans.tex | 1460 ++++++++++++++++++++ 1 file changed, 1460 insertions(+) create mode 100644 Master/texmf-dist/tex/generic/pdf-trans/pdf-trans.tex (limited to 'Master/texmf-dist/tex/generic/pdf-trans') 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 macro swallows 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{% + \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{% + \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{}\boxslanty{} is NOT equivalent to \boxslantxy{}{} + +\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{% + \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{% -> + \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{% + \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{% + \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 -- cgit v1.2.3