![在 TikZ 中缩放埃拉托斯特尼筛法](https://linux22.com/image/267838/%E5%9C%A8%20TikZ%20%E4%B8%AD%E7%BC%A9%E6%94%BE%E5%9F%83%E6%8B%89%E6%89%98%E6%96%AF%E7%89%B9%E5%B0%BC%E7%AD%9B%E6%B3%95.png)
考虑以下代码,取自 Alain Matthes 的回答这里。
代码
\documentclass{article}
\usepackage{tikz}
\makeatletter
\pgfutil@ifundefined{pgfmath@function@isprime}{%
\newif\ifpgf@unknown
\newif\ifpgf@isaprime
\pgfmathdeclarefunction{isprime}{1}{%
\begingroup%
\pgf@unknowntrue
\c@pgfmath@counta#1\relax%
\ifcase#1\relax
% |#1| = 0
\pgf@isaprimefalse\pgf@unknownfalse
\or
% |#1| = 1
\pgf@isaprimefalse\pgf@unknownfalse
\or
% |#1| = 2
\pgf@isaprimetrue\pgf@unknownfalse
\or
% |#1| = 3
\pgf@isaprimetrue\pgf@unknownfalse
\else
% |#1| > 3
\ifodd#1\relax
\else
\pgf@isaprimefalse\pgf@unknownfalse
\fi
\fi
\ifpgf@unknown
\c@pgfmath@countd=\thr@@ \pgf@isaprimetrue
\loop
\c@pgfmath@countb=\c@pgfmath@counta
\divide\c@pgfmath@countb by\c@pgfmath@countd
\ifnum\c@pgfmath@countb>\c@pgfmath@countd \pgf@unknowntrue
\else\pgf@unknownfalse\fi
\multiply\c@pgfmath@countb by\c@pgfmath@countd
\ifnum\c@pgfmath@countb=\c@pgfmath@counta
\global\pgf@isaprimefalse\pgf@unknownfalse\fi
\ifpgf@unknown\advance\c@pgfmath@countd by 2\relax%
\repeat
\fi
\ifpgf@isaprime
\def\pgfmathresult{1}%
\else
\def\pgfmathresult{0}%
\fi
\pgfmath@smuggleone\pgfmathresult%
\endgroup
}}{}
\makeatother
\begin{document}
\def\scaling{0.5}
\begin{tikzpicture}[y=-1cm,scale=\scaling]
\foreach \x in {0,...,9}
\foreach \y in {1,...,10}
{\draw (\x,\y) +(-0.5cm,-0.5cm) rectangle ++(0.5cm,0.5cm);
\pgfmathtruncatemacro{\nb}{\x*10+\y}
\ifnum\nb=1
\def\pgfmathresult{1}
\else
\node[minimum size=\scaling cm](last) at (\y-1,\x+1) {\nb};
\pgfmathisprime{\nb}
\fi
\ifnum\pgfmathresult=0
\draw[red](last.north west)--(last.south east)
(last.north east)--(last.south west);
\fi}
\end{tikzpicture}
\end{document}
输出
问题
缩放图片时如何正确绘制红线?如果我使用
\def\scaling{1}
一切都很好,但是
\def\scaling{0.5}
(如图所示),线条不是从正方形的角开始画出,也不是到正方形的角画出。
PS:我完全不了解 TikZ,所以这个问题可能是我的一个小错误。
答案1
缩放后与原始代码一起添加transform shape
(使得红线占据整个方块):
\documentclass{article}
\usepackage{tikz}
\makeatletter
\pgfutil@ifundefined{pgfmath@function@isprime}{%
\newif\ifpgf@unknown
\newif\ifpgf@isaprime
\pgfmathdeclarefunction{isprime}{1}{%
\begingroup%
\pgf@unknowntrue
\c@pgfmath@counta#1\relax%
\ifcase#1\relax
% |#1| = 0
\pgf@isaprimefalse\pgf@unknownfalse
\or
% |#1| = 1
\pgf@isaprimefalse\pgf@unknownfalse
\or
% |#1| = 2
\pgf@isaprimetrue\pgf@unknownfalse
\or
% |#1| = 3
\pgf@isaprimetrue\pgf@unknownfalse
\else
% |#1| > 3
\ifodd#1\relax
\else
\pgf@isaprimefalse\pgf@unknownfalse
\fi
\fi
\ifpgf@unknown
\c@pgfmath@countd=\thr@@ \pgf@isaprimetrue
\loop
\c@pgfmath@countb=\c@pgfmath@counta
\divide\c@pgfmath@countb by\c@pgfmath@countd
\ifnum\c@pgfmath@countb>\c@pgfmath@countd \pgf@unknowntrue
\else\pgf@unknownfalse\fi
\multiply\c@pgfmath@countb by\c@pgfmath@countd
\ifnum\c@pgfmath@countb=\c@pgfmath@counta
\global\pgf@isaprimefalse\pgf@unknownfalse\fi
\ifpgf@unknown\advance\c@pgfmath@countd by 2\relax%
\repeat
\fi
\ifpgf@isaprime
\def\pgfmathresult{1}%
\else
\def\pgfmathresult{0}%
\fi
\pgfmath@smuggleone\pgfmathresult%
\endgroup
}}{}
\makeatother
\begin{document}
\def\scaling{0.5}
\begin{tikzpicture}[y=-1cm,scale=\scaling,transform shape]
\foreach \x in {0,...,9}
\foreach \y in {1,...,10}
{ \draw (\x,\y) +(-.5cm,-.5cm) rectangle ++(.5cm,.5cm);
\pgfmathtruncatemacro{\nb}{\x*10+\y}
\ifnum\nb=1 \def\pgfmathresult{1}
\else
\node[minimum size= 1cm](last) at (\y-1,\x+1) {\nb} ;
\pgfmathisprime{\nb}
\fi
\ifnum\pgfmathresult=0
\draw[red](last.north west)--(last.south east)
(last.north east)--(last.south west);
\fi}
\end{tikzpicture}
\end{document}
答案2
发生这种情况的原因是网格中显示的每个数字都是通过以下方式显示的:
\node[minimum size=\scaling cm](last) at (\y-1,\x+1) {\nb};
并且十字架通过以下方式显示:
\draw[red](last.north west)--(last.south east)
(last.north east)--(last.south west);
第一行定义至少\scaling cm
较大的节点。如果字体足够小,则使它们正好\scaling cm
大。如果字体相对于而言太大\scaling cm
,则它们的大小将增加以适合数字。
接下来的两行在这些节点的末端之间画了一个十字。如果节点很大\scaling cm
,它们对应于网格(在代码的另一部分中绘制)。如果节点大于\scaling cm
(由于字体大小),那么十字就会太大。
从结果中可以看出,使用 0.5 缩放值时,字体大小足够小以适合网格,那么为什么会出现问题呢?原因是tikz
强制在节点内容(此处为数字)与其边框之间使用最小分隔符。可以通过强制分隔符为 来规避此问题0
:
\node[inner sep=0,minimum size=\scaling cm](last) at (\y-1,\x+1) {\nb};
由于字体未缩放,结果与 Gonazlo Medina 的结果略有不同:
\small
您还可以通过在后添加例如来缩放字体\begin{tikzpicture}
。