# Workaround for “dimension too large” for short, custom decorated, arcs?

I have already seen Avoiding Dimension too large' and ill-formatted floating point' errors in tikz, and probably there is no answer, but let's see...

I have this MWE, with a custom decoration, which can be applied to an arc, but not a short arc:

\documentclass[varwidth,tightpage,border=1bp]{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations}
\usepackage{trace}

\pagecolor{yellow!15} % ignored with preview, but not w/ varwidth

\makeatletter
\pgfkeys{/tikz/.cd, %
/pgf/decoration/deccrosslw/.store in=\deccrosslw, %
/pgf/decoration/deccrosslw=0.2cm, %
/pgf/decoration/deccrosslen/.store in=\deccrosslen, %
/pgf/decoration/deccrosslen=1pt, %
}
\pgfdeclaredecoration{deccross}{initial}
{
\state{initial}[width=\deccrosslen]
{
\pgfpointdecoratedinputsegmentlast
\pgfgetlastxy{\dcplx}{\dcply} % grab coords in macros
\typeout{initial \deccrosslen, \pgfdecoratedinputsegmentlength, dcpl \dcplx, \dcply} % print coords to stdout
\pgfpathmoveto{\pgfpoint{0pt}{0pt}} % already done, but anyway
\pgfpathlineto{\pgfpoint{\deccrosslen}{0pt}} % trace the actual line out (along "x" axis)
% cross out
\pgfpathmoveto{\pgfpoint{0pt}{0pt}}
\pgfpathlineto{\pgfpoint{0.5*\deccrosslen}{0.5*\deccrosslw}}
\pgfpathlineto{\pgfpoint{\deccrosslen}{0pt}}
\pgfpathmoveto{\pgfpoint{0pt}{0pt}}
\pgfpathlineto{\pgfpoint{0.5*\deccrosslen}{-0.5*\deccrosslw}}
\pgfpathlineto{\pgfpoint{\deccrosslen}{0pt}}
}
\state{final}
{
\pgfpathlineto{\pgfpointdecoratedpathlast}
}
}
\makeatother

\begin{document}

Hello:

\begin{tikzpicture}

\draw[]
(0,0) -- (1,0);
\draw[decoration={deccross,deccrosslen=5pt,deccrosslw=0.5cm},decorate]
(0,1) -- (1,1);
\draw[decoration={deccross,deccrosslen=2pt},decorate]
(0,2) -- (1pt,2); % short - no problem

\draw[] (2,0) -- ++(0,2cm)
arc (90:45:2cm) ;

\draw[] (4,0) -- ++(0,2cm)
coordinate(cs)
decorate[decoration={deccross}]{ arc (90:45:2cm) }
coordinate(ce);

%\traceon
\draw[decoration={deccross},decorate]
(cs)
%arc (90:92:2cm) % ! Dimension too large. <to be read again> \relax
arc (90:97:2cm) % 90:97 ok, 90:96 dimension too large
;

\end{tikzpicture}
\end{document}


When the code works, as in the paste above, this is what is generated:

But if the short arc (90:92:2cm) is uncommented, then there is a crash with ! Dimension too large.. This is exactly referred in Avoiding Dimension too large' and ill-formatted floating point' errors in tikz :

