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}


\pgfmathtruncatemacrois needed because\stageis 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\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\stageas anint, i.e. addint \stageat the start of theAlterEdgefunction, then you can use\stagedirectly. – Torbjørn T. May 06 '18 at 14:25int 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:29calclibrary 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\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\makeatletterand\makeatother(you can put it in your own .tex document). – Keith May 07 '18 at 02:33\makeatletter<the patch goes here>\makeatotherin the preamble will correct\tikz@cc@scan@rot. The\makeatletter...\makeatotheris needed when outside a package you want to access macros using the@symbol. – Kpym May 07 '18 at 05:01