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