# Why do the three small triangles not coincide exactly? They are unexpectedly shifted (tikz math library recursive function calls) [duplicate]

This question already has an answer here:

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}


## marked as duplicate by Kpym tikz-pgf StackExchange.ready(function() { if (StackExchange.options.isMobile) return; $('.dupe-hammer-message-hover:not(.hover-bound)').each(function() { var$hover = $(this).addClass('hover-bound'),$msg = $hover.siblings('.dupe-hammer-message');$hover.hover( function() { $hover.showInfoMessage('', { messageElement:$msg.clone().show(), transient: false, position: { my: 'bottom left', at: 'top center', offsetTop: -7 }, dismissable: false, relativeToBody: true }); }, function() { StackExchange.helpers.removeMessages(); } ); }); }); May 6 '18 at 17:30

This question has been asked before and already has an answer. If those answers do not fully address your question, please ask a new question.

• What made the behavior disappear? – AML May 6 '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 6 '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 6 '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 6 '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 6 '18 at 14:25