在tikz中绘制通用区域的边界

在tikz中绘制通用区域的边界

我需要在 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通过您的坐标绘制曲线时,它使用贝塞尔曲线(对于所有曲线,包括arcs、circles 和ellipses)。此曲线需要两个支撑点。

当你要求绘制 asmoothsmooth cycled 图时,这些支撑点是根据前一个点和下一个点计算出来的,手动状态

为了确定点处的曲线的控制点,处理程序计算向量 − 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}

在此处输入图片描述

相关内容