我们可以模仿 TikZ 中 \pscurve 的行为吗?

我们可以模仿 TikZ 中 \pscurve 的行为吗?

这里有图片。

PSTricks 有一个非常简洁的命令\pscurve。手册给出了示例

\pscurve[showpoints=true]{<->}(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)

得出

pscurve 示例

有人知道如何在 TikZ 中获得相同的行为吗?

我尝试过各种方法,包括

\tikz \draw plot[smooth] coordinates {(0,1.3) (0.7,1.8) (3.3,0.5) (4,1.6) (0.4,0.4)};

这让我

tikz 绘图示例

(我确实尝试过控制张力!)最终的曲线看起来总是像一连串带有圆角的直线段。

谢谢你的积分!

答案1

据我所知,这不能“开箱即用”。但是,只要进行一点编程,就没有理由做不到。具体需要什么编程取决于问题的确切规格:是准确复制 pstricks 的行为,还是只是做一些类似的事情?如果是前者,那么您需要深入研究 pstricks 代码并提取它如何决定在哪里绘制线条的公式。如果是后者,那么进行一点实验就可以产生合理的结果。

我不能保证下面的方法会通过任意点族产生一条平滑的曲线,但这是一种合理的方法。绘图命令由指定点之间的贝塞尔曲线完成。困难在于找出合适的控制点。为此,需要向前看下一个点并找出一对合适的控制点。我选择做的是想象一条连接前一个点和下一个点的线,取它的中点,然后将其连接到当前点。通过当前点取与此线正交的线给了我控制点的方向。长度与当前点和前一个/下一个点之间的距离成比例(视情况而定)。

对于指定的控制点,这给我:

伪曲线仿真

\documentclass{minimal}

\usepackage{tikz}
\usetikzlibrary{calc}

\begin{document}

\begin{tikzpicture}
\let\pcoord\relax
\let\tcoord\relax
\foreach [count=\num] \coord in {
  (0,1.3),
  (0.7,1.8),
  (3.3,0.5),
  (4,1.6),
  (0.4,0.4)
  } {
  \ifx\pcoord\relax
   \global\let\pcoord\coord
   \path \pcoord coordinate (c1);
  \else
   \ifx\tcoord\relax
   \global\let\tcoord\coord
   \else
    \path \pcoord coordinate (p);
    \path \tcoord coordinate (t);
    \path \coord coordinate (n);
    \path ($(p)!.75!(n)$) coordinate (m);
    \path ($(t)!1cm!90:(m)$) coordinate (r);
    \path ($(t)-(p)$);
    \pgfgetlastxy{\xx}{\yy}
    \pgfmathsetmacro{\len}{.5*veclen(\xx,\yy)}
    \path ($(t)!(p)!(r)$) coordinate (rp);
    \path ($(t)!\len pt!(rp)$) coordinate (c2);
    \draw (p) .. controls (c1) and (c2) .. (t);
    \path ($(t)-(n)$);
    \pgfgetlastxy{\xx}{\yy}
    \pgfmathsetmacro{\len}{.5*veclen(\xx,\yy)}
    \path ($(t)!(n)!(r)$) coordinate (rn);
    \path ($(t)!\len pt!(rn)$) coordinate (c1);
    \global\let\pcoord\tcoord
    \global\let\tcoord\coord
   \fi
  \fi
}
\draw (t) .. controls (c1) and (n) .. (n);

\end{tikzpicture}

\end{document}

(如果“愤怒地”完成,人们可能应该担心边界框。我没有。)

  1. 最好使用外接圆的切线来计算控制点的方向(这会使第一个看起来更好)。
  2. 将整个事物设为一条路径而不是几条路径的连接会更好。

答案2

我尝试将@Andrew的想法重新创建为一个情节处理程序。但是出于某种原因,我得到了不同的结果。也许有人可以告诉我哪里出了问题(已经晚了……)。无论如何,这是情节处理程序:

\makeatletter

\def\pgfplothandlermycurveto{%
  \def\pgf@plotstreamstart{%
    \global\let\pgf@plotstreampoint=\pgf@plot@mycurveto@handler@initial%
    \global\let\pgf@plotstreamspecial=\pgfutil@gobble%
    \global\let\pgf@plotstreamend=\pgf@plot@mycurveto@handler@finish%
    \global\pgf@plot@startedfalse%
  }%
}

\def\pgf@plot@mycurveto@handler@initial#1{%
  \pgf@process{#1}%
  \pgf@xa=\pgf@x%
  \pgf@ya=\pgf@y%
  \pgf@plot@first@action{\pgfqpoint{\pgf@xa}{\pgf@ya}}%
  \xdef\pgf@plot@mycurveto@first{\noexpand\pgfqpoint{\the\pgf@xa}{\the\pgf@ya}}%
  \global\let\pgf@plot@mycurveto@first@support=\pgf@plot@mycurveto@first%
  \global\let\pgf@plotstreampoint=\pgf@plot@mycurveto@handler@second%
}

