14

I want to draw a variant of the following figure, enter image description here

[Figure 22 of Freedman et al, Annals of Physics,310(2):428–492, April 2004.]

The lattice and dashed lines are easy. Using two for loops

\begin{tikzpicture}[scale = 1.5]
\foreach \x in {0,...,6}{
  \foreach \y in {0,...,4}{
    \fill[black] (\x,\y) circle (0.08/1.5);
  }
}
\draw[dashed] (0,1)--++(2,0)--++(0,2)--++(4,0);
\draw[dashed] (2,1)--++(2,0)--++(0,2);
\end{tikzpicture}

I get

enter image description here

For a single loop I can do patiently adjust its coordinate and arc on the corner. But with so many loops of different orientations and connections in the figure, I do not know an efficient way of producing it using tikz.

Do you guys know any package that can handle the connections of these loops?

Thanks.

Edit: @cfr, thanks for your suggestion. The knot package seems to deal with the case that strands go under/above each other, for example

enter image description here

(picture from this blog post)

Instead, I need to draw sort of the self avoiding paths.

  • Maybe you could look at the code for one of the packages which uses TikZ to draw knots? That has to do something not dissimilar, I think. – cfr Feb 4 '16 at 23:04
16

My answer consists of three parts.

Step 1: decorate segments

First, we would like to replace every segment

by a dumbbell:

This could be done, as the title suggests, by defining a decoration and applying it. So we may write

\pgfdeclaredecoration{dumbbells}{initial}
{
  \state{initial}[width=0pt,next state=depict one]{
    \egroup
    % set up parameters
    \bgroup
  }
  \state{depict one}[width=1cm,next state=depict one]
  {
    % construct the contour of the dumbbell
  }
  \state{final}{}
}

The size of dumbbells is controlled by segment length. For example

\tikz\draw[decorate,decoration={dumbbells,segment length=1cm}](0,0)--(1,0);

Step 2: decoration options

We need the corner rounded

This is easy, we could use rounded corners in constructing the decoration.

We also need a fat dumbbells

Notice that the radius of corners vary. This is hard in TikZ. But in PGF, the radius is changed on each call of \pgfsetcornersarced.

The radius and the fatness are controlled by rounded corners and border width. For example

\tikz\draw[decorate,decoration={dumbbells,segment length=1cm,rounded corners=.2cm}](0,0)--(1,0);
\tikz\draw[decorate,decoration={dumbbells,segment length=1cm,rounded corners=.2cm,border width=.1cm}](0,0)--(1,0);

Step 3: accumulating decorations

We need to draw a black, fat dumbbells. And then overlay it by a white, thin one. And then draw the dashes.

\tikzset{
    fill dumbbells/.style 2 args={
        decorate,decoration={
            dumbbells,
            segment length=1cm,
            rounded corners=.2cm,
            border width=#1,
            fill=#2
        }
    },
    draw dumbbells/.style={
        preaction={
            preaction={fill dumbbells={.01cm}{black}},
            postaction={fill dumbbells={-.01cm}{white}}
        },
        draw,dashed
    }
}

So now we can write

\tikz\draw[draw dumbbells](0,1)--++(2,0)--++(0,2)--++(4,0)(2,1)--++(2,0)--++(0,2);

Full code

\documentclass[border=9,tikz]{standalone}
\usepackage{}
\usetikzlibrary{decorations}
\begin{document}

