任务
使用TikZ绘制任意曲线的切线,且曲线方程未知,无法直接从数学上推导出切线方程。
方法1:利用带sloped选项的node
node在TikZ绘图中占据重要地位,如图所示,node的默认形状是矩形(rectangle),其边界和内部分布有若干预先定义的锚点(anchor)。在默认情况下,node总是如图中一般“横平竖直”,故south west
和south east
之间的连线默认为水平线,south west
和north west
之间的连线默认为竖直线,其它锚点之间的连线亦以此类推。
在沿曲线布放node时,有时希望node能随曲线的形状而自动旋转,这时可以使用sloped
选项,官方文档对sloped
的描述如下:
This option causes the node to be rotated such that a horizontal line becomes a tangent to the curve.
不难看出,在使用sloped
选项时,node会随曲线的斜率而旋转,相应地,south west
和south east
之间原本的水平连线会自动转至与曲线切线平行,south west
和north west
之间原本的竖直连线会自动转至与曲线切线垂直。因此,如果在布放node时指定使用south west
锚点,使得该锚点恰好位于曲线上,那么就可直接由该锚点引出曲线的切线和法线(不限制必须使用south west
锚点,此处仅为举例)。
以下就是利用node绘制曲线切线的简单示例,为清楚显示node的位置、形状及旋转情况,这里使用fill
将node填充为可见图形,此操作与切线绘制无关:
\documentclass{standalone}
\usepackage{xcolor}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}
\draw (0, 0) .. controls (1, 0) and (1, 1) .. (2, 0.5) % 绘制曲线
node[
pos = 0.6, % 设置切点在曲线上的位置
sloped, % 设置node按曲线斜率旋转
anchor = south west, % node的锚点设为左下角,即以此为切点
fill opacity = 0.4, % 将node填充为灰色半透明图形,与切线绘制无关
fill = gray % 将node填充为灰色半透明图形,与切线绘制无关
] (N) {};
\draw[blue] (N.south west) -- (N.south east); % 绘制切线(蓝线)
\draw[red] (N.south west) -- (N.north west); % 绘制法线(红线)
\end{tikzpicture}
\end{document}
实际绘制切线时不必填充node,并且还可利用坐标运算指定切线的长度和起止点:
\documentclass{standalone}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{calc} % 用于坐标运算
\begin{document}
\begin{tikzpicture}
\draw (0, 0) .. controls (1, 0) and (1, 1) .. (2, 0.5) % 绘制曲线
node[
pos = 0.6, % 设置切点在曲线上的位置
sloped, % 设置node按曲线斜率旋转
anchor = south west % node的锚点设为左下角,即以此为切点
] (N) {};
% 绘制切线(蓝线),切线长0.9cm
\draw[blue] ($(N.south west)!0.3cm!180:(N.south east)$) -- ($(N.south west)!0.6cm!(N.south east)$);
%绘制法线(红线),法线长0.5cm
\draw[red] ($(N.south west)!0.5cm!180:(N.north west)$) -- (N.south west);
\end{tikzpicture}
\end{document}
方法2:利用decorations.markings库
利用decorations.markings库在曲线上添加marking时,TikZ首先会自动进行坐标系变换,将坐标系原点移至指定位置,并将x轴旋转至与曲线相切,然后在此创建一个临时性的scope,在其中执行marking的具体代码,官方文档对这一过程的描述如下:
If we use this code as a marking at position 2cm on a path, then the following happens: PGF determines the position on the path that is 2cm along the path. Then is translates the coordinate system to this position and rotates it such that the positive x-axis is tangent to the path. Then a protective scope is created, inside which the above code is executed – resulting in a little cross on the path.
基于上述原理,可以利用decorations.markings库绘制曲线的切线,基本思路是在曲线指定位置添加一个marking,这个marking并不需要绘制任何可见图形,其任务只是借助TikZ自动的坐标系变换确定切线和法线的方位,并且将这一信息保存下来供其它绘图指令使用。
需要注意的是,TikZ在向某一path添加marking时,会利用这个path作为输入参数来确定marking的位置,但在完成marking的绘制后,TikZ会自动删除path,只保留下marking。若希望保留path,则需要在绘制path时使用postaction = decorate
指令TikZ先绘制完path之后再添加marking,官方文档对于这一点的说明如下:
The
markings
decoration allows you to place one or more such markings on a path. The decoration destroys the input path (except in certain cases, detailed later), which means that it uses the path for determining positions on the path, but after the decoration is done this path is gone. You typically need to use apostaction
to add markings.
以下就是利用decorations.markings绘制曲线切线的具体示例:
\documentclass{standalone}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{decorations.markings} % 启用decorations.markings
\begin{document}
\begin{tikzpicture}[
tangent/.style = { % 定义tangent样式,参数#1是切点在曲线上的相对位置
decoration = { % 对path进行装饰(decorate)
markings, % 启用marking
mark = at position #1 % 在指定位置#1添加marking
with{ % marking的具体内容
% 定义(0, 0)为tangent point-xxx,即切点
\coordinate (tangent point-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0, 0);
% 定义(1, 0)为tangent unit vector-xxx,即单位切向量
\coordinate (tangent unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (1, 0);
% 定义(0, 1)为tangent orthogonal unit vector-xxx,即单位法向量
\coordinate (tangent orthogonal unit vector-\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}) at (0, 1);
}
},
postaction = decorate % 设置postaction,从而保留path
},
use tangent/.style = { % 定义use tangent样式,参数#1是切点的序号
shift = (tangent point-#1), % 以tangent point-xxx为原点
x = (tangent unit vector-#1), % 以tangent unit vector-xxx为x轴单位向量
y = (tangent orthogonal unit vector-#1) % 以tangent orthogonal unit vector-xxx为y轴单位向量
},
use tangent/.default = 1 % 定义use tangent样式默认参数为1,即第1个切点
]
\draw[ % 绘制曲线
tangent = 0.3, % 相对位置0.3处的切点(序号1)
tangent = 0.7 % 相对位置0.7处的切点(序号2)
] (0, 0) .. controls (1, 0) and (1, 1) .. (2, 0.5);
\draw[blue, use tangent] (-0.3, 0) -- (0.3, 0); % 1号切点处的切线
\draw[red, use tangent] (0, 0) -- (0, 0.3); % 1号切点处的法线
\draw[orange, use tangent = 2] (-0.3, 0) -- (0.3, 0); % 2号切点处的切线
\draw[teal, use tangent = 2] (0, 0) -- (0, -0.3); % 2号切点处的法线
\end{tikzpicture}
\end{document}
上面的示例中一共定义了两个样式(style),二者配套使用即可在一条曲线的多个位置处绘制多条切线、法线:
-
tangent
样式:参数是切点在曲线上的相对位置(0~1),功能是利用decorations.markings确定指定切点处的切线和法线方位,其中marking代码段的实际功能只是定义三个坐标点,\pgfkeysvalueof{/pgf/decoration/mark info/sequence number}
是同一条曲线上marking的序号; -
use tangent
样式:参数是同一条曲线上切点的序号(1、2、……),功能是利用tangent
样式定义的坐标点建立局部坐标系,其原点就是tangent = xx
给定的切点位置,x、y轴分别沿切点处的切线和法线方向。
方法3:利用割线逼近
切线与曲线只有一个交点,割线与曲线有两个交点,但当割线的两个交点足够接近时,割线就可近似视为切线。基于这种思想,对于给定的曲线,可以做两条彼此平行而又相互接近的辅助线,利用intersections库求出二者各自与曲线的交点,利用这两个交点就可以做出割线,将其近似视为切线。
以下就是利用割线逼近方法绘制曲线切线的具体示例:
\documentclass{standalone}
\usepackage{xcolor}
\usepackage{tikz}
\usetikzlibrary{intersections} % 用于求取交点
\usetikzlibrary{calc} % 用于坐标运算
\begin{document}
\begin{tikzpicture}
\draw[name path = curve] (0, 0) .. controls (1, 0) and (1, 1) .. (2, 0.5); % 绘制曲线
\draw[dashed, name path = main] (1.2, 0) -- (1.2, 1); % 定义并绘制辅助线1
\draw[dashed, name path = sub] ($(1.2, 0) + (0.5pt, 0)$) -- ($(1.2, 1) + (0.5pt, 0)$); % 定义并绘制辅助线2
% 求辅助线1与曲线的交点
\path[name intersections = {of = curve and main}];
\coordinate (a) at (intersection-1);
% 求辅助线2与曲线的交点
\path[name intersections = {of = curve and sub}];
\coordinate (b) at (intersection-1);
\draw[blue] ($(a)!-0.3cm!(b)$) -- ($(a)!0.3cm!(b)$); % 绘制切线(蓝色)
\draw[red] (a) -- ($(a)!0.5cm!270:(b)$); % 绘制法线(红色)
\end{tikzpicture}
\end{document}
上面的示例中定义并绘制了两条竖直辅助线main
和sub
,二者相距0.5pt(数值及单位可人为调整);若不需要显示辅助线,则可将上述代码中第10行和第11行的\draw
改为\path
并删去dashed
。
参考资料
- 使用 TikZ 绘制曲线的切线
- 采用微元思想在TikZ中绘制曲线指定点的切线
- How to draw tangent line of an arbitrary point on a path in TikZ
- How to draw tangent vectors and component vectors on a curve
- TiKZ 绘图初等数学的样本