grph-trf.mkiv /size: 36 Kb    last modification: 2020-07-01 14:35
1%D \module
2%D   [       file=grph-trf,
3%D        version=2006.08.26, % overhaul/split of 1997.03.31 core-fig
4%D          title=\CONTEXT\ Graphic Macros,
5%D       subtitle=Transformations,
6%D         author=Hans Hagen,
7%D           date=\currentdate,
8%D      copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
9%C
10%C This module is part of the \CONTEXT\ macro||package and is
11%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
12%C details.
13
14\writestatus{loading}{ConTeXt Graphic Macros / Transformations}
15
16\unprotect
17
18%D We probably use too many dimens as the width calculations can go away. Some of
19%D this is an inheritance of limited backends (some supported fractions, some
20%D 1000's, some dimentions) so we calculate all of them. Nowadays scaling is always
21%D available so we could simplify the code. On the other hand, we now get some extra
22%D values for free.
23%D
24%D We could move the calculations to \LUA\ and clean up this lot anyway. On the
25%D other hand, there is some danger of messing up so it has a real low priority.
26
27\registerctxluafile{grph-trf}{}
28
29% local:
30
31\newdimen\d_grph_scale_x_size
32\newdimen\d_grph_scale_y_size
33\newdimen\d_grph_scale_x_offset
34\newdimen\d_grph_scale_y_offset
35
36\newdimen\d_grph_scale_h_size
37\newdimen\d_grph_scale_v_size
38
39\newconditional\c_grph_scale_done
40\newconditional\c_grph_scale_scaling_done
41\newconditional\c_grph_scale_limit_factors \settrue\c_grph_scale_limit_factors
42
43\newconditional\c_grph_scale_swap_factor
44
45\newdimen\d_grph_scale_wd
46\newdimen\d_grph_scale_ht
47\newdimen\d_grph_scale_dp
48
49% global
50
51\newdimen\d_grph_scale_used_x_size
52\newdimen\d_grph_scale_used_y_size
53
54\newcount\c_grph_scale_used_x_scale
55\newcount\c_grph_scale_used_y_scale
56
57\let     \m_grph_scale_used_x_scale\!!plusone
58\let     \m_grph_scale_used_y_scale\!!plusone
59
60\newdimen\d_grph_scale_outer_v_size % we cannot manipulate any global vsize !
61
62% scratch:
63
64\let\m_grph_scale_temp  \empty
65\let\m_grph_scale_temp_x\empty
66\let\m_grph_scale_temp_y\empty
67
68% public:
69
70\let\finalscaleboxxscale \!!plusone
71\let\finalscaleboxyscale \!!plusone
72\let\finalscaleboxwidth  \!!zeropoint
73\let\finalscaleboxheight \!!zeropoint
74
75% we can let sx/sy win (first check)
76
77\installcorenamespace{scale}
78\installcorenamespace{scalegrid}
79\installcorenamespace{scalenorm}
80\installcorenamespace{scalefact}
81
82\installcommandhandler \??scale {scale} \??scale % we can have instances
83
84\setupscale
85  [\c!sx=\scaleparameter\c!s,
86   \c!sy=\scaleparameter\c!s,
87   \c!s=1,
88  %\c!scale=,
89  %\c!xscale=,
90  %\c!yscale=,
91  %\c!width=,
92  %\c!height=,
93  %\c!lines=,
94  %\c!factor=,
95  %\c!hfactor=,
96  %\c!wfactor=,
97  %\c!grid=,
98  %\c!equalwidth=,
99  %\c!equalheight=,
100   \c!maxwidth=\scaleparameter\c!width,
101   \c!maxheight=\scaleparameter\c!height]
102
103\unexpanded\def\scale{\dodoubleempty\grph_scale}
104
105\def\grph_scale[#1][#2]%
106  {\bgroup
107   % this is quite common so we might make this a helper
108   \ifsecondargument
109     \edef\currentscale{#1}%
110     \setupcurrentscale[#2]%
111   \else\iffirstargument
112     \doifelseassignment{#1}
113       {\let\currentscale\empty
114        \setupcurrentscale[#1]}
115       {\edef\currentscale{#1}}%
116   \else
117     \let\currentscale\empty
118   \fi\fi
119   %
120   \dowithnextboxcs\grph_scale_finish\hbox}
121
122\def\grph_scale_finish
123  {% todo: p_scale_
124   \edef\p_scale      {\scaleparameter\c!scale      }%
125   \edef\p_xscale     {\scaleparameter\c!xscale     }%
126   \edef\p_yscale     {\scaleparameter\c!yscale     }%
127   \edef\p_width      {\scaleparameter\c!width      }%
128   \edef\p_height     {\scaleparameter\c!height     }%
129   \edef\p_depth      {\scaleparameter\c!depth      }%
130   \edef\p_lines      {\scaleparameter\c!lines      }%
131   \edef\p_factor     {\scaleparameter\c!factor     }%
132   \edef\p_hfactor    {\scaleparameter\c!hfactor    }%
133   \edef\p_wfactor    {\scaleparameter\c!wfactor    }%
134 % \edef\p_grid       {\scaleparameter\c!grid       }% used once
135   \edef\p_maxwidth   {\scaleparameter\c!maxwidth   }%
136   \edef\p_maxheight  {\scaleparameter\c!maxheight  }%
137   \edef\p_sx         {\scaleparameter\c!sx         }%
138   \edef\p_sy         {\scaleparameter\c!sy         }%
139   \edef\p_equalwidth {\scaleparameter\c!equalwidth }%
140   \edef\p_equalheight{\scaleparameter\c!equalheight}%
141   %
142   \d_grph_scale_dp\dp\nextbox
143   \ifx\p_depth\v!no \ifzeropt\d_grph_scale_dp \else
144     \setbox\nextbox\naturalhpack{\raise\d_grph_scale_dp\box\nextbox}% new
145     \d_grph_scale_dp\dp\nextbox
146   \fi \fi
147   \d_grph_scale_wd\wd\nextbox
148   \d_grph_scale_ht\ht\nextbox
149   \d_grph_scale_dp\dp\nextbox
150   %
151   \glet\finalscaleboxxscale \!!plusone
152   \glet\finalscaleboxyscale \!!plusone
153   \xdef\finalscaleboxwidth {\the\d_grph_scale_wd}%
154   \xdef\finalscaleboxheight{\the\d_grph_scale_ht}%
155   %
156   \forgetall
157   \dontcomplain
158   %
159   \setfalse\c_grph_scale_done
160   \grph_scale_calculate
161   \ifconditional\c_grph_scale_done
162     \grph_scale_apply
163   \fi
164   \grph_scale_position
165   %
166   \box\nextbox
167   \egroup}
168
169% \def\grph_scale_apply
170%   {\d_grph_scale_wd\finalscaleboxxscale\d_grph_scale_wd
171%    \d_grph_scale_ht\finalscaleboxyscale\d_grph_scale_ht
172%    \d_grph_scale_dp\finalscaleboxyscale\d_grph_scale_dp
173%    \setbox\nextbox\naturalhpack
174%      {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
175%       \smashedbox\nextbox
176%       \dostopscaling}%
177%    \wd\nextbox\d_grph_scale_wd
178%    \ht\nextbox\d_grph_scale_ht
179%    \dp\nextbox\d_grph_scale_dp}
180
181\def\grph_scale_apply
182  {\d_grph_scale_wd\finalscaleboxxscale\d_grph_scale_wd
183   \d_grph_scale_ht\finalscaleboxyscale\d_grph_scale_ht
184   \d_grph_scale_dp\finalscaleboxyscale\d_grph_scale_dp
185   \ifdim\d_grph_scale_wd=\wd\nextbox
186     \ifdim\d_grph_scale_ht=\ht\nextbox
187       \ifdim\d_grph_scale_dp=\dp\nextbox
188        % \grph_scale_apply_nop
189       \else
190          \grph_scale_apply_yes
191       \fi
192     \else
193       \grph_scale_apply_yes
194     \fi
195   \else
196     \grph_scale_apply_yes
197   \fi}
198
199\def\grph_scale_apply_yes
200  {\setbox\nextbox\naturalhpack
201     {\dostartscaling \finalscaleboxxscale \finalscaleboxyscale
202      \smashedbox\nextbox
203      \dostopscaling}%
204   \wd\nextbox\d_grph_scale_wd
205   \ht\nextbox\d_grph_scale_ht
206   \dp\nextbox\d_grph_scale_dp}
207
208\def\m_grph_scale_stamp_c{11}
209
210\def\grph_scale_calculate
211  {\ifdim\d_grph_scale_ht>\zeropoint \ifdim\d_grph_scale_wd>\zeropoint
212     \edef\m_grph_scale_stamp_a{\p_scale\p_xscale\p_yscale\p_factor\p_wfactor\p_hfactor\p_lines\p_width\p_height}%
213     \edef\m_grph_scale_stamp_b{\p_sx\p_sy}%
214     \ifx\m_grph_scale_stamp_a\empty
215       \ifx\m_grph_scale_stamp_b\m_grph_scale_stamp_c
216         % no scaling, don't change this (previous attempts failed anyway)
217         \insidefloattrue % trick
218         \grph_scale_calculations_yes
219       \else
220         \grph_scale_check_sx_sy
221         \grph_scale_calculations_nop
222       \fi
223     \else
224       \ifx\m_grph_scale_stamp_b\empty
225         % no need to check further
226       \else
227         \grph_scale_check_sx_sy
228       \fi
229       \grph_scale_calculations_yes
230     \fi
231   \fi \fi}
232
233\def\grph_scale_check_sx_sy
234  {\ifdim\p_sx\onepoint=\onepoint\else\edef\p_width {\the\dimexpr\p_sx\d_grph_scale_wd}\fi
235   \ifdim\p_sy\onepoint=\onepoint\else\edef\p_height{\the\dimexpr\p_sy\d_grph_scale_ht}\fi}
236
237\def\grph_scale_rounded#1%
238  {\expandafter\expandafter\expandafter\grph_scale_rounded_indeed
239     \expandafter\WITHOUTPT\the\dimexpr#1\points*100+32768\scaledpoint\relax.\relax}
240
241\def\grph_scale_rounded_indeed#1.#2\relax{#1}
242
243\def\grph_scale_calculations_nop
244  {\settrue\c_grph_scale_done
245   \xdef\finalscaleboxwidth {\the\dimexpr\p_sx\d_grph_scale_wd\relax}%
246   \xdef\finalscaleboxheight{\the\dimexpr\p_sy\d_grph_scale_ht\relax}%
247   \glet\finalscaleboxxscale\p_sx
248   \glet\finalscaleboxyscale\p_sy
249   \ifx\finalscaleboxxscale\empty\let\finalscaleboxxscale\!!plusone\fi
250   \ifx\finalscaleboxyscale\empty\let\finalscaleboxyscale\!!plusone\fi}
251
252\let\grph_scale_calculations_report\relax
253
254\def\grph_scale_calculations_yes
255  {\settrue\c_grph_scale_done
256   % initial values
257   \d_grph_scale_x_offset\zeropoint
258   \d_grph_scale_y_offset\zeropoint
259   \d_grph_scale_x_size  \d_grph_scale_wd
260   \d_grph_scale_y_size  \d_grph_scale_ht % alleen ht wordt geschaald!
261   % final values
262   \global\d_grph_scale_used_x_size \zeropoint % see note * (core-fig)
263   \global\d_grph_scale_used_y_size \zeropoint % see note * (core-fig)
264   \c_grph_scale_used_x_scale       \plusone   % see note * (core-fig)
265   \c_grph_scale_used_y_scale       \plusone   % see note * (core-fig)
266   \let\m_grph_scale_used_x_scale   \!!plusone
267   \let\m_grph_scale_used_y_scale   \!!plusone
268   % preparations
269   \setfalse\c_grph_scale_scaling_done
270   \grph_scale_check_parameters
271   % calculators
272   % beware, they operate in sequence, and calculate missing dimensions / messy
273   % grph_scale_by_nature % when? needed?
274   \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_factor   \fi
275   \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_scale    \fi
276   \ifconditional\c_grph_scale_scaling_done\else\grph_scale_by_dimension\fi
277   % used in actual scaling
278   \xdef\finalscaleboxwidth  {\the\d_grph_scale_used_x_size}%
279   \xdef\finalscaleboxheight {\the\d_grph_scale_used_y_size}%
280   \glet\finalscaleboxxscale \m_grph_scale_used_x_scale
281   \glet\finalscaleboxyscale \m_grph_scale_used_y_scale
282   \grph_scale_calculations_report}
283
284\setvalue{\??scalegrid\v!yes     }{\getnoflines   \d_grph_scale_used_y_size\edef\p_height{\the\noflines\lineheight}}
285\setvalue{\??scalegrid\v!height  }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight+\strutdepth}}
286\setvalue{\??scalegrid\v!depth   }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight-\strutdepth}}
287\setvalue{\??scalegrid\v!halfline}{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\dimexpr\noflines\lineheight+.5\lineheight}}
288\setvalue{\??scalegrid\v!fit     }{\getrawnoflines\d_grph_scale_used_y_size\edef\p_height{\the\noflines\lineheight}}
289\letvalue{\??scalegrid\empty     }\donothing
290
291\def\grph_scale_check_parameters % resolve self referencing loops
292  {\ifx\p_maxwidth \empty\else \edef\p_maxwidth {\the\dimexpr\p_maxwidth        }\fi
293   \ifx\p_maxheight\empty\else \edef\p_maxheight{\the\dimexpr\p_maxheight       }\fi
294   \ifx\p_lines    \empty\else \edef\p_height   {\the\dimexpr\p_lines\lineheight}\fi
295   \csname\??scalegrid\scaleparameter\c!grid\endcsname}
296
297\def\grph_scale_by_nature % where ! ! ! ! !
298  {\ifx\p_width \empty\else \global\d_grph_scale_used_x_size\p_width \fi
299   \ifx\p_height\empty\else \global\d_grph_scale_used_y_size\p_height\fi
300   \ifx\p_scale \empty\else        \c_grph_scale_used_x_scale\p_scale
301                                   \c_grph_scale_used_y_scale\p_scale \fi
302   \ifx\p_xscale\empty\else        \c_grph_scale_used_x_scale\p_xscale\fi
303   \ifx\p_yscale\empty\else        \c_grph_scale_used_y_scale\p_yscale\fi}
304
305% \defineexternalfigure[width-6][factor=auto,maxwidth=\textheight,maxheight=\textwidth]
306% \defineexternalfigure[width-7][factor=auto,maxwidth=\textwidth,maxheight=\textheight]
307% \placefigure{none}{\rotate[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-6]}} \page
308% \placefigure{none}{\framed[frame=on,offset=overlay]{\externalfigure[t:/sources/cow.pdf][width-7]}}
309
310%D The \typpe {min} option makes sure that the smallest available space determines
311%D the max size (so we can get a bleed on the other axis):
312%D
313%D \startlinecorrection
314%D \startcombination[nx=2,ny=2,distance=4cm]
315%D     {\externalfigure[hacker][factor=max,maxwidth=6cm,maxheight=6cm]} {}
316%D     {\externalfigure[mill]  [factor=max,maxwidth=6cm,maxheight=6cm]} {}
317%D     {\externalfigure[hacker][factor=min,maxwidth=6cm,maxheight=6cm]} {}
318%D     {\externalfigure[mill]  [factor=min,maxwidth=6cm,maxheight=6cm]} {}
319%D \stopcombination
320%D \stoplinecorrection
321
322\def\m_grph_scale_factor_set{\v!min,\v!max,\v!fit,\v!broad,\v!auto} % can be an \edef
323
324\def\grph_scale_by_factor
325  {\doifelseinset\p_factor\m_grph_scale_factor_set
326     \grph_scale_by_factor_a
327     {\doifelseinset\p_hfactor\m_grph_scale_factor_set
328        \grph_scale_by_factor_b
329        {\doifelseinset\p_wfactor\m_grph_scale_factor_set
330           \grph_scale_by_factor_c
331           \grph_scale_by_factor_d}}}
332
333\def\grph_scale_by_factor_a
334  {\grph_scale_apply_size
335   \ifdim\d_grph_scale_x_size >\d_grph_scale_y_size
336     \grph_scale_calculate_norm  \d_grph_scale_used_x_size\p_factor\p_maxwidth\hsize\d_grph_scale_h_size
337     \grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
338     \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size
339   \else
340     \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
341     \grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
342     \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size
343   \fi
344   \grph_scale_by_factor_indeed}
345
346\def\grph_scale_by_factor_b
347  {\grph_scale_apply_size
348   \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
349   \grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
350   \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size
351   \grph_scale_by_factor_indeed}
352
353\def\grph_scale_by_factor_c
354  {\grph_scale_apply_size
355   \grph_scale_calculate_norm  \d_grph_scale_used_x_size\p_wfactor\p_maxwidth\hsize\d_grph_scale_h_size
356   \grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
357   \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size
358   \grph_scale_by_factor_indeed}
359
360\def\grph_scale_by_factor_d
361  {\grph_scale_calculate_norm\d_grph_scale_used_y_size\p_factor \p_height \textheight\d_grph_scale_v_size
362   \grph_scale_calculate_norm\d_grph_scale_used_y_size\p_hfactor\p_height \textheight\d_grph_scale_v_size
363   \grph_scale_calculate_norm\d_grph_scale_used_x_size\p_wfactor\p_width  \hsize     \hsize}
364
365\def\grph_scale_by_factor_indeed
366  {\grph_scale_calculate_fact\p_factor
367   \settrue\c_grph_scale_scaling_done
368   \ifconditional\c_grph_scale_limit_factors
369     \ifdim\d_grph_scale_used_x_size\ifconditional\c_grph_scale_swap_factor<\else>\fi\d_grph_scale_h_size
370       \global\d_grph_scale_used_y_size\zeropoint
371       \global\d_grph_scale_used_x_size\d_grph_scale_h_size
372     \else\ifdim\d_grph_scale_used_y_size\ifconditional\c_grph_scale_swap_factor<\else>\fi\d_grph_scale_v_size
373       \global\d_grph_scale_used_x_size\zeropoint
374       \global\d_grph_scale_used_y_size\d_grph_scale_v_size
375     \fi\fi
376   \fi
377   \grph_scale_by_dimension}
378
379\def\grph_scale_by_scale
380  {\edef\m_grph_scale_temp{\p_scale\p_xscale\p_yscale}%
381   \ifx\m_grph_scale_temp\empty \else
382     \grph_scale_apply_scale\m_grph_scale_used_x_scale\p_xscale
383     \grph_scale_apply_scale\m_grph_scale_used_y_scale\p_yscale
384   % \global\d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size\relax % no global needed here
385   % \global\d_grph_scale_used_y_size\m_grph_scale_used_y_scale\d_grph_scale_y_size\relax % no global needed here
386     % wrong: we need to recalculate the scale
387     \global\d_grph_scale_used_x_size\zeropoint
388     \global\d_grph_scale_used_y_size\zeropoint
389     %
390     \ifx\p_maxwidth\empty
391       \ifx\p_maxheight\empty
392       \else
393         \ifdim\d_grph_scale_y_size>\p_maxheight\relax
394           \global\d_grph_scale_used_y_size\p_maxheight
395         \fi
396       \fi
397     \else
398       \ifdim\d_grph_scale_x_size>\p_maxwidth\relax
399          \global\d_grph_scale_used_x_size\p_maxwidth
400       \fi
401     \fi
402   \fi}
403
404\def\grph_scale_by_dimension
405  {\ifdim\d_grph_scale_used_x_size>\zeropoint
406     \ifdim\d_grph_scale_used_y_size>\zeropoint
407       \grph_scale_by_dimension_a
408     \else
409       \grph_scale_by_dimension_b
410     \fi
411   \else
412     \ifdim\d_grph_scale_used_y_size>\zeropoint
413       \grph_scale_by_dimension_c
414     \else
415       \grph_scale_by_dimension_d
416     \fi
417   \fi}
418
419\def\grph_scale_by_dimension_a
420  {\grph_scale_by_dimension_indeed
421     {\grph_scale_calculate_scale\m_grph_scale_used_y_scale\d_grph_scale_used_y_size\d_grph_scale_y_size
422      \grph_scale_calculate_scale\m_grph_scale_used_x_scale\d_grph_scale_used_x_size\d_grph_scale_x_size}%
423     {\grph_scale_calculate_scale\m_grph_scale_used_y_scale\d_grph_scale_used_y_size\d_grph_scale_y_size
424      \grph_scale_calculate_scale\m_grph_scale_used_x_scale\d_grph_scale_used_x_size\d_grph_scale_x_size}%
425     {\grph_scale_calculate_scale\m_grph_scale_used_y_scale\d_grph_scale_used_y_size\d_grph_scale_y_size
426      \grph_scale_calculate_scale\m_grph_scale_used_x_scale\d_grph_scale_used_x_size\d_grph_scale_x_size}}
427
428\def\grph_scale_by_dimension_b
429  {\grph_scale_by_dimension_indeed
430     {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
431      \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size}%
432     {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
433      \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size}%
434     {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
435      \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size}}
436
437\def\grph_scale_by_dimension_c
438  {\grph_scale_by_dimension_indeed % weird .. three same cases
439     {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
440      \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size}%
441     {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
442      \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size}%
443     {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
444      \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size}}
445
446\def\grph_scale_by_dimension_d
447  {\grph_scale_by_dimension_indeed
448     {\grph_scale_apply_scale\m_grph_scale_used_x_scale\p_xscale
449      \grph_scale_apply_scale\m_grph_scale_used_y_scale\p_yscale
450      \global\d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size
451      \global\d_grph_scale_used_y_size\m_grph_scale_used_y_scale\d_grph_scale_y_size}%
452     {\grph_scale_calculate_scales\d_grph_scale_used_x_size\d_grph_scale_x_size
453      \d_grph_scale_used_y_size\m_grph_scale_used_x_scale\d_grph_scale_y_size}%
454     {\grph_scale_calculate_scales\d_grph_scale_used_y_size\d_grph_scale_y_size
455      \d_grph_scale_used_x_size\m_grph_scale_used_x_scale\d_grph_scale_x_size}}
456
457\def\grph_scale_by_dimension_indeed#1#2#3%
458  {#1\relax
459   \ifx\p_maxwidth\empty \else
460     \ifdim\d_grph_scale_used_x_size>\p_maxwidth\relax
461       \global\d_grph_scale_used_x_size\p_maxwidth
462       #2\relax
463     \fi
464   \fi
465   \ifx\p_maxheight\empty \else
466     \ifdim\d_grph_scale_used_y_size>\p_maxheight\relax
467       \global\d_grph_scale_used_y_size\p_maxheight
468        #3\relax
469     \fi
470   \fi}
471
472\def\grph_scale_calculate_norm#1#2% todo: swap 1 and 2 and pass one less
473  {\csname\??scalenorm\ifcsname\??scalenorm#2\endcsname#2\else\s!unknown\fi\endcsname#1#2}
474
475\def\grph_scale_calculate_fact#1%
476  {\csname\??scalefact\ifcsname\??scalefact#1\endcsname#1\else\s!unknown\fi\endcsname}
477
478%setvalue{\??scalenorm\v!min    }#1#2#3#4#5{\global#1#4}
479\setvalue{\??scalenorm\v!max    }#1#2#3#4#5{\global#1#4}
480\setvalue{\??scalenorm\v!fit    }#1#2#3#4#5{\global#1#5}
481\setvalue{\??scalenorm\v!broad  }#1#2#3#4#5{\global#1\dimexpr#5-4\externalfigureparameter\c!bodyfont\relax}
482\setvalue{\??scalenorm\s!unknown}#1#2#3#4#5{\global#1\dimexpr#2\dimexpr\externalfigureparameter\c!bodyfont/10\relax\relax} % brr ex
483\setvalue{\??scalenorm\v!auto   }#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi}
484\setvalue{\??scalenorm\empty    }#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi}
485\setvalue{\??scalenorm\s!default}#1#2#3#4#5{\ifx#3\empty\else\global#1#3\fi}
486
487\setvalue{\??scalefact\v!min    }{\global\settrue \c_grph_scale_swap_factor}
488\setvalue{\??scalefact\s!unknown}{\global\setfalse\c_grph_scale_swap_factor}
489
490% \setvalue{\??scalenorm\v!min    }#1#2#3#4#5% an ugly hack
491%   {\ifdim\d_grph_scale_used_x_size>\d_grph_scale_h_size
492%      \d_grph_scale_used_y_size\vsize
493%    \else
494%      \d_grph_scale_used_x_size\hsize
495%    \fi}
496
497\setvalue{\??scalenorm\v!min}#1#2#3#4#5% an ugly hack
498  {\d_grph_scale_used_x_size\hsize
499   \d_grph_scale_used_y_size\vsize}
500
501\def\grph_scale_calculate_scales#1#2%
502  {\edef\m_grph_scale_used_x_scale{\luaexpr{\number#1/\number#2}}%
503   \let\m_grph_scale_used_y_scale\m_grph_scale_used_x_scale}
504
505\def\grph_scale_calculate_scale#1#2#3%
506  {\edef#1{\luaexpr{\number#2/\number#3}}}
507
508\def\grph_scale_apply_scale#1#2% #1 = parameter / scale can be empty
509  {% no overflow
510   \edef#1{\luaexpr
511     {\number
512      \ifx#2\empty
513        \ifx  \p_scale \empty     \plusthousand \else
514        \ifnum\p_scale=\zerocount \plusthousand \else
515                                  \p_scale      \fi\fi
516      \else\ifnum#2=\zerocount
517        \ifx  \p_scale \empty     \plusthousand \else
518        \ifnum\p_scale=\zerocount \plusthousand \else
519                                  \p_scale      \fi\fi
520      \else
521                                  #2%
522      \fi\fi
523      /1000}}}
524
525\def\grph_scale_apply_size
526  {\ifx\p_maxheight\empty
527     \d_grph_scale_outer_v_size\textheight
528     \ifinner
529       \d_grph_scale_outer_v_size \vsize % \textheight =\vsize
530       \scratchdimen\vsize % \scratchdimen=\textheight
531     \else\ifinsidefloat
532       \d_grph_scale_outer_v_size \vsize % \textheight =\vsize
533       \scratchdimen\vsize % \scratchdimen=\textheight
534     \else\ifinpagebody
535       \d_grph_scale_outer_v_size \vsize % \textheight =\vsize
536       \scratchdimen\vsize % \scratchdimen=\textheight
537     \else % hm, there should be an option to force this
538       \ifdim\pagegoal<\maxdimen
539         \ifdim\pagetotal<\pagegoal
540           \scratchdimen\dimexpr\pagegoal-\pagetotal\relax
541         \else
542           \scratchdimen\d_grph_scale_outer_v_size % \textheight
543         \fi
544       \else
545         \scratchdimen\d_grph_scale_outer_v_size % \textheight
546       \fi
547     \fi\fi\fi
548   \else
549     \scratchdimen\p_maxheight
550     \d_grph_scale_outer_v_size\scratchdimen
551   \fi
552   \ifx\p_height\empty
553     \d_grph_scale_v_size\scratchdimen
554   \else
555     \d_grph_scale_v_size\p_height
556   \fi
557   \ifx\p_width\empty
558     \d_grph_scale_h_size\hsize
559   \else
560     \d_grph_scale_h_size\p_width
561   \fi}
562
563% \startcombination
564%     {\externalfigure[cow.pdf] [frame=on,height=3cm,equalwidth=6cm]} {a cow}
565%     {\externalfigure[mill.png][frame=on,height=3cm,equalwidth=6cm]} {a mill}
566% \stopcombination
567
568\def\grph_scale_position
569  {\ifx\p_equalwidth\empty \else
570    \scratchdimen\p_equalwidth\relax
571    \ifdim\d_grph_scale_wd<\scratchdimen
572      \setbox\nextbox\naturalhpack to \scratchdimen{\hss\box\nextbox\hss}%
573    \fi
574   \fi
575   \ifx\p_equalheight\empty \else
576     \scratchdimen\p_equalheight\relax
577     \ifdim\d_grph_scale_ht<\scratchdimen
578       \setbox\nextbox\naturalvpack to \scratchdimen{\vss\box\nextbox\vss}%
579     \fi
580   \fi}
581
582\unexpanded\def\fastscale#1%
583  {\ifnum#1=1000\relax
584     \expandafter\grph_scale_fast_nop
585   \else
586     \expandafter\grph_scale_fast_yes
587   \fi{#1}}
588
589\def\grph_scale_fast_nop#1%
590  {\hbox}
591
592\def\grph_scale_fast_yes#1%
593  {\edef\finalscaleboxxscale{\withoutpt\the\dimexpr#1\onepoint/1000\relax}% brrr
594   \let\finalscaleboxyscale\finalscaleboxxscale
595   \dowithnextboxcs\grph_scale_fast_finish\hbox}
596
597\def\grph_scale_fast_finish
598  {\grph_scale_apply
599   \box\nextbox
600   \endgroup}
601
602\unexpanded\def\fastsxsy#1#2%
603  {\bgroup
604   \edef\p_sx{#1}%
605   \edef\p_sy{#2}%
606   \dowithnextboxcs\grph_scale_fast_sx_xy_finish\hbox}
607
608% \def\grph_scale_fast_sx_xy_finish
609%   {\grph_scale_check_sx_sy
610%    \grph_scale_calculations_nop
611%    \grph_scale_apply
612%    \box\nextbox
613%    \egroup}
614
615\def\grph_scale_fast_sx_xy_finish
616  {\grph_scale_check_sx_sy
617   \d_grph_scale_wd\wd\nextbox
618   \d_grph_scale_ht\ht\nextbox
619   \d_grph_scale_dp\dp\nextbox
620   \grph_scale_calculations_nop
621   \grph_scale_apply
622   \box\nextbox
623   \egroup}
624
625%D \macros
626%D   {clip, setupclipping}
627%D
628%D Although related to figures, clipping can be applied to arbitrary content. We can
629%D use \METAPOST\ to provide a non rectangular clipping path.
630%D
631%D \starttyping
632%D \startMPclip{fun}
633%D   clip currentpicture to fullcircle
634%D     shifted (.5,.5) xscaled \width yscaled \height ;
635%D \stopMPclip
636%D \stoptyping
637%D
638%D We get a rectangular piece of the figure when we say:
639%D
640%D \starttyping
641%D \clip[x=2,y=1]{\externalfigure[photo]}
642%D \stoptyping
643%D
644%D When we want to clip to the oval we defined a few lines ago, we say:
645%D
646%D \starttyping
647%D \clip[nx=1,ny=1,x=1,y=1,mp=fun]{\externalfigure[photo]}
648%D \stoptyping
649%D
650%D The general characteristics of clipping can be set up with
651%D
652%D \showsetup{setupclipping}
653
654\installcorenamespace{clipping}
655
656\installdirectcommandhandler \??clipping {clipping}
657
658\unexpanded\def\clip
659  {\dosingleempty\grph_clip}
660
661\def\grph_clip[#1]% nb top->bottom left->right
662  {\bgroup
663   \iffirstargument
664     \setupcurrentclipping[#1]%
665   \fi
666   \dowithnextboxcs\grph_clip_finish\hbox}
667
668\def\grph_clip_finish
669  {\doifelse{\clippingparameter\c!state}\v!start
670     \grph_clip_yes_finish
671     \grph_clip_nop_finish}
672
673\def\grph_clip_yes_finish
674  {\ifdim\clippingparameter\c!width>\zeropoint
675     \scratchwidth  \clippingparameter\c!width
676     \scratchxoffset\clippingparameter\c!hoffset
677   \else
678     \scratchwidth\dimexpr\wd\nextbox/\clippingparameter\c!nx\relax
679     \scratchxoffset\dimexpr\clippingparameter\c!x\scratchwidth-\scratchwidth\relax
680     \scratchwidth\clippingparameter\c!sx\scratchwidth
681   \fi
682   \relax % sure
683   \ifdim\clippingparameter\c!height>\zeropoint
684     \scratchheight\clippingparameter\c!height
685     \scratchyoffset\dimexpr\ht\nextbox-\clippingparameter\c!voffset-\scratchheight\relax
686   \else
687     \scratchheight\dimexpr\ht\nextbox/\clippingparameter\c!ny\relax
688     \scratchyoffset\dimexpr-\clippingparameter\c!y\scratchheight-\clippingparameter\c!sy\scratchheight+\scratchheight\relax
689     \scratchheight\clippingparameter\c!sy\scratchheight
690     \advance\scratchyoffset \ht\nextbox
691   \fi
692   \setbox\nextbox\naturalhpack
693     {\advance\scratchxoffset -\clippingparameter\c!leftoffset  \relax
694      \advance\scratchyoffset -\clippingparameter\c!bottomoffset\relax
695      \hskip-\scratchxoffset
696      \lower\scratchyoffset
697      \box\nextbox}%
698   \wd\nextbox\zeropoint
699   \ht\nextbox\zeropoint
700   \dp\nextbox\zeropoint
701   \setbox\nextbox\naturalhpack
702     {\advance\scratchwidth \dimexpr\clippingparameter\c!leftoffset  +\clippingparameter\c!rightoffset\relax
703      \advance\scratchheight\dimexpr\clippingparameter\c!bottomoffset+\clippingparameter\c!topoffset  \relax
704      \dostartclipping{\clippingparameter\c!mp}\scratchwidth\scratchheight
705        \box\nextbox
706      \dostopclipping}%
707   \setbox\nextbox\naturalhpack
708     {\hskip-\clippingparameter\c!leftoffset
709      \lower \clippingparameter\c!bottomoffset
710      \box\nextbox}%
711   \wd\nextbox\scratchwidth
712   \ht\nextbox\scratchheight
713   \dp\nextbox\zeropoint
714   \box\nextbox
715   \egroup}
716
717\def\grph_clip_nop_finish
718  {\box\nextbox
719   \egroup}
720
721\setupclipping
722  [\c!state=\v!start,
723   \c!n=\plusone, % was \plustwo
724   \c!nx=\clippingparameter\c!n,\c!x=\plusone,\c!sx=\plusone,
725   \c!ny=\clippingparameter\c!n,\c!y=\plusone,\c!sy=\plusone,
726   \c!width=\zeropoint,
727   \c!height=\zeropoint,
728   \c!hoffset=\zeropoint,
729   \c!voffset=\zeropoint,
730   \c!offset=\zeropoint,
731   \c!leftoffset=\clippingparameter\c!offset,
732   \c!rightoffset=\clippingparameter\c!offset,
733   \c!topoffset=\clippingparameter\c!offset,
734   \c!bottomoffset=\clippingparameter\c!offset,
735   \c!mp=]
736
737%D \startbuffer
738%D \startuseMPgraphic{test}
739%D   path p ; p := fullcircle scaled 4cm ;
740%D   draw p withpen pencircle scaled 1cm ;
741%D   setbounds currentpicture to boundingbox p ;
742%D \stopuseMPgraphic
743%D
744%D \hbox to \hsize \bgroup
745%D   \hss
746%D   \ruledhbox{\useMPgraphic{test}}%
747%D   \hss
748%D   \ruledhbox{\clip{\useMPgraphic{test}}}%
749%D   \hss
750%D \egroup
751%D \stopbuffer
752%D
753%D \typebuffer \getbuffer
754
755%D Mirroring.
756
757\unexpanded\def\mirror
758  {\bgroup
759   \dowithnextboxcs\grph_mirror_finish\hbox}
760
761\def\grph_mirror_finish
762  {\scratchdimen\wd\nextbox
763   % better use an hbox (if no \forgetall, leftskip etc may creep in)
764   %\setbox\nextbox\vbox{\forgetall\dostartmirroring\hskip-\wd\nextbox\box\nextbox\dostopmirroring}%
765   \setbox\nextbox\naturalhpack
766     {\dostartmirroring
767      \hskip-\wd\nextbox
768      \box\nextbox
769      \dostopmirroring}%
770   \wd\nextbox\scratchdimen
771   \box\nextbox
772   \egroup}
773
774%D A couple of examples, demonstrating how the depth is taken care of:
775%D
776%D \startbuffer
777%D test\rotate[frame=on, rotation=0]  {gans}%
778%D test\rotate[frame=on, rotation=90] {gans}%
779%D test\rotate[frame=on, rotation=180]{gans}%
780%D test\rotate[frame=on, rotation=270]{gans}%
781%D test
782%D \stopbuffer
783%D
784%D \typebuffer \getbuffer
785%D
786%D When we rotate over arbitrary angles, we need to relocate the resulting box
787%D because rotation brings that box onto the negative axis. The calculations (mostly
788%D sin and cosine) need to be tuned for the way a box is packages (i.e. the refence
789%D point). A typical example of drawing, scribbling, and going back to the days of
790%D school math.
791%D
792%D We do a bit more calculations than needed, simply because that way it's easier to
793%D debug the code.
794
795\installcorenamespace {rotate}
796\installcorenamespace {rotatelocation}
797\installcorenamespace {rotatepreset}
798
799% todo: scratchcounters
800
801\newdimen\d_grph_rotate_x_size
802\newdimen\d_grph_rotate_y_size
803\newdimen\d_grph_rotate_x_offset
804\newdimen\d_grph_rotate_y_offset
805\newdimen\d_grph_rotate_x_position
806\newdimen\d_grph_rotate_y_position
807
808\newdimen\d_grph_rotate_used_height
809
810\let\d_grph_rotate_width \!!widtha
811\let\d_grph_rotate_height\!!heighta
812\let\d_grph_rotate_depth \!!deptha
813
814\let\d_grph_rotate_saved_width \!!widthb
815\let\d_grph_rotate_saved_height\!!heightb
816\let\d_grph_rotate_saved_depth \!!depthb
817
818\let\d_grph_rotate_new_width \!!widthc
819\let\d_grph_rotate_new_height\!!heightc
820\let\d_grph_rotate_new_depth \!!depthc
821
822\newconditional\c_grph_rotate_obey_depth
823\newconditional\c_grph_rotate_not_fit
824\newconditional\c_grph_rotate_center
825
826\installframedcommandhandler \??rotate {rotate} \??rotate
827
828\setuprotate
829  [\c!rotation=90,
830   \c!location=\v!normal,
831   \c!width=\v!fit,
832   \c!height=\v!fit,
833   \c!offset=\v!overlay,
834   \c!frame=\v!off]
835
836\let\p_rotation_location\empty
837\let\p_rotation_rotation\empty
838
839\unexpanded\def\rotate % \bgroup: \rotate kan argument zijn
840  {\bgroup
841   \dosingleempty\grph_rotate}
842
843\def\grph_rotate[#1]%
844  {\iffirstargument
845     \setupcurrentrotate[#1]%
846   \fi
847   \edef\p_rotation_location{\rotateparameter\c!location}%
848   \edef\p_rotation_rotation{\rotateparameter\c!rotation}%
849   \csname\??rotatelocation
850     \ifcsname\??rotatelocation\p_rotation_location\endcsname\p_rotation_location\else\v!default\fi
851   \endcsname}
852
853\def\grph_rotate_framed
854  {\resetrotateparameter\c!location
855   \dowithnextboxcs\grph_rotate_finish\vbox
856   \inheritedrotateframed}
857
858\def\grph_rotate_normal
859  {\dowithnextboxcs\grph_rotate_finish\vbox}
860
861\def\grph_rotate_finish
862  {\grph_rotate_finish_indeed
863   \egroup}
864
865\setvalue{\??rotatelocation\v!depth}%
866  {\setfalse\c_grph_rotate_not_fit
867   \setfalse\c_grph_rotate_center
868   \settrue \c_grph_rotate_obey_depth
869   \grph_rotate_normal}
870
871\setvalue{\??rotatelocation\v!fit}%
872  {\settrue \c_grph_rotate_not_fit
873   \setfalse\c_grph_rotate_center
874   \settrue \c_grph_rotate_obey_depth
875   \grph_rotate_normal}
876
877\setvalue{\??rotatelocation\v!broad}%
878  {\setfalse\c_grph_rotate_not_fit
879   \setfalse\c_grph_rotate_center
880   \setfalse\c_grph_rotate_obey_depth
881   \grph_rotate_normal}
882
883\setvalue{\??rotatelocation\v!high}%
884  {\setfalse\c_grph_rotate_not_fit
885   \setfalse\c_grph_rotate_center
886   \setfalse\c_grph_rotate_obey_depth
887   \grph_rotate_framed}
888
889\setvalue{\??rotatelocation\v!middle}%
890  {\setfalse\c_grph_rotate_not_fit
891   \settrue \c_grph_rotate_center
892   \setfalse\c_grph_rotate_obey_depth  % hm, depth ?
893   \grph_rotate_normal}
894
895\setvalue{\??rotatelocation\v!default}%
896  {\setfalse\c_grph_rotate_not_fit
897   \setfalse\c_grph_rotate_center
898   \settrue \c_grph_rotate_obey_depth
899   \grph_rotate_framed}
900
901\unexpanded\def\dorotatebox#1% {angle} \hbox/\vbox/\vtop % a fast low level one
902  {\ifcase#1\relax
903     \expandafter\gobbleoneargument
904   \else
905     \expandafter\grph_rotate_box
906   \fi{#1}}
907
908\def\grph_rotate_box#1% {angle} \hbox/\vbox/\vtop
909  {\bgroup
910   \hbox\bgroup % compatibility hack
911     \edef\p_rotation_rotation{#1}%
912     \dowithnextboxcs\grph_rotate_finish_box}
913
914\def\grph_rotate_finish_box
915  {\setfalse\c_grph_rotate_not_fit      % this is the same as broad but
916   \setfalse\c_grph_rotate_center       % without the following grab as
917   \setfalse\c_grph_rotate_obey_depth   % we call finish directly
918   \grph_rotate_finish_indeed
919   \egroup
920   \egroup}
921
922\def\grph_rotate_finish_indeed
923  {\naturalhpack\bgroup
924     \ifx\p_rotation_rotation\empty
925       \grph_rotate_finish_nop
926     \else
927       \grph_rotate_finish_yes
928     \fi
929   \egroup}
930
931\def\grph_rotate_finish_nop
932  {\boxcursor\box\nextbox}
933
934\setvalue{\??rotatepreset\v!left}%
935  {\edef\p_rotation_rotation{90}}
936
937\setvalue{\??rotatepreset\v!right}%
938  {\edef\p_rotation_rotation{270}}
939
940\setvalue{\??rotatepreset\v!inner}%
941  {\signalrightpage
942   \doifelserightpage{\def\p_rotation_rotation{270}}{\def\p_rotation_rotation{90}}}
943
944\setvalue{\??rotatepreset\v!outer}%
945  {\signalrightpage
946   \doifelserightpage{\def\p_rotation_rotation{90}}{\def\p_rotation_rotation{270}}}
947
948\setvalue{\??rotatepreset\v!default}%
949  {}
950
951\def\grph_rotate_finish_yes
952  {\begincsname\??rotatepreset\p_rotation_rotation\endcsname
953   \setbox\nextbox\naturalvpack{\box\nextbox}% not really needed
954   \dontcomplain
955   \ifconditional\c_grph_rotate_center
956     \d_grph_rotate_saved_width \wd\nextbox
957     \d_grph_rotate_saved_height\ht\nextbox
958     \d_grph_rotate_saved_depth \dp\nextbox
959     \setbox\nextbox\naturalhpack{\hskip-.5\wd\nextbox\lower.5\ht\nextbox\box\nextbox}%
960     \smashbox\nextbox
961   \fi
962   %
963   \d_grph_rotate_width \wd\nextbox
964   \d_grph_rotate_height\ht\nextbox
965   \d_grph_rotate_depth \dp\nextbox
966   %
967   \setbox\nextbox\naturalvpack{\naturalhpack{\raise\dp\nextbox\box\nextbox}}% can we do without
968   %
969   \d_grph_rotate_used_height\ht\nextbox
970   %
971   \clf_analyzerotate % rather accurate
972     \p_rotation_rotation\space
973     \d_grph_rotate_width
974     \d_grph_rotate_height
975     \d_grph_rotate_depth
976     \d_grph_rotate_used_height
977     \c_grph_rotate_not_fit
978     \c_grph_rotate_obey_depth
979   \relax
980   %
981   \setbox\nextbox\naturalvpack to \d_grph_rotate_y_size
982     {\vfilll
983      \naturalhpack to \d_grph_rotate_x_size
984        {\dostartrotation\p_rotation_rotation
985           \wd\nextbox\zeropoint
986           \ht\nextbox\zeropoint
987           \box\nextbox
988         \dostoprotation
989         \hfill}%
990      \kern\d_grph_rotate_y_position}%
991   %
992   \setbox\nextbox\naturalhpack
993     {\kern\dimexpr\d_grph_rotate_x_position+\d_grph_rotate_x_offset\relax
994      \lower\d_grph_rotate_y_offset
995      \box\nextbox}%
996   %
997   \ifconditional\c_grph_rotate_center
998     \setbox\nextbox\naturalhpack{\hskip.5\d_grph_rotate_saved_width\lower-.5\d_grph_rotate_saved_height\box\nextbox}%
999     \wd\nextbox\d_grph_rotate_saved_width
1000     \ht\nextbox\d_grph_rotate_saved_height
1001     \dp\nextbox\d_grph_rotate_saved_depth
1002   \else
1003     \wd\nextbox\d_grph_rotate_new_width
1004     \ht\nextbox\d_grph_rotate_new_height
1005     \dp\nextbox\d_grph_rotate_new_depth
1006   \fi
1007   %
1008   \boxcursor\box\nextbox}
1009
1010% \dostepwiserecurse{0}{360}{10}
1011%   {\startlinecorrection[blank]
1012%    \hbox
1013%      {\expanded{\setuprotate[rotation=\recurselevel]}%
1014%       \traceboxplacementtrue
1015%       \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=depth] {\ruledhbox{\bfb  (depth)}}}}%
1016%       \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=fit]   {\ruledhbox{\bfb    (fit)}}}}%
1017%       \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=broad] {\ruledhbox{\bfb  (broad)}}}}%
1018%       \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=normal]{\ruledhbox{\bfb (normal)}}}}%
1019%       \hbox to .2\hsize{\hss\ruledhbox{\rotate[location=high]  {\ruledhbox{\bfb   (high)}}}}}
1020%    \stoplinecorrection}
1021
1022% \def\Test{\ruledhbox{%
1023%     \def\DemoX{\vl\kern.5\emwidth\vl}%
1024%     \kern\emwidth\ruledhpack{\green\rotate[rotation=20]  {\ruledhpack{\DemoX}}}%
1025%     \kern\emwidth\ruledhpack{\blue \rotate[rotation=0]   {\ruledhpack{\DemoX}}}%
1026%     \kern\emwidth\ruledhpack{\red  \rotate[rotation=-20] {\ruledhpack{\DemoX}}}%
1027%     \kern\emwidth\ruledhpack{\green\rotate[rotation=200] {\ruledhpack{\DemoX}}}%
1028%     \kern\emwidth\ruledhpack{\blue \rotate[rotation=180] {\ruledhpack{\DemoX}}}%
1029%     \kern\emwidth\ruledhpack{\red  \rotate[rotation=-200]{\ruledhpack{\DemoX}}}%
1030%     \kern\emwidth}}
1031
1032% \startTEXpage[offset=10pt,align=middle]
1033%     \setuprotate[location=fit]     \Test \par {\infofont\setstrut\strut fit}     \par
1034%     \setuprotate[location=depth]   \Test \par {\infofont\setstrut\strut depth}   \par
1035%     \setuprotate[location=broad]   \Test \par {\infofont\setstrut\strut broad}   \par
1036%     \setuprotate[location=high]    \Test \par {\infofont\setstrut\strut high}    \par
1037%     \setuprotate[location=middle]  \Test \par {\infofont\setstrut\strut middle}  \par
1038%     \setuprotate[location=default] \Test \par {\infofont\setstrut\strut default} \par
1039% \stopTEXpage
1040
1041\protect \endinput
1042