\def\pgf@plot@mycurveto@handler@second#1{%
  \pgf@process{#1}%
  \xdef\pgf@plot@mycurveto@second{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
  \global\let\pgf@plotstreampoint=\pgf@plot@mycurveto@handler@third%
  \global\pgf@plot@startedtrue%
}

\def\pgf@plot@mycurveto@handler@third#1{%
  \pgf@process{#1}%
  \xdef\pgf@plot@mycurveto@current{\noexpand\pgfqpoint{\the\pgf@x}{\the\pgf@y}}%
  % compute midpoint:
  \pgf@xa=\pgf@x%
  \pgf@ya=\pgf@y%
  \pgf@process{\pgf@plot@mycurveto@first}
  \advance\pgf@xa by\pgf@x%
  \advance\pgf@ya by\pgf@y%
  \pgf@xa=0.5\pgf@xa%
  \pgf@ya=0.5\pgf@ya%
  \pgf@xb=\pgf@xa%
  \pgf@yb=\pgf@ya%
  % vector from second to midpoint:
  \pgf@process{\pgf@plot@mycurveto@second}
  \advance\pgf@xa by-\pgf@x%
  \advance\pgf@ya by-\pgf@y%
  % vector from first to midpoint:
  \pgf@process{\pgf@plot@mycurveto@first}
  \advance\pgf@xb by-\pgf@x%
  \advance\pgf@yb by-\pgf@y%
  % normalize
  \pgfmathparse{\pgf@plottension / veclen(\pgf@xa,\pgf@ya)}%
  \let\pgf@l@dir=\pgfmathresult
  \pgfmathsetlength{\pgf@xa}{\pgf@xa * \pgf@l@dir}%
  \pgfmathsetlength{\pgf@ya}{\pgf@ya * \pgf@l@dir}%
  % compute orientation
  \pgfmathparse{\pgf@xa * \pgf@yb - \pgf@ya * \pgf@xb}%
  \pgfmathparse{-greater(\pgfmathresult,0) + less(\pgfmathresult,0)}
  \pgf@xa=\pgfmathresult\pgf@xa%
  \pgf@ya=\pgfmathresult\pgf@ya%
  % load second point
  \pgf@process{\pgf@plot@mycurveto@second}%
  \pgf@xb=\pgf@x%
  \pgf@yb=\pgf@y%
  \pgf@xc=\pgf@x%
  \pgf@yc=\pgf@y%
  % compute lengths
  \pgf@process{\pgf@plot@mycurveto@first}%
  \pgfmathparse{veclen((\pgf@xb-\pgf@x),(\pgf@yb-\pgf@y))}%
  \let\pgf@l@first=\pgfmathresult%
  \pgf@process{\pgf@plot@mycurveto@current}%
  \pgfmathparse{veclen(\pgf@xb-\pgf@x,\pgf@yb-\pgf@y)}%
  \let\pgf@l@second=\pgfmathresult%
  % first marshal:
  \pgfmathaddtolength{\pgf@xb}{-\pgf@l@first * \pgf@ya}%
  \pgfmathaddtolength{\pgf@yb}{\pgf@l@first * \pgf@xa}%
  \pgfmathaddtolength{\pgf@xc}{\pgf@l@second * \pgf@ya}%
  \pgfmathaddtolength{\pgf@yc}{-\pgf@l@second * \pgf@xa}%
  \edef\pgf@marshal{\noexpand\pgfpathcurveto{\noexpand\pgf@plot@mycurveto@first@support}%
    {\noexpand\pgfqpoint{\the\pgf@xb}{\the\pgf@yb}}{\noexpand\pgf@plot@mycurveto@second}}%
  {\pgf@marshal}%
  % Prepare next:
  \global\let\pgf@plot@mycurveto@first=\pgf@plot@mycurveto@second%
  \global\let\pgf@plot@mycurveto@second=\pgf@plot@mycurveto@current%
  \xdef\pgf@plot@mycurveto@first@support{\noexpand\pgfqpoint{\the\pgf@xc}{\the\pgf@yc}}%
}

\def\pgf@plot@mycurveto@handler@finish{%
  \ifpgf@plot@started%
    \pgfpathcurveto{\pgf@plot@mycurveto@first@support}{\pgf@plot@mycurveto@second}{\pgf@plot@mycurveto@second}%
  \fi%
}

\tikzoption{mysmooth}[]{\let\tikz@plot@handler=\pgfplothandlermycurveto}
\makeatother

为了获得绘图的单一路径,必须手动进行计算,而不使用任何其他路径。如果您在之后的某个地方包含上述代码\usepackage{tikz},则可以使用该mysmooth选项启动绘图处理程序。它会考虑张力并产生单一路径。

例如:

\tikz {
\draw plot[mysmooth,mark=x] coordinates {(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)};
\draw[red,densely dotted] plot[mysmooth,tension=1.5] coordinates {(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)};
\draw[gray,dashed] plot[smooth,tension=0.5] coordinates {(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)};
\draw[dotted,gray] (0,0) grid (4,2);
}

生产

例子

答案3

我刚刚尝试了以下解决方案,它们可以编译并给出“正确”的输出:将 PSTricks 图片放入 TikZ 节点内(这是圣诞节,奇迹比比皆是)。

\documentclass[10pt]{article} 

\usepackage{pstricks,tikz}
\begin{document}

\begin{tikzpicture}
\node {%
\begin{pspicture}(4,2)
\pscurve[showpoints=true]{<->}(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)
\end{pspicture}%
};
\draw [red] (0,0) -- (1,1);
\end{tikzpicture}
\end{document}

这里的红线只是为了确保我们可以混合 PSTricks 对象和 Tikz 对象。

我认为如果我们尝试更奇特的事情,我们可能会陷入冲突,但至少对于简单的事情来说,这似乎是一个解决方案。

谢谢 Herbert – 正是你的问题让我有了尝试这个技巧的想法。

答案4

\documentclass[10pt]{article} 

\usepackage{pstricks,tikz}
\begin{document}

\begin{tikzpicture}(4,2)
\node at (0,0){%
\pscurve[showpoints]{<->}(0,1.3)(0.7,1.8) (3.3,0.5)(4,1.6)(0.4,0.4)
};
\draw [red] (0,0) -- (1,1);
\end{tikzpicture}
\end{document}

相关内容