![TikZ:装饰笔触厚度会引发“尺寸太大”但看起来很好(同上标记)](https://linux22.com/image/479605/TikZ%EF%BC%9A%E8%A3%85%E9%A5%B0%E7%AC%94%E8%A7%A6%E5%8E%9A%E5%BA%A6%E4%BC%9A%E5%BC%95%E5%8F%91%E2%80%9C%E5%B0%BA%E5%AF%B8%E5%A4%AA%E5%A4%A7%E2%80%9D%E4%BD%86%E7%9C%8B%E8%B5%B7%E6%9D%A5%E5%BE%88%E5%A5%BD%EF%BC%88%E5%90%8C%E4%B8%8A%E6%A0%87%E8%AE%B0%EF%BC%89.png)
我正在用我的 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%
}