我正在尝试构建一个包含两个范围的 Tikz 图片。第一个范围的大小是已知的,因为它只有一个元素(一张图片)。第二个范围的大小未知,因为它可以包含任意数量的节点。
问题在于我需要能够将两个范围集中放置在彼此的上方,这意味着我要么需要找到一种方法来预先计算第二个范围的大小,要么需要在制作第二个范围之后移动它。
值得注意的是,解决方案还需要在第一个作用域的内容在 的开始部分定义\newenvironment
,而第二个作用域的内容在新环境中定义的情况下才能发挥作用。此外,创建作用域的顺序不能改变(如果可以将第一个作用域移动到环境的结束部分,这将是微不足道的,但由于其他限制,这里无法做到这一点)。
大致如下:
\newenvironment{anEnvironment}{
\begin{tikzpicture}
\begin{scope}
%... make some nodes in first scope
\end{scope}
\begin{scope}
}{
\end{scope}
%... Set centre position of secondscope to match firstscope.
\end{tikzpicture}
}
\begin{anEnvironment}
%... make nodes for second environment
\end{anEnvironment}
shift
创建范围后可以移动它(应用)吗?
或者,有没有办法创建一个不可见的 tikzpicture,我可以从中获取大小?这样就可以预先计算大小,然后使用正确的位置创建范围。
答案1
基于这答案(使用矩阵来集中一个 Tikzpic
置于范围内的中心),并且这回答(使用NewEnviron
和savebox
),我已经想出了一个可以满足我需求的解决方案。
本质上,newenvironment
我可以使用NewEnviron
(不得不在输入参数处理上做出妥协,但我可以接受)来提前知道整个主体。这意味着可以先在 中制作它savebox
以允许测量它,然后可以基于这些尺寸制作背景图像节点,随后重新制作以背景图像为中心 的 Tikz 图片。
下面是一个例子(为了清晰起见,我从中去掉了大量其他部分)。
\newif\ifttikzpictureIsDraft
\usepackage{environ}
\environbodyname\ttikzenvironbody
\newsavebox{\ttikzpicturebody}
\newlength{\ttikzpictureheight}
\newlength{\ttikzpicturewidth}
% Include tikzpicture for tfigure
\NewEnviron{ttikzpicture}[2][]{%
% Check if in draft mode, if so, set background box to draft image (yellow box)
\ifttikzpictureIsDraft%
\def\ttikzbackgroundimage{\templatedir/Classes/EmptyBoxDraft}%
\else%
\def\ttikzbackgroundimage{#2}%
\fi%
% Save the picture into a tikz pic so we can reuse it later twice
\tikzset{pics/ttikzpic/.style={code={\ttikzenvironbody}}}
% Create a fake tikzpicture inside a savebox so we can measure its size
\begin{lrbox}{\ttikzpicturebody}%
\begin{tikzpicture}[#1]%
\pic {ttikzpic};%
\end{tikzpicture}%
\end{lrbox}%
% Calculate width and height of the tikzpicture
\settoheight{\ttikzpictureheight}{\usebox{\ttikzpicturebody}}%
\settowidth{\ttikzpicturewidth}{\usebox{\ttikzpicturebody}}%
% Create the real tikzpicture using same optional input arguments
\begin{tikzpicture}[#1]%
% Put the background image in a new scope so we can reuse its bounding box for the main image.
\begin{scope}[local bounding box = backgroundimage]
% Inside add a node using background image scaled to match the tikz picture measured
\node (bgimage) [inner sep=0mm, anchor=center] (0,0) {\includegraphics[width=\ttikzpicturewidth, height=\ttikzpictureheight]{\ttikzbackgroundimage}};
% Finished with the effective figure
\end{scope}
% Now we draw the user pic centred on the background image
\matrix[at={(backgroundimage.center)}] {%
\pic {ttikzpic};\\%
};%
% Finish Tikz picture
\end{tikzpicture}
}
答案2
我最近弄清楚了如何使用tikzmark
调整pic
(见https://tex.stackexchange.com/a/611460/86这个想法的起源,尽管自那个答案以来语法略有变化)。它的核心功能利用了 apic
被 a 包围的事实scope
,实际上调整了范围位置。所以它可以在这里使用。它几乎按原样工作,只是因为 apic
是路径的一部分,所以我在原始代码中做了一些不适用于范围的假设。幸运的是,这些都是可以修复的,因此使用最新版本的 tikzmark(来自github
上面链接的存储库),下面的操作似乎可以满足您的要求。
\documentclass{article}
%\url{https://tex.stackexchange.com/q/567245/86}
\usepackage{tikz}
\usetikzlibrary{tikzmark}
\newenvironment{anEnvironment}{
\begin{tikzpicture}
\begin{scope}
\fill (0,0) circle[radius=5pt];
\end{scope}
\begin{scope}[
anchor=center,
scope anchor location,
adjust scope position,
]
}{
\end{scope}
\end{tikzpicture}
}
\begin{document}
\begin{anEnvironment}
\fill[red] (2,0) circle[radius=4pt];
\fill[red] (2,1) circle[radius=4pt];
\fill[red] (3,0) circle[radius=4pt];
\fill[red] (3,1) circle[radius=4pt];
\end{anEnvironment}
\end{document}
与所有 tikzmark 解决方案一样,它需要两次编译才能解决。