Open tcpaiva opened 10 months ago
diff --git a/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex b/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
index 5a9c5fc2..a29609f9 100644
--- a/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
+++ b/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
@@ -622,7 +626,7 @@
% Line shortening for straight lines:
%
\def\pgf@do@shorten@straightstart{%
- \edef\pgfprocessresultpathsuffix{\pgfsubpathfirsttoken{\the\pgf@xa}{\the\pgf@ya}\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}}%
+ \edef\pgfprocessresultpathsuffix{\pgfsubpathfirsttoken{\the\pgf@xa}{\the\pgf@ya}\pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}}%
\expandafter\expandafter\expandafter\def%
\expandafter\expandafter\expandafter\pgfprocessresultpathsuffix%
\expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathsuffix\pgfsubpath
end}%
```tex \documentclass{article} \usepackage{tikz} \usepackage{xpatch} \makeatletter \xpatchcmd\pgf@do@shorten@straightstart {\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}} {\pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}} {}{\PatchFailed} \makeatother \begin{document} \begin{pgfpicture} % all control points \foreach \i/\j in { 0pt/20pt, 14.45pt/0pt, 20pt/0pt, 25.55pt/0pt, 40pt/20pt } { \pgfpathcircle{\pgfqpoint{\i}{\j}}{1pt} } % new path start after shortening \pgfpathcircle{\pgfqpoint{0.26936pt}{19.62717pt}}{1pt} \pgfusepath{stroke} \pgfpathmoveto{\pgfqpoint{0pt}{20pt}} \pgfpathcurveto {\pgfqpoint{0.0pt}{20.0pt}}{\pgfqpoint{14.45007pt}{0.0pt}}{\pgfqpoint{20.0pt}{0.0pt}} \pgfpathcurveto {\pgfqpoint{25.54993pt}{0.0pt}}{\pgfqpoint{40.0pt}{20.0pt}}{\pgfqpoint{40.0pt}{20.0pt}} \pgfgetpath{\mypath} \pgfusepath{stroke} \pgfsetstrokecolor{red} \pgfsetarrows{->} \pgfsetpath{\mypath} \pgfusepath{stroke} \pgfsetstrokecolor{blue} \pgfsetarrows{<-} \pgfsetpath{\mypath} \pgfusepath{stroke} \end{pgfpicture} % based on original example \begin{tikzpicture}[every plot/.append style={smooth}] \draw plot coordinates {(0,1) (1,0) (2,1)}; \draw[->, yshift=2pt, red, opacity=.3] plot coordinates {(0,1) (1,0) (2,1)}; \draw[<-, yshift=-2pt, blue, opacity=.3] plot coordinates {(0,1) (1,0) (2,1)}; %% unexpected \end{tikzpicture} \end{document} ```
Before | after |
---|---|
Ah, my patch was wrong (or too simple), when the starting and first support points of curve-to is not identical.
What really helpful is to load bending
library, which will turn on precise path shortening (needed when path has arrow tips). Without bending
a curve-to is treated like a straight line, which is bound to give unsatisfied shortening results in certain cases.
\documentclass{article} \usepackage{tikz} \usepackage{xpatch} \begin{document} \def\tests{ \begin{tikzpicture}[scale=3] \def\pathP{ (0, 1) .. controls (0,1) and (.7, 0) .. (1,0) } \def\pathQ{[xshift=1cm] (0,1) .. controls (0,.5) and (.7, 0) .. (1,0) } \def\pathR{[xshift=2cm] (0,1) .. controls (0.5,1) .. (1,0) } \def\pathS{[xshift=3cm] (0,1) .. controls (0,.5) and (.7, 0) .. (.7,0) } \foreach \i in {\pathP, \pathQ, \pathR, \pathS} { \draw \i; \draw[->, shift={(1pt, 1pt)}, red, opacity=.3] \i; \draw[<-, shift={(-1pt, -1pt)}, blue, opacity=.3] \i; } \end{tikzpicture}} \subsection*{Before (pgf-tikz v3.1.10)} \tests \subsection*{+ wront patch} { \makeatletter \xpatchcmd\pgf@do@shorten@straightstart {\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}} {\pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}} {}{\PatchFailed} \makeatother \tests } \subsection*{+ bending library} \usetikzlibrary{bending} \tests \end{document}
Ah, my patch was wrong (or too simple), when the starting and first support points of curve-to is not identical.
An improved patch. More knowledge about Bezier curve than what I got is needed to make up more test cases.
diff --git a/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex b/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
index 5a9c5fc2..a9d7d4f1 100644
--- a/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
+++ b/tex/generic/pgf/basiclayer/pgfcorepathusage.code.tex
@@ -622,7 +622,13 @@
% Line shortening for straight lines:
%
\def\pgf@do@shorten@straightstart{%
- \edef\pgfprocessresultpathsuffix{\pgfsubpathfirsttoken{\the\pgf@xa}{\the\pgf@ya}\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}}%
+ \edef\pgfprocessresultpathsuffix{%
+ \pgfsubpathfirsttoken{\the\pgf@xa}{\the\pgf@ya}%
+ \ifx\pgfpointfirstonpath\pgfpointsecondonpath
+ \pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}%
+ \else
+ \pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}%
+ \fi}%
\expandafter\expandafter\expandafter\def%
\expandafter\expandafter\expandafter\pgfprocessresultpathsuffix%
\expandafter\expandafter\expandafter{\expandafter\pgfprocessresultpathsuffix\pgfsubpath
end}%
```tex \documentclass{article} \usepackage{tikz} \usepackage{xpatch} \begin{document} \def\tests{ \begin{tikzpicture}[scale=2] \def\pathP{ (0, 1) .. controls (0,1) and (.7, 0) .. (1,0) } \def\pathQ{[xshift=1cm] (0,1) .. controls (0,.5) and (.7, 0) .. (1,0) } \def\pathR{[xshift=2cm] (0,1) .. controls (0.7,.5) .. (1,0) } \def\pathS{[xshift=2.2cm] (1,0) .. controls (1.3,0) and (2,1) .. (2,1) } \foreach \i in {\pathP, \pathQ, \pathR, \pathS} { \draw \i; \draw[->, shift={(1pt, 1pt)}, red, opacity=.3] \i; \draw[<-, shift={(-1pt, -1pt)}, blue, opacity=.3] \i; } \end{tikzpicture}} \subsection*{Before (pgf-tikz v3.1.10)} \tests \subsection*{+ wront patch (v1)} { \makeatletter \xpatchcmd\pgf@do@shorten@straightstart {\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}} {\pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}} {}{\PatchFailed} \makeatother \tests } \subsection*{+ revised patch (v2)} { \makeatletter % perhaps a symmetric patch can be applied in \pgf@do@shorten@straightend \xpatchcmd\pgf@do@shorten@straightstart {\pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}} {% % use the same condition in \pgf@prep@straightstart \ifx\pgfpointfirstonpath\pgfpointsecondonpath \pgfsubpathsecondtoken{\the\pgf@xa}{\the\pgf@ya}% \else \pgfsubpathsecondtoken{\the\pgf@xc}{\the\pgf@yc}% \fi } {}{\PatchFailed} \makeatother \tests } \subsection*{+ bending library} \usetikzlibrary{bending} \tests \end{document} ```
Brief outline of the bug
The curve of the line for
\draw[]plot[smooth]coordinates{(0,1)(1,0)(2,1)}
is the same for\draw[->]plot[smooth]coordinates{(0,1)(1,0)(2,1)}
but it is not the same for\draw[<-]plot[smooth]coordinates{(0,1)(1,0)(2,1)}
Minimal working example (MWE)