4

I want to draw a structure that branches at regular intervals, kinda like a binary tree, using tikz.

If I were to write the algorithm recursively it would be something like this (in psuedo code):

Branch(node, level, maximum)
    If level = maximum, stop 
    Draw edge to node to the left, 
    Draw edge to node to the right, 
    Branch(left, level+1, maximum)
    Branch(right, level+1, maximum)

The reason why I need to do this is as follows. I am trying to write a proof that links together the recursive definition of B splines and the algorithm people in computer graphics use to calculate a B spline efficiently, which is actually not obvious if you just look at the picture.

I originally asked this question, which had an excellent answer to what I was asking for. However I face the issue that that solution relies on rotating grids, which limits the kind of labeling, coloring and drawing I can make.

I need to be able to color each individual edge on the lattice a different color. Because I need to write a step by step "comic strip" of how the algorithm navigates the space defined by the spline control intervals and control points.

Thus I believe the most effective way is to write an algorithm that draws this using tikz myself.

However I have never used the package before, and although I am knoweldgeable with both programming and compute graphics, the specificities of the language is throwing me off, like for example:

\begin{tikzpicture}[thick,scale=0.8]
    \draw (0:0) -- (45:1);
    \draw (-45:1) -- (0:0);
\end{tikzpicture}

Results in: enter image description here

WHich is rotated by 45 degrees from what I want, which would normally mean that the first coordinate is y and the second x, but if I flip the coordinates in that command, I get: enter image description here

If I wanted to render a lattice structure similar to the one in the question, how could I approach the issue?

EDIT: So apparently colons are used for polar coordinates and comas for cartesian, that;s half of my confusion. Is there a way to define functions/subroutines with TIKZ?

enter image description here

Essentially if I can write a function that takes a single integer parameter I can solve my own problem.

  • 1
    This is more or less precisely what the lindenmayersystems library of TikZ does. There is also the turtle library. However, I do not understand the question well enough to say much more. (Ah, and your confusion is about polar coordinates, in (45:1) the first entry is the angle and the second one the radius. If you swap them, you get a coordinate with 1 degree angle and an enormous radius of 45cm.) – user194703 Dec 17 '19 at 2:43
  • Is there something I can do or add (or remove) to make it more clear? I am essentially trying to achieve the same visual result of the question you answered, but I don;t want to rely on the grid because that gives me less control over labeling and coloring – Makogan Dec 17 '19 at 2:45
  • I still think that the grid is a reasonable first step, and you might want to use your own local coordinate system that allows you to access the various edges in a simpler way. The lindenmayersystems help if you recursively draw something recursively, see e.g. tex.stackexchange.com/q/119602/194703. But this does not make it easier to access individual stretches of the resulting diagram. – user194703 Dec 17 '19 at 2:49
  • I can build what I need from first principles as well. My main issue seems that the library doesn't seem to behave the way I expect. for example: imgur.com/umnpT80.png In my mind that should have looked like 7 parallel lines ofsetted by a space of 10 units. But that;s not at all what came out. Even just this doesn;t seem to behave as I expect: imgur.com/3xWA586.png – Makogan Dec 17 '19 at 2:52
  • ~~Oh NO! this thing is inpolar coordinates, that;s why, can I make it cartesian somehow?~~ Oh I see you use commas for cartesian and colons for polar – Makogan Dec 17 '19 at 3:00
4

If your question is whether you can draw the net with a two nested foreach loops, the answer is yes. These loops are stored in a a pic, which takes two arguments, one is the number of vertical layers and the other one controls its horizontal dimension.

