LehrFEM++ 1.0.0
A simple Finite Element Library for teaching
write_tikz.cc
1
3#include "write_tikz.h"
4
5#include <fstream>
6#include <iostream>
7
8#include "lf/base/base.h"
9#include "lf/mesh/mesh.h"
10
11namespace lf::io {
12
14 return static_cast<TikzOutputCtrl>(static_cast<unsigned int>(lhs) |
15 static_cast<unsigned int>(rhs));
16}
17
19 return static_cast<TikzOutputCtrl>(static_cast<unsigned int>(lhs) &
20 static_cast<unsigned int>(rhs));
21}
22
23bool writeTikZ(const lf::mesh::Mesh &mesh, const std::string &filename,
24 std::function<bool(const lf::mesh::Entity &)> &&selector,
25 TikzOutputCtrl output_ctrl) {
26 // Open output file for writing and quit in case of failure
27 std::ofstream outfile(filename);
28 if (!outfile) {
29 return false;
30 }
31 // ----------------------------------------------------------------
32 // For the enum flags: TikzOutputCtrl
33 bool EdgeNumOn =
34 static_cast<bool>(output_ctrl & TikzOutputCtrl::EdgeNumbering);
35 bool NodeNumOn =
36 static_cast<bool>(output_ctrl & TikzOutputCtrl::NodeNumbering);
37 bool CellNumOn =
38 static_cast<bool>(output_ctrl & TikzOutputCtrl::CellNumbering);
39 bool VerticeNumOn =
40 static_cast<bool>(output_ctrl & TikzOutputCtrl::VerticeNumbering);
41 bool RenderCellsOn =
42 static_cast<bool>(output_ctrl & TikzOutputCtrl::RenderCells);
43 bool ArrowsOn = static_cast<bool>(output_ctrl & TikzOutputCtrl::ArrowTips);
44 bool WithPreamble =
45 static_cast<bool>(output_ctrl & TikzOutputCtrl::WithPreamble);
46
47 using size_type = std::size_t; // lf::base::size_type;
48 using dim_t = lf::base::RefEl::dim_t; // lf::base::dim_t;
49 const Eigen::MatrixXd zero(Eigen::MatrixXd::Zero(0, 1));
50
51 // Obtain topological dimension of the mesh
52 const dim_t dim_mesh = mesh.DimMesh();
53 LF_VERIFY_MSG(dim_mesh == 2, "writeTikZ() only available for 2D meshes");
54
55 // Run through nodes
56 const dim_t node_codim(dim_mesh); // Codimension number for nodes in the mesh
57 const size_type no_of_nodes =
58 mesh.NumEntities(node_codim); // No. of nodes in codimension for nodes
59 size_type node_count = 0;
60
61 // START writing to file
62 if (WithPreamble) {
63 outfile << "\\documentclass[12pt,a4paper]{article}\n\\usepackage{tikz}"
64 "\n\\begin{document}\n"
65 << std::endl;
66 }
67 outfile << "% TikZ document graphics \n";
68
69 // Scale font size for large meshes
70 if (no_of_nodes > 50) {
71 outfile << "\\begin{tikzpicture}[scale=6, >= stealth, inner sep=0pt, "
72 "minimum size=0.2cm]\n";
73 outfile << "\\tikzstyle{every node}=[font=\\tiny]\n";
74 } else {
75 outfile << "\\begin{tikzpicture}[scale=4, >= stealth, inner sep=0pt, "
76 "minimum size=0.35cm]\n";
77 }
78
79 // ---------------------------------------------------------------------------
80
81 // Loop through codimensions
82 for (int co_dim = 0; co_dim <= dim_mesh; co_dim++) {
83 // Loop through all types of entities
84 for (const mesh::Entity *obj : mesh.Entities(co_dim)) {
85 if (selector(*obj)) { // IF SELECTOR -------
86 size_type obj_idx = mesh.Index(*obj);
87 lf::base::RefEl obj_refel = obj->RefEl();
88 int num_nodes_obj = obj_refel.NumNodes();
89 const geometry::Geometry *obj_geo_ptr = obj->Geometry();
90 const Eigen::MatrixXd &obj_corners(obj_refel.NodeCoords());
91 const Eigen::MatrixXd vertices = obj_geo_ptr->Global(obj_corners);
92 const Eigen::MatrixXd center =
93 vertices.rowwise().sum() / vertices.cols();
94 Eigen::MatrixXd center_mat(center.rows(), num_nodes_obj);
95
96 switch (obj_refel) {
98 if (NodeNumOn) {
99 outfile << "\\draw[red, fill = white] (" << vertices(0, 0) << ","
100 << vertices(1, 0) << ") "
101 << "node[draw, circle, fill = white] {" << obj_idx
102 << "};\n";
103 } else {
104 outfile << "\\draw[red] (" << vertices(0, 0) << ","
105 << vertices(1, 0) << ") "
106 << "node[] {*};\n";
107 } // if NodeNumOn
108 break;
109
110 } // case kPoint
111
113 center_mat << center, center;
114 const Eigen::MatrixXd scaled_vertices =
115 vertices * 0.80 + center_mat * 0.2;
116 const Eigen::MatrixXd semi_scaled_vertices =
117 vertices * 0.95 + center_mat * 0.05;
118
119 if (ArrowsOn) {
120 if (EdgeNumOn && NodeNumOn) {
121 outfile << "\\draw[->] (" << scaled_vertices(0, 0) << ","
122 << scaled_vertices(1, 0) << ") -- node[black] {"
123 << obj_idx << "} "
124 << "(" << scaled_vertices(0, 1) << ","
125 << scaled_vertices(1, 1) << ");\n";
126 } else if (NodeNumOn && !EdgeNumOn) {
127 outfile << "\\draw[->] (" << scaled_vertices(0, 0) << ","
128 << scaled_vertices(1, 0) << ") -- "
129 << "(" << scaled_vertices(0, 1) << ","
130 << scaled_vertices(1, 1) << ");\n";
131 } else if (!NodeNumOn && EdgeNumOn) {
132 outfile << "\\draw[->] (" << semi_scaled_vertices(0, 0) << ","
133 << semi_scaled_vertices(1, 0) << ") -- node[black] {"
134 << obj_idx << "} "
135 << "(" << semi_scaled_vertices(0, 1) << ","
136 << semi_scaled_vertices(1, 1) << ");\n";
137 } else if (!NodeNumOn && !EdgeNumOn) {
138 outfile << "\\draw[->] (" << semi_scaled_vertices(0, 0) << ","
139 << semi_scaled_vertices(1, 0) << ") -- "
140 << "(" << semi_scaled_vertices(0, 1) << ","
141 << semi_scaled_vertices(1, 1) << ");\n";
142 } else {
143 std::cout << "Check EdgeNumOn and NodeNumOn for kSegment "
144 << obj_idx << std::endl;
145 }
146
147 } else {
148 if (EdgeNumOn) {
149 outfile << "\\draw[] (" << vertices(0, 0) << ","
150 << vertices(1, 0) << ") -- node[black] {" << obj_idx
151 << "} "
152 << "(" << vertices(0, 1) << "," << vertices(1, 1)
153 << ");\n";
154 } else if (!EdgeNumOn) {
155 outfile << "\\draw[] (" << vertices(0, 0) << ","
156 << vertices(1, 0) << ") -- "
157 << "(" << vertices(0, 1) << "," << vertices(1, 1)
158 << ");\n";
159 } else {
160 std::cout << "Check EdgeNumOn and NodeNumOn for kSegment "
161 << obj_idx << std::endl;
162 }
163 } // arrows on
164
165 break;
166 } // case kSegment
167
168 case lf::base::RefEl::kTria(): {
169 center_mat << center, center, center;
170 const Eigen::MatrixXd scaled_vertices =
171 vertices * 0.70 + center_mat * 0.30;
172
173 if (RenderCellsOn) {
174 if (VerticeNumOn) {
175 outfile << "\\draw[green] (" << scaled_vertices(0, 0) << ","
176 << scaled_vertices(1, 0) << ") node[] {0} -- ("
177 << scaled_vertices(0, 1) << "," << scaled_vertices(1, 1)
178 << ") node[] {1} -- (" << scaled_vertices(0, 2) << ","
179 << scaled_vertices(1, 2) << ") node[] {2} -- cycle;\n";
180 } else {
181 outfile << "\\draw[green] (" << scaled_vertices(0, 0) << ","
182 << scaled_vertices(1, 0) << ") -- ("
183 << scaled_vertices(0, 1) << "," << scaled_vertices(1, 1)
184 << ") -- (" << scaled_vertices(0, 2) << ","
185 << scaled_vertices(1, 2) << ") -- cycle;\n";
186 } // if EdgeNumOn
187
188 if (CellNumOn) {
189 outfile << "\\draw[green] (" << center(0, 0) << ","
190 << center(1, 0) << ") node[] {" << obj_idx << "};\n";
191 }
192
193 } // RenderCellsOn
194 break;
195 } // case kTria
196
197 case lf::base::RefEl::kQuad(): {
198 center_mat << center, center, center, center;
199 const Eigen::MatrixXd scaled_vertices =
200 vertices * 0.70 + center_mat * 0.3;
201
202 if (RenderCellsOn) {
203 if (VerticeNumOn) {
204 outfile << "\\draw[magenta] (" << scaled_vertices(0, 0) << ","
205 << scaled_vertices(1, 0) << ") node[] {0} -- ("
206 << scaled_vertices(0, 1) << "," << scaled_vertices(1, 1)
207 << ") node[] {1} -- (" << scaled_vertices(0, 2) << ","
208 << scaled_vertices(1, 2) << ") node[] {2} -- ("
209 << scaled_vertices(0, 3) << "," << scaled_vertices(1, 3)
210 << ") node[] {3} -- cycle;\n";
211 } else {
212 outfile << "\\draw[magenta] (" << scaled_vertices(0, 0) << ","
213 << scaled_vertices(1, 0) << ") -- ("
214 << scaled_vertices(0, 1) << "," << scaled_vertices(1, 1)
215 << ") -- (" << scaled_vertices(0, 2) << ","
216 << scaled_vertices(1, 2) << ") -- ("
217 << scaled_vertices(0, 3) << "," << scaled_vertices(1, 3)
218 << ") -- cycle;\n";
219 }
220
221 if (CellNumOn) {
222 outfile << "\\draw[magenta] (" << center(0, 0) << ","
223 << center(1, 0) << ") node[] {" << obj_idx << "};\n";
224 }
225
226 } // RenderCellsOn
227
228 break;
229 } // case kQuad
230
231 default: {
232 std::cout << "Error for object " << obj_idx << " in co-dim "
233 << co_dim << std::endl;
234 std::cout << "Object type: " << obj_refel << std::endl;
235 break;
236 } // default
237 } // switch
238 } // IF SELECTOR --------------------
239 } // for entities
240
241 node_count++;
242 // LF_VERIFY_MSG(node_count == no_of_nodes, "Node count mismatch");
243 } // for codim
244
245 outfile << "\\end{tikzpicture}\n";
246 if (WithPreamble) {
247 outfile << "\n\\end{document}" << std::endl;
248 }
249 return true;
250} // writetikz
251
252// Second version of writeTikZ using default selector
253bool writeTikZ(const lf::mesh::Mesh &mesh, const std::string &filename,
254 TikzOutputCtrl output_ctrl) {
255 return writeTikZ(mesh, filename, base::PredicateTrue{}, output_ctrl);
256}
257
258} // namespace lf::io
A Function Object that can be invoked with any arguments and that always returns the value true.
Represents a reference element with all its properties.
Definition: ref_el.h:106
static constexpr RefEl kSegment()
Returns the (1-dimensional) reference segment.
Definition: ref_el.h:150
constexpr RefEl(RefElType type) noexcept
Create a RefEl from a lf::base::RefElType enum.
Definition: ref_el.h:172
unsigned int dim_t
Definition: ref_el.h:129
const Eigen::MatrixXd & NodeCoords() const
Get the coordinates of the nodes of this reference element.
Definition: ref_el.h:238
static constexpr RefEl kPoint()
Returns the (0-dimensional) reference point.
Definition: ref_el.h:141
static constexpr RefEl kTria()
Returns the reference triangle.
Definition: ref_el.h:158
constexpr size_type NumNodes() const
The number of nodes of this reference element.
Definition: ref_el.h:210
static constexpr RefEl kQuad()
Returns the reference quadrilateral.
Definition: ref_el.h:166
Interface class for shape information on a mesh cell in the spirit of parametric finite element metho...
virtual Eigen::MatrixXd Global(const Eigen::MatrixXd &local) const =0
Map a number of points in local coordinates into the global coordinate system.
Interface class representing a topological entity in a cellular complex
Definition: entity.h:39
Abstract interface for objects representing a single mesh.
virtual size_type NumEntities(unsigned codim) const =0
The number of Entities that have the given codimension.
virtual unsigned DimMesh() const =0
The dimension of the manifold described by the mesh, or equivalently the maximum dimension of the ref...
virtual nonstd::span< const Entity *const > Entities(unsigned codim) const =0
All entities of a given codimension.
virtual size_type Index(const Entity &e) const =0
Acess to the index of a mesh entity of any co-dimension.
unsigned int dim_t
type for dimensions and co-dimensions and numbers derived from them
Definition: base.h:36
Mesh input (from file) and output (in various formats) facilities.
Definition: gmsh_file_v2.cc:35
TikzOutputCtrl
Enum flags: TikzOutputCtrl for output control of mesh drawn in TikZ.
Definition: write_tikz.h:24
bool writeTikZ(const lf::mesh::Mesh &mesh, const std::string &filename, std::function< bool(const lf::mesh::Entity &)> &&selector, TikzOutputCtrl output_ctrl)
Writes mesh to file in TikZ Graphics format. File as input in LaTeX will draw the mesh.
Definition: write_tikz.cc:23
TikzOutputCtrl operator&(const TikzOutputCtrl &lhs, const TikzOutputCtrl &rhs)
Definition: write_tikz.cc:18
TikzOutputCtrl operator|(const TikzOutputCtrl &lhs, const TikzOutputCtrl &rhs)
Definition: write_tikz.cc:13