Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

Is there a good way to create a path in TikZ only some segments of which are stroked? I want to create the whole path in a single command so that it can be filled, but I also want to stroke some parts of the boundary of the filled region, but not all of them. The best solution I've thought of so far is to use edge operations in the middle of the path to do the stroking; for instance here is a green-filled square with one edge stroked:

\path[fill=green] (0,0) -- (1,0) edge (1,1) -- (1,1) -- (0,1) -- cycle;

This is a little better than

\path[fill=green] (0,0) -- (1,0) -- (1,1) -- (0,1) -- cycle;
\draw (1,0) -- (1,1);

but it still requires giving the command that draws the segment from (1,0) to (1,1) twice, which is annoying and error-prone if it's a more complicated command like a Bézier curve, and impossible if it's something like a circular arc that can't be drawn by a edge command (at least, not without writing a custom "to path"). Any suggestions?

share|improve this question
3  
Let's see if adding a bounty to this gets any progress; after all, it worked for the mysterious multiple postaction question! –  Loop Space Nov 15 '10 at 20:03
    
I can't remember seeing this question when it was posted, so the bounty did at least bring it up again. –  Caramdir Nov 15 '10 at 20:42
    
I should add that I wondered if some variant of the solution of the postaction question would work here. Specifying a postaction that split the path up into segments and then drew only part of it. Also, one of the "path replacing" decorations replaces pieces of paths by other things, so I'm sure that something is possible. –  Loop Space Nov 15 '10 at 21:38
    
@Andrew \pgfusepath fills and/or draws the current path and then destroys it (and AFAIK there can be only one path at any moment). So it's not hard to define a decoration that just draws a path and apply it to a subpath -- but it won't leave any path that can be filled. –  Grigory M Nov 15 '10 at 23:22
1  
I started a trend. Long may it continue... –  Seamus Nov 17 '10 at 0:05

4 Answers 4

I've found a new answer to this using the decorations library. We use the show path construction decoration to split the path up in to sections. We only render the pieces if a certain flag is set. The trick is to figure out a way to input the path in such a way that we can specify the flag switching without significantly disturbing the path. The method I settled on was to use a line of zero length as a toggle.

\documentclass{standalone}
\usepackage{etoolbox}
\usepackage{tikz}
\usetikzlibrary{decorations.pathreplacing}

