Take the 2-minute tour ×
TeX - LaTeX Stack Exchange is a question and answer site for users of TeX, LaTeX, ConTeXt, and related typesetting systems. It's 100% free, no registration required.

How can I create a Caesar's encryption disk with LaTeX?

Caesar's encryption disk

I guess, the ultimate solution would take a arbitrary list of letters and calculate the spaces and angles for each letter automatically. So if I pass 4 letters to it, each space should have 90 degrees.

share|improve this question
1  
This looks like fun. Can we add that to the tag? –  hpesoj626 Mar 20 '13 at 5:51
    
Done, added 'fun' :-) –  Uwe Ziegenhagen Mar 20 '13 at 6:04
1  
What have you tried so far? MWE? Do you want to give a list of letters? The number of letters? What should happen when the number is greater than 26? –  Qrrbrbirlbel Mar 20 '13 at 6:10
    
I have no idea how to tackle this problem, so there is no MWE yet. I could imagine it as the following: \ceasar[circleouterwidth=5cm]{a,b,c,d,e,f,g}{a,b,c,d,e,f,g} with character for the inner and the outer circle. Giving two separate lists could allow to use math symbols as well or Greek characters. There should not be a problem if there are more than 26 chars. –  Uwe Ziegenhagen Mar 20 '13 at 6:27
3  
Next challenge - build an Enigma machine in TeX? en.wikipedia.org/wiki/Enigma_machine –  Ethan Bolker Mar 20 '13 at 12:52

4 Answers 4

up vote 48 down vote accepted

Commands

  • \drawCaesarsDisk that works with a number of letters (only A to Z)
  • \drawCaesarsList that works with one list for both rings or two different lists

Keys

  • inner radius/middle radius/outer radius
    • Improvements: Specify inner radius and add inner height and outer height respectively to calculate the actual radii.
    • Improvements: With these heights, scale the letters so that they fit right into one ring segment.
  • number of letters (only \drawCaesarsDisk)
  • inner letters and outer letters (only \drawCaesarsList): If only inner letters is specified the letters in the outer ring will be the same as in the inner ring.
  • shift

Parameters (both commands)

  • First (optional): Key=Values for the disk.
  • Second (mandatory): where the Disk is placed.

Improvement:

  • Radii/font-size calculation (see above)
  • Starting with the first letter at the north position or right of it (possible style)
  • Adding styles for circles, separators, letters, etc.
  • Bug: The List command breaks with

    ! Dimension too large. <recently read> \pgfmath@x
    

    when 46 or more letters are specified.

  • I forgot something …

Code

