Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

I drew two blocks stacked on each other. Unfortunately, it looks off and I think it can be done more compactly code wise with a cleaner look.

Here is what I have:

\documentclass[tikz, convert = false]{standalone}%
\usetikzlibrary{calc}
\usetikzlibrary{intersections}

\begin{document}
\begin{tikzpicture}
  \coordinate (O) at (0, 0);
  \coordinate (P1) at (0.35, 1);
  \coordinate (P2) at (1.35, 1);
  \coordinate (P3) at (1, 0);

  \draw (O) -- (P3) node[pos = .5, font = \tiny, below] {$1$} -- (P2)
  node[pos = .5, right, font = \tiny] {$1$};
  \draw[dashed] (O) -- (P1) -- (P2);
  \draw (O) -- +(0, .2) coordinate (P4) -- +(1, .2) coordinate (P5) --
  +(1, 0);
  \draw[name path = uil] (P5) -- ($(P2) + (0, .2)$) coordinate (P6) --
  +(0, -.2);
  \draw (P6) -- +(-1, 0) coordinate (P7);
  \draw[dotted] (P7) -- (P1);

  \path[name path = uol] (P4) -- (P7);
  \path[name path = hl] (0, .35) -- +(1.25, 0);
  \path[name intersections = {of = uol and hl}];

  \coordinate (P8) at (intersection-1);

  \draw[dashed] (P8) -- (P7);
  \draw (P8) -- (P4);

  \path[name intersections = {of = uil and hl}];

  \coordinate (P9) at (intersection-1);

  \draw (P8) -- (P9);
  \draw (P8) -- +(0, .2) coordinate (P10) -- +(1, .2) coordinate (P11) --
  (P9);
  \draw (P6) -- +(0, .2) coordinate (P12);
  \draw (P11) -- (P12) -- +(-1, 0) coordinate (P13) -- (P10);
  \draw[dotted] (P13) -- +(0, -.2);
\end{tikzpicture}
\end{document}

Here is what it looks like (ugly):

enter image description here

How can the code be improved to make a better looking image and to be more simplified?

share|improve this question

2 Answers 2

up vote 7 down vote accepted

Here's an approach which takes perspective into account.

You can modify the dimensions of the boxes by changing the values of the parameters:

\aedepth
\aewidth
\aeheight
\aestepdepth

You can modify the apparent point of view by changing:

\aeeyelevel
\aeLVP
\aeRVP

Here's the code:

\documentclass[tikz,
               convert=false,
               crop=false,
               preview=true,
               border=4pt]{standalone}
\usetikzlibrary{calc}
\usetikzlibrary{intersections}

