Arcane  v3.16.6.0
Documentation développeur
Chargement...
Recherche...
Aucune correspondance
SimpleSVGMeshExporter.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2025 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-2025 */
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 nb_node = cell.typeInfo()->linearTypeInfo()->nbLocalNode();
141 for (Integer i = 0; i < nb_node; ++i) {
142 Real3 node_coord_3d = nodes_coord[cell.node(i)];
143 Real2 node_coord(node_coord_3d.x, -node_coord_3d.y);
144 node_coord *= mul_value;
145 if (i == 0)
146 ofile << "M ";
147 else
148 ofile << "L ";
149 // fait une homothétie pour bien voir les faces en cas de soudure.
150 Real2 coord = cell_pos + (node_coord - cell_pos) * 0.98;
151 ofile << coord.x << " " << coord.y << " ";
152 }
153 ofile << "z'";
154 if (cell.isOwn())
155 ofile << " fill='yellow'";
156 else
157 ofile << " fill='orange'";
158 ofile << " stroke='black'";
159 ofile << " stroke-width='1'/>\n";
160 _writeText(cell_pos.x, cell_pos.y, "blue", String::fromNumber(cell.uniqueId().asInt64()), 0.0, false);
161 }
162
163 // Affiche pour chaque noeud son uniqueId().
164 {
165 // Ensemble des noeuds déjà traités pour ne les afficher qu'une fois.
166 std::set<Int32> nodes_done;
167 ENUMERATE_CELL (icell, cells) {
168 Cell cell = *icell;
169 Integer nb_node = cell.nbNode();
170 for (Integer i = 0; i < nb_node; ++i) {
171 Node node = cell.node(i);
172 Int32 lid = node.localId();
173 if (nodes_done.find(lid) != nodes_done.end())
174 continue;
175 nodes_done.insert(lid);
176 Real3 coord_3d = nodes_coord[node];
177 Real2 coord(coord_3d.x, -coord_3d.y);
178 coord *= mul_value;
179 _writeText(coord.x, coord.y, "green", String::fromNumber(node.uniqueId().asInt64()), 0.0, true);
180 }
181 }
182 }
183
184 // Affiche pour chaque face son uniqueId().
185 // Fait une éventuelle rotation pour que l'affichage du numéro de la face soit aligné
186 // avec son segment.
187 {
188 // Ensemble des faces déjà traitées pour ne les afficher qu'une fois.
189 std::set<Int32> faces_done;
190 ENUMERATE_CELL (icell, cells) {
191 Cell cell = *icell;
192 Integer nb_face = cell.nbFace();
193 for (Integer i = 0; i < nb_face; ++i) {
194 Face face = cell.face(i);
195 Int32 lid = face.localId();
196 if (faces_done.find(lid) != faces_done.end())
197 continue;
198 faces_done.insert(lid);
199 // En cas de maillage multi-dim, il est possible
200 // d'avoir des faces réduites à un point.
201 if (face.nbNode()<2)
202 continue;
203 Real3 node0_coord = nodes_coord[face.node(0)];
204 Real3 node1_coord = nodes_coord[face.node(1)];
205 Real3 face_coord_3d = (node0_coord + node1_coord) / 2.0;
206
207 Real2 face_coord(face_coord_3d.x, -face_coord_3d.y);
208 face_coord *= mul_value;
209 Real3 direction = node1_coord - node0_coord;
210 direction = direction.normalize();
211 // TODO: vérifier entre -1.0 et 1.0
212 // Calcule l'angle de la rotation pour que l'affichage numéro de la face soit aligné avec
213 // le trait du bord de la face.
214 double angle = math::abs(std::asin(direction.y)) / M_PI * 180.0;
215 Real2 cell_center = cells_center[cell.localId()];
216 Real2 coord = cell_center + (face_coord - cell_center) * 0.92;
217 _writeText(coord.x, coord.y, "red", String::fromNumber(face.uniqueId().asInt64()), angle, true);
218 }
219 }
220 }
221
222 ofile << "</g>\n";
223 ofile << "</svg>\n";
224}
225
226/*---------------------------------------------------------------------------*/
227/*---------------------------------------------------------------------------*/
228
230SimpleSVGMeshExporter(std::ostream& ofile)
231: m_p(new Impl(ofile))
232{
233}
234
235/*---------------------------------------------------------------------------*/
236/*---------------------------------------------------------------------------*/
237
238SimpleSVGMeshExporter::
239~SimpleSVGMeshExporter()
240{
241 delete m_p;
242}
243
244/*---------------------------------------------------------------------------*/
245/*---------------------------------------------------------------------------*/
246
248write(const CellGroup& cells)
249{
250 m_p->write(cells);
251}
252
253/*---------------------------------------------------------------------------*/
254/*---------------------------------------------------------------------------*/
255
256} // End namespace Arcane
257
258/*---------------------------------------------------------------------------*/
259/*---------------------------------------------------------------------------*/
#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 -*-
Int32 Integer
Type représentant un entier.
double Real
Type représentant un réel.
@ Cell
Le maillage est AMR par maille.
Definition MeshKind.h:52
std::int32_t Int32
Type entier signé sur 32 bits.