2

The following code comes from this SE query: Can I centre my oversized coffin of unknown width?. It was posted by @cfr and accompanied by output, so, presumably, it worked at one time:

\begin{filecontents}{pic.tex}
\documentclass{standalone}
\begin{document}
\begin{tikzpicture}
  \shade [left color=Cerulean, right color=Cerulean, middle color=MidnightBlue] (0,0) rectangle (200mm,10mm);
\end{tikzpicture}
\end{document}
\end{filecontents}
\documentclass[a4paper,x11names,svgnames,dvipsnames]{article}
\usepackage{geometry,standalone,tikz,xcoffins,calc}
\begin{document}
\NewCoffin\TestCoffin
\SetHorizontalCoffin\TestCoffin{\input{pic}}

\MarkCoffinHandle\TestCoffin[hc,vc]{magenta}
\MarkCoffinHandle\TestCoffin[l,vc]{magenta}

Can I centre the coffin \emph{without} knowing the width of the picture?

This works:\par
\noindent
\TypesetCoffin\TestCoffin[l,vc](-.5\CoffinWidth\TestCoffin+.5\textwidth,0pt)
\bigskip

This doesn't:\par
{\centering
  \TypesetCoffin\TestCoffin[hc,vc]\par}


\end{document}

When I run that code now, it fails with the following error:

./Coffin_mwe_001.tex:22: Illegal unit of measure (pt inserted).
<to be read again> 
                   .
l.22 ...5\CoffinWidth\TestCoffin+.5\textwidth,0pt)

If I delete the fractional factor .5 from -.5\CoffinWidth\TestCoffin to make it -\CoffinWidth\TestCoffin/2 then the code works, though division by non-integers, not surprisingly, does not work. Note also that integer factors to \CoffinWidth also work correctly.

I cannot seem to find discussion of this on SE. Is there a workaround?

sgmoye
  • 8,586
  • Easiest way to centre almost anything without knowing its width: \begin{center}\makebox[0pt][c]{<almost anything>}\end{center}. Most likely this results from the parsing rules of \dimexpr. Take a look here. – Skillmon Nov 07 '18 at 17:48
  • My question is not about centering anything, but about non-integer factors to \CoffinWidth. I'll make my question more specific. – sgmoye Nov 07 '18 at 17:51
  • 1
    You can give a non-integer factor with .5\dimexpr\CoffinWidth\TestCoffin\relax as a workaround. – Skillmon Nov 07 '18 at 17:56
  • Odd. Well, make it into an answer and I'll accept it. – sgmoye Nov 07 '18 at 18:00
  • \CoffinWidth expands to \dim_eval:n { \coffin_wd:N #1 }. \dim_eval:n expands to \dim_use:N \__dim_eval:w #1\__dim_eval_end: which is the same as \the\dimexpr#1\relax. And you can't use a factor on \the. So we have to somehow turn this back into something where we can use a factor on. That something can be a \dimexpr without a \the before it. – Skillmon Nov 07 '18 at 18:00
  • OK, but integer factors do work correctly. Again, odd. – sgmoye Nov 07 '18 at 18:03
  • I should also point out that TeX is having a problem with the .. Neither the - nor the number seem to be the problem. – sgmoye Nov 07 '18 at 18:11
  • Just wait a few more minutes, I'm formulating a longish answer... – Skillmon Nov 07 '18 at 18:13
  • Just to be clear: If I say -2\CoffinWidth\TestCoffin the code TeXs so the problem would seem to be fractional factors. The \dimexpr trick does work. – sgmoye Nov 07 '18 at 18:20
  • 1
    I know, now wait! – Skillmon Nov 07 '18 at 18:22

1 Answers1

4

Explanation why it doesn't work:

\CoffinWidth is defined as \dim_eval:n { \coffin_wd:N #1 }. \dim_eval:n expands to \dim_use:N \__dim_eval:w #1\__dim_eval_end: so the above becomes \dim_use:N \__dim_eval:w \coffin_wd:N #1\__dim_eval_end:. That is (removing the l3 nomenclature) the same as \the\dimexpr\wd#1\relax.

You're using that inside of the optional argument of \TypesetCoffin which is again a \dimexpr so something like \dimexpr\the\dimexpr\wd\TestCoffin\relax\relax. In the following I'll drop the outer \dimexpr occasionally, I hope it is still understandable.

\the\dimexpr\wd#1\relax would expand to something like <float>pt. In the following let us assume that <float> is the (rather unspectacular) float 1.0. Note that \the\<dimen> always returns a period even if it won't make a different (so if the only decimal digit is a 0). Now with our example we take a look at what happens if you precede it with a factor:

Choosing an integer factor (let's take 2) what you get is 21.0pt, which is valid but certainly not the double of 1.0pt. Using another float as the factor (let's take 0.5) you get 0.51.0pt which is not a valid length, hence the error.

What do we do now? One way would be to use a division with an integer of 2 (putting back the outer \dimexpr and replacing the inner one with our exemplary 1.0pt): \dimexpr 1.0pt/2\relax is valid input. Another way would be to use multiplication, again only with integers: \dimexpr1.0pt*2\relax is still valid. But what if we want to use a float as the factor? We have to turn the thing back into something TeX considers a dimen, which is why we use \dimexpr around the inner expression: .5\dimexpr 1.0pt\relax is again valid.

Turning it into a working bit of code that does the intended thing:

With the wrapping of \dimexpr we considered a viable solution above your code becomes:

\TypesetCoffin\TestCoffin[l,vc](-.5\dimexpr\CoffinWidth\TestCoffin\relax+.5\textwidth,0pt)

And we're done. Complete MWE:

\begin{filecontents}{pic.tex}
\documentclass{standalone}
\begin{document}
\begin{tikzpicture}
  \shade [left color=Cerulean, right color=Cerulean, middle color=MidnightBlue] (0,0) rectangle (200mm,10mm);
\end{tikzpicture}
\end{document}
\end{filecontents}
\documentclass[a4paper,x11names,svgnames,dvipsnames]{article}
\usepackage{geometry,standalone,tikz,xcoffins,calc}
\begin{document}
\NewCoffin\TestCoffin
\SetHorizontalCoffin\TestCoffin{\input{pic}}

\MarkCoffinHandle\TestCoffin[hc,vc]{magenta}
\MarkCoffinHandle\TestCoffin[l,vc]{magenta}

Can I centre the coffin \emph{without} knowing the width of the picture?

This works:\par
\noindent
\TypesetCoffin\TestCoffin[l,vc](-.5\dimexpr\CoffinWidth\TestCoffin\relax+.5\textwidth,0pt)
\bigskip

This doesn't:\par
{\centering
  \TypesetCoffin\TestCoffin[hc,vc]\par}


\end{document}
Skillmon
  • 60,462
  • 2
    I hope the description does not only make sense in my own brain... – Skillmon Nov 07 '18 at 18:29
  • I understand and have accepted your answer, and, moreover, I have a workaround -- mission accomplished. The only lingering question I have is why, in 2017, did something like 0.5\CoffinWidth work? Was that an error? A fluke? – sgmoye Nov 07 '18 at 18:39
  • 1
    @sgmoye I don't know for sure, as I don't like to investigate it atm, but I guess there was a change in the underlying macros or in \CoffinWidth. With the knowledge from the first paragraph in my answer (that \CoffinWidth is essentially \the\dimexpr\wd#1\relax) one could as well just use .5\wd\TestCoffin as a solution, but I don't know whether this would still work in the distant future but I hope that the used workaround (adding \dimexpr...\relax) will still work in a reasonable amount of time from now on. – Skillmon Nov 07 '18 at 18:43