Кажется, есть баг или ошибка при использовании относительных команд. В моем случае я обнаружил случай, когда рисование плавной кривой рисует кривую неправильно.
Проверьте следующие случаи (первый — полностью относительный, а последний — полностью абсолютный), где относительное использование команд приводит к ошибке, в то время как абсолютное работает как положено.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{svg.path}
\begin{document}
% Original
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 s 111 248 248 248 s 248 -111 248 -248 S 393 8 256 8 z";
\end{tikzpicture}
% Mix of relative
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 s 111 248 248 248 S 504 393 504 256 S 393 8 256 8 z";
\end{tikzpicture}
% Mix of relative
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 S 119 504 256 504 s 248 -111 248 -248 S 393 8 256 8 z";
\end{tikzpicture}
% Full absolute
\begin{tikzpicture}
\draw svg "M256 8 C 119 8 8 119 8 256 S 119 504 256 504 S 504 393 504 256 S 393 8 256 8 z";
\end{tikzpicture}
\end{document}
решение1
В определении s
оператора
\pgfparserdef{svgpath}{all}{the letter s} { \pgf@lib@svg@finish@prev \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@rel@smooth} } \def\pgf@lib@svg@curveto@rel@smooth{% \ifnum\pgf@lib@svg@count=0\relax% nothing read \else% % Draw curve % Compute first control point \ifx\pgf@lib@svg@bezier@last\pgfutil@empty% \def\pgf@lib@svg@first@cp{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}} \else \def\pgf@lib@svg@first@cp{ \pgfpointadd {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}} {\pgfpointdiff {\pgf@lib@svg@bezier@last} {\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}} } } \fi \pgfpathcurveto {\pgf@lib@svg@first@cp} {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}% {\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}% % Clear quadratic last point and save new last control point: \let\pgf@lib@svg@quad@last=\pgfutil@empty% \pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}} \edef\pgf@lib@svg@bezier@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}% % update \advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{2}pt% \advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{3}pt% % Go on \pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@rel@smooth} \fi }
Следующая строка (в настоящее время строка 386 изpgflibrarysvg.path.code.tex
\pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}} \edef\pgf@lib@svg@bezier@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
неверно. Это потому, что \pgf@lib@svg@get@num{2}
и {3}
является конечной точкой предыдущей кривой. Но стандарт говорит, что он должен запомнить вторую контрольную точку предыдущей кривой. Если вы измените числа на {0}
и, {1}
это будет работать так, как и ожидалось.
(Я подозреваю, что эта строка скопирована из строки 300, тогда как в C
операторе {2}
и {3}
означают вторую контрольную точку.)
Вот МВЭ
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{svg.path}
\makeatletter
\def\pgf@lib@svg@curveto@rel@smooth{%
\ifnum\pgf@lib@svg@count=0\relax% nothing read
\else%
% Draw curve
% Compute first control point
\ifx\pgf@lib@svg@bezier@last\pgfutil@empty%
\def\pgf@lib@svg@first@cp{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}
\else
\def\pgf@lib@svg@first@cp{
\pgfpointadd
{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}
{\pgfpointdiff
{\pgf@lib@svg@bezier@last}
{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}
}
}
\fi
\pgfpathcurveto
{\pgf@lib@svg@first@cp}
{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}}%
{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{2}pt}{\pgf@lib@svg@get@num{3}pt}}}%
% Clear quadratic last point and save new last control point:
\let\pgf@lib@svg@quad@last=\pgfutil@empty%
\pgf@process{\pgfpointadd{\pgfqpoint{\pgf@lib@svg@last@x}{\pgf@lib@svg@last@y}}{\pgfqpoint{\pgf@lib@svg@get@num{0}pt}{\pgf@lib@svg@get@num{1}pt}}} %%%%%% fixing this line
\edef\pgf@lib@svg@bezier@last{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
% update
\advance\pgf@lib@svg@last@x by\pgf@lib@svg@get@num{2}pt%
\advance\pgf@lib@svg@last@y by\pgf@lib@svg@get@num{3}pt%
% Go on
\pgf@lib@svg@read@nums{4}{\pgf@lib@svg@curveto@rel@smooth}
\fi
}
\begin{document}
% Original
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 s 111 248 248 248 s 248 -111 248 -248 S 393 8 256 8 z";
\end{tikzpicture}
% Mix of relative
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 s 111 248 248 248 S 504 393 504 256 S 393 8 256 8 z";
\end{tikzpicture}
% Mix of relative
\begin{tikzpicture}
\draw svg "M 256 8 C 119 8 8 119 8 256 S 119 504 256 504 s 248 -111 248 -248 S 393 8 256 8 z";
\end{tikzpicture}
% Full absolute
\begin{tikzpicture}
\draw svg "M256 8 C 119 8 8 119 8 256 S 119 504 256 504 S 504 393 504 256 S 393 8 256 8 z";
\end{tikzpicture}
\end{document}