\newdimen\pgfdecorationcornersradius\newdimen\pgfdecorationborderwidth
\newdimen\a\newdimen\b\newdimen\o\newdimen\R\newdimen\r
\pgfkeys{
  /pgf/decoration/.cd,
  rounded corners/.code={\pgfmathsetlength\pgfdecorationcornersradius{#1}},
  border width/.code={\pgfmathsetlength\pgfdecorationborderwidth{#1}},
  fill/.initial=black
}

\pgfdeclaredecoration{dumbbells}{initial}
{
  \state{initial}[width=0,next state=depict one]{
    \egroup
    \pgfsetfillcolor{\pgfkeysvalueof{/pgf/decoration/fill}}
    \pgfmathsetlength\a{.5\pgfdecorationsegmentlength}
    \pgfmathsetlength\b{1.41421\pgfdecorationborderwidth}
    \pgfmathsetlength\R{\pgfdecorationcornersradius+\pgfdecorationborderwidth}
    \pgfmathsetlength\r{\pgfdecorationcornersradius-\pgfdecorationborderwidth}
    \bgroup
  }
  \state{depict one}[width=\pgfdecorationsegmentlength,next state=depict one]
  {
    \pgfpathmoveto{\pgfpoint{\o}{\a+\b}}
    \pgfsetcornersarced{\pgfpoint{\r}{\r}}
    \pgfpathlineto{\pgfpoint{\a}{\b}}
    \pgfsetcornersarced{\pgfpoint{\R}{\R}}
    \pgfpathlineto{\pgfpoint{2\a}{\a+\b}}
    \pgfpathlineto{\pgfpoint{3\a+\b}{\o}}
    \pgfpathlineto{\pgfpoint{2\a}{-\a-\b}}
    \pgfsetcornersarced{\pgfpoint{\r}{\r}}
    \pgfpathlineto{\pgfpoint{\a}{-\b}}
    \pgfsetcornersarced{\pgfpoint{\R}{\R}}
    \pgfpathlineto{\pgfpoint{\o}{-\a-\b}}
    \pgfpathlineto{\pgfpoint{-\a-\b}{\o}}
    \pgfpathclose
    \pgfusepath{fill}
    \pgfpathmoveto{\pgfpointorigin}
  }
  \state{final}{}
}

\tikz{
    \draw[decorate,decoration={dumbbells,segment length=1cm,fill=white}](0,0)--(1,0);
    \draw(0,0)--(1,0);
}
\tikz\draw[decorate,decoration={dumbbells,segment length=1cm}](0,0)--(1,0);
\tikz\draw[decorate,decoration={dumbbells,segment length=1cm,rounded corners=.2cm}](0,0)--(1,0);
\tikz\draw[decorate,decoration={dumbbells,segment length=1cm,rounded corners=.2cm,border width=.1cm}](0,0)--(1,0);

\tikzset{
    fill dumbbells/.style 2 args={
        decorate,decoration={
            dumbbells,
            segment length=1cm,
            rounded corners=.2cm,
            border width=#1,
            fill=#2
        }
    },
    draw dumbbells/.style={
        preaction={
            preaction={fill dumbbells={.01cm}{black}},
            postaction={fill dumbbells={-.01cm}{white}}
        },
        draw,dashed
    }
}

\begin{tikzpicture}
    \draw[draw dumbbells](0,1)--++(2,0)--++(0,2)--++(4,0)(2,1)--++(2,0)--++(0,2);
    \foreach \x in {0,...,6}{
        \foreach \y in {0,...,4}{
            \fill[black](\x,\y)circle(0.08/1.5);
        }
    }
\end{tikzpicture}

Update

OP wants to "fill" empty nodes by isolated rhombus. The most easy way uses only TikZ's features \foreach, rounded corners, and line width.

\begin{tikzpicture}
    \foreach \x in {0,...,6}{
        \foreach \y in {0,...,4}{
            \draw[rounded corners=.2cm,line width=.02cm](\x,\y)+(.5,0)--+(0,.5)--+(-.5,0)--+(0,-.5)--cycle;
        }
    }
    \draw[draw dumbbells](0,1)--++(2,0)--++(0,2)--++(4,0)(2,1)--++(2,0)--++(0,2);
    \foreach \x in {0,...,6}{
        \foreach \y in {0,...,4}{
            \fill[black](\x,\y)circle(0.08/1.5);
        }
    }
\end{tikzpicture}
  • Cool, but all the remaining nodes should have the romboidal edges, no? – Alenanno Feb 5 '16 at 9:26
  • @Alenanno I am sorry, but "rhomboidal edges"? – Symbol 1 Feb 5 '16 at 9:40
  • Oops sorry, I'm on the phone. Yeah, I mean the other edges for the isolated nodes as the image in the op. . – Alenanno Feb 5 '16 at 9:47
  • @Alenanno I knew someone will ask about it. Well, one can do this by node shape, pic, marking, etc. But for decoration, it is hard to concentrate on isolated points. – Symbol 1 Feb 5 '16 at 9:54
  • @Alenanno, fantastic solution! I'm trying to modify your definition of dumbbells to draw a rhombus on isolated points, but the rhombus comes with a line. And I don't know how to accomplish this using node shape either. Can you please elaborate more on this? – anecdote Feb 5 '16 at 15:01

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.