生成某些贝塞尔子路径时 PGF 会阻塞。
\input tikz
\tikzpicture [x=1pt,y=1pt]
\draw [help lines] (0,0) grid [step=10] (100,170);
\foreach [count=\n] \s/\t
in { 0/1, 0/.999, .001/1.0, 0/1.0,
0.25/0.50, 0.26/0.5, 0.25/.5, 0.25/0.5 }{
\pgftext [at=\pgfpoint{50}{20*(\n)}] {\s/\t}
\pgfpathcurvebetweentime {\s} {\t}
{ \pgfpoint {0} {20*(\n-1)} }
{ \pgfpoint {30} {20*(\n )} }
{ \pgfpoint {70} {20*(\n )} }
{ \pgfpoint {100} {20*(\n-1)} }
\pgfusepath{stroke}
}
\endtikzpicture
\bye
MWE 显示它取决于值及其格式:
对数字施加轻微的扰动可以解决问题,但这是一个不可接受的解决方案。
这些是我发现的唯一临界值,但可能还有更多。希望我忽略了一些明显的东西。是我吗?或者这是一个错误?
答案1
我倾向于认为这是一个错误。 中的原始代码pgfcorepathconstruct.code.tex
包含一些优化,我当时可能认为这些优化很聪明,但几年后看起来有点笨拙且难以调试。
忽略原始代码并从头开始重新实现会产生一些似乎效果更好的结果(尽管尚未经过全面测试)
\input tikz
\catcode`\@=11
\def\pgf@@pathcurvebetweentime#1#2#3#4#5#6{%
\pgfmathparse{#1}%
\let\pgf@time@s=\pgfmathresult%
\pgfmathparse{#2}%
\let\pgf@time@t=\pgfmathresult%
\ifdim\pgf@time@s pt>\pgf@time@t pt\relax%
\pgfmathsetmacro\pgf@time@s{1-#1}%
\pgfmathsetmacro\pgf@time@t{1-#2}%
\pgf@@@pathcurvebetweentime{#6}{#5}{#4}{#3}%
\else%
\pgf@@@pathcurvebetweentime{#3}{#4}{#5}{#6}%
\fi%
}
\def\pgf@@@pathcurvebetweentime#1#2#3#4{%
\begingroup%
% Get the curve Q from curve P for time 0 to t
\pgfextract@process\Pa{#1}%
\pgfextract@process\Pb{#2}%
\pgfextract@process\Pc{#3}%
\pgfextract@process\Pd{#4}%
% Qa = Pa
\pgfextract@process\Qa{\Pa}%
% Qb = Pa + t*(Pb-Pa).
\pgfextract@process\Qb{%
\pgfpointadd{\Pa}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Pa}{\Pb}}}%
}%
% Qc = Qb + t*((Pb + t*(Pc-Pb)) - Qb)
\pgfextract@process\Qc{%
\pgfpointadd{\Qb}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Qb}{\pgfpointadd{\Pb}{\pgfpointscale{\pgf@time@t}{\pgfpointdiff{\Pb}{\Pc}}}}}}%
}%
% Qd = (1-t)^3*Pa + 3*t(1-t)^2*Pb + 3*t^2(1-t)*Pc + t^3*Pd.
\pgfextract@process\Qd{\pgfpointcurveattime{\pgf@time@t}{\Pa}{\Pb}{\Pc}{\Pd}}%
%
% Now get the curve R from the reversed curve Q for time 0 to 1-s/t
\pgfmathdivide@{\pgf@time@s}{\pgf@time@t}%
\pgfmathadd@{-\pgfmathresult}{1.0}%
\let\pgf@time@s=\pgfmathresult%
% Rd = Qd
\pgfextract@process\Rd{\Qd}%
% Rc = Qd + s*(Qc-Qd).
\pgfextract@process\Rc{%
\pgfpointadd{\Qd}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Qd}{\Qc}}}%
}%
% Rb = Rc + s*((Qc + s*(Qb-Qc)) - Rc)
\pgfextract@process\Rb{%
\pgfpointadd{\Rc}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Rc}{\pgfpointadd{\Qc}{\pgfpointscale{\pgf@time@s}{\pgfpointdiff{\Qc}{\Qb}}}}}}%
}%
% Ra = (1-s)^3*Qd + 3*s(1-s)^2*Qc + 3*s^2(1-s)*Qb + s^3*Qa.
\pgfextract@process\Ra{\pgfpointcurveattime{\pgf@time@s}{\Qd}{\Qc}{\Qb}{\Qa}}%
\ifpgf@ignoremoveto\else\pgfpathmoveto{\Ra}\fi%
\pgfpathcurveto{\Rb}{\Rc}{\Rd}%
\endgroup%
}
\tikzpicture [x=1pt,y=1pt]
\draw [help lines] (0,0) grid [step=10] (100,170);
\foreach [count=\n] \s/\t
in { 0./1., 0/.999, .001/1.0, 0/1.0,
0.25/0.50, 0.26/0.5, 0.25/.5, 0.25/0.5 }{
\pgftext [at=\pgfpoint{50}{20*(\n)}] {\s/\t}
\pgfpathcurvebetweentime {\s} {\t}
{ \pgfpoint {0} {20*(\n-1)} }
{ \pgfpoint {30} {20*(\n )} }
{ \pgfpoint {70} {20*(\n )} }
{ \pgfpoint {100} {20*(\n-1)} }
\pgfsetstrokecolor{black}
\pgfusepath{stroke}
}
\endtikzpicture
\bye
答案2
详细阐述 @percusse 的建议,不需要直接控制输入的快速解决方法是
\input tikz
\pgfkeys{/pgf/number format/precision=6} % <------------------------------------
\tikzpicture [x=1pt,y=1pt]
\draw [help lines] (0,0) grid [step=10] (100,170);
\foreach [count=\n] \s/\t
in { 0/1, 0/.999, .001/1.0, 0/1.0,
0.25/0.50, 0.26/0.5, 0.25/.5, 0.25/0.5 }{
\pgftext [at=\pgfpoint{50}{20*(\n)}] {\s/\t}
\pgfmathroundtozerofill{\s}\let\S\pgfmathresult % <-----------------------------
\pgfmathroundtozerofill{\t}\let\T\pgfmathresult % <-----------------------------
\pgfpathcurvebetweentime {\S} {\T}
{ \pgfpoint {0} {20*(\n-1)} }
{ \pgfpoint {30} {20*(\n )} }
{ \pgfpoint {70} {20*(\n )} }
{ \pgfpoint {100} {20*(\n-1)} }
\pgfusepath{stroke}
}
\endtikzpicture
\bye
并产生
这并不是特别优雅,但是它确实有效。
另一个解决方案是刚刚起作用是
\input tikz
\input fp % <-------------------------------------------------------------------
\usetikzlibrary{fixedpointarithmetic} % <---------------------------------------
\tikzset{/pgf/fixed point arithmetic} % <---------------------------------------
\tikzpicture [x=1pt,y=1pt]
\draw [help lines] (0,0) grid [step=10] (100,170);
\foreach [count=\n] \s/\t
in { 0/1, 0/.999, .001/1.0, 0/1.0,
0.25/0.50, 0.26/0.5, 0.25/.5, 0.25/0.5 }{
\pgftext [at=\pgfpoint{50}{20*(\n)}] {\s/\t}
\pgfpathcurvebetweentime {\s} {\t}
{ \pgfpoint {0} {20*(\n-1)} }
{ \pgfpoint {30} {20*(\n )} }
{ \pgfpoint {70} {20*(\n )} }
{ \pgfpoint {100} {20*(\n-1)} }
\pgfusepath{stroke}
}
\endtikzpicture
\bye
使用 FPU 应该可以同样有效地工作,但是某些地方的某些东西阻碍了它bad formatted float '0.0'
。