LATEX

I have been recently become quite fond of LATEX (i.e. not the polymer), and have been extensively using tutorials and many examples; but of course, there always were problems for which I had to find the answers myself, and here I am sharing the tricks I used, in hope it could help others, the way I have been helped myself. So feel free to use it, to quote it, to distribute it if you think it's worth it...

Asymptote 3D

Asymptote is a specific language to describe drawings. You will find easily a lot of different examples on internet, but somehow, it took me some time to figure out how to draw beautiful crystal structures. Most of the time, expecially for 3D rotations in space, Jmol is better, but when a static image is sought for, Asymptote will deliver great results... here is just an example, step by step, so you'll be able to draw your own crystals...

Asymptote and LATEX

Asymptote is an independant language, so most of the examples you will find on internet are not immediately compatible with TEX. The preambule of an Asymptote file will most of the time be presented as:

import three;
import solids;

With LATEX, after you load the right package, you will need to write these declaration separately, so they'll will be used for all your figures, such as:

\usepackage{asymptote}

\begin{document}

\begin{asydef}
import three;
import solids;
\end{asydef}

The asymptote code will then be inserted later using the commands:

\begin{asy}
...
\end{asy}

You should then be aware of the way compiling your file will happen: first, running latex or pdflatex, a .asy file will be created; then you'll need to run the Asymptote compiler (pretty easy to find if you use Texmaker), but this compiler is not automatically installed, as it happens with the other latex packages: you need to install the Asymptote sofware separately.

You then need to re-run latex or pdflatex, so it can incorporate the compiled image in your final PDF. You also can configure, with TexMaker, the F1 key so that by pressing only this key, you will run consecutively all the steps.

Points declarations

If you have imported the 'three' package in Asymptote, a 'triple' class then exists, which allows the declaration of points with three coordinates. So you can declare the origin and three points along the three axis, as:

triple O=(0,0,0), X=(1,0,0), Y=(0,1,0), Z=(0,0,1);

You then can draw between these points:

draw(O--X);
draw(O--Y);
draw(O--Z);

