2

cropped output

It is probably some silly error on my part, but I am trying to understand why the three green triangles do not coincide exactly -- instead, they are unexpectedly shifted. (The original intent was to draw a snowflake-fractal-type picture, but I have altered my code in an attempt to debug this strange behavior. I apologize for not giving a more minimal example. My initial attempts to make it more minimal resulted in the strange behavior disappearing... but I want to retain this skeleton of recursive code.)

Scroll down to "above two lines commented out" to see the beginning of where the green triangle is constructed. This code should be repeated three times, drawing the exact same triangle three times, but there is unexpected shifting.

\documentclass[11pt]{article}
\RequirePackage{tikz}
\usepackage{xcolor}
\usepackage[margin=0.7in]{geometry}
\usetikzlibrary{calc,math}

\begin{document}
\begin{center}
\begin{tikzpicture}[x=5in,y=5in]
\tikzmath{
  % --------------------------
  % just test/debug code - (e.g., I need to remove redundant ``if'' structure testing \step
  % and properly orient triangles to point outward)
  % --------------------------
  let \c{1}=blue; let \c{2}=green; let \c{3}=red; let \c{4}=black;
  \maxstage=2; % the last stage (changed to 2 for debug)
  \numsteps=\maxstage-1; % number of levels
  % -------------------------------------------------------------------------
  % AlterEdge called recursively in final code
  % -------------------------------------------------------------------------
  function AlterEdge(\startx,\starty,\endx,\endy,\step,\stage){
    \step=\step-1; % stops drawing if step < 0
    \stage=\stage+1; % stage+1 starts at 2
    if (\step >= 0) then {
      coordinate \a, \b;
      %\a = (\startx pt,\starty pt);
      %\b = (\endx pt,\endy pt);
% above two lines commented out and replaced with two below for debug of strange behavior
      \a = (0,0);
      \b = (1,0);
      coordinate \mida, \midb, \midc;
      \mida = (\a)!1/3!(\b); \midb = (\a)!2/3!(\b); % the start and end of the dotted line
      \midc = (\mida)!1/2!60:(\b); % the third vertex of the new triangle jutting out
      %print(\mida); % debug - this makes shifting worse, but I thought I used absolute coordinates?
      { % print tikz commands
        \draw[color=black, dashed] (\mida)--(\midb);
        \pgfmathtruncatemacro\mytempresult{\stage} % not sure why this is necessary
        \draw[color=\c{\mytempresult}] (\mida)--(\midc)--(\midb);
      };
      if (\step > 0) then {
        AlterEdge(\ax,\ay,\midax,\miday,\step,\stage);
        AlterEdge(\midax,\miday,\midcx,\midcy,\step,\stage);
        AlterEdge(\midcx,\midcy,\midbx,\midby,\step,\stage);
        AlterEdge(\midbx,\midby,\bx,\by,\step,\stage);
      };
    };
  };
  % ----------------------
  % draw fractal
  % ----------------------
  coordinate \triangleA, \triangleB, \triangleC;
  \triangleA = (0,0); \triangleB = (1,0);
  \triangleC = (\triangleA)!1!60:(\triangleB);
  { % print tikz commands
    \draw[color=\c{1}] (\triangleA)--(\triangleC)--(\triangleB)--cycle;
  };
  AlterEdge(\triangleAx,\triangleAy,\triangleCx,\triangleCy,\numsteps,1);
  AlterEdge(\triangleCx,\triangleCy,\triangleBx,\triangleBy,\numsteps,1);
  AlterEdge(\triangleAx,\triangleAy,\triangleBx,\triangleBy,\numsteps,1);
}
\end{tikzpicture}
\end{center}
\end{document}

EDIT/UPDATE: I managed to make this work much better by inserting the code print(\hspace{-12.17pt});. The only problem is that this causes "()" to be printed at (0,0), as you can see below. Also, I'm not sure that this really answers the question, as I still don't see where the extra horizontal space is coming from. The updated code (with debug stuff removed) is below. (Before, it was a mess because of extra horizontal spaced added with each invocation of the function.)

\documentclass[11pt]{article}
\RequirePackage{tikz}
\usepackage{xcolor}
\usepackage[margin=0.7in]{geometry}
\usetikzlibrary{calc,math}

