23

I'm trying to reproduce the following two figures in TikZ.

Fig 1 Fig 2

My attempted code for Fig 1 is

\documentclass{minimal}
\usepackage{tikz}
\begin{document}
    \begin{tikzpicture}
    \draw [fill=black, ultra thick, red]  (0.0,0.0) -- (0.5, 0.5) -- (0.5, 1.5) -- (0.0, 1.0) -- cycle;
    \draw [fill=black, ultra thick, blue] (1.0,0.0) -- (1.5, 0.5)-- (1.5, 1.5)--(1.0, 1.0)--cycle;
    \draw  (0.0,0.0)  -- (1.0, 0.0)-- (1.5, 0.5)--(0.5, 0.5)--cycle;
    \draw  (0.0,1.0) -- (1.0, 1.0)-- (1.5, 1.5)--(0.5, 1.5)--cycle;
    \end{tikzpicture}
\end{document}

My Fig 1

and for the second figure the code is

\documentclass{minimal}
\usepackage{tikz}
\begin{document}
    \begin{tikzpicture}
    \draw [fill=black, ultra thick, red]  (1.0,0.0) -- (1.0, 1.0) -- (0.5, 1.5) -- (0.5, 0.5) -- cycle;
    \draw [fill=black, ultra thick, blue] (0.0,0.0) -- (0.0, 1.0)-- (1.5, 1.5)--(1.5, 0.5)--cycle;
    \draw  (0.0,0.0)  -- (1.0, 0.0)-- (1.5, 0.5)--(0.5, 0.5)--cycle;
    \draw  (0.0,1.0) -- (1.0, 1.0)-- (1.5, 1.5)--(0.5, 1.5)--cycle;
    \draw  (1.0, 0.0) -- (1.0, 1.0)  (0.5, 0.5) -- (0.5, 1.5);
    \end{tikzpicture}
\end{document}

My Fig 2

I'm a TikZ newbie and have troubles to produce exactly the same figures with more efficient code. I've a problem with overlays and exact coordinates. I'd highly appreciate if you could help me to fix these problems and get similar figures with more robust code.

4
  • 1
    I think that you need to take a look at the outer sep option on page 176 in the tikz manual. -and use \draw [draw=black, ultra thick, fill=blue]. -and read chapter 20 about transparency. Commented Feb 21, 2012 at 5:16
  • Thanks @Hans-PeterE.Kristiansen for your pointer. I almost rosoved the issue of transparency. Thanks again.
    – MYaseen208
    Commented Feb 21, 2012 at 5:23
  • @Hans-PeterE.Kristiansen: Can you give me more pointer about outer sep?
    – MYaseen208
    Commented Feb 21, 2012 at 5:36
  • I do not know how make it work myself - I just guessed that setting outer sep = 0 would help to make the lines join nicely. -but I do not know enough. Commented Feb 21, 2012 at 5:41

3 Answers 3

27

It is often forgotten that tikZ also has an xyz coordinate system. I think it lets you express the coordinates in a more natural way. (I also added the circles.)

\documentclass{minimal}
\usepackage{tikz}      
\usetikzlibrary{calc}  

