tikz 路径使用绘图区域

tikz 路径使用绘图区域

我发现了一个有趣的雪人这里,为了好玩,我用一些相对坐标重写它,如下所示:

\documentclass[border=2pt]{standalone}
\usepackage{tikz}
\usetikzlibrary{positioning,shapes}
\usetikzlibrary{intersections}
\usetikzlibrary{backgrounds}

\begin{document}
\begin{tikzpicture}[framed,line width=1pt]
    \def\a{2cm}
    \def\b{1cm}
    \def\c{0.5cm}
    \node[ellipse,draw,minimum width=\a,minimum height=\a/4] (P0) {};
    \node[ellipse,draw,minimum width=\b,minimum height=\b/2,above=-1pt of P0] (P1) {};
    \node[ellipse,draw,minimum width=\c,minimum height=\c,above=-1pt of P1] (P2) {};
    \draw (P2) ++(-30:.2) arc(-30:-150:.2);
    \draw[fill=black] (P2) +(.1,0) circle(.04) +(-.1,0) circle(.04);

    \path[name path=M1] (P1) ++(10:.4) --++(20:2);
    \path [name path=N1] (P0.east) |- (P2.east);
    \path [name intersections={of=M1 and N1,by=CS1}];
    \draw[very thick] (P1) ++(10:.4) -- (CS1);

    \path[name path=M2] (P1) ++(170:.4) --++(160:2);
    \path [name path=N2] (P0.west) |- (P2.west);
    \path [name intersections={of=M2 and N2,by=CS2}];
    \draw[very thick] (P1) ++(170:.4) -- (CS2);
  \end{tikzpicture}
  \end{document}

一切看起来都很好,但是正如你看到的这个输出: 在此处输入图片描述

这里有两个缺陷:

  1. 我本来想用路径命令只获取交点,但是现在好像用到了绘图区域,所以图片太宽了,还有白色!
  2. 交点命令现在分为 3 行,我们可以将其合并为一行来获取交点吗?tikz

答案1

这是在计算边界框时忽略某些命令的一种方法。[感谢 Torbjørn T. 告诉我不要重新发明轮子。]

\documentclass[tikz,multi,border=10pt]{standalone}
\usetikzlibrary{positioning,shapes.geometric,intersections,backgrounds}
\begin{document}
\begin{tikzpicture}[framed,line width=1pt]
  \def\a{2cm}
  \def\b{1cm}
  \def\c{0.5cm}
  \node[ellipse,draw,minimum width=\a,minimum height=\a/4] (P0) {};
  \node[ellipse,draw,minimum width=\b,minimum height=\b/2,above=-1pt of P0] (P1) {};
  \node[ellipse,draw,minimum width=\c,minimum height=\c,above=-1pt of P1] (P2) {};
  \draw (P2) ++(-30:.2) arc(-30:-150:.2);
  \draw[fill=black] (P2) +(.1,0) circle(.04) +(-.1,0) circle(.04);
  \begin{pgfinterruptboundingbox}
      \path [name path=M1] (P1) ++(10:.4*\snowpersonminimumtorsowidth) --++(20:2*\snowpersonminimumtorsowidth);
      \path [name path=N1] (P0.east) |- (P2.east);
      \path [name intersections={of=M1 and N1,by=CS1}];
      \path [name path=M2] (P1) ++(170:.4*\snowpersonminimumtorsowidth) --++(160:2*\snowpersonminimumtorsowidth);
      \path [name path=N2] (P0.west) |- (P2.west);
      \path [name intersections={of=M2 and N2,by=CS2}];
  \end{pgfinterruptboundingbox}
  \draw[very thick] (P1) ++(10:.4) -- (CS1);
  \draw[very thick] (P1) ++(170:.4) -- (CS2);
\end{tikzpicture}
\end{document}

获得更合理的边界框

您需要 3 行代码来表示交点,因为您需要两条不同路径的交点,每条路径都必须以某种方式定义和命名。这 3 行代码不一定需要位于 中tikzpicture,但它们必须位于某个地方。

