![在tikz中绘制通用区域的边界](https://linux22.com/image/454547/%E5%9C%A8tikz%E4%B8%AD%E7%BB%98%E5%88%B6%E9%80%9A%E7%94%A8%E5%8C%BA%E5%9F%9F%E7%9A%84%E8%BE%B9%E7%95%8C.png)
我需要在 tikz 中绘制通用区域的边界。下面给出了实现此想法的代码。
\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{color,xcolor}
\begin{document}
\begin{tikzpicture}
\draw[-latex] (-0.5,0) -- (6,0) node[right]{$x_1$};
\draw[-latex] (0,-0.5) -- (0,6) node[above]{$x_2$};
\draw [fill=cyan,opacity=0.5] plot [smooth cycle,tension=0.5] coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8) (5.38,0.82) (6.02,2.32) (6.02,3.66) (5.3,5.04) (3.68,5.44) (1.82,5.52)};
\draw[red,thick] plot [smooth,tension=0.5] coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8)};
\end{tikzpicture}
\end{document}
其输出如下:
但是,当我重复边界的坐标时,即使我改变了张力参数,红线似乎也不适合该区域。
我该如何解决这个问题?
答案1
您可以绘制两次,但第二次使用剪切矩形。
\documentclass{standalone}
\usepackage[utf8]{inputenc}
\usepackage{tikz}
\usepackage{color,xcolor}
\begin{document}
\begin{tikzpicture}
\draw[-latex] (-0.5,0) -- (6,0) node[right]{$x_1$};
\draw[-latex] (0,-0.5) -- (0,6) node[above]{$x_2$};
\draw [fill=cyan,opacity=0.5] plot [smooth cycle,tension=0.5] coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8) (5.38,0.82) (6.02,2.32) (6.02,3.66) (5.3,5.04) (3.68,5.44) (1.82,5.52)};
\begin{scope}
\clip (0.3,4.8) rectangle (4.20,0.15);
\draw[red,thick] plot [smooth cycle,tension=0.5] coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8) (5.38,0.82) (6.02,2.32) (6.02,3.66) (5.3,5.04) (3.68,5.44) (1.82,5.52)};
\end{scope}
\end{tikzpicture}
\end{document}
答案2
blank
以下是该包中的替代方案hobby
:
\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary{hobby}
\begin{document}
\begin{tikzpicture}[use Hobby shortcut]
\draw[fill=cyan, opacity=0.5, closed, tension=10] (0.38,4.74)..(0.78,3.54)..(2.16,2.88)..(2.88,1.54)..(4.18,0.8)..(5.38,0.82)..(6.02,2.32)..(6.02,3.66)..(5.3,5.04)..(3.68,5.44)..(1.82,5.52);
\draw[red, thick, closed, tension=10] (0.38,4.74)..(0.78,3.54)..(2.16,2.88)..(2.88,1.54)..(4.18,0.8)..([blank]5.38,0.82)..([blank]6.02,2.32)..([blank]6.02,3.66)..([blank]5.3,5.04)..([blank]3.68,5.44)..([blank]1.82,5.52);
\end{tikzpicture}
\end{document}
不过它的形状和以前不一样了。Hobby 生成的曲线比以前更平滑plot
- 这是由软件包/算法设计的。
编辑:我现在发现,我似乎完全窃取了 @Andrew Stacey 的评论中的想法。Andrew 确实是 Hobby 这个出色包/实现的作者。他可能有更好的方法来做到这一点。我的想法/出发点来自我的一个旧答案:https://tex.stackexchange.com/a/646711/8650
编辑:代码中的点较少,可以重用路径,但还没有填充 - 需要弄清楚。(好的 - 重用路径时无法进行填充)
\documentclass[tikz, border=1cm]{standalone}
\usetikzlibrary {decorations.pathreplacing, arrows.meta}
\usetikzlibrary{hobby}
\begin{document}
\begin{tikzpicture}[use Hobby shortcut]
\draw[red, thick,closed] (0.4,4.0)..(2.2,2.9)..(2.9,1.5)..(4.3,0.8)..([blank=soft]5.4,0.8)..([blank=soft]6.0,3)..([blank=soft]5.3,5.0)..([blank=soft]3.5,5.4)..([blank=soft]1.8,5.5);
\draw[cyan, use previous Hobby path={invert soft blanks, disjoint}] ;
\end{tikzpicture}
\end{document}
答案3
当 PGF/TikZsmooth
通过您的坐标绘制曲线时,它使用贝塞尔曲线(对于所有曲线,包括arc
s、circle
s 和ellipse
s)。此曲线需要两个支撑点。
当你要求绘制 asmooth
或smooth cycle
d 图时,这些支撑点是根据前一个点和下一个点计算出来的,手动状态:
为了确定点处的曲线的控制点是,处理程序计算向量是 − X并按张力因子缩放它(见下文)。我们称结果向量为s。 然后是 + s和是 − s将是周围的控制点是。
对于smooth cycle
绘图来说,最后一个坐标将是第一个点的前一个点,而第一个点将是最后一个点的下一个点。但是,smooth
手册上说:
曲线起点处的第一个控制点将再次作为起点本身;同样,最后一个控制点也将作为终点本身。
这就是为什么你的smooth
图与第一个和最后一个片段上的封闭图不相等的原因。它缺少有关第一个前一个点和最后一个下一个点的信息。
随着decorations.pathreplacing
图书馆我们甚至可以检查支撑点:
我们需要将红色 X 放在(0.38, 4.74)
其左下方的蓝色 X 上,以绘制相同的曲线:
为此,我建议稍微改变一下 plothandler,它使用第一个点和最后一个点来计算支撑点,但不在这些点上绘制任何线或曲线。
为此,我声明了一个 plothandler \pgfplothandlercurvetostartend
。在 TikZ 中,它映射到 key smooth start and end
。
您只需自己向图表提供要点即可:
\draw[red,thick]
plot [smooth start and end, tension=0.5]
coordinates {
(1.82,5.52) % coordinate before first
(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8)
(5.38,0.82) % coordinate after last
};
代码
\documentclass[tikz]{standalone}
\makeatletter
\tikzset{smooth start and end/.code={%
\let\tikz@plot@handler=\pgfplothandlercurvetostartend}}
\pgfdeclareplothandler{\pgfplothandlercurvetostartend}{}{
point macro=\pgf@plot@curvetostartend@handler@initial,
jump macro=\pgf@plot@smoothstartend@next@moveto}
\def\pgf@plot@smoothstartend@next@moveto{%
\global\pgf@plot@startedfalse
\global\let\pgf@plotstreampoint\pgf@plot@curvetostartend@handler@initial}
\def\pgf@plot@curvetostartend@handler@initial#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@first{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
\global\let\pgf@plot@curveto@first@support=\pgf@plot@curveto@first
\global\let\pgf@plotstreampoint=\pgf@plot@curvetostartend@handler@second}
\def\pgf@plot@curvetostartend@handler@second#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
\pgf@plot@first@action{\pgf@plot@curveto@second}%
\global\let\pgf@plotstreampoint=\pgf@plot@curvetostartend@handler@third}
\def\pgf@plot@curvetostartend@handler@third#1{%
\pgf@process{#1}%
\xdef\pgf@plot@curveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
% compute difference vector:
\pgf@xa=\pgf@x
\pgf@ya=\pgf@y
\pgf@process{\pgf@plot@curveto@first}%
\advance\pgf@xa by-\pgf@x
\advance\pgf@ya by-\pgf@y
% compute support directions:
\pgf@xa=\pgf@plottension\pgf@xa
\pgf@ya=\pgf@plottension\pgf@ya
% first marshal:
\pgf@process{\pgf@plot@curveto@second}%
\pgf@xb=\pgf@x
\pgf@yb=\pgf@y
\pgf@xc=\pgf@x
\pgf@yc=\pgf@y
\advance\pgf@xb by-\pgf@xa
\advance\pgf@yb by-\pgf@ya
\advance\pgf@xc by\pgf@xa
\advance\pgf@yc by\pgf@ya
\ifpgf@plot@started
\edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@curveto@first@support}%
{\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@curveto@second}}%
{\pgf@marshal}%
\else
% we didn't start yet, skip this drawing
\global\pgf@plot@startedtrue
\fi
% Prepare next:
\global\let\pgf@plot@curveto@first=\pgf@plot@curveto@second
\global\let\pgf@plot@curveto@second=\pgf@plot@curveto@current
\xdef\pgf@plot@curveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}}
\makeatother
\begin{document}
\begin{tikzpicture}
\draw[-latex] (-0.5,0) -- (6,0) node[right]{$x_1$};
\draw[-latex] (0,-0.5) -- (0,6) node[above]{$x_2$};
\draw[fill=cyan, opacity=0.5]
plot [smooth cycle,tension=0.5]
coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8)
(5.38,0.82) (6.02,2.32) (6.02,3.66) (5.3,5.04) (3.68,5.44) (1.82,5.52)};
% that's the wrong one
\draw[green!50!black,thin]
plot [smooth, tension=0.5]
coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8)};
% different plothandler and coordinate before first and coordinate after last supplied
\draw[red,thick]
plot [smooth start and end, tension=0.5]
coordinates {
(1.82,5.52) % coordinate before first
(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8)
(5.38,0.82) % coordinate after last
};
\end{tikzpicture}
\end{document}
输出
答案4
通过反复试验有点方便,有点不准确,但最短答案(当然不是最好的)使用dash pattern
:
\documentclass{standalone}
\usepackage{tikz}
\usepackage{color,xcolor}
\begin{document}
\begin{tikzpicture}
\draw[-latex] (-0.5,0) -- (6,0) node[right]{$x_1$};
\draw[-latex] (0,-0.5) -- (0,6) node[above]{$x_2$};
\draw [fill=cyan,opacity=0.5,draw=red, thick, dash pattern=on 140pt off 290pt on 60pt] plot [smooth cycle,tension=0.5] coordinates {(0.38,4.74) (0.78,3.54) (2.16,2.88) (2.88,1.54) (4.18,0.8) (5.38,0.82) (6.02,2.32) (6.02,3.66) (5.3,5.04) (3.68,5.44) (1.82,5.52)};
\end{tikzpicture}
\end{document}