我需要在 TikZ 中绘制一个图表,虽然我得到的结果看起来像我预期的那样,但我想知道是否有更好/更通用的解决方案来解决我的问题。
基本上,我想绘制一个具有 n 个连接的节点(在我的实现中为 3),然后重复/继续该模式(根据我想要继续该模式的连接进行旋转和平移)。
我想知道是否有可能得到如下解决方案:
\drawGraph{(position0)}{rotation0}{[2,3,1,3,1,3,3,3,3,2]}
得到与我所实现的类似的东西。
这是我当前的解决方案:
\documentclass{article}
\usepackage{ifthen}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document}
\begin{tikzpicture}
\newcommand\robotMovement[3]{
\begin{scope}[shift={#1},rotate=#2,black!30]
\ifthenelse{\equal{#3}{2}}{\draw[black,thick]}{\draw} (0,0) arc (0:45:1cm);
\ifthenelse{\equal{#3}{1}}{\draw[black,thick]}{\draw} (0,0) -- (0,1cm);
\ifthenelse{\equal{#3}{3}}{\draw[black,thick]}{\draw} (0,0) arc (0:-45:-1cm);
\filldraw (0,0) circle (0.1cm);
\end{scope}
}
% The whole map
\draw (0,0) rectangle (5cm,5cm);
\clip (0,0) rectangle (5cm,5cm);
% Obstacles
\draw[fill=black] (3cm,2cm) rectangle (5cm,2.5cm);
\draw[fill=black] (3cm,2.5cm) rectangle (3.5cm,4cm);
% Robot C-space coordinates
\coordinate (path00) at (4.6cm,0.6cm);
\coordinate (path0f) at ($(path00)+(0,1cm)$);
\coordinate (path01) at ($(path00)! 1! 45:(path0f)$);
\coordinate (path02) at ($(path00)!0.79! 22.5:(path01)$);
\coordinate (path03) at ($(path00)!0.79!-22.5:(path01)$);
\coordinate (path1f) at ($(path02)+(0,1cm)$);
\coordinate (path11) at ($(path02)! 1! 90:(path1f)$);
\coordinate (path12) at ($(path02)!0.79! 22.5:(path11)$);
\coordinate (path13) at ($(path02)!0.79!-22.5:(path11)$);
\coordinate (path2f) at ($(path13)+(0,1cm)$);
\coordinate (path21) at ($(path13)! 1! 45:(path2f)$);
\coordinate (path22) at ($(path13)!0.79! 22.5:(path21)$);
\coordinate (path23) at ($(path13)!0.79!-22.5:(path21)$);
\coordinate (path3f) at ($(path23)+(0,1cm)$);
\coordinate (path31) at ($(path23)! 1! 45:(path3f)$);
\coordinate (path32) at ($(path23)!0.79! 22.5:(path31)$);
\coordinate (path33) at ($(path23)!0.79!-22.5:(path31)$);
\coordinate (path4f) at ($(path31)+(0,1cm)$);
\coordinate (path41) at ($(path31)! 1! 0:(path4f)$);
\coordinate (path42) at ($(path31)!0.79! 22.5:(path41)$);
\coordinate (path43) at ($(path31)!0.79!-22.5:(path41)$);
\coordinate (path5f) at ($(path41)+(0,1cm)$);
\coordinate (path51) at ($(path41)! 1! 0:(path5f)$);
\coordinate (path52) at ($(path41)!0.79! 22.5:(path51)$);
\coordinate (path53) at ($(path41)!0.79!-22.5:(path51)$);
\coordinate (path6f) at ($(path53)+(0,1cm)$);
\coordinate (path61) at ($(path53)! 1! -45:(path6f)$);
\coordinate (path62) at ($(path53)!0.79! 22.5:(path61)$);
\coordinate (path63) at ($(path53)!0.79!-22.5:(path61)$);
\coordinate (path7f) at ($(path63)+(0,1cm)$);
\coordinate (path71) at ($(path63)! 1! -90:(path7f)$);
\coordinate (path72) at ($(path63)!0.79! 22.5:(path71)$);
\coordinate (path73) at ($(path63)!0.79!-22.5:(path71)$);
\coordinate (path8f) at ($(path73)+(0,1cm)$);
\coordinate (path81) at ($(path73)! 1! -135:(path8f)$);
\coordinate (path82) at ($(path73)!0.79! 22.5:(path81)$);
\coordinate (path83) at ($(path73)!0.79!-22.5:(path81)$);
\coordinate (path9f) at ($(path83)+(0,1cm)$);
\coordinate (path91) at ($(path83)! 1! -135:(path9f)$);
\coordinate (path92) at ($(path83)!0.79! 22.5:(path91)$);
\coordinate (path93) at ($(path83)!0.79!-22.5:(path91)$);
\robotMovement{(path00)}{45}{2}
\robotMovement{(path02)}{90}{3}
\robotMovement{(path13)}{45}{1}
\robotMovement{(path21)}{45}{3}
\robotMovement{(path31)}{0}{1}
\robotMovement{(path41)}{0}{3}
\robotMovement{(path53)}{-45}{3}
\robotMovement{(path63)}{-90}{3}
\robotMovement{(path73)}{-135}{3}
\robotMovement{(path83)}{-180}{2}
\filldraw[black!70] (path93) circle (0.1cm);
% Robot
\begin{scope}[shift={(4.6cm,0.6cm)},rotate=45,scale=0.5]
% Body
\draw[fill=white] (-3mm,-3mm) rectangle (3mm,3mm);
% Wheels
\draw[fill=black] (-4mm,0.75mm) rectangle (-3mm,2.25mm);
\draw[fill=black] (3mm,0.75mm) rectangle (4mm,2.25mm);
\draw[fill=black] (-4mm,-0.75mm) rectangle (-3mm,-2.25mm);
\draw[fill=black] (3mm,-0.75mm) rectangle (4mm,-2.25mm);
\end{scope}
\end{tikzpicture}
\end{document}
生成如下内容:
答案1
这对于这个特殊情况来说非常特殊,但它几乎可以推广到更多路径情况。这个想法本质上是一样的。
我为三向路径替代方案编写了一个简单的装饰,并将其绘制在原始路径下方。然后绘制路径本身并在其上放置一个点装饰。许多参数可以移动到键并单独设置,但这取决于您的方便和用例。
要使用它,需要两个参数。第一个参数是起始方向的 45 的倍数,第二个参数是路径选择数组。我从左转、直行、右转数到一到三。例如,
\robotrace{5}{3,1,2,1}
从面向西南开始,向右转、向左转、直行,然后再向左转。您也可以将此命令放在范围内,然后移动它以更改初始点。
所以整个代码是;
\documentclass[tikz,border=5mm]{standalone}
\usetikzlibrary{decorations}
\pgfdeclaredecoration{xroad}{junction}{%
\state{junction}[width=\pgfdecoratedinputsegmentlength]{%
\pgfpathmoveto{\pgfpointorigin}\pgfpathlineto{\pgfpointpolar{0}{1cm}}%
\pgfpathmoveto{\pgfpointorigin}\pgfpatharc{90}{45}{1cm}%
\pgfpathmoveto{\pgfpointorigin}\pgfpatharc{90}{135}{-1cm}}%
}
\pgfdeclaredecoration{xpost}{dot}{%
\state{dot}[width=\pgfdecoratedinputsegmentlength]{%
\pgfsetfillcolor{gray!50}
\pgfpathcircle{\pgfpointorigin}{1mm}\pgfusepath{fill}}%
}
\def\robotrace#1#2{
\def\mytotalrot{#1}
\draw[preaction={decorate,decoration={xroad},draw,very thin,gray},
postaction={decoration=xpost,decorate}]
(0,0) \foreach\x in {#2}{
\ifnum\x>1\ifnum\x>2%
arc (90+\mytotalrot*45:{90+(\mytotalrot-1)*45}:1cm)
\else
--++(\mytotalrot*45:1cm)
\fi\else
arc (-90+\mytotalrot*45:{-90+(\mytotalrot+1)*45}:1cm)
\fi
\pgfextra{\pgfmathparse{\mytotalrot+2-\x}\xdef\mytotalrot{\pgfmathresult}}}
node[circle,fill=black,inner sep=0,minimum size=2mm]{};
}
\begin{document}
\begin{tikzpicture}
\draw[style=help lines] (0,0) grid[step=1cm] (5,5);
\robotrace{1}{2,3,1,1,1,3,3,2,3,3,3,2,2,3,1,1}
\end{tikzpicture}
\end{document}
答案2
我认为这样就可以了。
\documentclass[border=5]{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}
\tikzset{%
robot/.style={
%robot path,
postaction={decoration={robot}, decorate},
robot movements/.cd, #1
},
robot swoosh/.style={draw=gray},
robot movements/.cd,
.unknown/.code={
\let\robotkey\pgfkeyscurrentname%
\pgfkeys{/tikz/\robotkey/.try={#1}}%
},
robot step/.store in=\robotstep,
robot step=3cm,
robot swoosh factor/.store in=\robotswooshfactor,
robot swoosh factor=1.25,
home/.style={ insert path={ (0,0) } },
forward/.style={
insert path={ [shift=(90:\robotstep)] -- (0,0) }
},
left/.style={
insert path={ arc (0:45:\robotstep*sqrt 2)
[shift=(112.5:2*\robotstep*sqrt 2*sin 22.5),rotate=45] }
},
right/.style={
insert path={ arc (180:135:\robotstep*sqrt 2)
[shift=(90-22.5:2*\robotstep*sqrt 2*sin 22.5),rotate=-45] }
},
turn left/.style={ rotate=45 },
turn right/.style={ rotate=-45 },
stop/.style={ insert path={ (0,0) } }
}
\def\curvetotext{curveto}
\pgfdeclaredecoration{robot}{start}{
\state{start}[next state=draw, width=0pt]{
\fill [black!75] circle [radius=0.25];}
\state{draw}[width=\pgfdecoratedinputsegmentlength,
switch if less than=\pgfdecoratedinputsegmentlength+1pt to final]{%
\dorobotswoosh
\fill [black!50] circle [radius=0.25];
}
\state{final}{
\dorobotswoosh
\dorobot
}
}
\def\getrobotangle{%
\pgfmathparse{\pgfdecoratedinputsegmentstartangle-\pgfdecoratedinputsegmentendangle}
\pgfmathparse{int(round(\pgfmathresult/45)*45)}%
\pgfmathparse{\pgfmathresult >180 ? \pgfmathresult-360 : \pgfmathresult}
\pgfmathparse{\pgfmathresult <-180 ? 360+\pgfmathresult : \pgfmathresult}
\let\robotangle=\pgfmathresult
\pgftransformshift{\pgfpointdecoratedinputsegmentlast}%
\pgftransformresetnontranslations
\pgftransformrotate{\pgfdecoratedinputsegmentendangle}%
}
\def\dorobotswoosh{%
\getrobotangle%
\ifx\pgfdecorationcurrentinputsegment\curvetotext
\draw [robot swoosh/.try] (0,0) -- (180:\robotstep/2*\robotswooshfactor) [yscale=\robotangle/45]
(0,0) arc (270:225:\robotstep*\robotswooshfactor/sqrt 2 and \robotstep/2);
\else
\draw [robot swoosh/.try]
(0,0) arc (270:225:\robotstep*\robotswooshfactor/sqrt 2 and \robotstep/2)
[yscale=-1]
(0,0) arc (270:225:\robotstep*\robotswooshfactor/sqrt 2 and \robotstep/2);
\fi
}%
\def\dorobot{
\filldraw [fill=white, draw=black]
(-0.5,-0.5) rectangle ++(1,1);
\fill (-0.375,0.375) rectangle ++(0.25,0.25)
(0.375,0.375) rectangle ++(-0.25,0.25)
(-0.375,-0.375) rectangle ++(0.25,-0.25)
(0.375,-0.375) rectangle ++(-0.25,-0.25);
}
\begin{document}
\begin{tikzpicture}
\draw [robot={home, turn left, right, left, left, left, left,
forward, left, forward, left, right, stop}];
\end{tikzpicture}
\end{document}