在 3D 空间中对齐自定义形状

在 3D 空间中对齐自定义形状

我学 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}

在此处输入图片描述

相关内容