我正在尝试定义一个新环境,该环境将在其内容周围绘制一个矩形。当这些环境嵌套时,问题就开始了,因为“本地边界框”是一种全局事物。对外部和内部范围使用唯一名称可以解决问题。
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{fit}
\newenvironment{myscope0}[0]{
\begin{scope}[draw, local bounding box=bounding box 0]
}{
\end{scope}
\node [draw, fit=(bounding box 0)] {};
}
\newenvironment{myscope1}[0]{
\begin{scope}[draw, local bounding box=bounding box 1]
}{
\end{scope}
\node [draw, fit=(bounding box 1)] {};
}
\begin{document}
\begin{tikzpicture}
\begin{myscope0}
\begin{myscope1}
\node at (0,0) {test 1};
\end{myscope1}
\begin{myscope1}
\node at (1,1) {test 2};
\end{myscope1}
\end{myscope0}
\end{tikzpicture}
\end{document}
我想要避免为每个可能的嵌套级别定义不同的环境,因为我将使用它来绘制复杂的图表。
我发现了另一个解决非常相似问题的主题:将当前计数器值传递给堆栈数据结构
他们定义了某种堆栈来存储计数器,并使用该计数器来形成名称。问题是它实际上不适用于范围:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{fit}
%Define stack data structure commands (\push, \pop, \splitstack)
\newtoks\mystack
\mystack={\empty}
\def\push#1#2{%
\def\tmp{{#1}}%
\expandafter\expandafter\expandafter%
#2\expandafter\expandafter\expandafter{\expandafter\tmp\the#2}%
\ignorespaces
}
\def\pop#1#2{%
\expandafter\splitstack\the#1\stop{#1}{#2}%
}
\def\splitstack#1#2\stop#3#4{%
\def\tmp{#1}
\ifx\tmp\empty
\else
\def#4{#1}\global#3={#2}%
\fi
}
%Define bracket pair counting commands (\openbracket, \closebracket)
\newcounter{mycounter}
\newenvironment{myscope}[0]{
\global\expandafter\edef\csname beginscopenumber\endcsname{\themycounter}%
\push{\beginscopenumber}{\mystack}%
\stepcounter{mycounter}%
\begin{scope} [local bounding box=bounding box \beginscopenumber]
}{
\end{scope}
\pop{\mystack}{\endscopenumber}%
\node [draw, fit=(bounding box \endscopenumber)] {};
}
\begin{document}
\begin{tikzpicture}
\begin{myscope}
\begin{myscope}
\node at (0,0) {test 1};
\end{myscope}
\begin{myscope}
\node at (1,1) {test 2};
\end{myscope}
\end{myscope}
\end{tikzpicture}
\end{document}
外部矩形仅包围最后一个嵌套范围。如能得到任何帮助,我将不胜感激。谢谢。
答案1
这是一个带有计数器的简单方法:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{fit}
\newcounter{myscopelevel}
\setcounter{myscopelevel}{0}
\newenvironment{myscope}[0]
{
\stepcounter{myscopelevel}
%\typeout{myscopelevel:\themyscopelevel}
\begin{scope}[local bounding box/.expanded=bounding box \themyscopelevel]
}{
\end{scope}
\node [draw, fit=(bounding box \themyscopelevel)] {};
\addtocounter{myscopelevel}{-1}
}
\begin{document}
\begin{tikzpicture}
\begin{myscope}
\begin{myscope}
\node at (0,0) {test 1};
\end{myscope}
\begin{myscope}
\node at (1,1) {test 2};
\end{myscope}
\end{myscope}
\end{tikzpicture}
\end{document}
下面是一个更简单的版本,使用组内的宏的局部性:
\documentclass{article}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usetikzlibrary{fit}
\pgfmathsetmacro\myscopelevel{0}
\newenvironment{myscope}[0]
{
\pgfmathsetmacro\myscopelevel{int(\myscopelevel+1)}
%\typeout{myscopelevel:\myscopelevel}
\begin{scope}[local bounding box/.expanded=bounding box \myscopelevel]
}{
\end{scope}
\node [draw, fit=(bounding box \myscopelevel)] {};
}
\begin{document}
\begin{tikzpicture}
\begin{myscope}
\begin{myscope}
\node at (0,0) {test 1};
\end{myscope}
\begin{myscope}
\node at (1,1) {test 2};
\end{myscope}
\end{myscope}
\end{tikzpicture}
\end{document}
答案2
TikZ 绘图的主要原则之一是:将node
s 和pic
s 沿着path
s 放置。它们之间存在所谓的平衡:node
是具有完整的锚点和名称,形状有限; 是pic
具有任何形状,但“黑客”锚点和名称。
您可以通过 like-node 回答您的问题pic
具体描述如下这个答案我定义了一个pic
有3个参数的:#1是右上方的文本,#2是左下方的文本,#3是稍后可以引用的覆盖节点的名称。
希望这有帮助!PS:local bounding box
总是矩形,所以是有限的。
\documentclass[tikz,border=5mm]{standalone}
\begin{document}
\begin{tikzpicture}
\tikzset{pics/leonidovic/.style args=
{above right #1 below left #2 nodename #3}{code={%
\path
(0,0) node[draw,minimum height=15mm,minimum width=20mm] (#3) {}
(#3.north east)+(-.6,-.35) node[draw,minimum height=5mm,minimum width=10mm]{#1}
(#3.south west)+(.6,.35) node[draw,minimum height=5mm,minimum width=10mm]{#2};%
}}}
\path
(0,0) pic{leonidovic=above right test1 below left test2 nodename A}
(5,2) pic{leonidovic=above right test3 below left test4 nodename B}
;
\draw (A)--(B);
\draw[->] (A) -| (B);
\end{tikzpicture}
\end{document}