最近在写一个画立方体的包,基础的形状和锚点设置都已经写好,然后想实现多个立方体之间的对齐,因为使用 positioning 包只能实现二维图形的对齐,三维图形还需要额外的偏移,目前针对这个功能写了个 demo,但是对写的代码不是很满意,总觉得有更好的写法 `dnnplot.sty` ```tex \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 = (\block@pre.back north west) - (\block@pre.north 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` ```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} ``` 运行结果如下图,经过两次偏移后的立方体实现了 x 轴上的中心对齐: ![](https://pics.latexstudio.net/data/images/201911/00ec5d11765b2db.png)

0 回答0

你的回答

请登录后回答

你的回答将会帮助更多人,请务必认真回答问题。