15

I want to draw an incomplete cube, as in the following figure.

enter image description here

But, I can only draw a complete cube, see below.

enter image description here

\documentclass[12pt]{article}
\usepackage{tikz}
\usepackage{verbatim}
\usetikzlibrary{positioning}
\begin{document}
\begin{tikzpicture}[on grid][scale=1.4]
  \shade[yslant=-0.5,right color=white, left color=white]
    (0,0) rectangle +(3,3);
  \draw[yslant=-0.5] (0,0) grid (3,3);
  \shade[yslant=0.5,right color=white,left color=white]
    (3,-3) rectangle +(3,3);
  \draw[yslant=0.5] (3,-3) grid (6,0);
  \shade[yslant=0.5,xslant=-1,bottom color=white,
    top color=white] (6,3) rectangle +(-3,-3);
  \draw[yslant=0.5,xslant=-1] (3,0) grid (6,3);
\end{tikzpicture}
\end{document}
0

3 Answers 3

12

I would like to argue that one should use orthographic projections and write it in such a way that one can change the view angle. There are already many posts on this, perhaps most impressingly this one. The idea to use pics for the unit cubes to draw 3d cubes with some little cubes missing is also not new, it has been used here, where the cubes are rotatable in 3d. I just recycled the code to get

\documentclass[tikz,border=3.14mm]{standalone}
\usepackage{tikz-3dplot}
\usetikzlibrary{calc}
\tikzset{plane/.style n args={3}{insert path={%
#1 -- ++ #2 -- ++ #3 -- ++ ($-1*#2$) -- cycle}},
unit xy plane/.style={plane={#1}{(1,0,0)}{(0,1,0)}},
unit xz plane/.style={plane={#1}{(1,0,0)}{(0,0,1)}},
unit yz plane/.style={plane={#1}{(0,1,0)}{(0,0,1)}},
get projections/.style={insert path={%
let \p1=(1,0,0),\p2=(0,1,0)  in 
[/utils/exec={\pgfmathtruncatemacro{\xproj}{sign(\x1)}\xdef\xproj{\xproj}
\pgfmathtruncatemacro{\yproj}{sign(\x2)}\xdef\yproj{\yproj}
\pgfmathtruncatemacro{\zproj}{sign(cos(\tdplotmaintheta))}\xdef\zproj{\zproj}}]}},
pics/unit cube/.style={code={
\path[get projections];
\draw (0,0,0) -- (1,1,1);
\ifnum\zproj=-1
 \path[3d cube/every face,3d cube/xy face,unit xy plane={(0,0,0)}]; 
\fi
\ifnum\yproj=1
 \path[3d cube/every face,3d cube/yz face,unit yz plane={(1,0,0)}]; 
\else
 \path[3d cube/every face,3d cube/yz face,unit yz plane={(0,0,0)}]; 
\fi
\ifnum\xproj=1
 \path[3d cube/every face,3d cube/xz face,unit xz plane={(0,0,0)}]; 
\else
 \path[3d cube/every face,3d cube/xz face,unit xz plane={(0,1,0)}]; 
\fi
\ifnum\zproj>-1
 \path[3d cube/every face,3d cube/xy face,unit xy plane={(0,0,1)}]; 
\fi
}},
3d cube/.cd,
xy face/.style={fill=gray!20},
xz face/.style={fill=gray!50},
yz face/.style={fill=gray!90},
every face/.style={draw,very thick}
}
\begin{document}
\foreach \Angle in {5,15,...,355} 
{\tdplotsetmaincoords{60}{\Angle} % the first argument cannot be larger than 90
\begin{tikzpicture}[line join=round]
 \pgfmathtruncatemacro{\NumCubes}{7}
 \path[use as bounding box] (-\NumCubes/2-3,-\NumCubes/2-2) 
 rectangle (\NumCubes/2+3,\NumCubes/2+4);
 \begin{scope}[tdplot_main_coords]
  \pgfmathtruncatemacro{\NextToLast}{\NumCubes-1}
  \path[get projections];
  \ifnum\yproj=1
   \def\LstX{1,2,3}
  \else 
   \def\LstX{3,2,1}
  \fi
  \ifnum\xproj=-1
   \def\LstY{1,2,3}
  \else 
   \def\LstY{3,2,1}
  \fi
  \foreach \X in \LstX
  {\foreach \Y in \LstY
   {\ifnum\Y=3
    \pgfmathtruncatemacro{\Zmax}{5-max(\X,2)}
   \else
    \pgfmathtruncatemacro{\Zmax}{4-\X}
   \fi
   \foreach \Z in {1,...,\Zmax}
    {\path (\X-2,\Y-2,\Z-1) pic{unit cube};}}
  }
 \end{scope}
\end{tikzpicture}}
\end{document}

enter image description here

1
  • "I would like to argue that one should use orthographic projections". Spoken like a true engineer! +1 Apr 1, 2019 at 14:13
18

You can define a single cube as pic and place it where you want (starting from bottom back to top front).

\documentclass[tikz,border=7pt]{standalone}
\tikzset{
  cube/.pic={
    \draw[fill=black!20] (0,1,0) -- (0,1,1) -- (1,1,1) -- (1,1,0);
    \draw[fill=black!50] (1,0,0) -- (1,0,1) -- (1,1,1) -- (1,1,0);
    \draw[fill=white] (0,0,0) rectangle (1,1,0);
  }
}
\begin{document}
  \tikz[z={(.4,.3)}]\path\pgfextra{\def~{pic{cube}}} % <--- to make the code shorter
      (2,0,2)~(2,0,1)~(0,0,0)~(1,0,0)~(2,0,0)~
      (2,1,2)~(1,1,1)~(0,1,0)~(1,1,0)~
      (0,2,2)~(1,2,2)~(0,2,1)~(0,2,0)~;
\end{document}

enter image description here

5
  • 1
    ...better to use the redefined ~ version inside a group, even if it's just to shorten your code. As in, \begingroup \def~{pic{code}} \begin{tikzpicture} ... \end{tikzpicture}.
    – Werner
    Apr 1, 2019 at 19:22
  • @Werner Agree, thanks. Done.
    – Kpym
    Apr 1, 2019 at 19:30
  • The \pgfextra and {...} only to avoid { and }? ` \tikz[z={(.4,.3)}]{\def~{pic{cube}} \path (2,0,2)~(2,0,1)~(0,0,0)~(1,0,0)~(2,0,0)~ (2,1,2)~(1,1,1)~(0,1,0)~(1,1,0)~ (0,2,2)~(1,2,2)~(0,2,1)~(0,2,0)~;}`
    – user121799
    Apr 1, 2019 at 20:23
  • @marmot I never avoid shorter code in general ;) But here, as redefining ~ is not a good practice, I decided to follow the comment of @Werner and to make its definition as local as possible : so local to the path is better to local for the entire tikz.
    – Kpym
    Apr 1, 2019 at 20:49
  • If that's your aim:\documentclass[tikz,border=7pt]{standalone} \tikzset{ cube/.pic={ \draw[fill=black!20] (0,1,0) -- (0,1,1) -- (1,1,1) -- (1,1,0); \draw[fill=black!50] (1,0,0) -- (1,0,1) -- (1,1,1) -- (1,1,0); \draw[fill=white] (0,0,0) rectangle (1,1,0); },icube/.style={insert path={#1 pic{cube}}} } \begin{document} \tikz[z={(.4,.3)}]\path[icube/.list={(2,0,2),(2,0,1),(0,0,0),(1,0,0),(2,0,0), (2,1,2),(1,1,1),(0,1,0),(1,1,0), (0,2,2),(1,2,2),(0,2,1),(0,2,0)}]; \end{document}
    – user121799
    Apr 1, 2019 at 20:59
14

Just for fun: everything is in 2D

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\draw (0,0) rectangle (1,1) (1,1) rectangle (2,2) (0,1) rectangle (1,2) (0,2) rectangle (1,3) (1,0) rectangle (2,1) (2,0) rectangle (3,1);
\draw (3.6,1.6)--(3.6,.6)--(3,0)--(3,1)--cycle--(3.6,2.6)--(2.6,2.6)--(2.6,3.6)--(.6,3.6)--(0,3);
\draw (2,1)--(2.4,1.4) (2,2)--(2.6,2.6) (1,2)--(1.4,2.4) (1,3)--(1.6,3.6) (2.4,3.4)--(2.6,3.6) (3.4,2.4)--(3.6,2.6); 
\draw (2.4,1.4) rectangle (3.4,2.4) (1.4,2.4) rectangle (2.4,3.4);
\draw (.4,3.4)--(1.4,3.4) (3.4,1.4)--(3.4,.4) (.2,3.2)--(1.2,3.2)--(1.2,2.2)--(2.2,2.2)--(2.2,1.2)--(3.2,1.2)--(3.2,.2);
\end{tikzpicture}
\end{document}

enter image description here

With colors

\documentclass[tikz]{standalone}
\begin{document}
\begin{tikzpicture}
\fill[black!70] (3,0)--(3.6,.6)--(3.6,2.6)--(3.4,2.4)--(3.4,1.4)--(3,1)--cycle (2.4,2.4)--(2.6,2.6)--(2.6,3.6)--(2.4,3.4)--(2.4,1.4)--(2,1)--(2,2)--cycle (1,2)--(1.4,2.4)--(1.4,3.4)--(1,3)--cycle;
\fill[black!30] (0,3)--(.6,3.6)-_(2.6,3.6)--(2.4,3.4)--(1.4,3.4)--(1,3)--cycle (2.4,2.4)--(2.6,2.6)--(3.6,2.6)--(3.4,2.4)--(1.4,2.4)--(1,2)--(2,2)--cycle (2,1)--(2.4,1.4)--(3.4,1.4)--(3,1)--cycle;
\draw (0,0) rectangle (1,1) (1,1) rectangle (2,2) (0,1) rectangle (1,2) (0,2) rectangle (1,3) (1,0) rectangle (2,1) (2,0) rectangle (3,1);
\draw (3.6,1.6)--(3.6,.6)--(3,0)--(3,1)--cycle--(3.6,2.6)--(2.6,2.6)--(2.6,3.6)--(.6,3.6)--(0,3);
\draw (2,1)--(2.4,1.4) (2,2)--(2.6,2.6) (1,2)--(1.4,2.4) (1,3)--(1.6,3.6) (2.4,3.4)--(2.6,3.6) (3.4,2.4)--(3.6,2.6); 
\draw (2.4,1.4) rectangle (3.4,2.4) (1.4,2.4) rectangle (2.4,3.4);
\draw (.4,3.4)--(1.4,3.4) (3.4,1.4)--(3.4,.4) (.2,3.2)--(1.2,3.2)--(1.2,2.2)--(2.2,2.2)--(2.2,1.2)--(3.2,1.2)--(3.2,.2);
\end{tikzpicture}
\end{document}

enter image description here

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.