TikZ:装饰笔触厚度会引发“尺寸太大”但看起来很好(同上标记)

TikZ:装饰笔触厚度会引发“尺寸太大”但看起来很好(同上标记)

我正在用我的 Ditto Mark Macro 制作一些花卉图案(见Tikz:使用乳胶长度作为路径的长度(同上标记))。即对笔触使用可变粗细。下面将其实现为带星号的宏版本。

然而,当我尝试使用可变厚度的笔触时,虽然生成的路径看起来很好,但Dimension too large单个笔触却出现了 35 个错误...\ditto*

我该如何解决?

梅威瑟:

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{xparse}

\makeatletter

\usepackage{tikz}
\usetikzlibrary{math}
\usetikzlibrary{decorations}

\pgfkeys{/pgf/decoration/.cd,
    start stroke width/.store in = \startstrokewidth,
    end stroke width/.store in   = \endstrokewidth,
}
\pgfkeys{/tikz/.cd,
    pen stroke/.style args={#1,#2}{
        decorate,
        decoration={
            variable stroke width,
            start stroke width=#1,
            end stroke width=#2,
        }
    }
}

\pgfdeclaredecoration{variable stroke width}{initial}{%
    % modified version of:
    % https://tex.stackexchange.com/questions/14283/stroke-with-variable-thickness
    \state{initial}[width=0pt, next state=line, persistent precomputation={%
        \pgfmathsubtract@{\startstrokewidth}{\endstrokewidth}%
        \pgfmathdivide{\pgfmathresult}{\pgfdecoratedpathlength}%
        \let\strokeincrement=\pgfmathresult%
        \def\strokewidth{\startstrokewidth}%
    }]{}
    \state{line}[width=\startstrokewidth, persistent postcomputation={%
        \pgfmathsubtract@{\strokewidth}{\strokeincrement}%
        \let\strokewidth=\pgfmathresult%
    }]{%
        \pgfsetlinewidth{\strokewidth}%
        \pgfsetarrows{-}%
        \pgfpathmoveto{\pgfpointorigin}%
        \pgfpathlineto{\pgfqpoint{.75pt}{0pt}}%
        \pgfusepath{stroke}%
    }
    \state{final}{%
        \pgfsetlinewidth{\pgflinewidth}%
        \pgfpathmoveto{\pgfpointorigin}%
        \pgfusepath{stroke}% 
    }
}


