如何使用 LaTeX 创建凯撒加密磁盘?
我猜,最终的解决方案是采用任意字母列表并自动计算每个字母的空格和角度。因此,如果我将 4 个字母传递给它,则每个空格应该有 90 度。
答案1
命令
\drawCaesarsDisk
适用于多个字母(仅限 A 至 Z)\drawCaesarsList
适用于两个环的一个列表或两个不同的列表
按键
inner radius
/middle radius
/outer radius
- 改进:指定内半径并分别添加
inner height
和outer height
计算实际半径。 - 改进:利用这些高度,缩放字母,使它们正好适合一个环段。
- 改进:指定内半径并分别添加
number of letters
(仅有的\drawCaesarsDisk
)inner letters
和outer letters
(仅有的\drawCaesarsList
):如果仅inner letters
指定,外圈的字母将与内圈的字母相同。shift
参数(两个命令)
- 第一个(可选):磁盘的 Key=Values。
- 第二个(必填):磁盘放置的位置。
改进:
- 半径/字体大小计算(见上文)
- 从北边位置或右方第一个字母开始(可能的样式)
- 添加圆圈、分隔符、字母等样式。
漏洞:List 命令中断
! Dimension too large. <recently read> \pgfmath@x
当指定 46 个或更多字母时。
我忘了一些东西……
代码
\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}
输出
答案2
以下是我目前所做的:
\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}
答案3
这里:
\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}
答案4
使用 PSTricks 只是为了好玩。
\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}
动画版
更有趣!
\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}
警告
如果我们\degrees[<value other than 360>]
之前调用,则\pst@angleunit
需要转换为 RPN 符号来表示点,但不需要转换为表示旋转角度。请参阅以下代码片段。
\rput{!angle 6.5 sub}(!3.5 angle \pst@angleunit PtoC){\t}
很有趣?别问我!我几分钟前才知道这个功能!
还有一个特性,与\foreach \t in {A,...,Z}{}
产生正确结果的不同,\psforeach{\t}{A,..,Z}{}
会产生奇怪的输出!