Closed Andrew15-5 closed 1 year ago
I can see what's causing this, and will need to think a bit about how to circumvent it. The issue is that the bridge
code inserts the hoop into every gap in the path, but when you break the right-left path at the intersection of the below-above path then the issue is that the right-left path is already broken where it crosses the above-below path and the code inserts a hoop at that break as well as the intended break.
So the goal will be to figure out how to patch the code to ensure that the bridge is only inserted at the new break and not at the pre-existing breaks. I'll need to think a bit about how to do that.
Here's some code for you. Incidentally, one reason why the bridging code is not (yet) in the core code is because I don't use it myself so haven't experimented with all the variations. I don't want to fix the code until it's had lots of opportunity to see how the edge cases work, such as this.
Firstly, and most insignificantly, you don't need the rbridge
code. Since there's an option to specify the bridging path
all you need to do to get the opposite path is to change this. In the code below I include a command that sets the bridging path
depending on whether a parameter is empty or not. The {t}
or {}
is there to signal whether to use the original or reversed path.
Secondly, the problem is that when the final path is considered then it already has a break in it. Ideally, the code should only insert the jumps at new breaks and ignore existing ones. That's possible, but a bit tricker to code. So I went for a simpler solution which was to change the order in which everything happened. Rather than do bridge, break, bridge, break, bridge, break, bridge, break then I went for bridge, bridge, bridge, bridge, break, break, break, break. That way, all the bridges are added to their over paths before any of the under paths are broken.
To condense the code, I added a few more styles. In particular, one that takes a list and calls the insert bridges
on each pair in the list first, and then insert gaps
afterwards.
\documentclass{article}
\usepackage{tikz}
\usepackage{spath3}
\usetikzlibrary{positioning,arrows.meta,knots}
\tikzset{
bridging path/.initial=intersection arc,
bridging span/.initial=8pt,
bridging gap/.initial=4pt,
swap bridging path/.code={%
\ifx#1\relax\relax
\tikzset{bridging path=intersection arc}%
\else
\tikzset{bridging path=intersection reverse arc}%
\fi
},
insert bridges/.style n args={3}{%
swap bridging path={#3},
spath/split at intersections with={#1}{#2},
spath/insert gaps after
components={#1}{\pgfkeysvalueof{/tikz/bridging span}},
spath/join components upright
with={#1}{\pgfkeysvalueof{/tikz/bridging path}},
},
insert gaps/.style n args={3}{%
spath/split at intersections with={#2}{#1},
spath/insert gaps after
components={#2}{\pgfkeysvalueof{/tikz/bridging gap}},
},
process bridge pairs/.style={
insert bridges/.list={#1},
insert gaps/.list={#1},
}
}
\AtBeginDocument{%
\tikz[overlay] { \path[spath/save global=intersection arc] (0,0) arc[
radius=1cm, start angle=180, delta angle=-180]; }%
\tikzset{
spath/clone global={intersection reverse arc}{intersection arc},
spath/reverse globally=intersection reverse arc
}
}
\begin{document}
\fontsize{14}{14}
\def\offset{8pt}
\begin{tikzpicture}[
node distance=4cm,
arrow/.style={-Triangle, line width=1pt},
start/.style={pos=.2}
]
\node (c) {};
\node[draw,above=of c] (above) {above};
\node[draw,left=of c] (left) {left};
\node[draw,below=of c] (below) {below};
\node[draw,right=of c] (right) {right};
\path[spath/save=abovebelow]
([xshift=-\offset]above.south) --
([xshift=-\offset]below.north)
node[start, above, rotate=90] {above--below};
\path[spath/save=belowabove]
([xshift=\offset]below.north) --
([xshift=\offset]above.south)
node[start, below, rotate=90] {below--above};
\path[spath/save=leftright]
([yshift=-\offset] left.east) --
([yshift=-\offset] right.west)
node[start, below] {left--right};
\path[spath/save=rightleft]
([yshift=\offset] right.west) --
([yshift=\offset] left.east)
node[start, above] {right--left};
\tikzset{
bridging span/.initial=8pt,
bridging gap/.initial=4pt,
process bridge pairs={
{abovebelow}{rightleft}{t},
{leftright}{abovebelow}{},
{belowabove}{leftright}{},
{rightleft}{belowabove}{}
}
}
\draw[arrow, spath/use=abovebelow];
\draw[arrow, spath/use=belowabove];
\draw[arrow, spath/use=leftright];
\draw[arrow, spath/use=rightleft];
\end{tikzpicture}
\end{document}
Please use syntax highlighting for a block of code (if specific language is used). For this copy next template:
```\
```latex \command ```
It's very hard to read a big listing without colors (well, even small ones). Maybe it's only hard for some of us, but definitely not for the minority of us.
As an addition, I can advise using the next template to significantly reduce the vertical size of the comment if the code (or anything else) is very long:
<details><summary>Summary</summary>
previous template for a block of code goes here (above blank line is neccessary; summary tag is optional)
</details>
P.S. I used it in my first comment because the source code is not the main topic of the comment and it's very long too.
To make it more pleasing, I changed the "switches":
or "outer" pattern:
Unfortunately (for comparison with previous code) I made a lot of small changes. Overall I improved code structure, readability, and size. Some key points:
insert gaps/.style n args
from 3 to 2 (probably a typo)\spath
and \sdraw
commands that wrap around \path
and \draw
commands respectively{<name>}
to (<name>)
for a path's name (in \spath
and \sdraw
commands) will fit better in tikz code (the same way names are used for \node
command)Some notes:
@
char and some prefix)\path
after the name of the package (because they both have path
part)\spath
is used, then it will be only natural to use \sdraw
, otherwise separate names should be chosen\strand
)P.S. I want to express how impressed I am by your knowledge of tikz syntax. Because I had no idea about things like \pgfkeysvalueof
, /.list
, /.code={...#1...}
, \ifx#1\relax\relax
(last one I knew but don't know how to use properly). And together all this creates a very flexible and easy to maintain code which can do pretty complex stuff. But since you are a developer of tikz library, I guess you kinda have to know this stuff. In any ways, good for you.
I forgot about the syntax highlighting - fixed now.
insert gaps
should have 3 arguments since it gets the same list as insert arcs
. It therefore needs to absorb that third argument and discard it. The switch just tests for empty vs non-empty so any character will do.@
?\spath
and \sdraw
commands go against the principle of "don't do the unexpected" (can't remember the right name for that right now) since they aren't equivalent wrappers around \path
and \draw
. Also, the spath library provides so many keys and variations that a separate command for each one would be too much.arc
for bridge
? Someone else had already used the term bridge
to refer to this on TeX-SX so I just kept the name.spath3
package. You should be loading the spath3
tikz library. I didn't spot that in your initial code, sorry. The knots
library loads it, but none of your code here uses the knots
library so if you took that out - as it isn't needed - then you'll need to load the spath3
tikzlibrary explicitly.It therefore needs to absorb that third argument and discard it.
I don't know, it works just fine with 2
arguments, probably auto discarding the 3rd one automatically.
Which names are you referring to with the protection via @?
The once that are in \tikzset
command (e.g., arc
is too simple and needs to be protected if it would be added to library)
Your
\spath
and\sdraw
commands
The names for the commands were chosen "randomly" and are here just to demonstrate my example of wrappers.
By "renaming", do you mean
arc
forbridge
?
Mostly yes (I added a lot or very small changes, including renaming). If we use geometric terms, then arc is more accurately represents the shape. Bridge is an abstraction or an example of an arc. Bridge can be a straight line and therefore brings confusion to the code. (Bridge in my head always comes in a form of any real bridge with some kind of details: color, shape, fences — this further confuses my brain.)
You've loaded the
spath3
package. You should be loading thespath3
tikz library.
You see! You have 2 different (for you) things with the same name. For me, who only lightly used your packages/libraries, they are the same thing (and they do the same thing in my code).
But I have one more thing: in neovim+texlab it shows me that I can use spath3
package, but it doesn't show spath3
and knots
tikz library (it shows a lot of others). I only found out through some issues on GitHub that I need to use library via \usetikzlibrary
command (either show me where in doc it is stated, or please add this because I didn't find it).
And after all this, I thought that spath3
is a package and knots
is a tikz library. I had no idea that there is a package and tikz library with the same name. I think you should consider this "confusion" and maybe rename one or the other, or simply drop one of them (as I said they do the same thing for me and therefore one is a redundancy). Of course, they perhaps have different things, but I don't know this.
If I change knots
library to spath3
then I have to also add intersections
.
If knots
library automatically imports spath3
and intersections
, then why spath3
can't automatically import intersections
? This doesn't seem logical. They both should import Wait, it is because not always intersections
the same way IMO.intersections
is used with spath3
. So in my example, knots
is just a shortcut for importing 2 other libraries that I use.
I can make the distinction between the spath3
package and spath3
library clearer in the documentation, but the naming overlap is deliberate since the package defines a slew of commands that aren't available to a user and the library makes them available. There is no redundancy between them.
I have no idea what "neovim+texlab" is so can't comment on what it makes available or not. If there's something straightforward I can do with how my package is configured then I'll consider it, but I'm not going to delve into systems that I have no experience of to find that out.
FYI, Neovim is a terminal text editor which can be turned into a very decent IDE and more. texlab is language server (implementation of LSP for tex). I can use texlab in neovim to give me some guidance when making latex documents (It doesn't really do much except autosuggestion/autocompletion, unlike LS for other languages). It is also can be used in VS Code. So I was referring to them just to describe the situation (not all tikz libraries are autosuggested), which made me think that there are no knots
and spath3
libraries.
I want to say this again that I know very little about raw tex syntax and package/library development. I only use lualatex
command (and latexmk
helper) for my documents, as I use latex syntax and sometime Lua code. With that said, I can't objectively judge about things like renaming package/library as you said it yourself:
the naming overlap is deliberate since the package defines a slew of commands that aren't available to a user and the library makes them available. There is no redundancy between them.
This information is completely new to me. I can only say opinion from a user perspective. For me, it is confusing that 2 different things use the same name, and you can either import one or the other (roughly speaking) because I had never seen such naming overlapping. (Although I clearly still in the process of searching for new useful packages.)
My "mission" is to bring attention to some issues a user can stumble upon and yours is... well, it includes many things, but the point is that you know your stuff better. If you can address this misunderstanding in the documentation, it would be lovely.
The naming makes sense to me since the package doesn't expose any user commands and the TikZ library does, so someone just doing \usepackage{spath3}
will very quickly realise that something's wrong. However, I can see that I should make this clearer in the documentation. Thank you for your perspective.
With my setup: https://github.com/loopspace/spath3/issues/23#issuecomment-1444223270 I can do simple stuff like this:
![arc, rarc](https://user-images.githubusercontent.com/37143421/221264010-d2708eb3-e439-492c-8518-85f06e7be47c.png)
But I failed to do the petty "pattern" (it probably has a name): each of 4 lines go over only 1 of the other lines:![4 arcs + 1 redundant](https://user-images.githubusercontent.com/37143421/221264981-2c6faf87-1da4-4ea2-b9bf-d66a40af9754.png)
But somehow a new 5th arc (red number 1) is introduced when I "requested" only 4.
source code
```latex \documentclass{article} \usepackage{tikz} \usepackage{spath3} \usetikzlibrary{positioning,arrows.meta,knots} \tikzset{ bridging path/.initial=intersection arc, bridging rpath/.initial=intersection reverse arc, bridging span/.initial=8pt, bridging gap/.initial=4pt, bridge/.style 2 args={ spath/split at intersections with={#1}{#2}, spath/insert gaps after components={#1}{\pgfkeysvalueof{/tikz/bridging span}}, spath/join components upright with={#1}{\pgfkeysvalueof{/tikz/bridging path}}, spath/split at intersections with={#2}{#1}, spath/insert gaps after components={#2}{\pgfkeysvalueof{/tikz/bridging gap}}, }, rbridge/.style 2 args={ spath/split at intersections with={#1}{#2}, spath/insert gaps after components={#1}{\pgfkeysvalueof{/tikz/bridging span}}, spath/join components upright with={#1}{\pgfkeysvalueof{/tikz/bridging rpath}}, spath/split at intersections with={#2}{#1}, spath/insert gaps after components={#2}{\pgfkeysvalueof{/tikz/bridging gap}}, }, } \AtBeginDocument{% \tikz[overlay] { \path[spath/save global=intersection arc] (0,0) arc[ radius=1cm, start angle=180, delta angle=-180]; }% \tikz[overlay] { \path[spath/save global=intersection reverse arc] (0,0) arc[ radius=1cm, start angle=-180, delta angle=180]; }% } \begin{document} \fontsize{14}{14} \def\offset{8pt} \begin{tikzpicture}[ node distance=4cm, arrow/.style={-Triangle, line width=1pt}, ] \node (c) {}; \node[draw,above=of c] (above) {above}; \node[draw,left=of c] (left) {left}; \node[draw,below=of c] (below) {below}; \node[draw,right=of c] (right) {right}; \path[spath/save=abovebelow] ([xshift=-\offset]above.south) -- ([xshift=-\offset]below.north) node[start, above, rotate=90] {above--below}; \path[spath/save=belowabove] ([xshift=\offset]below.north) -- ([xshift=\offset]above.south) node[start, below, rotate=90] {below--above}; \path[spath/save=leftright] ([yshift=-\offset] left.east) -- ([yshift=-\offset] right.west) node[start, below] {left--right}; \path[spath/save=rightleft] ([yshift=\offset] right.west) -- ([yshift=\offset] left.east) node[start, above] {right--left}; \tikzset{ bridging span/.initial=8pt, bridging gap/.initial=4pt, bridge={abovebelow}{rightleft}, bridge={leftright}{abovebelow}, bridge={belowabove}{leftright}, bridge={rightleft}{belowabove}, % bridge={abovebelow}{rightleft}, % bridge={abovebelow}{leftright}, % rbridge={belowabove}{rightleft}, % rbridge={belowabove}{leftright}, } \draw[arrow, spath/use=abovebelow]; \draw[arrow, spath/use=belowabove]; \draw[arrow, spath/use=leftright]; \draw[arrow, spath/use=rightleft]; \end{tikzpicture} \end{document} ```