Here is MWE
using Asymptote
3D
drawing:
% sphtri.tex:
\documentclass{article}
\usepackage[inline]{asymptote}
\usepackage{lmodern}
\begin{document}
\begin{figure}
\centering
\begin{asy}
settings.prc=false;
settings.tex="pdflatex";
settings.render=0;
import three;
size(100); size3(100);
currentprojection=orthographic(
camera=(5.4290316601351,2.94352790610013,1.1108527434919),up=Z,target=O,zoom=0.7);
real r=1;
triple A,B,C;
A=dir(60.0,20.0);
B=dir(40.0,40.0);
C=dir(80.0,80.0);
guide3 AB=arc(O,A,B,CCW);
guide3 BC=arc(O,B,C,CCW);
guide3 CA=arc(O,C,A,CCW);
radialshade(project(circle((0,0,0),1
,currentprojection.camera-currentprojection.target))
,rgb(0.79,0.79,0.85), project(O), 1.0
,rgb(0.99,0.99,0.85), project(O), 0.2
);
guide3 g=AB--BC--CA--cycle;
fill(project(g),rgb(1,1,0.8));
draw(arc(O,A,B,CCW),red+1bp);
draw(arc(O,B,C,CCW),olive+1bp);
draw(arc(O,C,A,CCW),blue+1bp);
pen alphaPen=red;
pen betaPen=darkgreen;
pen gammaPen=blue;
void markAngle(string lab,triple v, guide3 gright, guide3 gleft, real arcdist, pen arcpen=currentpen){
triple t,s;
t=arcpoint(gright,arcdist);
s=arcpoint(gleft,arcdist);
draw(arc(v,t,s,cross(t-v,s-v),CCW),arcpen);
label("$"+lab+"$",(v+t+s)/3,arcpen);
}
real ra,rb,rg;
ra=0.17; rb=0.21; rg=0.4;
markAngle("\alpha",A,reverse(CA),AB,ra,alphaPen);
markAngle("\beta",B,reverse(AB),BC,rb,betaPen);
markAngle("\gamma",C,reverse(BC),CA,rg,gammaPen);
dot(A,red); dot(B,olive); dot(C,blue);
label("$A$",project(A),SW);
label("$B$",project(B),N);
label("$C$",project(C),SE);
\end{asy}
\caption{Spherical arcs and spherical triangles}
\end{figure}
\end{document}
%
% To process it with `latexmk`, create file `latexmkrc`:
%
% sub asy {return system("asy '$_[0]'");}
% add_cus_dep("asy","eps",0,"asy");
% add_cus_dep("asy","pdf",0,"asy");
% add_cus_dep("asy","tex",0,"asy");
%
% and run `latexmk -pdf sphtri.tex`.
(See update at the end for an alternative output)
Done with Lualatex and tikz, simply converting the code from this javascript fiddle
This is a sample result for number 36:
Which was generated with:
\begin{tikzpicture}[y=-1cm]
\draw[red] (0,0) rectangle (5,5);
\primediagram{36}{2.5}{2.5}{2.5};
\end{tikzpicture}
The macro \primediagram
receives four parameters. The first one is the number to represent. The remaining three are the center and radius of the diagram to be generated.
A more interesting example:
Produced by a tikz loop:
\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}
The complete code
To produce these figures, three files are required:
primediagram.sty
This one simply defines the tex macro which interfaces with the lua code:
% This is primediagram.sty
\directlua{dofile("primediagram.lua")}
\newcommand{\primediagram}[4]{
\directlua{draw(#1,#2,#3,#4)}
}
primediagram.lua
This one contains the lua code which actually performs the computations and outputs the required \draw
commands for tikz. It is a direct translation to lua of the mentioned javascript code.
-- 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
The main document
You only need to include the sty
package, as for example:
\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}
Which produces the figure already shown.
Update: Rotating sub-groups
If each sub-groups is rotated according to the angle at which it is drawn, the output is different, nicer, and more close to the one shown by the OP. I also removed the black filling of the dots:
This is the new code (only primediagram.lua
has to be replaced):
-- 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
Best Answer
edit (2017/09/01 & 02):
Release 1.2o deprecates some macros which were used here, so the answer was updated. On this occasion I replaced uses of
\if...\else...\fi
with thexint
provided\xintiiifOne
etc... which safely select a branch à lafirstoftwo/secondoftwo
way and avoid things like\expandafter\expandafter\expandafter
at user level.Note: the xint manual also contains code implementing expandably Rabin-Miller strong pseudo-primality tests...
This answer has evolved in stages. New contributions were added at the bottom (apart from the images which I put on top).
macro
\factorize
to produce programmatically the factorization of inputN
. The output is put in macro\factors
. For example forN=36
,\factors
expands to{{}{}{36}}{{2}{2}{9}}{{3}{2}{1}}
. Each successive triplet is{p}{k}{m}
wherep^k
is thep
-factor ofN
, andm
the result of dividingN
by it and all previous ones. The first triple{}{}{N}
is a bit of a nuisance, and this explains\expandafter\@gobble\factors
in some the displaying codes. Initially the displays used tabulars.then I added code using
pst-tree
to produce the trees from the result available in\factors
. I also added code for just printing the factorization inline.I now add code using
TikZ+forest
, which I have learned a bit since seeing it used beautifully in Qrrbrbirlbel's answer. The code for theforest
tree also incoporates theinline
version of the factorization.I use
pst-tree
andforest
only to display, not to compute the factorization. Bothpst-tree
andforest
syntax for the trees allowed a simple approach to work from\factors
to the trees: two token lists are filled-up step by step; if using the nativeTikZ
syntax withchild
, that would be much more difficult because of braces{
and}
.Images of trees produced with
forest
:Images of trees using
pst-tree
(as were done manually by PSTikZ.) Here are some samples (the code also has the variant to not display the1
's when they are exponents). For some other ways to do trees, e.g with TikZ's childs and nodes, the\factors
macro prepared by the\factorize
command should probably be done in a slightly different manner.I too propose half of an answer using package xint for the arithmetic computations (on arbitrarily big numbers). The command
\factorize{N}
results in macro\factors
containing a list of triplets{p}{k}{m}
, wherep
is a prime number showing up in the factorization,k
is its exponent,m
is the result of division ofN
byp^k
as well as all previous factors corresponding to smaller primes. So the last triplet hasm=1
, and the first is{}{}{N}
.The tree could then be constructed from this macro
\factors
; here I just have a\displayfactorization
to display the result using tabulars (and I use some macros of xint to transform\factors
into what goes into the tabular). There is an optional argument to set up the width of the second column.I use the numprint package to print very long numbers without going beyond the page physical limits.
The algorithm is very lame: first divisions by 2 are tested, then 3, then 5, and all successive odd integers until
N
has been reduced to 1.There is no impact on TeX memory, apart from
\factors
being filled up.The algorithm would be of course faster if done using only TeX
\count
registers (and eTeX\numexpr
for convenience), but this would restrict it to numbers< 2^{31}
.update: I have incorporated the usual halting test to not go beyond square root of n, makes the thing a bit more efficient when the factorization ends in a 'big' prime (two such examples added).
and an example with big integers:
And now the code repeated, together with code to produce trees in the format of the OP question, using
pst-tree
:This resuires
latex+dvips
or can also usexelatex
.Code for inline product decomposition:
Code for doing the trees with
forest
: