我尝试在 TikZ 中定义一个可重用的对象,但遇到了一些麻烦。以下最小工作示例显示了该问题。
\documentclass{article}
\usepackage{tikz}
%\usepackage{trace-pgfkeys}
\usetikzlibrary{calc}
\makeatletter
\pgfkeys{
/object/.cd,
angle/.initial=0,
}
\def\object[#1](#2,#3)#4;{
% \pgfkeys{/object/.cd,#1,angle/.get=\@angle}
\pgfkeys{/object/.cd,#1}
\node (center) at (#2,#3) {#4};
\coordinate (#4 center) at (center);
% \draw [rotate around={\@angle:(center)}] ($(center)+(-1,-.5)$) coordinate (#4 a) rectangle ++(2,1);
\draw [rotate around={\pgfkeysvalueof{/object/angle}:(center)}] ($(center)+(-1,-.5)$) coordinate (#4 a) rectangle ++(2,1);
% \def\@angle{0}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\object[](0,0){A};
\object[angle=30](3,0){B};
\object[](6,0){C};
\draw (A a) -- (B center);
\end{tikzpicture}
\end{document}
mwe 的结果如下图所示。
尽管没有给出角度,但对象 C 也旋转了。这说明我误解了 pgfkeys 的工作原理,应该加以利用。如果未给出选项角度,则希望使用默认值。如何才能正确完成?我该如何摆脱中间变量\@angle
?
附加问题:手册指出,“。” 不得用于坐标名称,而且它也不起作用。但是 TikZ 库定义的“对象”坐标大量使用“xy”坐标名称。上面的示例中是否有方法可以做到这一点,因为它会反映 TikZ 本身是如何做到的?
有关的:这个问题。
编辑:我替换了代码中的几行,因此\@angle
不再需要辅助宏,请参阅 Qrrbrbirlbel 的回答。
答案1
笔记
- 我已经删除了该库并直接在节点上
calc
使用键xshift
和。yshift
center
;
您的定义中的实际上\object
是不需要的,因为无论如何您都会对最后一个参数进行分组。使用您的定义,即使\object[](,)text;
是 也是可能的。如果没有 ,;
您必须写\object[](,){text}
(尽管额外的;
也不会有什么坏处)。但是,我没有改变你的论点定义。
我提供了您的宏的改进版本:
- 我已将您的
\def
初始化替换为\newcommand
允许第一个参数为可选的初始化。 - 在另一个节点的帮助下,创建矩形的算法被重写。
- 我已将您的
\pgfkeys
宏中的 全局设置键/object/angle
。除非您进行本地更改(通过将宏包含在一组括号中{ }
)或备份其值,否则它将不会被更改。
线路
\def\@angle{0}
只会改变\@angle
宏,而不会改变键!
还有其他方法可以“获取” PGF 密钥的一个值。其中一种方法是使用\pgfkeysgetvalue
或\pgfkeysvalueof
:
\pgfkeysgetvalue{<key>}{<macro>}
将的值保存<key>
在<macro>
:\pgfkeys{/object/.cd,#1} \pgfkeysgetvalue{/object/angle}\@angle
\pgfkeysvalueof{<key>}
扩展为的当前值<key>
:\pgfkeys{/object/.cd,#1} % and three lines later: \draw [rotate around={\pgfkeysvalueof{/object/angle}:(center)}] ([xshift=-1cm,yshift=-.5cm]center) coordinate (#4 a) rectangle ++(2,1);
您也可以将该值直接保存到宏中:
处理程序
/.store in
或/.estore in
(保存前展开其参数):\pgfkeys{ /object/.cd, angle/.store in=\@angle, angle=0, }
然后
\@angle
就可以使用而不需要额外“获取”宏里面的值。处理程序
.store in
只是一种快捷方式,内部\def\@angle{#1}
使用。事实上,我们.code
甚至可以使用它来计算参数。在这种情况下,这没有多大意义,因为我们只使用rotate
或的角度rotate around
。这些键已经可用于计算(例如rotate=360-25+2*10
)。\pgfkeys{ /object/.cd, angle/.code=\pgfmathsetmacro\@angle{#1}, angle=0, }
代码
\documentclass[tikz]{standalone}
\makeatletter
\pgfkeys{
/object/.cd,
angle/.initial=0,
}
\def\object[#1](#2,#3)#4;{{
\pgfkeys{/object/.cd,#1,angle/.get=\@angle}
\node (center) at (#2,#3) {#4};
\coordinate (#4 center) at (center);
\draw [rotate around={\@angle:(center)}] ([xshift=-1cm,yshift=-.5cm]center) coordinate (#4 a) rectangle ++(2,1);
}}
\makeatother
\begin{document}
\begin{tikzpicture}
\object[](0,0){A};
\object[angle=30](3,0){B};
\object[](6,0){C};
\draw (A a) -- (B center);
\end{tikzpicture}
\end{document}
输出
改进 (?)
节点已经理解旋转的概念,但不仅形状旋转,内容也旋转。
我的解决方案提供了两个将要创建的节点:
- 未旋转的带有文本(在下面的示例中为浅灰色)
x-<name>
和名称的图像:; - 隐藏文本的旋转矩形,名称:
<name>
。
其中<name>
是键提供的名称,如果为空,则使用/object/name
节点的内容( )。#4
旋转的节点包含文本,\phantom
因此如果文本大于最小尺寸,其大小将调整为与未旋转的节点相同。
如果您只希望一个\object
是矩形,请添加shape=rectangle
到\node
命令中。否则,可能会shape
使用为命令范围指定的规范。
代码
\documentclass[tikz]{standalone}
\makeatletter
\pgfkeys{
/object/.cd,
angle/.initial=0,
name/.initial={},
}
\newcommand*{\object}[1][]{\@object[#1]}
\def\@object[#1](#2,#3)#4;{{
\pgfkeys{/object/.cd,#1}
\pgfkeysgetvalue{/object/name}\@name% saves /object/name in \@name
\ifx\@name\pgfutil@empty\edef\@name{#4}\fi% if no name is given use #4
\node[
draw=lightgray,% debug
minimum width=2cm, minimum height=1cm, name/.expand once=x-\@name] at (#2,#3) {#4};
\node[draw,minimum width=2cm, minimum height=1cm, name/.expand once=\@name, rotate=\pgfkeysvalueof{/object/angle}] at (#2,#3) {\phantom{#4}};
}}
\makeatother
\begin{document}
\begin{tikzpicture}
\object(0,0){A};
\object[angle=30](3,0){B};
\object[name=C has another name](6,0){C};
\draw (A.south west) -- (B.center);
\draw[red] (B.north east) -- (x-B.north west) -- (C has another name.mid west);
\draw[blue,bend right,->] (A) edge (B)
(B) edge (C has another name);
\end{tikzpicture}
\end{document}
输出
答案2
trapezium
以下是使用形状和键的完全不同的方法shape border rotate
:
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{shapes.geometric}
\tikzset{
rotated rectangle/.style={
shape=trapezium,trapezium angle=90,
shape border uses incircle,shape border rotate=#1,
minimum width=2cm,minimum height=1cm,trapezium stretches=true,
},
}
\begin{document}
\begin{tikzpicture}
\node[draw,rotated rectangle=0] (A) at (0,0) {A};
\node[draw,rotated rectangle=30] (B) at (3,0) {B};
\node[draw,rotated rectangle=0] (C) at (6,0) {C};
\draw (A.bottom left corner) -- (B.center);
\draw[red] (B.top right corner) -- (C.mid west);
\end{tikzpicture}
\end{document}