1

I want to create some chemical Lewis structures with TikZ - I can't use chemfig for this since I need to draw the atoms according to their coordinates - and need to define some custom bond types, for example wedge-shaped bonds and dashed-wedge-shaped bonds. Decorations seemed like the natural way to do this (if someone knows a better way, I'm open to suggestions) and managed to get something working. I've done it in such a way that the bond is surrounded by some white-space in order to make it look right in situations where two bonds might overlap (I've colored the white-space blue to make it visible in my example code). To make it look a little prettier I wanted to use rounded corners but unfortunately these don't seem to work properly in my decoration. How can I get the rounded corners to work?

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations}

\begin{document}

\begin{tikzpicture}

\newlength{\dashedwedgelen}
\setlength{\dashedwedgelen}{5pt}

\newlength{\wedgeheight}
\setlength{\wedgeheight}{2.5pt}

\pgfmathsetmacro\startheight{\wedgeheight/5}
\pgfmathsetmacro\whitespace{\wedgeheight/2}
\pgfmathsetmacro\dashgapratio{0.3}

\pgfdeclaredecoration{dashed wedge}{initial}
{
  \state{initial}[
  width=0.0,
  persistent precomputation={
    \pgfmathsetmacro\dashseglen{(\pgfdecoratedpathlength - \dashgapratio*\dashedwedgelen) / floor((\pgfdecoratedpathlength - \dashgapratio*\dashedwedgelen)/\dashedwedgelen)}},
  next state=body
  ]
  {
    % surrounding white space
    \color{blue}
    \pgfpathmoveto{\pgfpoint{0}{\startheight + \whitespace}}
    \pgfpathlineto{\pgfpoint{\pgfdecoratedpathlength}{\wedgeheight + \whitespace}}
    \pgfpathlineto{\pgfpoint{\pgfdecoratedpathlength}{-(\wedgeheight + \whitespace)}}
    \pgfpathlineto{\pgfpoint{0}{-(\startheight + \whitespace)}}
    \pgfpathlineto{\pgfpoint{0}{\startheight + \whitespace}}
    \pgfclosepath
    \pgfusepath{fill, stroke}
    \pgfpathmoveto{\pgfpointdecoratedinputsegmentlast}
  }
  \state{body}[width=\dashseglen]
  {
    % computations
    \pgfmathsetmacro\segwidth{\dashgapratio*\dashseglen}
    \pgfmathsetmacro\segstartheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance) / \pgfdecoratedpathlength}
    \pgfmathsetmacro\segendheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance + \dashgapratio*\dashseglen) / \pgfdecoratedpathlength}
    % drawing
    \pgfpathmoveto{\pgfpoint{0}{\segstartheight}}
    \pgfpathlineto{\pgfpoint{\segwidth}{\segendheight}}
    \pgfpathlineto{\pgfpoint{\segwidth}{-\segendheight}}
    \pgfpathlineto{\pgfpoint{0}{-\segstartheight}}
    \pgfpathlineto{\pgfpoint{0}{\segstartheight}}
    \pgfpathclose
  }
  \state{final}
  { 
    % computations
    \pgfmathsetmacro\segwidth{\dashgapratio*\dashseglen}
    \pgfmathsetmacro\segstartheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance) / \pgfdecoratedpathlength}
    \pgfmathsetmacro\segendheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance + \dashgapratio*\dashseglen) / \pgfdecoratedpathlength}
    % drawing
    \pgfpathmoveto{\pgfpoint{0}{\segstartheight}}
    \pgfpathlineto{\pgfpoint{\segwidth}{\segendheight}}
    \pgfpathlineto{\pgfpoint{\segwidth}{-\segendheight}}
    \pgfpathlineto{\pgfpoint{0}{-\segstartheight}}
    \pgfpathlineto{\pgfpoint{0}{\segstartheight}}
    \pgfpathclose
    \pgfmoveto{\pgfpointdecoratedpathlast}
  }
}

\node (x) at (0,0) [rectangle, rounded corners=0.8mm, fill = blue, inner sep=0.1mm, scale=2.5] {Ti};
\node (y) at (1.5,0.) [rectangle, rounded corners=0.8mm, fill = blue, inner sep=0.1mm, scale=2.5] {L};

\fill [red, decorate, decoration=dashed wedge, rounded corners=0.5pt] (x) -- (y);

\end{tikzpicture}

\end{document}

