如何让多米诺骨牌倒下?

如何让多米诺骨牌倒下?

如何用 LaTex 绘制如下图所示的多米诺骨牌倒下的场景?在此处输入图片描述

答案1

这是一个 Asymptote 版本,它使用半现实模型来计算倒下的多米诺骨牌,并给出矢量输出:

还有动画版本(一半——完整的 200 帧的 gif 太大,无法上传):

在此处输入图片描述

两个版本都需要一段时间来编译。

静态图像的代码(保存foo.asy并运行asy foo):

settings.outformat="pdf";
settings.render=0;
settings.prc=false;

import three;
unitsize(1cm);


currentprojection=perspective(
                  camera=(-10,0,5),
                  target=(48,2,-1),
                  angle=5,
                  autoadjust=false);

real height = 1;
real width = 0.5;
real depth = 0.08;
real separation = 0.5; //This is the interval from start to start.

surface domino = scale(depth, width, height) * shift(-1,-1/2,0) * unitcube;

triple labelposition = (-depth, 0, 0.7*height);

surface labelfor(string s) {
  static transform3 T = shift(labelposition)*rotate(90,Y)*rotate(90,Z)*scale3(0.016)*scale(-1,1,1);
  return T*surface(Label(s, p=fontsize(32)));
}


path receeding = scale(separation) * yscale(-1) * ( (0,-7) .. (7,0) .. (25,-6) .. (60,2) .. (95,-3) :: (140, -1) :: (200,0));


struct pointAndAngle {
  triple point;
  real angle;
}

pointAndAngle dominoPosition(int n) {
  pointAndAngle toreturn;
  real t = arctime(receeding, n*separation);
  toreturn.point = XYplane(point(receeding,t));
  pair tangent = dir(receeding, t);
  toreturn.angle = degrees(atan2(tangent.y, tangent.x));
  return toreturn;
}

transform3 dominoUpright(int n) {
  pointAndAngle info = dominoPosition(n);
  return shift(info.point) * rotate(info.angle, Z);
}

transform3 lyingDown(int n) {
  return dominoUpright(n) * rotate(90, Y);
}


int nDominoes = 200;

draw(dominoUpright(0) * domino, invisible);
draw(dominoUpright(nDominoes-1) * domino, invisible);
draw(lyingDown(nDominoes-1) * domino, invisible);

int nToppled = 8;

write("Computing image with " + (string)nToppled + " dominoes toppled.");

surface currentdomino;

for (int n = nDominoes-1; n >= 0; --n) {

  pointAndAngle position = dominoPosition(n);
  transform3 T = shift(position.point) * rotate(position.angle, Z);
  if (n <= nToppled-1) {
    if (currentdomino.s.length == 0) T = T * rotate(85,Y);
    else {
      path3 toisectleft = T * circle(c=(0, interp(-width/2, width/2, 1/3), 0),normal=Y,r=height);
      path3 toisectright = T* circle(c=(0, interp(-width/2, width/2, 2/3), 0),normal=Y,r=height);
      triple[] isectionpointsleft = intersectionpoints(toisectleft, currentdomino);
      triple[] isectionpointsright = intersectionpoints(toisectright, currentdomino);;
      real zleft=0, zright=0;
      for (triple pt : isectionpointsleft) {
    if (pt.z >= zleft) zleft = pt.z;
      }
      for (triple pt : isectionpointsright) {
    if (pt.z >= zright) zright = pt.z;
      }
      real angle1 = aSin(zleft / height);
      real angle2 = aSin(zright / height);
      if (angle1 > angle2) {
    real tmp = angle2;
    angle2 = angle1;
    angle1 = tmp;
      }
      real angle = interp(angle1, angle2, 2);
      T = T * rotate(90-angle, Y);
    }
  }
  currentdomino = T * domino;
  draw(currentdomino, gray(0.5));
  if (n < 80)
    draw( T*labelfor((string)(n+1)), emissive(white), meshpen=white );
}

动画版代码:

settings.outformat="gif";
settings.render=0;

import three;
import animation;
unitsize(1cm);


currentprojection=perspective(
                  camera=(-10,0,5),
                  target=(48,2,-1),
                  angle=5,
                  autoadjust=false);

real height = 1;
real width = 0.5;
real depth = 0.08;
real separation = 0.5; //This is the interval from start to start.

surface domino = scale(depth, width, height) * shift(-1,-1/2,0) * unitcube;
path3[] dominoOutline = scale(depth,width,height) * shift(-1,-1/2,0) * unitbox;

path receeding = scale(separation) * yscale(-1) * ( (0,-7) .. (7,0) .. (25,-6) .. (60,2) .. (95,-3) :: (140, -1) :: (200,0));


struct pointAndAngle {
  triple point;
  real angle;
}

pointAndAngle dominoPosition(int n) {
  pointAndAngle toreturn;
  real t = arctime(receeding, n*separation);
  toreturn.point = XYplane(point(receeding,t));
  pair tangent = dir(receeding, t);
  toreturn.angle = degrees(atan2(tangent.y, tangent.x));
  return toreturn;
}

transform3 dominoUpright(int n) {
  pointAndAngle info = dominoPosition(n);
  return shift(info.point) * rotate(info.angle, Z);
}

transform3 lyingDown(int n) {
  return dominoUpright(n) * rotate(90, Y);
}


int nDominoes = 200;
animation a;

draw(dominoUpright(0) * domino, invisible);
draw(dominoUpright(nDominoes-1) * domino, invisible);
draw(lyingDown(nDominoes-1) * domino, invisible);


