Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I wanted to create a sequence of images that show a rhombus being folded. I'm able to do what I want, but the code is not very elegant. I wind up (needlessly?) repeating chunks of code to get the effect that I want.

Here's the code:

\documentclass{article}
\usepackage[svgnames]{xcolor}
\usepackage[margin=0.35in]{geometry}
\usepackage{tikz}
\usepackage{tkz-euclide}
\usetikzlibrary{calc}
\usetikzlibrary{decorations}
\tikzset{rhombus fill/.style={fill=blue!\number\numexpr30+#1\relax},
         my arrow/.style={decorate,decoration={markings,mark=at position 1 with {\arrow[scale=2.25]{stealth};}}}}
\def\mystep{6}
\edef\myangle{0}
\def\stepmyangle#1{\xdef\myangle{\number\numexpr\myangle+#1\relax}}
\pagestyle{empty}
\setlength{\parindent}{0pt}
\begin{document}


%-@-(4)------------------------------------------------------------------------------------
\newcounter{currentstep}
\foreach \x/\y in {0/0,10/30,12/60,14/0,10/0,9/0}
  {\stepmyangle{\x}%%
   \begin{tikzpicture}
      \coordinate (W) at (0,2in);
      \coordinate (Y) at (0,-2in);
      \coordinate (X) at (1.14in,0);
      \coordinate (Z) at (-1.14in,0);

      \fill[rhombus fill=0] (W) -- (Z) -- (Y);

      \ifnum\x>0\relax
        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in
              coordinate (A) at ($(W)+(\n3-\myangle:\n2)$);
        \fill[rhombus fill=\y] (W) -- (A) -- (Y);
        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in
              coordinate (A) at ($(W)+(\n3-\myangle:\n2)$)
              %% Here results in an error message:  "Missing \endcsname insert"
              %%[fill,rhombus fill=\y] (W) -- (A) -- (Y)
              [draw,postaction={my arrow}] (A) arc (\n3-\myangle:\n1:\n2)
              ;
      \else
        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in
              coordinate (A) at ($(W)+(\n3:\n2)$)
              ;
      \fi
      %% Here doesn't work because it blocks the arrows.
      %%[fill,rhombus fill=\y] (W) -- (A) -- (Y)

      \draw[gray!20] (W) -- (X) -- (Y);

      \draw (W)
        \foreach \x in {A,Y,Z} { -- (\x) } -- cycle;
      \draw[dashed] (W) -- (Y);

    \ifnum\thecurrentstep>2\relax\draw[black,fill=black!20] (W) -- (A) -- (Y) -- cycle;\fi

    \end{tikzpicture}%%
    \ifnum\thecurrentstep=2\relax
      \vspace{2ex}\par
    \else
      \ifnum\thecurrentstep<5\relax
        \hspace*{\fill}%%
      \fi
    \fi
    \global\stepcounter{currentstep}%%
  } 

\end{document}

which produces:

enter image description here

The first problem is that I'm repeating a block of code:

        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in ...;

It would be nice if I could set these values once and call on them later, from outside the path, when I need them. I've tried something like

        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in \edef\myarclength{\n2};

But that resulted in an error.

The second problem is that I can't seem to just write

        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in
              coordinate (A) at ($(W)+(\n3-\myangle:\n2)$)
              [fill,rhombus fill=\y] (W) -- (A) -- (Y)
              [draw,postaction={my arrow}] (A) arc (\n3-\myangle:\n1:\n2)
              ;

and save myself repasting the code. The last example results in an

Missing \endcsname insert

error message.

share|improve this question
    
The first problem needs \pgfextra{\edef…} (or \pgfextra \edef… \endpgfextra or [/utils/exec=\edef…]). The second problem is that you just use \y which misses its argument 1 or 2. And I think there will be a third problem: You can't fill some part of a path and draw another part. This will need to be done in two separate paths which means that you need either to save the let … in results in coordinates (if possible which it seems to be in your case) or to use \xdef in the first problem. –  Qrrbrbirlbel Sep 26 '13 at 21:53
    
I've overloaded '\y'. Yikes. I should change the '\foreach' loop to iterate over '\xx/\yy' instead. –  A.Ellett Sep 26 '13 at 22:59
    
@Qrrbrbirlbel Could you write up the \pgfextra portion of your comment as an answer? –  A.Ellett Sep 27 '13 at 0:39

1 Answer 1

up vote 4 down vote accepted

The second problem arises because you use \y as a \foreach variable as well as calc’s shorthand for the y values of \p coordinates.

Using \foreach \xValue/\yValue in … solves this when you are using rhombus fill=\yValue then.

The first problem is a little bit more complex. You can actually execute arbitrary TeX stuff on a path. You can either use

\path \pgfextra{<TeX stuff>};
\path \pgfextra<TeX stuff>\endpgfextra;

or

\path [/utils/exec=<TeX stuff>];
%   or /utils/exec={<TeX stuff>} if <TeX stuff> contains , or =

But a macro defined with \def/\edef would only be defined on that path and won’t survive the ;. You will need to use \gdef/\xdef here. (I don’t know where you want to use \myarclength so I can’t say whether there maybe another way to solve this.)

I see a third problem though:
You cannot draw part of a path and fill another part of a path (I dare you! The arc will also have a filling …).

In your case though you can save the coordinate (A) and draw the arc and use another part that \fills the triangle with the saved coordinate (A).

\path let
     \p1=($(Y)-(X)$),
     \n1={atan2(\y1,\x1)},
     \n2={veclen(\y1,\x1)},
     \p2=($(Y)-(Z)$),
     \n3={atan2(\y2,\x2)}
   in [draw, postaction=my arrow]
    ($(W)+(\n3-\myangle:\n2)$) coordinate (A) arc (\n3-\myangle:\n1:\n2);
\fill[rhombus fill=\yValue] (W) -- (A) -- (Y);

I realize this is not helpful because you first want to fill the area and then draw the arrow (where it would come in handy to save the \n values for later use).

Luckily, you can draw and fill parts of paths separately; actually, the edge path operator creates another path but we can use that:

\path let
      \p1=($(Y)-(X)$),
      \n1={atan2(\y1,\x1)},
      \n2={veclen(\y1,\x1)},
      \p2=($(Y)-(Z)$),
      \n3={atan2(\y2,\x2)}
    in 
      (W) edge [rhombus fill=\yValue,
                to path={--($(W)+(\n3-\myangle:\n2)$) coordinate (A)--(Y)}] ()
      (A) edge [draw, postaction=my arrow,
                to path={arc (\n3-\myangle:\n1:\n2)}]                       ();

Yes, we simply ignore \tikztotarget and directly specify our path in to path.

If you would take a look at the new loop header:

\foreach \xValue/\yValue[
  evaluate={\myangle=\myangle+\xValue},
  remember=\myangle as \myangle (initially 0),
  count=\currentstep from 0] in {0/0, 10/30, 12/60, 14/0, 10/0, 9/0}{

I have included your counters and auxiliary macros into \foreach options.

Furthermore, you maybe could try your diagram with one \matrix (so only one TikZ picture) but I guess this doesn’t belong to this question anymore.

Code

\documentclass{article}
\usepackage[svgnames]{xcolor}
\usepackage[margin=0.35in]{geometry}
\usepackage{tikz,tkz-euclide}
\usetikzlibrary{calc,decorations}
\tikzset{
  rhombus fill/.style={fill=blue!\number\numexpr30+#1\relax},
  my arrow/.style={
    decorate,
    decoration={markings,mark=at position 1 with {\arrow[scale=2.25]{stealth};}}}}
\begin{document}
\foreach \xValue/\yValue[
  evaluate={\myangle=\myangle+\xValue},
  remember=\myangle as \myangle (initially 0),
  count=\currentstep from 0] in {0/0, 10/30, 12/60, 14/0, 10/0, 9/0}{
   \begin{tikzpicture}
      \coordinate (W) at (0,2in);
      \coordinate (Y) at (0,-2in);
      \coordinate (X) at (1.14in,0);
      \coordinate (Z) at (-1.14in,0);

      \fill[rhombus fill=0] (W) -- (Z) -- (Y);

      \ifnum\xValue>0\relax
        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in 
              (W) edge [rhombus fill=\yValue,
                        to path={-- ($(W)+(\n3-\myangle:\n2)$) coordinate (A) -- (Y)}] ()
              (A) edge [draw, postaction=my arrow,
                        to path={arc (\n3-\myangle:\n1:\n2)}]                          ();
      \else
        \path let
                \p1=($(Y)-(X)$),
                \n1={atan2(\y1,\x1)},
                \n2={veclen(\y1,\x1)},
                \p2=($(Y)-(Z)$),
                \n3={atan2(\y2,\x2)}
              in coordinate (A) at ($(W)+(\n3:\n2)$);
      \fi

      \draw[gray!20] (W) -- (X) -- (Y);
      \draw (W) \foreach \x in {A,Y,Z} { -- (\x) } -- cycle;
      \draw[dashed] (W) -- (Y);

    \ifnum\currentstep>2\relax\draw[black,fill=black!20] (W) -- (A) -- (Y) -- cycle;\fi
    \end{tikzpicture}%
    \ifnum\currentstep=2\relax
      \vspace{2ex}\par
    \else
      \ifnum\currentstep<5\relax
        \hspace*{\fill}%%
      \fi
    \fi}
\end{document}
share|improve this answer
    
Thank you. I particularly like the part where you show how to include the counters in the \foreach options. –  A.Ellett Sep 27 '13 at 5:15

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.