我学 tikz 没多久。最近在用 tikz 写一个包,用于在深度神经网络中绘制立方体。
我已经设置了所需的基本形状和锚点(用于标记)。然后我考虑两个相邻块的对齐,例如 x 轴的中心对齐。首先,我在原点处绘制一个块,然后使用positioning
包在前一个块的右侧绘制一个较小的块。它只是在 x 轴上向右移动,并没有完全居中。换句话说,它仅在 y 轴上居中,并且需要在 z 轴上移动才能在 3d 空间中居中对齐。
我写了一个 demo 并实现了性能。我在 中实现了对齐功能block/.code
,但我认为这不是一个好方法。有没有更好的方法来做同样的事情?
dnnplot.syt
\ProvidesPackage{dnnplot}
\RequirePackage{pdftexcmds}
\usetikzlibrary{math, calc}
\makeatletter
\let\pdfstrcmp=\pdf@strcmp
\pgfkeys{/block plot/.cd,
width/.store in=\block@width, width=1cm,
height/.store in=\block@height, height=1cm,
channel/.store in=\block@channel, channel=1cm,
scale/.store in=\block@scale, scale=.1,
pre/.store in=\block@pre, pre=,
align/.store in=\block@align, align=,
}
\pgfdeclareshape{base block}
{
\inheritsavedanchors[from=rectangle] % this is nearly a 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}
\saveddimen{\offset}{\pgfmathsetlength\pgf@x{\block@offset}}
\anchor{back north west}{
\southwest \pgf@xa=\pgf@x
\northeast
\pgfmathsetlength\pgf@x{\pgf@xa + \offset}
\pgfmathsetlength\pgf@y{\pgf@y + \offset}
}
\anchor{back north east}{
\northeast
\pgfmathsetlength\pgf@x{\pgf@x + \offset}
\pgfmathsetlength\pgf@y{\pgf@y + \offset}
}
\anchor{back south east}{
\northeast \pgf@xa=\pgf@x
\southwest
\pgfmathsetlength\pgf@x{\pgf@xa + \offset}
\pgfmathsetlength\pgf@y{\pgf@y + \offset}
}
\backgroundpath{
% store lower right in xa/ya and upper right in xb/yb
\southwest \pgf@xa=\pgf@x \pgf@ya=\pgf@y
\northeast \pgf@xb=\pgf@x \pgf@yb=\pgf@y
\def\block@offset{\pgfqpoint{\offset}{\offset}}
% main path
\pgfpathmoveto{\pgfqpoint{\pgf@xa}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@ya}}{\block@offset}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\block@offset}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xa}{\pgf@yb}}{\block@offset}}
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
\pgfpathclose
% other edge
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@ya}}
\pgfpathlineto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
\pgfpathlineto{\pgfqpoint{\pgf@xa}{\pgf@yb}}
\pgfpathmoveto{\pgfqpoint{\pgf@xb}{\pgf@yb}}
\pgfpathlineto{\pgfpointadd{\pgfpoint{\pgf@xb}{\pgf@yb}}{\block@offset}}
}
}
\tikzset{
block/.code={\tikzset{/block plot/.cd, #1}
% scale
\pgfmathsetlengthmacro\scaled@width{\block@scale*\block@width}
\pgfmathsetlengthmacro\scaled@height{\block@scale*\block@height}
\pgfmathsetlengthmacro\scaled@channel{\block@scale*\block@channel}
\pgfmathsetlengthmacro\block@offset{sqrt(2)/4*\scaled@width}
% shift
\ifx\block@pre\pgfutil@empty
\else\ifx\block@align\pgfutil@empty
\else
\tikzmath{
coordinate \pre@offset, \cur@offset, \block@shift;
\pre@offset = (\[email protected] north west) - (\[email protected] west);
\cur@offset = (\block@offset, \block@offset);
\block@shift = (0, 0);
if \pdf@strcmp{\block@align}{center}==0 then{
\block@shift = ($0.5*(\pre@offset) - 0.5*(\cur@offset)$);
} else{};
}
\tikzset{shift={(\block@shift)}}
\fi\fi
% general
\tikzset{
base block, draw, opacity=.2,
minimum height=\scaled@height,
minimum width=\scaled@channel,
}
}
}
\newcommand{\blocklabel}[3]{
\ifnum\pdf@strcmp{#2}{back east}=0
\path (#1.back south east) -- node[right] {#3} (#1.back north east);
\fi
}
\makeatother
tikz.tex
\documentclass[tikz, border=1cm]{standalone}
\usepackage{xcolor}
\usetikzlibrary{calc, math, positioning}
\usepackage{dnnplot}
\begin{document}
\begin{tikzpicture}
\node[fill=red, block={scale=1.5, width=50mm, height=50mm, channel=20mm}](a){};
\fill[blue] (a.center) circle (1pt);
\fill[fill=red] (a.north east) node[anchor=west] {north east} circle (1pt);
\fill[fill=red] (a.north west) circle (1pt);
\fill[fill=red] (a.south east) circle (1pt);
\fill[fill=red] (a.south west) circle (1pt);
\fill[fill=red] (a.back north east) circle (1pt);
\fill[fill=red] (a.back north west) circle (1pt);
\fill[fill=red] (a.back south east) circle (1pt);
\blocklabel{a}{back east}{back east label}
\node[fill=green, right=4cm of a, block={scale=1.5, width=10mm, height=10mm,
channel=10mm}](b){};
\node[fill=green, right=4cm of a, block={scale=1.5, width=10mm, height=10mm,
channel=10mm, pre=a, align=center}](c){};
\draw (a.center) --node[above]{shift in x-axis} (b.center);
\draw[draw=red, ->] (b.center) -- node[right]{shift in z-axis}(c.center);
\end{tikzpicture}
\end{document}