\newbool{partpath}
\pgfkeys{/tikz/partial rendering/.style={
    postaction={
      decorate,
      decoration={
        show path construction,
        moveto code={
          \global\booltrue{partpath}
        },
        lineto code={
          \ifx\tikzinputsegmentfirst\tikzinputsegmentlast
            \ifbool{partpath}{\global\boolfalse{partpath}}{\global\booltrue{partpath}}
          \fi
          \ifbool{partpath}{
            \draw (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
          }{}
        },
        curveto code={
          \ifbool{partpath}{
            \draw (\tikzinputsegmentfirst) .. controls (\tikzinputsegmentsupporta) and (\tikzinputsegmentsupportb) .. (\tikzinputsegmentlast);
          }{}
        },
        closepath code={
          \ifbool{partpath}{
            \draw (\tikzinputsegmentfirst) -- (\tikzinputsegmentlast);
          }{}
        }
      }
    }
  }
}

\begin{document}

\begin{tikzpicture}
\path[fill=green,partial rendering]
 (0,0) -- (0,1) -- +(0,0) -- (1,1) -- +(0,0) -- (1,0) -- +(0,0) .. controls +(0,-1) and +(0,-1) .. (0,0);
\end{tikzpicture}

\end{document}

All those -- +(0,0)s are there to toggle the rendering when the path is drawn for the second time. (I tried using empty movetos: just +(0,0), but having those there messed up the fill routine.) Result:

enter image description here

share|improve this answer

This is a reworking of Jan's code to make it a little more TikZ-like. It still does the same thing: repeats the path, once as a fill and once as a draw, but with certain parts of the path removed for the draw stage. The main modification is that (hopefully) it now looks exactly like a standard TikZ command.

\documentclass{article}

\usepackage{tikz}
\makeatletter
\long\def\my@drawfill#1#2;{%
\@skipfalse
\fill[#1,draw=none] #2;
\@skiptrue
\draw[#1,fill=none] #2;
}

\newif\if@skip

\newcommand{\skipit}[1]{%
\if@skip
\else
#1
\fi
}

\newcommand{\drawfill}[1][]{%
  \my@drawfill{#1}}
\makeatother



\begin{document}
\begin{tikzpicture}
  \drawfill[fill=green,draw=blue,ultra thick] (0,0) -- (0,1) \skipit{--} (1,1) -- (1,0) \skipit{.. controls +(0,-1) and +(0,-1) ..} (0,0);
\end{tikzpicture}
\end{document}

This produces:

alt text

I'm sure that there are additional improvements to be made, which is one reason why I'm making this community wiki (the other being that it is really Jan's answer). In particular:

  1. I couldn't make the \skipit command take an optional argument and still work. I think that it doesn't get expanded properly before the genuine TikZ commands see it and they don't like having macros as part of their path specification.

  2. The assignment of key-value pairs is a bit of a hack: basically, we turn off the drawing on the fill command and turn off the filling on the draw command. It might be useful to be able to specify a set of keys that only get put on the draw command and a set for the fill command, so something like \drawfill[options for both, fillopt={options for fill}, drawopt={options for draw}] but I don't know enough (anything) about pgfkeys so don't have a clue how to go about that.

share|improve this answer
    
Can arcs also be skipped? –  Hotschke Jul 24 at 14:14

If I understand correctly, what you want to do is to only have to enter the path once. Would something like this work (it does not follow usual tikz syntax, but that should not be that hard to fix)?

\documentclass[]{article}
\usepackage{tikz}

\def\drawfill#1#2#3{{\def\skip{--}\fill[#1]#3;}{\def\skip{}\draw[#2]#3;}}
\begin{document}
\begin{tikzpicture}
   \drawfill{fill=green}{very thick}{(0,0) -- (0,1) \skip (1,1) -- (1,0)\skip (0,0)}
\end{tikzpicture}
\end{document}
share|improve this answer
    
I would modify it a little so that the \skip takes an argument which is the piece of the path to typeset. That way, you could say \skip{ .. controls +(1,0) and +(1,0) .. } and have it do the Right Thing. –  Loop Space Nov 16 '10 at 8:14
    
@Andrew: Even better, have an optional argument, defaulting to --. –  Jan Hlavacek Nov 16 '10 at 8:39
    
Nice. Being a perfectionist, I wish one could specify the \skip as part of an actual path, but it doesn't seem that TikZ likes to have macros expand to path components. So \draw (0,0) \mypath (1,0); doesn't work. –  Loop Space Nov 16 '10 at 12:17
1  
I'm beginning to think that this is the only reasonable way to do it. After experimenting a little, I find that it comes down to wanting to construct two different paths that are related. Once the paths are constructed internally as pgf paths (however that is represented), they can't be split up or have stuff applied to just a segment. So the only time to change Big Stuff is when the paths are defined, and that means that, TeXnically, you have to enter it twice. Of course, you don't actually have to enter it twice, but you have to convince TikZ that you did so - which is what this does. –  Loop Space Nov 16 '10 at 16:54
    
@Jan, I've reworked your answer to make it look a little more TikZ-y. Feel free to re-work it again! –  Loop Space Nov 16 '10 at 17:24

I'd like to be proven wrong, but I think this is impossible without drawing the path twice. Section 12.3.3 of the TikZ manual (v2.10) states:

Note that many options apply only to the path as a whole and cannot be scoped in this way. For example, it is not possible to scope the color of the path. See the explanations in the section on paths for more details.

And section 14.16:

When TikZ encounters and opening or a closing brace ({ or }) at some point where a path operation should come, it will open or close a scope. All options that can be applied “locally” will be scoped inside the scope. For example, if you apply a transformation like [xshift=1cm] inside the scoped area, the shifting only applies to the scope. On the other hand, an option like color=red does not have any effect inside a scope since it can only be applied to the path as a whole.

The problem seems to be that the dash pattern is applied to the path as a whole. Most of the time this is a good thing because it means that dashes work nicely across corners.

So I'd break the this up into several commands:

\begin{tikzpicture}
    \path[fill=green] (0,0) -- (1,0) -- (1,1) -- (0,1) -- cycle;
    \draw (1,1) -- (0,1) -- (0,0) -- (1,0);
    \draw[dashed] (1,0) -- (1,1);
\end{tikzpicture}

For more complicated paths, you might want to store some parts of the path into TeX macros.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.