您可以使用常规宏,但所需的参数数量会使其变得相当混乱。您也可以滥用 apic来实现这一点。就我个人而言,我会将整个雪人做成 apic并完成它,但您的公里数可能会有所不同。这是单独的交叉点计算pic。您需要以键值语法向其提供 5 位信息:第一条路径的名称、第一条路径、第二条路径的名称、第二条路径、用于命名交叉点的前缀。

\documentclass[tikz,multi,border=10pt]{standalone}
\usetikzlibrary{positioning,shapes.geometric,intersections,backgrounds}
\tikzset{%
  pics/calc snowperson intersections/.style={%
    code={%
      \tikzset{%
        snowperson intersections/.cd,
        #1,
      }
      \begin{pgfinterruptboundingbox}
        \path [name path=\snowpersonintersectionsnameone] \snowpersonintersectionspathone;
        \path [name path=\snowpersonintersectionsnametwo] \snowpersonintersectionspathtwo;
        \path [name intersections={of={\snowpersonintersectionsnameone} and {\snowpersonintersectionsnametwo}, by=\snowpersonintersectionsname}];
      \end{pgfinterruptboundingbox}
    }
  },
  snowperson intersections/.search also={/tikz},
  snowperson intersections/.cd,
  name first path/.store in=\snowpersonintersectionsnameone,
  name second path/.store in=\snowpersonintersectionsnametwo,
  first path/.store in=\snowpersonintersectionspathone,
  second path/.store in=\snowpersonintersectionspathtwo,
  name intersections/.store in=\snowpersonintersectionsname,
  name first path=path 1.
  name second path=path 2,
  first path={(-1,0) -- (1,0},
  second path={(0,-1) -- (0,1)},
  name intersections=snowperson,
}
\begin{document}
\begin{tikzpicture}[framed,line width=1pt]
  \def\a{2cm}
  \def\b{1cm}
  \def\c{0.5cm}
  \node[ellipse,draw,minimum width=\a,minimum height=\a/4] (P0) {};
  \node[ellipse,draw,minimum width=\b,minimum height=\b/2,above=-1pt of P0] (P1) {};
  \node[ellipse,draw,minimum width=\c,minimum height=\c,above=-1pt of P1] (P2) {};
  \draw (P2) ++(-30:.2) arc(-30:-150:.2);
  \draw[fill=black] (P2) +(.1,0) circle(.04) +(-.1,0) circle(.04);
  \pic {calc snowperson intersections={name first path=M1, name second path=N1, name intersections=CS1, first path={(P1) ++(10:.4) --++(20:2)}, second path={(P0.east) |- (P2.east)}}};
  \pic {calc snowperson intersections={name first path=M2, name second path=N2, name intersections=CS2, first path={(P1) ++(170:.4) --++(160:2)}, second path={(P0.west) |- (P2.west)}}};
  \draw[very thick] (P1) ++(10:.4) -- (CS1);
  \draw[very thick] (P1) ++(170:.4) -- (CS2);
\end{tikzpicture}
\end{document}

给出与之前相同的输出:

相同的输出

但我更倾向于全力以赴:

\tikzset{
  /tikz/.cd,
  pics/snowperson/.style={%
    code={%
      \tikzset{%
        inner sep=0pt,
        snowperson/.cd,
        #1,
      }
      \begin{scope}[local bounding box/.expanded=\snowpersonname, line width=\snowpersonlinewidth, pic actions]
        \node [ellipse, draw, pic actions, minimum width=\snowpersonminimumbasewidth, minimum height=\snowpersonminimumbasewidth*\snowpersonbaseratio] (P0) {};
        \node [ellipse, draw, pic actions, minimum width=\snowpersonminimumtorsowidth, minimum height=\snowpersonminimumtorsowidth*\snowpersontorsoratio, above=-\snowpersonlinewidth of P0] (P1) {};
        \node [ellipse, draw, pic actions,minimum width=\snowpersonminimumheadwidth, minimum height=\snowpersonminimumheadwidth*\snowpersonheadratio, above=-\snowpersonlinewidth of P1] (P2) {};
        \draw (P2) ++(-30:.4*\snowpersonminimumheadwidth) arc(-30:-150:.4*\snowpersonminimumheadwidth);
        \draw [fill=black] (P2) +(.2*\snowpersonminimumheadwidth,0) circle(.08*\snowpersonminimumheadwidth) +(-.2*\snowpersonminimumheadwidth,0) circle(.08*\snowpersonminimumheadwidth);
        \begin{pgfinterruptboundingbox}
          \path [name path=M1] (P1) ++(10:.4*\snowpersonminimumtorsowidth) --++(20:2*\snowpersonminimumtorsowidth);
          \path [name path=N1] (P0.east) |- (P2.east);
          \path [name intersections={of=M1 and N1,by=CS1}];
          \path [name path=M2] (P1) ++(170:.4*\snowpersonminimumtorsowidth) --++(160:2*\snowpersonminimumtorsowidth);
          \path [name path=N2] (P0.west) |- (P2.west);
          \path [name intersections={of=M2 and N2,by=CS2}];
        \end{pgfinterruptboundingbox}
        \draw [line width=\snowpersonarmwidth] (P1) ++(10:.4*\snowpersonminimumtorsowidth) -- (CS1);
        \draw [line width=\snowpersonarmwidth] (P1) ++(170:.4*\snowpersonminimumtorsowidth) -- (CS2);
      \end{scope}
    }
  },
  snowperson/.search also={/tikz},
  snowperson/.cd,
  minimum base width/.store in=\snowpersonminimumbasewidth,
  minimum torso width/.store in=\snowpersonminimumtorsowidth,
  minimum head width/.store in=\snowpersonminimumheadwidth,
  base ratio/.store in=\snowpersonbaseratio,
  torso ratio/.store in=\snowpersontorsoratio,
  head ratio/.store in=\snowpersonheadratio,
  line width/.store in=\snowpersonlinewidth,
  arm thickness/.store in=\snowpersonarmwidth,
  minimum base width=20mm,
  minimum torso width=10mm,
  minimum head width=5mm,
  line width=.4pt,
  arm thickness=1pt,
  base ratio=.25,
  torso ratio=.5,
  head ratio=1,
  name/.store in=\snowpersonname,
  name=snow person,
}

然后简单地

    \begin{tikzpicture}[framed,line width=1pt]
      \pic {snowperson};
    \end{tikzpicture}

生产

全猪图片版本

请注意,的线宽pic现在与周围tikzpicture的无关line width。要生成原始1pt版本,我们需要:

\begin{tikzpicture}[framed]
  \pic {snowperson={line width=1pt}};
\end{tikzpicture}

制作原版

原始雪人

\begin{tikzpicture}[framed,line width=1pt]
  \pic {snowperson={name=sam}};
  \pic [right=of sam.south, draw=blue!50!cyan, inner color=blue!50!cyan!25!white, outer color=blue!50!cyan!50!white] {snowperson={name=child, minimum base width=10mm, minimum torso width=5mm, minimum head width=4mm, base ratio=.4, torso ratio=.65}};
  \pic [right=of child.west, ball color=cyan!2!white] {snowperson={name=alex, line width=1pt, arm thickness=2pt}};
\end{tikzpicture}

向我们讲述了雪人家庭的起源:

雪人家庭

[另一种方法是选择使用时活动的默认线宽pic,但这个版本似乎更灵活。]

snowperson pic单精度和三精度的完整代码:

\documentclass[tikz,multi,border=10pt]{standalone}
\usetikzlibrary{positioning,shapes.geometric,intersections,backgrounds}
\tikzset{
  /tikz/.cd,
  pics/snowperson/.style={%
    code={%
      \tikzset{%
        inner sep=0pt,
        snowperson/.cd,
        #1,
      }
      \begin{scope}[local bounding box/.expanded=\snowpersonname, line width=\snowpersonlinewidth, pic actions]
        \node [ellipse, draw, pic actions, minimum width=\snowpersonminimumbasewidth, minimum height=\snowpersonminimumbasewidth*\snowpersonbaseratio] (P0) {};
        \node [ellipse, draw, pic actions, minimum width=\snowpersonminimumtorsowidth, minimum height=\snowpersonminimumtorsowidth*\snowpersontorsoratio, above=-\snowpersonlinewidth of P0] (P1) {};
        \node [ellipse, draw, pic actions,minimum width=\snowpersonminimumheadwidth, minimum height=\snowpersonminimumheadwidth*\snowpersonheadratio, above=-\snowpersonlinewidth of P1] (P2) {};
        \draw (P2) ++(-30:.4*\snowpersonminimumheadwidth) arc(-30:-150:.4*\snowpersonminimumheadwidth);
        \draw [fill=black] (P2) +(.2*\snowpersonminimumheadwidth,0) circle(.08*\snowpersonminimumheadwidth) +(-.2*\snowpersonminimumheadwidth,0) circle(.08*\snowpersonminimumheadwidth);
        \begin{pgfinterruptboundingbox}
          \path [name path=M1] (P1) ++(10:.4*\snowpersonminimumtorsowidth) --++(20:2*\snowpersonminimumtorsowidth);
          \path [name path=N1] (P0.east) |- (P2.east);
          \path [name intersections={of=M1 and N1,by=CS1}];
          \path [name path=M2] (P1) ++(170:.4*\snowpersonminimumtorsowidth) --++(160:2*\snowpersonminimumtorsowidth);
          \path [name path=N2] (P0.west) |- (P2.west);
          \path [name intersections={of=M2 and N2,by=CS2}];
        \end{pgfinterruptboundingbox}
        \draw [line width=\snowpersonarmwidth] (P1) ++(10:.4*\snowpersonminimumtorsowidth) -- (CS1);
        \draw [line width=\snowpersonarmwidth] (P1) ++(170:.4*\snowpersonminimumtorsowidth) -- (CS2);
      \end{scope}
    }
  },
  snowperson/.search also={/tikz},
  snowperson/.cd,
  minimum base width/.store in=\snowpersonminimumbasewidth,
  minimum torso width/.store in=\snowpersonminimumtorsowidth,
  minimum head width/.store in=\snowpersonminimumheadwidth,
  base ratio/.store in=\snowpersonbaseratio,
  torso ratio/.store in=\snowpersontorsoratio,
  head ratio/.store in=\snowpersonheadratio,
  line width/.store in=\snowpersonlinewidth,
  arm thickness/.store in=\snowpersonarmwidth,
  minimum base width=20mm,
  minimum torso width=10mm,
  minimum head width=5mm,
  line width=.4pt,
  arm thickness=1pt,
  base ratio=.25,
  torso ratio=.5,
  head ratio=1,
  name/.store in=\snowpersonname,
  name=snow person,
}
\begin{document}
\begin{tikzpicture}[framed,line width=1pt]
  \pic {snowperson};
\end{tikzpicture}
\begin{tikzpicture}[framed]
  \pic {snowperson={line width=1pt}};
\end{tikzpicture}
\begin{tikzpicture}[framed,line width=1pt]
  \pic {snowperson={name=sam}};
  \pic [right=of sam.south, draw=blue!50!cyan, inner color=blue!50!cyan!25!white, outer color=blue!50!cyan!50!white] {snowperson={name=child, minimum base width=10mm, minimum torso width=5mm, minimum head width=4mm, base ratio=.4, torso ratio=.65}};
  \pic [right=of child.west, ball color=cyan!2!white] {snowperson={name=alex, line width=1pt, arm thickness=2pt}};
\end{tikzpicture}
\end{document}

相关内容