逐步修改图形的环境

逐步修改图形的环境

我想要一个可以产生以下两个示例的环境,其中图片不是动画。

我希望环境能够自动处理数字的数量。

这适用于显示逐步解释的图形,例如一个有限马尔可夫链的简化。从 LaTeX 的角度来看,我只想输入:

\begin{stepByStep}
    \step Fig.1
    \step Fig.2
    \step Fig.3
    \step Fig.4
\end{stepByStep}

\begin{stepByStep}
    \step Fig.1
    \step Fig.2
    \step Fig.3
    \step Fig.4
    \step Fig.5
    \step Fig.6
    \step Fig.7
\end{stepByStep}

在此处输入图片描述

答案1

以下是可以为您完成此操作的解决方案,但语法略有修改。您一次指定两个步骤,其中一个可以为空白:

\begin{stepByStep}
    \step{\FigA}{\FigB}
    \step{}{\FigD}
\end{stepByStep}

\begin{stepByStep}
    \step{\FigA}{\FigB}
    \step{\FigC}{\FigD}
    \step{\FigD}{}
\end{stepByStep}

它将各个图形放置在tabular环境中,并用于\tikzmark在适当的点之间绘制箭头。因此,它应该能够处理不同高度和长度的图形,但我没有进行广泛的测试。下面是最后一个案例的输出。

在此处输入图片描述

定制:

定义了一些参数以便您轻松进行调整:

  1. \WidthOfArrow指定水平箭头尺寸(最小值)
  2. \HeightOfArrow指定垂直箭头的大小
  3. \ArrowImageSep指定箭头和图像之间的空间

笔记:

  • 这需要运行两次。第一次用于确定线条的起点和终点,第二次用于绘制线条。
  • 不进行检查以确保只有最后一行具有空白参数。
  • 不进行任何检查以确保只有适当的参数可以为空。例如,如果第二行是最后一行,则只有第一个参数可以为空。但是如果第三行是最后一行,则只有第二个参数可以为空。

参考:

进一步增强:

  • 垂直箭头有点太长,这是个小问题。我通过设置添加了一个临时解决方案来修复此问题\VerticalArrowAdjust,但这不是必需的,或者至少应该能够计算出精确的值。

  • 如果此语法不适合您,您可以对其进行调整以获得您想要的精确语法。

代码:

\documentclass{article}
\usepackage[demo]{graphicx}% Add [demo] option if don't have figures
\usepackage{adjustbox}
\usepackage{etoolbox}

\usepackage{tikz}
\usetikzlibrary{calc}

\newcommand*{\WidthOfArrow}{1.5cm}%  Horizontal Arrow size (minimum)
\newcommand*{\HeightOfArrow}{1.5cm}% Vertical Arrow size
\newcommand*{\ArrowImageSep}{1.5pt}% Space between arrow and image
\newcommand*{\VerticalArrowAdjust}{8.5pt}% Kludge

%------------------ Should not need to adjust below this
\newlength{\VerticalSep}%
\pgfmathsetlength{\VerticalSep}{\HeightOfArrow + 2*\ArrowImageSep}%
\newtoggle{FirstRow}% No vertical arrow in this case