%% A macro to create the coordinate positions for the corners of the boxes
%% with respect to the positioning of the vanishing points.               
%% #1 plane name                                                          
%% #2 coordinate of corner-stone                                          
%% #3 left side length                                                    
%% #4 right side length                                                   
%% #5 height                                                              
\def\boxlayout#1(#2)#3#4#5{%%
  \coordinate (#1/bot/front)      at (#2);
  \coordinate (#1/bot/side/left)  at ($(#1/bot/front)!#3!(LVP)$);
  \coordinate (#1/bot/side/right) at ($(#1/bot/front)!#4!(RVP)$);

  \begin{pgfinterruptboundingbox}
    \path[name path=#1/bot/line/left] (#1/bot/side/right) -- (LVP);
    \path[name path=#1/bot/line/right] (#1/bot/side/left) -- (RVP);
    \path[name intersections={of=#1/bot/line/left and #1/bot/line/right,by=#1/bot/back}];
  \end{pgfinterruptboundingbox}

  \coordinate (#1/top/front)      at ($(#1/bot/front)+(0,#5)$);

  \begin{pgfinterruptboundingbox}
    \path[name path=#1/top/line/left]  (#1/top/front) -- (LVP);
    \path[name path=#1/vert/line/left] (#1/bot/side/left) -- ++(0,#5);
    \path[name intersections={of=#1/top/line/left and #1/vert/line/left,by=#1/top/side/left}];
    %%
    \path[name path=#1/top/line/right] (#1/top/front) -- (RVP);
    \path[name path=#1/vert/line/right] (#1/bot/side/right) -- ++(0,#5);
    \path[name intersections={of=#1/top/line/right and #1/vert/line/right,by=#1/top/side/right}];
    %%
    \path[name path=#1/top/receding/right]  (#1/top/side/left) -- (RVP);
    \path[name path=#1/top/receding/left]   (#1/top/side/right) -- (LVP);
    \path[name intersections={of=#1/top/receding/right and #1/top/receding/left,by=#1/top/back}];
  \end{pgfinterruptboundingbox}
}

%% change the following parameters to create boxes of different dimensions      
%% this example assumes that the stacked boxes have the same heights.  It should
%% be easy enough to modify the code to change this.                            
\def\aedepth{3cm}
\def\aewidth{4.5cm}
\def\aeheight{1.25cm}
\def\aestepdepth{1.25cm}
%% the macros change the perspective of the viewer.
%% increasing the value of the "eyelevel" gives an increasing bird-eye view.
%% LVP=left vanishing point
%% RVP=right vanishing point
\def\aeeyelevel{5in}
\def\aeLVP{-10in}
\def\aeRVP{15in}

\begin{document}

\begin{tikzpicture}

  \begin{pgfinterruptboundingbox}
    %% Left and right vanishing points
    \coordinate (LVP) at (\aeLVP,\aeeyelevel);
    \coordinate (RVP) at (\aeRVP,\aeeyelevel);
    \draw[red,thin] (LVP) -- (RVP);
  \end{pgfinterruptboundingbox}

  %% constructing the bottom box:
  %% the bottom box's name is "A"
  \boxlayout{A}(0,0){\aedepth}{\aewidth}{\aeheight}

  \begin{pgfinterruptboundingbox}
    %% preparing to construct the top box
    %% the "t" prefix on coordinate names means "temp"
    \coordinate (tB) at ($(A/top/front)+(0,\aeheight)$);
    \coordinate (tC) at ($(A/top/front)!\aestepdepth!(RVP)$);

    \path[name path=tB--RVP] (tB) -- (RVP);
    \path[name path=tC--UP]  (tC) -- ++(0,2cm);
    \path[name intersections={of=tB--RVP and tC--UP,by=tD}];
    %%
    \path[name path=tC--LVP] (tC) -- (LVP);
    \path[name path=TOP--RVP] (A/top/side/left) -- (RVP);
    \path[name intersections={of=tC--LVP and TOP--RVP,by=tE}];

    %% calculating the modified dimensions for the top box by 
    %% taking the perspective into account.
    \path($(tC)-(tE)$);
    \pgfgetlastxy{\aedepthx}{\aedepthy}
    \pgfmathparse{ veclen(\aedepthx,\aedepthy)}
    \global\let\aetopdepth\pgfmathresult
    %%
    \path($(tC)-(tD)$);
    \pgfgetlastxy{\aeheightx}{\aeheighty}
    \pgfmathparse{ veclen(\aeheightx,\aeheighty)}
    \global\let\aetopheight\pgfmathresult
    %%
    \path($(tC)-(A/top/side/right)$);
    \pgfgetlastxy{\aewidthx}{\aewidthy}
    \pgfmathparse{ veclen(\aewidthx,\aewidthy) }
    \global\let\aetopwidth\pgfmathresult
  \end{pgfinterruptboundingbox}

  %% The top box is named "B"
  \boxlayout{B}(tC){\aetopdepth pt}{\aetopwidth pt}{\aetopheight pt}

  %%--------------------------------------------------------------------------------
  %% DRAWING THE BOXES
  %% vertical lines:
  %% bottom box
  \draw[blue]           (A/bot/front)      -- (A/top/front);
  \draw[blue]           (A/bot/side/left)  -- (A/top/side/left);
  \draw[blue]           (A/bot/side/right) -- (A/top/side/right);
  \draw[gray!40,dashed] (A/bot/back)       -- (A/top/back);
  %% top box
  \draw[blue]           (B/bot/front)      -- (B/top/front);
  \draw[blue]           (B/bot/side/left)  -- (B/top/side/left);
  \draw[blue]           (B/bot/side/right) -- (B/top/side/right);
  \draw[gray!40,dashed] (B/bot/back)       -- (B/top/back);
  %% edges
  %% bottom box bottom edge
  \draw [blue]           (A/bot/side/left) -- (A/bot/front) -- (A/bot/side/right);
  \draw [gray!40,dashed] (A/bot/side/left) -- (A/bot/back) -- (A/bot/side/right);
  %% visible top of bottom box
  \draw [blue]           (A/top/side/left) -- 
                         (A/top/front)     --
                         (B/bot/front)     --
                         (B/bot/side/left) -- cycle;

  %% top box top edge
  \draw [blue]           (B/top/side/left) -- (B/top/front) -- (B/top/side/right) -- (B/top/back) -- cycle;
  %% top box bottom edge
  \draw [blue]           (B/bot/side/left) -- (B/bot/front) -- (B/bot/side/right);
  \draw [gray!40,dashed] (B/bot/side/left) -- (B/bot/back)  -- (B/bot/side/right);

\end{tikzpicture}

\end{document}

which produces:

enter image description here

share|improve this answer

Without totally rewriting all the magic numbers, one option would be to add some fill and slightly adjust the unit vectors helps:

enter image description here

Code:

\documentclass[tikz, convert = false, border=2pt]{standalone}%
\usetikzlibrary{calc}
\usetikzlibrary{intersections}

\tikzset{Hidden Line/.style={thin, gray!30}}


\begin{document}
\begin{tikzpicture}[x=1.5cm, y=0.7cm]
  \coordinate (O) at (0, 0);
  \coordinate (P1) at (0.35, 1);
  \coordinate (P2) at (1.35, 1);
  \coordinate (P3) at (1, 0);

  \draw[Hidden Line] (O) -- (P1) -- (P2);

  \path (O) -- (P3) node[pos = .5, font = \tiny, below] {$1$};



  \draw [fill=green!25, fill opacity=0.3] (O) -- +(0, .2) coordinate (P4) -- +(1, .2) coordinate (P5) --
      +(1, 0) -- cycle;

  \path  (P3) -- (P2)
      node[pos = .5, right, font = \tiny] {$1$}
      ;
  \path[name path = uil, red] (P5) -- ($(P2) + (0, .2)$) coordinate (P6) --
      +(0, -.2);
  \draw [fill=green!25, fill opacity=0.3, join=round]
      ($(P3) +(0, 0.2)$) --
      (P3) -- (P2) --
      ++(0, 0.2) --
      cycle
      ;

  \draw [Hidden Line] (P6) -- +(-1, 0) coordinate (P7);
  \draw [Hidden Line] (P7) -- (P1);

  \path[name path = uol] (P4) -- (P7);
  \path[name path = hl] (0, .35) -- +(1.25, 0);
  \path[name intersections = {of = uol and hl}];

  \coordinate (P8) at (intersection-1);

  \draw [Hidden Line] (P8) -- (P7);
  \draw  (P8) -- (P4);

  \path[name intersections = {of = uil and hl}];

  \coordinate (P9) at (intersection-1);

  \path  (P6) -- +(0, .2) coordinate (P12);
  \coordinate (P13) at ($(P12)+(-1, 0)$);
  \draw[Hidden Line, draw opacity=0.8] (P13) -- +(0, -.2);

  \draw [fill=red!40, fill opacity=0.5] (P9) -- (P8)
      (P8) -- +(0, .2) coordinate (P10) -- +(1, .2) coordinate (P11) --
      (P9);

  \draw [fill=red!20, fill opacity=0.7, join=round] (P11) -- (P12) -- (P13) -- (P10);

  \draw [fill=red!60, fill opacity=0.2, join=round] 
          (P6) -- ++(0, .2) -- 
          (P11) -- ++(0, -.2) -- cycle;
\end{tikzpicture}
\end{document}
share|improve this answer
    
Doesn't the back of the block look like it is wider than the front though? Mine does that too. –  dustin Apr 25 at 3:34
    
@dustin: Yeah, I think that is because you really need to apply a perspective view where the lines receding into the back are not parallel, but would meet if they were extended out much further. –  Peter Grill Apr 25 at 3:41

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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