輸入情報

輸入情報

コンテクスト:この質問は、ネストされた要素を持つTikZ画像を作成するためのベストプラクティスシンボル1提供された答えこの質問に対して、 はどこで\scopenode定義されますか。

\scopenodeスコープがノードに変換されます。つまり、 でスコープに名前を付けたりname=foo、 でスコープの位置を指定したりat=(somewhere)、 で位置を調整したりできますanchor=something。これらはネストできるので、基本的に素晴らしいです。

そして、tikzexternalize と saveboxes の使用に互換性を持たせるにはどうすればよいでしょうか?cfr提供された答えの背景と のコンテンツ\scopenodeの両方を表示できるようにすることで、これらの を改善します。(スコープノードの背景は実際に描画されます\scopenode\scopenodeその上それ以外の場合はコンテンツは無効です。

問題:\scopenodeTiに含めようとしたZ matrix。しかし、いくつか問題があります。

  • Symbol 1 のソリューションでは、\scopenode要素は適切に配置されていますが、その内容は塗りつぶし色の背後に隠れているため表示されません。
    ここに画像の説明を入力してください

  • cfr のソリューションでは、コンテンツは表示されます (適切に配置されます) が、\scopenode乱雑になります。
    ここに画像の説明を入力してください

質問:\scopenodeTiとの互換性を保つ方法matrix


MWEs
(この例では、1つ行 2 列。両方のセル (A1 と B1) に、スコープノードが塗りつぶされて描画されます。A (赤オレンジ) は南に固定され、B (黄緑) は北に固定されます。各スコープノードには、(0,0) から (1,1) へのパスが描画されます。

 _______
| A |   |
|---|---|  <-- baseline
|___|_B_|

シンボル1のソリューションでは、

\documentclass{article} 
\usepackage{tikz} 
\usetikzlibrary{matrix} 
\usetikzlibrary{backgrounds} 
% \usetikzlibrary{external} 
% \tikzexternalize 
% \tikzset{external/prefix=build/} 

\makeatletter 
\newbox\tikz@sand@box 
\newcount\tikz@scope@depth 
\tikz@scope@depth111\relax 
\def\scopenode[#1]#2{% 
\begin{pgfinterruptboundingbox}% 
\advance\tikz@scope@depth111\relax% 
% process the user option 
\begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]% 
% try to extract positioning information: name, at, anchor 
\global\let\tikz@fig@name\tikz@fig@name% 
\global\let\tikz@node@at\tikz@node@at% 
\global\let\tikz@anchor\tikz@anchor% 
\end{scope}% 
\let\tikz@scopenode@name\tikz@fig@name% 
\let\tikz@scopenode@at\tikz@node@at% 
\let\tikz@scopenode@anchor\tikz@anchor% 
% try to typeset this scope 
% we only need bounding box information 
% the box itself will be discard 
\setbox\tikz@sand@box=\hbox{% 
\begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]% 
#2% 
\end{scope}% 
}% 
% goodbye. haha 
\setbox\tikz@sand@box=\hbox{}% 
% now typeset again 
\begin{scope}[local bounding box=\tikz@scopenode@name]% 
% use the bounding box information to reposition the scope 
\pgftransformshift{\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}% 
\pgf@x-\pgf@x\pgf@y-\pgf@y}% 
\pgftransformshift{\tikz@scopenode@at}% 
\begin{scope}[#1]% 
#2 
\end{scope}% 
\end{scope}% 
\pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}% 
\global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name% 
\end{pgfinterruptboundingbox}% 
% make up the bounding box 
\path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);% 
% draw something, not necessary 
\draw[#1](\tikz@scopenode@[email protected] west)rectangle(\tikz@scopenode@[email protected] east);% 
} 
\makeatother 
\begin{document} 
\begin{tikzpicture}[ 
remember picture, 
inner sep=0pt, 
outer sep=0pt, 
] 
\draw [help lines](-2,-2) grid (2,2); 
\matrix[ 
column sep=2em, 
row sep = 1em, 
nodes in empty cells, 
anchor=center, 
nodes={anchor=center}, 
] 
{ 
\scopenode[draw = red, fill = orange, anchor=south] { 
\draw [blue] (0,0) -- (1,1); 
}; 
& 
\scopenode[draw = yellow, fill = green, anchor=north] { 
\draw [black] (0,1) -- (1,0); 
}; 
\\ 
}; 
\end{tikzpicture} 
\end{document}

cfr のソリューション:

\documentclass{article} 
\usepackage{tikz} 
\usetikzlibrary{matrix} 
\usetikzlibrary{backgrounds} 
% \usetikzlibrary{external} 
% \tikzexternalize 
% \tikzset{external/prefix=build/} 

