loopspace / spath3

TikZ/PGF package for manipulating soft paths, includes the knots and calligraphy TikZ libraries.
16 stars 2 forks source link

spath3 and nodes #14

Open fdagnat opened 2 years ago

fdagnat commented 2 years ago

Hi, in a complex figure, I would like to save the path of a node (its border). Can I do this using spath3?

I found an example on stackoverflow that does not work any more ([https://tex.stackexchange.com/questions/428270/tikz-convert-a-fit-node-into-a-path-for-clipping-filling]()). The documentation does not contain any example.

I have tried:

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{spath3}
\begin{document}
\begin{tikzpicture}
  \node[draw,inner ysep=3mm,spath/save=box] (0,0) {Text};
  \draw [blue,spath/transform={box}{shift={(0.2,0.2)}},spath/use=box];
\end{tikzpicture}
\end{document}

It compiles fine but there is a warning about an empty path and I do not get any blue rectangle...

As the following example works as intended as I have tried to combine it with save path macro of tikz that works for saving node border.

\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{spath3}
\begin{document}
\begin{tikzpicture}
  \draw[spath/save=box] (0,0) rectangle (1,1);
  \draw [blue,spath/transform={box}{shift={(2,0)}},spath/use=box];
  \draw [green,spath/translate={box}{0cm}{2cm},spath/use=box];
  \draw [magenta] (2,2) [spath/use={box,move}] ;
\end{tikzpicture}
\end{document}

I ended up with (to test various use)

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{spath3}
\begin{document}
\fbox{
\begin{tikzpicture}
  \node[save path=\pathBox,draw,inner ysep=3mm] (t) at (0,0) {Text};
  \draw [red,use path=\pathBox,spath/save=box];
  \draw [blue,spath/transform={box}{shift={(2,0)}},spath/use=box];
  \draw [green,spath/translate={box}{0cm}{2cm},spath/use=box];
  \draw [magenta] ([xshift=1cm,yshift=1cm]t) [spath/use={box,move}] ;
\end{tikzpicture}
}
\end{document}

where the transformation are weird (they are not only translation, there is some scaling going on) and the bounding box is buggy too.

loopspace commented 2 years ago

The main thing with your code is that because nodes are defined inside their own scopes, the spath/save has to be actually a spath/save global so that the path is available to the main level of drawing. TikZ's save path key is always global which is why that gets round that issue. So your first code works with spath/save global=box.

The transformations are weird because it turns out that nodes draw rectangles in weird ways. When you ask TikZ to draw a rectangle then it actually draws four straight sides. But when you put a rectangle around a node then it uses special "rectangle drawing" syntax. I didn't think that any code in TikZ/PGF actually used that special syntax so I didn't make provision for it in my library. Now that I'm aware of it, I will fix it.

fdagnat commented 2 years ago

Hello,

Ok, thank you for your response.

It would be interesting to patch the documentation to specify that a node define its own scope. I was not aware of that and I haven't find it being said in the tikz manual (by skimming rapidly).

For your information, my use case was to draw several time the node border slightly translated to give the feeling of a collection of such nodes.

Have a good and thanks for your work

loopspace commented 2 years ago

I'll add that to the spath3 documentation (I don't have any control over the main TikZ documentation).

I've found a hack that might help you while I'm implementing the rectangle code (as that might take a bit of time). If you rotate a node then it reverts to drawing rectangles by drawing their sides. Turns out that rotate=0 isn't enough to trigger this, but rotate=5, rotate=-5 is. So if you add rotate=5,rotate=-5 to the node that defines the path, you'll be fine with the transformations.

fdagnat commented 2 years ago

hum, if you get to implement it, it would be nice that it works for any shape and not only for rectangle. I noticed that we do not get the scale for circle shape and the transform and translate works fine.

Your solution (rotate=5,rotate=-5) works for transform and translate works fine for rectangle but the move still give surprising result (same for the circle). In both case the move seems strange probably because we do not where the border path of shape start...

I'm not really in hurry, at the moment, I use copy paste or macro combined with translation.

Thank you again

loopspace commented 2 years ago

By move do you mean the line where you have ([xshift=1cm,yshift=1cm]t)? If so, that might be to do with the fact that that is a slightly strange coordinate. By just using t you aren't specifying which anchor you want to use, and the way that TikZ chooses the anchor might be interfering with the shifts. I certainly get unexpected behaviour with this syntax even with ordinary path construction, let alone any of the spath3 stuff.

What do you mean about the circle shape not getting the scale? Is this a good thing or a bad thing? There shouldn't be any issues with circles as they are just regular paths and my library should be able to cope with them already. Can you post some code to illustrate what you are (or aren't) seeing so that I can investigate.

