因此,我尝试定义一个 tikz/pgf 形状。基本上这些节点不会包含任何文本,这只是一种不复制大量代码来绘制这些框的方法。
我有几个问题
在形状中是否有访问已定义锚点的官方方法?我为其创建了一个宏 (
\pgfutil@useanchor
),但我认为可能有更好的方法。形状本身,有没有更好的方法来绘制这两个额外的区域?(我可能没有得到正确的边距,只是想支持较粗的外线宽度)
键,尤其是
dbox strib width
,为什么更改初始值不会改变节点上的额外锚点?参见下图做改变\beforebackgroundpath
,显然这里做错了什么。
有任何想法吗?
\documentclass[a4paper]{memoir}
\pagestyle{empty}
\usepackage{tikz}
\usetikzlibrary{shapes}
\makeatletter
% access to anchor coordinates, got to be a better way
\def\pgfutil@useanchor#1#2{\csname pgf@anchor@#1@#2\endcsname}
\pgfkeys{/pgf/.cd,
dbox strib width/.initial=5mm,
% dbox strib width/.code={%
% \def\pgf@lib@temp{#1}%
% \pgfkeyslet{/pgf/dbox strib width}{\pgf@lib@temp}%
% },
dbox strib color/.initial=blue,
}
\pgfdeclareshape{dbox}
{
% this is just a rectangle with extra colored areas
\inheritsavedanchors[from=rectangle]
\inheritanchorborder[from=rectangle]
\inheritanchor[from=rectangle]{north}
\inheritanchor[from=rectangle]{north west}
\inheritanchor[from=rectangle]{north east}
\inheritanchor[from=rectangle]{center}
\inheritanchor[from=rectangle]{west}
\inheritanchor[from=rectangle]{east}
\inheritanchor[from=rectangle]{mid}
\inheritanchor[from=rectangle]{mid west}
\inheritanchor[from=rectangle]{mid east}
\inheritanchor[from=rectangle]{base}
\inheritanchor[from=rectangle]{base west}
\inheritanchor[from=rectangle]{base east}
\inheritanchor[from=rectangle]{south}
\inheritanchor[from=rectangle]{south west}
\inheritanchor[from=rectangle]{south east}
\anchor{center left}{
\pgf@process{\pgfutil@useanchor{dbox}{west}}
\advance\pgf@x by \pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by \pgflinewidth
}
\anchor{center left above}{
\pgf@process{\pgfutil@useanchor{dbox}{north west}}
\advance\pgf@x by \pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by \pgflinewidth
}
\anchor{center left below}{
\pgf@process{\pgfutil@useanchor{dbox}{south west}}
\advance\pgf@x by \pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by \pgflinewidth
}
\anchor{center right}{
\pgf@process{\pgfutil@useanchor{dbox}{east}}
\advance\pgf@x by -\pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by -\pgflinewidth
}
\anchor{center right above}{
\pgf@process{\pgfutil@useanchor{dbox}{north east}}
\advance\pgf@x by -\pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by -\pgflinewidth
}
\anchor{center right below}{
\pgf@process{\pgfutil@useanchor{dbox}{south east}}
\advance\pgf@x by -\pgfkeysvalueof{/pgf/dbox strib width}
\advance\pgf@x by -\pgflinewidth
}
\beforebackgroundpath{
\pgfsetfillcolor{\pgfkeysvalueof{/pgf/dbox strib color}}
\pgfpathrectanglecorners{
\pgfpointadd{\southwest}{
\pgfpoint{\pgflinewidth}{\pgflinewidth}
}
}{
\pgfpointadd{\pgf@process{\pgfutil@useanchor{dbox}{north west}}}%
{\pgfpoint{\pgflinewidth+\pgfkeysvalueof{/pgf/dbox strib width}}{-\pgflinewidth}}
}
\pgfusepath{fill}
\pgfpathrectanglecorners{
\pgfpointadd{\northeast}{
\pgfpoint{-\pgflinewidth}{-\pgflinewidth}
}
}{
\pgfpointadd{\pgf@process{\pgfutil@useanchor{dbox}{south east}}}%
{\pgfpoint{-\pgflinewidth-\pgfkeysvalueof{/pgf/dbox strib width}}{\pgflinewidth}}
}
\pgfusepath{fill}
}
%
% Background path
%
\inheritbackgroundpath[from=rectangle]
}
\makeatother
\begin{document}
\begin{tikzpicture}
\begin{scope}[
ms/.style = {minimum height=17mm,minimum
width=6cm,draw,fill=cyan,shape=dbox,
dbox strib color=red!50!white,
},
]
\node[ms,
%dbox strib width=1cm,
] (BBb) at (0,2) {};
\node[ms,
dbox strib width=1cm,
] (BBa) at (0,0) {};
\end{scope}
\fill[green] (BBa.center left) circle (1mm);
\fill[green] (BBa.center left above) circle (1mm);
\fill[green] (BBa.center left below) circle (1mm);
\fill[green] (BBa.center right) circle (1mm);
\fill[green] (BBa.center right above) circle (1mm);
\fill[green] (BBa.center right below) circle (1mm);
\end{tikzpicture}
\end{document}
现在的情况如下
答案1
以下是根据第一原理(即没有继承)得出的所需形状的完整示例(我理解为)。我利用了(未记录的)命令,\addtosavedmacro
该命令可以在“已保存的宏”(请参阅\savedmacro
手册)内使用,在宏内一次定义多个宏\getdboxparameters
。
所有“常见”锚点都已定义,但图像根据节点是否具有某些文本内容排除了锚点。
为了添加填充颜色,必须添加一个dbox inner color
键。
\documentclass[tikz,border=5]{standalone}
\usetikzlibrary{plotmarks}
\makeatletter
\pgfkeys{/pgf/.cd,
dbox strib width/.initial=5mm,
dbox strib color/.initial=red!50,
dbox inner color/.initial=blue!20
}
\pgfdeclareshape{dbox}{%
\savedmacro\getdboxparameters{%
\pgfmathsetlength\pgf@xa{\wd\pgfnodeparttextbox}%
\pgfmathsetlength\pgf@ya{\ht\pgfnodeparttextbox+\dp\pgfnodeparttextbox}%
\pgfextract@process\centerpoint{%
\pgfqpoint{.5\pgf@xa}{.5\pgf@ya}%
}%
\addtosavedmacro\centerpoint%
%
\pgfmathsetlengthmacro\dstrib{\pgfkeysvalueof{/pgf/dbox strib width}}%
\pgfmathsetlengthmacro\innerxsep{\pgfkeysvalueof{/pgf/inner xsep}}%
\pgfmathsetlengthmacro\innerysep{\pgfkeysvalueof{/pgf/inner ysep}}%
\pgfmathsetlengthmacro\outerxsep{\pgfkeysvalueof{/pgf/outer xsep}}%
\pgfmathsetlengthmacro\outerysep{\pgfkeysvalueof{/pgf/outer ysep}}%
\pgfmathsetlengthmacro\minimumwidth{\pgfkeysvalueof{/pgf/minimum width}}%
\pgfmathsetlengthmacro\minimumheight{\pgfkeysvalueof{/pgf/minimum height}}%
%
\pgfmathsetlengthmacro\halfwidth{max(\minimumwidth,%
\pgf@xa+2*(\innerxsep+\dstrib))/2}%
\pgfmathsetlengthmacro\halfheight{max(\minimumheight,%
\pgf@ya+2*(\innerysep))/2}%
\pgfextract@process\southwest{%
\pgfpointadd{\centerpoint}{%
\pgfpointadd{\pgfqpoint{-\halfwidth}{-\halfheight}}%
{\pgfqpoint{-\outerxsep}{-\outerysep}}}%
}%
\pgfextract@process\northeast{%
\pgfpointadd{\centerpoint}{%
\pgfpointadd{\pgfqpoint{\halfwidth}{\halfheight}}%
{\pgfqpoint{\outerxsep}{\outerysep}}}%
}%
\edef\linewidth{\the\pgflinewidth}%
\addtosavedmacro{\linewidth}%
\addtosavedmacro\dstrib%
\addtosavedmacro\outerxsep%
\addtosavedmacro\outerysep%
\addtosavedmacro\southwest%
\addtosavedmacro\northeast%
\addtosavedmacro\halfwidth%
}
\backgroundpath{%
\getdboxparameters%
\pgfpathrectanglecorners%
{\pgfpointadd{\southwest}{\pgfqpoint{\outerxsep}{\outerysep}}}%
{\pgfpointadd{\northeast}{\pgfqpoint{-\outerxsep}{-\outerysep}}}%
}
\behindbackgroundpath{%
\getdboxparameters%
\pgfpathrectanglecorners%
{\pgfpointadd%
{\southwest\pgf@xa=\pgf@x\northeast\pgf@x=\pgf@xa%
\advance\pgf@x by\dstrib}%
{\pgfqpoint{\outerxsep}{-\outerysep}}}%
{\pgfpointadd%
{\northeast\pgf@xa=\pgf@x\southwest\pgf@x=\pgf@xa%
\advance\pgf@x by-\dstrib}%
{\pgfqpoint{-\outerxsep}{\outerysep}}}%
\pgfsetfillcolor{\pgfkeysvalueof{/pgf/dbox inner color}}%
\pgfusepath{fill}%
\pgfpathrectanglecorners%
{\pgfpointadd{\southwest}{\pgfqpoint{\outerxsep}{\outerysep}}}%
{\pgfpointadd%
{\southwest\pgf@xa=\pgf@x\northeast\pgf@x=\pgf@xa%
\advance\pgf@x by\dstrib}%
{\pgfqpoint{\outerxsep}{-\outerysep}}%
}%
\pgfpathrectanglecorners%
{\pgfpointadd{\northeast}{\pgfqpoint{-\outerxsep}{-\outerysep}}}%
{\pgfpointadd%
{\northeast\pgf@xa=\pgf@x\southwest\pgf@x=\pgf@xa%
\advance\pgf@x by-\dstrib}%
{\pgfqpoint{-\outerxsep}{\outerysep}}%
}%
\pgfsetfillcolor{\pgfkeysvalueof{/pgf/dbox strib color}}%
\pgfusepath{fill}%
}
\anchorborder{%
\getdboxparameters%
\pgf@xb=\pgf@x%
\pgf@yb=\pgf@y%
\southwest%
\pgf@xa=\pgf@x% xa/ya is se
\pgf@ya=\pgf@y%
\northeast%
\advance\pgf@x by-\pgf@xa%
\advance\pgf@y by-\pgf@ya%
\pgf@xc=.5\pgf@x% x/y is half width/height
\pgf@yc=.5\pgf@y%
\advance\pgf@xa by\pgf@xc% xa/ya becomes center
\advance\pgf@ya by\pgf@yc%
\edef\pgf@marshal{%
\noexpand\pgfpointborderrectangle
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}
{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}%
\pgf@process{\pgf@marshal}%
\advance\pgf@x by\pgf@xa%
\advance\pgf@y by\pgf@ya%
}
\anchor{center}{\getdboxparameters\centerpoint}
\anchor{north}{\getdboxparameters\centerpoint%
\pgf@xa=\pgf@x\northeast\pgf@x=\pgf@xa}
\anchor{south}{\getdboxparameters\centerpoint%
\pgf@xa=\pgf@x\southwest\pgf@x=\pgf@xa}
\anchor{east}{\getdboxparameters\centerpoint%
\pgf@ya=\pgf@y\northeast\pgf@y=\pgf@ya}
\anchor{west}{\getdboxparameters\centerpoint%
\pgf@ya=\pgf@y\southwest\pgf@y=\pgf@ya}
\anchor{north west}{\getdboxparameters\southwest%
\pgf@xa=\pgf@x\northeast\pgf@x=\pgf@xa}
\anchor{south east}{\getdboxparameters\northeast%
\pgf@xa=\pgf@x\southwest\pgf@x=\pgf@xa}
\anchor{north east}{\getdboxparameters\northeast}
\anchor{south west}{\getdboxparameters\southwest}
\anchor{base}{\getdboxparameters\centerpoint\pgf@y=0pt\relax}
\anchor{base west}{\getdboxparameters\southwest\pgf@y=0pt\relax}
\anchor{base east}{\getdboxparameters\northeast\pgf@y=0pt\relax}
\anchor{mid}{\getdboxparameters\centerpoint%
\pgfmathsetlength\pgf@y{0.5ex}}
\anchor{mid west}{\getdboxparameters\southwest%
\pgfmathsetlength\pgf@y{0.5ex}}
\anchor{mid east}{\getdboxparameters\northeast%
\pgfmathsetlength\pgf@y{0.5ex}}
\anchor{center left}{\getdboxparameters%
\pgfpointadd{\southwest\pgf@xa=\pgf@x\centerpoint\pgf@x=\pgf@xa}%
{\pgfpoint{\dstrib+\outerxsep}{+0pt}}}
\anchor{center left above}{\getdboxparameters%
\pgfpointadd{\southwest\pgf@xa=\pgf@x\northeast\pgf@x=\pgf@xa}%
{\pgfpoint{\dstrib+\outerxsep}{+0pt}}}
\anchor{center left below}{\getdboxparameters%
\pgfpointadd{\southwest}%
{\pgfpoint{\dstrib+\outerxsep}{+0pt}}}
\anchor{center right}{\getdboxparameters%
\pgfpointadd{\northeast\pgf@xa=\pgf@x\centerpoint\pgf@x=\pgf@xa}%
{\pgfpoint{-\dstrib-\outerxsep}{+0pt}}}
\anchor{center right above}{\getdboxparameters%
\pgfpointadd{\northeast}%
{\pgfpoint{-\dstrib-\outerxsep}{+0pt}}}
\anchor{center right below}{\getdboxparameters%
\pgfpointadd{\southwest\pgf@ya=\pgf@y\northeast\pgf@y=\pgf@ya}%
{\pgfpoint{-\dstrib-\outerxsep}{+0pt}}}
}
\begin{document}
\begin{tikzpicture}
\fill [red] circle [radius=.1pt];
\node [draw=gray!50, line width=0.125in, dbox, dbox strib width=0.5in,
inner xsep=0.75in, inner ysep=0.5in] (s) {};
\foreach \anchor/\placement in
{north west/left, north/below, north east/right,
west/left, center/above, east/right,
south west/left, south/above, south east/right,
10/right, 190/below,
center left/above, center left above/above, center left below/below,
center right/above, center right above/above, center right below/below}
\draw[shift=(s.\anchor)] plot[mark=x] coordinates{(0,0)}
node[\placement] {\scriptsize\texttt{(s.\anchor)}};
\end{tikzpicture}
\end{document}
答案2
这不是对您的问题的直接回答,而只是一个例子,说明您可以使用pic
带锚点的绘制形状,作为一种不复制大量代码即可绘制这些框的方法。
\documentclass[tikz,border=5,convert={density=2100}]{standalone}
\tikzset{
dbox width/.store in=\dboxwidth,dbox width=10mm,
dbox height/.store in=\dboxheight,dbox height=5mm,
dbox color/.store in=\dboxcolor,dbox color=blue!50,
strip width/.store in=\stripwidth,strip width=2mm,
strip color/.store in=\stripcolor,strip color=red!50,
set box size/.style = {inner sep=0,minimum width=#1,minimum height=\dboxheight},
dbox/.pic = {
\node[pic actions,fill=\dboxcolor,set box size=\dboxwidth] (-main) at (0,0){};
\node[pic actions,fill=\stripcolor,below right,set box size=\stripwidth] (-left) at (-main.north west){};
\node[pic actions,fill=\stripcolor,below left,set box size=\stripwidth] (-right) at (-main.north east){};
}
}
\begin{document}
\begin{tikzpicture}
\pic[dbox color=green!70] (A) at (0,1) {dbox};
\pic[strip color=yellow!70, strip width=1mm] (B) at (0,0) {dbox};
\foreach \a in {center,north,south}
\fill[green] (A-left.\a) circle(.4pt);
\draw[-latex] (A-left.center) -- (B-right.center);
\end{tikzpicture}
\end{document}