5

How can the red vertical arrows drawn in this TikZ picture be clipped to the outside of the curvy region X, that is, so that only the portion of the arrows below the region's boundary are actually drawn? (I know how to clip them to the inside.)

Is the invclip style from https://tex.stackexchange.com/a/59168/13492 useful here? So far, I don't understand exactly how to use it. Or something else?

\documentclass[tikz,border=3mm]{standalone}

\begin{document}

\begin{tikzpicture}
    % Curvy region X
    \coordinate (X1) at (0,0);
    \coordinate (X2) at (2,2);
    \coordinate (X3) at (4,1);
    \coordinate (X4) at (3,-1);
    \coordinate (X5) at (1,-1.5);
    \coordinate (X6) at (0,0);
    \path[save path=\pathX] (X1) to[out=90,in=180] (X2) to[out=0,in=90] (X3) to[out=270,in=90] (X4) to[out=270,in=0] (X5) to[out=180,in=270] (X6);
    
    \filldraw[use path=\pathX,thick,blue,fill=blue!20] ;

    % Some vertical arrows -- how clip to EXTERIOR of region X??    
    \def\somex{0.75, 1.5, 2.5, 3.5}
    \foreach \x in \somex {
        \draw[red,thick][->] (\x,0) -- (\x,-2);
     }
\end{tikzpicture}

\end{document} 

How clip arrows to outside of the shaded region?

I want a method that works even if the region X is not actually filled.

In the "real" application, I'll want the arrows to begin not at the boundary of the region, but at a certain specified distance below the boundary. If I knew how to clip to the exterior of a region, that would, I think, be easy to do: temporarily shift the curved path vertically downward by that distance, clip to the exterior of that shifted region.

5
  • Just color the blue area last: \filldraw[use path=\pathX,thick,blue,fill=blue!20];
    – AndréC
    Commented May 27 at 19:41
  • @AndréC: Yes, that will work, but i'd like a general method that works, for example, if the curve is not filled in. I've edited the question to emphasize that.
    – murray
    Commented May 27 at 19:50
  • 2
    Yes, invclip is exactly what you want here. Commented May 27 at 20:26
  • @AndrewStacey: But how does one apply invclip here? As I said, I just don't understand how.
    – murray
    Commented May 27 at 20:56
  • @murray It would be useful to provide details as to what you have tried with invclip and what hasn't worked. Commented May 28 at 10:14

2 Answers 2

8

To add a little detail to cfr's answer, the reason why invclip and use path don't work well together is because of how use path works. What it does is simple: it overwrites the current path with the saved path. What is more important is when it does this: it does it at the very end of the path construction (via \tikz@addmode). This conflicts with invclip, since invclip works by adding something to the path.

So in \clip[use path=\pathX, invclip]; then actually the use path=\pathX overwrites the rectangle added by invclip, thus rendering it null and void.

There are a couple of ways around this. One is to use my spath3 library which has a more sophisticated alternative to use path (spath/use) which splices the saved path into the existing path, rather than overwriting it, and does it at the moment of invocation, thus meaning that extra parts to the path can be added or manipulated afterwards. This would also work better with your eventual goal of shifting the path since spath3 can do all sorts of modifications to a path between defining it and using it.

A slightly more mundane solution is to modify the use path code (or, rather, define an alternative) to set the current path at the moment of invocation rather than waiting until the end.

\makeatletter
\tikzset{
  use path now/.code={%
    \pgfsyssoftpath@setcurrentpath#1%
  }
}
\makeatother

Here's both versions in a single document. The first uses use path now, the second spath3 (as a bonus, I've shifted the path by 5pt downwards to create that extra space):

