我已经看到了避免 tikz 中的“尺寸过大”和“浮点格式错误”错误,可能没有答案,但让我们看看......
我有这个 MWE,带有自定义装饰,可以应用于弧,但不能应用于短弧:
\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}
当代码运行时,如上所示,生成的内容如下:
但是如果取消注释了 short arc (90:92:2cm)
,则会出现崩溃! Dimension too large.
。这正是避免 tikz 中的“尺寸过大”和“浮点格式错误”错误:
您能做的不多。...因为 TeX 无法处理您交给它的计算。因为非常老旧但仍然闪亮的齿轮无法处理任何如此精确的东西。我的意思是,由于您的线宽规范,弧长非常小(对于这样的弧来说,它太粗了)。
这可能是同样的问题,但我仍然使用线宽,它实际上很细?另外,请注意,短线没有问题 - 只有短弧才有问题......
我尝试了trace
一下,并且我尝试重建“堆栈跟踪”(参见下面选定的复制粘贴);似乎有一个\pgfmathloop
要做装饰,在哪里\pgfmathveclen@
调用,哪个调用\pgfmathreciprocal@
,这最终会导致崩溃。
我能做些什么吗 - 也许通过在我的自定义装饰中编写一个特殊情况 - 让代码不会在短弧上崩溃?
以下是跟踪记录的片段:
\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.
<to be read again>
\relax
\pgfmathreciprocal@@ ...c@pgfmath@counta pt\relax
答案1
好吧,我想要一个解决方法 - 这里有一个解决方法:)
,尽管我真的很想知道是否有更合适的方法来做到这一点。此解决方法产生以下输出,对应于装饰arc (90:92:2cm)
(如预期的那样,短弧可能有点难以看到,但它确实存在):
基本上,首先我会不断进行暴力破解,增加半径并重新编译,直到通过。结果是:
- 对于 90:92 的圆弧角,我至少需要 5.4 厘米的半径
- 对于 90:91 的圆弧角,我至少需要 10.5 厘米的半径
因此,由于我的原始半径是 2 厘米,而我想要显示 90:91(因此我必须使用 10.5 厘米半径)——如果我想要支持 1 度弧,我的放大比例是 10.5/2(\scaleNorm
在下面的代码中,其倒数为\scaleInv
)。诀窍是:
- 不要缩小
\draw
,而是使用明确大的半径,以及相应放大的装饰参数和线宽 - 然后将包裹
\draw
在 中{scope}
,它会缩小,一切(包括线宽),使用transform canvas
,恢复到原来的大小
从几何学上讲,弧的曲率应该(并且确实)经得住放大/缩小过程。唯一的问题是正确地锚定范围 - 基本上,我们需要事先指定一个命名坐标,我们将锚定到该坐标(在它下面是cs
,它也用于开始弧) - 然后在中transform canvas
,我们可以使用shift=($(cs)-\scaleInv*(cs)$)
来正确地重新对齐。
请注意,下面可以显示一个装饰性的一度arc (90:91:...)
- 但它仍然会与! Dimension too large
零度弧崩溃arc (90:90:...)
;这是不幸的,因为非装饰弧通常不会绘制任何东西,并且默默地通过(并且要实现这一点,需要在解决方法中进行额外的条件检查)。
因此,仅tikzpicture
解决方案的一部分(因为 OP 中的 MWE 其他地方没有任何变化)实现了此解决方法,如下所示:
\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}