At that point, if you tried to compile your file, you will see a picture so small that you will be strongly disapointed... We just need to add an argument, at the beginning of our `asy' declaration:

\begin{asy}[width=5cm]

And finally, because this is going to be your ordinate system, you can then put arrows and use colors to take more easily appart the three directions

draw(O--X,blue,Arrow3);
draw(O--Y,green,Arrow3);
draw(O--Z,red,Arrow3);
It would be great to put labels at the end of each arrow. This may be done through the following instructions:
label("$x$",X,blue);
label("$y$",Y,green);
label("$z$",Z,red);

But if you do this, your will actually write 'x', 'y' and 'z' centered at the exact end of your arrows, and so the labels overlapping the drawing will be difficult to read. A way to avoid this is to scale up the distance between the label and the origin, through the following commands:

label("$x$",scale3(1.1)*X,blue);
label("$y$",scale3(1.1)*Y,green);
label("$z$",scale3(1.1)*Z,red);
So this is what we have so far:

and to make sure you didn't miss anything, this is the complete code used to generate this image

\documentclass{article}

\usepackage{asymptote}

\begin{document}

\begin{asydef}
import three;
import solids;
\end{asydef}

\begin{asy}[width=5cm]
triple O=(0,0,0), X=(1,0,0), Y=(0,1,0), Z=(0,0,1);
draw(O--X,blue,Arrow3);
draw(O--Y,green,Arrow3);
draw(O--Z,red,Arrow3);
label("$x$",scale3(1.1)*X,blue);
label("$y$",scale3(1.1)*Y,green);
label("$z$",scale3(1.1)*Z,red);
\end{asy}

\end{document}

Spheres

The command to draw a sphere is actually extremely easy:

draw(unitsphere,gray);

But if you do this, you will draw at the origin a sphere which radius is equal to 1, and so your axis will be hidden. In order to avoid this, we will draw a smaller sphere, by setting the radius to 0.5, using once more the scale3 function:

draw(scale3(0.5)*unitsphere,gray);

Because we want here to draw a crystal structure, all our atoms will be centered at different places... so we need to change the center, and this is done through the shift function. The first thing we can do is to center the sphere at the location of a point we already have defined, e.g. X:

draw(shift(X)*scale3(0.5)*unitsphere,gray);

But we also can draw it without naming the point at which we center it. Here the sphere will be centered at (1,1,1), and in order for the axis system not to be partially hidden by it, I drew a smaller sphere with a 0.2 diameter:

draw(shift(1,1,1)*scale3(0.2)*unitsphere,gray);

For reasons that will be explained later, it is better to center the position of the unit cell at the point of origin. Imagine you want to represent at the scale the unit cell of copper, which is a Face Centered Cubic, which a cell parameter of 361.49 pm. The van der Waals radius of this atom is 140 pm (see e.g.http://www.webelements.com), so we could write a code such as this one, using the coordinates in Angstroms:

\begin{asy}[width=5cm]
triple O=(0,0,0), X=(1,0,0), Y=(0,1,0), Z=(0,0,1);
draw(O--X,blue,Arrow3);
draw(O--Y,green,Arrow3);
draw(O--Z,red,Arrow3);
label("$x$",scale3(1.1)*X,blue);
label("$y$",scale3(1.1)*Y,green);
label("$z$",scale3(1.1)*Z,red);

draw(shift(1.807,1.807,1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(-1.807,1.807,1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(1.807,-1.807,1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(1.807,1.807,-1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(-1.807,-1.807,1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(-1.807,1.807,-1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(1.807,-1.807,-1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(-1.807,-1.807,-1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(-1.807,0,0)*scale3(1.4)*unitsphere,lightred);
draw(shift(1.807,0,0)*scale3(1.4)*unitsphere,lightred);
draw(shift(0,-1.807,0)*scale3(1.4)*unitsphere,lightred);
draw(shift(0,1.807,0)*scale3(1.4)*unitsphere,lightred);
draw(shift(0,0,-1.807)*scale3(1.4)*unitsphere,lightred);
draw(shift(0,0,1.807)*scale3(1.4)*unitsphere,lightred);
\end{asy}

The 'lightred' color is so great for copper atoms! You would have noticed that we don't see the arrows anymore, and some of the atoms are hidden, because the atoms are actually too big. So, we will define a variable 'ars' (standing for atomic radius scale) at the begining of our 'asy' section as follow:

real ars=0.4;

and later on, all the atoms should be written as:

draw(shift(1.807,1.807,1.807)*scale3(1.4*ars)*unitsphere,lightred);

Using this method, if you are not fully satisfied with the result, instead of re-typing all the diameters for each atom, you will just need to change the value of the ars variable; in the same time, if you have different types of atoms, you won't need to calculate "what is 40% of the diameter of that atom?", and won't make any mistakes... We could also have declared a variable for the lattice parameter, and for the atomic radius, the file could then have been easily portable for any other FCC structure.

At that point, I think I don't really need the arrows, but that it would be great to have the cell limits:

draw((1.807,1.807,1.807)--(-1.807,1.807,1.807)--(-1.807,-1.807,1.807)-- (1.807,-1.807,1.807)--cycle);
draw((1.807,1.807,-1.807)--(-1.807,1.807,-1.807)--(-1.807,-1.807,-1.807)-- (1.807,-1.807,-1.807)--cycle);
draw((1.807,1.807,1.807)--(1.807,1.807,-1.807));
draw((-1.807,1.807,1.807)--(-1.807,1.807,-1.807));
draw((1.807,-1.807,1.807)--(1.807,-1.807,-1.807));
draw((-1.807,-1.807,1.807)--(-1.807,-1.807,-1.807));

and at the same time, we could put dashed or dotted lines to mark the center of each face:

draw((1.807,1.807,1.807)--(-1.807,-1.807,1.807),dotted);

or

draw((1.807,1.807,1.807)--(-1.807,-1.807,1.807),dotted);
draw((1.807,-1.807,1.807)--(-1.807,1.807,1.807),dotted);
draw((1.807,1.807,-1.807)--(-1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,-1.807)--(-1.807,1.807,-1.807),dotted);

draw((1.807,1.807,1.807)--(1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,1.807)--(1.807,1.807,-1.807),dotted);
draw((-1.807,1.807,1.807)--(-1.807,-1.807,-1.807),dotted);
draw((-1.807,-1.807,1.807)--(-1.807,1.807,-1.807),dotted);

draw((1.807,1.807,1.807)--(-1.807,1.807,-1.807),dotted);
draw((1.807,1.807,-1.807)--(-1.807,1.807,1.807),dotted);
draw((1.807,-1.807,1.807)--(-1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,-1.807)--(-1.807,-1.807,1.807),dotted);

Light

There are many predefined light systems; we will see some of them in the next section, but you can also define your own. Here is a light-coding I found browsing the web:

currentlight=light(gray(0.4),specularfactor=3,viewport=false,
(-0.5,-0.25,0.45),(0.5,-0.5,0.5),(0.5,0.5,0.75));

Adding this code at the beginnig of your 'asy' section will produce the following result:

3D animation

When opening the PDF with acrobat reader, you should see a message telling you to click to activate;

We are now going to add just one more line, in the 'asydef' section:

settings.toolbar=true;

which will add a control bar when the figure is active. Dragging the object, you can change the orientation, but also change the lightning, and other option, as mentionned earlier:

and with another lighting:

Perspective

Last, you can also adjust the projection; by default, you have a perspective, and its parameters may be adjusted. Also, you may prefer an orthographic projection, by adding the following line:

currentprojection=orthographic(5,4,2);

which yields:

Final code

Just to make sure you've got it all right, here is the complete final file:

\documentclass{article}

\usepackage{asymptote}

\begin{document}

\begin{asydef}
import three;
import solids;
settings.toolbar=true;
\end{asydef}

\begin{asy}[width=5cm]
currentprojection=orthographic(5,4,2);
currentlight=light(gray(0.4),specularfactor=3,viewport=false,
(-0.5,-0.25,0.45),
(0.5,-0.5,0.5),(0.5,0.5,0.75));
real ars=0.4;

draw(shift(1.807,1.807,1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(-1.807,1.807,1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(1.807,-1.807,1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(1.807,1.807,-1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(-1.807,-1.807,1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(-1.807,1.807,-1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(1.807,-1.807,-1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(-1.807,-1.807,-1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(-1.807,0,0)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(1.807,0,0)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(0,-1.807,0)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(0,1.807,0)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(0,0,-1.807)*scale3(1.4*ars)*unitsphere,lightred);
draw(shift(0,0,1.807)*scale3(1.4*ars)*unitsphere,lightred);

draw((1.807,1.807,1.807)--(-1.807,1.807,1.807)--(-1.807,-1.807,1.807)-- (1.807,-1.807,1.807)--cycle);
draw((1.807,1.807,-1.807)--(-1.807,1.807,-1.807)--(-1.807,-1.807,-1.807)-- (1.807,-1.807,-1.807)--cycle);
draw((1.807,1.807,1.807)--(1.807,1.807,-1.807));
draw((-1.807,1.807,1.807)--(-1.807,1.807,-1.807));
draw((1.807,-1.807,1.807)--(1.807,-1.807,-1.807));
draw((-1.807,-1.807,1.807)--(-1.807,-1.807,-1.807));

draw((1.807,1.807,1.807)--(-1.807,-1.807,1.807),dotted);
draw((1.807,-1.807,1.807)--(-1.807,1.807,1.807),dotted);
draw((1.807,1.807,-1.807)--(-1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,-1.807)--(-1.807,1.807,-1.807),dotted);

draw((1.807,1.807,1.807)--(1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,1.807)--(1.807,1.807,-1.807),dotted);
draw((-1.807,1.807,1.807)--(-1.807,-1.807,-1.807),dotted);
draw((-1.807,-1.807,1.807)--(-1.807,1.807,-1.807),dotted);

draw((1.807,1.807,1.807)--(-1.807,1.807,-1.807),dotted);
draw((1.807,1.807,-1.807)--(-1.807,1.807,1.807),dotted);
draw((1.807,-1.807,1.807)--(-1.807,-1.807,-1.807),dotted);
draw((1.807,-1.807,-1.807)--(-1.807,-1.807,1.807),dotted);

\end{asy}

\end{document}