Arcane  v3.14.10.0
Documentation utilisateur
Chargement...
Recherche...
Aucune correspondance
SimpleSVGMeshExporter.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2023 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* SimpleSVGMeshExporter.cc (C) 2000-2023 */
9/* */
10/* Écrivain d'un maillage au format SVG. */
11/*---------------------------------------------------------------------------*/
12/*---------------------------------------------------------------------------*/
13
14// Il faut mettre cela en premier pour MSVC sinon on n'a pas 'M_PI'
15#define _USE_MATH_DEFINES
16#include <cmath>
17
18#include "arcane/SimpleSVGMeshExporter.h"
19
20#include "arcane/utils/Iostream.h"
21#include "arcane/ItemGroup.h"
22#include "arcane/IMesh.h"
23#include "arcane/VariableTypes.h"
24
25#include <set>
26#include <map>
27
28/*---------------------------------------------------------------------------*/
29/*---------------------------------------------------------------------------*/
30
31namespace Arcane
32{
33using std::ostream;
34
35/*---------------------------------------------------------------------------*/
36/*---------------------------------------------------------------------------*/
37
39{
40 public:
41 Impl(ostream& ofile) : m_ofile(ofile){}
42 void _writeText(Real x,Real y,StringView color,StringView text,double rotation,bool do_background);
43 void write(const CellGroup& cells);
44 private:
45 ostream& m_ofile;
46 double m_font_size = 3.0;
47};
48
49/*---------------------------------------------------------------------------*/
50/*---------------------------------------------------------------------------*/
51
52void SimpleSVGMeshExporter::Impl::
53_writeText(Real x,Real y,StringView color,StringView text,double rotation,bool do_background)
54{
55 // Affiche un fond blanc en dessous du texte.
56 if (do_background){
57 m_ofile << "<text x='" << x << "' y='" << y << "' dominant-baseline='central' text-anchor='middle'"
58 << " style='stroke:white; stroke-width:0.6em'";
59 if (rotation!=0.0)
60 m_ofile << " transform='rotate(" << rotation << "," << x << "," << y << ")'";
61 m_ofile << " font-size='" << m_font_size << "'>" << text << "</text>\n";
62 }
63 m_ofile << "<text x='" << x << "' y='" << y << "' dominant-baseline='central' text-anchor='middle'"
64 << " fill='" << color << "'";
65 if (rotation!=0.0)
66 m_ofile << " transform='rotate(" << rotation << "," << x << "," << y << ")'";
67 m_ofile << " font-size='" << m_font_size << "'>" << text << "</text>\n";
68}
69
70/*---------------------------------------------------------------------------*/
71/*---------------------------------------------------------------------------*/
72
73void SimpleSVGMeshExporter::Impl::
74write(const CellGroup& cells)
75{
76 if (cells.null())
77 return;
78 IMesh* mesh = cells.mesh();
79 Int32 mesh_dim = mesh->dimension();
80 if (mesh_dim != 2)
81 ARCANE_FATAL("Invalid dimension ({0}) for mesh. Only 2D mesh is allowed", mesh_dim);
82
83 // Note: comme par défaut en SVG l'origin est en haut à gauche, on prend pour chaque
84 // valeur de 'Y' son opposé pour l'affichage.
85 // NOTE: on pourrait utiliser les transformations de SVG mais c'est plus compliqué à
86 // traiter pour l'affichage du texte
87
88 VariableNodeReal3& nodes_coord = mesh->nodesCoordinates();
89 ostream& ofile = m_ofile;
90 Real mul_value = 1000.0;
91 const Real min_val = std::numeric_limits<Real>::lowest();
92 const Real max_val = std::numeric_limits<Real>::max();
93 Real2 min_bbox(max_val, max_val);
94 Real2 max_bbox(min_val, min_val);
95 // Calcul le centre des mailles et la bounding box du groupe de maille.
96 std::map<Int32, Real2> cells_center;
97 ENUMERATE_CELL (icell, cells) {
98 Cell cell = *icell;
99 Real3 center;
100 Integer nb_node = cell.nbNode();
101 if (nb_node > 0) {
102 for (Integer i = 0; i < nb_node; ++i) {
103 Real3 node_coord_3d = nodes_coord[cell.node(i)] * mul_value;
104 Real2 node_coord(node_coord_3d.x, -node_coord_3d.y);
105 min_bbox = math::min(min_bbox, node_coord);
106 max_bbox = math::max(max_bbox, node_coord);
107 center += node_coord_3d;
108 }
109 center /= nb_node;
110 }
111 Real2 center_2d(center.x, -center.y);
112 cells_center[cell.localId()] = center_2d;
113 }
114
115 Real bbox_width = math::abs(max_bbox.x - min_bbox.x);
116 Real bbox_height = math::abs(max_bbox.y - min_bbox.y);
117 Real max_dim = math::max(bbox_width, bbox_height);
118 m_font_size = max_dim / 80.0;
119
120 // Ajoute 10% des dimensions de part et d'autre de la viewBox pour être sur
121 // que le texte est bien écrit (car il peut déborder de la bounding box)
122 ofile << "<?xml version=\"1.0\"?>\n";
123 ofile << "<svg"
124 << " viewBox='" << min_bbox.x - bbox_width * 0.1 << "," << min_bbox.y - bbox_height * 0.1 << "," << bbox_width * 1.2 << "," << bbox_height * 1.2 << "'"
125 << " xmlns='http://www.w3.org/2000/svg' version='1.1'>\n";
126 ofile << "<!-- V3 bbox min_x=" << min_bbox.x << " min_y=" << min_bbox.y << " max_x=" << max_bbox.x << " max_y=" << max_bbox.y << " -->";
127 ofile << "<title>Mesh</title>\n";
128 ofile << "<desc>MeshExample</desc>\n";
129
130 //ofile << "<g transform='matrix(1,0,0,-1,0,200)'>\n";
131 //ofile << "<g transform='translate(" << min_bbox.x << "," << -min_bbox.y << ")'>\n";
132 ofile << "<g>\n";
133
134 // Affiche pour chaque maille son contour et son uniqueId().
135 ENUMERATE_CELL (icell, cells) {
136 Cell cell = *icell;
137 Real2 cell_pos = cells_center[cell.localId()];
138 Integer nb_node = cell.nbNode();
139 ofile << "<path d='";
140 for (Integer i = 0; i < nb_node; ++i) {
141 Real3 node_coord_3d = nodes_coord[cell.node(i)];
142 Real2 node_coord(node_coord_3d.x, -node_coord_3d.y);
143 node_coord *= mul_value;
144 if (i == 0)
145 ofile << "M ";
146 else
147 ofile << "L ";
148 // fait une homothétie pour bien voir les faces en cas de soudure.
149 Real2 coord = cell_pos + (node_coord - cell_pos) * 0.98;
150 ofile << coord.x << " " << coord.y << " ";
151 }
152 ofile << "z'";
153 if (cell.isOwn())
154 ofile << " fill='yellow'";
155 else
156 ofile << " fill='orange'";
157 ofile << " stroke='black'";
158 ofile << " stroke-width='1'/>\n";
159 _writeText(cell_pos.x, cell_pos.y, "blue", String::fromNumber(cell.uniqueId().asInt64()), 0.0, false);
160 }
161
162 // Affiche pour chaque noeud son uniqueId().
163 {
164 // Ensemble des noeuds déjà traités pour ne les afficher qu'une fois.
165 std::set<Int32> nodes_done;
166 ENUMERATE_CELL (icell, cells) {
167 Cell cell = *icell;
168 Integer nb_node = cell.nbNode();
169 for (Integer i = 0; i < nb_node; ++i) {
170 Node node = cell.node(i);
171 Int32 lid = node.localId();
172 if (nodes_done.find(lid) != nodes_done.end())
173 continue;
174 nodes_done.insert(lid);
175 Real3 coord_3d = nodes_coord[node];
176 Real2 coord(coord_3d.x, -coord_3d.y);
177 coord *= mul_value;
178 _writeText(coord.x, coord.y, "green", String::fromNumber(node.uniqueId().asInt64()), 0.0, true);
179 }
180 }
181 }
182
183 // Affiche pour chaque face son uniqueId().
184 // Fait une éventuelle rotation pour que l'affichage du numéro de la face soit aligné
185 // avec son segment.
186 {
187 // Ensemble des faces déjà traitées pour ne les afficher qu'une fois.
188 std::set<Int32> faces_done;
189 ENUMERATE_CELL (icell, cells) {
190 Cell cell = *icell;
191 Integer nb_face = cell.nbFace();
192 for (Integer i = 0; i < nb_face; ++i) {
193 Face face = cell.face(i);
194 Int32 lid = face.localId();
195 if (faces_done.find(lid) != faces_done.end())
196 continue;
197 faces_done.insert(lid);
198
199 Real3 node0_coord = nodes_coord[face.node(0)];
200 Real3 node1_coord = nodes_coord[face.node(1)];
201 Real3 face_coord_3d = (node0_coord + node1_coord) / 2.0;
202 Real2 face_coord(face_coord_3d.x, -face_coord_3d.y);
203 face_coord *= mul_value;
204 Real3 direction = node1_coord - node0_coord;
205 direction = direction.normalize();
206 // TODO: vérifier entre -1.0 et 1.0
207 // Calcule l'angle de la rotation pour que l'affichage numéro de la face soit aligné avec
208 // le trait du bord de la face.
209 double angle = math::abs(std::asin(direction.y)) / M_PI * 180.0;
210 Real2 cell_center = cells_center[cell.localId()];
211 Real2 coord = cell_center + (face_coord - cell_center) * 0.92;
212 _writeText(coord.x, coord.y, "red", String::fromNumber(face.uniqueId().asInt64()), angle, true);
213 }
214 }
215 }
216
217 ofile << "</g>\n";
218 ofile << "</svg>\n";
219}
220
221/*---------------------------------------------------------------------------*/
222/*---------------------------------------------------------------------------*/
223
225SimpleSVGMeshExporter(std::ostream& ofile)
226: m_p(new Impl(ofile))
227{
228}
229
230/*---------------------------------------------------------------------------*/
231/*---------------------------------------------------------------------------*/
232
233SimpleSVGMeshExporter::
234~SimpleSVGMeshExporter()
235{
236 delete m_p;
237}
238
239/*---------------------------------------------------------------------------*/
240/*---------------------------------------------------------------------------*/
241
243write(const CellGroup& cells)
244{
245 m_p->write(cells);
246}
247
248/*---------------------------------------------------------------------------*/
249/*---------------------------------------------------------------------------*/
250
251} // End namespace Arcane
252
253/*---------------------------------------------------------------------------*/
254/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro envoyant une exception FatalErrorException.
#define ENUMERATE_CELL(name, group)
Enumérateur générique d'un groupe de mailles.
SimpleSVGMeshExporter(std::ostream &ofile)
Créé une instance associée au flux ofile.
void write(const CellGroup &cells)
Exporte les entités du groupe cells.
Vue sur une chaîne de caractères UTF-8.
Definition StringView.h:47
__host__ __device__ Real2 min(Real2 a, Real2 b)
Retourne le minimum de deux Real2.
Definition MathUtils.h:336
T max(const T &a, const T &b, const T &c)
Retourne le maximum de trois éléments.
Definition MathUtils.h:392
ItemGroupT< Cell > CellGroup
Groupe de mailles.
Definition ItemTypes.h:183
MeshVariableScalarRefT< Node, Real3 > VariableNodeReal3
Grandeur au noeud de type coordonnées.
-*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
double Real
Type représentant un réel.
Int32 Integer
Type représentant un entier.