fdagnat commented 2 years ago

Below are the few experiments, I made. What I find surprising for the user is that they are used to "see" the border of a node through its anchor (center by default), and when you use the move, it starts at some point of the border (in general not the anchor of the node). That is not an error on your code. It is more a surprise for the naive user (that I am)...

In the code below, I was expecting the magenta path not to be where it ends up . After thinking about, it is correct but it disqualify using move for my use case because I have the impression that the starting point of the border of a node depends on its shape (seems to be north east for rectangle, east for circle).

So nothing for to investigate. Perhaps some explanation in the documentation but I'm unsure of where and what to state...

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{spath3}
\begin{document}
\begin{tikzpicture}
  \node[draw,inner ysep=3mm,spath/save global=box,rotate=5,rotate=-5] (t) at (0,0) {Text};
  \draw [blue,spath/transform={box}{shift={(2,0)}},spath/use=box];
  \draw [green,spath/translate={box}{0cm}{2cm},spath/use=box];
  \draw [magenta] ([xshift=1cm,yshift=1cm]t) [spath/use={box,move}] ;
\end{tikzpicture}

\begin{tikzpicture}
  \node[draw,circle,inner ysep=3mm,spath/save global=box] (t) at (0,0) {Text};
  \draw [blue,spath/transform={box}{shift={(2,0)}},spath/use=box];
  \draw [green,spath/translate={box}{0cm}{2cm},spath/use=box];
  \draw [magenta] ([xshift=1cm,yshift=1cm]t) [spath/use={box,move}] ;
\end{tikzpicture}

\begin{tikzpicture}
  \node[draw,circle,inner ysep=3mm,spath/save global=box,rotate=5,rotate=-5] (t) at (0,0) {Text};
  \draw [blue,spath/transform={box}{shift={(2,0)}},spath/use=box];
  \draw [green,spath/translate={box}{0cm}{2cm},spath/use=box];
  \draw [magenta] ([xshift=1cm,yshift=1cm]t.center) [spath/use={box,move}] ;
  \draw[->] ([xshift=1cm,yshift=1cm]t.center) -- ++ (1,1);
\end{tikzpicture}
\end{document}
loopspace commented 2 years ago

Looking at the paths in a bit more detail, the rectangle around a node does start at the north east. Also, putting a shift on a node coordinate without anchor is ignored. So ([xshift=2cm,yshift=2cm]t) [spath/use={box,move}] shifts the north east of the rectangle (as that's the start point of the path) to the centre of the node (as that's what t ends up as). If you put t.north east then you will get what, I think, you want.

What to do about this depends a bit on your use case. It sounds a bit like you want something that will work regardless of the node shape. In that case what you could do is add a move at the start of the path to the centre of the node. You'd do this after defining the node, something like:

  \node[spath/save global=pre box,draw,inner ysep=3mm,rotate=5,rotate=-5] (t) at (0,0) {Text};
  \path[spath/save=box] (t.center) [spath/use=pre box];
  \tikzset{spath/show=box}

This would then mean you could use t.center when transforming coordinates irrespective of the node shape.

fdagnat commented 2 years ago

Thank you. Translate and transform seems easier for my use case and they work well with the rotate trick.