![绘制动画扭曲网格](https://linux22.com/image/333526/%E7%BB%98%E5%88%B6%E5%8A%A8%E7%94%BB%E6%89%AD%E6%9B%B2%E7%BD%91%E6%A0%BC.png)
我想画一些可以动画的包裹网格。我将问题分成两个问题,第一个比第二个更重要。对于下面的几个数学公式,我将使用符号“$$”(LaTeX 可识别)。我没有用 LaTeX 制作复杂图片的经验,更不用说制作动画了。
- 我的第一个目标是绘制一个具有指数递减正弦形式的网格:我们可以在扰动后可视化水面的波形(例如,我们将一块石头扔进湖中)。下面是一张显示我想如何绘制网格的图片:
我最初想用手在上面的表面添加网格,但这真的很困难,而且肯定不如真正的网格好。此外,我不知道如何在网格上绘制正弦波(从黑点开始,像球面波一样扩展)。这是另一张显示扭曲的绿色网格的图片(在网上找到的):
问题 1:有没有办法绘制一个像上图第一张图那样定向,并由给定函数 $f$ 扭曲的网格,如上图第二张图所示?
举一个具体的例子,我们可以选择 $f(r,\theta)=\sin(\theta)\sum_{k=1}^{n}\exp(-a_{k}r)\cos(b_{k}r)r^{k}$,其中 $n$ 为严格正整数,$a_{k}>0$ 且 $b_{k}$ 为一些实数,$r>0$ 为实数,$\theta$ 为 $0$ 和 $2\pi$ 之间的角度。
- 我的第二个目标是“简单地”为网格上的扰动扩展制作动画。我在这些漂亮的示例中看到了一些代码:如何绘制圆极化电磁波,我的第一个动画项目超时了在第一种情况下,我不知道如何在最终的 PDF 上添加动画(我有一些运动不同时间的图片,每页一张);在第二种情况下,LaTeX 无法编译代码!
问题2 :一旦绘制了扭曲的网格,如何在最终的 PDF 上为其制作动画?这需要哪些包?
我将非常感激任何帮助/建议。
答案1
以下是使用 LuaLaTeX 的解决方案,原因有二:
- 这个图中有很多复杂的公式,所以用真正的编程语言来解释会更容易
- 有大量的三角函数计算,Lua 比 TeX 更快
LaTeX 文件:
\documentclass{minimal}
\usepackage[a4paper,top=20mm,bottom=20mm,left=15mm,right=15mm]{geometry}
\usepackage{tikz}
\usepackage{animate}
\begin{document}
\directlua{require("anim.lua");}
\begin{center}
\begin{animateinline}[poster=first,controls,loop]{20}
\multiframe{20}{rt=0+0.05}{
\begin{tikzpicture}
\useasboundingbox (-8.5,-5.4) rectangle (8.5,3.1);
\directlua{plot_grid(8,4,0.3,\rt);}
\end{tikzpicture}
}
\end{animateinline}
\end{center}
\end{document}
文件anim.lua
(在同一目录中):
ak,bk,omegak={0.6,0.8},{10,20},{2*math.pi,4*math.pi} -- list of coefs
zmax=2
function wave(r,theta,t)
sum=0
for k=1,#ak do
sum=sum+math.exp(-ak[k]*r)*math.cos(bk[k]*r-omegak[k]*t)*r^k
end
return sum*math.sin(theta)
end
function color(z) -- color of facets
if z>0 then if z<zmax then col="red!"..(100*z/zmax); else col="red"; end -- red color for positive wave values
else if z>-zmax then col="blue!"..(-100*z/zmax); else col="blue"; end -- blue color for positive wave values
end
return col
end
function plot_grid(width,height,shrink,t)
local gridx,gridy={},{}
local Nr,Nt=20,10
local zscale=1
for i=0,Nr do
local r=i/Nr
gridx[i]={}
gridy[i]={}
for j=-Nt,Nt do
local theta=math.pi*j/Nt
local z=wave(r,theta,t)
local factor=1-shrink*math.cos(theta)
local x=r*width*factor*math.sin(theta)
local y=r*height*factor*math.cos(theta)+z*zscale*factor
gridx[i][j]=x
gridy[i][j]=y
end
end
-- grid faces, from top to bottom
for j=0,Nt-1 do
local theta=math.pi*j/Nt
local start,stop,step=0,Nr-1,1
if theta<math.pi/2 then start,stop,step=Nr-1,0,-1; end
for i=start,stop,step do
local r=i/Nr
-- print facet at (r,theta)
tex.print("\\filldraw[fill="..color(wave(r,theta,t)).."] ("..gridx[i][j]..","..gridy[i][j]..") -- ("..gridx[i+1][j]..","..gridy[i+1][j]..") -- ("..gridx[i+1][j+1]..","..gridy[i+1][j+1]..") -- ("..gridx[i][j+1]..","..gridy[i][j+1]..") -- cycle;")
-- print facet at (r,-theta)
tex.print("\\filldraw[fill="..color(wave(r,-theta,t)).."] ("..gridx[i][-j]..","..gridy[i][-j]..") -- ("..gridx[i+1][-j]..","..gridy[i+1][-j]..") -- ("..gridx[i+1][-j-1]..","..gridy[i+1][-j-1]..") -- ("..gridx[i][-j-1]..","..gridy[i][-j-1]..") -- cycle;")
end
end
end
你可以用它编译两次lualatex
,然后用 Acrobat Reader(唯一一个显示动画的阅读器)打开它。结果是:
解释:
首先,简单介绍一下 LuaLaTeX。它就像另一个 LaTeX 引擎,但您可以在其中添加 Lua 代码。Lua 是一种简单的脚本语言,具有与其他语言一样的函数、循环和条件语句。Lua 块例如包含在directlua{...}
语句中。当 LuaLaTeX 编译文件时,它们directlua{...}
会被执行并替换为其输出;即 LaTeX 代码;例如,这里的行\directlua{plot_grid(8,4,0.3,\rt);}
被替换为
\filldraw[fill=blue!-0] (0,2.66) -- (0,2.8) -- (-1.7667936522486,2.8044534789179) -- (-1.6784539696362,2.6194714601329) -- cycle;
\filldraw[fill=blue!0] (0,2.52) -- (0,2.66) -- (1.6784539696362,2.5462786901229) -- (1.5901142870238,2.3797166001964) -- cycle;
\filldraw[fill=blue!-0] (0,2.52) -- (0,2.66) -- (-1.6784539696362,2.6194714601329) -- (-1.5901142870238,2.5141519632038) -- cycle;
....
即 Tikz 命令。然后生成一个纯 LaTeX 文档,并编译为另一个 LaTeX 文档。
总结一下:LuaLaTeX 文档是普通的 LaTeX 文档,但是包含一些 Lua 块,可以代替您生成许多 LaTeX 代码。
然后关于文件,从 LaTeX 开始:它非常简单;\animateinline
定义一个有 20 帧和循环的动画,并以 0.05 的步长从 0 开始\multiframe
迭代时间(实数变量\rt
),并执行 20 次,因此将具有值:0,0.05,0.10,...,0.95。然后我们定义一个带有边界框的 tikzpicture(感谢 AlexG)并调用将生成所有图形的\rt
Lua函数。plot_grid
该anim.lua
文件以全局变量定义开始:3 个系数数组,对应于您为波提出的总和。您可以添加更多系数,但 3 个数组必须具有相同的长度。然后zmax
是着色,我们将进一步了解。
函数wave
用于计算r,θ坐标和吨时间。它使用系数计算总和(我认为这部分在纯 LaTeX 中很难)并返回结果。
函数color
用于对面进行着色,我们稍后会用到它。如果最大颜色是红色;如果0 < z < zmax颜色部分为红色;对于负值,颜色也为蓝色。
函数plot_grid
有两个部分。首先,它计算网格每个节点的坐标。它创建两个空数组,并定义点的数量Nr
和Nt
。在循环中,你可以看到r
将从 0 变为 1,编号区间,theta
从 -π 到 +π2 新台币间隔。然后对于每个(r,θ)配对过程如下:
- 计算透视因子。通常网格会从
-width
到+width
和-height
到进行显示+height
。但在你的问题中你想要一些透视,即顶部的网格小于底部的网格。在这里我引入参数shrink
具有以下含义的参数:在顶部,网格大小乘以1-收缩在底部它乘以1+收缩。 - 计算X和是位置。该因子用于乘以网格的宽度和高度,以及是我们将波的振幅(
z
)乘以一个您可以修改的比例因子。 - 将结果存储在数组中
完成后,我们可以从上到下绘制面,因为这是透视图。这是第二个循环。我们从接近 0 的 θ 开始,这是较远的面。这些start,stop,step
线也用于透视:如果 -π/2<θ<π/2,那么我们应该先绘制大半径并转到中心,在其他情况下,我们应该从中心转到边界。然后是核心:tex.print
允许打印将在 LaTeX 文档中替换的输出。这是一个简单的\filldraw
Tikz 命令;字符串连接..
在 Lua 中。您还可以注意到我们同时绘制 (r,θ) 和 (r,-θ) 面。
总结:第一次尝试 LuaLaTeX 时我很害怕,但从那时起,我就开始喜欢它了。当你做科学图表或模拟时,它真的很有用。在我的 LaTeX 文档中使用 Lua,我可以绘制复杂的图、绘制隐式图、求解 ODE、积分函数,然后在我的 LaTeX 文档中进行整个模拟。学习一门新的(简单的)编程语言是必要的,但 Lua+LaTeX 的威力是惊人的!
答案2
您可以从以下代码开始...
确保每张图片都在自己的环境中......
\PassOptionsToPackage{pst,dvipsnames,table,svgnames,xcdraw,showerrors}{xcolor}
\documentclass[multi,crop,pstricks,border=0.15cm]{standalone}
\standaloneenv{my}
\usepackage[T1]{fontenc} % Use 8-bit encoding that has 256 glyphs
\usepackage[ansinew]{inputenc} % Uses the utf8 input encoding
\usepackage{graphics}
\usepackage{xcolor}
\usepackage{pst-perspective}
\usepackage{auto-pst-pdf}
\begin{document}
\begin{my}
\begin{pspicture}[showgrid=false](3,2)(11,6)
% \psgrid
\rput(7,4){\psCircleTS[fillstyle=solid,fillcolor=blue,opacity=0.5]{2}}
\rput(7,4){\psCircleTS[fillstyle=solid,fillcolor=blue,opacity=0.5]{2.5}}
\rput(7,4){\psCircleTS[fillstyle=solid,fillcolor=blue,opacity=0.5]{3.0}}
\rput(7,4){\psCircleTS[fillstyle=solid,fillcolor=blue,opacity=0.5]{3.5}}
\end{pspicture}
\end{my}
\end{document}
当然还有很多工作要做,很可能您需要更多的 pstricks 包...并且建议,如果您使用重复的 eps 图形,则使用 \usepackage{xsavebox} 来减小文件大小...
您可以使用 pdflatex 或 latex - dvips - ps2pdf 进行编译。