summaryrefslogtreecommitdiff
path: root/graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex
diff options
context:
space:
mode:
Diffstat (limited to 'graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex')
-rw-r--r--graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex1417
1 files changed, 1262 insertions, 155 deletions
diff --git a/graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex b/graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex
index d73c1ad0bd..af29676b46 100644
--- a/graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex
+++ b/graphics/pgf/contrib/zx-calculus/tikzlibraryzx-calculus.code.tex
@@ -1,5 +1,5 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-%%% Version: 2021/10/15
+%%% Version: 2021/10/22
%%% License: MIT
%%% Author: Léo Colisson
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
@@ -15,7 +15,7 @@
\RequirePackage{xparse} % For NewDocumentComments
\RequirePackage{bm} % For bold math fonts
-\usetikzlibrary{cd,backgrounds,positioning,shapes,calc}
+\usetikzlibrary{cd,backgrounds,positioning,shapes,calc,intersections}
% Declare layers.
\pgfdeclarelayer{background} % Fox boxes using "fit" to group parts of the graph.
\pgfdeclarelayer{edgelayer} % For edges that are explicitely defined "wc"
@@ -28,6 +28,7 @@
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% User modifiable variables
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
% Define colors, can be redefine by user
\definecolor{colorZxZ}{RGB}{204,255,204}
\definecolor{colorZxX}{RGB}{255,136,136}
@@ -54,12 +55,31 @@
\newcommand{\zxHSColFlat}{1mm}
\newcommand{\zxHSRowFlat}{1mm}
%% Wires only: when adding only wires with empty nodes, the space between columns can be too small. Useful not to shrink swap gates...
-\newcommand{\zxWCol}{.55em}
-\newcommand{\zxWRow}{.55em}
+\newcommand{\zxWCol}{2mm}
+\newcommand{\zxWRow}{2mm}
+%% Same as zxWCol, but when a single empty node is connected to a non-empty node.
+\newcommand{\zxwCol}{1mm}
+\newcommand{\zxwRow}{1mm}
%% When vdots/dots are used in lines
\newcommand{\zxDotsCol}{3mm}
\newcommand{\zxDotsRow}{3mm}
+%% Default separation between rows and columns
+\newcommand{\zxDefaultColumnSep}{1.5mm}
+\newcommand{\zxDefaultRowSep}{1.5mm}
+% To cancel the default tow separation
+\newcommand{\zxZeroCol}{-\zxDefaultColumnSep}
+\newcommand{\zxZeroRow}{-\zxDefaultRowSep}
+%% When adding two lines with only empty nodes, it can create quite a large space. Use this to reduce it
+%% Yes, we can add multiple arguments, space will add up (see documentation pgfmatrixnextcell)
+\newcommand{\zxNCol}{-\zxDefaultColumnSep,.5mm}
+\newcommand{\zxNRow}{-\zxDefaultRowSep,.5mm}
+
+% Angles by default for s and o related arrows
+\def\zxDefaultSoftAngleS{30}
+\def\zxDefaultSoftAngleN{60}
+\def\zxDefaultSoftAngleO{40}
+\def\zxDefaultSoftAngleChevron{60}
% Angles by default for s and o related arrows
\def\zxDefaultSoftAngleS{30}
@@ -67,6 +87,42 @@
\def\zxDefaultSoftAngleO{40}
\def\zxDefaultSoftAngleChevron{60}
+% Angles by default for s and o related arrows (in/out version)
+\def\zxDefaultSoftAngleN{60}
+\def\zxDefaultSoftAngleO{40}
+\def\zxDefaultSoftAngleChevron{60}
+
+% Styles for O,N,... (new bezier version)
+\tikzset{
+ /zx/args/-andL/.cd,
+ defaultO/.style={-=.2,L=.4},
+ defaultN/.style={-=.2,L=.8},
+ defaultN-/.style={1-=.4,1L=0},
+ defaultNN/.style={},
+ defaultNIN/.style={1-=0,1L=.6},
+ defaultChevron/.style={}, % < should be stronger than N- also in ui mode.
+ defaultChevronDown/.style={}, % The ^ v versions (default NN and default NIN will be loaded before).
+ defaultS/.style={-=.8,L=0},
+ defaultS'/.style={-=.8,L=.2},
+ default-S/.style={1-=.8,1L=0},
+ defaultSIS/.style={1-=0,1L=.8},
+ % Loads the default styles for the "use intersection" method.
+ /zx/args/-andL/ui/.style={
+ /zx/args/-andL/defaultO/.style={-=.2,L=.17},
+ /zx/args/-andL/defaultN/.style={-=.2,L=.7},
+ /zx/args/-andL/defaultN-/.style={1-=.5,1L=.2,2-=.2,2L=.5}, %% Todo: write a different style for <
+ /zx/args/-andL/defaultNN/.style={},
+ /zx/args/-andL/defaultChevron/.style={1-=.2,1L=0,2-=.2,2L=.8},
+ /zx/args/-andL/defaultChevronDown/.style={1L=.2,1-=0,2L=.2,2-=.8},
+ /zx/args/-andL/defaultNIN/.style={1-=0,1L=.66,2-=.55,2L=.16},
+ /zx/args/-andL/defaultS/.style={-=.8,L=0},
+ /zx/args/-andL/defaultS'/.style={-=.8,L=.3},
+ /zx/args/-andL/default-S/.style={1-=.8,1L=0},
+ /zx/args/-andL/defaultSIS/.style={1-=0,1L=.8,2-=.15,2L=.6},
+ },
+}
+
+
% Scale to use when scaling 3 dots
\def\zxScaleDots{.7}
@@ -86,11 +142,410 @@
\ifthenelse{\equal{#1}{-}}{\zxMinus}{#1}#4/#5%
}
+% Minus sign to use in \zxZ-{\alpha}
+%\NewExpandableDocumentCommand{\zxMinusInShort}{}{-}
+\NewExpandableDocumentCommand{\zxMinusInShort}{}{-}
+
+% The library tries to find intersection between fake center east/... and the border of the node
+% to draw the nodes directly on the border.
+% To enable this function (can also be set locally), enable this macro:
+% \def\zxEnableIntersectionsNodes{} %% To add the "name shape" on each node
+% \def\zxEnableIntersectionsWires{} %% For wires only (can't work without \zxEnableIntersectionsNodes)
+\newcommand{\zxEnableIntersections}{%
+ \def\zxEnableIntersectionsWires{}%
+ \def\zxEnableIntersectionsNodes{}%
+}
+% to disable intersections, undefined it:
+\let\zxEnableIntersectionsNodes\undefined
+\let\zxEnableIntersectionsWires\undefined
+\newcommand{\zxDisableIntersections}{%
+ \let\zxEnableIntersectionsNodes\undefined%
+ \let\zxEnableIntersectionsWires\undefined%
+}
+% Now, if it cannot find a good intersection (either because "name path" is disabled, or
+% because no intersection is found, or because intersections are disabled anyway) we need to
+% have a fallback mechanism. Either we choose instead the "fake center" (or center if fake
+% center does not exists), but then the wire will be hidden behind the node (it is a problem
+% mostly if you use H nodes a lot, otherwise we recommend this solution):
+\def\zxWireInsideIfNoIntersectionName{}
+% If you prefer to start the wire on the surface of the node, do that instead...
+% but be aware that the shape of the wire will be changed a lot, since we can't use anymore the
+% fake anchors... You could also define a style that does that.
+% \let\zxWireInsideIfNoIntersectionName\undefined
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%%% Adding anchors
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+% We add anchors "fake center {north, south, east, west}" to the nodes. The wires will leave from these anchors (except in IO mode) depending on the direction. If the anchor does not exist, center is picked.
+% https://tex.stackexchange.com/questions/14769/add-more-anchors-to-standard-tikz-nodes
+\def\zx@pgfaddtoshape#1#2{%
+ \begingroup
+ \def\pgf@sm@shape@name{#1}%
+ \let\anchor\pgf@sh@anchor
+ #2%
+ \endgroup
+}
+\def\zx@useanchor#1#2{\csname pgf@anchor@#1@#2\endcsname}
+\zx@pgfaddtoshape{rounded rectangle}{%
+ \anchor{fake center east}{%
+ \zx@useanchor{rounded rectangle}{north east}%
+ \pgf@yc=.5\pgf@y% final y = 0.5*this y + 0.5*other y.
+ \zx@useanchor{rounded rectangle}{south east}%
+ \pgf@y=.5\pgf@y%
+ \advance\pgf@y by \pgf@yc%
+ }%
+ \anchor{fake center west}{%
+ \zx@useanchor{rounded rectangle}{north west}%
+ \pgf@yc=.5\pgf@y% final y = 0.5*this y + 0.5*other y.
+ \zx@useanchor{rounded rectangle}{south west}%
+ \pgf@y=.5\pgf@y%
+ \advance\pgf@y by \pgf@yc%
+ }%
+ \anchor{fake center north}{%
+ \zx@useanchor{rounded rectangle}{center}%
+ }%
+ \anchor{fake center south}{%
+ \zx@useanchor{rounded rectangle}{center}%
+ }%
+}
+
+\zx@pgfaddtoshape{coordinate}{%
+ \anchor{fake center east}{%
+ \zx@useanchor{coordinate}{center}%
+ }%
+ \anchor{fake center west}{%
+ \zx@useanchor{coordinate}{center}%
+ }%
+ \anchor{fake center north}{%
+ \zx@useanchor{coordinate}{center}%
+ }%
+ \anchor{fake center south}{%
+ \zx@useanchor{coordinate}{center}%
+ }%
+}
+
+\zx@pgfaddtoshape{circle}{%
+ \anchor{fake center east}{%
+ \zx@useanchor{circle}{center}%
+ }%
+ \anchor{fake center west}{%
+ \zx@useanchor{circle}{center}%
+ }%
+ \anchor{fake center north}{%
+ \zx@useanchor{circle}{center}%
+ }%
+ \anchor{fake center south}{%
+ \zx@useanchor{circle}{center}%
+ }%
+}
+
+\zx@pgfaddtoshape{rectangle}{
+ \anchor{fake center east}{%
+ \zx@useanchor{rectangle}{center}%
+ }%
+ \anchor{fake center west}{%
+ \zx@useanchor{rectangle}{center}%
+ }%
+ \anchor{fake center north}{%
+ \zx@useanchor{rectangle}{center}%
+ }%
+ \anchor{fake center south}{%
+ \zx@useanchor{rectangle}{center}%
+ }%
+}
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%% Tikz styles
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% For arguments later:
+\tikzset{
+ /zx/args/-andL/.cd,
+ % - is "towards the point", or "x value",
+ % L is "perpendicular to the line going towards the point" (L is for the perpendicular shape), or "y value".
+ 1-/.initial=.5, % random value, defaultO... will change that.
+ 2-/.initial=.5,
+ -/.style={
+ 1-=#1,
+ 2-=#1,
+ },
+ 1L/.initial=.5,
+ 2L/.initial=.5,
+ L/.style={
+ 1L=#1,
+ 2L=#1,
+ },
+ symmetry-L/.code={% 1- <-> 1L, 2- <-> 2L
+ \edef\zx@tmpone{\pgfkeysvalueof{/zx/args/-andL/1-}}%
+ \edef\zx@tmptwo{\pgfkeysvalueof{/zx/args/-andL/2-}}%
+ \pgfkeysalso{%
+ 1-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/1L},
+ 2-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2L},
+ 1L/.evaluated=\zx@tmpone,
+ 2L/.evaluated=\zx@tmptwo,
+ }%
+ },
+ symmetry/.code={% 1- <-> 2-, 1L <-> 2L
+ \edef\zx@tmpone{\pgfkeysvalueof{/zx/args/-andL/1-}}%
+ \edef\zx@tmptwo{\pgfkeysvalueof{/zx/args/-andL/1L}}%
+ \pgfkeysalso{
+ 1-/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2-},
+ 1L/.evaluated=\pgfkeysvalueof{/zx/args/-andL/2L},
+ 2-/.evaluated=\zx@tmpone,
+ 2L/.evaluated=\zx@tmptwo,
+ }%
+ },
+ negate1L/.style={
+ /zx/args/-andL/1L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1L},
+ },
+ negate2L/.style={
+ /zx/args/-andL/2L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2L},
+ },
+ negateL/.style={
+ negate1L,
+ negate2L,
+ },
+ negate1-/.style={
+ /zx/args/-andL/1-/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1-},
+ },
+ negate2-/.style={
+ /zx/args/-andL/2-/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2-},
+ },
+ negate-/.style={
+ negate1-,
+ negate2-,
+ },
+ negateL/.style={
+ negate1L,
+ negate2L,
+ },
+ oneMinus1-/.style={
+ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-},
+ },
+ oneMinus2-/.style={
+ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-},
+ },
+ oneMinus1L/.style={
+ /zx/args/-andL/1L/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/1L},
+ },
+ oneMinus2L/.style={
+ /zx/args/-andL/2L/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2L},
+ },
+ % Angle/length:
+ 1 angle and length/.code 2 args={%
+ \pgfmathparse{#2*cos(#1)}%
+ \pgfkeysalso{1-/.expand once=\pgfmathresult}%
+ \pgfmathparse{#2*sin(#1)}%
+ \pgfkeysalso{1L/.expand once=\pgfmathresult}%
+ },
+ 2 angle and length/.code 2 args={%
+ \pgfmathparse{#2*cos(#1)}%
+ \pgfkeysalso{2-/.expand once=\pgfmathresult}%
+ \pgfmathparse{#2*sin(#1)}%
+ \pgfkeysalso{2L/.expand once=\pgfmathresult}%
+ },
+ 1al/.style 2 args={
+ 1 angle and length={#1}{#2}
+ },
+ 2al/.style 2 args={
+ 2 angle and length={#1}{#2}
+ },
+ al/.style 2 args={
+ 1 angle and length={#1}{#2},
+ 2 angle and length={#1}{#2},
+ },
+ 1 angle/.style={
+ 1 angle and length={#1}{.6}
+ },
+ 2 angle/.style={
+ 2 angle and length={#1}{.6}
+ },
+ 1a/.style={
+ 1 angle={#1},
+ },
+ 2a/.style={
+ 2 angle={#1},
+ },
+ angle/.style={
+ 1 angle={#1},
+ 2 angle={#1},
+ },
+ a/.style={
+ 1 angle and length={#1}{.6},
+ 2 angle and length={#1}{.6},
+ },
+}
+
+%%% Useful debug functions
+%% This function will be called when debugging the library.
+\def\zx@message#1{}
+% The ^^J adds a new line:
+\def\zx@verbose@message#1{\message{#1^^J}} % For more important messages. Like to show the code is not looping forever
+% To enable debugging:
+% WARNING: if you use in code, do not forget the makeatletter!
+%\def\zx@message#1{\message{#1^^J}}
+% To display stroke of while trying to compute the intersections:
+% WARNING: if you use in code, do not forget the makeatletter!
+%\def\zx@draw@stroke@inter@debug{}
+
+
+%% This function checks if the node has a "name path", if so it computes the intersection between
+%% if not if \zxWireInsideIfNoIntersectionName is defined it defines the \tikzto* to the
+%% new@center (argument #2), otherwise it does nothing.
+% #1: Node to consider: \tikztostart or \tikztotarget
+% #2: name of the new@center node corresponding to #1
+% #3: name of the other new@center node
+% #4: result will be stored in this macro... if there is something to change.
+% #5: 1 if start, 2 if end
+% Result will be moved back into #1
+\def\zx@find@intersection@fakecenter#1#2#3#4#5{%
+ % First, we check if the user wants to compute the intersection:
+ \ifdefined\zxEnableIntersectionsWires%
+ %% We compute the intersection
+ \edef\tikz@intersect@path@a{zx@name@path@#1}%
+ \ifcsname tikz@intersect@path@name@\tikz@intersect@path@a \endcsname%
+ \zx@verbose@message{[ZX] I will start computing intersections}%
+ \pgfintersectionofpaths{%
+ \begin{pgfinterruptboundingbox}%
+ %%%% /!\ This lines is the one I'm not sure how to write:
+ \expandafter\pgfsetpath\csname tikz@intersect@path@name@\tikz@intersect@path@a\endcsname%
+ \pgfgetpath\temppath%
+ \ifdefined\zx@draw@stroke@inter@debug%
+ \pgfusepath{stroke} % We draw it, useful to debug, and realize the shape is moved.
+ \fi%
+ \pgfsetpath\temppath%
+ \end{pgfinterruptboundingbox}%
+ }{% The first path is moved to the center... So we need to shift it also here.
+ %%% First intersection: we use the line between the two nodes... but it's really ugly (e.g. in o it does not make a lot of sense)
+ \begin{pgfinterruptboundingbox}%
+ \ifdefined\zxIntersectionLineBetweenStartEnd%
+ %% Not idea why, but x axis is inverted???
+ \pgfpointdiff{\tikz@scan@one@point\pgf@process(#2)}{\pgfpointanchor{#1}{center}}%
+ \pgfpathmoveto{\pgfpoint{-\pgf@x}{\pgf@y}}%
+ % And now both axis are???
+ \pgfpointdiff{\tikz@scan@one@point\pgf@process(#3)}{\pgfpointanchor{#1}{center}}%
+ \pgfpathlineto{\pgfpoint{-\pgf@x}{-\pgf@y}}%
+ \else%
+ %% We use now the method used for bezier curve (at least it's what I see "experimentally")
+ %% More precisely, we use the direction of the bezier curve to know where to start the wire.
+ %% Parse once the control points for efficiency reasons:
+ %% First parse the fake centers.
+ \tikz@scan@one@point\pgf@process(#2)%
+ \edef\zx@tmp@current@fake@x{\the\pgf@x}%
+ \edef\zx@tmp@current@fake@y{\the\pgf@y}%
+ \zx@message{The input fakes are #2 and #3.}%
+ \tikz@scan@one@point\pgf@process(#3)%
+ \edef\zx@tmp@other@fake@x{\the\pgf@x}%
+ \edef\zx@tmp@other@fake@y{\the\pgf@y}%
+ \zx@message{The parsed input fakes are (\zx@tmp@current@fake@x , \zx@tmp@current@fake@y) and (\zx@tmp@other@fake@x , \zx@tmp@other@fake@y).}%
+ %% Reorder the controls to compute. #5 = 1 if "start fake center" is "current fake center".
+ \ifnum#5=1 % <-- important space!!!
+ \edef\zx@tmp@start@fake@x{\zx@tmp@current@fake@x}%
+ \edef\zx@tmp@start@fake@y{\zx@tmp@current@fake@y}%
+ \edef\zx@tmp@end@fake@x{\zx@tmp@other@fake@x}%
+ \edef\zx@tmp@end@fake@y{\zx@tmp@other@fake@y}%
+ \else%
+ \edef\zx@tmp@end@fake@x{\zx@tmp@current@fake@x}%
+ \edef\zx@tmp@end@fake@y{\zx@tmp@current@fake@y}%
+ \edef\zx@tmp@start@fake@x{\zx@tmp@other@fake@x}%
+ \edef\zx@tmp@start@fake@y{\zx@tmp@other@fake@y}%
+ \fi%
+ \zx@message{We computed: start fake (\zx@tmp@start@fake@x , \zx@tmp@start@fake@y) end fake (\zx@tmp@end@fake@x , \zx@tmp@end@fake@y )}%
+ \pgfkeysalso{/zx/tmp/zx@getControlPoints={\zx@tmp@start@fake@x}{\zx@tmp@start@fake@y}{\zx@tmp@end@fake@x}{\zx@tmp@end@fake@y}}%
+ % Now results are in controlOne, and controlTwo
+ \ifnum#5=1 \relax%
+ \def\zx@control{\controlOne}%
+ \else%
+ \def\zx@control{\controlTwo}%
+ \fi%
+ %%% Parse new control
+ \tikz@scan@one@point\pgf@process(\zx@control)%
+ \edef\zx@tmp@current@ctrl@x{\the\pgf@x}%
+ \edef\zx@tmp@current@ctrl@y{\the\pgf@y}%
+ \zx@message{[ZX] Current control is number #5, i.e. \zx@control (both are \controlOne and \controlTwo)}%
+ % We store the center coordinates since it's used several times
+ \pgfpointanchor{#1}{center}%
+ \edef\zx@tmp@real@center@x{\the\pgf@x}%
+ \edef\zx@tmp@real@center@y{\the\pgf@y}%
+ %%% Go to current fake center, except that real center is the new origin.
+ \pgfpointdiff{\pgfpoint{\zx@tmp@real@center@x}{\zx@tmp@real@center@y}}{\pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}}%
+ \pgfpathmoveto{\pgfpoint{\pgf@x}{\pgf@y}}%
+ %% What, now both axis are inverted??? If someone can explain me this...
+ %% We scale the point to force it to cross the boundary.
+ \pgfpathlineto{%
+ \pgfpointadd{%
+ \pgf@process{%
+ \pgfpointscale{10}{%
+ \pgf@process{%
+ \pgfpointdiff{%
+ \pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}%
+ }{%
+ \pgfpoint{\zx@tmp@current@ctrl@x}{\zx@tmp@current@ctrl@y}%
+ }%
+ }%
+ }%
+ }%
+ }{%
+ \pgfpointdiff{%
+ \pgfpoint{\zx@tmp@real@center@x}{\zx@tmp@real@center@y}%
+ }{%
+ \pgfpoint{\zx@tmp@current@fake@x}{\zx@tmp@current@fake@y}%
+ }%
+ }%
+ }%
+ \fi%
+ \pgfgetpath\temppath%
+ \ifdefined\zx@draw@stroke@inter@debug%
+ \pgfusepath{stroke}% We draw it, useful to debug, and realize the shape is moved.
+ \fi%
+ \pgfsetpath\temppath%
+ \end{pgfinterruptboundingbox}%
+ }%
+ \pgfintersectionsolutions%
+ \pgfpointintersectionsolution{1}%
+ \ifnum\pgfintersectionsolutions=1%% The good number of solution has been found!
+ \zx@message{[ZX] Cool, just found one solution!}
+ %% Store the intersection (warning: the center of the shape is moved to the center!)
+ \edef\zx@relinter@x{\the\pgf@x}%
+ \edef\zx@relinter@y{\the\pgf@y}%
+ %% Because the shape was moved to center, we shift it back by adding the coord of the shape:
+ \pgfextractx\pgf@xa{\pgfpointanchor{#1}{center}}%
+ \pgfextractx\pgf@xb{\pgfpointanchor{#1}{center}}%
+ % WARNING! pgfmath removes the dimension (converted in pt). Make sure to put them back after
+ \pgfmathsetmacro{\zx@inter@x}{\pgf@x+\zx@relinter@x}%
+ \pgfmathsetmacro{\zx@inter@y}{\pgf@y+\zx@relinter@y}%
+ \edef#4{\zx@inter@x pt,\zx@inter@y pt}%
+ \else% The bad number of solution has been found
+ \zx@message{[ZX] WARNING: expecting one solution, found \pgfintersectionsolutions}%
+ \ifdefined\zxWireInsideIfNoIntersectionName%
+ % No intersection was found, but still want to use fake center (or center).
+ % ==> The wire will be inside the shape
+ % Basically \tikztostart := tikztostart@new@center
+ \edef#4{#2}%
+ \fi% Otherwise, do nothing
+ \fi%
+ \else%
+ \zx@message{ZX: no path named \tikz@intersect@path@a was found.}%
+ \ifdefined\zxWireInsideIfNoIntersectionName%
+ % No intersection was found, but still want to use fake center (or center).
+ % ==> The wire will be inside the shape
+ % Basically \tikztostart := tikztostart@new@center
+ \edef#4{#2}%
+ \fi% Otherwise, do nothing
+ \fi%
+ \else%
+ \zx@message{[ZX]: intersection mechanism disabled}%
+ \ifdefined\zxWireInsideIfNoIntersectionName%
+ % No intersection was found, but still want to use fake center (or center).
+ % ==> The wire will be inside the shape
+ % Basically \tikztostart := tikztostart@new@center
+ \edef#4{#2}%
+ \fi% Otherwise, do nothing
+ \fi%
+}%
+
% Styles. User should not modify "wires definition", but is free to change:
% - "/zx/default style nodes/" to change completely the node style
% - "/zx/user overlay nodes" to add stuff on current node style
@@ -110,7 +565,7 @@
looseness=1.2,
},
lw/.style={looseness wires only},
- % Use this when you are drawing lines between none nodes only (like swap gates...)
+ % Use this when you are drawing lines between none nodes only (like swap gates...) in IO mode
between none/.style={
looseness wires only,
wire centered
@@ -118,6 +573,50 @@
bn/.style={
between none
},
+ % To debug the bezier curve.
+ edge above/.code={%
+ \def\zxEdgesAbove{}%
+ },%
+ edge not above/.code={%
+ \let\zxEdgesAbove\undefined%
+ },
+ control points visible/.code={%
+ \def\zxControlPointsVisible{}%
+ },%
+ control points not visible/.code={%
+ \let\zxControlPointsVisible\undefined%
+ },
+ % See explaination at the beginning where we define \def\zxEnableIntersectionsWires{}
+ % Rouhgly, tries to start the wires on the border of the shape on the line between the
+ % fake anchors.
+ use intersections/.code={%
+ \def\zxEnableIntersectionsWires{}%
+ },
+ dont use intersections/.code={%
+ \let\zxEnableIntersectionsWires\undefined%
+ },
+ ui/.style={
+ use intersections,
+ /zx/args/-andL/ui
+ },
+ intersections mode between start end/.code={%
+ \def\zxIntersectionLineBetweenStartEnd{}%
+ },
+ intersections mode bezier controls/.code={%
+ \let\zxIntersectionLineBetweenStartEnd\undefined%
+ },
+ wires behind nodes/.code={%
+ \def\zxWireInsideIfNoIntersectionName{}%
+ },
+ no wires behind nodes/.code={%
+ \let\zxWireInsideIfNoIntersectionName\undefined%
+ },
+ intersection between start end/.code={
+ \def\zxIntersectionLineBetweenStartEnd{}%
+ },
+ intersection bezier control/.code={
+ \let\zxIntersectionLineBetweenStartEnd\undefined%
+ },
% ------------------------------
% Practical stuff to draw lines easily:
% Prefer to use these are they can be easily customized for each style and shorter to type.
@@ -133,7 +632,7 @@
% If only tex was a functional language... https://tex.stackexchange.com/questions/618955
C@generic/.style n args={8}{ % min/max, angle1, angle2, anchor, \x or \y, \y or \x, where to move,radius code (for circle should be "radius=\n3")
to path={
- \pgfextra{ %% <- we will use def... so need to "exit" a few seconds pgf
+ \pgfextra{%% <- we will use def... so need to "exit" a few seconds pgf
% Test if tikztostart is a point or a node, and define StartPoint accordingly.
\ifPgfpointOrNode{\tikztostart}{%
\def\StartPoint{\tikztostart}%
@@ -163,24 +662,32 @@
}%
\ifpgfmathcomparison\else -- ##7\fi
%%%% Version 1:
- \pgfextra{
- \pgfmathparse{
+ \pgfextra{%
+ \pgfmathparse{%
ifthenelse(##61<##62, % if end angle < angle, draw clockwis
"arc[start angle=##3,end angle=##2,##8]",%
"arc[start angle=##2,end angle=##3,##8]"%
)%
- }
- }
- \pgfmathresult
+ }%
+ }%
+ \pgfmathresult%
\pgfextra{%
%% We check if we are moving or not (required to preserve arrow tip direction)
\pgfmathapproxequalto{##52}{\n1}%
}%
\ifpgfmathcomparison\else -- (\TargetPoint)\fi
- \tikztonodes % All to path finishes with that to deal with futur nodes I think
+ \tikztonodes% All to path finishes with that to deal with futur nodes I think
}
},
- %%
+ % At the first version, styles were defined using in=... out=... looseness=... However
+ % it gives sometimes bad results (like the curve goes forward at some points) when nodes are
+ % too close or too far appart. However, it may still be useful, so now we define the old
+ % styles, that you can use them using \ar[r,IO,C].
+ % NB: for the newest styles, we add new anchors to the nodes depending on the direction.
+ % I also wanted to add more complicated ways to configqure the starting point (i.e. start at the boundary
+ % and not behind the node), but seems like it's hard (impossible?) to do with matrices...
+ % The reason is that the intersection library seems to fail with matrices.
+ % If you know how to solve that, you can help here: https://tex.stackexchange.com/questions/619274
C/.style={C@generic={min}{90}{180+90}{west}{\x}{\y}{(\n1,\y1)}{y radius=\n3, x radius=##1*\n3}},
C/.default=1,
% Like C, but rotated
@@ -190,97 +697,568 @@
C'/.default=1,
C./.style={C@generic={min}{0}{-180}{south}{\y}{\x}{(\x1,\n1)}{x radius=\n3, y radius=##1*\n3}},
C./.default=1,
- % Like a C shape (with without a perfect half circle). This was the old definition of C...
- % Hopefully not useful anymore.
- c/.style={/tikz/in=180,/tikz/out=180,looseness=2},
- % Like C, but symetric
- c-/.style={/tikz/in=0,/tikz/out=0,looseness=2},
- c'/.style={/tikz/in=90,/tikz/out=90,looseness=2},
- c./.style={/tikz/in=-90,/tikz/out=-90,looseness=2},
+ %%% bezier{px1}{py1}{px2}{py2} creates a bezier curve where px1/py1 are the
+ %%% coordinates of the first control (in "percentage" 0<px1<1, between start and end point) and px2/py2
+ %%% are the coordinates in % of the second control point
+ %%% bezier@general is used to construct also x/y versions, 5 and 6'th argument are \x or \y.
+ bezier@general/.style n args={6}{
+ possibly@on@edge@layer/.code={%% see "edges above" style. for debug mode only.
+ \ifdefined\zxEdgesAbove\else%
+ \pgfkeysalso{%
+ on layer=edgelayer%
+ }%
+ \fi%
+ },
+ possibly@on@edge@layer,
+ to path={%
+ %%% First, check that inputs/outputs are points.
+ \pgfextra{% <- Type latex code inside path
+ %% Setup the startup node. This code can be changed by styles
+ %% /zx/tmp/zx@setup@start@node will contain the anchor of the first fake center
+ %% /zx/tmp/zx@setup@end@node will contain the anchor of the second fake center
+ %% If none of them are defined, nothing happens and the start point will be a node.
+ % Retrieve the content of the keys
+ % But first check if they are defined
+ \pgfkeysifdefined{/zx/tmp/zx@setup@start@node}{}{% Put an empty value
+ \pgfkeysalso{/zx/tmp/zx@setup@start@node/.initial=,}%
+ }%
+ \pgfkeysifdefined{/zx/tmp/zx@setup@end@node}{}{% Put an empty value
+ \pgfkeysalso{/zx/tmp/zx@setup@end@node/.initial=,}%
+ }%
+ \pgfkeysalso{
+ /zx/tmp/zx@setup@start@node/.get=\zx@anchor@start@node,
+ /zx/tmp/zx@setup@end@node/.get=\zx@anchor@end@node,
+ /zx/tmp/zx@getControlPoints/.code n args={4}{%
+ \zx@message{I will evaluate my control points:}%
+ % Args: start point, x,y then end point x,y
+ % Use ########1 ... (yes, LaTeX is a funny exponential language, and I love nested functions)
+ % Because to path is considered as a function already.
+ \def\x################1{%
+ \ifnum################1=1 % <-- super important space...
+ ########1%
+ \else%
+ ########3%
+ \fi%
+ }%
+ \zx@message{[ZX] x is defined.}%
+ \def\y################1{%
+ \ifnum ################1 = 1 % <-- super important space...
+ ########2%
+ \else%
+ ########4%
+ \fi%
+ }%
+ \tikz@scan@one@point\pgf@process(\x1-##51*##1+##52*##1,\y1-##61*##2+##62*##2)%
+ \edef\controlOne{\the\pgf@x,\the\pgf@y}%
+ \tikz@scan@one@point\pgf@process(\x1-##51*##3+##52*##3,\y1-##61*##4+##62*##4)%
+ \edef\controlTwo{\the\pgf@x,\the\pgf@y}%
+ \zx@message{[ZX] First control point is: \controlOne, second is \controlTwo.}%
+ },%
+ }%
+ %%% This will be the new \tikztostart and \tikztotarget... if someone defines them
+ \let\new@tikztostart\undefined%
+ \let\new@tikztotarget\undefined%
+ % Check if a start anchor was defined...
+ \ifthenelse{\equal{\zx@anchor@start@node}{}}{%
+ % No start anchor was chosen... :c
+ \ifthenelse{\equal{\zx@anchor@end@node}{}}{%
+ % Nothing was defined... So I won't do anything! :C
+ }{%
+ % An end node was defined :D Let's configure its end anchor.
+ \pgfkeysalso{%
+ /zx/utils/change@tikz@fake@center@intersect={\tikztotarget}{\zx@anchor@end@node}{\tikztostart}{center}{\new@tikztotarget}{2},
+ }%
+ }%
+ }{% A start node was chosen :D
+ \ifthenelse{\equal{\zx@anchor@end@node}{}}{%
+ % No end node was chosen... I'll take center to configure the start node,
+ % and not configure the end node.
+ \pgfkeysalso{
+ /zx/utils/change@tikz@fake@center@intersect={\tikztostart}{\zx@anchor@start@node}{\tikztotarget}{center}{\new@tikztostart}{1},
+ }%
+ }{%
+ % And an end node was chosen :D
+ \zx@message{[ZX] Both anchors are set. Lets configure intersection.}%
+ \pgfkeysalso{
+ /zx/utils/change@tikz@fake@center@intersect={\tikztostart}{\zx@anchor@start@node}{\tikztotarget}{\zx@anchor@end@node}{\new@tikztostart}{1},
+ /zx/utils/change@tikz@fake@center@intersect={\tikztotarget}{\zx@anchor@end@node}{\tikztostart}{\zx@anchor@start@node}{\new@tikztotarget}{2},
+ }%
+ }%
+ }%
+ \ifdefined\new@tikztostart%
+ \edef\tikztostart{\new@tikztostart}%
+ \fi%
+ \ifdefined\new@tikztotarget%
+ \edef\tikztotarget{\new@tikztotarget}%
+ \fi%
+ %%% Test if tikztostart is a point or a node, and define StartPoint accordingly.
+ % \ifPgfpointOrNode{\tikztostart}{%
+ % \def\StartPoint{\tikztostart}%
+ % }{%
+ % \def\StartPoint{\tikztostart.center}%
+ % }%
+ % % Test if tikztostart is a point or a node, and define StartPoint accordingly.
+ % \ifPgfpointOrNode{\tikztotarget}{%
+ % \def\TargetPoint{\tikztotarget}%
+ % }{%
+ % \def\TargetPoint{\tikztotarget.center}%
+ % }%
+ %%% Well, let's just use \tikztostart and \tikztotarget in any case, setting it to
+ %%% center will put the wire below the node which is not really desired for H nodes
+ %%% (position will be wrong) or when using arrows. And if center is really desired
+ %%% it's easy to force it using start anchor and end anchor.
+ \def\StartPoint{\tikztostart}%
+ \def\TargetPoint{\tikztotarget}%
+ %%% TODO: check that it does not change the shape of the wire since I'm not sure what \x1
+ %%% is in that case%
+ }%
+ let
+ \p1=(\StartPoint),
+ \p2=(\TargetPoint),%% ##5 = \x or \y, so ##51 = \x1 or \y1.
+ \p{control1}=(\x1-##51*##1+##52*##1, \y1-##61*##2+##62*##2),
+ \p{control2}=(\x1-##51*##3+##52*##3, \y1-##61*##4+##62*##4) in
+ (\StartPoint) .. controls (\p{control1}) and (\p{control2}) .. (\TargetPoint)
+ \ifdefined\zxControlPointsVisible
+ (\StartPoint) node[anchor=center,circle,fill=yellow,inner sep=.5pt,on layer=foreground]{}
+ -- (\p{control1}) node[anchor=center,circle,fill=orange,inner sep=.5pt,on layer=foreground]{}
+ (\p{control2}) node[anchor=center,circle,fill=purple,inner sep=.5pt,on layer=foreground]{}
+ -- (\TargetPoint) node[anchor=center,circle,fill=brown,inner sep=.5pt,on layer=foreground]{}
+ \fi
+ \tikztonodes
+ },
+ },
+ %% Not sure it will be very useful, compared to bezier, bezier x and bezier y directly.
+ bezier 4/.style n args={4}{
+ bezier@general={##1}{##2}{##3}{##4}{\x}{\y},
+ },
+ % Like bezier, all proportions are relative to x distance
+ bezier 4 x/.style n args={4}{
+ bezier@general={##1}{##2}{##3}{##4}{\x}{\x}
+ },
+ % Like bezier, all proportions are relative to y distance
+ bezier 4 y/.style n args={4}{
+ bezier@general={##1}{##2}{##3}{##4}{\y}{\y}
+ },
+ bezier/.code={%
+ \pgfkeys{
+ /zx/args/-andL/.cd,
+ ##1
+ }%
+ \pgfkeysalso{
+ bezier 4={\pgfkeysvalueof{/zx/args/-andL/1-}}{\pgfkeysvalueof{/zx/args/-andL/1L}}{\pgfkeysvalueof{/zx/args/-andL/2-}}{\pgfkeysvalueof{/zx/args/-andL/2L}}
+ }%
+ },
+ bezier x/.code={%
+ \pgfkeys{
+ /zx/args/-andL/.cd,
+ ##1
+ }%
+ \pgfkeysalso{
+ bezier 4 x={\pgfkeysvalueof{/zx/args/-andL/1-}}{\pgfkeysvalueof{/zx/args/-andL/1L}}{\pgfkeysvalueof{/zx/args/-andL/2-}}{\pgfkeysvalueof{/zx/args/-andL/2L}}
+ }%
+ },
+ bezier y/.code={%
+ \pgfkeys{
+ /zx/args/-andL/.cd,
+ ##1
+ }%
+ \pgfkeysalso{
+ bezier 4 y={\pgfkeysvalueof{/zx/args/-andL/1-}}{\pgfkeysvalueof{/zx/args/-andL/1L}}{\pgfkeysvalueof{/zx/args/-andL/2-}}{\pgfkeysvalueof{/zx/args/-andL/2L}}
+ }%
+ },
+ % Directions: configure start/end points to "fake center *" if it exists.
+ % If the input is not a node, it's copied to ##3
+ /zx/utils/change@tikz@fake@center/.code n args={3}{%
+ % ##1: \tikztostart or \tikztotarget,
+ % ##2: fake center north...
+ % ##3 name of result. e.g. \tikztostart
+ \ifPgfpointOrNode{##1}{%
+ %%% Sometimes, ##1 is not 1pt,2pt but "tikz-1-2.north east". Since later we use
+ %%% a parsing mechanism which assumes that we have a coordinate... this is a problem.
+ \edef##3{##1}%
+ % This is a great explaination of how parsing is done in tikz:
+ % https://tex.stackexchange.com/a/516897/116348
+ }{% This is a node, not a point:
+ \ifAnchorExists{##1}{##2}{%
+ \pgfpointanchor{##1}{##2}%
+ }{%
+ \pgfpointanchor{##1}{center}%
+ }%
+ %%% Whoo, pgfpoint only redefine pgf@x/pgf@y, but in no way it stores it!!!
+ %%% So can't do \pgfpoint{\pgf@x}{\pgf@y}...
+ %%% I needed to create my own system... see \zx@parse@coordx.
+ \edef##3{\the\pgf@x,\the\pgf@y}%
+ }%
+ },
+ % Directions: configure start/end points to the intersection between
+ % the "fake center *" if it exists and the "fake center *" of the destination.
+ % If the input is not a node, nothing is done.
+ /zx/utils/change@tikz@fake@center@intersect/.code n args={6}{%
+ % ##1: \tikztostart or \tikztotarget
+ % ##2: fake center north... for ##1
+ % ##3: \tikztostart or \tikztotarget, the other one (needed to compute the intersection)
+ % ##4 fake center north... for ##3
+ % ##5: result will be moved to that macro
+ % ##6: 1 if start, 2 if end.
+ \ifPgfpointOrNode{##1}{}{% This is a node, not a point:
+ %% Configure the zx@new@center@* which should point to "fake center" if it exists.
+ \pgfkeysalso{%
+ /zx/utils/change@tikz@fake@center={##1}{##2}{\zx@new@center},%
+ }%
+ \pgfkeysalso{%
+ /zx/utils/change@tikz@fake@center={##3}{##4}{\zx@new@center@other},%
+ }%
+ \zx@message{ZX: coordinate of new center is \zx@new@center}%
+ \zx@message{ZX: coordinate of new other center is \zx@new@center@other}%
+ \zx@find@intersection@fakecenter{##1}{\zx@new@center}{\zx@new@center@other}{##5}{##6}%
+ }%
+ },
+ start fake center east/.style={%
+ /zx/tmp/zx@setup@start@node/.initial=fake center east,
+ },
+ start fake center west/.style={%
+ /zx/tmp/zx@setup@start@node/.initial=fake center west,
+ },
+ start fake center north/.style={%
+ /zx/tmp/zx@setup@start@node/.initial=fake center north,
+ },
+ start fake center south/.style={%
+ /zx/tmp/zx@setup@start@node/.initial=fake center south,
+ },
+ start real center/.style={
+ /zx/tmp/zx@setup@start@node/.initial=center,
+ },
+ start no fake center/.style={
+ /zx/tmp/zx@setup@start@node/.initial=,
+ },
+ end fake center east/.style={%
+ /zx/tmp/zx@setup@end@node/.initial=fake center east,
+ },
+ end fake center west/.style={%
+ /zx/tmp/zx@setup@end@node/.initial=fake center west,
+ },
+ end fake center north/.style={%
+ /zx/tmp/zx@setup@end@node/.initial=fake center north,
+ },
+ end fake center south/.style={%
+ /zx/tmp/zx@setup@end@node/.initial=fake center south,
+ },
+ end real center/.style={
+ /zx/tmp/zx@setup@end@node/.initial=center,
+ },
+ end no fake center/.style={
+ /zx/tmp/zx@setup@end@node/.initial=,
+ },
+ left to right/.style={
+ start fake center east,
+ end fake center west
+ },
+ right to left/.style={
+ start fake center west,
+ end fake center east
+ },
+ up to down/.style={
+ start fake center south,
+ end fake center north
+ },
+ down to up/.style={
+ start fake center north,
+ end fake center south
+ },
+ no fake center/.style={
+ start no fake center,
+ end no fake center,
+ start anchor=,
+ end anchor=,
+ },
+ %% Forced versions are versions which do not nicely fallback to center if shape does not
+ %% have "fake center XXX". This is used mostly for wires based on in/out (our function b.
+ %% Not sure how to have a code which always fallback to center if shape does not.
+ %% All shapes used in the default style should work with force left to right.
+ force left to right/.style={
+ on layer=edgelayer,
+ start anchor=fake center east,
+ end anchor=fake center west
+ },
+ force right to left/.style={
+ on layer=edgelayer,
+ start anchor=fake center west,
+ end fake center east
+ },
+ force up to down/.style={
+ on layer=edgelayer,
+ start anchor=fake center south,
+ end fake center north
+ },
+ force down to up/.style={
+ on layer=edgelayer,
+ start anchor=fake center north,
+ end fake center south
+ },
% Similar to C, but with a softer angle. The '.- marker represents the portion of
% the circle (hence the o) to keep (top, bottom,left/right).
% Angle is customizable, for instance o'=50.
- o'/.style={/tikz/out=##1,/tikz/in=180-##1},
- o'/.default=\zxDefaultSoftAngleO,
- o./.style={/tikz/out=-##1,/tikz/in=180+##1},
- o./.default=\zxDefaultSoftAngleO,
- -o/.style={/tikz/out=-90-##1,/tikz/in=90+##1},
- -o/.default=\zxDefaultSoftAngleO,
- o-/.style={/tikz/out=-90+##1,/tikz/in=90-##1},
- o-/.default=\zxDefaultSoftAngleO,
- % Similar to o, but can be used also for diagonal items.
- % Why ()? Visualize fixing the top part and moving the bottom part.
- (/.style={bend right=##1},
+ %%% Actually, it may not be super useful to define it via bezier since it's used only
+ %%% horizontally and vertically... Anyway.
+ o'/.style={%
+ left to right,
+ bezier x={
+ defaultO,
+ ##1,
+ %% 2- --> 1 - (2-)
+ oneMinus2-,
+ },
+ },
+ o./.style={%
+ left to right,
+ bezier x={%
+ /zx/args/-andL/.cd,
+ defaultO,
+ ##1,
+ %% 2- --> 1 - (2-)
+ oneMinus2-,
+ negate1L,
+ negate2L,
+ },%
+ },
+ -o/.style={%
+ up to down,
+ bezier y={%
+ /zx/args/-andL/.cd,
+ defaultO,
+ ##1,
+ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-},
+ symmetry-L,
+ }
+ },
+ o-/.style={%
+ up to down,
+ bezier y={%
+ /zx/args/-andL/.cd,
+ defaultO,
+ ##1,
+ /zx/args/-andL/2-/.evaluated=1-\pgfkeysvalueof{/zx/args/-andL/2-},
+ /zx/args/-andL/1L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/1L},
+ /zx/args/-andL/2L/.evaluated=-\pgfkeysvalueof{/zx/args/-andL/2L},
+ symmetry-L,
+ },
+ },
+ % Similar to o, but can be used also for diagonal items. Combine it with
+ % The dot versions are mode logic in "left to right", and the others for up to down (possible to change)
+ % Can combine with "force left to right"...
+ (/.style={
+ bend right=##1,
+ },
(/.default=30,
- )/.style={bend left=##1},
+ )/.style={
+ bend left=##1,
+ },
)/.default=30,
- ('/.style={bend left=##1},
+ ('/.style={
+ bend left=##1
+ },
('/.default=30,
- (./.style={bend right=##1},
+ (./.style={
+ bend right=##1
+ },
(./.default=30,
- <'/.style={out=##1,in=180,looseness=0.65},
- <'/.default=\zxDefaultSoftAngleChevron,
- <./.style={out=-##1,in=180,looseness=0.65},
- <./.default=\zxDefaultSoftAngleChevron,
- '>/.style={out=0,in=180-##1,looseness=0.65},
- '>/.default=\zxDefaultSoftAngleChevron,
- .>/.style={out=0,in=180+##1,looseness=0.65},
- .>/.default=\zxDefaultSoftAngleChevron,
- ^./.style={out=-90+##1,in=90,looseness=0.65},
- ^./.default=\zxDefaultSoftAngleChevron,
- .^/.style={out=-90-##1,in=90,looseness=0.65},
- .^/.default=\zxDefaultSoftAngleChevron,
- 'v/.style={out=90+##1,in=-90,looseness=0.65},
- 'v/.default=\zxDefaultSoftAngleChevron,
- v'/.style={out=90-##1,in=-90,looseness=0.65},
- v'/.default=\zxDefaultSoftAngleChevron,
- % Links with a s-like shape.
- s/.style={/tikz/out=0,/tikz/in=180,looseness=0.6},
+ %%%% Links with a N-shape, i.e. like s shape, but symetric against the diagonal. Equivalently, it's a soft 's' shape with a much wider angle (>45).
+ %% Nbase will be reused later by < > shapes as well. It's useful to make a distinction between N and
+ %% Nbase when user will want to overwrite N without overwritting < >.
+ Nbase/.style={
+ left to right,
+ bezier={
+ /zx/args/-andL/.cd,
+ defaultN,
+ ##1,
+ oneMinus2-,
+ oneMinus2L,
+ },
+ },
+ N/.style={Nbase={##1}},
+ % With this model, we don't need differences between N' and N. so we can also call it N.
+ % But keep other notations to allow easy style change (to use IO again for instance).
+ N'/.style={N={##1}},
+ N./.style={N={##1}},
+ -N/.style={N={defaultN-,##1}},
+ -N'/.style={-N={##1}},
+ -N./.style={-N={##1}},
+ N-/.style={-N'={symmetry,##1}},
+ N'-/.style={N-={##1}},
+ N.-/.style={N-={##1}},
+ %% Up to down version
+ NN/.style={N'={symmetry-L,defaultNN,##1},up to down},
+ NN./.style={NN={##1}},
+ .NN/.style={NN={##1}},
+ NIN/.style={NN={defaultNIN,##1}},
+ INN/.style={NIN={symmetry,##1}},
+ NNI/.style={INN={##1}},
+ %%% <' is basically like -N' (historically < was first), we just put an anchor on the east/....
+ <'/.style={Nbase={defaultN,defaultN-,defaultChevron,symmetry,##1},end anchor=west},
+ <./.style={<'={##1}},
+ % Don't use <>^ alone char as style name, it could be useful later for other shortcuts
+ % (replacement directions)
+ '>/.style={Nbase={defaultN,defaultN-,defaultChevron,##1},start anchor=east},
+ .>/.style={'>={##1}},
+ ^./.style={
+ Nbase={defaultN,defaultN-,defaultChevron,symmetry-L,defaultNN,defaultNIN,defaultChevronDown,symmetry,##1},
+ end anchor=north
+ },
+ .^/.style={^.={##1}},
+ 'v/.style={
+ Nbase={defaultN,defaultN-,defaultChevron,symmetry-L,defaultNN,defaultNIN,defaultChevronDown,##1},
+ start anchor=south
+ },
+ v'/.style={'v={##1}},
+ %%%% Links with a s-like shape.
+ s/.style={
+ left to right,
+ bezier={%
+ /zx/args/-andL/.cd,
+ defaultS,
+ ##1,
+ oneMinus2-,
+ oneMinus2L,
+ }
+ },
+ % like S, but with anchor east and west
+ S/.style={
+ s={##1}, start anchor=east, end anchor=west
+ },
% -s'.- shapes are like s, but with a soften (customizable like o) angle.
% The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the -
- s'/.style={/tikz/out=##1,/tikz/in=180+##1},
- s'/.default=\zxDefaultSoftAngleS,
- s./.style={/tikz/out=-##1,/tikz/in=180-##1},
- s./.default=\zxDefaultSoftAngleS,
- -s'/.style={/tikz/out=0,/tikz/in=180+##1},
- -s'/.default=\zxDefaultSoftAngleS,
- -s./.style={/tikz/out=0,/tikz/in=180-##1},
- -s./.default=\zxDefaultSoftAngleS,
- s'-/.style={/tikz/out=##1,/tikz/in=180},
- s'-/.default=\zxDefaultSoftAngleS,
- s.-/.style={/tikz/out=-##1,/tikz/in=180},
- s.-/.default=\zxDefaultSoftAngleS,
+ s'/.style={s={defaultS',##1}},
+ s./.style={s'={##1}},
+ -s/.style={s'={default-S,##1}},
+ -s'/.style={-s={##1}}, % To fit with s' notation
+ -s./.style={-s={##1}},
+ s-/.style={-s'={symmetry,##1}},
+ s'-/.style={s-={##1}},
+ s.-/.style={s-={##1}},
+ % Anchor more marked
+ S/.style={s={##1}, start anchor=east, end anchor=west,},
+ -S/.style={-s'={##1},start anchor=east},
+ -S'/.style={-S={##1}},
+ -S./.style={-S={##1}},
+ S-/.style={s'-={##1},end anchor=west},
+ S'-/.style={S-={##1}},
+ S.-/.style={S-={##1}},
+ %%%% Doubling = up to down.
% Links with a s-like shape... but read from top to bottom
- ss/.style={/tikz/out=0-90,/tikz/in=180-90,looseness=0.6},
+ ss/.style={s={symmetry-L,##1},up to down},
+ SS/.style={ss={##1}, start anchor=south, end anchor=north},
% -s'.- shapes are like s, but with a soften (customizable like o) angle.
- % The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the -
- ss./.style={/tikz/out=##1-90,/tikz/in=180-90+##1},
- ss./.default=\zxDefaultSoftAngleS,
- .ss/.style={/tikz/out=-##1-90,/tikz/in=180-90-##1},
- .ss/.default=\zxDefaultSoftAngleS,
- sIs./.style={/tikz/out=0-90,/tikz/in=180-90+##1},
- sIs./.default=\zxDefaultSoftAngleS,
- .sIs/.style={/tikz/out=0-90,/tikz/in=180-90-##1},
- .sIs/.default=\zxDefaultSoftAngleS,
- ss.I/.style={/tikz/out=##1-90,/tikz/in=180-90},
- ss.I/.default=\zxDefaultSoftAngleS,
- I.ss/.style={/tikz/out=-##1-90,/tikz/in=180-90},
- I.ss/.default=\zxDefaultSoftAngleS,
- %%%% Links with a N-shape, i.e. like s shape, but symetric against the diagonal. Equivalently, it's a soft 's' shape with a much wider angle (>45).
- N'/.style={/tikz/out=##1,/tikz/in=180+##1},
- N'/.default=\zxDefaultSoftAngleN,
- N./.style={/tikz/out=-##1,/tikz/in=180-##1},
- N./.default=\zxDefaultSoftAngleN,
- -N'/.style={/tikz/out=0,/tikz/in=180+##1},
- -N'/.default=\zxDefaultSoftAngleN,
- -N./.style={/tikz/out=0,/tikz/in=180-##1},
- -N./.default=\zxDefaultSoftAngleN,
- N'-/.style={/tikz/out=##1,/tikz/in=180},
- N'-/.default=\zxDefaultSoftAngleN,
- N.-/.style={/tikz/out=-##1,/tikz/in=180},
- N.-/.default=\zxDefaultSoftAngleN,
+ % The '. say if you are going up or down, and 'I' forces a sharp angle (I is flat) on the side of the I
+ ss./.style={s.={symmetry-L,##1},up to down},
+ .ss/.style={ss.={##1}},
+ sIs/.style={ss={defaultSIS,##1}},
+ sIs./.style={ss.={defaultSIS,##1}},
+ .sIs/.style={sIs.={##1}},
+ Iss/.style={sIs={symmetry,##1}},
+ ssI/.style={Iss={##1}},
+ ss.I/.style={sIs.={symmetry,##1}},
+ I.ss/.style={ss.I={##1}},
+ SIS/.style={sIs={##1},start anchor=south},
+ .SIS/.style={.sIs={##1},start anchor=south},
+ ISS/.style={ssI={##1},end anchor=north},
+ SS.I/.style={ss.I={##1},end anchor=north},
+ I.SS/.style={SS.I={##1}},
+ SSI/.style={ISS={##1}},
+ % At the first version, styles were defined using in=... out=... looseness=... However
+ % it gives sometimes bad results (like the curve goes forward at some points) when nodes are
+ % too close or too far appart. However, it may still be useful, so now we define the old
+ % styles, that you can use them using \ar[r,IO,C].
+ IO/.style={
+ C/.style={/tikz/in=180,/tikz/out=180,looseness=2},
+ % Like C, but symetric
+ C-/.style={/tikz/in=0,/tikz/out=0,looseness=2},
+ C'/.style={/tikz/in=90,/tikz/out=90,looseness=2},
+ C./.style={/tikz/in=-90,/tikz/out=-90,looseness=2},
+ % Similar to C, but with a softer angle. The '.- marker represents the portion of
+ % the circle (hence the o) to keep (top, bottom,left/right).
+ % Angle is customizable, for instance o'=50.
+ o'/.style={/tikz/out=####1,/tikz/in=180-####1},
+ o'/.default=\zxDefaultSoftAngleO,
+ o./.style={/tikz/out=-####1,/tikz/in=180+####1},
+ o./.default=\zxDefaultSoftAngleO,
+ -o/.style={/tikz/out=-90-####1,/tikz/in=90+####1},
+ -o/.default=\zxDefaultSoftAngleO,
+ o-/.style={/tikz/out=-90+####1,/tikz/in=90-####1},
+ o-/.default=\zxDefaultSoftAngleO,
+ % Similar to o, but can be used also for diagonal items.
+ % Why ()? Visualize fixing the top part and moving the bottom part.
+ (/.style={bend right=####1},
+ (/.default=30,
+ )/.style={bend left=####1},
+ )/.default=30,
+ ('/.style={bend left=####1},
+ ('/.default=30,
+ (./.style={bend right=####1},
+ (./.default=30,
+ <'/.style={out=####1,in=180,looseness=0.65},
+ <'/.default=\zxDefaultSoftAngleChevron,
+ <./.style={out=-####1,in=180,looseness=0.65},
+ <./.default=\zxDefaultSoftAngleChevron,
+ '>/.style={out=0,in=180-####1,looseness=0.65},
+ '>/.default=\zxDefaultSoftAngleChevron,
+ .>/.style={out=0,in=180+####1,looseness=0.65},
+ .>/.default=\zxDefaultSoftAngleChevron,
+ ^./.style={out=-90+####1,in=90,looseness=0.65},
+ ^./.default=\zxDefaultSoftAngleChevron,
+ .^/.style={out=-90-####1,in=90,looseness=0.65},
+ .^/.default=\zxDefaultSoftAngleChevron,
+ 'v/.style={out=90+####1,in=-90,looseness=0.65},
+ 'v/.default=\zxDefaultSoftAngleChevron,
+ v'/.style={out=90-####1,in=-90,looseness=0.65},
+ v'/.default=\zxDefaultSoftAngleChevron,
+ % Links with a s-like shape.
+ s/.style={/tikz/out=0,/tikz/in=180,looseness=0.6},
+ % -s'.- shapes are like s, but with a soften (customizable like o) angle.
+ % The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the -
+ s'/.style={/tikz/out=####1,/tikz/in=180+####1},
+ s'/.default=\zxDefaultSoftAngleS,
+ s./.style={/tikz/out=-####1,/tikz/in=180-####1},
+ s./.default=\zxDefaultSoftAngleS,
+ -s'/.style={/tikz/out=0,/tikz/in=180+####1},
+ -s'/.default=\zxDefaultSoftAngleS,
+ -s./.style={/tikz/out=0,/tikz/in=180-####1},
+ -s./.default=\zxDefaultSoftAngleS,
+ s'-/.style={/tikz/out=####1,/tikz/in=180},
+ s'-/.default=\zxDefaultSoftAngleS,
+ s.-/.style={/tikz/out=-####1,/tikz/in=180},
+ s.-/.default=\zxDefaultSoftAngleS,
+ % Links with a s-like shape... but read from top to bottom
+ ss/.style={/tikz/out=0-90,/tikz/in=180-90,looseness=0.6},
+ % -s'.- shapes are like s, but with a soften (customizable like o) angle.
+ % The '. say if you are going up or down, and - forces a sharp angle (- is flat) on the side of the -
+ ss./.style={/tikz/out=####1-90,/tikz/in=180-90+####1},
+ ss./.default=\zxDefaultSoftAngleS,
+ .ss/.style={/tikz/out=-####1-90,/tikz/in=180-90-####1},
+ .ss/.default=\zxDefaultSoftAngleS,
+ sIs./.style={/tikz/out=0-90,/tikz/in=180-90+####1},
+ sIs./.default=\zxDefaultSoftAngleS,
+ .sIs/.style={/tikz/out=0-90,/tikz/in=180-90-####1},
+ .sIs/.default=\zxDefaultSoftAngleS,
+ ss.I/.style={/tikz/out=####1-90,/tikz/in=180-90},
+ ss.I/.default=\zxDefaultSoftAngleS,
+ I.ss/.style={/tikz/out=-####1-90,/tikz/in=180-90},
+ I.ss/.default=\zxDefaultSoftAngleS,
+ %%%% Links with a N-shape, i.e. like s shape, but symetric against the diagonal. Equivalently, it's a soft 's' shape with a much wider angle (>45).
+ N'/.style={/tikz/out=####1,/tikz/in=180+####1},
+ N'/.default=\zxDefaultSoftAngleN,
+ N./.style={/tikz/out=-####1,/tikz/in=180-####1},
+ N./.default=\zxDefaultSoftAngleN,
+ -N'/.style={/tikz/out=0,/tikz/in=180+####1},
+ -N'/.default=\zxDefaultSoftAngleN,
+ -N./.style={/tikz/out=0,/tikz/in=180-####1},
+ -N./.default=\zxDefaultSoftAngleN,
+ N'-/.style={/tikz/out=####1,/tikz/in=180},
+ N'-/.default=\zxDefaultSoftAngleN,
+ N.-/.style={/tikz/out=-####1,/tikz/in=180},
+ N.-/.default=\zxDefaultSoftAngleN,
+ },
% No line but vdots/dots in between.
- 3 vdots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\cvdots$}" anchor=center},
+ 3 vdots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\cvdotsCenterMathline$}" anchor=center},
3 vdots/.default={},
3 dots/.style={draw=none, "\makebox[0pt][r]{##1}\scalebox{\zxScaleDots}{$\chdots$}" anchor=center},
3 dots/.default={},
@@ -288,9 +1266,12 @@
% a new column/row. However, make sure the corresponding row/column is larger, using &[\zxHCol]
% for columns and \\[\zxHRow] for rows (for Z/X style, use zxSCol and sxSRow), if you have both spiders
% and Hadamard, use \zxHSCol and \zxHSRow.
- H/.style={"" {zxHSmall,anchor=center}},
- Z/.style={"" {zxNoPhaseSmallZ,anchor=center}},
- X/.style={"" {zxNoPhaseSmallX,anchor=center}},
+ H/.style={"" {zxHSmall,anchor=center,##1}},
+ H/.default={},
+ Z/.style={"" {zxNoPhaseSmallZ,anchor=center,##1}},
+ Z/.default={},
+ X/.style={"" {zxNoPhaseSmallX,anchor=center,##1}},
+ X/.default={},
% Arrow will go out from the center of the shape instead of from the border. Useful
% when connecting nodes with different shapes, it will give back a symetric connection.
wire centered/.style={
@@ -319,7 +1300,7 @@
% Style for empty nodes
zxAllNodes/.style={
shape=rectangle, % Otherwise nodes are asymetrical rectangle, which is not practical in our case. Gives notably anchor "center" which is really centered compared to asymatrical rectangles
- anchor=center, % Center cells
+ anchor=center, % Center cells
line width=\zxDefaultLineWidth,
execute at begin node={\thinmuskip=0mu\medmuskip=0mu\thickmuskip=0mu}, % Reduce space around +/-...
},
@@ -372,9 +1353,20 @@
zxNoneDouble+,
inner ysep=0mm,
},
+ % Used to compute the intersection with the node's boundary
+ allow boundary intersection/.code={%
+ \ifdefined\zxEnableIntersectionsNodes%
+ \edef\zx@name@path{zx@name@path@\tikz@fig@name}%
+ \zx@message{[ZX] The name of the path will be \zx@name@path.}%
+ \pgfkeysalso{
+ name path=\zx@name@path, % Used by intersection library
+ }%
+ \fi%
+ },
% Will be specific to all spiders
zxSpiders/.style={
draw=black,
+ allow boundary intersection,% Used later to do math on it.
},
% Will use this style when drawing a X/Z node without phase (not for end user directly)
zxNoPhase/.style={
@@ -388,7 +1380,7 @@
zxNoPhaseSmall/.style={
zxNoPhase
},
- % Style for nodes that are small enough to fit in a circle, like $\zxMinus \frac{\pi}{4}$
+ % Style for nodes that are small enough to fit in a circle, like $\zxMinus \frac{\pi}{4}$ or $- \alpha$
zxShort/.style={
zxAllNodes,
zxSpiders,
@@ -397,7 +1389,7 @@
rounded rectangle,
inner sep=0.0mm,
scale=0.8,
- }, % negative outer sep would draw lines from inside...
+ },% negative outer sep would draw lines from inside...
% Style for nodes that are bigger, like $\alpha+\beta$ or $(a\oplus b)\pi$
zxLong/.style={zxShort, inner xsep=1.2mm},
%%% Styles of the label when |phase in label| is used
@@ -429,14 +1421,16 @@
%%% Instead of adding directly the style as the node's content (which would make
%%% impossible styles that adds the phase in a label outside of the node)
%%% add@Phase@Spider{,Z,X}={phase of the node} will be in charge of adding it.
- add@Phase@Spider/.style n args={4}{ % add@Phase@Spider{emptyStyle}{NotEmptyStyle}{node content}
+ % add@Phase@Spider{emptyStyle}{ShortStyle}{LongStyle}{label style}{node content}
+ add@Phase@Spider/.style n args={5}{%
zx@emptyStyle/.style={##1},
- zx@notEmptyStyle/.style={##2},
- zx@labelStyle/.style={##3},
- /zx/zx@content/.initial={##4},
+ zx@shortStyle/.style={##2},
+ zx@notEmptyStyle/.style={##3},
+ zx@labelStyle/.style={##4},
+ /zx/zx@content/.initial={##5},
phase in content,
},
- add@Phase@Spider@Frac/.style n args={8}{ % add@Phase@Spider{emptyStyle}{NotEmptyStyle}{labelstyle}{sign}{above fraction (no parens)}{below fraction (no parens)}{above fraction (parens)}{below fraction (parens)}
+ add@Phase@Spider@Frac/.style n args={8}{% add@Phase@Spider{emptyStyle}{NotEmptyStyle}{labelstyle}{sign}{above fraction (no parens)}{below fraction (no parens)}{above fraction (parens)}{below fraction (parens)}
zx@emptyStyle/.style={##1},
zx@notEmptyStyle/.style={##2},
zx@labelStyle/.style={##3},
@@ -446,8 +1440,8 @@
},
% #1 is the node content. Seems that storing it in /zx/zx@content is not enough because keys
% seems to be local to nodes and are not transfered to label.
- zx@Execute@Very@End/.style n args={4}{
- zx@commandToExecuteVeryEnd/.try={##1}{##2}{##3}{##4},
+ zx@Execute@Very@End/.style n args={5}{
+ zx@commandToExecuteVeryEnd/.try={##1}{##2}{##3}{##4}{##5},
},
zx@Execute@Very@End/.default={}{}{}{},
%% zx@Execute@Very@End@Frac={emptystyle}{contentstyle}{labelstyle}{sign}{above frac (no parens)}{below frac (no parens)}{above frac (parens)}{below frac (parens)}
@@ -478,8 +1472,8 @@
%% Modifies zx@commandToExecuteVeryEnd (which is executed at the very end by zx@Execute@Very@End)
%% in order to add the good style
\pgfkeysalso{
- zx@commandToExecuteVeryEnd/.style n args={4}{%
- execute at begin node={####4},% ####4 = content
+ zx@commandToExecuteVeryEnd/.style n args={5}{%
+ execute at begin node={####5},% ####4 = content
}%
}%
% Checks if the content (stored by add@Phase@Spider in /zx/zx@content) is empty or not
@@ -487,9 +1481,15 @@
\pgfkeysalso{%
zx@emptyStyle,%
}%
- }{%
- \pgfkeysalso{%
- zx@notEmptyStyle,%
+ }{% We check if we need to force "short mode" (zxShort instead of zxLong)
+ \ifthenelse{\equal{\pgfkeysvalueof{/zx/zx@shortModeForced}}{true}}{%
+ \pgfkeysalso{%
+ zx@shortStyle,%
+ }%
+ }{% Otherwise, just use the default style.
+ \pgfkeysalso{%
+ zx@notEmptyStyle,%
+ }%
}%
}%
}%
@@ -510,12 +1510,12 @@
}{%
\pgfkeysalso{%
% ##1 is the argument of "phase in label", i.e. the style of the label
- zx@commandToExecuteVeryEnd/.code n args={4}{% ####3: label style, ####4: content
+ zx@commandToExecuteVeryEnd/.code n args={5}{% ####4: label style, ####5: content
% Checks if the content (stored by add@Phase@Spider in /zx/zx@content) is empty or not
- \ifthenelse{\equal{####4}{}}{% Content is empty
+ \ifthenelse{\equal{####5}{}}{% Content is empty
}{% Content is not empty
\pgfkeysalso{
- label={[####3,##1] ####4},%
+ label={[####4,##1] ####5},%
}%
}%
},%
@@ -541,26 +1541,70 @@
},
pill/.style={phase in label left=##1},
%%% Was supposed to automatically find the good style depending on content... Can't find how to do.
- % Styles zxLong{X/Z} zxNoPhase{X/Z} are automatically selected by \zxZ2{...} and \zxX2{...} commands
+ % Styles zxLong{X/Z} zxNoPhase{X/Z} are automatically selected by \zxZ4{...} and \zxX4{...} commands
% and zxShort is selected for fractions only like in \zxFracZ-{\pi}{4}
% zxZ/.style={zxChoose={##1},fill=colorZxZ},
% zxX/.style={zxChoose={##1},fill=colorZxX},
- %%% First argument is additional style. Second argument is content of node.
- zxZ2/.style 2 args={
- add@Phase@Spider={zxNoPhaseZ}{zxLongZ}{stylePhaseInLabelZ}{##2},
- /zx/post preparation labels,
- /zx/user post preparation labels,
- %/zx/user overlay nodes,
- ##1,
- zx@Execute@Very@End={zxNoPhaseZ}{zxLongZ}{stylePhaseInLabelZ}{##2},
+ %%% First argument is additional style.
+ %%% Second argument is the minus mode: "-" for minus sign, which forces short mode.
+ %%% Third argument is "*" for forced short mode.
+ %%% 4th argument is content of node.
+ zx@spider/.code n args={8}{
+ %% ##1: zxnophase style
+ %% ##2: zxshort style
+ %% ##3: zxlong style
+ %% ##4: label style
+ %% user provided:
+ %% ##5: additional tikz options
+ %% ##6: minus "-" or empty, like "-alpha"
+ %% ##7: star "*" or empty, to force short mode
+ %% ##8: content
+ %%% The argument is a minus. Like \zxZ-{\alpha}, goal is to typeset "-\alpha" in short mode.
+ \ifthenelse{\equal{##6}{-}}{% It's a minus!
+ \pgfkeysalso{% We update the content to "-content"
+ /zx/zx@shortModeForced/.initial={true},%
+ }%
+ }{}%
+ \ifthenelse{\equal{##7}{*}}{% We force short mode!
+ \pgfkeysalso{%
+ /zx/zx@shortModeForced/.initial={true},%
+ }%
+ }{}%
+ % It's a minus, and LaTeX is... grrrr. How to get a cleaner code? Tried def/let, not working.
+ \ifthenelse{\equal{##6}{-}}{%
+ \pgfkeysalso{%
+ add@Phase@Spider={##1}{##2}{##3}{##4}{\zxMinusInShort##8},%
+ }%
+ }{%
+ \pgfkeysalso{%
+ add@Phase@Spider={##1}{##2}{##3}{##4}{##8},%
+ }%
+ }%
+ \pgfkeysalso{%
+ /zx/post preparation labels,
+ /zx/user post preparation labels,
+ % /zx/user overlay nodes,
+ ##5,
+ }%
+ \ifthenelse{\equal{##6}{-}}{% It's a minus, and LaTeX is... grrrr
+ \pgfkeysalso{%
+ zx@Execute@Very@End={##1}{##2}{##3}{##4}{\zxMinusInShort##8},%
+ }%
+ }{%
+ \pgfkeysalso{%
+ zx@Execute@Very@End={##1}{##2}{##3}{##4}{##8},%
+ }%
+ }%
},
- %% ##1: other styles, ##2: content
- zxX2/.style 2 args={
- add@Phase@Spider={zxNoPhaseX}{zxLongX}{stylePhaseInLabelX}{##2},
- /zx/post preparation labels,
- /zx/user post preparation labels,
- ##1,
- zx@Execute@Very@End={zxNoPhaseX}{zxLongX}{stylePhaseInLabelX}{##2},
+ %% ##1: additional tikz options
+ %% ##2: minus "-" or empty, like "-alpha"
+ %% ##3: star "*" or empty, to force short mode
+ %% ##4: content
+ zxZ4/.style n args={4}{
+ zx@spider={zxNoPhaseZ}{zxShortZ}{zxLongZ}{stylePhaseInLabelZ}{##1}{##2}{##3}{##4}
+ },
+ zxX4/.style n args={4}{
+ zx@spider={zxNoPhaseX}{zxShortX}{zxLongX}{stylePhaseInLabelX}{##1}{##2}{##3}{##4}
},
%% These take 6 arguments: additional style, sign (string "-" for minus, nothing for "+",
%% otherwise inserted directly), above fraction (no parens), below fraction (no parens), above fraction (parens), below fraction (parens).
@@ -610,13 +1654,35 @@
/zx/user overlay wires/.style={
},
/zx/defaultEnv/.style={
- column sep=tiny,
- row sep=tiny,
+ %tiny depends on the size of the font... which we want to keep consistent look
+ column sep=\zxDefaultColumnSep,
+ row sep=\zxDefaultRowSep,
+ zx column sep/.code={%
+ \def\zxDefaultColumnSep{##1}%
+ \pgfkeysalso{
+ column sep=##1,
+ }%
+ },
+ zx row sep/.code={%
+ \def\zxDefaultRowSep{##1}%
+ \pgfkeysalso{%
+ row sep=##1,
+ }%
+ },
+ %column sep=tiny,
+ %row sep=tiny,
% center on the math axis
baseline={([yshift=-axis_height]current bounding box.center)},
% Fix 1-row diagram baseline
- 1-row diagram/.style={%
- /tikz/baseline={([yshift=-axis_height]current bounding box.center)}%
+ % By default, 1-row diagrams have a different baseline... This package does not want a special case for 1-row diagrams.
+ 1-row diagram/.style={},
+ %% usage: math baseline=wantedBaseline, where you have somewhere \zxX[a=wantedBaseline]{\beta}
+ math baseline/.style={baseline={([yshift=-axis_height]##1)}},
+ %%% Include a diagram in another diagram.
+ use diagram/.style 2 args={
+ execute at end picture={
+ \node[fit=##2,inner sep=0pt,yshift=-axis_height]{\zxUseDiagram{##1}};
+ }
},
% Load (thanks ".search also") our own style
/tikz/every node/.style={%
@@ -625,6 +1691,15 @@
\pgfkeysalso{%
alias=####1,%
}%
+ %% name path won't work with alias... So let's create two name path ^^
+ %% https://tex.stackexchange.com/questions/619622
+ \ifdefined\zxEnableIntersectionsNodes%
+ \edef\zx@name@path{zx@name@path@####1}%
+ \zx@message{[ZX] Name given using an alias: \zx@name@path.}%
+ \pgfkeysalso{
+ name path=\zx@name@path, % Used by intersection library
+ }%
+ \fi%
\ifdefined\zxDebugMode%
\pgfkeysalso{%
label={[inner sep=0pt,overlay,red,font={\fontsize{5}{6}}]-45:\scalebox{.5}{####1}}
@@ -707,7 +1782,7 @@
\def\node@on@layer{\aftergroup\node@@on@layer}
%%% Declare a symbol for a short minus (useful in fractions)
-\DeclareMathSymbol{\zxMinus}{\mathbin}{AMSa}{"39} % Requires amssymb
+\DeclareMathSymbol{\zxMinus}{\mathbin}{AMSa}{"39}% Requires amssymb
%%% Checks if a function is a point or a node.
%%% Not sure if best solution (needed to dig into source of TeX), but can't find anything better in manual
@@ -720,6 +1795,23 @@
}%
}
+% shape anchor name if exists if not. Works, while doing \pgfutil@ifundefined{pgf@anchor@\shapenode{}@#2} fails.
+% I guess it has to do with the way macro are expanded...
+\def\ifAnchorExistsFromShape#1#2#3#4{
+ \pgfutil@ifundefined{pgf@anchor@#1@#2}{%
+ #4%
+ }{%
+ #3%
+ }%
+}
+
+% node name, anchor name, if exists, if not.
+\def\ifAnchorExists#1#2#3#4{%
+ %%% First we extract the shape of the node:
+ \edef\pgf@node@name{#1}%
+ \edef\shapenode{\csname pgf@sh@ns@\pgf@node@name\endcsname}%
+ \ifAnchorExistsFromShape{\shapenode}{#2}{#3}{#4}
+}
%%% Create different kinds of dots...
%% https://tex.stackexchange.com/questions/617959
@@ -750,6 +1842,19 @@
\DeclareRobustCommand{\cvdots}{\cvdotsCenterMathline}
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%%% Practical functions to nest diagrams
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\NewDocumentCommand{\zxSaveDiagram}{mO{}m}{
+ \newsavebox{#1}%
+ \savebox{#1}{\begin{ZX}[ampersand replacement=\&,#2]#3\end{ZX}}%
+}
+
+\NewDocumentCommand{\zxUseDiagram}{m}{
+ \usebox{#1}%
+}
+
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%% Practical macros to automatically choose appropriate style and arrows
@@ -762,7 +1867,7 @@
% Useful to put on the left of a node like "n \vdots", linked to the next node. Example: \leftManyDots{n}.
% First optional argument is scale of text, second is scale of =.
\NewExpandableDocumentCommand{\leftManyDots}{O{1}O{\zxScaleDots}m}{%
- |[zxNone+,inner xsep=0pt]| \scalebox{#1}{$#3$\,}\makebox[0pt][l]{\scalebox{#2}{$\cvdots$}} \ar[r,-s.,start anchor=north east] \ar[r,-s',start anchor=south east] \pgfmatrixnextcell%
+ |[zxNone+,inner xsep=0pt]| \scalebox{#1}{$#3$\,}\makebox[0pt][l]{\scalebox{#2}{$\cvdotsCenterMathline$}} \ar[r,-N.,start anchor=north east] \ar[r,-N',start anchor=south east] \pgfmatrixnextcell[\zxwCol]%
}
% Useful to link two nodes and put a vdots in between.
@@ -772,7 +1877,7 @@
% Like \leftManyDots but on the right. Do *not* create a new node, like in |[zxShortZ]| \alpha \rightManyDots{m}
\NewExpandableDocumentCommand{\rightManyDots}{O{1}O{\zxScaleDots}m}{%
- \ar[r,s'-,end anchor=north west] \ar[r,s.-,end anchor=south west] \pgfmatrixnextcell |[zxNone+,inner xsep=0pt]| \makebox[0pt][r]{\scalebox{#2}{$\cvdots$}}\scalebox{#1}{\,$#3$}
+ \ar[r,N'-,end anchor=north west] \ar[r,N.-,end anchor=south west] \pgfmatrixnextcell[\zxwCol] |[zxNone+,inner xsep=0pt]| \makebox[0pt][r]{\scalebox{#2}{$\cvdotsCenterMathline$}}\scalebox{#1}{\,$#3$}
}
% A swap on one line... Practical mostly to gain space. Must be used with large nodes tough...
@@ -786,19 +1891,20 @@
}
\NewExpandableDocumentCommand{\zxLoopAboveDots}{O{20}O{}m}{%
- \ar[loop,in=90-#1,out=90+#1,looseness=8,min distance=3mm,"\cvdots" {scale=.6,anchor=north,yshift=-0.4mm},#2]
+ \ar[loop,in=90-#1,out=90+#1,looseness=8,min distance=3mm,"\cvdotsCenterMathline" {scale=.6,anchor=north,yshift=-0.25mm},#2]
}
+
% Usage: node without any style, but may have space. Default is no space, \zxNone+{} is both horizontal
% and vertical, \zxNone-{} is only horizontal space, \zxNone|{} is only vertical space.
\NewExpandableDocumentCommand{\zxNone}{t+t-t|O{}m}{
- \IfBooleanTF{#1}{ % \zxNone+
+ \IfBooleanTF{#1}{% \zxNone+
|[zxNone+,#4]| #5%
}{
- \IfBooleanTF{#2}{ % \zxNone-
+ \IfBooleanTF{#2}{% \zxNone-
|[zxNone-,#4]| #5%
}{
- \IfBooleanTF{#3}{ % \zxNone
+ \IfBooleanTF{#3}{% \zxNone
|[zxNoneI,#4]| #5%
}{% \zxNone
|[zxNone,#4]| #5%
@@ -809,13 +1915,13 @@
% Usage: alias of \zxNone... To bad token can't be easily forwarded to another function.
\NewExpandableDocumentCommand{\zxN}{t+t-t|O{}m}{
- \IfBooleanTF{#1}{ % \zxNone+
+ \IfBooleanTF{#1}{% \zxNone+
|[zxNone+,#4]| #5%
}{
- \IfBooleanTF{#2}{ % \zxNone-
+ \IfBooleanTF{#2}{% \zxNone-
|[zxNone-,#4]| #5%
}{
- \IfBooleanTF{#3}{ % \zxNone
+ \IfBooleanTF{#3}{% \zxNone
|[zxNoneI,#4]| #5%
}{% \zxNone
|[zxNone,#4]| #5%
@@ -826,13 +1932,13 @@
% Cf \zxNone, but with larger space.
\NewExpandableDocumentCommand{\zxNoneDouble}{t+t-t|O{}m}{
- \IfBooleanTF{#1}{ % \zxNoneDouble+
+ \IfBooleanTF{#1}{% \zxNoneDouble+
|[zxNoneDouble+,#4]| #5%
}{
- \IfBooleanTF{#2}{ % \zxNoneDouble-
+ \IfBooleanTF{#2}{% \zxNoneDouble-
|[zxNoneDouble-,#4]| #5%
}{
- \IfBooleanTF{#3}{ % \zxNoneDouble
+ \IfBooleanTF{#3}{% \zxNoneDouble
|[zxNoneDoubleI,#4]| #5%
}{% \zxNoneDouble
|[zxNoneDouble,#4]| #5%
@@ -843,14 +1949,14 @@
%% For maximum styling liberty, the content is given directly to the style.
% It allows the style to put the phase in a label.
-\NewExpandableDocumentCommand{\zxZ}{O{}m}{
- |[zxZ2={#1}{#2}]| %
+\NewExpandableDocumentCommand{\zxZ}{O{}t*t-m}{
+ |[zxZ4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}]| %
}
%% For maximum styling liberty, the content is given directly to the style.
%% It allows the style to put the phase in a label.
-\NewExpandableDocumentCommand{\zxX}{O{}m}{
- |[zxX2={#1}{#2}]| %
+\NewExpandableDocumentCommand{\zxX}{O{}t*t-m}{
+ |[zxX4={#1}{\IfBooleanTF{#3}{-}{}}{\IfBooleanTF{#2}{*}{}}{#4}]| %
}
\NewExpandableDocumentCommand{\zxH}{O{}m}{
@@ -889,13 +1995,14 @@
%%%%% Main environment \begin{ZX}...\end{ZX}
\NewDocumentEnvironment{ZX}{O{}}{%
\bgroup%
+ \fontsize{10}{12}\selectfont% Normalize the font size to have consistent drawings everywhere.
% Add a switch in case someone really wants the current tikzcd version:
\ifdefined\doNotPatchQuantikz% Do not patch tikzcd.
\else% Restore locally original tikzcd.
\let\tikzcd@\tikzcd@@originalCopyZx%
\let\endtikzcd\endtikzcd@originalCopyZx%
\fi%
- \pgfsetlayers{background,edgelayer,nodelayer,main,box,labellayer,foreground} % Layers are defined locally to avoid to disturb other drawings
+ \pgfsetlayers{background,edgelayer,nodelayer,main,box,labellayer,foreground}% Layers are defined locally to avoid to disturb other drawings
\begin{tikzcd}[%
/zx/defaultEnv,%
#1]%
@@ -935,11 +2042,11 @@
% Check if width < ratio*(height+depth) to see if short style applies
\ifdimcomp{\wd\zx@box}{<}{\dimexpr \zxMaxRatio\ht\zx@box + \zxMaxRatio\dp\zx@box\relax}{%
#3% Short style is used
- }{ % Else
+ }{% Else
#4% Long style is used
- } %
- }{
+ }%
+ }{%
#4% Long style is used
- }
+ }%
}%
}