As we are still in the festive spirit of the 12 days of Christmas, let’s explore a unique way to create a Christmas tree. Instead of traditional methods, we can use the power of code to draw a Christmas tree. Have you ever considered creating a forest of Christmas trees? With the right tools, it’s surprisingly straightforward.
Creating a Christmas Tree with Forest
This approach utilizes the forest
package in LaTeX, combined with TikZ for graphics, to programmatically generate a Christmas tree. This method offers a distinctive, structured way to visualize a tree, moving beyond freehand drawing to a more algorithmic creation.
Here’s the LaTeX code to draw a Christmas tree:
documentclass[tikz, border=5pt, rgb, x11names, svgnames, dvipsnames]{standalone}
usepackage{forest}
usetikzlibrary{shapes.geometric,backgrounds,shadows,fit,fadings,calc}
pgfdeclarelayer{foreground}
pgfdeclarelayer{boncyff}
pgfdeclarelayer{canghennau}
pgfdeclarelayer{goleuni}
pgfsetlayers{background,canghennau,boncyff,goleuni,main,foreground}
makeatletter
% adapted (simplified version) from tex/generic/pgf/frontendlayer/tikz/libraries/tikzlibrarybackgrounds.code.tex
tikzset{%
on foreground layer/.style={%
execute at begin scope={%
pgfonlayer{foreground}%
lettikz@options=pgfutil@empty%
tikzset{every on foreground layer/.try,#1}%
tikz@options%
},
execute at end scope={endpgfonlayer}
},
on canghennau layer/.style={
execute at begin scope={%
pgfonlayer{canghennau}%
lettikz@options=pgfutil@empty%
tikzset{every on canghennau layer/.try,#1}%
tikz@options%
},
execute at end scope={endpgfonlayer}
},
on boncyff layer/.style={
execute at begin scope={%
pgfonlayer{boncyff}%
lettikz@options=pgfutil@empty%
tikzset{every on boncyff layer/.try,#1}%
tikz@options%
},
execute at end scope={endpgfonlayer}
},
on goleuni layer/.style={
execute at begin scope={%
pgfonlayer{goleuni}%
lettikz@options=pgfutil@empty%
tikzset{every on goleuni layer/.try,#1}%
tikz@options%
},
execute at end scope={endpgfonlayer}
},
aa/.store in=cfr@aa, aa=0,
pics/anrheg/.style n args={2}{
code={
node (-bocs) [anchor=north, rounded corners=2pt, outer sep=0pt, minimum width=5mm, minimum height=5mm, fill=#1, rotate=cfr@aa] {};
path [fill=#2, draw=#2, rotate=cfr@aa] ([xshift=-.5mm]-bocs.south) [out=80, in=-105] to ([xshift=.5mm]-bocs.north) [out=175, in=5] to ([xshift=-.5mm]-bocs.north) [out=-85, in=100] to ([xshift=.5mm]-bocs.south) [out=-175, in=-5] to cycle;
path [fill=#2, draw=#2, rotate=cfr@aa] ([yshift=.5mm]-bocs.west) [out=-10, in=-175] to ([yshift=-.5mm]-bocs.east) [out=85, in=-85] to ([yshift=.5mm]-bocs.east) [out=-175, in=-10] to ([yshift=-.5mm]-bocs.west) [out=95, in=-95] to cycle;
},
},
}
makeatother
tikzfading[name=disglair, inner color=transparent!0, outer color=transparent!100]
colorlet{lliw1}{Crimson}
colorlet{lliw2}{DeepPink}
colorlet{lliw3}{Violet}
colorlet{lliw4}{Purple3}
colorlet{lliw5}{Cyan}
colorlet{lliw6}{Green1}
colorlet{lliw7}{Gold}
colorlet{lliw8}{Aquamarine1}
colorlet{lliw0}{OrangeRed1}
colorlet{lliwanrheg1a}{WildStrawberry}
colorlet{lliwanrheg1b}{Ivory}
colorlet{lliwanrheg2a}{Red1}
colorlet{lliwanrheg2b}{Yellow1}
colorlet{lliwanrheg3a}{Turquoise2}
colorlet{lliwanrheg3b}{WildStrawberry}
colorlet{lliwanrheg4a}{Yellow1}
colorlet{lliwanrheg4b}{DodgerBlue3}
colorlet{lliwanrheg5a}{Ivory}
colorlet{lliwanrheg5b}{Turquoise2}
colorlet{lliwanrheg0a}{DodgerBlue3}
colorlet{lliwanrheg0b}{Red1}
begin{document}
forestset{
declare count register=nodes y goeden, nodes y goeden'=0,
declare count register=tier count, tier count'=1,
% canghennau
cangen chwith/.style={
edge path={
noexpandscoped[on canghennau layer]{
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,20pt) [out=-90, in=150] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,15pt) [out=-90, in=150] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,10pt) [out=-90, in=150] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,5pt) [out=-90, in=150] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) [out=-90, in=150] to (.child anchor)forestoption{edge label};
}
},
},
cangen dde/.style={
edge path={
noexpandscoped[on canghennau layer]{
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,20pt) [out=-90, in=30] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,15pt) [out=-90, in=30] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,10pt) [out=-90, in=30] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) +(0,5pt) [out=-90, in=30] to (.child anchor)forestoption{edge label}
noexpandpath [draw=ForestGreen, thick, forestoption{edge}] (!u.parent anchor) [out=-90, in=30] to (.child anchor)forestoption{edge label};
}
},
},
plant/.style={
before typesetting nodes={
repeat=#1{
prepend={[, bud, cangen chwith]},
append={[, bud, cangen dde]},
},
},
},
boncyff/.style={
edge path={
noexpandscoped[on boncyff layer]{
noexpandpath [line cap=round, line width=2.5pt, draw=Chocolate4, forestoption{edge}] (!u.parent anchor) -- (.child anchor)forestoption{edge label};
}
},
},
seren/.style={
star, minimum size=25pt, star points=7, star point ratio=3, parent anchor=south, outer sep=2pt, inner color=white, outer color=Gold1, draw=Goldenrod1,
inner color=white, outer color=Silver, draw=Snow3,
tikz={scoped[on goleuni layer]node (sglein) [minimum width=50pt, circle, inner color=white, outer color=Silver, path fading=disglair] {};}
},
enw/.style={
nodes y goeden'+=1,
name/.process={Rw}{nodes y goeden}{n##1},
},
anrheg/.style={
no edge, enw, anchor=north
},
bud/.style={
inner sep=0pt, outer sep=0pt, parent anchor=center, child anchor=center, enw,
},
gwag/.style={
inner sep=0pt, outer sep=0pt, parent anchor=center, child anchor=center, no edge,
},
}
begin{forest}
for tree={
if level=0{}{
bud,
},
boncyff,
if n=1{
tier count'+=1,
}{},
s sep+=7.5,
before computing xy={
l/.process={Rw+n+d}{tier count}{4*#1 pt}
},
before typesetting nodes={
if n children=0{
append={
[, bud, boncyff
[, bud, l'=2pt, boncyff
[, anrheg, alias=troed, before computing xy={l'=0pt}
]
]
]
},
delay={
for children={
if={
>OOw+n={n}{!u.n children}{(#1+1)/2}
}{}{
append={
[, gwag, l'=2pt
[, anrheg, before computing xy={l'=7.5pt}
]
]
},
},
},
}
}{},
},
},
[, seren, plant=1
[, plant=2
[, plant=3
[, plant=4
[, plant=5
[, plant=6
]
]
]
]
]
]
foreach i in {1,...,50} {
ifnumi=29relaxelseifnumi=28relaxelse
pgfmathsetmacro{result}{int(mod(i,9))}
node [circle, ball color=lliwresult] at (ni) {};
scoped[on goleuni layer]
node [circle, minimum width=20pt, inner color=lliwresult!50!white, outer color=lliwresult!50!Silver, path fading=disglair] at (ni) {};
fifi
}
foreach i in {51,...,62} {
tikzset{aa=0}
pgfmathsetmacro{result}{int(mod(i,6))}
pgfmathsetmacro{casgliad}{int(mod(4+i,6))}
pgfmathsetmacro{nesaf}{int(1+i)}
ifnumi>56
pic at (ni) {anrheg={lliwanrhegresult a}{lliwanrhegresult b}};
else
pic at (ni) {anrheg={lliwanrhegresult b}{lliwanrhegresult a}};
fi
tikzset{aa=45}
ifnumi<56
pic at ([yshift=3.85mm,xshift=.25pt]$(ni)!1/4!(nnesaf)$) {anrheg={lliwanrhegcasgliad a}{lliwanrhegcasgliad b}};
fi
tikzset{aa=-45}
ifnumi>56
ifnumi<62
pic at ([yshift=3.85mm,xshift=-.25pt]$(ni)!3/4!(nnesaf)$) {anrheg={lliwanrhegcasgliad b}{lliwanrhegcasgliad a}};
fi
fi
}
path (n29) ++(0,-1.5mm) coordinate (c0)
(c0) arc (-90:0:5mm and 2.5mm) coordinate (c1)
(c0) arc (-90:-180:5mm and 2.5mm) coordinate (c2)
(c0) +(2.5mm,-4.5mm) coordinate (c3)
(c0) +(-2.5mm,-4.5mm) coordinate (c4)
(c1) +(0,-2mm) coordinate (c5)
(c2) +(0,-2mm) coordinate (c6)
;
path [fill=Sienna1] (c2) arc (-180:0:5mm and 2.5mm) -- (c5) -- (c3) arc (0:-180:2.5mm and 1.25mm) -- (c6) -- cycle;
begin{scope}
clip (c2) arc (-180:0:5mm and 2.5mm) -- (c5) -- (c3) arc (0:-180:2.5mm and 1.25mm) coordinate [midway] (c7) -- (c6) -- cycle;
path [draw=Sienna3] (c6) arc (-180:0:5mm and 2.5mm);
path [draw=Sienna3] (c2) arc (-180:0:5mm and 2.5mm);
end{scope}
begin{scope}[on canghennau layer]
path [fill=Sienna1, draw=Sienna3] (c2) arc (-180:180:5mm and 2.5mm);
path [fill=Brown!50!black] (n29 |- c2) circle (4mm and 2mm);
end{scope}
begin{scope}[on background layer]
node [fill=MidnightBlue, inner sep=15pt, fit=(sglein) (troed) (n21) (n35) (c7) (n51) (n62) (n34)] {};
end{scope}
% foreach i in {1,...,62}
% node (anrheg i) [red] at (ni) {i};
end{forest}
end{document}
This code, when compiled with LaTeX, will generate a Christmas tree. The forest
package is instrumental in creating the tree’s structure, defining branches and levels in a hierarchical manner. TikZ then handles the graphical elements, drawing the trunk, branches, star, and decorations. The code also utilizes layers to manage the drawing order, ensuring elements like lights and branches appear correctly.
Adding a Festive Feline Touch
To enhance our Christmas tree drawing, let’s add a playful element – a cat! Often, cats find themselves curiously positioned around Christmas trees. While our programmatically drawn tree might not physically accommodate a cat underneath, we can certainly add one to the scene.
Here’s how to include a cat image above the tree:
node (cath) [scale=.15, anchor=south, yshift=4.5mm, xshift=5mm] at (n34.north) {includegraphics{cath-gorwedd}};
This code snippet incorporates a pre-drawn cat image (cath-gorwedd
) and scales it appropriately to fit with the Christmas tree, placing it playfully above the tree.
The complete code for the cat as a standalone TikZ picture is available in the appendix for those interested in creating custom TikZ images. This example shows how you can further personalize your digital Christmas tree drawings.
Drawing a Christmas tree using code offers a unique blend of technology and festive creativity. Experiment with the code, change colors, decorations, or even add more elements to create your own unique digital Christmas tree forest!