% -------------------
% Package tikzorbital
% -------------------
%
% This package provides several commands in order to draw atomic orbitals and
% molecular diagrams.
%
% Germain Vallverdu <
[email protected]>
% 05 decembre 2012
%
http://gvallver.perso.univ-pau.fr/
%
% Licence : LaTeX Project Public Licence
%
http://www.latex-project.org/lppl.txt
%
% Feel free to contact me if you have any ideas, suggestions or bugs report !
%
% Change
% ------
% 27/02/2013 : add -px, -py, -pz orbital type
% 05/03/2015 : add satom macro, with scaling options for each lobe
%
% -----------------------------------------------------------------------------
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{tikzorbital}[2012/12/05 draw atomic orbitals and molecular diagrams with tikz]
% -----------------------------------------------------------------------------
\RequirePackage{tikz}
\usetikzlibrary{shapes}
\RequirePackage{ifthen}
\pgfdeclarelayer{background}
\pgfdeclarelayer{main}
\pgfdeclarelayer{foreground}
\pgfsetlayers{background,main,foreground}
% -----------------------------------------------------------------------------
% keys in order to submit tikz command to macro
% -----------------------------------------------------------------------------
\pgfkeys{/tikz/.cd,
execute style/.style = {#1},
execute macro/.style = {execute style/.expand once=#1}
}
% -----------------------------------------------------------------------------
% commande \drawLevel[key = value]{name}
% -----------------------------------------------------------------------------
% draw a level with a given name in order to draw molecular diagrams
%
% argument
% name : base name of level anchor.
%
% options
% elec : Number of electrons : up, down, updown or pair
% pos : left position of the level
% width : level widht
% style : level style (a tikzstyle)
% spinstyle : style of arrows which represents electrons (a tikzstyle)
% spinlength : length of spin arrows
% -----------------------------------------------------------------------------
\pgfkeys{/tikzorbital/drawLevel/.cd,
% number of electron in the level : up, down, updown or pair
elec/.store in = \drawLevel@elec,
elec/.default = no,
% position of the left anchor of the level
pos/.store in = \drawLevel@pos,
pos/.default = {(0,0)},
% width of levels
width/.store in = \drawLevel@width,
width/.default = 2,
% style of levels
style/.store in = \drawLevel@style,
style/.default = {line width = 2pt, color = black!80, line cap = round},
% style of arrows
spinstyle/.store in = \drawLevel@spinstyle,
spinstyle/.default = {very thick, color = red!80, -stealth},
% length of spin arrows
spinlength/.store in = \drawLevel@spinlength,
spinlength/.default = 1,
% execute options
elec, pos, width, style, spinstyle, spinlength
}
% the drawLevel command
\newcommand{\drawLevel}[2][]{%
\begingroup
\pgfkeys{/tikzorbital/drawLevel/.cd, #1}
\def\drawLevel@name{#2}
\draw[execute macro = \drawLevel@style]
\drawLevel@pos
node (left \drawLevel@name) {}
-- ++ (\drawLevel@width, 0)
node (right \drawLevel@name) {}
node[pos=0.5] (middle \drawLevel@name) {}
node[pos=0.3] (pos1) {}
node[pos=0.7] (pos2) {};
\ifthenelse{\equal{\drawLevel@elec}{updown} \or \equal{\drawLevel@elec}{pair}}{
\draw[execute macro = \drawLevel@spinstyle]
(pos1.center) ++ (0,-\drawLevel@spinlength/2) --
++ (0,\drawLevel@spinlength);
\draw[execute macro = \drawLevel@spinstyle]
(pos2.center) ++ (0, \drawLevel@spinlength/2) --
++ (0,-\drawLevel@spinlength);
}{
\ifthenelse{\equal{\drawLevel@elec}{up}}{
\draw[execute macro = \drawLevel@spinstyle]
(middle #2.center) ++ (0,-\drawLevel@spinlength/2) --
++ (0,\drawLevel@spinlength);
}{
\ifthenelse{\equal{\drawLevel@elec}{down}}{
\draw[execute macro = \drawLevel@spinstyle]
(middle #2.center) ++(0,\drawLevel@spinlength/2) --
++ (0,-\drawLevel@spinlength);
}{
}
}
}
\endgroup
}
% -----------------------------------------------------------------------------
% some customization of orbital
% -----------------------------------------------------------------------------
% inner color for orbital filling
\colorlet{innerColor}{black!10}
% color for orbital drawing
\colorlet{drawColor}{black!80}
% more style for lobe orbital drawing
\newcommand{\setOrbitalDrawing}[1]{\def\orbitalDrawing{#1}}
\setOrbitalDrawing{thick}
% -----------------------------------------------------------------------------
% inner \@alobe command
% -----------------------------------------------------------------------------
% Draw one lobe of a p or d atomic orbital, at a given position with a given scale,
% color, rotation and opacity. Draw zero, one or two balls which represent electrons.
%
% arguments
% #1 : position
% #2 : rotation
% #3 : scale
% #4 : color
% #5 : number of electron
% #6 : opacity
% -----------------------------------------------------------------------------
\newcommand{\@alobe}[6]{
\begin{scope}[rotate around = {#2:#1}]
% draw orbital lobe
\begin{pgfonlayer}{background}
\draw[draw = drawColor, outer color = #4, inner color = innerColor,
opacity = #6, execute macro = \orbitalDrawing]
#1 .. controls ++ (#3, #3) and ++ (#3, - #3) .. #1;
\end{pgfonlayer}
%Coordinates of the electrons
\path #1 ++ (0.50 * #3, 0) node (e1) {};
\path #1 ++ (0.25 * #3, 0) node (e2) {};
\end{scope}
% Draw the electrons
\ifnum#5>0
\foreach \n in {1,...,#5} {
\shade[ball color = #4] (e\n) circle (1mm);
}
\fi
}
% -----------------------------------------------------------------------------
% commande \orbital[key = value]{type}
% -----------------------------------------------------------------------------
% draw an atomic orbital of a given type.
%
% argument
% type : lobe, s, px, py, pz, dxz, dyz, dxy, dz2, dx2y2
%
% options
% pos : left position of the level
% pcolor : color of the positive lobe
% ncolor : color of the negative lobe
% scale : scaling factor
% opacity : opacity of the orbital
% rotate : rotate of the AO (lobe type only)
% nelec : number of electron (lobe type only)
% -----------------------------------------------------------------------------
% define options
\pgfkeys{/tikzorbital/orbital/.cd,
% position of the orbital
pos/.store in = \orbital@pos,
pos/.default = {(0,0)},
% color of the positive lobe
pcolor/.store in = \orbital@pcolor,
pcolor/.default = blue,
% color of the negative lobe
ncolor/.store in = \orbital@ncolor,
ncolor/.default = black!30,
% color for s type
color/.store in = \orbital@color,
color/.default = empty,
% scale factor
scale/.store in = \orbital@scale,
scale/.default = 1,
% opacity of the orbital
opacity/.store in = \orbital@opacity,
opacity/.default = 1.,
% lobe type options
% rotation of the orbital
rotate/.store in = \orbital@rotate,
rotate/.default = 0,
% number of electrons
nelec/.store in = \orbital@nelec,
nelec/.default = 0,
% execute options
pos, pcolor, ncolor, scale, opacity, rotate, nelec, color
}
% orbital command
\newcommand{\orbital}[2][]{
\begingroup
\pgfkeys{/tikzorbital/orbital/.cd, #1}
% orbital type
\def\orbital@type{#2}
% general style
\tikzstyle{base} = [draw = drawColor, thick, inner color = innerColor,
circle, opacity = \orbital@opacity,
execute macro = \orbitalDrawing]
% check if color was setted
\ifthenelse{\equal{\orbital@color}{empty}}{
\pgfkeys{/tikzorbital/orbital/.cd, color = \orbital@pcolor}
}{}
% draw the whished orbital
\ifthenelse{\equal{\orbital@type}{lobe}}{
\@alobe{\orbital@pos}{\orbital@rotate}{\orbital@scale}{\orbital@color}{\orbital@nelec}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{py}}{
\@alobe{\orbital@pos}{0}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{180}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{-py}}{
\@alobe{\orbital@pos}{180}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{0}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{pz}}{
\@alobe{\orbital@pos}{90}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{270}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{-pz}}{
\@alobe{\orbital@pos}{270}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{90}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{px}}{
\node[base, outer color = \orbital@ncolor, scale = \orbital@scale * 1.8,
xshift = 2pt, yshift = 2pt] at \orbital@pos {};
\node[base, outer color = \orbital@pcolor, scale = \orbital@scale * 1.8]
at \orbital@pos {};
}{
\ifthenelse{\equal{\orbital@type}{-px}}{
\node[base, outer color = \orbital@pcolor, scale = \orbital@scale * 1.8,
xshift = 2pt, yshift = 2pt] at \orbital@pos {};
\node[base, outer color = \orbital@ncolor, scale = \orbital@scale * 1.8]
at \orbital@pos {};
}{
\ifthenelse{\equal{\orbital@type}{dyz}}{
\@alobe{\orbital@pos}{45}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{135}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{225}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{315}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{dxz}}{
\@alobe{\orbital@pos}{80}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{280}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{100}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{260}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{dxy}}{
\@alobe{\orbital@pos}{10}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{170}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{350}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{190}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{dx2y2}}{
\begin{pgfonlayer}{background}
\node[base, outer color = \orbital@pcolor, scale = \orbital@scale * 1.8,
xshift = 2pt, yshift = 2pt] at \orbital@pos {};
\end{pgfonlayer}
\@alobe{\orbital@pos}{0}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
\@alobe{\orbital@pos}{180}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
\node[base, outer color = \orbital@pcolor, scale = \orbital@scale * 1.8]
at \orbital@pos {};
}{
\ifthenelse{\equal{\orbital@type}{dz2}}{
\@alobe{\orbital@pos}{270}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
\begin{pgfonlayer}{background}
\node[ellipse, minimum width = \orbital@scale * .8cm,
minimum height = \orbital@scale * .3cm, draw = drawColor,
inner color = innerColor, outer color = \orbital@ncolor,
execute macro = \orbitalDrawing]
at \orbital@pos {};
\end{pgfonlayer}
\@alobe{\orbital@pos}{90}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
}{
\ifthenelse{\equal{\orbital@type}{s}}{
\node[base, outer color = \orbital@color, scale = \orbital@scale * 1.8]
at \orbital@pos {};
}{
\node[red] at \orbital@pos {orbital type unknown};
}}}}}}}}}}}}}
\endgroup
}
%
% other possibility for dxy and dxz atomic orbital
% ------------------------------------------------
%
% dxz
% \begin{scope}[xshift = 2.2pt, yshift = 2pt]
% \@alobe{\orbital@pos}{90}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
% \@alobe{\orbital@pos}{270}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
% \end{scope}
% \@alobe{\orbital@pos}{90}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
% \@alobe{\orbital@pos}{270}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
%
% dxy
% \begin{scope}[xshift = 2.2pt, yshift = 2pt]
% \@alobe{\orbital@pos}{10}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
% \@alobe{\orbital@pos}{170}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
% \end{scope}
% \@alobe{\orbital@pos}{350}{\orbital@scale}{\orbital@pcolor}{0}{\orbital@opacity}
% \@alobe{\orbital@pos}{190}{\orbital@scale}{\orbital@ncolor}{0}{\orbital@opacity}
%
% -------------------------------------------------
% -----------------------------------------------------------------------------
% commande \atom[options]{lobes}
% -----------------------------------------------------------------------------
% quickly draw an atom with several orbital lobes around it.
% DEPRECATED, use satom insteed.
%
% argument
% lobes : A comma separated list lobe definition with
% color/rotation-angle/anchor/number of electrons
%
% options
% pos : position of the atom
% name : name of the atom, also used to label the node
% color : color of the atom
% opacity : opacity of the orbital
% scale : scaling factor
% -----------------------------------------------------------------------------
% define options
\pgfkeys{/tikzorbital/atom/.cd,
% position of the atom
pos/.store in = \atom@pos,
pos/.default = {(0,0)},
% atom name
name/.store in = \atom@name,
name/.default = X,
% color of the atom
color/.store in = \atom@color,
color/.default = green,
% opacity of the orbitals
opacity/.store in = \atom@opacity,
opacity/.default = .8,
% scaling factor
scale/.store in = \atom@scale,
scale/.default = 1.,
% execute options
pos, name, color, opacity, scale
}
% atom definition
\newcommand{\atom}[2][]{
\begingroup
\pgfkeys{/tikzorbital/atom/.cd, #1}
\colorlet{atomColor}{\atom@color}
\node[shape = circle, thick, inner sep = 0pt, minimum size = 1.5em,
draw = atomColor!40, color = atomColor!70!gray, fill = atomColor!20,
scale = \atom@scale]
at \atom@pos (\atom@name) {\atom@name};
\def\s{1.}
\foreach \acolor/\rot/\anchor/\Ne in {#2} {
\@alobe{(\atom@name.\anchor)}{\rot}{1.5*\atom@scale}{\acolor}{\Ne}{\atom@opacity}
}
\endgroup
}
% -----------------------------------------------------------------------------
% commande \satom[options]{lobes}
% -----------------------------------------------------------------------------
% quickly draw an atom with several orbital lobes around it
%
% argument
% lobes : A comma separated list lobe definition with
% color/rotation-angle/anchor/number of electrons/scale
%
% options
% pos : position of the atom
% name : name of the atom, also used to label the node
% color : color of the atom
% opacity : opacity of the orbital
% scale : global scaling factor
% -----------------------------------------------------------------------------
% define options
\pgfkeys{/tikzorbital/satom/.cd,
% position of the atom
pos/.store in = \satom@pos,
pos/.default = {(0,0)},
% atom name
name/.store in = \satom@name,
name/.default = X,
% color of the atom
color/.store in = \satom@color,
color/.default = green,
% opacity of the orbitals
opacity/.store in = \satom@opacity,
opacity/.default = .8,
% scaling factor
scale/.store in = \satom@scale,
scale/.default = 1.,
% execute options
pos, name, color, opacity, scale
}
% atom definition
\newcommand{\satom}[2][]{
\begingroup
\pgfkeys{/tikzorbital/satom/.cd, #1}
\colorlet{atomColor}{\satom@color}
\node[shape = circle, thick, inner sep = 0pt, minimum size = 1.5em,
draw = atomColor!40, color = atomColor!70!gray, fill = atomColor!20,
scale = \satom@scale]
at \satom@pos (\satom@name) {\satom@name};
\foreach \acolor/\rot/\anchor/\Ne/\s in {#2} {
\@alobe{(\satom@name.\anchor)}{\rot}{1.5*\s*\atom@scale}{\acolor}{\Ne}{\satom@opacity}
}
\endgroup
}
%% end of file %%