我怎样才能(有可能)制作一种装饰风格,以一条路径(或可能多条路径,那就完美了)作为参数,并在路径相交处制作圆弧、蛇形、椭圆形(无论什么)?我见过以下两种方法:
但是它们相当详尽,特别是如果一条路径与另一条路径有多个交点,那么这会变得非常详尽。此外,它们大多仅限于直线。
第一次尝试:
受到 Emma 的回答的启发这个问题我能够组装一个 MWE,但它仍然不够好,因为它不支持曲线路径,并且线条不会连接(如果使用多个坐标来构建路径)。除此之外,无法控制跳跃大小...
\documentclass{standalone}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing,intersections,calc}
\tikzset{
over path/.style={
decoration={show path construction, lineto code={
\path[name path=this path] (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
\path[name intersections={of=this path and #1, total=\t}, /utils/exec={\global\let\t=\t}]%
let \n1={int(\t+1)} in%
(\tikzinputsegmentfirst) coordinate (int-0)%
foreach \i in {1,...,\n1}{%
\ifnum \i<\n1%
(intersection-\i) coordinate (int-\i)%
\else
(\tikzinputsegmentlast) coordinate (int-\n1)%
\fi};
\draw (\tikzinputsegmentfirst) foreach[remember=\i as \last (initially 0)] \i in {1,...,\t}{%
let \p1=($(int-\last)-(int-\i)$), \n1={veclen(\x1,\y1)}, \n2={abs(4pt)}, \n3={\i+1} in%
[rounded corners=\n2/4] -- ($(int-\last)!\n1-\n2!(int-\i)$) to[bend left=90, looseness=1.7] ($(int-\last)!\n1+\n2!(int-\n3)$)} -- (\tikzinputsegmentlast);
}
},
decorate
}
}
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (-1,0.5);
\coordinate (b) at (8,0.5);
\coordinate (c) at (3,-0.5);
\draw[ultra thick, name path=sine, domain=-1:8, smooth, samples=50] plot (\x,{sin(\x r)});
\draw[over path=sine] (a) -- (c) |- (b);
\end{tikzpicture}
\end{document}
线路连接不良:
答案1
这是使用spath3
库。其工作原理如下:
- 在上方路径与下方路径的相交处分割上方路径。
- 在这些点处的路径上插入间隙。
- 将圆弧接合到这些间隙中(将其连接到现有路径,以使连接无缝)。
- 在下部路径与新的上部路径相交处分割下部路径。
- 在这些点的下方路径中插入小间隙。
开发版本(github
——即将在 CTAN 上发布)包含一个版本的拼接代码,可确保弧线始终“直立”。这将很快在 CTAN 上发布。
结果如下:
\documentclass{article}
%\url{https://tex.stackexchange.com/q/334483/86}
\usepackage{tikz}
\usetikzlibrary{spath3,intersections}
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (-1,0.5);
\coordinate (b) at (8,0.5);
\coordinate (c) at (3,-0.5);
\path[
ultra thick,
spath/save=sine,
domain=-1:8,
smooth,
samples=50
] plot (\x,{sin(\x r)});
\path[spath/save=over] (a) -- (c) |- (b);
\path[spath/save=arc] (0,0) arc[radius=1cm, start angle=180, delta angle=-180];
\tikzset{
spath/split at intersections with={over}{sine},
spath/insert gaps after components={over}{8pt},
spath/join components with={over}{arc},
spath/split at intersections with={sine}{over},
spath/insert gaps after components={sine}{4pt},
}
\draw[spath/use=sine];
\draw[spath/use=over];
\end{tikzpicture}
\end{document}
答案2
这是一个解决方案。它是全自动的,即使对于曲线也应该很好。符号是avoid intersection={name of other path}{drawing options}
。它会找到交叉点列表,然后执行一个装饰,测量到下一个交叉点的距离,当距离很近时,进行规避动作。使用选项avoid intersect amplitude
、avoid intersect width
和,avoid intersect offset
您可以调整规避动作。
它并不完美。它非常慢(在我的电脑上,这两个示例分别需要 1.4 秒和 3.8 秒),这可能是不可避免的。此外,如果您smooth
在下面的第二个示例中包含该选项,它会因“维度太大”错误而中断。我不知道为什么。我认为输出看起来非常好。
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{decorations}
\usetikzlibrary{intersections}
\makeatletter
\tikzset{
avoid intersection amplitude/.store in=\avint@amplitude,
avoid intersection width/.code={\edef\avint@width{\dimexpr#1/2}},
avoid intersection offset/.store in=\avint@offset,
avoid intersection has corners/.code={\pgfdecoratepathhascornerstrue}
}
\def\avint@amplitude{5pt}
\def\avint@width{5pt}
\def\avint@offset{0pt}
\pgfdeclaredecoration{avoidintersect}{initial}{
\state{initial}[width=\pgfdecoratedinputsegmentlength/100,next state=measure]
{
\gdef\avint@intersectionnumber{1}
\pgfpathlineto{\pgfpointorigin}
}
\state{measure}[width=\pgfdecoratedinputsegmentlength/100,next state=wait,auto corner on length=2pt,
persistent postcomputation=\let\pgf@decorate@next@state\avint@smuggle@pgf@decorate@next@state]
{
\pgfpathlineto{\pgfpointorigin}
\pgfgettransform\avint@temptransform
\pgftransforminvert
\pgfpointintersectionsolution{\avint@intersectionnumber}
\pgf@pos@transform{\pgf@x}{\pgf@y}
\pgfmathveclen{\pgf@x}{\pgf@y}
\pgfsettransform\avint@temptransform
\xdef\avint@waitcycles{\the\numexpr\dimexpr\pgfmathresult pt-\avint@width*3-\avint@offset\relax/\dimexpr\pgfdecoratedinputsegmentlength/100\relax}
\ifnum\avint@waitcycles>50\relax\gdef\avint@waitcycles{50}\fi
\global\let\avint@smuggle@pgf@decorate@next@state\pgf@decorate@next@state
\ifdim\pgfmathresult pt<\dimexpr\avint@width+\avint@offset\relax
\gdef\avint@smuggle@pgf@decorate@next@state{zig}
\else
\ifdim\pgfmathresult pt<\dimexpr\avint@width*2+\avint@offset\relax
\gdef\avint@smuggle@pgf@decorate@next@state{measure}
\fi
\fi
}
\state{wait}[width=\pgfdecoratedinputsegmentlength/100,next state=measure,repeat state=\avint@waitcycles,auto corner on length=2pt]{
\pgfpathlineto{\pgfpointorigin}
}
\state{zig}[width=\avint@width, next state=zag]{
\pgfpathcurveto{\pgfqpoint{\avint@width}{0cm}}{\pgfqpoint{0pt}{\avint@amplitude}}{\pgfqpoint{\avint@width}{\avint@amplitude}}
}
\state{zag}[width=\avint@width, next state=measure,
persistent postcomputation=\let\pgf@decorate@next@state\avint@smuggle@pgf@decorate@next@state]{
\pgfpathcurveto{\pgfqpoint{\avint@width}{\avint@amplitude}}{\pgfqpoint{0pt}{0cm}}{\pgfqpoint{\avint@width}{0pt}}
\xdef\avint@intersectionnumber{\the\numexpr\avint@intersectionnumber+1}
\global\let\avint@smuggle@pgf@decorate@next@state\pgf@decorate@next@state
\ifnum\avint@intersectionnumber>\pgfintersectionsolutions
\gdef\avint@smuggle@pgf@decorate@next@state{done}
\fi
}
\state{done}[width=\pgfdecoratedinputsegmentlength/100,auto corner on length=2pt]{
\pgfpathlineto{\pgfpointorigin}
}
\state{final}{\pgfpathlineto{\pgfpointdecoratedpathlast}}
}
\tikzset{
avoid intersection/.code 2 args={
\pgfkeysalso{name path=avint@temp,draw=none}
\expandafter\def\expandafter\tikz@postactions\expandafter{\tikz@postactions
\pgfintersectionsortbyfirstpath
\tikz@intersect@namedpaths
\pgfintersectionofpaths
{\pgfsetpath\tikz@intersect@path@name@avint@temp}
{\expandafter\pgfsetpath\csname tikz@intersect@path@name@#1\endcsname}
\begin{pgfdecoration}{{avoidintersect}{\pgfdecoratedpathlength}}
\pgfsetpath\tikz@intersect@path@name@avint@temp
\end{pgfdecoration}
\pgfgetpath\avint@temp@path
\pgfusepath{discard}
\draw[/utils/exec={\tikz@addmode{\pgfsyssoftpath@setcurrentpath\avint@temp@path}},#2](0,0)rectangle (0,0);%
}
}
}
\makeatother
\begin{document}
\begin{tikzpicture}
\coordinate (a) at (-1,0.5);
\coordinate (b) at (8,0.5);
\coordinate (c) at (3,-0.5);
\draw[ultra thick, name path=sine, domain=-1:8, smooth, samples=50] plot (\x,{sin(\x r)});
\draw[avoid intersection={sine}{white,double=black},avoid intersection has corners] (a) -- (c) |- (b);
\end{tikzpicture}
\begin{tikzpicture}
\coordinate (a) at (-1,0.5);
\coordinate (b) at (8,0.5);
\coordinate (c) at (3,-0.5);
\draw[ultra thick,name path=line] (a) -- (c) |- (b);
\draw[avoid intersection={line}{white,double=black},avoid intersection offset=1.5pt,domain=-1:8,samples=50] plot (\x,{sin(\x r)});
\end{tikzpicture}
\end{document}