\begin{document}
\begin{center}
\begin{tikzpicture}[x=5in,y=5in]
\tikzmath{
  let \c{1}=blue; let \c{2}=green; let \c{3}=red; let \c{4}=black;
  \maxstage=4; % the last stage
  \numsteps=\maxstage-1; % number of levels
  % -------------------------------------------------------------------------
  % AlterEdge called recursively
  % -------------------------------------------------------------------------
  function AlterEdge(\startx,\starty,\endx,\endy,\step,\stage,\anglesign){
    int \step, \stage;
    \step=\step-1; % stops drawing if step < 0
    \stage=\stage+1; % stage+1 starts at 2
    %if (\step >= 0) then {
      coordinate \a, \b;
      \a = (\startx pt,\starty pt);
      \b = (\endx pt,\endy pt);
      coordinate \mida, \midb, \midc;
      \mida = (\a)!1/3!(\b); \midb = (\a)!2/3!(\b); % the start and end of the dotted line
      \midc = (\mida)!1/2!\anglesign*60:(\b); % the third vertex of the new triangle jutting out
      print(\hspace{-12.17pt}); % ???
      { % print tikz commands
        \draw[color=white, dashed] (\mida)--(\midb);
        \draw[color=\c{\stage}] (\mida)--(\midc)--(\midb);
      };
      if (\step > 0) then {
        AlterEdge(\ax,\ay,\midax,\miday,\step,\stage,\anglesign);
        AlterEdge(\midax,\miday,\midcx,\midcy,\step,\stage,\anglesign);
        AlterEdge(\midcx,\midcy,\midbx,\midby,\step,\stage,\anglesign);
        AlterEdge(\midbx,\midby,\bx,\by,\step,\stage,\anglesign);
      };
    %};
  };
  % ----------------------
  % draw snowflake fractal
  % ----------------------
  coordinate \triangleA, \triangleB, \triangleC;
  \triangleA = (0,0); \triangleB = (1,0);
  \triangleC = (\triangleA)!1!60:(\triangleB);
  { % print tikz commands
    \draw[color=\c{1}] (\triangleA)--(\triangleC)--(\triangleB)--cycle;
  };
  AlterEdge(\triangleAx,\triangleAy,\triangleCx,\triangleCy,\numsteps,1,1);
  AlterEdge(\triangleCx,\triangleCy,\triangleBx,\triangleBy,\numsteps,1,1);
  AlterEdge(\triangleAx,\triangleAy,\triangleBx,\triangleBy,\numsteps,1,-1); % bottom
}
\end{tikzpicture}
\end{center}
\end{document}

updated output, cropped

Keith
  • 21
  • 1
    What made the behavior disappear? – AML May 06 '18 at 13:47
  • @AML I think I commented out the function and three function calls at the bottom, and moved the code for the triangle to the bottom (outside the function), and then copy-and-pasted it so that it was repeated three times (what I thought would be the result of three function calls) – Keith May 06 '18 at 13:54
  • Unrelated: the \pgfmathtruncatemacro is needed because \stage is a float, not an integer, and e.g. \c{2.0} doesn't exist, while \c{2} does. – Torbjørn T. May 06 '18 at 14:08
  • @TorbjørnT. I eventually figured that out, but what puzzled me is that I couldn't figure out how to embed the conversion to integer inside the \c{} with the pgf math evaluation or print functions (they produced errors) - it seemed like I had no choice but to introduce \mytempresultas an intermediate step. – Keith May 06 '18 at 14:23
  • Declare \stage as an int, i.e. add int \stage at the start of the AlterEdge function, then you can use \stage directly. – Torbjørn T. May 06 '18 at 14:25
  • @TorbjørnT. Ah, thanks. I wasn't sure if that would work since it was in an argument to the function - in C++ you write int functionname(int arg1,..., but I didn't see similar examples in the manual, so I thought maybe function arguments could not have a declared type. – Keith May 06 '18 at 14:29
  • I've never really used this library, so I don't know the ins and outs of it. Hence, I just tried, and it seemed to work ... – Torbjørn T. May 06 '18 at 14:31
  • The problem comes from a known bug in calc library and the usage of \midc = (\mida)!1/2!\anglesign*60:(\b);. You can apply the Mark Wibrow's patch. – Kpym May 06 '18 at 17:10
  • @Kpym What is the easiest or best way to manually apply Mark Widbrow's patch in a MiKTeX distribution? I tried pasting the code from his answer above \begin{document}and below \usetikzlibrary{calc,math}, but it has no effect on my output. Shall I edit a TeX source file somewhere in the directory where MikTex installs packages? I tried searching the web, but all I get is info about how to manually install packages, whereas I want to patch one that is already installed. Thanks in advance. – Keith May 07 '18 at 02:09
  • @Kpym Never mind, I got it. For the benefit of anyone who has the same issue and is not familiar with arcane TeX commands: you have to enclose the patch in \makeatletter and \makeatother (you can put it in your own .tex document). – Keith May 07 '18 at 02:33
  • @Keith Exactly ! Putting the patch in between \makeatletter<the patch goes here>\makeatother in the preamble will correct \tikz@cc@scan@rot. The \makeatletter...\makeatother is needed when outside a package you want to access macros using the @ symbol. – Kpym May 07 '18 at 05:01

0 Answers0