There is not much you can do. ... Because TeX can't handle the computations you throw at it. Because of very old but still shiny gears can't crunch anything that precise. By that I mean very tiny arc length due to your line width specification (It's too thick for such arc).

It may be that it is the same problem here, but still - I do use a line width, which is actually thin? Also, note there is no problem with a short line - only with a short arc...

I tried to trace a bit, and I've tried to reconstruct a "stack trace" (see selected copypaste below); it seems like there is a \pgfmathloop to do the decoration, where \pgfmathveclen@ is called, which calls \pgfmathreciprocal@, which is what ultimately crashes.

Is there anything I could do - maybe by coding a special case in my custom decoration - to have the code not crash on short arcs?

Here is the snippet from the trace:

\pgfmathloop #1\repeatpgfmathloop ->\def \pgfmathcounter {1}\def \pgfmath@itera
...
#1<-\advance \pgf@xb \c@pgf@counta \pgf@yb \edef \pgf@decorate@temp {\pgf@xa \t
...
\pgf@y -\pgf@yc \pgfmathveclen@ {\pgfmath@tonumber {\pgf@x }}{\pgfmath@tonumbe
...
...
\pgfmathveclen@ #1#2->\begingroup \pgfmath@x #1pt\relax \pgfmath@y #2pt\relax \
...
fmathreciprocal@ {\pgfmath@tonumber {\pgfmath@y }}\pgfmath@x \pgfmathresult \pg
...
#1<-\pgfmath@tonumber {\pgf@x }
#2<-\pgfmath@tonumber {\pgf@y }
...
...
\pgfmath@reciprocaltemp ->0.00006

\pgfmathreciprocal@@ #1.#2#3#4#5#6#7\pgfmath@ ->\c@pgfmath@counta #2#3#4#5#6\re
...
returnone \pgfmath@x \endgroup
#1<-0
#2<-0
#3<-0
#4<-0
#5<-0
#6<-6
#7<-0000000
...
{\count91}
{changing \count91=6}
{into \count91=166666666}
{\divide}
{changing \count91=166666666}
{into \count91=16666}
{\relax}
{\dimen107}
! Dimension too large.
\relax
\pgfmathreciprocal@@ ...c@pgfmath@counta pt\relax

-

Well, I wanted a workaround - here is a workaround :), although I'd really love to know if there is a more proper way of doing this. This workaround produces the output below, for what would correspond to a decorated arc (90:92:2cm) (as expected, the short arc may be a bit hard to see, but it is there):

Basically, first I kept bruteforcing and increasing the radius and re-compiling, until it passed. It turns out:

• For an arc angle of 90:92, I need at least a radius of 5.4cm
• For an arc angle of 90:91, I need at least a radius of 10.5cm

So, since my original radius is 2cm, and I want to show 90:91 (thus I have to use 10.5cm radius) -- I have a magnifying scaling ratio of 10.5/2 (\scaleNorm in the code below, with its inverse being \scaleInv), if I want to support 1 degree arc. The trick is then:

• Do not scale in \draw, but use explicitly large radius, and correspondingly magnified decoration parameters and line width
• Then wrap the \draw in a {scope}, which will scale down, everything (including line widths), using transform canvas, back to what should be original size

Geometrically, the curvature of the arc should (and does) survive the up/down scale procedure. The only problem is to anchor the scope correctly - basically, we need a named coordinate specified beforehand, to which we will anchor (below it's cs, which is also used to start the arc) - and then in the transform canvas, we can use shift=($(cs)-\scaleInv*(cs)$) to re-align correctly.

Note that the below can show a decorated one-degree arc (90:91:...) - but it will still crash with ! Dimension too large for a zero-degree arc arc (90:90:...); which is unfortunate, as a non-decorated arc typically just doesn't draw anything, and passes silently (and to achieve that, would require extra conditional checks in the workaround).

So, just the tikzpicture part of the solution (since there are no changes elsewhere in respect to the MWE in OP), which implements this workaround, is:

\begin{tikzpicture}

\draw[]
(0,0) -- (1,0);
\draw[decoration={deccross,deccrosslen=5pt,deccrosslw=0.5cm},decorate]
(0,1) -- (1,1);
\draw[decoration={deccross,deccrosslen=2pt},decorate]
(0,2) -- (1pt,2); % short - no problem

\draw[] (2,0) -- ++(0,2cm)
coordinate(ics)
arc (90:45:2cm)
(ics)  { arc (90:97:2cm) }
;

\draw[] (4,0) -- ++(0,2cm)
coordinate(cs)
decorate[decoration={deccross}]%
{ arc (90:45:2cm) }
coordinate(ce)
;

%\traceon
\pgfmathsetmacro{\scaleInv}{2/10.5}
\pgfmathsetmacro{\scaleNorm}{1/\scaleInv}
\typeout{NOW \scaleInv, \scaleNorm}
%\scalebox{\pgfmathresult}{% not good, way off
% doing draw[scale=0.8 in  again raises Dimension too large ...
% the scope scale (without transform shape) seemingly
%  has no influence on decorations;
% so it basically restores the failure at 90:92 (90:91 passes!)
% transform canvas transforms _everything_ - including stroke
\begin{scope}[
at=(cs),
anchor=center,
% scale=\scaleInv, % may restore bad @ 90:92 - even if below uses 10.5cm radius!
% transform shape, % no real change to decorations
transform canvas={
scale=\scaleInv,                % works with this, but not anchored
shift=($(cs)-\scaleInv*(cs)$),  % this anchors ok
},
]
\pgfmathsetmacro{\declB}{\scaleNorm*\deccrosslen}
\pgfmathsetmacro{\decwB}{\scaleNorm*\deccrosslw}
\pgfmathsetmacro{\sclw}{\scaleNorm*\pgflinewidth}
\draw[
scale=1,
line width=\sclw,
decoration={deccross,deccrosslen=\declB,deccrosslw=\decwB},
decorate
]
(cs)
%arc (90:92:2cm) % ! Dimension too large. <to be read again> \relax
%arc (90:97:2cm) % 90:97 ok, 90:96 dimension too large
%arc (90:92:5.4cm) % for >= 5.4cm, it passes for 90:92!
arc (90:92:10.5cm) % for >= 10.5cm, it passes for 90:91!
;
\end{scope}

\end{tikzpicture}

-