8

I've been searching this for hours, but didn't find a reason for this behaviour:

Here is my example:

\documentclass{article}
\usepackage{tikz}
\usetikzlibrary{3d}


\begin{document}
    \begin{tikzpicture}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
        \fill[blue!50,opacity=0.6] (0,0,0) rectangle (2,1,0);
        \fill[green!50,opacity=0.6] (0,0,0) -- (2,0,0) -- (2,1,0) -- (0,1,0) -- (0,0,0);
        \draw[->] (0,0,0) -- (1,0,0);
        \draw[->] (0,0,0) -- (0,1,0);
        \draw[->] (0,0,0) -- (0,0,1);

        \begin{scope}[xshift=3cm]
            \fill[blue!50,opacity=0.6] (0,0,0) circle (1);
            \draw[->] (0,0,0) -- (1,0,0);
            \draw[->] (0,0,0) -- (0,1,0);
            \draw[->] (0,0,0) -- (0,0,1);
        \end{scope}
    \end{tikzpicture}
\end{document}

enter image description here

I'd expect both rectangles to be painted the same. To be more precise, both should appear like the green one, but the don't.

Obviously, the coordinate of the upper right corner (2,1,0) is correct for both rectangles, but only the green one correctly aligns with the coordinate system's axes.

In comparison to this, the circle correcly uses the modified vectors, since it is drawn as an ellipse.

What do I have to do, to get the blue rectangle painted like the green one?

Edit: I found something interesting in this answer. Apparently the following code works, but I find it a little inconvenient to place all my rectangle into scopes.

Additionally, is canvas is xy plane at z really implemented the wrong way? Why isn't this fixed, then?

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary{3d}

\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
  \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
  \def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
  \def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
  \tikz@canvas@is@plane
}
\makeatother

\begin{document}
\begin{tikzpicture}[x={(0.866cm,0.5cm)},y={(-0.866cm,0.5cm)},z={(0cm,1cm)}]
        \begin{scope}[canvas is xy plane at z=0,transform shape]
            \fill[blue!50,opacity=0.6] (0,0,0) rectangle (2,1,0);
        \end{scope}

        \fill[green!50,opacity=0.6] (0,0,0) -- (2,0,0) -- (2,1,0) -- (0,1,0) -- (0,0,0);

        \draw[->] (0,0,0) -- (1,0,0);
        \draw[->] (0,0,0) -- (0,1,0);
        \draw[->] (0,0,0) -- (0,0,1);

        \begin{scope}[xshift=3cm]
            \fill[blue!50,opacity=0.6] (0,0,0) circle (1);
            \draw[->] (0,0,0) -- (1,0,0);
            \draw[->] (0,0,0) -- (0,1,0);
            \draw[->] (0,0,0) -- (0,0,1);
        \end{scope}
\end{tikzpicture}
\end{document}

enter image description here

  • 1
    Welcome to TeX.SX. – Claudio Fiandrino Apr 11 '13 at 13:29
  • Regarding your question whether canvas is xy plane at z is really implemented the wrong way: Judging by the fact that it doesn't work in its current implementation, but it does with the correction, I would say "yes". It probably hasn't been fixed because no bug report has been posted. – Jake Apr 11 '13 at 14:49
  • If the canvas is xy plane at z approach works for you in principle: You can define a convenience style using \tikzset{3d/.style={canvas is xy plane at z=0}}. Then you can draw your rectangle using \fill [3d] (0,0) rectangle (2,1);, without the need for a scope. – Jake Apr 11 '13 at 15:04
  • @Jake Looks like the question has been sorted out. Could you please post your comments as answer so the OP can accept it? Or, the OP should clarify about aspects of his questions that still remain unanswered. – kan May 4 '13 at 21:19
  • For the record: Jake's patch is now incorporated in v3.1 of TikZ. – Stefan Pinnow Jan 15 at 18:55
15

You don't have to put the commands in a scope, you can pass the options to the commands directly:

\draw[canvas is xy plane at z=0] ...;,

but this greatly increases line length. Instead you can define styles with a parameter to use these:

\tikzset{my style name/.style={canvas is xy plane at z=#1}}

And as a small remark: instead of giving the unit vectors in cartesian form (which is very inconvineant if you want to change them), you can use polar notation:

[x={(0.866cm,0.5cm)}] [x={(-30:1cm)}

Code

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

\makeatletter
\tikzoption{canvas is xy plane at z}[]{%
  \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
  \def\tikz@plane@x{\pgfpointxyz{1}{0}{#1}}%
  \def\tikz@plane@y{\pgfpointxyz{0}{1}{#1}}%
  \tikz@canvas@is@plane
}
\makeatother

\tikzset{xyp/.style={canvas is xy plane at z=#1}}
\tikzset{xzp/.style={canvas is xz plane at y=#1}}
\tikzset{yzp/.style={canvas is yz plane at x=#1}}

\begin{document}
\begin{tikzpicture}[x={(-30:1cm)},y={(210:1cm)},z={(90:1cm)}]
    \draw[->] (0,0,0) -- node[pos=1.2] {x} (1,0,0);
    \draw[->] (0,0,0) -- node[pos=1.2] {y} (0,1,0);
    \draw[->] (0,0,0) -- node[pos=1.2] {z} (0,0,1);
    \foreach \n in {-0.1,-0.2,...,-2}
    {   \fill[opacity=0.3,yellow,draw=black,xyp=\n] (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
        \fill[opacity=0.3,red,draw=black,xzp=\n] (0,0) (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
        \fill[opacity=0.3,blue,draw=black,yzp=\n] (0,0) (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
    }  
\end{tikzpicture}
\end{document}

Output

enter image description here

2

Reading the source, I found that you just need to replace

canvas is xy plane at z

by

canvas is yx plane at z

Their definition in tikzlibrary3d.code.tex are

\tikzoption{canvas is xy plane at z}{%
  \tikz@addtransform{\pgftransformshift{\pgfpointxyz{0}{0}{#1}}}%
}
\tikzoption{canvas is yx plane at z}[]{%
  \def\tikz@plane@origin{\pgfpointxyz{0}{0}{#1}}%
  \def\tikz@plane@x{\pgfpointxyz{0}{1}{#1}}%
  \def\tikz@plane@y{\pgfpointxyz{1}{0}{#1}}%
  \tikz@canvas@is@plane
}

For example @Tom Bombadil's answer can by modified to

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

\tikzset{xyp/.style={canvas is yx plane at z=#1}}
\tikzset{xzp/.style={canvas is xz plane at y=#1}}
\tikzset{yzp/.style={canvas is yz plane at x=#1}}

\begin{document}
\begin{tikzpicture}[x={(-30:1cm)},y={(210:1cm)},z={(90:1cm)}]
    \draw[->] (0,0,0) -- node[pos=1.2] {x} (1,0,0);
    \draw[->] (0,0,0) -- node[pos=1.2] {y} (0,1,0);
    \draw[->] (0,0,0) -- node[pos=1.2] {z} (0,0,1);
    \foreach \n in {-0.1,-0.2,...,-2}
    {   \fill[opacity=0.3,yellow,draw=black,xyp=\n] (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
        \fill[opacity=0.3,red,draw=black,xzp=\n] (0,0) (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
        \fill[opacity=0.3,blue,draw=black,yzp=\n] (0,0) (0-\n/5,0-\n/5) rectangle (2+\n/5,2+\n/5);
    }  
\end{tikzpicture}
\end{document}

And the output is exactly the same.


Apparently @Alain Matthes in the linked question found this too.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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