# How is the interior of a path determined when reverse clipping?

I'm been playing around with [reverseclip] from How can I invert a 'clip' selection within TikZ?. It works quite well. When you apply [reverseclip] it seems to add another part to your path---a clockwise traversal of the current page. However, I am having trouble understanding how the interior of a multi-part path is determined. An example:

\documentclass{article}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[remember picture,overlay]
% A path that follows the edges of the current page, CW
\tikzstyle{reverseclip}=[insert path={(current page.north east) --
(current page.south east) --
(current page.south west) --
(current page.north west) --
(current page.north east)}
]
\coordinate (A) at (0,0);
\coordinate (B) at (1,0);
\coordinate (C) at (1,1);
\begin{pgfinterruptboundingbox}
\path [clip] (A) -- (B) -- (C) [reverseclip]; % good, CCW
%  \path [clip] (C) -- (B) -- (A) [reverseclip]; % bad, CW
\end{pgfinterruptboundingbox}
\fill[red!30] (A) circle (3cm);
%\fill[red!30,even odd rule] (A) circle (3cm); % does not make bad good
\end{tikzpicture}
\end{document}


So what happens is that I only get the desired reverse clipping if the orientation of my path is counter-clockwise. When I make the orientation clockwise, everything is undesirably filled.

In the documentation, Section 15.4.2 Graphic Parameters: Interior Rules, I learned about the nonzero and even odd rules. I rationalized this behavior by imagining the circle drawn in a CW fashion. Then, the first clip path is CCW and everything should work. With the nonzero rule, it made sense why a CW clip path would not clip anything. But then, I tried specifying the even odd rule, expecting that this would make the result independent of the orientation of the clip path. My expectations were wrong.

It seems that the interior rules are not applying in the way I understood they would.

1. When (reverse) clipping, how is the interior region determined?
2. How can I reverse a path saved via \pgfsyssoftpath@getcurrentpath{\mypath}?
3. Besides defining [reverseclipCW] and [reverseclipCCW], is there a way to make the reverseclip concept more robust to the orientation of paths?
4. What is the orientation of basic shapes (circle, rectangle, etc)? Clockwise?
-
Incidentally, for reversing a path I don't think there is an option currently built in to TikZ but I have some path manipulation code available at the TeX.SX launchpad repository which can do that (the spath library). Very, very definitely experimental code, though: bazaar.launchpad.net/~tex-sx/tex-sx/development/files –  Loop Space Oct 12 '12 at 13:39

## 1- How to use nonzero rule and even odd rule with paths

The current rule (nonzero rule or even odd rule) is applied operation by operation and path by path.

In the following picture:

• on the left column, all circles (inner and outer) are CCW (CCW=counter clockwise),
• on the right column, outer circles are CCW and inner circles are CW (CW=clockwise),
• on the first line, two paths are used to draw each pair of circles,
• on the second line and on the third line, a single path is used to draw each pair of circles,
• on the first line and on the second lines, filling uses the nonzero rule (implicitly).
• on the third line, filling uses the even odd rule.

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
\begin{tikzpicture}[every node/.style={align=flush left,font=\bfseries}]
\node at (0,3){Outer circle=CCW\\Inner circle=CCW};
\node at (4.5,3){Outer circle=CCW\\Inner circle=CW};
\begin{scope}[yshift=0mm,
every path/.style={draw=black,fill=cyan}]

\path (0,0) ++(0:2cm) arc (0:360:2cm);
\path (0,0) ++(0:1.8cm) arc (0:360:1.4cm);

