5

I have been trying to generate the Hilbert curve in tikz: https://www.kerrymitchellart.com/tutorials/hilbert/hilbert-tutorial.html.

This is my attempt so far (vary the integer macro \i from 1 onward).

I do not know how to rotate them properly from iteration 3 onward, and I don't know how to connect them from iteration 3 onward.

Not very applicable, but related: TikZ: Hilbert curves

Maybe someone can understand this: https://www.compuphase.com/hilbert.htm

\documentclass[
    tikz
    ,border = 1cm
]{standalone}
\begin{document}
    \begin{tikzpicture}
        \draw[help lines] (-1,-1) grid (1,1);
        \pgfmathsetmacro{\i}{4}
        \pgfmathsetmacro{\step}{ifthenelse(\i==1,\i-1,1)*(1/2)^(\i-1)}
        \foreach \x[parse = true] in {1,...,2^(\i-1)} {
            \pgfmathsetmacro{\xshift}{
                ifthenelse(\i==1,0,-1)+
                ((\x-1)/2^(\i-2)+\step)
            }
            \foreach \y[parse = true] in {1,...,2^(\i-1)} {
                \pgfmathsetmacro{\yshift}{
                    ifthenelse(\i==1,0,-1)+
                    ((\y-1)/2^(\i-2)+\step)
                }
                    \draw[
                        red
                        ,xshift = \xshift cm
                        ,yshift = \yshift cm
                        ,rotate= {
                            ifthenelse(
                                \i>1
                                ,ifthenelse(
                                    mod(\y,2)!=0,2*\x+1,0
                                )*90
                                ,0
                            )
                        }
                    ]
                        ({-(0.5)^(\i)},{-(0.5)^(\i)}) 
                        -- 
                        ({-(0.5)^(\i)},{(0.5)^(\i)}) 
                        -- 
                        ({(0.5)^(\i)},{(0.5)^(\i)}) 
                        -- 
                        ({(0.5)^(\i)},{-(0.5)^(\i)})
                    ;
                \pgfmathparse{\i>1 && mod(\x,2)==1 && mod(\y,2)==1}
                \ifnum\pgfmathresult=1
                    \draw[
                        red
                        ,xshift = \xshift cm
                        ,yshift = \yshift cm
                        ,rotate= {
                            ifthenelse(
                                \i>1
                                ,ifthenelse(
                                    mod(\y,2)!=0,2*\x+1,0
                                )*90
                                ,0
                            )
                        }
                    ]
                        ({-(0.5)^(\i)-\step},{-(0.5)^(\i)}) 
                        -- 
                        ({-(0.5)^(\i)},{-(0.5)^(\i)}) 
                    ;
                \fi
                \pgfmathparse{\i>1 && mod(\x,2)==0 && mod(\y,2)==1}
                \ifnum\pgfmathresult=1
                    \draw[
                        red
                        ,xshift = \xshift cm
                        ,yshift = \yshift cm
                        ,rotate= {
                            ifthenelse(
                                \i>1
                                ,ifthenelse(
                                    mod(\y,2)!=0,2*\x+1,0
                                )*90
                                ,0
                            )
                        }
                    ]
                        ({(0.5)^(\i)},{-(0.5)^(\i)}) 
                        -- 
                        ({(0.5)^(\i)+\step},{-(0.5)^(\i)}) 
                    ;
                \fi
                \pgfmathparse{\i>1 && mod(\x,2)==0 && mod(\y,2)==0}
                \ifnum\pgfmathresult=1
                    \draw[
                        red
                        ,xshift = \xshift cm
                        ,yshift = \yshift cm
                        ,rotate= {
                            ifthenelse(
                                \i>1
                                ,ifthenelse(
                                    mod(\y,2)!=0,2*\x+1,0
                                )*90
                                ,0
                            )
                        }
                    ]
                        ({-(0.5)^(\i)},{-(0.5)^(\i)}) 
                        -- 
                        ({-(0.5)^(\i)-\step},{-(0.5)^(\i)}) 
                    ;
                \fi
            }      
        }
    \end{tikzpicture}
\end{document}

output

2 Answers 2

8

Here is proposition with luadraw. We can remove the color matrix calculation if we only want the curve. The curve is deduced from the initial pattern by geometric transformations

\documentclass[12pt]{standalone}
\usepackage[svgnames]{xcolor}
\usepackage{fouriernc}
\usepackage[]{luadraw}%https://github.com/pfradin/luadraw
%https://tex.stackexchange.com/questions/749100/hilbert-curve-in-tikz
\begin{document}
\begin{luadraw}{name=Hilbert, exec=true}
local n = 4
local N = 2^n
local g = graph:new{window={0,N,0,N}, size={12,12}}
g:Setmatrix( matrixof( function(z) return z.re+cpx.I*(N-z.im) end) )
g:Linejoin("round"); g:Linewidth(1)
-- Calculating the color matrix
local M, L = {} 
for i = 1, N do
    L = {}
    for j = 1, N do table.insert(L,"") end
    table.insert(M,L)
end
M[1][1] = "G"; M[1][2] = "B"; M[2][1] = "R"; M[2][2] = "W"  -- initial matrix
local m, m2 = 1, 2
for p = 1, n-1 do
    -- complete the rows and columns from 1+2^p to 2^{p+1}
    m = m2; m2 = 2*m2
    for i = 1+m, m2 do
        for j = 1, m do
            M[i][j] = M[m+1-j][m2+1-i]
        end
    end
    for j = 1+m, m2 do
        for i = 1, m2 do
            M[i][j] = M[i][m2+1-j]
        end
    end
end
local colors = { ["G"]="green!50",  ["W"]="white", ["B"]="blue!50", ["R"]="red!50"}
for i = 1, N do
    for j = 1, N do
        g:Dsquare( Z(j-1,i-1), Z(j-1,i),-1,"draw=gray,fill="..colors[M[i][j]])
    end
end
-- end of matrix colors
-- Calculation of the curve
local curve = { {Z(0.5,2), Z(0.5,1.5), Z(0.5,0.5), Z(1.5,0.5), Z(1.5,1.5), Z(2,1.5)} } --initial curve
m, m2 = 1, 2
for k  = 2, n do
    local br = rotate(curve,-90,Z(m,m))
    br = shift(br,Z(m2,m2))
    local l = sym(curve,{m2,cpx.I})
    local bl = sym(br,{m2,cpx.I}) 
    bl[1][1] = rotate(bl[1][1],-90,bl[1][2])
    curve = concat(bl,br,l,curve)
    m = m2; m2 = 2*m2
end
g:Dpolyline(curve, "line width=1.2pt")
g:Show()
\end{luadraw}
\end{document}

enter image description here

6

Lindenmayer systems were designed for this purpose. See chapter 57 of the manual: Lindenmayer System Drawing Library for more information.

enter image description here

\documentclass{article}

\usepackage{tikz}
\usetikzlibrary {lindenmayersystems}

\pgfdeclarelindenmayersystem{Hilbert curve}{
\symbol{X}{\pgflsystemdrawforward}
\symbol{+}{\pgflsystemturnright}
\symbol{-}{\pgflsystemturnleft}
\rule{A -> +BX-AXA-XB+}
\rule{B -> -AX+BXB+XA-}
}

\begin{document}

\begin{tikzpicture}
\draw[lindenmayer system={Hilbert curve, axiom=A, order=5, angle=90}] lindenmayer system;
\end{tikzpicture}

\end{document}

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.