TikZ doesn't allow you to apply the fill
and draw
commands to separate pieces of a path. The relevant part is in the macro \tikz@finish
. On a normal path, the drawing and filling is done by the piece:
\edef\tikz@temp{\noexpand\pgfusepath{%
\iftikz@mode@fill fill,\fi%
\iftikz@mode@draw draw,\fi%
\iftikz@mode@clip clip,\fi%
}}%
\tikz@temp%
In a node shape, the \backgroundpath
is the path used at this point. Now you don't want this: you want to be able to specify part of the \backgroundpath
as for draw
and part for fill
. So you have to specify two paths. Neither can actually be in place at the point where TikZ normally draws or fills since neither should have both actions applied. Normally, I'd recommend using the fact that a node shape can have several paths associated to it (\beforebackgroundpath
and so forth), but then you get into complications with passing styles to the different parts (in the TQFT package I use this to style the various parts of a cobordism, but there it is reasonable as there are different components. Here you just have one thing and splitting it is less user-friendly.).
So we just need to subvert the normal TikZ mechanism and replace it with our own. This means using the \backgroundpath
at definition time rather than leaving it to later. You do this already in the hackgenuspic
(and other) shapes. The only bit you don't do is use it conditionally.
At the time that the \backgroundpath
is processed, all of TikZ's path options have been processed. So TikZ knows the fill colour, the line width, the draw colour, and so forth. The only bit it doesn't know is whether or not to fill or draw the path. This is only figured out at the finish. (This is reasonable: the definition of the path can depend on the options, but doesn't usually depend on the action to be taken.) Fortunately, it isn't hard to find out what the desired actions are: we simply execute \tikz@mode
. This sets a few conditionals, namely \iftikz@mode@fill
and \iftikz@mode@draw
(there's also \iftikz@mode@clip
and a few more - for a truly robust solution we should consider them as well).
And from that, the rest is fairly easy. We execute \tikz@mode
and if we need to fill
the path, we define and fill the hole, and if we need to draw it, we define and draw the outer part. Given that we're using \tikz@mode
a little earlier than usual, I've put it inside a group. I suspect I'm just being overcautious on this, though, as TikZ is fairly careful about not making assumptions.
Here's my code. The shape is based on hackgenuspic
(but I renamed it to just genus
). It's quite likely that I've missed something - I haven't stress-tested it! Please let me know if it breaks. (If not, it would seem a reasonable addition to the TQFT package - what do you think?)
\documentclass[convert]{standalone}
%\documentclass{article}
\usepackage{tikz, pgf}
\usetikzlibrary{shapes}
\makeatletter
\pgfdeclareshape{genus}{
\anchor{center}{\pgfpointorigin}
\backgroundpath{
\begingroup
\tikz@mode
\iftikz@mode@fill
\pgfpathmoveto{\pgfqpoint{-0.78cm}{-.17cm}}
\pgfpathcurveto %
{\pgfpoint{-0.35cm}{-.44cm}}
{\pgfpoint{0.35cm}{-.44cm}}
{\pgfpoint{.78cm}{-0.17cm}}
\pgfpathmoveto{\pgfqpoint{-0.78cm}{-0.17cm}}
\pgfpathcurveto %
{\pgfpoint{-0.25cm}{.25cm}}
{\pgfpoint{.25cm}{.25cm}}
{\pgfpoint{0.78cm}{-0.17cm}}
\pgfusepath{fill}
\fi
\iftikz@mode@draw
\pgfpathmoveto{\pgfqpoint{-1cm}{0cm}}
\pgfpathcurveto %
{\pgfpoint{-0.5cm}{-.5cm}}
{\pgfpoint{0.5cm}{-.5cm}}
{\pgfpoint{1cm}{0cm}}
\pgfpathmoveto{\pgfqpoint{-0.75cm}{-0.15cm}}
\pgfpathcurveto %
{\pgfpoint{-0.25cm}{.25cm}}
{\pgfpoint{.25cm}{.25cm}}
{\pgfpoint{0.75cm}{-0.15cm}}
\pgfusepath{stroke}
\fi
\endgroup
}
}
\makeatother
\begin{document}
\begin{tikzpicture}[scale=.5]
\fill[color=black!10] (-6,3) arc (-180:0:2 cm and 1 cm)
(-2,3) .. controls +(-60:1) and +(-120:1) .. (2,3)
(2,3) arc (-180:0:2 cm and 1 cm)
(6,3) .. controls +(-90:2) and +(0:4) .. (0,-10) .. controls +(180:4) and +(-90:2) .. (-6,3);
\node [genus, scale=1, fill=green] at (0,0) {};
\node [genus, draw, scale=1, fill=orange] at (0,-2) {};
\node [genus, draw, ultra thick, scale=1, fill=green] at (0, -4) {};
\node [genus, draw, scale=.7] at (0, -6) {};
\node [genus, draw, dashed, scale=.5, fill=green] at (0, -8) {};
\draw (-4,3) ellipse (2 cm and 1 cm)
(-2,3) .. controls +(-60:1) and +(-120:1) .. (2,3)
(4,3) ellipse (2cm and 1cm)
(6,3) .. controls +(-90:2) and +(0:4) .. (0,-10) .. controls +(180:4) and +(-90:2) .. (-6,3);
\end{tikzpicture}
\end{document}
with result:
Best Answer
Is this OK?
Remove the
\clip
if you want the full ellipse.This was adapted from the shadings library example in the pgf manual.