\begin{document}
    \begin{tikzpicture}[scale=4,fill opacity=0.4,thick,
                        line cap=round,line join=round]
    %% Define coordinate labels.
    % t(op) and b(ottom) layers
    \path \foreach \layer/\direction in {b/{0,0,0},t/{0,1,0}} {
        (\direction)
        \foreach \point/\label in {{0,0,0}/ll,{1,0,0}/lr,{1,0,-1}/ur,{0,0,-1}/ul} {
            +(\point) coordinate (\layer\label)
        }
        ($(\layer ll)!0.5!(\layer ur)$) coordinate (\layer md)
    };

    % Put text next to the labels as requested.
    % Funilly enough we need to set fill opacity to 1.
    \draw \foreach \text/\label/\anchor in {%
        one/bll/east,
        two/bul/east,
        three/tll/east,
        four/tul/east,
        five/blr/west,
        six/bur/west,
        seven/tlr/west,
        eight/tur/west} {
        (\label) node[anchor=\anchor,fill opacity=1] {\text}
    };

    % Draw left cube.
    \fill (0,0,-1) circle (0.5pt);
    \foreach \direction in {(0,0,1),(0,1,0),(1,0,0)} {
        \draw[dashed,black] (bul) -- + \direction;
    }
    \fill[blue!60] (bmd) -- (bur) -- (tur) -- (tmd);
    \fill[red!60]  (blr) -- (tlr) -- (tul) -- (bul);
    \fill[blue!60] (bll) -- (bmd) -- (tmd) -- (tll);
    \draw (bll) -- (blr) -- (tlr) -- (tll) -- cycle;
    \draw (blr) -- (bur) -- (tur) -- (tlr) -- cycle;
    \draw (tll) -- (tlr) -- (tur) -- (tul) -- cycle;
    \foreach \point in {bll,blr,bur,tll,tlr,tul,tur} {
        \fill[fill opacity=1] (\point) circle (0.75pt);
    }

    % Draw right cube.
    \path (blr) + (0.65,0) coordinate (pos);
    \foreach \direction in {(0,0,1),(0,1,0),(1,0,0)} {
        \draw[dashed] (pos) ++ (bul) -- + \direction;
    }
    \fill[blue!60] (pos) +(blr) -- +(bur) -- +(tur) -- +(tlr);
    \fill[red!60]  (pos) +(bll) -- +(bul) -- +(tul) -- +(tll);
    \draw (pos) +(tll) -- +(tlr) -- +(tur) -- +(tul) -- cycle
                +(tll) -- +(bll) -- +(blr) -- +(bur) -- +(tur)
                +(blr) -- +(tlr);
    \end{tikzpicture}
\end{document}

cube with shaded sides

4
  • 1
    Yes and No. Yes it's more easy to see where are the points. No because you have the same calculus to place the points, No because you have a lot of coordinates to write. The better way is to name the coordinates with the 3D library. Each side is a plan, and you can work with only 2 coordinates. After getting the coordinates, you can working without problem. (see my update) Commented Feb 21, 2012 at 9:06
  • I understand and in my HD, half of the 3D examples used your method and the other half the 3D library. But I think it's preferable to name the coordinates. The code will be easier to modify and read. Commented Feb 21, 2012 at 9:44
  • (+1): Thanks @MarcvanDongen for such a formidable answer. I'd highly appreciate if you let me how to put some text (like A, B, etc...) close to every circle. Thanks again for all your help. Much appreciated.
    – MYaseen208
    Commented Feb 21, 2012 at 16:12
  • 1
    @MarcvanDongen: Nice answer. One minor problem is that the lines does not match up nicely - it can only be seen on the right figure, where there is no circles in the corners to hide the problem. (If you do not know what I mean, then try setting the line width to ultra thich.) Commented Feb 26, 2012 at 5:38
23

Your options are not fine. When you write \draw[fill=black, ultra thick, red], as you can see fill=black doesn't work. Your last option red is used for drawing and filling. to fill with red and to draw with black, you need to write \draw[color=black,fill=red, ultra thick]. Surface and line are red and the line width is important so you the result is not fine. Now in a first time, you can use \draw and \fill separately. The order is important because some options have some effects on the first drawings. There are other methods (ways) to create this picture but I give you the codes later. For the circles at each vertex is interesting to use variables instead of "raw" coordinates and you can use \foreach. Comments are in the code.

Figure

enter image description here

My code update

I keep the code initial to show what is wrong and what is right

\documentclass{minimal}
\usepackage{tikz}
\usetikzlibrary{calc}
\begin{document} 

 \tikzset{vertex/.style={shape=circle, % style for a vertex
                    minimum size=3pt,
                    fill=black,
                    inner sep = 0pt}}
