I was idling thinking how one might go about this, when I came up with a very simple solution. I wouldn't be surprised to learn that this is what Illustrator does. Looking at the diagrams, it would seem that way.
My initial plan was to figure out some sort of decoration that would "shift" a path to the left or right, but that just seemed fraught with difficulties. But I couldn't think of a way to get TikZ to treat the two halves of a path in a different manner. Then I realised that there is such a way: clipping.
When TikZ clips against a path then the two sides of that path are treated in a different manner. So that can be used to get it to only draw one side. Sort of. You draw a path, but clip it against itself. Since the clipping path has no width, this means that half the path gets drawn. The "Sort of" is because the decision about which half depends on the region that is being enclosed, not the actual side of the path. This, I think, leads to the funny look on the Illustrator images in the question.
A general solution to this would involve a command to draw and clip in the same breath. That could be done with my spath
library (still in development, but available from the TeX-SX site on launchpad), and one would have to use the "reverse" clip method from somewhere around here for dealing with the other side. But to demonstrate the concept, we can just do it by hand. Here's the cube:
and here's the code:
\documentclass{article}
%\url{http://tex.stackexchange.com/q/29991/86}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[scale=5,line width=2mm]
\draw (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\draw (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\begin{scope}[yshift=-2cm,line width=4mm]
\begin{scope}
\clip (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\draw (0,0,0) -- (1,0,0) -- (1,1,0) -- (0,1,0) -- cycle;
\end{scope}
\begin{scope}
\clip (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (1,0,0) -- (1,0,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\end{scope}
\begin{scope}
\clip (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\draw (0,1,0) -- (0,1,-1) -- (1,1,-1) -- (1,1,0) -- cycle;
\end{scope}
\end{scope}
\end{tikzpicture}
\end{document}
Note the scopes to limit the clips, and the doubled line width, since we lose half of it in the clip.
It is evident that the movement of document elements between runs cause the problem. This movement is related to the ToC only being typeset on the second (and subsequent) runs. As such, using Bruno's suggestion in set minimum number of pages for TOC, we use the a priori knowledge that Chapter 1 starts on (absolute) page 4, say, to insert only the necessary number of blank pages via:
\foreach \n in {\value{page},...,4} {\vbox{}\newpage}
Since \value{page}
is relative to the location of \foreach
, both the first and subsequent compiles will insert only the necessary number of pages in order retain a fixed start position.
The reference to "absolute" page numbering actually just refers to the page number within the most recent numbering scheme. However, since the numbering scheme is not changed until the first chapter in the MWE, the reference is absolute.
Here is the complete MWE that compiles without error:
\def\NumberOfIterations{35}% ok if this is 34 or less
% Commenting out any one of these results in the file being generated
\def\AddWatermark{}% if commented works fine (tested to 1000)
\def\AddPhantomXAxis{}% if commented works fine (tested to 1000)
\def\AddTOC{}% if commented works fine (tested to 1000)
\def\UseStandardChapter{}% if commented, problem occurs at 42 (exactly where the second page of the TOC would start).
\documentclass{book}
\ifdefined\UseStandardChapter
\else
\renewcommand\chapter[1]{\section{#1}}
\fi
\usepackage{standalone}
\usepackage{pgfplots}
\usetikzlibrary{intersections}
\ifdefined\AddWatermark%% Problem on 2nd run if this is used
\usepackage[all,center]{background}%
\SetBgContents{\textsc{DRAFT}}%
\SetBgOpacity{0.2}%
\fi
%% Does not appear to be needed to reproduce problem
%% https://tex.stackexchange.com/questions/21421/is-there-a-way-to-clear-paths-previously-defined-with-name-path-global-in-tikz
%
%\makeatletter%
%\tikzset{%
% clear global paths/.style={%
% execute at end picture=\clear@global@paths,%
% name path global/.append code={%
% \ifx\global@paths\pgfutil@empty%
% \gdef\global@paths{##1}%
% \else%
% \xdef\global@paths{\global@paths,##1}%
% \fi%
% }%
% },%
% clear global paths now/.code={%
% \expandafter\global\expandafter\let\csname tikz@intersect@path@name@#1\endcsname=\relax%
% }%
%}%
%\let\global@paths=\pgfutil@empty%
%\def\clear@global@paths{%
% \edef\@temp{\noexpand\pgfkeys{/tikz/clear global paths now/.list={\global@paths}}}%
% \@temp%
% \global\let\global@paths=\pgfutil@empty%
% \global\let\tikz@intersect@namedpaths=\pgfutil@empty%
%}%
%\makeatother%
%%-----------------------------------------------------
\usepackage{filecontents}
\begin{filecontents}{MyFigure.tex}
\documentclass{article}
\usepackage{standalone}
\usepackage{pgfplots}
\usetikzlibrary{intersections}
\begin{document}
\ifdefined\AddPhantomXAxis
\newcommand*{\DrawPhantomXAxis}{%% Problem on 2nd run if this is used
% Draw a non-visible x-axis so that it can be
% used to determine intersections with x-axis
\draw [mark=none, draw=none, name path=XAxisPath]%
(current axis.left of origin) --%
(current axis.right of origin);%
}%
\else% Do absolutely nothing.
\newcommand*{\DrawPhantomXAxis}{}%
\fi%
\newcommand*{\ShowIntersectionWithXAxisPath}[2]{
\DrawPhantomXAxis{}% in case graphs did not have an x axis drawn
\fill
[name intersections={of=#1 and XAxisPath, name=i, total=\t}]
[brown, opacity=1, every node/.style={black, opacity=1}]
\foreach \s in {1,...,\t}{(i-\s) circle (3pt)
node [above left, red] {#2}};
}
\pgfmathdeclarefunction{GivenF}{1}{\pgfmathparse{exp(#1)-10^9}}
\begin{tikzpicture}
\begin{axis}[xmin=0.0, xmax=25, ymin=-1E9, ymax=1E9, xlabel=$x$, ylabel=$y$]
% Draw x-axis
\addplot [name path global=XAxisPath, gray,thin] coordinates{(0.0,0.0) (25,0.0)};
% Graph Function
\addplot[domain=0.0:21.42, samples=50, ultra thick, blue, name path global=GraphCurve]
({x},{GivenF(x)})
node [left,yshift=-3.5ex,blue] {$y = e^x -10^9$};
\ShowIntersectionWithXAxisPath{GraphCurve}{$x \approx 20.723$}
\end{axis}
\end{tikzpicture}
\end{document}
\end{filecontents}
%-----------------------------------------------------
\begin{document}
\ifdefined\AddTOC
\pagenumbering{roman}
\tableofcontents
% \pagenumbering{arabic}
\clearpage
\fi%
% Insert sufficient pages (only if necessary) to start
% first chapter on page 4. This leaves its position
% (and all subsequent ToC- and AUX-related content) fixed.
\foreach \n in {\value{page},...,4} {\typeout{test \thepage}\vbox{}\newpage}
\pagenumbering{arabic}% Only switch page numbering here, since this also sets page counter to 1
\chapter{First Chapter}
\foreach \x in {1,...,\NumberOfIterations}{
\section{Section \x}
\input{MyFigure.tex}
}
\end{document}
Best Answer
The paths are stored in macros called
\tikz@intersect@path@name@<name of path>
so to clear the paths, you need to blank that macro. The crudest, but simplest, way is to simply\let
it to\relax
after thetikzpicture
environment. A more fancy method would be to put in a new hook at the end of the picture which blanks the global paths defined in that picture. To do this, we need to store a list of the names of paths to blank by adding some code to the naming key, then we work through that list setting each path to\relax
in turn. Thus:Inside the
tikzpicture
,\global@paths
is a comma-separated list of the paths that have been globally defined. At the end of the picture, we work through this list blanking each one (as can be seen by the output of the\show
) and then finally blank our list ready for the next call.Update: Turns out that TikZ tries really hard to remember paths that have been globally named, to the extent that there is a macro that can reconstruct a named path. I'm having trouble seeing where it is defined, because wherever I place the
\show\tikz@intersect@namedpaths
inside thetikzpicture
environment then I get nothing, but if I put it straight afterwards then I get the code necessary to reconstruct the last named path (and only the last named one). So somewhere in the code to end thetikzpicture
, that macro gets set. I've added code to blank it to the above and that seems to fix the problem. Since it only remembers the last globally named path, I would guess that this isn't meant to happen so I don't feel too guilty about blanking it. But be warned that I haven't a clue what it's for, nor where it is getting set, so something else may break because of this (though I doubt it).