for (int nToppled = 0; nToppled < 100; ++nToppled) {
  save();

  write("Computing image with " + (string)nToppled + " dominoes toppled.");

  surface currentdomino;

  for (int n = nDominoes-1; n >= 0; --n) {

    pointAndAngle position = dominoPosition(n);
    transform3 T = shift(position.point) * rotate(position.angle, Z);
    if (n <= nToppled) {
      if (currentdomino.s.length == 0) T = T * rotate(85,Y);
      else {
    path3 toisectleft = T * circle(c=(0, interp(-width/2, width/2, 1/3), 0),normal=Y,r=height);
    path3 toisectright = T* circle(c=(0, interp(-width/2, width/2, 2/3), 0),normal=Y,r=height);
    triple[] isectionpointsleft = intersectionpoints(toisectleft, currentdomino);
    triple[] isectionpointsright = intersectionpoints(toisectright, currentdomino);;
    real zleft=0, zright=0;
    for (triple pt : isectionpointsleft) {
      if (pt.z >= zleft) zleft = pt.z;
    }
    for (triple pt : isectionpointsright) {
      if (pt.z >= zright) zright = pt.z;
    }
    real angle1 = aSin(zleft / height);
    real angle2 = aSin(zright / height);
    if (angle1 > angle2) {
      real tmp = angle2;
      angle2 = angle1;
      angle1 = tmp;
    }
    real angle = interp(angle1, angle2, 2);
    T = T * rotate(90-angle, Y);
      }
    }
    currentdomino = T * domino;
    draw(currentdomino, emissive(white), meshpen=black + linewidth(1pt));
  }

  a.add();
  restore();

}

a.movie(delay=50);

答案2

由于我找不到原始代码,所以这不会产生与上面的评论中链接的完全相同的图像,但这是非常相同的想法并使用相同的原理。

直立多米诺骨牌的“波浪”排列相当简单。末端(或起点 - 取决于你如何看待它)的四张倒下的多米诺骨牌形成了一个令人不满意的大杂烩。

\documentclass[border=0.125cm]{standalone}
\usepackage{tikz}
\usetikzlibrary{calc}

\tikzset{3D/.cd,
  x/.store in=\xx, x=0,
  y/.store in=\yy, y=0,
  z/.store in=\zz, z=0
}

\tikzdeclarecoordinatesystem{3D}{%
  \tikzset{3D/.cd,#1}%
  \pgfpoint{sin(\yy)*(\xx)}{-((\xx)/75)^2+(\zz)/100*(\xx)}%
}

\begin{document}

\begin{tikzpicture}[line join=round, very thin]
\def\e{1260}
\foreach \x [evaluate={\i=mod(\x+90,360); \j=int((\i<180)*2-1); \t=3; \sc=\x/\e; \n=int((\e-\x)/15+5); \X=\x/\e;}] in {10,25,...,\e}{

   \path [shift={(3D cs:x=\x-\t,y={3*sin(\x-\t)})}, yslant=cos(\x)/5]
     (-\X/2, 0)   coordinate (A')  ( \X/2, 0)   coordinate (B')
     ( \X/2,2*\X) coordinate (C')  (-\X/2,2*\X) coordinate (D');

   \path [shift={(3D cs:x=\x,y=3*sin \x)}, yslant=cos(\x)/5]
     (-\X/2, 0)   coordinate (A) ( \X/2, 0)   coordinate (B)
     ( \X/2,2*\X) coordinate (C) (-\X/2,2*\X) coordinate (D);

   \filldraw [black!90] (B) -- (B') -- (C') -- (C)  -- cycle;
   \filldraw [black!80] (A) -- (A') -- (D') -- (D)  -- cycle;
   \filldraw [black!70] (C) -- (D)  -- (D') -- (C') -- cycle;
   \filldraw [black]    (A) -- (B)  -- (C)  -- (D)  -- cycle;

   \node [text=white, shift={($(C)!0.5!(D)$)}, anchor=north, yslant=cos(\x)/5, font=\sf, scale=\sc*1.5]
     at (0,-.33*\X) {\n};
}
%
\foreach \i [evaluate={\x=\i*30-10; \X=1; \n=int(5-\i);\xsl=\x/180}]in {1,...,4}{

  \path [shift={(3D cs:x=\x+\e,y=-3*\x/90)}, yslant=cos \e/5, xslant=\xsl]
    (-\X/2, 0)           coordinate (A) ( \X/2, 0)           coordinate (B)
    ( \X/2, \X*2-\x/360) coordinate (C) (-\X/2, \X*2-\x/360) coordinate (D);

  \path [shift={(3D cs:x=\x+\e,y=-3*\x/90)}, shift={(5/50,5/50-\i*2/50)}, yslant=cos \e/5, xslant=\xsl]
      (-\X/2, 0)           coordinate (A') ( \X/2, 0)           coordinate (B')
      ( \X/2, \X*2-\x/330) coordinate (C') (-\X/2, \X*2-\x/330) coordinate (D');

  \filldraw [black!70] (C) -- (D)  -- (D') -- (C') -- cycle;
  \filldraw [black!70] (A) -- (B)  -- (B') -- (A') -- cycle;
  \filldraw [black!90] (B) -- (B') -- (C') -- (C)  -- cycle;
  \filldraw [black]    (A) -- (B)  -- (C)  -- (D)  -- cycle;

 \node [text=white, shift={($(C)!0.5!(D)$)}, anchor=north, xslant=\xsl,yslant=cos \e/5, font=\sf, scale=1.5]
       at (0,-.33*\X) {\n};
}

\end{tikzpicture}

\end{document}

在此处输入图片描述

相关内容