4

Using Steven B. Segletes's answer, I can centre something horizontally, optionally rotating it, using

\centering
\makebox[0pt]{\rotatebox{<angle>}{<contents>}}
\par

However, I would also like to specify that the box have a specified height. Moreover, since I am doing this using a command which already uses expl3 syntax, I thought that it might make sense to try to use expl3 functions. (However, I'm not wedded to this idea - my macros are already a witch's brew of TeX, LaTeX2e and expl3 syntax, so a little more really isn't going to hurt anything which I'm not offending against already.)

I can get the effect I want using the following:

\documentclass[a4paper]{article}
\usepackage{expl3,xparse,geometry}
\geometry{margin=20mm}
\ExplSyntaxOn
\tl_new:N \l_cfr_troibocs_tl
\bool_new:N \l_cfr_bocs_bool
\keys_define:nn { mycommand }
{
  hfit .bool_set:N = \l_cfr_hfit_bool,
  hfit .default:n = true,
  vfit .bool_set:N = \l_cfr_vfit_bool,
  vfit .default:n = true,
  rotate .code:n = {
    \tl_set:Nn \l_cfr_troibocs_tl {#1}
    \bool_set_true:N \l_cfr_troi_bool },
  troi .bool_set:N = \l_cfr_troi_bool,
  troi .default:n = true,
  troibocs .tl_set:N = \l_cfr_troibocs_tl,
  troibocs .initial:n = 0,
}
\NewDocumentCommand\mycommand { o m }{
  \group_begin:
  \IfValueT{#1}{ \keys_set:nn { mycommand } { #1 } }
  % from Steven B. Segletes's answer at https://tex.stackexchange.com/a/162202/
    \bool_if:NTF \l_cfr_troi_bool
    {
      \hbox_set:Nn \g_tmpa_box {\rotatebox[]{\l_cfr_troibocs_tl}{\file_input:n {#2}}}
    }
    {
      \hbox_set:Nn \g_tmpa_box {\file_input:n {#2}}
    }
    \bool_if:NT \l_cfr_vfit_bool
    {
      \box_set_ht:Nn \g_tmpa_box {.8\textheight}
    }
    \centering
    \bool_if:NTF \l_cfr_hfit_bool
    {
      \makebox[0pt]{\box_use:N \g_tmpa_box}
    }{
      \box_use:N \g_tmpa_box
    }
    \par
  \group_end:
}
\ExplSyntaxOff
\usepackage{filecontents,tikz}
\begin{filecontents}{mytikz.tex}
  \begin{tikzpicture}
    \path [draw, fill] (0,0) rectangle +(265mm,175mm);
  \end{tikzpicture}
\end{filecontents}

\begin{document}
\mycommand[
  rotate=90,
  vfit,
  hfit
  ]{mytikz}
\end{document}

Is there a better/cleaner way of doing this?

My attempts to translate more of the definition into expl3 syntax have so far met with abject failure. I suspect my difficulties are related to egreg's answer but I'm not sure, and I'm not sure how to modify the code anyway.

If I use \hbox_to_zero:n, then the box is not centred horizontally but I cannot just put \leavemode before it in this context as that will just break things completely. Nor can I alter the width of the box as I alter the height, since \box_set_wd:Nn \g_tmpa_box {0pt} has no effect.

[I've also tried to replace the \rotatebox with the new experimental extension \box_rotate:Nn but that behaves bizarrely, relative to my expectations, so I've abandoned that idea.]

  • Only height or also depth? The \centering seems completely out of place. – egreg Apr 26 '15 at 16:08
  • @egreg Well, total height, I suppose. So both. But it seems to work just setting the height. I want the height+depth to be set as .8\textheight regardless of what is actually in the box. Since what's in the box is likely to be a tikzpicture, I think the depth is probably not making much difference? But I'm not good with boxes. – cfr Apr 26 '15 at 16:12
  • @egreg I didn't mean to have 2 \centering. But if I don't have \centering at all, the picture is not centred. – cfr Apr 26 '15 at 16:16
  • I believe you should better explain what the keys should do. – egreg Apr 26 '15 at 16:23
1

If I understand well your requirement, standard methods suffice:

\documentclass{article}
\usepackage{graphicx,lipsum,color}

\newcommand\rotbox[3][\dimexpr\height+\depth\relax]{%
  % #1 is the final height, #2 is the angle, #3 the contents
  \raisebox{\depth}[#1][0pt]{%
    \makebox[0pt]{%
      \rotatebox{#2}{\color{red}#3}%
    }%
  }%
}

\begin{document}

\lipsum[3]
\begin{center}
XX\rotbox{45}{This text is rotated}XX
\end{center}
\lipsum*[2]
\begin{center}
XX\rotbox[4cm]{45}{This text is rotated}XX
\end{center}
\lipsum[2]

\end{document}

I added the red color just for better clarity. If you want to have the natural width (after rotation), drop the \makebox[0pt].

enter image description here

A possible expl3 version:

\documentclass{article}
\usepackage{graphicx,lipsum,color,xparse}

\ExplSyntaxOn
\NewDocumentCommand{\xrotbox}{O{}m}
 {
  \group_begin:
  \keys_set:nn { cfr/rotbox } { #1 }
  \cfr_xrotbox:n { #2 }
  \group_end:
 }

\keys_define:nn { cfr/rotbox }
 {
  hfit .bool_set:N = \l_cfr_hfit_bool,
  hfit .default:n = true,
  vfit .bool_set:N = \l_cfr_vfit_bool,
  vfit .default:n = true,
  rotate .fp_set:N = \l_cfr_rotate_fp,
  rotate .initial:n = 0,
  %troi .bool_set:N = \l_cfr_troi_bool,
  %troi .default:n = true,
  %troibocs .tl_set:N = \l_cfr_troibocs_tl,
  %troibocs .initial:n = 0,
 }

\box_new:N \l_cfr_xrotbox_box

\cs_new_protected:Npn \cfr_xrotbox:n #1
 {
  \hbox_set:Nn \l_cfr_xrotbox_box { #1 }
  \fp_compare:nF { \l_cfr_rotate_fp = \c_zero_fp }
   {
    \box_rotate:Nn \l_cfr_xrotbox_box { \l_cfr_rotate_fp }
   }
  \hbox_set:Nn \l_cfr_xrotbox_box
   {
    \box_move_up:nn { \box_dp:N \l_cfr_xrotbox_box } { \box_use:N \l_cfr_xrotbox_box }
   }
  \bool_if:NF \l_cfr_hfit_bool
   {
    \hbox_set_to_wd:Nnn \l_cfr_xrotbox_box { 0pt }
     {
      \hss \box_use:N \l_cfr_xrotbox_box \hss
     }
   }
  \bool_if:NF \l_cfr_vfit_bool
   {
    \box_set_ht:Nn \l_cfr_xrotbox_box { 0pt }
   }
  \leavevmode\box_use:N \l_cfr_xrotbox_box
 }
\ExplSyntaxOn

\begin{document}

\lipsum[3]
\begin{center}
XX\xrotbox[rotate=45]{This text is rotated}XX
\end{center}
\lipsum*[2]
\begin{center}
XX\xrotbox[rotate=45,hfit,vfit]{This text is rotated}XX
\end{center}
\lipsum[2]

\end{document}

enter image description here

  • Thanks! This was very helpful even though it didn't actually work. The expl3 enabled me to figure out enough to produce something which seems to work. I guess my original version is more compact, but it feels wrong to have that in the middle of a block of expl3 syntax, even though there is plenty of similar in the same file (and, indeed in the same command). I'm not sure whether I should post a version of what I actually got to work but accept this answer, or whether I should just accept this answer. – cfr Apr 26 '15 at 19:14
  • @cfr As I said, without really knowing what the keys are expected to do, it's difficult to guess. – egreg Apr 26 '15 at 19:23
  • Yes, I know. I was trying not to explain a bunch of irrelevant stuff and I think I ended up leaving too much to the reader's imagination. Sorry. – cfr Apr 26 '15 at 19:30
  • I've posted my mangled version, as well. I figure I can always delete it later. – cfr Apr 26 '15 at 20:02
1

This is based on egreg's answer but is adapted to what I actually wanted to do. I'm afraid that my original question did not sufficiently explain the context and was therefore unclear. As such, I think egreg's answer a perfectly good one. However, in case it is useful to anybody else, I'm also posting the code which I came up with by adapting that answer.

The point of the code is to typeset an image which is really too large for the space available, but which actually fits from a human (non-TeX) perspective. For example, a mind map can overflow the page area slightly without 'looking' too large because it contains a reasonable amount of empty space.

The command I'm actually using to do this inputs a file and optionally typesets a title and subtitle, entry for the ToC and bibliography. Normally, what is input is mostly text. However, I wanted to use the same command to typeset a single page image with a title so that I could ensure consistency of formatting etc. In this case, the contents of the file gets put in a box and further manipulated, whereas in the standard case it is just input normally.

The code below just concerns the image case. That is, it doesn't bother differentiating the regular case from the image case or worrying about the title, ToC or bibliography.

\mycommand[]{} takes an optional argument consisting of 0 to 3 keys:

  • rotate=<angle> if the contents should be rotated;
  • hfit if the contents should be forced to fit horizontally by centring it in a box of 0pt width;
  • vfit if the contents should be forced to fit vertically by setting it in a box of height .8\textheight plus half the difference between the natural height of the box and .8\textheight.

The mandatory argument is the name of the file to be input e.g. the name of the file containing the tikzpicture for a mind map.

The example picture is a little wider than \textheight and a little taller than \textwidth. Hence, even when rotated, it is too large as far as TeX is concerned. (Since it is a single black box, it also looks too big to a human. But the point is that it has dimensions sufficiently similar to the species of image I'm concerned with.)

I'm not sure this is really correct, but the full version of it seems to work so far....

\documentclass[a4paper]{article}
\usepackage{expl3,xparse,geometry}
\geometry{margin=20mm}
\ExplSyntaxOn
\fp_new:N \l_cfr_troibocs_fp
\bool_new:N \l_cfr_bocs_bool
\dim_zero_new:N \l_cfr_width_dim
\box_new:N \l_cfr_bocs_box
\NewDocumentCommand\mycommand{O{}m}
 {
  \group_begin:
  \centering
  \keys_set:nn { cfr/rotbox } { #1 }
  \cfr_troibocs:n { 0pt } { .8\textheight } { #2 }
  \par
  \group_end:
 }

\keys_define:nn { cfr/rotbox }
 {
  hfit .bool_set:N = \l_cfr_hfit_bool,
  hfit .default:n = true,
  vfit .bool_set:N = \l_cfr_vfit_bool,
  vfit .default:n = true,
  rotate .fp_set:N = \l_cfr_troibocs_fp,
  rotate .initial:n = 0,
 }
\cs_new_protected:Npn \cfr_troibocs:n #1 #2 #3
 {
  \hbox_set:Nn \l_cfr_bocs_box { #3 }
  \fp_compare:nF { \l_cfr_troibocs_fp = \c_zero_fp }
   {
    \box_rotate:Nn \l_cfr_bocs_box { \l_cfr_troibocs_fp }
   }
  \hbox_set:Nn \l_cfr_bocs_box
   {
    \box_move_up:nn { \box_dp:N \l_cfr_bocs_box } { \box_use:N \l_cfr_bocs_box }
   }
  \bool_if:NT \l_cfr_hfit_bool
   {
    \hbox_set_to_wd:Nnn \l_cfr_bocs_box { #1 }
     {
      \hss \box_use:N \l_cfr_bocs_box \hss
     }
   }
  \bool_if:NT \l_cfr_vfit_bool
   {
     \dim_set:Nn \l_cfr_width_dim { \box_ht:N \l_cfr_bocs_box }
     \dim_sub:Nn \l_cfr_width_dim { #2 }
     \dim_compare:nNnT {0pt} < \l_cfr_width_dim
     {
       \vbox_set_to_ht:Nnn \l_cfr_bocs_box { #2 + .5\l_cfr_width_dim }
         {
           \vss \box_use:N \l_cfr_bocs_box \vss
         }
     }
   }
  \leavevmode\box_use:N \l_cfr_bocs_box
 }
\ExplSyntaxOff
\usepackage{filecontents,tikz}
\begin{filecontents}{mytikz.tex}
  \begin{tikzpicture}
    \path [draw, fill] (0,0) rectangle +(265mm,175mm);
  \end{tikzpicture}
\end{filecontents}

\begin{document}
\mycommand[
  rotate=90,
  hfit,
  vfit
  ]{\input{mytikz}}
\end{document}

dummy output

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.