Open muzimuzhi opened 1 month ago
Thanks for reporting, I'll try your code to see what's going on. My immediate thought is that I wonder whether this is just about how pre-actions interact with the main path. Does the effect persist if you take out the spath
stuff?
Oh, hang on - that's what your second example demonstrates.
I think I've isolated the issue, but I'm not sure what the fix is.
The problem (I think) is that the original coordinates of the path are getting included when the preaction part updates the picture bounding box. This is nothing to do with the preaction and is because the path is transformed before it is used.
When a path is created then the coordinates are added to the path bounding box, but because you are transforming it before using it then actually these coordinates shouldn't be used but rather their transformed ones (well, the interaction is more complicated because you are using both the transformed and original paths, but in essence this is what is going on).
So when a path is reused I need to ensure that all the various bounding boxes are updated correctly, but also if the current
path is transformed then these bounding boxes need to be reset before updating so that the original values are discarded.
An attempt which adds \pgf@resetpathsizes
if the path to modify and use is current
seems to work. But I really don't know any details about spath3
.
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{spath3}
\tikzset{every picture/.append style={
execute at end picture={
\draw[dashed]
(current bounding box.north east) rectangle
(current bounding box.south west);
}
}}
\makeatletter
\ExplSyntaxOn
% TODO: do similar for \@@_maybe_current_two_paths_reuse_first:nnnn and
% \@@_maybe_current_two_paths_reuse_second:nnnn
\cs_new_protected_nopar:Npn \__tikzspath_maybe_current_path_reuse_NEW:nnn #1#2#3
{
\bool_set_true:N \l_spath_movetorelevant_bool
\tl_if_eq:nnT {#2} {current}
{
\pgf@resetpathsizes % <<< added
\spath_get_current_path:c {\__tikzspath_path_name:n {#2}}
}
#1 {#2} #3
\tl_if_eq:nnT {#2} {current}
{
\tl_if_empty:cF {\__tikzspath_path_name:n {#2}}
{
\spath_set_current_path:c {\__tikzspath_path_name:n {#2}}
\spath_set_tikz_data:v {\__tikzspath_path_name:n {#2}}
}
}
}
\ExplSyntaxOff
\makeatother
\parindent=0pt
\begin{document}
\def\examples{%
Expected bbox \\
\begin{tikzpicture}[line width=1pt]
\path[spath/save=p1] (0,0) rectangle (1,.8);
\path[draw=blue!50, line width=10pt,
spath/transform={p1}{shift={(.3,.3)}}, spath/use=p1];
\end{tikzpicture}
With \texttt{preaction} \\
\begin{tikzpicture}[line width=1pt]
\path[draw=none]
[preaction={draw=blue!50, line width=10pt,
spath/transform={current}{shift={(.3,.3)}}
}]
(0,0) rectangle (1,.8);
\end{tikzpicture}
Without \texttt{preaction} \\
\begin{tikzpicture}[line width=1pt]
% \path[draw=red] (0,0) rectangle (1,.8);
\path[draw=blue!50, line width=10pt]
(0,0) rectangle (1,.8)
[spath/transform={current}{shift={(.3,.3)}}];
\end{tikzpicture}
}
\parbox[t]{.3\textwidth}{Before\par \examples}%
%
\ExplSyntaxOn
\cs_set_eq:NN \__tikzspath_maybe_current_path_reuse:nnn
\__tikzspath_maybe_current_path_reuse_NEW:nnn
\ExplSyntaxOff
\parbox[t]{.3\textwidth}{After\par \examples}%
\end{document}
I tried to test with ./testsuite.tex
but only found some tests already failed with current dev.
This seems to me to be the right fix. If the current
path is manipulated, then the original path sizes are now defunct and should be re-read from the start. The right place to put the fix is when the current
path is removed and put back, as you have identified, though I think it works best in \spath_set_current_path:N
since the path bounding box should be reset whenever the current path is overwritten, and that's what that command does.
There is a more general issue with bounding boxes and modifying the current path. There are two bounding boxes in play: the picture bounding box and the path bounding box. When coordinates are read in, and the path is built, then - under normal circumstances - both of these are updated. Then if the path is drawn, the path bounding box is used to add half the linewidth to the picture bounding box. This is what was happening with your example, since the path bounding box included the original path. So it wasn't that the preaction was polluting the main action, but rather the original path was still there as a "ghost" in the preaction path.
If modifying the current path then actually one could say that the picture bounding box shouldn't be updated with the original path coordinates. This isn't so easy to fix at the code level since the coordinates are used to adjust the bounding box as they are read in, and we might not know that we're going to modify the path until it is finished. However, the overlay
key exists to prevent this updating so judicious use of this key can solve this issue. That just requires better documentation so I will add that in.
So fix is hopefully in: 86d48b50a59d47f977ca263febbedb596c45f343
(Not closing this yet as it feels like it needs extensive testing to check that nothing else has broken. Incidentally, the testsuite.tex
is for testing the routines in the underlying spath3.sty
code, it doesn't test anything in the TikZ library.)
I was trying with
spath3
to achieve a shadow-like effect with bounding box auto updated. Then I found that if apreaction
contains both line width change andspath/transform
, the new line width was also applied to the main action, causing a wrong final bounding box.