我发现了一个有趣的雪人这里,为了好玩,我用一些相对坐标重写它,如下所示:
\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}
这里有两个缺陷:
- 我本来想用路径命令只获取交点,但是现在好像用到了绘图区域,所以图片太宽了,还有白色!
- 交点命令现在分为 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}