Передача данных стека в имена узлов tikz

Передача данных стека в имена узлов tikz

Я пытаюсь использовать стековую структуру данных (как обсуждалось здесь:Вставить/вытащить или сохранить длину/размер?) для хранения различных имен набора имен узлов tikzmark (как обсуждалось вtikzmarkруководство) разбросаны по всему моему тексту.

По отдельности реализация стека (WE1) и \tikzmark(WE2) работает отлично, но их совместное поведение каким-то образом конфликтует с множественными ошибками.

Я не могу понять, что происходит не так, когда я пытаюсь передать вытолкнутые элементы стека данных как имена узлов в \tikzmarkкоманде (MWE ниже). Это проблема, возникающая из-за того, что мой код LaTeX не сразу оценивает команды \pop (я пробовал играть с \expandafterи \edefбезуспешно...)? Я также пробовал передавать \pop{\latexstack}в \newcommand{}, но мне не удалось заставить этот метод работать...

МВЭ[Неправильное комбинированное поведение...]

\documentclass{article}
\usepackage{blindtext, tikz}
    \newtoks\latexstack
    \latexstack={\empty}

    \def\push#1#2{
        \begingroup
        \toks0={{#1}}
        \edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
    }

    \def\pop#1{
        \begingroup
        \edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}\act
    }

    \def\SplitOff#1#2(tail)#3{
        \ifx#1\empty
            \errhelp{Attempting to pop empty stack #3.}
            \errmessage{You can't pop an empty stack.}
        \else
            #1\global#3={#2}
        \fi
    }

    \newcommand\tikzmark[1]{\tikz[overlay,remember picture] \node(#1) {};}

\begin{document}
    \push{A1}{\latexstack}
    \push{B2}{\latexstack}

    \blindtext \tikzmark{\pop{\latexstack}}\\ 
    \blindtext \tikzmark{\pop{\latexstack}}\\ 

    \begin{tikzpicture}[remember picture,overlay,scale=0.5] 
        \draw[red] (A) -- (B);
    \end{tikzpicture}
\end{document}

МЫ1[Правильное поведение структуры данных стека: A1, B2, C3 и D4 помещаются в стек и последовательно извлекаются из структуры данных]

\documentclass{article}
    \newtoks\latexstack
    \latexstack={\empty}

    \def\push#1#2{
        \begingroup
        \toks0={{#1}}
        \edef\act{\endgroup\global#2={\the\toks0 \the#2}}\act
    }

    \def\pop#1{
        \begingroup
        \edef\act{\endgroup\noexpand\SplitOff\the#1(tail)#1}\act
    }

    \def\SplitOff#1#2(tail)#3{
        \ifx#1\empty
            \errhelp{Attempting to pop empty stack #3.}
            \errmessage{You can't pop an empty stack.}
        \else
            #1\global#3={#2}
        \fi
    }

\begin{document}
    \push{A1}{\latexstack}
    \push{B2}{\latexstack}
    \push{C3}{\latexstack}
    \push{D4}{\latexstack}

    \pop{\latexstack},\\ 
    \pop{\latexstack},\\ 
    \pop{\latexstack},\\ 
    \pop{\latexstack}.
\end{document}

МЫ2[Правильное поведение \tikzmark: Точки A и B отмечены и соединены красной линией]

\documentclass{article}
\usepackage{blindtext, tikz}

    \newcommand\tikzmark[1]{\tikz[overlay,remember picture] \node(#1) {};}

\begin{document}
    \blindtext \tikzmark{A}\\
    \blindtext \tikzmark{B}

    \begin{tikzpicture}[remember picture,overlay,scale=0.5] 
        \draw[red] (A) -- (B);
    \end{tikzpicture}
\end{document}

решение1

Я думаю, что проблема здесь в расширении. Когда TikZ создает узлы, имя узла полностью расширяется с помощью \edef.

Если предположить, что код OP оригинальный, то рассмотрим следующее:

\push{A1}{\latexstack}
\push{B2}{\latexstack}
\edef\nodename{\pop{\latexstack}}
\show\nodename

Это иллюстрирует полное расширение и даст (в файле журнала):

! Undefined control sequence.
\pop #1^^@- \begingroup \edef \act 
                                 {\endgroup \noexpand \SplitOff \the #1(tail...
l.36     \edef\nodename{\pop{\latexstack}
                                       }
! Undefined control sequence.
\pop ... \noexpand \SplitOff \the #1(tail)#1}\act 

l.36     \edef\nodename{\pop{\latexstack}
                                       }
> \nodename=macro:
-> \begingroup \edef {\endgroup \SplitOff {B2}{A1}\empty (tail)\latexstack }.
l.37     \show\nodename

Обратите внимание, что проблема в том, чтонетэто \actне определено. Ошибки исчезнут, если \let\act=\relaxпоместить где-нибудь в преамбуле, но содержимое \nodenameвсе равно будет целой кучей кода LaTeX, а не желаемым именем узла.

Одним из решений является наличие \poptoкоманды, которая помещает значение наверху стека в макрос, который затем используется в качестве имени узла (Примечание. Я также переписал макрос \push):

\def\push#1#2{%
  \def\tmp{{#1}}%
  \expandafter\expandafter\expandafter%
    #2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces}

\def\popto#1#2{%
  \expandafter\SplitOffTo\the#1\stop{#1}{#2}%  
}

\def\SplitOffTo#1#2\stop#3#4{%
  \def\tmp{#1}%
  \ifx\tmp\empty%
    \errhelp{Attempting to pop empty stack #3.}%
    \errmessage{You can't pop an empty stack.}%
  \else%
    \def#4{#1}\global#3={#2}%
  \fi%
}

Это можно использовать следующим образом:

\newtoks\latexstack
\latexstack={\empty}
\push{A1}{\latexstack}
\push{B2}{\latexstack}

\popto{\latexstack}{\nodename}
\tikzmark{\nodename}
\show\nodename
Some text \tikzmark{\nodename}

\popto{\latexstack}{\nodename}
\tikzmark{\nodename}
\show\nodename
Some more text \tikzmark{\nodename}

В файле журнала будет показано (что-то вроде) следующее:

> \nodename=macro:
->B2.
l.31 \show\nodename

> \nodename=macro:
->A1.
l.34 \show\nodename

Если все это кажется вам немного неудобным, то \poptoвсе это можно объединить в \tikzmarkpopмакрос:

\documentclass[border=5]{standalone}
\usepackage{tikz}

\def\push#1#2{%
  \def\tmp{{#1}}% 
  \expandafter\expandafter\expandafter%
    #2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces}

\def\popto#1#2{%
  \expandafter\SplitOffTo\the#1\stop{#1}{#2}%  
}

\def\SplitOffTo#1#2\stop#3#4{% 
  \def\tmp{#1}
  \ifx\tmp\empty% 
    \errhelp{Attempting to pop empty stack #3.}%
    \errmessage{You can't pop an empty stack.}%
  \else%
    \def#4{#1}\global#3={#2}%
  \fi}


\def\tikzmarkpop#1{%
\popto{#1}{\nodename}%
\tikz[remember picture, overlay]\coordinate(\nodename);} 

\newtoks\latexstack
\latexstack={\empty}

\begin{document}

\push{A1}{\latexstack}
\push{B2}{\latexstack}  

Some text\tikzmarkpop{\latexstack}
Some more text\tikzmarkpop{\latexstack}

\begin{tikzpicture}[remember picture, overlay] 
  \draw [red, <->] (A1) -- (B2);
\end{tikzpicture}
\end{document}

введите описание изображения здесь

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