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 \draw
s 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}
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}
tikz
to take that data and plot it.luamesh
package to generate meshes in LuaTeX. Your TeX distribution should already have that.\draw (-1.5,-1) coordinate [label=left:$A$] (A) -- (1.5,1) coordinate [label=above:$B$] (B) -- (1.5,-1)coordinate [label=below right:$C$] (C) -- cycle;
but most likely this is not what you are after, right?