% We need to have the sizes of up to four pictures
\newlength{\HeightA}%
\newlength{\HeightB}%
\newlength{\HeightC}%
\newlength{\HeightD}%
\newlength{\WidthA}%
\newlength{\WidthB}%
\newlength{\WidthC}%
\newlength{\WidthD}%
\newcommand{\tikzmark}[1]{\tikz[overlay,remember picture] \node (#1) {};}

% https://tex.stackexchange.com/questions/46418/measure-and-retain-lengths-between-tabular-rows
\makeatletter
\newcommand*{\MeasureAndPlaceFigure}[3]{%#=1Fig, #2=Width, #3=Length
    \setbox\z@\hbox{#1}%
    \global\csname#2\endcsname\wd\z@%
    \global\csname#3\endcsname\ht\z@%
    \adjustbox{width=!,height=!,valign=m}{\box\z@}%
}%

\newcommand*{\@stepAB}[2]{%  A --> B
    \MeasureAndPlaceFigure{#1}{WidthA}{HeightA}%
    \tikzmark{rightA}&&\tikzmark{leftB}%
    \MeasureAndPlaceFigure{#2}{WidthB}{HeightB}%
    \\[\VerticalSep]% Skip to next line
    %
    \ifdim\HeightB=0pt% Need both images to have horizontal arrrow
    \else%
        \DrawHorizontalArrow{rightA}{leftB}%
    \fi%
    %
    \iftoggle{FirstRow}{}{%  Vertical arrow only if NOT first row
        \DrawVerticalArrow{rightC}{-\WidthC}{\HeightC}{rightA}{-\WidthA}{\HeightA}%
    }%
    \global\togglefalse{FirstRow}%
    \let\step\@stepCD% Next invocation of \step will call stepCD
}%

\newcommand*{\@stepCD}[2]{%  C <-- D
    \MeasureAndPlaceFigure{#1}{WidthC}{HeightC}%
    \tikzmark{rightC}&&\tikzmark{leftD}%
    \MeasureAndPlaceFigure{#2}{WidthD}{HeightD}%
    \\[\VerticalSep]% Skip to next line
    \ifdim\HeightC=0pt\relax% Need both images to have horizontal arrrow
    \else%
        \DrawHorizontalArrow{leftD}{rightC}%
    \fi%
    \iftoggle{FirstRow}{}{%  Vertical arrow only if NOT first row
        \DrawVerticalArrow{leftB}{\WidthB}{\HeightB}{leftD}{\WidthD}{\HeightD}%
    }%
    \global\togglefalse{FirstRow}%
    \let\step\@stepAB% Next invocation of \step will call stepAB
}%

\let\step\@stepAB% First invocation of \step will call \@stepAB
\makeatother

\newcounter{CurrentSate}%
\newenvironment{stepByStep}{%
    \setcounter{CurrentSate}{0}%
    \global\toggletrue{FirstRow}% No vertical arrow until 2nd row
    \begin{tabular}{@{}c@{} p{\WidthOfArrow} @{}c@{}}%
}{%
    \end{tabular}%
}%

\newcommand*{\DrawHorizontalArrow}[3][]{%
    \tikz[overlay,remember picture]{%
        \draw[ultra thick, ->, red, 
            shorten <=\ArrowImageSep, shorten >=\ArrowImageSep, #1]
            ($(#2)$) -- 
            ($(#3)$);
    }%
}%

\newcommand*{\DrawVerticalArrow}[7][]{%
    \tikz[overlay,remember picture]{%
        \draw[ultra thick, ->, red,
            shorten <=\ArrowImageSep, shorten >=\ArrowImageSep, #1]
            ($(#2)+0.5*(#3,-#4+\VerticalArrowAdjust)$) --
            ($(#5)+0.5*(#6,#7+\VerticalArrowAdjust)$);
    }%
}%

\def\FigA{\includegraphics[width=2.0cm,height=1.0cm]{images/EiffelWide}}%
\def\FigB{\includegraphics[width=1.5cm,height=3.0cm]{images/EiffelTall}}%
\def\FigC{\includegraphics[width=3.0cm,height=1.5cm]{images/EiffelWide}}%
\def\FigD{\includegraphics[width=2.0cm,height=4.0cm]{images/EiffelTall}}%

\begin{document}
\section*{Test 1}
\begin{stepByStep}
    \step{\FigA}{\FigB}
    \step{\FigC}{\FigD}
\end{stepByStep}
%
\section*{Test 2}
\begin{stepByStep}
    \step{\FigA}{\FigB}
    \step{}{\FigD}
\end{stepByStep}
%
\section*{Test 3}
\begin{stepByStep}
    \step{\FigA}{\FigB}
    \step{\FigC}{\FigA}
    \step{\FigD}{}
\end{stepByStep}
\end{document}

相关内容