25

I am working in the field of Nanostructures and have to draw many figure like : enter image description here enter image description here

2
  • 7
    It's generally good to show what you've tried so far... have you looked at the manual for pst-3d?
    – cmhughes
    May 4, 2012 at 8:52
  • Considering the solution provided is exactly what you asked for, and extremely well explained, it seems unkind (to say the least) not to accept that answer neither thank him.
    – felixgaal
    May 26, 2012 at 13:34

1 Answer 1

83

How about this:

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}
\usetikzlibrary{3d}


\begin{document}

\pgfmathtruncatemacro{\tubelength}{5} % in "double hexagon lengths"
\pgfmathtruncatemacro{\tubecirumferenceatoms}{12} 
\pgfmathsetmacro{\tuberadius}{3}
\newcommand{\carboncolor}{red}
\newcommand{\bondcolor}{black}

\tikzset{yzplane/.style={canvas is yz plane at x=#1,very thin}}

\begin{tikzpicture}[x={(-0.2cm,-0.5cm)}, y={(1cm,0cm)}, z={(0cm,1cm)}]
\foreach \x in {1,...,\tubelength}
{ \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\ycoord}{cos(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \draw[thick,\bondcolor] (\x*3+0.5,\ycoord,\zcoord) -- (\x*3+1.5,\ycoord,\zcoord);
    }
    \begin{scope}[yzplane=\x*3+0.5]
        \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \shade[ball color=\carboncolor] (\y/\tubecirumferenceatoms*360:\tuberadius) circle (0.2) ;
    }
    \end{scope}

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\ycoord}{cos(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordtwo}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoordtwo}{sin(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\rotanglethree}{\y/\tubecirumferenceatoms*360-360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordthree}{cos(\rotanglethree)*\tuberadius}
        \pgfmathsetmacro{\zcoordthree}{sin(\rotanglethree)*\tuberadius}
        \draw[thick,\bondcolor] (\x*3+1.5,\ycoord,\zcoord) -- (\x*3+2,\ycoordtwo,\zcoordtwo);
        \draw[thick,\bondcolor] (\x*3+1.5,\ycoord,\zcoord) -- (\x*3+2,\ycoordthree,\zcoordthree);
    }
    \begin{scope}[yzplane=\x*3+1.5]
        \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \shade[ball color=\carboncolor] (\y/\tubecirumferenceatoms*360:\tuberadius) circle (0.2);
    }
    \end{scope}

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoord}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\rotangle)*\tuberadius}
        \draw[thick,\bondcolor] (\x*3+2,\ycoord,\zcoord) -- (\x*3+3,\ycoord,\zcoord);
    }
    \begin{scope}[yzplane=\x*3+2]
        \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \shade[ball color=\carboncolor] (\rotangle:\tuberadius) circle (0.2);
    }
    \end{scope}

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\ycoord}{cos(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordtwo}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoordtwo}{sin(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\rotanglethree}{\y/\tubecirumferenceatoms*360-360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordthree}{cos(\rotanglethree)*\tuberadius}
        \pgfmathsetmacro{\zcoordthree}{sin(\rotanglethree)*\tuberadius}
        \draw[thick,\bondcolor] (\x*3+3.5,\ycoord,\zcoord) -- (\x*3+3,\ycoordtwo,\zcoordtwo);
        \draw[thick,\bondcolor] (\x*3+3.5,\ycoord,\zcoord) -- (\x*3+3,\ycoordthree,\zcoordthree);
    }
    \begin{scope}[yzplane=\x*3+3]
        \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \shade[ball color=\carboncolor] (\rotangle:\tuberadius) circle (0.2);
    }
    \end{scope}


}
\end{tikzpicture}

\end{document}

You can modify a few things:

  • The length of the tube (multiples of 4 atoms)

  • The amount of atoms on one circle

  • The radius of the tube

  • The color of the atoms

  • The color of the bonds

The above produces:

enter image description here


Edit 1: If you play around with the settings, e.g. like

\pgfmathtruncatemacro{\tubelength}{20} % in "double hexagon lengths"
\pgfmathtruncatemacro{\tubecirumferenceatoms}{20} 
\pgfmathsetmacro{\tuberadius}{4}
\newcommand{\carboncolor}{red!80!black}
\newcommand{\bondcolor}{blue!20!black}

you get this, which looks a lot "nanotubier":

enter image description here


Edit 2:

  • The "back" atoms now fade to white, the "back" bonds now fade to gray
  • As I don't know which atoms will be in the back (depends on your choice of xyz-axes), I added a key \initialrotationangle which rotates the tube by that angle, you'll have to find a good value yourself
  • Before, the "bondlength" was a static value of 1, which looked bad for small radii, so now it's computed dynamically (it does not account for the curvature of the cylinder, so it might look bad for very small values of \tubecircumferenceatoms)
  • The atom size also was static before, now you can specify it as a fraction of the bondlength. You can set this fraction to zero to have just the "bond net" without any atoms
  • As I computed the coordinates for the bonds anyway, I now compute the ones for the atoms as well and therefore got rid of the 3D library if TikZ
  • You can now influence the look of the bonds, e.g. thin or dashed to your liking

And here's the new code. I'm aware that I have several loops running over \y, but I can not put everything in one loop, as their order is important for drawing foreground and background things.