\makeatletter 
\pgfdeclarelayer{scopenode} 
\pgfsetlayers{background,scopenode,main} 
\tikzset{% 
% adapted from tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex 
on scopenode layer/.style={% 
execute at begin scope={% 
\pgfonlayer{scopenode}% 
\let\tikz@options=\pgfutil@empty% 
\tikzset{every on scopenode layer/.try,#1}% 
\tikz@options% 
}, 
execute at end scope={\endpgfonlayer} 
}, 
} 
% ateb Symbol 1: tex.stackexchange.com/a/… 
\newbox\tikz@sand@box 
\newcount\tikz@scope@depth 
\tikz@scope@depth111\relax 
\def\scopenode[#1]#2{% name=<enw>, at=<man>, anchor=<angor> 
\begin{pgfinterruptboundingbox}% 
\advance\tikz@scope@depth111\relax% 
% process the user option 
\begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]% 
% try to extract positioning information: name, at, anchor 
\global\let\tikz@fig@name\tikz@fig@name% 
\global\let\tikz@node@at\tikz@node@at% 
\global\let\tikz@anchor\tikz@anchor% 
\end{scope}% 
\let\tikz@scopenode@name\tikz@fig@name% 
\let\tikz@scopenode@at\tikz@node@at% 
\let\tikz@scopenode@anchor\tikz@anchor% 
% try to typeset this scope 
% we only need bounding box information 
% the box itself will be discard 
\setbox\tikz@sand@box=\hbox{% 
\begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]% 
#2% 
\end{scope}% 
}% 
% goodbye. haha 
\setbox\tikz@sand@box=\hbox{}% 
% now typeset again 
\begin{scope}[local bounding box=\tikz@scopenode@name]% 
% use the bounding box information to reposition the scope 
\pgftransformshift{\pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}% 
\pgf@x-\pgf@x\pgf@y-\pgf@y}% 
\pgftransformshift{\tikz@scopenode@at}% 
\begin{scope}[#1]% 
#2 
\end{scope}% 
\end{scope}% 
\pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}% 
\global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name% 
\end{pgfinterruptboundingbox}% 
% make up the bounding box 
\path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);% 
% draw something, not necessary 
\begin{scope}[on scopenode layer]% 
\draw[#1](\tikz@scopenode@[email protected] west)rectangle(\tikz@scopenode@[email protected] east);% 
\end{scope}% 
} 
\makeatother 
\begin{document} 
\begin{tikzpicture}[ 
remember picture, 
inner sep=0pt, 
outer sep=0pt, 
] 
\draw [help lines](-2,-2) grid (2,2); 
\matrix[ 
column sep=2em, 
row sep = 1em, 
nodes in empty cells, 
anchor=center, 
nodes={anchor=center}, 
] 
{ 
\scopenode[draw = red, fill = orange, anchor=south] { 
\draw [blue] (0,0) -- (1,1); 
}; 
& 
\scopenode[draw = yellow, fill = green, anchor=north] { 
\draw [black] (0,1) -- (1,0); 
}; 
\\ 
}; 
\end{tikzpicture} 
\end{document}

答え1

これは私がこれまでに得た最高のものです:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{matrix}
\usetikzlibrary{backgrounds}
% \usetikzlibrary{external}
% \tikzexternalize
% \tikzset{external/prefix=build/}

