pgfpathcurvebetweentime 对于某些值表现得很奇怪

pgfpathcurvebetweentime 对于某些值表现得很奇怪

生成某些贝塞尔子路径时 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'

相关内容