\documentclass[parskip]{scrartcl}
\usepackage[margin=15mm]{geometry}
\usepackage{tikz}

\begin{document}

\pgfmathtruncatemacro{\tubelength}{10} % in "double hexagon lengths"
\pgfmathtruncatemacro{\tubecirumferenceatoms}{12} 
\pgfmathsetmacro{\tuberadius}{3}
\newcommand{\carboncolor}{red}
\newcommand{\bondcolor}{blue}
\pgfmathsetmacro{\initialrotationangle}{270}
\pgfmathsetmacro{\atombondlengthfraction}{0.2}
\newcommand{\bonddrawoptions}{thin}

\begin{tikzpicture}[x={(-0.2cm,-0.5cm)}, y={(1cm,0cm)}, z={(0cm,1cm)}, scale=0.5]
\foreach \x in {1,...,\tubelength}
{ \pgfmathsetmacro{\bondlength}{2*3.14159265*\tuberadius/sqrt(3)/\tubecirumferenceatoms}
    \pgfmathsetmacro{\atomradius}{\bondlength*\atombondlengthfraction}
    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360}
        \pgfmathsetmacro{\ycoord}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\rotangle)*\tuberadius}
        \pgfmathtruncatemacro{\shadingcolor}{50*cos(\rotangle+\initialrotationangle)+50}
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+0.5*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+1.5*\bondlength,\ycoord,\zcoord);
        \shade[ball color=\carboncolor!\shadingcolor] (\x*3*\bondlength+0.5*\bondlength,\ycoord,\zcoord) circle (\atomradius*1cm) ;
    }

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {
        \pgfmathsetmacro{\ycoord}{cos(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordtwo}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoordtwo}{sin(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\rotanglethree}{\y/\tubecirumferenceatoms*360-360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordthree}{cos(\rotanglethree)*\tuberadius}
        \pgfmathsetmacro{\zcoordthree}{sin(\rotanglethree)*\tuberadius}
        \pgfmathtruncatemacro{\shadingcolor}{50*cos(\rotangle+\initialrotationangle)+50}
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+1.5*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+2*\bondlength,\ycoordtwo,\zcoordtwo);
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+1.5*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+2*\bondlength,\ycoordthree,\zcoordthree);
        \shade[ball color=\carboncolor!\shadingcolor] (\x*3*\bondlength+1.5*\bondlength,\ycoord,\zcoord) circle (\atomradius*1cm);
    }

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoord}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\rotangle)*\tuberadius}
        \pgfmathtruncatemacro{\shadingcolor}{50*cos(\rotangle+\initialrotationangle)+50}
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+2*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+3*\bondlength,\ycoord,\zcoord);
        \shade[ball color=\carboncolor!\shadingcolor] (\x*3*\bondlength+2*\bondlength,\ycoord,\zcoord) circle (\atomradius*1cm);
    }

    \foreach \y in {1,...,\tubecirumferenceatoms}
    {   \pgfmathsetmacro{\ycoord}{cos(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\zcoord}{sin(\y/\tubecirumferenceatoms*360)*\tuberadius}
        \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordtwo}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoordtwo}{sin(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\rotanglethree}{\y/\tubecirumferenceatoms*360-360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordthree}{cos(\rotanglethree)*\tuberadius}
        \pgfmathsetmacro{\zcoordthree}{sin(\rotanglethree)*\tuberadius}
        \pgfmathtruncatemacro{\shadingcolor}{50*cos(\rotangle+\initialrotationangle)+50}
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+3.5*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+3*\bondlength,\ycoordtwo,\zcoordtwo);
        \draw[\bonddrawoptions,\bondcolor!\shadingcolor!gray] (\x*3*\bondlength+3.5*\bondlength,\ycoord,\zcoord) -- (\x*3*\bondlength+3*\bondlength,\ycoordthree,\zcoordthree);
    }
    \foreach \y in {1,...,\tubecirumferenceatoms}
    { \pgfmathsetmacro{\rotangle}{\y/\tubecirumferenceatoms*360+360/2/\tubecirumferenceatoms}
        \pgfmathsetmacro{\ycoordtwo}{cos(\rotangle)*\tuberadius}
        \pgfmathsetmacro{\zcoordtwo}{sin(\rotangle)*\tuberadius}
        \pgfmathtruncatemacro{\shadingcolor}{50*cos(\rotangle+\initialrotationangle)+50}
        \shade[ball color=\carboncolor!\shadingcolor] (\x*3*\bondlength+3*\bondlength,\ycoordtwo,\zcoordtwo) circle (\atomradius*1cm);
    }

}
\end{tikzpicture}

\end{document}

And a few samples:

enter image description here

And just the bonds:

enter image description here

7
  • 15
    Awesome! How about sending it to texample.net?
    – Speravir
    May 5, 2012 at 22:31
  • Probably, but not yet. It still has several flaws that I want to work out first, and I think I can simplify it quite a bit. So maybe when I'm done. May 5, 2012 at 22:33
  • I cannot differentiate the front parts from the rear ones. Is it possible to improve this appearance issue? May 6, 2012 at 2:32
  • I'm working on it. It will fade the color to white for the "back" atoms. May 6, 2012 at 11:05
  • Absolutely amazing! May 6, 2012 at 12:32

You must log in to answer this question.

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