enter image description here

  • 1
    I think the problem is that you explicitly draw a line and close the path. If you remove the \pgfpathlineto before each \pgfclosepath then the problem may go away. – Mark Wibrow Sep 12 '14 at 12:27
  • @MarkWibrow Thank you very much. This indeed works like a charm. – Philipp Sep 12 '14 at 17:47
2

The problem is that you explicitly draw a line and close the path. If you remove the \pgfpathlineto before each \pgfclosepath then the problem goes away.

It is also possible to make the code a teensy bit more efficient by using \pgfqpoint (which doesn't use the math parser) and \pgfmathsetlengthmacro (to make sure parsed expressions stored in macros end in pt).

\documentclass{standalone}

\usepackage{tikz}
\usetikzlibrary{decorations}

\begin{document}

\begin{tikzpicture}

\newlength{\dashedwedgelen}
\setlength{\dashedwedgelen}{5pt}

\newlength{\wedgeheight}
\setlength{\wedgeheight}{2.5pt}

\pgfmathsetmacro\startheight{\wedgeheight/5}
\pgfmathsetmacro\whitespace{\wedgeheight/2}
\pgfmathsetmacro\dashgapratio{0.3}

\pgfdeclaredecoration{dashed wedge}{initial}
{
  \state{initial}[
  width=0.0,
  persistent precomputation={
    \pgfmathsetmacro\dashseglen{(\pgfdecoratedpathlength - \dashgapratio*\dashedwedgelen) / floor((\pgfdecoratedpathlength - \dashgapratio*\dashedwedgelen)/\dashedwedgelen)}%
    %
    \pgfmathsetlengthmacro\wedgeheight{\wedgeheight}%
    \pgfmathsetlengthmacro\startheight{\startheight}%
    \pgfmathsetlengthmacro\whitespace{\whitespace}%
    },
  next state=body
  ]
  {
    % surrounding white space
    \pgfmathsetlengthmacro\beginheight{\startheight+\whitespace}
    \pgfmathsetlengthmacro\endheight{\wedgeheight + \whitespace}
    \pgfpathmoveto{\pgfqpoint{0pt}{\beginheight}}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedpathlength}{\endheight}}
    \pgfpathlineto{\pgfqpoint{\pgfdecoratedpathlength}{-\endheight}}
    \pgfpathlineto{\pgfqpoint{0pt}{-\beginheight}}
    \pgfclosepath
    \pgfsetfillcolor{blue}
    \pgfsetstrokecolor{blue}
    \pgfusepath{fill, stroke}
  }
  \state{body}[width=\dashseglen]
  {
    % computations
    \pgfmathsetlengthmacro\segwidth{\dashgapratio*\dashseglen}
    \pgfmathsetlengthmacro\segstartheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance) / \pgfdecoratedpathlength}
    \pgfmathsetlengthmacro\segendheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance + \dashgapratio*\dashseglen) / \pgfdecoratedpathlength}
    % drawing
    \pgfpathmoveto{\pgfqpoint{0pt}{\segstartheight}}
    \pgfpathlineto{\pgfqpoint{\segwidth}{\segendheight}}
    \pgfpathlineto{\pgfqpoint{\segwidth}{-\segendheight}}
    \pgfpathlineto{\pgfqpoint{0pt}{-\segstartheight}}
    \pgfpathclose
  }
  \state{final}
  { 
    % computations
    \pgfmathsetlengthmacro\segwidth{\dashgapratio*\dashseglen}
    \pgfmathsetlengthmacro\segstartheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance) / \pgfdecoratedpathlength}
    \pgfmathsetlengthmacro\segendheight{\startheight + (\wedgeheight - \startheight)*(\pgfdecoratedcompleteddistance + \dashgapratio*\dashseglen) / \pgfdecoratedpathlength}
    % drawing
    \pgfpathmoveto{\pgfqpoint{0pt}{\segstartheight}}
    \pgfpathlineto{\pgfqpoint{\segwidth}{\segendheight}}
    \pgfpathlineto{\pgfqpoint{\segwidth}{-\segendheight}}
    \pgfpathlineto{\pgfqpoint{0pt}{-\segstartheight}}
    \pgfpathclose
  }
}

\node (x) at (0,0) [rectangle, rounded corners=0.8mm, fill = blue, inner sep=0.1mm, scale=2.5] {Ti};
\node (y) at (1.5,0.) [rectangle, rounded corners=0.8mm, fill = blue, inner sep=0.1mm, scale=2.5] {L};

\fill [red, decorate, decoration=dashed wedge, rounded corners=0.5pt] (x) -- (y);

\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.