\documentclass[tikz,border=3mm]{standalone}
\begin{document}
\begin{tikzpicture}[pics/net/.style 2 args={code={%
\foreach \Y [evaluate=\Y as \Xmax using {int(\Y+#2)}] in {1,...,#1}
 {\foreach \X in {-\Xmax,...,\Xmax}
  {\draw[line cap=rect] (\X,\Y) -- ++ (-135:{sqrt(1/2)})
   -- ++ (-45:{sqrt(1/2)}) -- ++ (45:{sqrt(1/2)})
   -- ++ (135:{sqrt(1/2)}) 
   \ifnum\X=\Xmax (\X,\Y) ++ (-45:{sqrt(1/2)}) -- ++ (45:{sqrt(1/2)})\fi
   \ifnum\X=-\Xmax (\X,\Y) ++ (-135:{sqrt(1/2)}) -- ++ (135:{sqrt(1/2)})\fi
   ;}}}}]
   \path (0,3) pic[yscale=-1]{net={4}{2}}
    (0,-5) pic{net={2}{1}};
\end{tikzpicture}
\end{document}

enter image description here

| improve this answer | |
3

It's not tikz, but what the heck. Here is a metapost method. enter image description here

Compile with lualatex.

\documentclass{article}
\usepackage{luamplib}
\mplibnumbersystem{double}
\begin{document}
\begin{mplibcode}
def branch(expr n,l,m,k)=
    begingroup;
    save nl_,nr_; % make local
    pair nl_,nr_; % declare variables as (x,y) pairs
    if l<m: % essentially your pseudocode
        nl_:=((xpart n)-1,(ypart n)-1); % xpart=x-coordinate of pair
        nr_:=((xpart n)+1,(ypart n)-1); % as above
        draw (n--nl_) scaled k; % a--b = straight line from pair a to pair b
        draw (n--nr_) scaled k; 
        branch(nl_,l+1,m,k);
        branch(nr_,l+1,m,k);
    fi;
    endgroup;
enddef;

beginfig(0);
u:=.5cm;  % scale
for i=0 upto 5: 
    branch((2i,0),0,6,u);
endfor;
z0=u*(2,0); % =(2u,0)=(1cm,0cm)
z1=u*(3,-1); % z1 means the same as z[1]...indexed list z
z2=u*(2,-2); % z is a predefined variable name of type pair
z3=u*(1,-3);
z4=u*(0,-4);
z5=u*(1,-5);
z6=u*(2,-6);
draw z0--z1--z2--z3--z4--z5--z6 withpen pencircle scaled 2bp withcolor blue;
for i=0 upto 6:
    fill fullcircle scaled 4bp shifted z[i];
endfor;
endfig;
\end{mplibcode}
\end{document}

For a more complex example that includes changes in color and labels

enter image description here

\documentclass[border=10cm]{standalone}

\usepackage{luamplib}
\mplibnumbersystem{double}
\usepackage[margin=0.5cm]{geometry}

\begin{document}
{\centering
\begin{mplibcode}
u:=1cm;

% Draw a lattice layer upside down
% parameters are: horizontal offset, level (height), thickness of % the lines, color of the lines
vardef inverted_layer(expr n,l,s,c)= 
     %declare variables
    save parent, lc, rc; 
    pair parent, lc, rc;  
    parent:=(n, l);
    % assign values of left and child nodes, forming a 'v' pattern
    lc :=  (n-1, l+1);
    rc :=  (n+1, l+1);
    draw u*parent--u*rc withpen pencircle scaled s withcolor c;
    draw u*parent--u*lc withpen pencircle scaled s withcolor c;
enddef;

% Draw and inverted lattice
% parameters are: horizontal offset, number of layers, thickness
% of the lines, color of the lines
vardef inverted_lattice(expr n,l, size, color)=
    for i=0 upto l:
        for j=0 upto i:
            inverted_layer((j + n)*2 - i, i-(l+1), size, color);
        endfor;
    endfor;
enddef;

% Similar as above except the lattice isn;t upside down
vardef layer(expr n,l,s,c)=
    save parent, lc, rc;  
    pair parent, lc, rc;  
    parent:=(n, l);
    lc :=  (n-1, l-1);
    rc :=  (n+1, l-1);
    draw u*parent--u*rc withpen pencircle scaled s withcolor c;
    draw u*parent--u*lc withpen pencircle scaled s withcolor c;
enddef;

vardef lattice(expr n,l, size, color)=
for i=0 upto l:
    for j=0 upto i:
            layer((j + n)*2 - i, -i, size, color);
        endfor;
    endfor;
enddef;

% Start figure
beginfig(0);
% Create labels for the bottom level
for i=-3 upto 9:
    save j;
    numeric j;
    j := i - 3;
    % No plus symbol for egatives
    if i<0:
        label.top(textext("\huge$K_{i"& decimal j &"}$"), (i*u*2,-7*u));
    % no arithmetic symbols for 0
    elseif i-3=0:
        label.top(textext("\huge$K_{i}$"), (i*u*2,-7*u));
    % regular labeling
    else:
        label.top(textext("\huge$K_{i+"& decimal j &"}$"), (i*u*2,-7*u));
    fi
endfor;
for i=0 upto 6:
    %create labels for the top level 
    if i-3<0:
        label.top(textext("\huge$C_{i"& decimal(i-3)&"}$"), (i*u*2,0));
    elseif i-3=0:   
        label.top(textext("\huge$C_{i}$"), (i*u*2,0));
    else:
        label.top(textext("\huge$C_{i+"& decimal(i-3) &"}$"), (i*u*2,0));
    fi
    % draw 5 regular lattices in black at different offsets
    % so that they partially overlap
    lattice(i,5,1, black);
endfor;

% draw the inverted red lattice with thick lines
inverted_lattice(3,5,3, red);

z0=u*(2,0);
z1=u*(3,-1);
z2=u*(2,-2);
z3=u*(1,-3);
z4=u*(0,-4);
z5=u*(1,-5);
z6=u*(2,-6);

% draw the blue path
draw z0--z1--z2--z3--z4--z5--z6 withpen pencircle scaled 3bp withcolor blue;
for i=0 upto 6:
    fill fullcircle scaled 4bp shifted z[i];
endfor;
endfig;
\end{mplibcode}
\par}
\end{document}
| improve this answer | |
  • This seems very promising, although I am struggling a bit with the syntax – Makogan Dec 17 '19 at 4:22
  • Also to answer your comment, it needs to be hidden because the top portion of that figure has less points than the bottom. – Makogan Dec 17 '19 at 4:23
  • I'll comment it a bit. I'm just learning metapost myself so I'm not completely sure of all the details. – Scott H. Dec 17 '19 at 4:24
  • @Makogan I had to hide it because I was getting an error if it wasn't hidden. hide hides the execution(?) from the compiler not the output...something was going on with the double call to the function and I'm not sure what. – Scott H. Dec 17 '19 at 4:35
  • So, trying to modify your script, apparently z0 is a good enough variable name but x10 isn't? imgur.com/vSWTL5E.png Why is that failing to compile, do you know? – Makogan Dec 17 '19 at 4:43

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.