3

I have an issue with a reverse clipping on a 2D surface represented in a 3D space.

Although the reversed clipping is working, the cut part is not projected on a plane.

enter image description here

Here is the MWE:

\documentclass{standalone}

\usepackage{amsmath, amssymb}
\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{arrows,decorations.pathmorphing}
\usepackage{tikz-3dplot}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}
\usetikzlibrary{shadings}

\tikzset{>=latex}
\tdplotsetmaincoords{70}{120}

%Cavity
\def \xcav {5}
\def \zcav {5}
\def \ycav {2}

\tikzset{
    invclip/.style={clip,insert path={{[reset cm]
    (-16383.99999pt,-16383.99999pt) rectangle (16383.99999pt,16383.99999pt)
    }}}
    }

\begin{document}
    \begin{tikzpicture}
         [
         scale=1,
         tdplot_main_coords
         ]

    % Cavity
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (\xcav,0,0) --++ (0,0,\zcav) --++ (-\xcav,0,0) -- cycle;
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (0,0,\zcav) --++ (0,-\ycav,0) -- cycle;
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (\xcav,0,0) --++ (0,-\ycav,0) -- cycle;

    \begin{scope}[canvas is xz plane at y=0]
        \begin{pgfinterruptboundingbox} % useful to avoid the rectangle in the bounding box
            \path[invclip](0,0) circle (0.25);
        \end{pgfinterruptboundingbox} 
       \shadedraw[clip] (-\xcav/2,-\zcav/2) --++ (\xcav,0) --++ (0,\zcav) --++ (-\xcav,0) -- cycle;
    \end{scope} 

    \draw (\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (0,0,\zcav) --++ (0,-\ycav,0) -- cycle;
    \draw (-\xcav/2,-\ycav,+\zcav/2) --++ (0,\ycav,0) --++ (\xcav,0,0) --++ (0,-\ycav,0) -- cycle;

    \end{tikzpicture}
\end{document}

Any thoughts ?

4
  • You reset cm... what did you expect?
    – Symbol 1
    Jan 29, 2016 at 11:42
  • 1
    Try invclip/.style={clip,insert path={{(-10,-10)rectangle(10,10)}}.
    – Symbol 1
    Jan 29, 2016 at 11:44
  • Ok it works, my bad, do you want to post a response so I can validate it ?
    – Thomas
    Jan 29, 2016 at 12:04
  • Not yet. I am trying to come upwith a general solutoin.
    – Symbol 1
    Jan 29, 2016 at 13:39

1 Answer 1

5

Some mumble-jumble:

The notable solution to invert clipping is to insert a path that is as large as possible. Currently the limit is associated to TeX's dimensions: about 214pt. However, users could have done some transformations so that a barely valid path, such as (-16383pt,16383pt)rectangle(16383pt,16383pt), will definitely exceed the limit.

That is why reset cm comes in: it resets all transformations and guarantees that a (the) valid path is still valid. Nevertheless, the drawback is also obvious. After resetting, the user need either to reconstruct the transformation or work harder with no transformation.

So a good solution to clipping-inverting should have limit the scope of reset cm, this is why you see double braces at insert path={{. But it does not work, probably because that value is passed between macros too many times and eventually TeX will "flay" all braces.

A solution to this is to add even more braces. Experiment shows that four braces is enough. By enough, I mean the result does change: The circle is not replace by the projected one, but just disappears.

It turns out that the scoping affects the calculation of winding number. Since nonzero-rule is default to clip, everything lies inside the large large path is reserved, making clipping meaningless.

A solution to this is to add a predefined option

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

into insert path. Experiment shows that the following works

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

Magically, now braces become unnecessary.

Complete code

\documentclass{standalone}

\usepackage{amsmath, amssymb}
\usepackage{graphicx}
\usepackage{tikz}
\usetikzlibrary{arrows,decorations.pathmorphing}
\usepackage{tikz-3dplot}
\usetikzlibrary{arrows}
\usetikzlibrary{calc}
\usetikzlibrary{shadings}

\tikzset{>=latex}
\tdplotsetmaincoords{70}{120}

%Cavity
\def \xcav {5}
\def \zcav {5}
\def \ycav {2}

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

\begin{document}
    \begin{tikzpicture}
         [
         scale=1,
         tdplot_main_coords
         ]

    % Cavity
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (\xcav,0,0) --++ (0,0,\zcav) --++ (-\xcav,0,0) -- cycle;
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (0,0,\zcav) --++ (0,-\ycav,0) -- cycle;
    \draw (-\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (\xcav,0,0) --++ (0,-\ycav,0) -- cycle;

    \begin{scope}[canvas is xz plane at y=0]
        \begin{pgfinterruptboundingbox} % useful to avoid the rectangle in the bounding box
            \path[invclip](0,0) circle (0.25);
        \end{pgfinterruptboundingbox} 
       \shadedraw[clip] (-\xcav/2,-\zcav/2) --++ (\xcav,0) --++ (0,\zcav) --++ (-\xcav,0) -- cycle;
    \end{scope} 

    \draw (\xcav/2,-\ycav,-\zcav/2) --++ (0,\ycav,0) --++ (0,0,\zcav) --++ (0,-\ycav,0) -- cycle;
    \draw (-\xcav/2,-\ycav,+\zcav/2) --++ (0,\ycav,0) --++ (\xcav,0,0) --++ (0,-\ycav,0) -- cycle;

    \end{tikzpicture}
\end{document}
1

You must log in to answer this question.

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