Информация об импорте

Информация об импорте

Контекст:Этот вопрос является продолжениемЛучшая практика создания изображений TikZ с вложенными элементами.Символ 1предоставилОтветна этот вопрос, где \scopenodeопределено.

\scopenodeобласти видимости превращены в узлы, т. е. можно: назвать область видимости с помощью name=foo; позиционировать область видимости с помощью at=(somewhere); и настраивать позицию с помощью anchor=something. Они в основном потрясающие, так как их можно вкладывать.

Затем вКак сделать использование tikzexternalize и saveboxes совместимым?,cfrпредоставилОтветулучшение этих \scopenodes путем включения отображения как \scopenodeфона , так и содержимого \scopenode. (Фон Scopenode действительно будет нарисованвыше(В противном случае содержание.)

Проблема:Я попытался включить \scopenodeв TiкZ. matrixОднако у меня есть некоторые вопросы:

  • При использовании решения Symbol 1 \scopenodeэлементы позиционируются правильно, но их содержимое не отображается, поскольку оно скрыто за цветом заливки.
    введите описание изображения здесь

  • Благодаря решению CFR контент отображается (и хорошо позиционирован), но \scopenodeвсе портится.
    введите описание изображения здесь

Вопрос:Как сделать \scopenodeсовместимым с TiкЗ matrix?


MWE
(Пример создает матрицу содинстрока и два столбца. В обеих ячейках (A1 и B1) закрашен-нарисован scopenope. A (красно-оранжевый) закреплен на юге, а B (желто-зеленый) закреплен на севере. В каждом scopenode нарисован путь от (0,0) до (1,1)).

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

С решением Symbol 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а второе — \pgf@matrix@shift@nodes@secondary. Они просто применяются \pgf@shift@nodeк списку узлов. Чтобы зарегистрировать scopenode, вы добавили строку

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

поэтому узел области действия также перемещается.


В настоящее время все в scopenode будет набрано дважды. Для вложенного scopenode все набрано дважды по глубине . Это действительно раздражает. Может быть, кто-то сможет улучшить это, кстати TiкZ имеет дело с матрицей.

(Однако матрица не может быть вложенной. Вы выиграли!)



Кроме того, вы изменили

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

к

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

так что имя области видимости не может быть доступно из другого места.

В частности, ТикZ будет применяться \pgf@shift@nodeк самой матрице. Если матрица не имеет имени, то последний scopenode будет смещен, что нежелательно. Вы потратили два часа только на то, чтобы найти этот глупый баг. ИЗВЛЕКИТЕ УРОК.



Кроме того, вы жестко закодировали фоновый путь узла области видимости, так что теперь он заполняется/рисуется до содержимого области видимости. (Отсюда и название)фонpath) Но расчет длинный и, похоже, избыточный. Надеюсь, кто-нибудь сможет его улучшить.

Тем не менее, вы избежали использования pgfonlayer. Это здорово.

Связанный контент