%D \module %D [ file=grph-trf, %D version=2006.08.26, % overhaul/split of 1997.03.31 core-fig %D title=\CONTEXT\ Graphic Macros, %D subtitle=Transformations, %D author=Hans Hagen, %D date=\currentdate, %D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] %C %C This module is part of the \CONTEXT\ macro||package and is %C therefore copyrighted by \PRAGMA. See mreadme.pdf for %C details. \writestatus{loading}{ConTeXt Graphic Macros / Transformations} \unprotect %D We probably use too many dimens as the width calculations can %D go away. Some of this is an inheritance of limited backends %D (some supported fractions, some 1000's, some dimentions) so %D we calculate all of them. Nowadays scaling is always available %D so we could simplify the code. On the other hand, we now get %D some extra values for free. %D %D We could move the calculations to \LUA\ and clean up this %D lot anyway. On the other hand, there is some danger of messing %D up so it has a real low priority. % local: \newdimen\d_grph_scale_x_size \newdimen\d_grph_scale_y_size \newdimen\d_grph_scale_x_offset \newdimen\d_grph_scale_y_offset \newdimen\d_grph_scale_h_size \newdimen\d_grph_scale_v_size \newconditional\c_grph_scale_done \newconditional\c_grph_scale_scaling_done \newdimen\d_grph_scale_wd \newdimen\d_grph_scale_ht \newdimen\d_grph_scale_dp % global \newdimen\d_grph_scale_used_x_size \newdimen\d_grph_scale_used_y_size \newcount\c_grph_scale_used_x_scale \newcount\c_grph_scale_used_y_scale \newdimen\d_grph_scale_outer_v_size % we cannot manipulate any global vsize ! % scratch: \let\m_grph_scale_temp \empty \let\m_grph_scale_temp_x\empty \let\m_grph_scale_temp_y\empty % public: \let\finalscaleboxxscale \!!plusone \let\finalscaleboxyscale \!!plusone \let\finalscaleboxwidth \!!zeropoint \let\finalscaleboxheight \!!zeropoint \let\finalscaleboxxfactor\!!hundred \let\finalscaleboxyfactor\!!hundred % we can let sx/sy win (first check) \installcorenamespace{scale} \installcorenamespace{scalegrid} \installcorenamespace{scalenorm} \installcommandhandler \??scale {scale} \??scale % we can have instances \setupscale [\c!sx=1, \c!sy=1, %\c!scale=, %\c!xscale=, %\c!yscale=, %\c!width=, %\c!height=, %\c!lines=, %\c!factor=, %\c!hfactor=, %\c!wfactor=, %\c!grid=, %\c!equalwidth=, %\c!equalheight=, \c!maxwidth=\scaleparameter\c!width, \c!maxheight=\scaleparameter\c!height] \unexpanded\def\scale{\dodoubleempty\grph_scale} % we could have: \freezeparameter\c!scale etc (less backtracking when used multiple) \def\grph_scale[#1][#2]% {\bgroup % this is quite common so we might make this a helper \ifsecondargument \edef\currentscale{#1}% \setupcurrentscale[#2]% \else\iffirstargument \doifassignmentelse{#1} {\let\currentscale\empty \setupcurrentscale[#1]} {\edef\currentscale{#1}}% \else \let\currentscale\empty \fi\fi % \dowithnextboxcs\grph_scale_finish\hbox} \def\grph_scale_finish {% todo: p_scale_ \edef\p_scale {\scaleparameter\c!scale }% \edef\p_xscale {\scaleparameter\c!xscale }% \edef\p_yscale {\scaleparameter\c!yscale }% \edef\p_width {\scaleparameter\c!width }% \edef\p_height {\scaleparameter\c!height }% \edef\p_depth {\scaleparameter\c!depth }% \edef\p_lines {\scaleparameter\c!lines }% \edef\p_factor {\scaleparameter\c!factor }% \edef\p_hfactor {\scaleparameter\c!hfactor }% \edef\p_wfactor {\scaleparameter\c!wfactor }% % \edef\p_grid {\scaleparameter\c!grid }% used once \edef\p_maxwidth {\scaleparameter\c!maxwidth }% \edef\p_maxheight {\scaleparameter\c!maxheight }% \edef\p_sx {\scaleparameter\c!sx }% \edef\p_sy {\scaleparameter\c!sy }% \edef\p_equalwidth {\scaleparameter\c!equalwidth }% \edef\p_equalheight{\scaleparameter\c!equalheight}% % \d_grph_scale_dp\dp\nextbox \ifx\p_depth\v!no \ifzeropt\d_grph_scale_dp \else \setbox\nextbox\hbox{\raise\d_grph_scale_dp\box\nextbox}% new \d_grph_scale_dp\dp\nextbox \fi \fi \d_grph_scale_wd\wd\nextbox \d_grph_scale_ht\ht\nextbox \d_grph_scale_dp\dp\nextbox % \global\let\finalscaleboxxscale \!!plusone \global\let\finalscaleboxyscale \!!plusone \xdef \finalscaleboxwidth {\the\d_grph_scale_wd}% \xdef \finalscaleboxheight{\the\d_grph_scale_ht}% \global\let\finalscaleboxxfactor\!!hundred \global\let\finalscaleboxyfactor\!!hundred % \forgetall \dontcomplain % \setfalse\c_grph_scale_done \grph_scale_calculate \ifconditional\c_grph_scale_done \grph_scale_apply \fi \grph_scale_position % \box\nextbox \egroup} \def\grph_scale_apply {\d_grph_scale_wd\finalscaleboxxscale\d_grph_scale_wd \d_grph_scale_ht\finalscaleboxyscale\d_grph_scale_ht \d_grph_scale_dp\finalscaleboxyscale\d_grph_scale_dp \setbox\nextbox\hbox {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale \smashedbox\nextbox \dostopscaling}% \wd\nextbox\d_grph_scale_wd \ht\nextbox\d_grph_scale_ht \dp\nextbox\d_grph_scale_dp} \def\m_grph_scale_stamp_c{11} \def\grph_scale_calculate {\ifdim\d_grph_scale_ht>\zeropoint \ifdim\d_grph_scale_wd>\zeropoint \edef\m_grph_scale_stamp_a{\p_scale\p_xscale\p_yscale\p_factor\p_wfactor\p_hfactor\p_lines\p_width\p_height}% \edef\m_grph_scale_stamp_b{\p_sx\p_sy}% \ifx\m_grph_scale_stamp_a\empty \ifx\m_grph_scale_stamp_b\m_grph_scale_stamp_c % no scaling, don't change this (previous attempts failed anyway) \insidefloattrue % trick \grph_scale_calculations_yes \else \grph_scale_check_sx_sy \grph_scale_calculations_nop \fi \else \ifx\m_grph_scale_stamp_b\empty % no need to check further \else \grph_scale_check_sx_sy \fi \grph_scale_calculations_yes \fi \fi \fi} \def\grph_scale_check_sx_sy {\ifdim\p_sx\onepoint=\onepoint\else\edef\p_width {\the\dimexpr\p_sx\d_grph_scale_wd}\fi \ifdim\p_sy\onepoint=\onepoint\else\edef\p_height{\the\dimexpr\p_sy\d_grph_scale_ht}\fi} \def\grph_scale_rounded#1% {\expandafter\expandafter\expandafter\grph_scale_rounded_indeed \expandafter\WITHOUTPT\the\dimexpr#1\points*100+32768sp\relax.\relax} \def\grph_scale_rounded_indeed#1.#2\relax{#1} \def\grph_scale_calculations_nop {\settrue\c_grph_scale_done \xdef\finalscaleboxwidth {\the\dimexpr\p_sx\d_grph_scale_wd\relax}% \xdef\finalscaleboxheight{\the\dimexpr\p_sy\d_grph_scale_ht\relax}% \glet\finalscaleboxxscale\p_sx \glet\finalscaleboxyscale\p_sy \ifx\finalscaleboxxscale\empty\let\finalscaleboxxscale\!!plusone\fi \ifx\finalscaleboxyscale\empty\let\finalscaleboxyscale\!!plusone\fi \xdef\finalscaleboxxfactor{\grph_scale_rounded\finalscaleboxxscale}% \xdef\finalscaleboxyfactor{\grph_scale_rounded\finalscaleboxyscale}} \def\grph_scale_calculations_yes {\settrue\c_grph_scale_done % initial values \d_grph_scale_x_offset\zeropoint \d_grph_scale_y_offset\zeropoint \d_grph_scale_x_size \d_grph_scale_wd \d_grph_scale_y_size \d_grph_scale_ht % alleen ht wordt geschaald! % final values \global\d_grph_scale_used_x_size \zeropoint % see note * (core-fig) \global\d_grph_scale_used_y_size \zeropoint % see note * (core-fig) \c_grph_scale_used_x_scale \plusone % see note * (core-fig) \c_grph_scale_used_y_scale \plusone % see note * (core-fig) % preparations \setfalse\c_grph_scale_scaling_done \grph_scale_check_parameters % calculators % beware, they operate in sequence, and calculate missing dimensions / messy %setscaleboxbynature % when? needed? \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_factor \fi \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_scale \fi \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_dimension\fi % finalizers / to be done (no longer needed this way, clean up) \grph_scale_convert_large_scale\d_grph_scale_h_size\figx\c_grph_scale_used_x_scale\m_grph_scale_temp_x \grph_scale_convert_large_scale\d_grph_scale_v_size\figy\c_grph_scale_used_y_scale\m_grph_scale_temp_y % used in actual scaling \xdef\finalscaleboxwidth {\the\d_grph_scale_used_x_size}% \xdef\finalscaleboxheight {\the\d_grph_scale_used_y_size}% \xdef\finalscaleboxxfactor{\the\c_grph_scale_used_x_scale}% \xdef\finalscaleboxyfactor{\the\c_grph_scale_used_y_scale}% \xdef\finalscaleboxxscale {\withoutpt\the\dimexpr\m_grph_scale_temp_x\points/\plushundred\relax}% \xdef\finalscaleboxyscale {\withoutpt\the\dimexpr\m_grph_scale_temp_y\points/\plushundred\relax}} \setvalue{\??scalegrid\v!yes }{\getnoflines \d_grph_scale_used_y_size\edef\p_height{\the\noflines\lineheight}} \setvalue{\??scalegrid\v!height }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight+\strutdepth}} \setvalue{\??scalegrid\v!depth }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight-\strutdepth}} \setvalue{\??scalegrid\v!halfline}{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight+.5\lineheight}} \setvalue{\??scalegrid\v!fit }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\noflines\lineheight}} \letvalue{\??scalegrid\empty }\donothing \def\grph_scale_check_parameters % resolve self referencing loops {\ifx\p_maxwidth \empty\else \edef\p_maxwidth {\the\dimexpr\p_maxwidth }\fi \ifx\p_maxheight\empty\else \edef\p_maxheight{\the\dimexpr\p_maxheight }\fi \ifx\p_lines \empty\else \edef\p_height {\the\dimexpr\p_lines\lineheight}\fi \getvalue{\??scalegrid\scaleparameter\c!grid}} \def\grph_scale_by_nature % where ! ! ! ! ! {\ifx\p_width \empty\else \global\d_grph_scale_used_x_size\p_width \fi \ifx\p_height\empty\else \global\d_grph_scale_used_y_size\p_height\fi \ifx\p_scale \empty\else \c_grph_scale_used_x_scale\p_scale \c_grph_scale_used_y_scale\p_scale \fi \ifx\p_xscale\empty\else \c_grph_scale_used_x_scale\p_xscale\fi \ifx\p_yscale\empty\else \c_grph_scale_used_y_scale\p_yscale\fi} % \defineexternalfigure[width-6][factor=auto,maxwidth=\textheight,maxheight=\textwidth] % \defineexternalfigure[width-7][factor=auto,maxwidth=\textwidth,maxheight=\textheight] % \placefigure{none}{\rotate[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-6]}} \page % \placefigure{none}{\framed[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-7]}} \def\m_grph_scale_factor_set{\v!max,\v!fit,\v!broad,\v!auto} % can be an \edef \def\grph_scale_by_factor {\doifinsetelse\p_factor\m_grph_scale_factor_set \grph_scale_by_factor_a {\doifinsetelse\p_hfactor\m_grph_scale_factor_set \grph_scale_by_factor_b {\doifinsetelse\p_wfactor\m_grph_scale_factor_set \grph_scale_by_factor_c \grph_scale_by_factor_d}}} \def\grph_scale_by_factor_a {\grph_scale_apply_size \ifdim\d_grph_scale_x_size>\d_grph_scale_y_size \grph_scale_calculate_norm \d_grph_scale_used_x_size\p_factor\p_maxwidth\hsize\d_grph_scale_h_size \grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size \else \grph_scale_calculate_norm \d_grph_scale_used_y_size\p_factor\p_maxheight\d_grph_scale_outer_v_size\d_grph_scale_v_size \grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size \fi \grph_scale_by_factor_indeed} \def\grph_scale_by_factor_b {\grph_scale_apply_size \grph_scale_calculate_norm \d_grph_scale_used_y_size\p_hfactor\p_maxheight\d_grph_scale_outer_v_size\d_grph_scale_v_size \grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size \grph_scale_by_factor_indeed} \def\grph_scale_by_factor_c {\grph_scale_apply_size \grph_scale_calculate_norm \d_grph_scale_used_x_size\p_wfactor\p_maxwidth\hsize\d_grph_scale_h_size \grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size \grph_scale_by_factor_indeed} \def\grph_scale_by_factor_d {\grph_scale_calculate_norm\d_grph_scale_used_y_size\p_factor \p_height \textheight\d_grph_scale_v_size \grph_scale_calculate_norm\d_grph_scale_used_y_size\p_hfactor\p_height \textheight\d_grph_scale_v_size \grph_scale_calculate_norm\d_grph_scale_used_x_size\p_wfactor\p_width \hsize \hsize} \def\grph_scale_by_factor_indeed {\settrue\c_grph_scale_scaling_done \ifdim\d_grph_scale_used_x_size>\d_grph_scale_h_size \global\d_grph_scale_used_y_size\zeropoint \global\d_grph_scale_used_x_size\d_grph_scale_h_size \else\ifdim\d_grph_scale_used_y_size>\d_grph_scale_v_size \global\d_grph_scale_used_x_size\zeropoint \global\d_grph_scale_used_y_size\d_grph_scale_v_size \fi\fi \grph_scale_by_dimension} \def\grph_scale_by_scale {\edef\m_grph_scale_temp{\p_scale\p_xscale\p_yscale}% \ifx\m_grph_scale_temp\empty \else \grph_scale_apply_scale\d_grph_scale_used_x_size\d_grph_scale_x_size\c_grph_scale_used_x_scale\p_xscale \grph_scale_apply_scale\d_grph_scale_used_y_size\d_grph_scale_y_size\c_grph_scale_used_y_scale\p_yscale \global\d_grph_scale_used_x_size\zeropoint \global\d_grph_scale_used_y_size\zeropoint \ifx\p_maxwidth\empty \ifx\p_maxheight\empty \else \ifdim\d_grph_scale_y_size>\p_maxheight\relax \global\d_grph_scale_used_y_size\p_maxheight \fi \fi \else \ifdim\d_grph_scale_x_size>\p_maxwidth\relax \global\d_grph_scale_used_x_size\p_maxwidth \fi \fi \fi} \def\grph_scale_by_dimension {\ifdim\d_grph_scale_used_x_size>\zeropoint \ifdim\d_grph_scale_used_y_size>\zeropoint \grph_scale_by_dimension_a \else \grph_scale_by_dimension_b \fi \else \ifdim\d_grph_scale_used_y_size>\zeropoint \grph_scale_by_dimension_c \else \grph_scale_by_dimension_d \fi \fi} \def\grph_scale_by_dimension_a {\grph_scale_by_dimension_indeed {\grph_scale_calculate_scale\d_grph_scale_used_y_size\d_grph_scale_y_size\c_grph_scale_used_y_scale \grph_scale_calculate_scale\d_grph_scale_used_x_size\d_grph_scale_x_size\c_grph_scale_used_x_scale}% {\grph_scale_calculate_scale\d_grph_scale_used_y_size\d_grph_scale_y_size\c_grph_scale_used_y_scale \grph_scale_calculate_scale\d_grph_scale_used_x_size\d_grph_scale_x_size\c_grph_scale_used_x_scale}% {\grph_scale_calculate_scale\d_grph_scale_used_y_size\d_grph_scale_y_size\c_grph_scale_used_y_scale \grph_scale_calculate_scale\d_grph_scale_used_x_size\d_grph_scale_x_size\c_grph_scale_used_x_scale}} \def\grph_scale_by_dimension_b {\grph_scale_by_dimension_indeed {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size}% {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size}% {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size}} \def\grph_scale_by_dimension_c {\grph_scale_by_dimension_indeed {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size}% {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size}% {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size}} \def\grph_scale_by_dimension_d {\grph_scale_by_dimension_indeed {\grph_scale_apply_scale\d_grph_scale_used_x_size\d_grph_scale_x_size\c_grph_scale_used_x_scale\p_xscale \grph_scale_apply_scale\d_grph_scale_used_y_size\d_grph_scale_y_size\c_grph_scale_used_y_scale\p_yscale}% {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size\d_grph_scale_used_y_size\d_grph_scale_y_size}% {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size\d_grph_scale_used_x_size\d_grph_scale_x_size}} \def\grph_scale_by_dimension_indeed#1#2#3% {#1\relax \ifx\p_maxwidth\empty \else \ifdim\d_grph_scale_used_x_size>\p_maxwidth\relax \global\d_grph_scale_used_x_size\p_maxwidth #2\relax \fi \fi \ifx\p_maxheight\empty \else \ifdim\d_grph_scale_used_y_size>\p_maxheight\relax \global\d_grph_scale_used_y_size\p_maxheight #3\relax \fi \fi} \def\grph_scale_calculate_norm#1#2% todo: swap 1 and 2 and pass one less {\csname\??scalenorm\ifcsname\??scalenorm#2\endcsname#2\else\s!unknown\fi\endcsname#1#2} \setvalue{\??scalenorm\v!max }#1#2#3#4#5{\global#1#4} \setvalue{\??scalenorm\v!fit }#1#2#3#4#5{\global#1#5} \setvalue{\??scalenorm\v!broad }#1#2#3#4#5{\global#1\dimexpr#5-4\@@exbodyfont\relax} \setvalue{\??scalenorm\s!unknown}#1#2#3#4#5{\global#1\dimexpr#2\dimexpr\@@exbodyfont/10\relax\relax} % brr ex \setvalue{\??scalenorm\v!auto }#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi} \setvalue{\??scalenorm\empty }#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi} \setvalue{\??scalenorm\s!default}#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi} \def\grph_scale_calculate_scales#1#2#3#4% {\scratchdimen\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax \c_grph_scale_used_x_scale\scratchdimen \c_grph_scale_used_y_scale\scratchdimen #3\dimexpr\c_grph_scale_used_x_scale\dimexpr#4/\plusthousand\relax\relax} \def\grph_scale_calculate_scale#1#2#3% {#3\dimexpr#1/\dimexpr#2/\plusthousand\relax\relax} \def\grph_scale_apply_scale#1#2#3#4% #4 = parameter / scale can be empty {\ifcase0#4\relax \ifcase0\p_scale\relax #3=\plusthousand \else #3=\p_scale \fi \else #3=#4% \fi \relax % important ! still ? \global#1\ifnum#3=\plusthousand#2\else\dimexpr#3\dimexpr#2/\plusthousand\relax\relax\fi \relax} \def\grph_scale_apply_size {\ifx\p_maxheight\empty \d_grph_scale_outer_v_size\textheight \ifinner \d_grph_scale_outer_v_size \vsize % \textheight =\vsize \scratchdimen\vsize % \scratchdimen=\textheight \else\ifinsidefloat \d_grph_scale_outer_v_size \vsize % \textheight =\vsize \scratchdimen\vsize % \scratchdimen=\textheight \else\ifinpagebody \d_grph_scale_outer_v_size \vsize % \textheight =\vsize \scratchdimen\vsize % \scratchdimen=\textheight \else % hm, there should be an option to force this \ifdim\pagegoal<\maxdimen \ifdim\pagetotal<\pagegoal \scratchdimen\dimexpr\pagegoal-\pagetotal\relax \else \scratchdimen\d_grph_scale_outer_v_size % \textheight \fi \else \scratchdimen\d_grph_scale_outer_v_size % \textheight \fi \fi\fi\fi \else \scratchdimen\p_maxheight \d_grph_scale_outer_v_size\scratchdimen \fi \ifx\p_height\empty \d_grph_scale_v_size\scratchdimen \else \d_grph_scale_v_size\p_height \fi \ifx\p_width\empty \d_grph_scale_h_size\hsize \else \d_grph_scale_h_size\p_width \fi} \def\grph_scale_convert_large_scale#1#2#3#4% {\scratchdimen#1\relax \ifnum#3=\plusthousand % == scale 1 \else % better 1000 100 10 ranges, evt round 2sp \divide\scratchdimen \plusthousand \multiply\scratchdimen #3\relax \fi \scratchdimen-\scratchdimen % beter hier - dan in driver \edef#2{\the\scratchdimen}% \scratchcounter#3\relax \ifnum\scratchcounter>\plustenthousand \divide\scratchcounter\plusten \scratchdimen\the\scratchcounter\points \else \scratchdimen\the\scratchcounter\points \divide\scratchdimen\plusten \fi \edef#4{\withoutpt\the\scratchdimen}} % \startcombination % {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {} % {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {} % \stopcombination \def\grph_scale_position {\ifx\p_equalwidth\empty \else \scratchdimen\p_equalwidth\relax \ifdim\d_grph_scale_wd<\scratchdimen \setbox\nextbox\hbox to \scratchdimen{\hss\box\nextbox\hss}% \fi \fi \ifx\p_equalheight\empty \else \scratchdimen\p_equalheight\relax \ifdim\d_grph_scale_ht<\scratchdimen \setbox\nextbox\vbox to \scratchdimen{\vss\box\nextbox\vss}% \fi \fi} \unexpanded\def\fastscale#1% {\ifnum#1=1000\relax \expandafter\grph_scale_fast_nop \else \expandafter\grph_scale_fast_yes \fi{#1}} \def\grph_scale_fast_nop#1% {\hbox} \def\grph_scale_fast_yes#1% {\edef\finalscaleboxxscale{\withoutpt\the\dimexpr#1pt/1000\relax}% brrr \let\finalscaleboxyscale\finalscaleboxxscale \dowithnextboxcs\grph_scale_fast_finish\hbox} \def\grph_scale_fast_finish {\grph_scale_apply \box\nextbox \endgroup} %D \macros %D {clip, setupclipping} %D %D Although related to figures, clipping can be applied to %D arbitrary content. We can use \METAPOST\ to provide a non %D rectangular clipping path. %D %D \starttyping %D \startMPclip{fun} %D clip currentpicture to fullcircle %D shifted (.5,.5) xscaled \width yscaled \height ; %D \stopMPclip %D \stoptyping %D %D We get a rectangular piece of the figure when we say: %D %D \starttyping %D \clip[x=2,y=1]{\externalfigure[photo]} %D \stoptyping %D %D When we want to clip to the oval we defined a few lines ago, %D we say: %D %D \starttyping %D \clip[nx=1,ny=1,x=1,y=1,mp=fun]{\externalfigure[photo]} %D \stoptyping %D %D The general characteristics of clipping can be set up with %D %D \showsetup{setupclipping} \unexpanded\def\setupclipping {\dodoubleargument\getparameters[\??cp]} \unexpanded\def\clip {\dosingleempty\grph_clip} \def\grph_clip[#1]% nb top->bottom left->right {\bgroup \iffirstargument \getparameters[\??cp][#1]% \fi \dowithnextboxcs\grph_clip_finish\hbox} \def\grph_clip_finish {\doifelse\@@cpstate\v!start \grph_clip_yes_finish \grph_clip_nop_finish} \def\grph_clip_yes_finish {\ifdim\@@cpwidth>\zeropoint \!!dimena\@@cpwidth \!!dimenc\@@cphoffset \else \!!dimena\wd\nextbox \divide\!!dimena \@@cpnx \!!dimenc\@@cpx\!!dimena \advance\!!dimenc -\!!dimena \!!dimena\@@cpsx\!!dimena \fi \relax % sure \ifdim\@@cpheight>\zeropoint \!!dimenb\@@cpheight \!!dimend\ht\nextbox \advance\!!dimend -\@@cpvoffset \advance\!!dimend -\!!dimenb \else \!!dimenb\ht\nextbox \divide\!!dimenb \@@cpny \!!dimend-\@@cpy\!!dimenb \advance\!!dimend -\@@cpsy\!!dimenb \advance\!!dimend \!!dimenb \!!dimenb\@@cpsy\!!dimenb \advance\!!dimend \ht\nextbox % dimend ! \fi \setbox\nextbox\hbox % old {\advance\!!dimenc -\@@cpleftoffset % new ! \advance\!!dimend -\@@cpbottomoffset % new ! % - added \hskip-\!!dimenc\lower\!!dimend\box\nextbox}% old \wd\nextbox\zeropoint \ht\nextbox\zeropoint \dp\nextbox\zeropoint \setbox\nextbox\hbox {\advance\!!dimena \@@cpleftoffset % new ! \advance\!!dimena \@@cprightoffset % new ! \advance\!!dimenb \@@cpbottomoffset % new ! \advance\!!dimenb \@@cptopoffset % new ! \dostartclipping\@@cpmp\!!dimena\!!dimenb % old \box\nextbox \dostopclipping}% \setbox\nextbox\hbox % new ! {\!!dimena-\@@cpleftoffset % new ! \!!dimenb \@@cpbottomoffset % new ! % - removed \hskip\!!dimena\lower\!!dimenb\box\nextbox}% new ! \wd\nextbox\!!dimena \ht\nextbox\!!dimenb \dp\nextbox\zeropoint \box\nextbox \egroup} \def\grph_clip_nop_finish {\box\nextbox \egroup} \setupclipping [\c!state=\v!start, \c!n=1, % was 2 \c!nx=\@@cpn,\c!x=1,\c!sx=1, \c!ny=\@@cpn,\c!y=1,\c!sy=1, \c!width=\!!zeropoint, \c!height=\!!zeropoint, \c!hoffset=\!!zeropoint, \c!voffset=\!!zeropoint, \c!offset=\zeropoint, \c!leftoffset=\@@cpoffset, % \zeropoint, \c!rightoffset=\@@cpoffset, % \zeropoint, \c!topoffset=\@@cpoffset, % \zeropoint, \c!bottomoffset=\@@cpoffset,% \zeropoint, \c!mp=] %D \startbuffer %D \startuseMPgraphic{test} %D path p ; p := fullcircle scaled 4cm ; %D draw p withpen pencircle scaled 1cm ; %D setbounds currentpicture to boundingbox p ; %D \stopuseMPgraphic %D %D \hbox to \hsize \bgroup %D \hss %D \ruledhbox{\useMPgraphic{test}}% %D \hss %D \ruledhbox{\clip{\useMPgraphic{test}}}% %D \hss %D \egroup %D \stopbuffer %D %D \typebuffer \getbuffer %D Mirroring. \unexpanded\def\mirror {\bgroup \dowithnextboxcs\grph_mirror_finish\hbox} \def\grph_mirror_finish {\scratchdimen\wd\nextbox % better use an hbox (if no \forgetall, leftskip etc may creep in) %\setbox\nextbox\vbox{\forgetall\dostartmirroring\hskip-\wd\nextbox\box\nextbox\dostopmirroring}% \setbox\nextbox\hbox{\dostartmirroring\hskip-\wd\nextbox\box\nextbox\dostopmirroring}% \wd\nextbox\scratchdimen \box\nextbox \egroup} %D A couple of examples, demonstrating how the depth is %D taken care of: %D %D \startbuffer %D test\rotate[frame=on, rotation=0] {gans}% %D test\rotate[frame=on, rotation=90] {gans}% %D test\rotate[frame=on, rotation=180]{gans}% %D test\rotate[frame=on, rotation=270]{gans}% %D test %D \stopbuffer %D %D \typebuffer \getbuffer % When we rotate over arbitrary angles, we need to relocate the % resulting box because rotation brings that box onto the negative % axis. The calculations (mostly sin and cosine) need to be tuned for % the way a box is packages (i.e. the refence point). A typical example % of drawing, scribbling, and going back to the days of school math. % % We do a bit more calculations than needed, simply because that way % it's easier to debug the code. % Cleanup in progress ... todo: less boxing \installcorenamespace {rotate} \installcorenamespace {rotatelocation} \installcorenamespace {rotatepreset} % we can alias these to \d_layers-* to save some dimens or maybe have a generic % set of scratch variables % maybe just \rotation_... \newdimen\d_grph_rotate_x_size \newdimen\d_grph_rotate_y_size \newdimen\d_grph_rotate_x_offset \newdimen\d_grph_rotate_y_offset \newdimen\d_grph_rotate_x_position \newdimen\d_grph_rotate_y_position \newdimen\d_grph_rotate_used_height \let\d_grph_rotate_width \!!widtha \let\d_grph_rotate_height\!!heighta \let\d_grph_rotate_depth \!!deptha \let\d_grph_rotate_saved_width \!!widthb \let\d_grph_rotate_saved_height\!!heightb \let\d_grph_rotate_saved_depth \!!depthb \newconditional\c_grph_rotate_obey_depth \newconditional\c_grph_rotate_not_fit \newconditional\c_grph_rotate_center \installframedcommandhandler \??rotate {rotate} \??rotate \setuprotate [\c!rotation=90, \c!location=\v!normal, \c!width=\v!fit, \c!height=\v!fit, \c!offset=\v!overlay, \c!frame=\v!off] \let\p_rotation_location\empty \let\p_rotation_rotation\empty \unexpanded\def\rotate % \bgroup: \rotate kan argument zijn {\bgroup \dosingleempty\grph_rotate} \def\grph_rotate[#1]% {\iffirstargument \setupcurrentrotate[#1]% \fi \edef\p_rotation_location{\rotateparameter\c!location}% \edef\p_rotation_rotation{\rotateparameter\c!rotation}% \csname\??rotatelocation \ifcsname\??rotatelocation\p_rotation_location\endcsname\p_rotation_location\else\v!default\fi \endcsname} \def\grph_rotate_framed {\resetrotateparameter\c!location \dowithnextboxcs\grph_rotate_finish\vbox \inheritedrotateframed} \def\grph_rotate_normal {\dowithnextboxcs\grph_rotate_finish\vbox} \def\grph_rotate_finish {\grph_rotate_finish_indeed \egroup} \setvalue{\??rotatelocation\v!depth}% {\setfalse\c_grph_rotate_not_fit \setfalse\c_grph_rotate_center \settrue \c_grph_rotate_obey_depth \grph_rotate_normal} \setvalue{\??rotatelocation\v!fit}% {\settrue \c_grph_rotate_not_fit \setfalse\c_grph_rotate_center \settrue \c_grph_rotate_obey_depth \grph_rotate_normal} \setvalue{\??rotatelocation\v!broad}% {\setfalse\c_grph_rotate_not_fit \setfalse\c_grph_rotate_center \setfalse\c_grph_rotate_obey_depth \grph_rotate_normal} \setvalue{\??rotatelocation\v!high}% {\setfalse\c_grph_rotate_not_fit \setfalse\c_grph_rotate_center \setfalse\c_grph_rotate_obey_depth \grph_rotate_framed} \setvalue{\??rotatelocation\v!middle}% {\setfalse\c_grph_rotate_not_fit \settrue \c_grph_rotate_center \setfalse\c_grph_rotate_obey_depth % hm, depth ? \grph_rotate_normal} \setvalue{\??rotatelocation\v!default}% {\setfalse\c_grph_rotate_not_fit \setfalse\c_grph_rotate_center \settrue \c_grph_rotate_obey_depth \grph_rotate_framed} \unexpanded\def\dorotatebox#1% {angle} \hbox/\vbox/\vtop % a fast low level one {\ifcase#1\relax \expandafter\gobbleoneargument \else \expandafter\grph_rotate_box \fi{#1}} \def\grph_rotate_box#1% {angle} \hbox/\vbox/\vtop {\bgroup \hbox\bgroup % compatibility hack \edef\p_rotation_rotation{#1}% \dowithnextboxcs\grph_rotate_finish_box} \def\grph_rotate_finish_box {\setfalse\c_grph_rotate_not_fit % this is the same as broad but \setfalse\c_grph_rotate_center % without the following grab as \setfalse\c_grph_rotate_obey_depth % we call finish directly \grph_rotate_finish_indeed \egroup \egroup} \def\grph_rotate_finish_indeed {\hbox\bgroup \ifx\p_rotation_rotation\empty \grph_rotate_finish_nop \else \grph_rotate_finish_yes \fi \egroup} \def\grph_rotate_finish_nop {\boxcursor\box\nextbox} \setvalue{\??rotatepreset\v!left}% {\edef\p_rotation_rotation{\doifoddpageelse{90}{270}}} \setvalue{\??rotatepreset\v!right}% {\edef\p_rotation_rotation{\doifoddpageelse{270}{90}}} \setvalue{\??rotatepreset\v!inner}% {\signalrightpage \doifrightpageelse{\def\p_rotation_rotation{270}}{\def\p_rotation_rotation{90}}} \setvalue{\??rotatepreset\v!outer}% {\signalrightpage \doifrightpageelse{\def\p_rotation_rotation{90}}{\def\p_rotation_rotation{270}}} \setvalue{\??rotatepreset\v!default}% {\edef\p_rotation_rotation{\realnumber{\p_rotation_rotation}}}% get rid of leading zeros and spaces \def\grph_rotate_finish_yes {\csname\??rotatepreset \ifcsname\??rotatepreset\p_rotation_rotation\endcsname\p_rotation_rotation\else\v!default\fi \endcsname \setbox\nextbox\vbox{\box\nextbox}% not really needed \dontcomplain \ifconditional\c_grph_rotate_center \d_grph_rotate_saved_width \wd\nextbox \d_grph_rotate_saved_height\ht\nextbox \d_grph_rotate_saved_depth \dp\nextbox \setbox\nextbox\vbox{\vskip.5\ht\nextbox\hskip-.5\wd\nextbox\box\nextbox}% \smashbox\nextbox \fi \d_grph_rotate_width \wd\nextbox \d_grph_rotate_height\ht\nextbox \d_grph_rotate_depth \dp\nextbox \setbox\nextbox\vbox{\hbox{\raise\dp\nextbox\box\nextbox}}% \d_grph_rotate_used_height \ht\nextbox % much of the next happens in lua (all the sin and cos) so we can do that in % one go if needed \setcalculatedcos\cos\p_rotation_rotation \setcalculatedsin\sin\p_rotation_rotation \ifdim\sin\points>\zeropoint \ifdim\cos\points>\zeropoint \grph_rotate_calculate_a \grph_rotate_apply \else \grph_rotate_calculate_b \grph_rotate_apply \wd\nextbox\ifconditional\c_grph_rotate_not_fit\sin\d_grph_rotate_depth\else\d_grph_rotate_x_size\fi \fi \else \ifdim\cos\points<\zeropoint \grph_rotate_calculate_c \grph_rotate_apply \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi \else\ifdim\sin\points=\zeropoint \grph_rotate_calculate_d \grph_rotate_apply % no wd ? \else \grph_rotate_calculate_e \grph_rotate_apply \wd\nextbox\ifconditional\c_grph_rotate_not_fit\negated\sin\d_grph_rotate_height\else\d_grph_rotate_x_size\fi \fi\fi \fi \ifconditional\c_grph_rotate_center \setbox\nextbox\vbox{\vskip-.5\d_grph_rotate_saved_height\hskip.5\d_grph_rotate_saved_height\box\nextbox}% \wd\nextbox\d_grph_rotate_saved_width \ht\nextbox\d_grph_rotate_saved_height \dp\nextbox\d_grph_rotate_saved_depth \fi \boxcursor\box\nextbox} \def\grph_rotate_calculate_a {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax \d_grph_rotate_x_position\zeropoint \d_grph_rotate_y_position\cos\d_grph_rotate_used_height \ifconditional\c_grph_rotate_not_fit \d_grph_rotate_x_offset\dimexpr\negated\sin\d_grph_rotate_used_height+\sin\d_grph_rotate_depth\relax \fi \ifconditional\c_grph_rotate_obey_depth \d_grph_rotate_y_offset\cos\d_grph_rotate_depth \fi} \def\grph_rotate_calculate_b {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\sin\d_grph_rotate_used_height\relax \d_grph_rotate_y_size\dimexpr\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax \d_grph_rotate_x_position\negated\cos\d_grph_rotate_width \d_grph_rotate_y_position\zeropoint \ifconditional\c_grph_rotate_not_fit \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\sin\d_grph_rotate_depth\relax \fi \ifconditional\c_grph_rotate_obey_depth \d_grph_rotate_y_offset\negated\cos\d_grph_rotate_height \fi} \def\grph_rotate_calculate_c {\d_grph_rotate_x_size\dimexpr\negated\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\negated\cos\d_grph_rotate_used_height\relax \d_grph_rotate_x_position\d_grph_rotate_x_size \d_grph_rotate_y_position\negated\sin\d_grph_rotate_width \ifconditional\c_grph_rotate_not_fit \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax \fi \ifconditional\c_grph_rotate_obey_depth \d_grph_rotate_y_offset\dimexpr\d_grph_rotate_y_size+\cos\d_grph_rotate_depth\relax \fi} \def\grph_rotate_calculate_d {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax \d_grph_rotate_x_position\zeropoint \d_grph_rotate_y_position\d_grph_rotate_y_size \d_grph_rotate_x_offset\zeropoint \ifconditional\c_grph_rotate_obey_depth \d_grph_rotate_y_offset\d_grph_rotate_depth \fi} \def\grph_rotate_calculate_e {\d_grph_rotate_x_size\dimexpr\cos\d_grph_rotate_width+\negated\sin\d_grph_rotate_used_height\relax \d_grph_rotate_y_size\dimexpr\negated\sin\d_grph_rotate_width+\cos\d_grph_rotate_used_height\relax \d_grph_rotate_x_position\negated\sin\d_grph_rotate_used_height \d_grph_rotate_y_position\d_grph_rotate_y_size \ifconditional\c_grph_rotate_not_fit \d_grph_rotate_x_offset\dimexpr-\d_grph_rotate_x_size+\negated\sin\d_grph_rotate_height\relax \fi \ifconditional\c_grph_rotate_obey_depth \d_grph_rotate_y_offset\negated\sin\d_grph_rotate_depth \fi} \def\grph_rotate_apply {\setbox\nextbox\vbox to \d_grph_rotate_y_size {\vfill \hbox to \d_grph_rotate_x_size {\dostartrotation\p_rotation_rotation \wd\nextbox\zeropoint \ht\nextbox\zeropoint \box\nextbox \dostoprotation \hfill}% \kern\d_grph_rotate_y_position}% \setbox\nextbox\hbox {\kern\dimexpr\d_grph_rotate_x_position+\d_grph_rotate_x_offset\relax \lower\d_grph_rotate_y_offset\box\nextbox}} % \dostepwiserecurse{0}{360}{10} % {\startlinecorrection[blank] % \hbox % {\expanded{\setuprotate[rotation=\recurselevel]}% % \traceboxplacementtrue % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=depth] {\ruledhbox{\bfb (depth)}}}}% % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=fit] {\ruledhbox{\bfb (fit)}}}}% % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=broad] {\ruledhbox{\bfb (broad)}}}}% % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=normal]{\ruledhbox{\bfb (normal)}}}}% % \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high] {\ruledhbox{\bfb (high)}}}}} % \stoplinecorrection} \protect \endinput