\documentclass[tikz,border=3mm]{standalone}
%\url{https://tex.stackexchange.com/q/719042/86}

\usetikzlibrary{spath3} % <-- only needed for spath3

\tikzset{
  invclip/.style={
    clip even odd rule,
    overlay,
    insert path={
      [reset cm]
      (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)
    },
  },
  clip even odd rule/.code={%
    \pgfseteorule
  }
}

% Not needed with spath3
\makeatletter
\tikzset{
  use path now/.code={%
    \pgfsyssoftpath@setcurrentpath#1%
  }
}
\makeatother

\begin{document}

\begin{tikzpicture}
    % Curvy region X
    \coordinate (X1) at (0,0);
    \coordinate (X2) at (2,2);
    \coordinate (X3) at (4,1);
    \coordinate (X4) at (3,-1);
    \coordinate (X5) at (1,-1.5);
    \coordinate (X6) at (0,0);
\path[save path=\pathX] (X1) to[out=90,in=180] (X2) to[out=0,in=90] (X3) to[out=270,in=90] (X4) to[out=270,in=0] (X5) to[out=180,in=270] (X6);
    
    \filldraw[use path=\pathX,thick,blue,fill=blue!20];

\begin{scope}
\clip[use path now=\pathX, invclip];
    % Some vertical arrows -- how clip to EXTERIOR of region X??    
    \def\somex{0.75, 1.5, 2.5, 3.5}
    \foreach \x in \somex {
        \draw[red,thick][->] (\x,0) -- (\x,-2);
}
\end{scope}
\end{tikzpicture}

\begin{tikzpicture}
    % Curvy region X
    \coordinate (X1) at (0,0);
    \coordinate (X2) at (2,2);
    \coordinate (X3) at (4,1);
    \coordinate (X4) at (3,-1);
    \coordinate (X5) at (1,-1.5);
    \coordinate (X6) at (0,0);
\path[spath/save=pathX] (X1) to[out=90,in=180] (X2) to[out=0,in=90] (X3) to[out=270,in=90] (X4) to[out=270,in=0] (X5) to[out=180,in=270] (X6);
    
    \filldraw[spath/use=pathX,thick,blue,fill=blue!20];

\begin{scope}
\clip[spath/use={transform={yshift=-5pt},pathX}, invclip];
    % Some vertical arrows -- how clip to EXTERIOR of region X??    
    \def\somex{0.75, 1.5, 2.5, 3.5}
    \foreach \x in \somex {
        \draw[red,thick][->] (\x,0) -- (\x,-2);
}
\end{scope}
\end{tikzpicture}

\end{document} 

A region with arrows coming out of it and clipped against the region's boundary, not using the spath3 library

A second version of the image that uses the spath3 library and also shifts the clipping path to cut the arrows outside the region

2
  • So may ways, and they work!
    – murray
    Commented May 28 at 13:43
  • What exactly is the role of the odd even rule here? (I've tried to understand exactly what it does from the manual and posts here but still don't "get it".)
    – murray
    Commented May 28 at 16:46
7

Two pitfalls which may be the stumbling block:

  1. The path must be closed or else invclip is no different from the entire potential region i.e. to no clip at all. There's no point anyway in defining X0 and X6 to be the same point, but you don't want to end with X0 either. You want to end cycle so you get a closed path.
  2. clip is finicky. It is antisocial. It does not play well with others. Theoretically, it may be possible to combine it with other operations but, in practice, I've never found a case where that worked. Similarly, it doesn't work to use a saved path. It has to be specified explicitly and you can't get the specification to do double service. Since invclip is just clip underneath, the same rule applies.

So,

\documentclass[tikz,border=3mm]{standalone}
% ateb: https://tex.stackexchange.com/a/719065/ addaswyd o ateb Paul Gaborit: https://tex.stackexchange.com/a/59168/ a chwestiwn murray: https://tex.stackexchange.com/q/719042/
\tikzset{invclip/.style={% ateb Paul Gaborit: https://tex.stackexchange.com/a/59168/
    clip,insert path={{[reset cm]
      (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)
    }}}}
\begin{document}
\begin{tikzpicture}
  \coordinate (X1) at (0,0);
  \coordinate (X2) at (2,2);
  \coordinate (X3) at (4,1);
  \coordinate (X4) at (3,-1);
  \coordinate (X5) at (1,-1.5);
  \path[thick,draw=blue,fill=blue!20] (X1) to[out=90,in=180] (X2) to[out=0,in=90] (X3) to[out=270,in=90] (X4) to[out=270,in=0] (X5) to[out=180,in=270] cycle;
  \begin{scope}[even odd rule]
    \begin{pgfinterruptboundingbox} % ateb Paul Gaborit: https://tex.stackexchange.com/a/59168/
%       useful to avoid the rectangle in the bounding box
      \path[invclip] (X1) to[out=90,in=180] (X2) to[out=0,in=90] (X3) to[out=270,in=90] (X4) to[out=270,in=0] (X5) to[out=180,in=270] cycle;;
    \end{pgfinterruptboundingbox} 
    \def\somex{0.75, 1.5, 2.5, 3.5}
    \foreach \x in \somex {
      \draw[red,thick][->] (\x,0) -- (\x,-2);
    } 
  \end{scope}
\end{tikzpicture}
\end{document}

clipped arrows

Shifting the path is left as an exercise for the reader.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .