完整代码

完整代码

有人能帮我生成代码来根据任何给定的自然数的质因数分解来输入图表吗,比如这些图表在此处输入图片描述

考虑下一个数字 36 及其质因数分解,$36=3^2\cdot 2^2$,按降序排列质数……然后,从 3 的图案开始,即相隔 120 度的 3 个圆圈,现在,用相同图案的另外 3 个圆圈替换每个圆圈以表示 $3^2$,这部分看起来像 9 的图案,也是 $3^2$。现在……为了完成 36 的图案,我们采用 9 的图案,并在每个圆圈中用 4 的图案替换它……也就是说,9 个圆圈中的每一个都被替换为 4 个更小的圆圈,这些圆圈的排列方式与 4 的图案相同

答案1

(请参阅最后的更新以了解替代输出)

使用 Lualatex 和 tikz 完成,只需将代码从这个 javascript 小提琴

这是数字 36 的示例结果:

结果

生成方式如下:

\begin{tikzpicture}[y=-1cm]
\draw[red] (0,0) rectangle (5,5);
\primediagram{36}{2.5}{2.5}{2.5};
\end{tikzpicture}

该宏\primediagram接收四个参数,第一个参数是要表示的数字,其余三个参数是要生成的图表的中心和半径。

一个更有趣的例子:

结果2

由 tikz 循环生成:

\begin{tikzpicture}[y=-1cm]
\foreach \y in {0,...,6} {
  \foreach \x in {0,...,4} {
    \draw(3.1*\x,3.1*\y) rectangle +(3,3);
    \pgfmathtruncatemacro{\number}{\x+5*\y}
    \primediagram{\number}{3.1*\x+1.55}{3.1*\y+1.55}{1.3};
    \node[black!50, below right] at (3.1*\x, 3.1*\y)  {\number};
  }
}
\end{tikzpicture}

完整代码

为了生成这些图形,需要三个文件:

primediagram.sty

这个只是定义了与 lua 代码接口的 tex 宏:

% This is primediagram.sty
\directlua{dofile("primediagram.lua")}
\newcommand{\primediagram}[4]{
    \directlua{draw(#1,#2,#3,#4)}
}

primediagram.lua

这包含实际执行计算并输出\drawtikz 所需命令的 lua 代码。它是上述内容的直接 lua 翻译JavaScript 代码

-- This is primediagram.lua
local smallfirst = false
local off2 = 0

function circle(cx, cy, s) 
    tex.print(string.format("\\fill (%f, %f) circle(%f);", cx, cy, s))
end

function draw(N, cx, cy, s)
  if N==0 then
    return
  end
  if N==1 then
     circle(cx,cy,s)
  else
    local f, r, d, oy, x, y
    f = primefactor(N)
    if f == 2 then
        oy = 0;
        if N % 4 == 0 then
            f = 4;
            r = 2 * s / (f + 2);
            d = f * s / (f + 2);
        else 
            f = 2;
            r = 0.75 * 2 * s / (2 + 2);
            d = 2 * s / (2 + 2);
        end
    else
        r = 2 * s / (f + 2);
        d = f * s / (f + 2);
        oy = d / 2 * (1 - math.cos(math.pi / f));
    end
    for i = 0, f do
        x = math.sin(math.pi + 2 * math.pi * (i + 0.5) / f + off2);
        y = math.cos(math.pi + 2 * math.pi * (i + 0.5) / f + off2);
        draw(N / f, cx + x * d, cy - y * d + oy, r);
    end
  end
end

local primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 
    47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 
    113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 
    191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 
    263, 269, 271}

function primefactor(N) 
    local ans = N;
    for i,pi in pairs(primes) do
        if N % pi == 0 then
            ans = pi;
            if smallfirst then
                return ans
            end
        end
    end
    return ans
end

主要文件

您只需包含sty包,例如:

\documentclass{article}
\usepackage{nopageno}
\usepackage[margin=1cm]{geometry}
\usepackage{tikz}
\usepackage{primediagram}

\begin{document}
\begin{tikzpicture}[y=-1cm]
\foreach \y in {0,...,6} {
  \foreach \x in {0,...,4} {
    \draw(3.1*\x,3.1*\y) rectangle +(3,3);
    \pgfmathtruncatemacro{\number}{\x+5*\y}
    \primediagram{\number}{3.1*\x+1.55}{3.1*\y+1.55}{1.3};
    \node[black!50, below right] at (3.1*\x, 3.1*\y)  {\number};
  }
}
\end{tikzpicture}
\end{document}

由此得到如图所示的图形。

更新:轮换子组

如果每个子组都按照绘制的角度进行旋转,输出结果会有所不同,更漂亮,更接近原帖所展示的结果。我还删除了点的黑色填充:

新结果

这是新的代码(只需primediagram.lua替换):

-- This is primediagram.lua
local smallfirst = false
local off2 = 0

function circle(cx, cy, s) 
    tex.print(string.format("\\draw (%f, %f) circle(%f);", cx, cy, s))
end

function draw(N, cx, cy, s, a)
  if N==0 then
    return
  end
  if N==1 then
     circle(cx,cy,s)
  else
    local f, r, d, x, y, off
    off = 0
    a = a or 0
    tex.print(string.format("\\begin{scope}[xshift=%fcm, yshift=-%fcm, rotate=%f]", cx, cy, a))
    f = primefactor(N)
    if f == 2 then
        oy = 0;
        if N % 4 == 0 then
            f = 4;
            r = 2 * s / (f + 2);
            d = f * s / (f + 2);
        else 
            f = 2;
            r = 0.75 * 2 * s / (2 + 2);
            d = 2 * s / (2 + 2);
            off = math.pi/2
        end
    else
        r = 2 * s / (f + 2);
        d = f * s / (f + 2);
    end
    for i = 0, f-1 do
        local angle = math.pi + 2 * math.pi * (i + 0.5) / f + off
        x = math.sin(angle);
        y = math.cos(angle);
        draw(N / f, x * d, y * d , r, angle*180/math.pi+180);
    end
    tex.print("\\end{scope}")
  end
end

local primes = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 
    47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 
    113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 
    191, 193, 197, 199, 211, 223, 227, 229, 233, 239, 241, 251, 257, 
    263, 269, 271}

function primefactor(N) 
    local ans = N;
    for i,pi in pairs(primes) do
        if N % pi == 0 then
            ans = pi;
            if smallfirst then
                return ans
            end
        end
    end
    return ans
end

答案2

这是一个tikzmath解决方案。

\documentclass[varwidth=147mm]{standalone}
\usepackage{tikz}
\usetikzlibrary{math}
\tikzmath{
  % draw diagram for \n centered at (\x,\y) with radius \r
  function primediagram(\n,\x,\y,\r){
    int \n, \largest;
    \largest = \n;
    if \n != 4 then {% 4 is considered as particular case
      % find the largest prime divisor
      for \d in {61,59,53,47,43,41,37,31,29,23,19,17,13,11,7,5,3,2}{
        if \d < \n && \largest == \n && abs(\n/\d - div(\n,\d)) < .001 then{
          \largest = \d;
        };
      };
    };
    % if \n is prime or 4, draw the circles, else recursion ...
    \step = 360/\largest;
    for \i in {1,...,\largest}{
      \a = (\n==2||\n==8||\n==32)? 0:((\n==4)? 45:90); % aesthetic adjustment
      \newx = \n==1 ? 0 : \x+cos(\a+\i*\step)*\r;
      \newy = \n==1 ? 0 : \y+sin(\a+\i*\step)*\r;
      if \largest == \n then{
        {\fill (\newx,\newy) circle(1.8*\r/\largest);};
      }
      else {
        primediagram(\n/\largest,\newx,\newy,\r/\largest);
      };
    };
  };
}
\begin{document}
  \foreach \n in {1,...,35}{%
    \begin{tikzpicture}[scale=.7]
      \path (2.1,-2.1) rectangle (-2.1,2.1);
      \draw (2,-2) rectangle (-2,2) node[red,below right]{\n};
      \tikzmath{primediagram(\n,0,0,1);};
    \end{tikzpicture}\linebreak[0]%
  }
\end{document}

在此处输入图片描述

相关内容