\newdimen\dto@x
\newdimen\dto@y
\newdimen\dto@spc
\NewDocumentCommand\ditto{ s O{2ex} m }{%
    % #1 = starred means use pen stroke, unstarred use regular line
    % #2 = minimum width
    % #3 = string to use for calculating width
    \settowidth{\dto@x}{#3}%
    %\showthe\dto@x%
    \dto@x = \ifdim#2<\dto@x\the\dto@x\else\the\dimexpr#2\relax\fi% whichever is widest of #2 and #3
    \divide\dto@x by 4% sine wave has 4 points
    \dto@y = .0675ex% .125ex%
    \dto@spc = .5pt% ditto mark sizing
    \begin{tikzpicture}[baseline=-.5ex,cap=round]
        \IfBooleanTF{#1}{% starred
            \draw[pen stroke={.4pt,.35pt}] (0,0) sin (1\dto@x, \dto@y) cos (2\dto@x, 0) sin (3\dto@x, -\dto@y) cos (4\dto@x, 0);
        }{% unstarred
            \draw (0,0) sin (1\dto@x, \dto@y) cos (2\dto@x, 0) sin (3\dto@x, -\dto@y) cos (4\dto@x, 0);
        }%
        \draw[xshift=-.2ex, pen stroke={.4pt,.35pt}] (2\dto@x + .25pt, 3\dto@y) -- (2\dto@x - .25pt, -3\dto@y);
        \draw[xshift=.2ex, pen stroke={.4pt,.35pt}] (2\dto@x + .25pt, 3\dto@y) -- (2\dto@x - .25pt, -3\dto@y);
    \end{tikzpicture}%
}

\makeatother

\begin{document}

\noindent
blah blah Test blah blah\\
blah blah \ditto{Test} blah blah\\
blah blah \ditto*{Test} blah blah\\     % throws 'Dimension too large' several times, but looks great in doc?!
blah blah Testing testing blah blah\\
blah blah \ditto{Testing testing} blah blah\\
%blah blah \ditto*{Testing testing} blah blah\\
blah blah \ditto{} blah blah\\
%blah blah \ditto*{} blah blah\\
blah blah \ditto[10em]{Test} blah blah\\
%blah blah \ditto*[10em]{Test} blah blah\\
blah blah \ditto[10em]{Testing testing} blah blah\\
%blah blah \ditto*[10em]{Testing testing} blah blah\\
blah blah \ditto[10em]{} blah blah\\
%blah blah \ditto*[10em]{} blah blah\\

\end{document}

有关的:

答案1

总是同样的问题:veclen不喜欢小值。请参阅此帖子:如何做标记

解决方案xfp

\documentclass{article}
\usepackage[showframe]{geometry}
\usepackage{xparse}

\makeatletter

\usepackage{tikz,xfp}
\usetikzlibrary{math}
\usetikzlibrary{decorations}

\pgfkeys{/pgf/decoration/.cd,
    start stroke width/.store in = \startstrokewidth,
    end stroke width/.store in   = \endstrokewidth,
}
\pgfkeys{/tikz/.cd,
    pen stroke/.style args={#1,#2}{
        decorate,
        decoration={
            variable stroke width,
            start stroke width=#1,
            end stroke width=#2,
        }
    }
}

\pgfdeclaredecoration{variable stroke width}{initial}{%
    % modified version of:
    % https://tex.stackexchange.com/questions/14283/stroke-with-variable-thickness
    \state{initial}[width=0pt, next state=line, persistent precomputation={%
        \pgfmathsubtract@{\startstrokewidth}{\endstrokewidth}%
        \pgfmathdivide{\pgfmathresult}{\pgfdecoratedpathlength}%
        \let\strokeincrement=\pgfmathresult%
        \def\strokewidth{\startstrokewidth}%
    }]{}
    \state{line}[width=\startstrokewidth, persistent postcomputation={%
        \pgfmathsubtract@{\strokewidth}{\strokeincrement}%
        \let\strokewidth=\pgfmathresult%
    }]{%
        \pgfsetlinewidth{\strokewidth}%
        \pgfsetarrows{-}%
        \pgfpathmoveto{\pgfpointorigin}%
        \pgfpathlineto{\pgfqpoint{.75pt}{0pt}}%
        \pgfusepath{stroke}%
    }
    \state{final}{%
        \pgfsetlinewidth{\pgflinewidth}%
        \pgfpathmoveto{\pgfpointorigin}%
        \pgfusepath{stroke}% 
    }
}


\newdimen\dto@x
\newdimen\dto@y
\newdimen\dto@spc
\NewDocumentCommand\ditto{ s O{2ex} m }{%
    % #1 = starred means use pen stroke, unstarred use regular line
    % #2 = minimum width
    % #3 = string to use for calculating width
    \settowidth{\dto@x}{#3}%
    %\showthe\dto@x%
    \dto@x = \ifdim#2<\dto@x\the\dto@x\else\the\dimexpr#2\relax\fi% whichever is widest of #2 and #3
    \divide\dto@x by 4% sine wave has 4 points
    \dto@y = .0675ex% .125ex%
    \dto@spc = .5pt% ditto mark sizing
    \begin{tikzpicture}[baseline=-.5ex,cap=round]
        \IfBooleanTF{#1}{% starred
            \draw[pen stroke={.4pt,.35pt}] (0,0) sin (1\dto@x, \dto@y) cos (2\dto@x, 0) sin (3\dto@x, -\dto@y) cos (4\dto@x, 0);
        }{% unstarred
            \draw (0,0) sin (1\dto@x, \dto@y) cos (2\dto@x, 0) sin (3\dto@x, -\dto@y) cos (4\dto@x, 0);
        }%
        \draw[xshift=-.2ex, pen stroke={.4pt,.35pt}] (2\dto@x + .25pt, 3\dto@y) -- (2\dto@x - .25pt, -3\dto@y);
        \draw[xshift=.2ex, pen stroke={.4pt,.35pt}] (2\dto@x + .25pt, 3\dto@y) -- (2\dto@x - .25pt, -3\dto@y);
    \end{tikzpicture}%
}

\pgfmathdeclarefunction*{veclen}{2}{%
\begingroup%
  \pgfmath@x#1pt\relax%
  \pgfmath@y#2pt\relax%
\pgf@xa=\pgf@x%
\pgf@ya=\pgf@y%
\edef\tkz@temp@a{\fpeval{\pgfmath@tonumber{\pgf@xa}}}
\edef\tkz@temp@b{\fpeval{\pgfmath@tonumber{\pgf@ya}}}
\edef\tkz@temp@sum{\fpeval{(\tkz@temp@a*\tkz@temp@a+\tkz@temp@b*\tkz@temp@b)}}
\edef\tkzFPMathLen{\fpeval{sqrt(\tkz@temp@sum)}}
%\edef\pgfmath@tmp{\fpeval{round(\tkzFPMathLen,6)}}
%\pgfmath@tmp %
  \pgfmath@returnone\tkzFPMathLen pt%
  \endgroup%
}
\makeatother


\begin{document}

\noindent
blah blah Test blah blah\\
blah blah \ditto{Test} blah blah\\
blah blah \ditto*{Test} blah blah\\     % throws 'Dimension too large' several times, but looks great in doc?!
blah blah Testing testing blah blah\\
blah blah \ditto{Testing testing} blah blah\\
%blah blah \ditto*{Testing testing} blah blah\\
blah blah \ditto{} blah blah\\
%blah blah \ditto*{} blah blah\\
blah blah \ditto[10em]{Test} blah blah\\
%blah blah \ditto*[10em]{Test} blah blah\\
blah blah \ditto[10em]{Testing testing} blah blah\\
%blah blah \ditto*[10em]{Testing testing} blah blah\\
blah blah \ditto[10em]{} blah blah\\
%blah blah \ditto*[10em]{} blah blah\\

\end{document}

在此处输入图片描述

Loop Space 的另一个修改

\pgfmathdeclarefunction*{veclen}{2}{%
  \begingroup%
  \pgfmath@x#1pt\relax%
  \pgfmath@y#2pt\relax%
  \ifdim\pgfmath@x<0pt\relax%
  \pgfmath@x-\pgfmath@x%
  \fi%
  \ifdim\pgfmath@y<0pt\relax%
  \pgfmath@y-\pgfmath@y%
  \fi%
  \ifdim\pgfmath@x=0pt\relax%
  \pgfmath@x\pgfmath@y%
  \else%
  \ifdim\pgfmath@y=0pt\relax%
  \else%
  \ifdim\pgfmath@x>\pgfmath@y%
  \pgfmath@xa\pgfmath@x%
  \pgfmath@x\pgfmath@y%
  \pgfmath@y\pgfmath@xa%
  \fi%
  % We use a scaling factor to reduce errors.
  % First, see if we should scale down
  \let\pgfmath@tmp@scale=\divide
  \let\pgfmath@tmp@restore=\multipy
  \ifdim\pgfmath@y>10000pt\relax%
  \c@pgfmath@counta1500\relax%
  \else%
  \ifdim\pgfmath@y>1000pt\relax%
  \c@pgfmath@counta150\relax%
  \else%
  \ifdim\pgfmath@y>100pt\relax%
  \c@pgfmath@counta50\relax%
  \else%
  % Not scaling down, should we scale up?
  \let\pgfmath@tmp@scale=\multiply
  \let\pgfmath@tmp@restore=\divide
  \ifdim\pgfmath@y<0.00001pt\relax%
  \c@pgfmath@counta1500\relax%
  \else%
  \ifdim\pgfmath@y<0.0001pt\relax%
  \c@pgfmath@counta150\relax%
  \else%
  \ifdim\pgfmath@y<0.001pt\relax%
  \c@pgfmath@counta50\relax%
  \else
  \c@pgfmath@counta1\relax%
  \fi%
  \fi%
  \fi%
  \fi%
  \fi%
  \fi%
  \pgfmath@tmp@scale\pgfmath@x\c@pgfmath@counta\relax%
  \pgfmath@tmp@scale\pgfmath@y\c@pgfmath@counta\relax%
  \pgfmathreciprocal@{\pgfmath@tonumber{\pgfmath@y}}%
  \pgfmath@x\pgfmathresult\pgfmath@x%
  \pgfmath@xa\pgfmath@tonumber{\pgfmath@x}\pgfmath@x%
  \edef\pgfmath@temp{\pgfmath@tonumber{\pgfmath@xa}}%
  %
  % Use A+x^2*(B+x^2*(C+x^2*(D+E*x^2)))
  % where
  % A = +1.000012594
  % B = +0.4993615349
  % C = -0.1195159052
  % D = +0.04453994279
  % E = -0.01019210944
  %
  \[email protected]\pgfmath@xa%
  \advance\[email protected]\relax%
  \pgfmath@x\pgfmath@temp\pgfmath@x%
  \advance\[email protected]\relax%
  \pgfmath@x\pgfmath@temp\pgfmath@x%
  \advance\[email protected]\relax%
  \pgfmath@x\pgfmath@temp\pgfmath@x%
  \advance\[email protected]\relax%
  \ifdim\pgfmath@y<0pt\relax%
  \pgfmath@y-\pgfmath@y%
  \fi%
  \pgfmath@x\pgfmath@tonumber{\pgfmath@y}\pgfmath@x%
  % Invert the scaling factor.
  \pgfmath@tmp@restore\pgfmath@x\c@pgfmath@counta\relax%
  \fi%
  \fi%
  \pgfmath@returnone\pgfmath@x%
  \endgroup%
}

相关内容