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

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

• 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