\documentclass[tikz]{standalone}
\usetikzlibrary{backgrounds}
\makeatletter
\tikzset{
    /caesar/.cd,
    inner radius/.store in=\qrr@caesar@innerR,
    middle radius/.store in=\qrr@caesar@middleR,
    outer radius/.store in=\qrr@caesar@outerR,
    inner letters/.store in=\qrr@caesar@innerL,
    outer letters/.store in=\qrr@caesar@outerL,
    number of letters/.code=\pgfmathtruncatemacro\qrr@caesar@number{#1},
    shift/.store in=\qrr@caesar@shift,
    % defaults:
    outer letters=,
    shift=0
}
\newcommand*{\drawCaesarsDisk}[2][]{%
    \begingroup
    \pgfqkeys{/caesar}{#1}%
    \foreach \radius in {\qrr@caesar@innerR,\qrr@caesar@middleR,\qrr@caesar@outerR}
        \draw (#2) circle [radius=\radius];
    \foreach \step in {0,...,\numexpr\qrr@caesar@number-1}{
        \draw[shift={(#2)}] (\step*360/\qrr@caesar@number:\qrr@caesar@innerR) -- (\step*360/\qrr@caesar@number:\qrr@caesar@outerR);
        \node[shift={(#2)},rotate=(\step+.5)*360/\qrr@caesar@number-90] at ({(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@innerR)+.5*(\qrr@caesar@middleR)} ) {\@Alph{\numexpr26-\step}};
        \pgfmathtruncatemacro\pgf@temp{mod(\step+\qrr@caesar@shift,\qrr@caesar@number)}%
        \node[shift={(#2)},rotate=(\step+.5)*360/\qrr@caesar@number-90] at ({(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@outerR)+.5*(\qrr@caesar@middleR)} ) {\@Alph{\numexpr26-\pgf@temp}};
    }
    \endgroup
}
\newcount\qrr@caesar@c
\newcommand*{\drawCaesarsList}[2][]{%
    \begingroup
    \pgfqkeys{/caesar}{#1}%
    \foreach \radius in {\qrr@caesar@innerR,\qrr@caesar@middleR,\qrr@caesar@outerR}
        \draw (#2) circle [radius=\radius];
    \qrr@caesar@c=0\relax
    \foreach \element in \qrr@caesar@innerL {\global\advance\qrr@caesar@c1}
    \ifx\pgfutil@empty\qrr@caesar@outerL
        \let\qrr@caesar@outerL\qrr@caesar@innerL
    \fi
    \edef\qrr@caesar@number{\number\qrr@caesar@c}%
    \foreach \innerLetter[count=\step from 0] in \qrr@caesar@innerL {
        \draw[shift={(#2)}] (\step*360/\qrr@caesar@number:\qrr@caesar@innerR) -- (\step*360/\qrr@caesar@number:\qrr@caesar@outerR);
        \node[shift={(#2)},rotate=-(\step+.5)*360/\qrr@caesar@number-90] at ({-(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@innerR)+.5*(\qrr@caesar@middleR)} ) {\innerLetter};
    }
    \foreach \outerLetter[count=\step@ from 0] in \qrr@caesar@outerL {
        \ifnum\step@=\qrr@caesar@number\breakforeach\fi
        \pgfmathtruncatemacro\step{mod(\step@+\qrr@caesar@shift,\qrr@caesar@number)}%
        \node[shift={(#2)},rotate=-(\step+.5)*360/\qrr@caesar@number-90] at ({-(\step+.5)*360/\qrr@caesar@number}:{.5*(\qrr@caesar@outerR)+.5*(\qrr@caesar@middleR)} ) {\outerLetter};
    }
    \endgroup
}
\makeatother
\begin{document}
\begin{tikzpicture}
\drawCaesarsDisk[
    inner radius=2cm,
    middle radius=2cm+1.3em,
    outer radius=2cm+3em,
    number of letters=26,
    shift=13,
    ]{0,0}
\end{tikzpicture}

\begin{tikzpicture}
\drawCaesarsList[
    inner radius=.5cm,
    middle radius=.5cm+1.3em,
    outer radius=.5cm+3em,
    inner letters={a,b,c,d,e,f,g},
    outer letters={A,B,C,D,E,F,G}
    ]{2,0}
\end{tikzpicture}

\begin{tikzpicture}
\drawCaesarsList[
    inner radius=2cm,
    middle radius=2cm+1.3em,
    outer radius=2cm+3em,
    inner letters={a,...,z,A,B,...,T},%,U,V,W,X,Y,Z},
    shift=26,
    ]{0,0}
\end{tikzpicture}
\end{document}

Output

enter image description here

enter image description here

enter image description here

share|improve this answer
    
Wow! However I get an error: "! Package tikz Error: A node must have a (possibly empty) label text. ... l.58 ]{0,0} –  Uwe Ziegenhagen Mar 20 '13 at 7:17
    
@UweZiegenhagen I have added some explanation since you made your comment. I also updated the solution to work with the 2.10 version of TikZ. The problem was a parsing error that was already discussed in other questions. And to clarify: Yes, you can give two (possibly different) lists and you can specify a shift. –  Qrrbrbirlbel Mar 20 '13 at 7:35
    
You are awesome! :-) –  Uwe Ziegenhagen Mar 20 '13 at 7:47
    
An alternative way of getting the length of a \foreach list is: \foreach \x [count=\c from 1, remember=\c] in {A,...,Z}{}. Then \c holds the length of the list. –  Mark Wibrow Mar 20 '13 at 11:50

Here is what I've done so far:

\documentclass{standalone}
\usepackage{tikz}
\begin{document}
  \begin{tikzpicture}
    \pgfmathsetmacro{\alphsize}{26}

    \pgfmathsetmacro{\ang}{360/\alphsize}
    \pgfmathsetmacro{\d}{10}
    \pgfmathsetmacro{\op}{98 + \ang/2 - 1.2}
    \pgfmathsetmacro{\e}{\ang + \ang*\d}
    \pgfmathsetmacro{\ep}{\op + \ang*\d}

    \foreach \x in {0,\ang,...,360} {
      \draw[gray] (\x:8em) -- (\x:12em);
    }

    \foreach \x [count=\xi] in {A,...,Z} {
      \node[rotate=\ang - \ang*\xi] at (\op - \ang*\xi:11em) {\Large\x};
      \node[rotate=\e - \ang*\xi] at (\ep - \ang*\xi:9em) {\Large\x};
    }

    \draw[thick] (0cm,0cm) circle(12em);
    \draw[gray] (0cm,0cm) circle(10em);
    \draw[thick] (0cm,0cm) circle(8em);
  \end{tikzpicture}
\end{document}

Caesar latin circle

share|improve this answer

Here:

\documentclass{article}
\usepackage{tikz}
\usepackage{ifthen}

\newcounter{encrypted}
\newcounter{original}

\newcommand{\increase}[1]{%command to increase a counter by 1 modulo 26
\ifthenelse{\arabic{#1}<26}{\addtocounter{#1}{1}}{\setcounter{#1}{1}}
}

\begin{document}

\setcounter{encrypted}{7}
\setcounter{original}{1}
\begin{tikzpicture}[scale=0.5]
\draw(0,0)circle(5)circle(7)circle(9);
\foreach \x in {1,2,...,26}
{
\draw(\x*360/26:5)--(\x*360/26:9);
\node at (\x*360/26+360/26+180/26:6){\Alph{encrypted}};
\node at (\x*360/26+360/26+180/26:8){\Alph{original}};
\increase{encrypted}
\increase{original}
}
\end{tikzpicture}

\end{document}

enter image description here

share|improve this answer
    
This looks really promising. Is there an easy way to take just a list of characters instead of hard-coding the 26 letters? –  Uwe Ziegenhagen Mar 20 '13 at 6:33
1  
@Toscho I have added the picture for you. I hope you don't mind. :-) –  hpesoj626 Mar 20 '13 at 9:10

Just 4 fun with PSTricks.

enter image description here

\documentclass[pstricks,border=12pt]{standalone}
\SpecialCoor
\makeatletter
\def\N{26}

\begin{document}
% speficy the angular distance between the 2 sets of alphabets
\def\offset{13}
\begin{pspicture}(-5,-5)(5,5)
    \psforeach{\r} {2,3,4}{\pscircle{\r}}
    \degrees[\N]
    \psforeach{\t}{65,66,..,90}{%
        \psline(2;\the\psLoopIndex)(4;\the\psLoopIndex)
        \pstVerb{/angle {\the\psLoopIndex\space 0.5 add} bind def}%
        \rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\char\t\relax}
        \rput{!angle \offset\space add 6.5 sub}(!2.5 angle \offset\space add \pst@angleunit PtoC){\char\t\relax}
    }
\end{pspicture}
\end{document}

Animated version

To be funner!

enter image description here

\documentclass[pstricks,border=12pt]{standalone}
\usepackage{multido}
\SpecialCoor
\makeatletter
\def\N{26}

\begin{document}
\multido{\i=0+1}{\N}{%
% speficy the angular distance between the 2 sets of alphabets
\def\offset{\i}
\begin{pspicture}(-5,-5)(5,5)
    \psforeach{\r} {2,3,4}{\pscircle{\r}}
    \degrees[\N]
    \psforeach{\t}{65,66,..,90}{%
        \psline(2;\the\psLoopIndex)(4;\the\psLoopIndex)
        \pstVerb{/angle {\the\psLoopIndex\space 0.5 add} bind def}%
        \rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\char\t\relax}
        \rput{!angle \offset\space add 6.5 sub}(!2.5 angle \offset\space add \pst@angleunit PtoC){\char\t\relax}
    }
\end{pspicture}}
\end{document}

Warning

If we invoke \degrees[<value other than 360>] previously, conversion with \pst@angleunit is needed for representing points in RPN notation but it is NOT need for representing rotation angle. See the following code snippet.

\rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\t}

It is funny? Don't ask me! I just knew this feature several minutes ago!

One more feature, unlike \foreach \t in {A,...,Z}{} that produces a correct result, \psforeach{\t}{A,..,Z}{} produces a weird output!

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.