\begin{tikzpicture}[scale=4] 
  % define the points  
 \path  (0,0)     coordinate (A)  (1,0)     coordinate (B) % bottom
        (1.5,0.5) coordinate (C)  (0.5,0.5) coordinate (D)
        (0,1)     coordinate (E)  (1,1)     coordinate (F) % top  add 1 for y
        (1.5,1.5) coordinate (G)  (0.5,1.5) coordinate (H)
        ($(A)!0.5!(C)$) coordinate (O)   % middle of A--C
        ($(E)!0.5!(G)$) coordinate (P);%   

    \draw (A) -- (E) (B) -- (F) (C) -- (G) ; % lateral 
    \draw[gray,dashed]  (D) -- (H) (D) -- (C) (D) -- (A) (D) -- (B) (A) -- (C);   
    \fill [blue!50,fill opacity=.5] (P) -- (O) -- (C) -- (G) -- cycle;
    \fill [red!50, fill opacity=.5] (H) -- (D) -- (B) -- (F) -- cycle;
    \fill [blue!50,fill opacity=.5] (A) -- (O) -- (P) -- (E) -- cycle;
    \draw (A) -- (B) -- (C) (F) -- (H); % bottom 
    \draw (E) -- (F) -- (G) -- (H) -- (E) -- (G); % top
    % vertex 
    \foreach \vertex in {A,...,C} {\node[vertex] at (\vertex) {};}
    \foreach \vertex in {E,...,H} {\node[vertex] at (\vertex) {};}
    \node[vertex,fill=gray] at (D) {};       
  \end{tikzpicture} 
  \end{document}   

version 3D

I think it's the better way. With canvas is xy plane at z=0, you are on a plan (xy). I used some negative values to respect my first solution and to use the same code,. The code looks better with only positive values. To use other side, you just need to write for example canvas is xz plane at y=0 and you get a plan (lateral) axis are x and z. The result is exactly the same and you need no calculus but you need some orientation in space !

I added yellow color to show how to use other plans Be careful, I used canvas is yx plane and not canvas is xy plane.

enter image description here

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}     
\usetikzlibrary{calc,3d}

\begin{document}
\thispagestyle{empty} 

 \tikzset{vertex/.style={shape=circle, % style for a vertex
                        minimum size=3pt,
                        fill=gray,
                        inner sep = 0pt}}  

  \begin{tikzpicture}
    [x={(-0.5cm,-0.5cm)}, y={(1cm,0cm)}, z={(0cm,1cm)}, scale=4]  
    \draw[thick](0,0,0)--(1.2,0,0) node[below right]{x} ;
    \draw[thick](0,0,0)--(0,1.2,0) node[below right]{y} ;
    \draw[thick](0,0,0)--(0,0,1.2) node[below right]{z} ;
  % face  bottom
   \begin{scope}[canvas is xy plane at z=0,very thin]
       \coordinate  (A) at (0,0);   \coordinate (C) at (-1,1);
       \coordinate  (B) at (-1,0);  \coordinate  (D) at (0,1); 
        \coordinate (O) at  ($(A)!0.5!(C)$); % middle of A--C   
   \end{scope}  
     % face  top
    \begin{scope}[canvas is xy plane at z=1,very thin]
        \coordinate  (E) at (0,0);  \coordinate (G) at (-1,1);     
        \coordinate  (F) at (-1,0); \coordinate (H) at (0,1);
        \coordinate (P) at  ($(E)!0.5!(G)$); % middle of A--C     
    \end{scope} 

    \begin{scope}[canvas is yx plane at z=0]
      \path[fill = yellow] (0,0) rectangle (1,-1);
    \end{scope} 

     \foreach \vertex in {A,...,H} {\node[vertex] at (\vertex) {};}
        \draw (A) -- (B) -- (C) -- (D) -- cycle; % bottom
        \draw (E) -- (F) -- (G) -- (H) -- cycle; % top 
        \draw (A) -- (E) (B) -- (F) (C) -- (G) (D)--(H); % lateral  
        \fill [blue!50,fill opacity=.5] (P) -- (O) -- (C) -- (G) -- cycle;
        \fill [red!50, fill opacity=.5] (H) -- (D) -- (B) -- (F) -- cycle;
        \fill [blue!50,fill opacity=.5] (A) -- (O) -- (P) -- (E) -- cycle;     
