有没有办法使用 TikZ 绘制满足
f( 0) = -1, f'( 0) = 0
f( 2) = 2, f'( 2) = -1
f(-2) = -1, f'(-2) = 1
当然,我可以找到满足给定条件的多项式,但我宁愿将条件提供给 TikZ 并让它完成工作。
答案1
正如 Peter 所说,您定义的曲线并不唯一。如果这不是问题,那么您可以使用控制点来生成曲线,方法是在您想要的点处给出切线规范。我试着稍微勾勒一下这个机制是如何工作的在这个答案中。
\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw[style=help lines] (-3,-3) grid[step=1cm] (3,3);
\node (O) at (0,0) {0};
\draw[thick] (-3,0) -- (3,0) (0,-3) -- (0,3);
\draw (-2,-1) node[below] {$f(-2)$}.. controls (-1,0) and (-1,-1) .. (0,-1) %
node[below right] {$f(0)$}.. controls ++(1,0) and (1,3) .. (2,2)node[below] {$f(2)$};
\end{tikzpicture}
\end{document}
您可以进一步调整控制点与定义点的距离(通过保持方向不变)来增加该控制点的贡献。
答案2
此解决方案与 @percusse 和 @Altermundus 的解决方案类似,控制点是使用给定点处的斜率计算的。此处提出的方法的一个小好处是,它可以扩展到三个以上的点,并且在每个点都可以指定一个唯一的值,<delta x>
以便可以更好地控制该点的行为
要开始曲线,请使用
\ExtrapolateStart{<delta x>}{<x>}{<y>}{<y'>}
以下所有点(最后一点除外)均指定为
\Extrapolate{<delta x>}{<x>}{<y>}{<y'>}
最后一个点用
\ExtrapolateEnd{<delta x>}{<x>}{<y>}{<y'>}
以下是各种设置的输出:
为了调试目的,控制点显示为蓝色,但如果不需要,可以注释掉该部分代码。
以下示例为 5 个点指定了x
、y
和值:y'
\ExtrapolateStart{\DeltaXStart}{-2}{0}{3.0}% delta x, x, y, y'
\Extrapolate{\DeltaXMiddle}{-1}{2}{1}
\Extrapolate{\DeltaXMiddle}{0}{1}{-2}
\Extrapolate{\DeltaXMiddle}{1}{-1}{-0.5}
\ExtrapolateEnd{\DeltaXEnd}{2}{1}{2.0}
笔记:
- 当我试图为 5 点解决方案绘制一个像样的图表时,我观察到线条中存在各种扭结,但现在我不再能够重现该问题。不知道这个问题是怎么回事神奇地已修复。我唯一能想到的可能是我提供的坐标和导数的值没有意义,因此导致了奇怪的图形,但这需要进一步调查。
代码:
\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{calc}
\newcommand{\ExtrapolateStart}[4]{%
($(#2,#3)-(#1, #1*#4)$) --%
(#2,#3) .. controls%
($(#2,#3)+(#1, #1*#4)$)%
}%
\newcommand{\Extrapolate}[4]{%
and%
($(#2,#3)-(#1, #1*#4)$) ..%
(#2,#3) .. controls%
($(#2,#3)+(#1, #1*#4)$)%
}%
\newcommand{\ExtrapolateEnd}[4]{%
and%
($(#2,#3)-(#1, #1*#4)$) ..%
(#2,#3) --%
($(#2,#3)+(#1, #1*#4)$)%
}%
%--------- For debugging use only
\newcommand{\ShowPoints}[4]{%
\filldraw [blue, opacity=0.5]%
(#2,#3) circle (2pt)%
($(#2,#3)-(#1, #1*#4)$) circle (1pt) --%
($(#2,#3)+(#1, #1*#4)$) circle (1pt)%
}%
\newcommand*{\AddLabel}[2][]{%
\node [draw,shape=rectangle,fill=white,#1] at (-1,2.5) {#2};
}
%
\begin{document}
\noindent
Example using 3 points where $x$, $f(x)$ and $f^\prime(x)$ are given for various $\Delta x$:
\bigskip\par\noindent
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.5}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;
% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXMiddle$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{1.0}%
\newcommand*{\DeltaXMiddle}{1.0}%
\newcommand*{\DeltaXEnd}{1.0}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;
% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXMiddle$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.4}%
\newcommand*{\DeltaXMiddle}{1.0}%
\newcommand*{\DeltaXEnd}{0.6}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{0}{-1}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-1}
}
\draw [ultra thick, red, smooth] \MyPath;
% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{0}{-1}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-1};
%
\AddLabel{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}
\newpage\noindent
Example using 5 points where $x$, $f(x)$ and $f^\prime(x)$ are given:
\bigskip
\par\noindent
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.3}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{0}{3.0}
\Extrapolate{\DeltaXMiddle}{-1}{2}{1}
\Extrapolate{\DeltaXMiddle}{0}{1}{-2}
\Extrapolate{\DeltaXMiddle}{1}{-1}{-0.5}
\ExtrapolateEnd{\DeltaXEnd}{2}{1}{2.0}
}
\draw [ultra thick, red, smooth] \MyPath;
% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{0}{3.0};
\ShowPoints{\DeltaXMiddle}{-1}{2}{1};
\ShowPoints{\DeltaXMiddle}{0}{1}{-2};
\ShowPoints{\DeltaXMiddle}{1}{-1}{-0.5};
\ShowPoints{\DeltaXEnd}{2}{1}{2.0};
%
\AddLabel[xshift=2cm]{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}
%
\begin{tikzpicture}
\newcommand*{\DeltaXStart}{0.5}%
\newcommand*{\DeltaXMiddle}{0.3}%
\newcommand*{\DeltaXEnd}{0.5}%
%
\draw [thin, gray, opacity=0.5] (-3,-3) grid (3,3);
\edef\MyPath{
\ExtrapolateStart{\DeltaXStart}{-2}{-1}{1}
\Extrapolate{\DeltaXMiddle}{-1}{-2}{0}
\Extrapolate{\DeltaXMiddle}{0}{1.5}{0}
\Extrapolate{\DeltaXMiddle}{1}{-2}{0}
\ExtrapolateEnd{\DeltaXEnd}{2}{2}{-2}
}
\draw [ultra thick, red, smooth] \MyPath;
% Following for debugging use only:
\ShowPoints{\DeltaXStart}{-2}{-1}{1};
\ShowPoints{\DeltaXMiddle}{-1}{-2}{0};
\ShowPoints{\DeltaXMiddle}{0}{1.5}{0};
\ShowPoints{\DeltaXMiddle}{1}{-2}{0};
\ShowPoints{\DeltaXEnd}{2}{2}{-2};
%
\AddLabel{$\Delta x = \DeltaXStart,\DeltaXMiddle,\DeltaXEnd$};
\end{tikzpicture}
\end{document}
答案3
我认为使用 MetaPost 或 Asymptote 绘制曲线更好。它们提供方向曲线说明符 ( {dir}
) 来获得适当的样条曲线。TikZ 不擅长插值和曲线拟合。MetaPost 和 Asymptote 使用的算法对于纯 TeX 绘图包来说太复杂了。
渐近线示例,
unitsize(2cm);
draw ( (-2,-1) {(1,1)} .. (0,-1) {(1,0)} .. (2,2) {(1,-1)} );
dot((0,-1) ^^ (2,2) ^^ (-2,1));
这里,{(1,1)}
后面的说明符(-2,1)
表示切线方向为(1,1),即(1,f'(x))。
并且可以很容易地定义一个函数来概括该方法:
unitsize(2cm);
// points should be sorted by x
guide fit_curve(pair[] points, real[] diffs)
{
guide g;
for (int i = 0; i < points.length; ++i)
g = g .. points[i] {(1,diffs[i])};
return g;
}
pair[] pts = { (-2,-1), (0,-1), (2,2) };
real[] diffs = { 1, 0, -1 };
draw (fit_curve(pts, diffs));
dot(pts);
答案4
更新我添加了一个宏来绘制由三个点定义的曲线以及这些点处的切线规范。该宏名为\expression
这里的多项式是f(x)= -(9/128)*x^5-(5/32)*x^4+(15/32)*x^3+x^2-1
我画了三个函数
1)橙色第一次尝试:
(a).. controls ((a)+(1,f'(a)) and ((b)+(-1,f'(b)) .. (b) .. controls ((b)+(1,f'(b)) and ((c)+(-1,f'(c)) .. (c)
2)蓝色:
(a).. controls ((a)+(1,f'(a)) and ((b)+(-1/2,f'(b)/2) .. (b) .. controls ((b)+(1,f'(b)) and ((c)+(-1/2,f'(c)/2) .. (c)
3)红色的多项式,我使用我的包 tkz-fct 来绘制最后一个函数,因为我可以轻松绘制切线。
如下图所示,结果还不错。可以制作宏来自动获取控制点。
图片
代码
\documentclass[11pt]{scrartcl}
\usepackage{tkz-fct}
\usetikzlibrary{calc}
\newcommand\expression[9]{
(#1,#2) .. controls ($(#1,#2)+(1,#3)$) and ($(#4,#5)+(-1,-#6)$) ..(#4,#5)
..controls ($(#4,#5)+(1,#6)$) and ($(#7,#8)+(-1,-#9)$)..(#7,#8)
}
\begin{document}
\begin{tikzpicture}
\tkzInit[xmin=-3,xmax=3,ymax=3,ymin=-3];
\tkzAxeXY
\draw[help lines](-2,-2) grid (3,3);
\draw[orange,line width=1pt] \expression {-2} {-1} {1}%
{0} {-1} {0}%
{2} {2} {-1};
\draw[blue,line width=1pt] (-2,-1) .. controls (-1,0) and (-0.5,-1) ..(0,-1)..controls(1,-1) and (1.5,2.5)..(2,2) ;
\tkzFct[color = red,domain =-2:2,line width=3pt,opacity=.5]{(-9./128)*x**5-(5./32)*x**4+(15./32)*x**3+x**2-1}
\begin{scope}[line width=.5pt]
\tkzDrawTangentLine[draw,color=green](-2)
\tkzDrawTangentLine[draw,color=green](0)
\tkzDrawTangentLine[draw,color=green](2)
\end{scope}
\end{tikzpicture}
\end{document}