\path (4.5,0) ++(0:2cm) arc (0:360:2cm);
\path (4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\node[right] at (7,0) {Each circle=one path};
\end{scope}
\begin{scope}[yshift=-4.5cm,
every path/.style={draw=black,fill=orange}]

\path (0,0) ++(0:2cm) arc (0:360:2cm)
(0,0) ++(0:1.8cm) arc (0:360:1.4cm);

\path (4.5,0) ++(0:2cm) arc (0:360:2cm)
(4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\node[right] at (7,0)
{Outer and inner circles=single path\\nonzero rule};
\end{scope}
\begin{scope}[yshift=-9cm,
even odd rule,every path/.style={draw=black,fill=lime}]

\path (0,0) ++(0:2cm) arc (0:360:2cm)
(0,0) ++(0:1.8cm) arc (0:360:1.4cm);

\path (4.5,0) ++(0:2cm) arc (0:360:2cm)
(4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\node[right] at (7,0)
{Outer and inner circles=single path\\even odd rule};
\end{scope}

\end{tikzpicture}
\end{document}


## 2- How to use nonzero rule and even odd rule with clipping paths

The even odd rule can't be applied directly to a clipping path (it's a bug).

In the following example, each line shows a filled rectangle. Each rectangle is clipped by four circles in a single path. The first line uses nonzero rule (implicitly), the second line uses a scope to apply even odd rule to the clipping path, and the third line uses the new option clip even odd rule suggested by Andrew Stacey:

\tikzset{clip even odd rule/.code={\pgfseteorule}} % Credit to Andrew Stacey


\documentclass{standalone}
\usepackage{tikz}
\tikzset{clip even odd rule/.code={\pgfseteorule}} % Credit to Andrew Stacey
\begin{document}
\begin{tikzpicture}[every node/.style={align=flush left,font=\bfseries}]
\node at (2.25,3) {All circles in a single clipping path};
\node at (0,2){Outer circle=CCW\\Inner circle=CCW};
\node at (4.5,2){Outer circle=CCW\\Inner circle=CW};
\begin{scope}[yshift=0mm]
\node[right] at (7,0) {clipping path with nonzero rule};

\clip
(0,0) circle (2cm)
(0,0) ++(0:1.8cm) arc (0:360:1.4cm)
(4.5,0) circle (2cm)
(4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\draw[fill=red] (-2,-1) rectangle (7,1);
\end{scope}

\begin{scope}[yshift=-4.5cm,even odd rule]
\node[right] at (7,0) {clipping path with even odd rule\\(via scope)};

\clip
(0,0) circle(2cm)
(0,0) ++(0:1.8cm) arc (0:360:1.4cm)
(4.5,0) circle(2cm)
(4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\draw[fill=orange] (-2,-1) rectangle (7,1);
\end{scope}

\begin{scope}[yshift=-9cm]
\node[right] at (7,0)
{clipping path with even odd rule\\(via new \texttt{clip even odd rule} option)};

\clip[clip even odd rule]
(0,0) circle(2cm)
(0,0) ++(0:1.8cm) arc (0:360:1.4cm)
(4.5,0) circle(2cm)
(4.5,0) ++(0:1.8cm) arc (360:0:1.4cm);

\draw[fill=lime] (-2,-1) rectangle (7,1);
\end{scope}
\end{tikzpicture}
\end{document}


Note on CCW and CW:

In a path:

• A circle (or ellipse) operation is always CCW.
• A rectangle operation can be CCW or CW depending on corners provided:

(a) rectangle (b) is equivalent to (a) -| (b) |- (a).

-
Do you know if TikZ/PGF plans to eventually support the even odd rule for clipping? It seems like this would resolve a lot of the "is my curve oriented properly" concerns when attempting to reverse clip. That, or having a simple way to reverse a path. –  Tom Oct 12 '12 at 4:04
@Tom my first Note is false ! I'll try to find an example to show how we can use the two rules with clip. But I do not have time to correct my answer today. –  Paul Gaborit Oct 12 '12 at 6:05
Aha. Good to know. So using \begin{scope}[even odd rule] \end{scope} around the pgfinterruptboundingbox environment and the \fill command seems to fix the issue I was having with my example. Looking forward to your updated answer. –  Tom Oct 12 '12 at 6:24
I just ran into the even odd rule issue with clips. The reason they "aren't supported" is because the even odd rule is a TikZ option and the clip path simply checks "Are any options set?" without particularly taking note of what they are. In my situation I couldn't use a scope because I wanted the clip to continue to have an effect so I defined a new key, clip even odd rule which invoked \pgfseteorule directly instead of delaying it to an option. I don't know if this introduces problems elsewhere but I doubt it. –  Loop Space Oct 12 '12 at 13:37
@AndrewStacey Thanks for your excellent suggestion ! –  Paul Gaborit Oct 12 '12 at 19:14