\end{tikzpicture}
\end{document}

For fun

I would like to avoid maximum of coordinates

\documentclass[12pt,a4paper]{article}
\usepackage{tikz}     
\usetikzlibrary{calc,3d}

\begin{document}
\thispagestyle{empty} 

 \tikzset{vertex/.style={shape=circle, % style for a vertex
                        minimum size=8pt,
                        ball color=gray,
                        inner sep = 0pt}}  

\begin{tikzpicture}
    [x={(-0.5cm,-0.5cm)}, y={(1cm,0cm)}, z={(0cm,1cm)}, scale=4]
\foreach \z in {0,1}  \foreach \y in {0,1}  \foreach  \x in {0,1}   
    {\coordinate (\x\y\z) at  (\x,\y,\z) ;} 

         \coordinate (O) at  ($(000)!0.5!(110)$);
         \coordinate (P) at  ($(001)!0.5!(111)$);

\fill[fill opacity=.5,blue!30] (O) 
    \foreach \pt in {P,011,010}{--(\pt.center)}--cycle;% 

\fill[fill opacity=.5,red!30] (000) 
    \foreach \pt in {110,111,001}{--(\pt.center)}--cycle;% 

\fill[fill opacity=.5,blue!30] (O) 
    \foreach \pt in {P,101,100}{--(\pt.center)}--cycle;% 

\draw[thick,double] (000.center)
    \foreach \pt in {010,011,001}{--(\pt.center)}--cycle;%

\foreach \y in {0,1}  \foreach  \z in {0,1}    
    {\node[vertex] (0\y\z) at  (0\y\z) {};}

\draw[thick,double] (100.center)
    \foreach \pt in {110,111,101}{--(\pt.center)}--cycle;%  

 \foreach \y in {0,1}  \foreach  \z in {0,1}    
    {\draw[thick,double] (0\y\z) -- (1\y\z);
     \node[vertex] (1\y\z) at  (1\y\z) {};}
\end{tikzpicture} 
\end{document}

enter image description here

12
  • Thanks @Altermundus for your help. This is awesome. Would you mind to make little circle on every vertex? Thanks
    – MYaseen208
    Commented Feb 21, 2012 at 6:49
  • No problem but I need before explain some of the problems Commented Feb 21, 2012 at 7:18
  • Okay. If you see the original figures, you can find small circles at very vertices, e.g. circles at (0, 0), (0, 1), etc. Thanks again for all your help.
    – MYaseen208
    Commented Feb 21, 2012 at 7:21
  • @Altermundus Just one minor comment about the first code exmple (there are so many:-). Redefing the labels using copy-and-paste sort of defeats the purpose of using the labels. It would be nicer if you could reuse the label commands. This can be done using incremental coordinates (or shifts). The second cube in my example reuses the coordinate labels.
    – user10274
    Commented Feb 21, 2012 at 14:04
  • I have another one because I have the beginning of a package that I made for my students. I don't understand exactly what you mean by "Redefing the labels using copy-and-paste". Is it the fact to use node after coordinate at the same position? What do you understand by "label commands". Sorry but my english is not very good! Commented Feb 21, 2012 at 15:03
6

