绘制动画扭曲网格

绘制动画扭曲网格

我想画一些可以动画的包裹网格。我将问题分成两个问题,第一个比第二个更重要。对于下面的几个数学公式,我将使用符号“$$”(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)并调用将生成所有图形的\rtLua函数。plot_grid

anim.lua文件以全局变量定义开始:3 个系数数组,对应于您为波提出的总和。您可以添加更多系数,但 3 个数组必须具有相同的长度。然后zmax是着色,我们将进一步了解。

函数wave用于计算r,θ坐标和时间。它使用系数计算总和(我认为这部分在纯 LaTeX 中很难)并返回结果。

函数color用于对面进行着色,我们稍后会用到它。如果最大颜色是红色;如果0 < z < zmax颜色部分为红色;对于负值,颜色也为蓝色。

函数plot_grid有两个部分。首先,它计算网格每个节点的坐标。它创建两个空数组,并定义点的数量NrNt。在循环中,你可以看到r将从 0 变为 1,编号区间,theta从 -π 到 +π2 新台币间隔。然后对于每个(r,θ)配对过程如下:

  • 计算透视因子。通常网格会从-width+width-height到进行显示+height。但在你的问题中你想要一些透视,即顶部的网格小于底部的网格。在这里我引入参数shrink具有以下含义的参数:在顶部,网格大小乘以1-收缩在底部它乘以1+收缩
  • 计算X位置。该因子用于乘以网格的宽度和高度,以及我们将波的振幅(z)乘以一个您可以修改的比例因子。
  • 将结果存储在数组中

完成后,我们可以从上到下绘制面,因为这是透视图。这是第二个循环。我们从接近 0 的 θ 开始,这是较远的面。这些start,stop,step线也用于透视:如果 -π/2<θ<π/2,那么我们应该先绘制大半径并转到中心,在其他情况下,我们应该从中心转到边界。然后是核心:tex.print允许打印将在 LaTeX 文档中替换的输出。这是一个简单的\filldrawTikz 命令;字符串连接..在 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 进行编译。

在此处输入图片描述

相关内容