[Tex/LaTex] How to draw small a triangle mesh using tikz

floatstikz-pgf

My question is simple but I haven't been able to find any answers.

How can I draw a small a small triangle mesh (4-5) triangles using tikz and label each node and triangle face?

This is a diagram that I would like to recreate (but fewer triangles and labels for each node and triangle face).

enter image description here

Let me be clear I am not trying to generate a mesh or read from a mesh file. I Just want to make a simple diagram with 4-5 triangles with labels.

Best Answer

I'm a beginner at tikz and I just developed this on the fly, so it is not pretty. I also included a lot of diagnostic text so as to help you follow my logic.

It takes a node file that provides node numbers and their coordinates.

And an element file that gives an element number and the nodes that make up the connectivity of the element. Doesn't matter if they are triangles or quads, or something else.

The macro \drawmesh, used inside a tikzpicture creates the string of \draws to formulate the mesh. Note numbers, coordinates, element connectivity are all stored in accessible, expandable arrays \noddat[row,col] and \eledat[row,col].

EDITED to add the macro \labelnodes.

EDITED to add the macro \labelelements.

EDITED to allow for either file input or manual input of node and element data. The file input approach would look like this:

\begin{filecontents*}{nodedata.dat}
1  0.000  0.000
2  1.000  0.000
3  2.000  0.500
4  0.000  1.000
5  1.000  1.000
6  1.750  1.300
7  2.700  0.800
8  2.300  1.700
\end{filecontents*}
\begin{filecontents*}{elementdata.dat}
1  1  2  5
2  5  4  1
3  2  3  6
4  6  5  2
5  3  7  8  6
\end{filecontents*}
\readmesh{nodedata.dat}{elementdata.dat}

The manual input approach like this:

\def\nodedata{1 0.000 0.000,2 1.000 0.000,3 2.000 0.500,
4 0.000 1.000,5 1.000 1.000,6 1.750 1.300,7 2.700 0.800,8 2.300 1.700}
\def\elementdata{1 1 2 5,2 5 4 1,3 2 3 6,4 6 5 2,5 3 7 8 6}
\readmesh{}{}

EDITED to allow several alternatives for \labelnode appearance

EDITED to allow LaTeX style labels for nodes and elements, rather than just numbers.

The MWE:

\documentclass{article}
\usepackage{tikz,listofitems,readarray,filecontents}
\usetikzlibrary{calc}
\begin{filecontents*}{nodedata.dat}
1  0.000  0.000
2  1.000  0.000
3  2.000  0.500
4  0.000  1.000
5  1.000  1.000
6  1.750  1.300
7  2.700  0.800
n_8  2.300  1.700
\end{filecontents*}
\begin{filecontents*}{elementdata.dat}
E_1  1  2  5
2  5  4  1
3  2  3  6
4  6  5  2
5  3  7  n_8  6
\end{filecontents*}