\makeatletter
    \newbox\tikz@sand@box
    \newcount\tikz@scope@depth
    \newdimen\tikz@scope@shiftx
    \newdimen\tikz@scope@shifty
    \newdimen\tikz@scope@swx
    \newdimen\tikz@scope@swy
    \newdimen\tikz@scope@nex
    \newdimen\tikz@scope@ney
    \tikz@scope@depth111\relax
    \def\scopenode[#1]#2{%
        \begin{pgfinterruptboundingbox}%
            \advance\tikz@scope@depth111\relax%
            % process the user option
            \begin{scope}[name=tempscopenodename,at={(0,0)},anchor=center,#1]%
                % try to extract positioning information: name, at, anchor
                \global\let\tikz@fig@name@\tikz@fig@name%
                \global\let\tikz@node@at@\tikz@node@at%
                \global\let\tikz@anchor@\tikz@anchor%
            \end{scope}%
            \let\tikz@scopenode@name\tikz@fig@name@%
            \let\tikz@scopenode@at\tikz@node@at@%
            \let\tikz@scopenode@anchor\tikz@anchor@%
            % try to typeset this scope
            % we only need bounding box information
            % the box itself will be discard
            \setbox\tikz@sand@box=\hbox{%
                \begin{scope}[local bounding box=tikz@sand@box\the\tikz@scope@depth,#1]%
                    #2%
                \end{scope}%
            }%
            % goodbye. haha
            \setbox\tikz@sand@box=\hbox{}%
            % now typeset again
            \begin{scope}[local bounding box=\tikz@scopenode@name]%
                % use the bounding box information to reposition the scope
                \pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{\tikz@scopenode@anchor}%
                \tikz@scope@shiftx-\pgf@x%
                \tikz@scope@shifty-\pgf@y%
                \tikz@scopenode@at%
                \advance\tikz@scope@shiftx\pgf@x%
                \advance\tikz@scope@shifty\pgf@y%
                \pgftransformshift{\pgfpoint{\tikz@scope@shiftx}{\tikz@scope@shifty}}
                % the background path
                % lengthy, tedious calculation
                % someone please improve this
                \pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{south west}
                \tikz@scope@swx\pgf@x\advance\tikz@scope@swx\tikz@scope@shiftx
                \tikz@scope@swy\pgf@y\advance\tikz@scope@swy\tikz@scope@shifty
                \pgfpointanchor{tikz@sand@box\the\tikz@scope@depth}{north east}
                \tikz@scope@nex\pgf@x\advance\tikz@scope@nex\tikz@scope@shiftx
                \tikz@scope@ney\pgf@y\advance\tikz@scope@ney\tikz@scope@shifty
                \path(\tikz@scope@swx,\tikz@scope@swy)coordinate(tempsw)
                     (\tikz@scope@nex,\tikz@scope@ney)coordinate(tempne);
                \path[#1](tempsw)rectangle(tempne);
                % typeset the content for real
                \begin{scope}[#1]%
                    #2%
                \end{scope}%
            \end{scope}%
            \pgfkeys{/pgf/freeze local bounding box=\tikz@scopenode@name}%
            \global\let\tikz@scopenode@name@smuggle\tikz@scopenode@name%
        \end{pgfinterruptboundingbox}%
        % make up the bounding box
        \path(\tikz@scopenode@[email protected] west)(\tikz@scopenode@[email protected] east);%
        % compatible code for matrix
        \expandafter\pgf@nodecallback\expandafter{\tikz@scopenode@name@smuggle}%
    }
\makeatother



\begin{document}
    \begin{tikzpicture}[remember picture,inner sep=0pt,outer sep=0pt]
        \draw[help lines](-2,-2)grid(2,2);
        \matrix()
        [
            column sep=2em,
            row sep=1em,
            nodes in empty cells,
            anchor=center,
            nodes={anchor=center},
        ]
        {
            \scopenode[draw=red,fill=orange,name=aaa,anchor=south] {
                \draw[blue](0,0)--(1,1)circle(.2);
            };
            &
            \scopenode[draw=yellow,fill=green,name=bbb,anchor=north] {
                \draw[black](0,1)--(1,0)circle(.1);
            };
            &
            \scopenode[fill=cyan,name=ccc,anchor=east,scale=.8] {
                \draw(0,0)--(1,1)circle(.3)--(2,0);
            };
            \\
            \node(aaaa){};
            &
            \node(bbbb){};
            &
            \node(cccc){};
            \\
        };
    \draw[->](2,2)node[above]{this is the orange scopenode}to[bend left](aaa.east);
    \draw[->](-2,-2)node[below]{this is the green scopenode}to[bend left](bbb.west);
    \draw[->](3,-1)node[right]{this is the cyan scopenode}to[bend left](ccc.south);
    \end{tikzpicture}
\end{document}

輸入情報

親愛なる未来の私へ:

ご参考までに、マトリックスの内容はhboxに一度だけタイプセットされます。その後、対応するセルに移動されます。そして、マトリックス全体が目的の位置に移動されます。最初の移動は によって行われ\pgf@matrix@shift@nodes@initial、2番目の移動は によって行われます\pgf@matrix@shift@nodes@secondary。これらは単に\pgf@shift@nodeノードリストに適用されています。スコープノードを登録するには、次の行を追加します。

\expandafter\pgf@nodecallback\expandafter{\tikz@scopenode@name@smuggle}%

したがって、スコープノードも移動されます。


現在、スコープノード内のすべてが2回タイプセットされます。ネストされたスコープノードの場合、2つのさでタイプセットされます。これは本当にイライラします。ところで、誰かがこれを改善できるかもしれません。Z は行列を扱います。

(ただし、マトリックスはネストできません。あなたの勝ちです!)



また、あなたは変わった

\global\let\tikz@fig@name\tikz@fig@name

\global\let\tikz@fig@name@\tikz@fig@name

スコープノードの名前が他の場所からアクセスできないようにします。

特に、TiZ はマトリックス自体に適用されます\pgf@shift@node。マトリックスに名前が付いていないと、最後のスコープノードがシフトされますが、これは望ましくありません。この愚かなバグを見つけるために 2 時間も費やしました。教訓を学びましょう。



また、スコープノードの背景パスをハードコードしたので、スコープの内容の前に背景が塗りつぶされるようになりました。(そのため、名前は背景パス) しかし、計算は長く、一見冗長です。誰かが改善してくれることを願っています。

それにもかかわらず、 の使用を避けましたpgfonlayer。それは素晴らしいことです。

関連情報