Just for fun: a version that draws the planes in a 3D-like order, i.e. planes in the foreground are drawn last. This is a rather small modification of this answer. In both of the posts, it is rather straightforward to do the ordering because the normal vectors of all planes lie in a plane. Therefore, one only has to distinguish between 4 cases (at most).

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz}
\usepackage{tikz-3dplot}
\usetikzlibrary{calc}
\newcommand{\DrawRectangularPlane}[4][]{\draw[#1] 
#2 -- ++  #3 --++ #4 -- ++ ($-1*#3$) -- cycle;}
\newcommand{\DrawSinglePlane}[2][]{\ifcase#2
\or % 1 xz plane at y=-1 
\DrawRectangularPlane[fill=red,#1]{({-2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},-\PlaneScale)}
{(2*\PlaneScale,0,0)}{(0,0,2*\PlaneScale)} 
\or% 2 xz plane at y=1
\DrawRectangularPlane[fill=blue,#1]{({-2*cos(45)*\PlaneScale},{2*sin(45)*\PlaneScale},-\PlaneScale)}
{(2*\PlaneScale,0,0)}{(0,0,2*\PlaneScale)} 
\or% 3 yz plane at x=-1
\DrawRectangularPlane[fill=red,#1]{({-2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},-\PlaneScale)}
{(0,2*\PlaneScale,0)}{(0,0,2*\PlaneScale)} %
\or% 4 yz plane at x=1
\DrawRectangularPlane[fill=blue,#1]{({2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},-\PlaneScale)}
{(0,2*\PlaneScale,0)}{(0,0,2*\PlaneScale)} % 
\or% 5 diagonal upper right quadrant
\DrawRectangularPlane[fill=blue,#1]{({2*cos(45)*\PlaneScale},{2*sin(45)*\PlaneScale},-\PlaneScale)}
{({-2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},0)}{(0,0,2*\PlaneScale)} 
\or% 6 diagonal upper left quadrant
\DrawRectangularPlane[fill=red,#1]{({-2*cos(45)*\PlaneScale},{2*sin(45)*\PlaneScale},-\PlaneScale)}
{({2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},0)}{(0,0,2*\PlaneScale)} 
\or% 7 diagonal lower right quadrant
\DrawRectangularPlane[fill=red,#1]{({2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},-\PlaneScale)}
{({-2*cos(45)*\PlaneScale},{2*sin(45)*\PlaneScale},0)}{(0,0,2*\PlaneScale)} 
\or %d iagonal lower left quadrant
\DrawRectangularPlane[fill=blue,#1]{({-2*cos(45)*\PlaneScale},{-2*sin(45)*\PlaneScale},-\PlaneScale)}
{({2*cos(45)*\PlaneScale},{2*sin(45)*\PlaneScale},0)}{(0,0,2*\PlaneScale)} 
\fi
} 
\begin{document}
\foreach \X in {0,5,...,355} % {70}
{\tdplotsetmaincoords{90+40*sin(\X)}{\X} % the first argument cannot be larger than 90
\pgfmathsetmacro{\PlaneScale}{1}
\begin{tikzpicture}
\path[use as bounding box] (-4*\PlaneScale,-4*\PlaneScale) rectangle (4*\PlaneScale,4*\PlaneScale);
\begin{scope}[tdplot_main_coords]
\pgfmathtruncatemacro{\xproj}{sign(cos(\tdplotmainphi-45))}
\pgfmathtruncatemacro{\zproj}{sign(sin(\tdplotmainphi-45))}
\ifnum\xproj=1
  \ifnum\zproj=1
   \foreach \X in {5,6,7,8}
    {\DrawSinglePlane{\X}}
  \else
   \foreach \X in {8,6,7,5}
    {\DrawSinglePlane{\X}}
  \fi  
\else
  \ifnum\zproj=1
   \foreach \X in {5,7,6,8}
    {\DrawSinglePlane{\X}}
  \else
   \foreach \X in {6,5,8,7}
    {\DrawSinglePlane{\X}}
  \fi  
\fi  
% \draw[thick,->] (0,0,0) -- (2,0,0) node[anchor=north east]{$x$};
% \draw[thick,->] (0,0,0) -- (0,2,0) node[anchor=north west]{$y$};
% \draw[thick,->] (0,0,0) -- (0,0,1.5) node[anchor=south]{$z$};
\end{scope}
\end{tikzpicture}}
\end{document}

enter image description here

The case of two parallel planes is even simpler. One can the do the ordering with

\pgfmathtruncatemacro{\xproj}{sign(sin(\tdplotmainphi))}
%\node[anchor=north west] at (current bounding box.north west) {\tdplotmainphi,\xproj};
\ifnum\xproj=1
   \foreach \X in {3,4}
    {\DrawSinglePlane{\X}}
\else
   \foreach \X in {4,3}
    {\DrawSinglePlane{\X}}
\fi  

enter image description here

You must log in to answer this question.

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