\newcommand\coord[2][]{%
  \edef\comparenode{#2}%
  \foreachitem\zzz\in\noddat[]{%
    \edef\testnode{\noddat[\zzzcnt,1]}%
    \ifx\testnode\comparenode
      \xaddtomacro\tmp{(\noddat[\zzzcnt,2]#1,\noddat[\zzzcnt,3]#1)}\fi
  }%
}

\makeatletter\let\addtomacro\g@addto@macro\makeatother
\newcommand\xaddtomacro[2]{%
  \edef\xtmp{#2}%
  \expandafter\addtomacro\expandafter#1\expandafter{\xtmp}%
}

\newcommand\drawmesh[1][\draw]{%
  \def\tmp{}%
  \foreachitem\z\in\eledat[]{%
    \addtomacro\tmp{#1}%
    \foreachitem\zz\in\eledat[\zcnt]{%
      \ifnum\zzcnt=1\relax\else
        \ifnum\zzcnt<\listlen\eledat[\zcnt]\relax
          \ifnum\zzcnt=2\relax\coord{\zz}\fi
          \addtomacro\tmp{--}%
          \coord{\eledat[\zcnt,\the\numexpr\zzcnt+1\relax]}%
        \else
          \addtomacro\tmp{--}%
          \coord{\eledat[\zcnt,2]}%
        \fi
      \fi
    }%
    \addtomacro\tmp{;}%
  }%
  \tmp%
}

\newcommand\labelnodes[1][\node at]{%
  \foreachitem\z\in\noddat[]{%
    #1 (\noddat[\zcnt,2],\noddat[\zcnt,3]){%
%% ALTERNATIVE 1
%      \textcolor{red}{$\noddat[\zcnt,1]$}};
%% ALTERNATIVE 2
      \fboxsep=0pt\relax
      \colorbox{white}{\color{red}$\noddat[\zcnt,1]$}};
%%
  }%
}

\newcommand\labelelements[1][\node at]{%
  \foreachitem\z\in\eledat[]{%
    \def\tmp{#1 }%
    \addtomacro\tmp{($}
    \foreachitem\zz\in\eledat[\zcnt]{%
      \ifnum\zzcnt=1\relax\else
        \ifnum\zzcnt=2\relax\else\addtomacro\tmp{ + }\fi%
        \coord[{/\the\numexpr\listlen\eledat[\zcnt]-1\relax}]{%
          \eledat[\zcnt,\zzcnt]}%
      \fi
    }%
    \addtomacro\tmp{$)}%
    \xaddtomacro\tmp{{\noexpand\textcolor{blue!70!green}{$\eledat[\zcnt,1]$}};}%
   \tmp
  }%
}

\newcommand\readmesh[2]{%
  \ignoreemptyitems%
  \readarraysepchar{,}%
  \ifx\relax#1\relax\else\readdef{#1}\nodedata\fi
  \ifx\relax#2\relax\else\readdef{#2}\elementdata\fi
  \setsepchar{,/ }%
  \readlist*\noddat{\nodedata}%
  \readlist*\eledat{\elementdata}%
}
\begin{document}
%% FILE INPUT
\readmesh{nodedata.dat}{elementdata.dat}

%% OR MANUAL INPUT
%\def\nodedata{1 0.000 0.000,2 1.000 0.000,3 2.000 0.500,
%4 0.000 1.000,5 1.000 1.000,6 1.750 1.300,7 2.700 0.800,n_8 2.300 1.700}
%\def\elementdata{E_1 1 2 5,2 5 4 1,3 2 3 6,4 6 5 2,5 3 7 n_8 6}
%\readmesh{}{}

Selected data extracts: \eledat[3,3], \noddat[3,3]

Segment list in terms of node numbers:\\
\foreachitem\z\in\eledat[]{%
  Element $\eledat[\zcnt,1]$:
  \foreachitem\zz\in\eledat[\zcnt]{%
    \ifnum\zzcnt=1\relax\else
      \ifnum\zzcnt<\listlen\eledat[\zcnt]\relax
        $\zz$--$\eledat[\zcnt,\the\numexpr\zzcnt+1\relax]$,
      \else
        $\zz$--$\eledat[\zcnt,2]$
      \fi
    \fi
  }%
  \\
}

Segment list in terms of node coordinates:\\
\drawmesh[draw]

\begin{figure}[ht]
\centering
\begin{tikzpicture}[scale=1.5]
  \drawmesh
  \labelnodes
  \labelelements
\end{tikzpicture}
\caption{A finite element mesh}
\end{figure}
\end{document}

enter image description here

Without all the diagnostic stuff included, and choosing manual over file input as the mode of input, the code is a bit more streamlined

\documentclass{article}
\usepackage{tikz,listofitems,readarray}
\usetikzlibrary{calc}
\newcommand\coord[2][]{%
  \edef\comparenode{#2}%
  \foreachitem\zzz\in\noddat[]{%
    \edef\testnode{\noddat[\zzzcnt,1]}%
    \ifx\testnode\comparenode
      \xaddtomacro\tmp{(\noddat[\zzzcnt,2]#1,\noddat[\zzzcnt,3]#1)}\fi
  }%
}
\makeatletter\let\addtomacro\g@addto@macro\makeatother
\newcommand\xaddtomacro[2]{%
  \edef\xtmp{#2}%
  \expandafter\addtomacro\expandafter#1\expandafter{\xtmp}%
}
\newcommand\drawmesh[1][\draw]{%
  \def\tmp{}%
  \foreachitem\z\in\eledat[]{%
    \addtomacro\tmp{#1}%
    \foreachitem\zz\in\eledat[\zcnt]{%
      \ifnum\zzcnt=1\relax\else
        \ifnum\zzcnt<\listlen\eledat[\zcnt]\relax
          \ifnum\zzcnt=2\relax\coord{\zz}\fi
          \addtomacro\tmp{--}%
          \coord{\eledat[\zcnt,\the\numexpr\zzcnt+1\relax]}%
        \else
          \addtomacro\tmp{--}%
          \coord{\eledat[\zcnt,2]}%
        \fi
      \fi
    }%
    \addtomacro\tmp{;}%
  }%
  \tmp%
}
\newcommand\labelnodes[1][\node at]{%
  \foreachitem\z\in\noddat[]{%
    #1 (\noddat[\zcnt,2],\noddat[\zcnt,3]){%
      \fboxsep=0pt\relax
      \colorbox{white}{\color{red}$\noddat[\zcnt,1]$}};
  }%
}
\newcommand\labelelements[1][\node at]{%
  \foreachitem\z\in\eledat[]{%
    \def\tmp{#1 }%
    \addtomacro\tmp{($}
    \foreachitem\zz\in\eledat[\zcnt]{%
      \ifnum\zzcnt=1\relax\else
        \ifnum\zzcnt=2\relax\else\addtomacro\tmp{ + }\fi%
        \coord[{/\the\numexpr\listlen\eledat[\zcnt]-1\relax}]{%
          \eledat[\zcnt,\zzcnt]}%
      \fi
    }%
    \addtomacro\tmp{$)}%
    \xaddtomacro\tmp{{\noexpand\textcolor{blue!70!green}{$\eledat[\zcnt,1]$}};}%
   \tmp
  }%
}
\newcommand\readmesh[2]{%
  \ignoreemptyitems%
  \readarraysepchar{,}%
  \ifx\relax#1\relax\else\readdef{#1}\nodedata\fi
  \ifx\relax#2\relax\else\readdef{#2}\elementdata\fi
  \setsepchar{,/ }%
  \readlist*\noddat{\nodedata}%
  \readlist*\eledat{\elementdata}%
}
\begin{document}
\def\nodedata{1 0.000 0.000,2 1.000 0.000,3 2.000 0.500,
4 0.000 1.000,5 1.000 1.000,6 1.750 1.300,7 2.700 0.800,n_8 2.300 1.700}
\def\elementdata{E_1 1 2 5,2 5 4 1,3 2 3 6,4 6 5 2,5 3 7 n_8 6}
\readmesh{}{}
\begin{figure}[ht]
\centering
\begin{tikzpicture}[scale=1.5]
  \drawmesh
  \labelnodes
  \labelelements
\end{tikzpicture}
\caption{A finite element mesh}
\end{figure}
\end{document}
Related Question