Rheolef  7.1
an efficient C++ finite element environment
field_seq_visu_vtk_paraview.cc
Go to the documentation of this file.
1 //
22 // paraview vtk visualization
23 //
24 // author: Pierre.Saramito@imag.fr
25 //
26 // date: 12 may 1997 update: 23 oct 2011
27 //
28 #include "rheolef/field_expr.h"
29 #include "rheolef/piola_util.h"
30 #include "rheolef/rheostream.h"
31 #include "rheolef/iorheo.h"
32 #include "rheolef/iofem.h"
33 #include "rheolef/interpolate.h"
34 #include "rheolef/render_option.h"
35 
36 using namespace std;
37 namespace rheolef {
38 
39 // ----------------------------------------------------------------------------
40 // field puts
41 // ----------------------------------------------------------------------------
42 // extern:
43 template <class T> odiststream& field_put_vtk (odiststream&, const field_basic<T,sequential>&);
44 
45 template <class T>
46 odiststream&
48 {
49  //
50  // 0) prerequises
51  //
52  using namespace std;
53  typedef typename field_basic<T,sequential>::float_type float_type;
55  typedef point_basic<size_type> ilat;
56  ostream& os = ops.os();
57  //
58  // 1) set render options
59  //
60  render_option popt;
61  popt.valued = uh.get_space().valued();
62  popt.fill = iorheo::getfill(os); // isocontours or color fill
63  popt.elevation = iorheo::getelevation(os);
64  popt.color = iorheo::getcolor(os);
65  popt.gray = iorheo::getgray(os);
66  popt.black_and_white = iorheo::getblack_and_white(os);
67  popt.showlabel = iorheo::getshowlabel(os);
68  popt.stereo = iorheo::getstereo(os);
69  popt.volume = iorheo::getvolume(os);
70  popt.iso = true;
71  popt.cut = iorheo::getcut(os);
72  popt.grid = iorheo::getgrid(os);
73  popt.format = iorheo::getimage_format(os);
74  popt.mark = iorheo::getmark(os);
75  bool is_scalar = (popt.valued == "scalar");
76  if (popt.mark == "") popt.mark = "scalar";
77  if (popt.mark != "" && !is_scalar) popt.mark = "|"+popt.mark +"|";
78  popt.style = (popt.valued == "vector") ? (iorheo::getvelocity(os) ? "velocity" : "deformation") : "none";
79  popt.scale = iorheo::getvectorscale(os);
80  popt.origin = iofem::getorigin(os);
81  popt.normal = iofem::getnormal(os);
82  popt.resolution = iofem::getresolution(os);
83  popt.n_isovalue = iorheo::getn_isovalue(os);
84  popt.n_isovalue_negative = iorheo::getn_isovalue_negative(os);
85  popt.isovalue = iorheo::getisovalue(os); // isovalue is always a Float
86  popt.label = iorheo::getlabel(os);
87  const geo_basic<float_type,sequential>& omega = uh.get_geo();
88  size_type dim = omega.dimension();
89  size_type map_dim = omega.map_dimension();
90  popt.view_2d = (dim == 2);
91  popt.view_map = (dim > map_dim);
92 #if (_RHEOLEF_PARAVIEW_VERSION_MAJOR >= 5) && (_RHEOLEF_PARAVIEW_VERSION_MINOR >= 5)
93  // paraview version >= 5.5 has high order elements
94  popt.high_order = (omega.order() > 1 || uh.get_space().degree() > 1);
95 #else
96  popt.high_order = false;
97 #endif
98 #if (_RHEOLEF_PARAVIEW_VERSION_MAJOR == 5) && (_RHEOLEF_PARAVIEW_VERSION_MINOR == 7)
99  // paraview version == 5.7 has opacity bug
100  popt.have_opacity_bug = true;
101 #else
102  popt.have_opacity_bug = false;
103 #endif
104  popt.xmin = uh.get_geo().xmin();
105  popt.xmax = uh.get_geo().xmax();
106  field_basic<T,sequential> uh_scalar;
107  if (popt.valued == "scalar") {
108  uh_scalar = uh;
109  } else {
110  size_type k = uh.get_space().degree();
111  space_basic<T,sequential> T0h (uh.get_geo(), "P"+itos(k));
112  uh_scalar = interpolate(T0h, norm(uh));
113  }
114  // TODO: u_min=min(uh.u.min,uh.b.min) instead of interpolate norm ?
115  popt.f_min = uh_scalar.min();
116  popt.f_max = uh_scalar.max();
117  //
118  // 2) output data
119  //
120  bool verbose = iorheo::getverbose(os);
121  bool clean = iorheo::getclean(os);
122  bool execute = iorheo::getexecute(os);
123  string basename = iorheo::getbasename(os);
124  string outfile_fmt = "";
125  string tmp = get_tmpdir() + "/";
126  if (!clean) tmp = "";
127  string filelist;
128  string filename = tmp+basename + ".vtk";
129  filelist = filelist + " " + filename;
130  ofstream vtk_os (filename.c_str());
131  odiststream vtk (vtk_os);
132  if (verbose) clog << "! file \"" << filename << "\" created.\n";
133  field_put_vtk (vtk, uh);
134  vtk.close();
135  //
136  // 3) create python data file
137  //
138  std::string py_name = filename = tmp+basename + ".py";
139  filelist = filelist + " " + filename;
140  ofstream py (filename.c_str());
141  if (verbose) clog << "! file \"" << filename << "\" created.\n";
142  point xmin = uh.get_geo().xmin(),
143  xmax = uh.get_geo().xmax();
144  py << popt
145  << endl
146  << "paraview_field_" << popt.valued << "(paraview, \"" << tmp+basename << "\", opt)" << endl
147  << endl
148  ;
149  py.close();
150  //
151  // 4) run pyton
152  //
153  int status = 0;
154  string command;
155  if (execute) {
156  string prog = (popt.format == "") ? "paraview --script=" : "pvbatch --use-offscreen-rendering ";
157  command = "LANG=C PYTHONPATH=" + string(_RHEOLEF_PKGDATADIR) + " " + prog + py_name;
158  if (popt.format != "") command = "DISPLAY=:0.0 " + command;
159  if (popt.stereo && popt.format == "") command = command + " --stereo";
160  if (verbose) clog << "! " << command << endl;
161  status = system (command.c_str());
162  }
163  //
164  // 4) clear vtk data
165  //
166  if (clean) {
167  command = "/bin/rm -f " + filelist;
168  if (verbose) clog << "! " << command << endl;
169  status = system (command.c_str());
170  }
171  return ops;
172 }
173 // --------------------------------------------------------------------
174 // plane cut : via vtk-paraview script
175 // --------------------------------------------------------------------
176 template <class T> idiststream& geo_get_vtk (idiststream&, geo_basic<T,sequential>&);
177 
178 template <class T>
179 field_basic<T,sequential>
181  const field_basic<T,sequential>& uh,
182  const point_basic<T>& origin,
183  const point_basic<T>& normal)
184 {
185  //
186  // 1) prerequises
187  //
188  using namespace std;
189  typedef typename field_basic<T,sequential>::float_type float_type;
191  typedef typename geo_basic<float_type,sequential>::node_type node_type;
192  typedef point_basic<size_type> ilat;
193  ostream& os = std::cout;
194  bool verbose = iorheo::getverbose(os);
195  bool clean = iorheo::getclean(os);
196  bool execute = iorheo::getexecute(os);
197  string basename = iorheo::getbasename(os);
198  string tmp = get_tmpdir() + "/";
199  if (!clean) tmp = "";
200  //
201  // 2) output data
202  //
203  string filelist;
204  string vtk_name = tmp+basename + ".vtk";
205  filelist = filelist + " " + vtk_name;
206  ofstream vtk_os (vtk_name.c_str());
207  odiststream vtk (vtk_os);
208  if (verbose) clog << "! file \"" << vtk_name << "\" created.\n";
209  field_put_vtk (vtk, uh);
210  vtk.close();
211  //
212  // create python script
213  //
214  //
215  // 3) create python data file
216  //
217  string py_name = tmp+basename + "-cut.py";
218  string vtk_cut_name = tmp+basename + "-cut.vtk";
219  filelist = filelist + " " + py_name + " " + vtk_cut_name;
220  ofstream py (py_name.c_str());
221  if (verbose) clog << "! file \"" << py_name << "\" created.\n";
222  py << setprecision(numeric_limits<T>::digits10)
223  << "from paraview.simple import *" << endl
224  << "reader = LegacyVTKReader(FileNames=['" << vtk_name << "'])" << endl
225  << "slice = Slice(SliceType=\"Plane\")" << endl
226  << "slice.SliceOffsetValues = [0.0]" << endl
227  << "slice.SliceType.Origin = " << render_option::python(origin) << endl
228  << "slice.SliceType.Normal = " << render_option::python(normal) << endl
229  << "writer = paraview.simple.CreateWriter(\"" << vtk_cut_name << "\", slice)" << endl
230  << "writer.FileType = 'Ascii'" << endl
231  << "writer.UpdatePipeline()" << endl
232  ;
233  py.close();
234  //
235  // 3) run pyton
236  //
237  int status = 0;
238  string command;
239  command = "LANG=C PYTHONPATH=" + string(_RHEOLEF_PKGDATADIR) + " pvbatch " + py_name;
240  if (verbose) clog << "! " << command << endl;
241  status = system (command.c_str());
242  //
243  // 4) load vtk cutted mesh
244  //
245  ifstream vtk_polydata (vtk_cut_name.c_str());
246  check_macro (vtk_polydata, "field: vtk polydata file \"" << vtk_cut_name << "\" not found.");
247  if (verbose) clog << "! load `" << vtk_cut_name << "'." << endl;
248  idiststream ips_vtk_polydata (vtk_polydata);
249  geo_basic<T,sequential> gamma_cut;
250  geo_get_vtk (ips_vtk_polydata, gamma_cut);
251  gamma_cut.set_name (basename + "-cut");
252  check_macro (gamma_cut.n_node() > 0, "empty mesh & plane intersection: HINT check normal and origin");
253  //
254  // clean
255  //
256  if (clean) {
257  command = "/bin/rm -f " + filelist;
258  if (verbose) clog << "! " << command << endl;
259  status = system (command.c_str());
260  }
261  //
262  // project geometry from 2d/3d on plane in 1d/2d
263  //
264  // 1D) x := dot(OM, tangent)
265  //
266  // 2D) x1 := dot(OM, t1)
267  // x2 := dot(OM, t2)
268  //
269  bool use_projection = true;
270  if (use_projection) {
271  switch (uh.get_geo().dimension()) {
272  case 2: {
273  // project in 1D space
274  gamma_cut.set_dimension (1);
275  point_basic<T> tangent = point_basic<T>(normal[1], -normal[0]);
276  disarray<node_type,sequential> node = gamma_cut.get_nodes();
277  for (size_type i = 0, n = node.size(); i < n; i++) {
278  node[i] = point_basic<T> (dot(node[i], tangent), 0);
279  }
280  gamma_cut.set_nodes (node);
281  break;
282  }
283  case 3: {
284  gamma_cut.set_dimension (2);
285  point_basic<T> t1 = point_basic<T>(1, 0, 0);
286  if (norm(vect(t1, normal)) == Float(0)) t1 = point_basic<T>(0, 1, 0);
287  t1 = t1 - dot(t1,normal)*normal;
288  t1 = t1 / norm(t1);
289  point_basic<T> t2 = vect(normal,t1);
290  disarray<node_type,sequential> node = gamma_cut.get_nodes();
291  for (size_type i = 0, n = node.size(); i < n; i++) {
292  node[i] = point_basic<T> (dot(node[i] - origin, t1), dot(node[i] - origin, t2), 0);
293  }
294  gamma_cut.set_nodes (node);
295  break;
296  }
297  default: error_macro ("unexpected dimension="<< uh.get_geo().dimension());
298  }
299  }
300  // -------------------------------
301  // get field values
302  // polydata header:
303  // POINT_DATA <n_node>
304  // SCALARS scalars float
305  // LOOKUP_TABLE default
306  // -------------------------------
307  string data_type;
308  while (true) {
309  vtk_polydata >> data_type;
310  if ((data_type == "POINT_DATA") ||
311  (data_type == "CELL_DATA" )) {
312  break;
313  }
314  }
315  scatch (vtk_polydata, "default");
316  string approx = (data_type == "POINT_DATA") ? "P1" : "P0";
317  space_basic<T,sequential> V_cut (gamma_cut, approx);
318  field_basic<T,sequential> u_cut (V_cut);
319  u_cut.set_u().get_values (ips_vtk_polydata);
320  return u_cut;
321 }
322 // --------------------------------------------------------------------
323 // isovalue surface : via vtk-paraview script
324 // --------------------------------------------------------------------
325 template <class T> idiststream& geo_get_vtk (idiststream&, geo_basic<T,sequential>&);
326 
327 template <class T>
328 geo_basic<T,sequential>
330 {
331  //
332  // 1) prerequises
333  //
334  using namespace std;
335  typedef typename field_basic<T,sequential>::float_type float_type;
337  typedef typename geo_basic<float_type,sequential>::node_type node_type;
338  typedef point_basic<size_type> ilat;
339  ostream& os = std::cout;
340  bool verbose = iorheo::getverbose(os);
341  bool clean = iorheo::getclean(os);
342  bool execute = iorheo::getexecute(os);
343  T isovalue = iorheo::getisovalue(os);
344  string basename = iorheo::getbasename(os);
345  string tmp = get_tmpdir() + "/";
346  if (!clean) tmp = "";
347  //
348  // 2) output data
349  //
350  string filelist;
351  string vtk_name = tmp+basename + ".vtk";
352  filelist = filelist + " " + vtk_name;
353  ofstream vtk_os (vtk_name.c_str());
354  odiststream vtk (vtk_os);
355  if (verbose) clog << "! file \"" << vtk_name << "\" created.\n";
356  field_put_vtk (vtk, uh);
357  vtk.close();
358  //
359  // create python script
360  //
361  //
362  // 3) create python data file
363  //
364  string py_name = tmp+basename + "-iso.py";
365  string vtk_iso_name = tmp+basename + "-iso.vtk";
366  filelist = filelist + " " + py_name + " " + vtk_iso_name;
367  ofstream py (py_name.c_str());
368  if (verbose) clog << "! file \"" << py_name << "\" created.\n";
369  py << setprecision(numeric_limits<T>::digits10)
370  << "from paraview.simple import *" << endl
371  << "reader = LegacyVTKReader(FileNames=['" << vtk_name << "'])" << endl
372  << "iso_surface = Contour(PointMergeMethod=\"Uniform Binning\")" << endl
373  << "iso_surface.ContourBy = ['POINTS', 'scalar']" << endl
374  << "iso_surface.Isosurfaces = [" << isovalue << "]" << endl
375  << "writer = paraview.simple.CreateWriter(\"" << vtk_iso_name << "\", iso_surface)" << endl
376  << "writer.FileType = 'Ascii'" << endl
377  << "writer.UpdatePipeline()" << endl
378  ;
379  py.close();
380  //
381  // 3) run pyton
382  //
383  int status = 0;
384  string command;
385  command = "LANG=C PYTHONPATH=" + string(_RHEOLEF_PKGDATADIR) + " pvbatch " + py_name;
386  if (verbose) clog << "! " << command << endl;
387  status = system (command.c_str());
388  //
389  // 4) load vtk isosurface mesh
390  //
391  ifstream vtk_polydata (vtk_iso_name.c_str());
392  check_macro (vtk_polydata, "field: vtk polydata file \"" << vtk_iso_name << "\" not found.");
393  if (verbose) clog << "! load `" << vtk_iso_name << "'." << endl;
394  idiststream ips_vtk_polydata (vtk_polydata);
395  geo_basic<T,sequential> gamma_iso;
396  geo_get_vtk (ips_vtk_polydata, gamma_iso);
397  gamma_iso.set_name (basename + "-iso");
398  gamma_iso.set_dimension (uh.get_geo().dimension());
399  check_macro (gamma_iso.n_node() > 0, "empty mesh & plane intersection: HINT check normal and origin");
400  //
401  // clean
402  //
403  if (clean) {
404  command = "/bin/rm -f " + filelist;
405  if (verbose) clog << "! " << command << endl;
406  status = system (command.c_str());
407  }
408  return gamma_iso;
409 }
410 // ----------------------------------------------------------------------------
411 // instanciation in library
412 // ----------------------------------------------------------------------------
413 #define _RHEOLEF_instanciation(T) \
414 template odiststream& \
415 visu_vtk_paraview<Float> ( \
416  odiststream&, \
417  const field_basic<Float,sequential>&); \
418 template field_basic<Float,sequential> \
419 paraview_plane_cut ( \
420  const field_basic<Float,sequential>&, \
421  const point_basic<Float>&, \
422  const point_basic<Float>&); \
423 template geo_basic<Float,sequential> \
424 paraview_extract_isosurface ( \
425  const field_basic<Float,sequential>&);
426 
428 #undef _RHEOLEF_instanciation
429 
430 }// namespace rheolef
rheolef::geo_basic
generic mesh with rerefence counting
Definition: domain_indirect.h:64
rheolef::field_basic::get_space
const space_type & get_space() const
Definition: field.h:300
rheolef::render_option::f_max
Float f_max
Definition: render_option.h:47
rheolef::point_basic
Definition: point.h:87
check_macro
check_macro(expr1.have_homogeneous_space(Xh1), "dual(expr1,expr2); expr1 should have homogeneous space. HINT: use dual(interpolate(Xh, expr1),expr2)")
rheolef::render_option::origin
point origin
Definition: render_option.h:49
rheolef::render_option::grid
bool grid
Definition: render_option.h:44
rheolef::normal
details::field_expr_v2_nonlinear_terminal_function< details::normal_pseudo_function< Float > > normal()
normal: see the expression page for the full documentation
Definition: field_expr_terminal.h:439
rheolef::render_option::black_and_white
bool black_and_white
Definition: render_option.h:45
rheolef::get_tmpdir
std::string get_tmpdir()
get_tmpdir: see the rheostream page for the full documentation
Definition: rheostream.cc:50
rheolef::geo_get_vtk
idiststream & geo_get_vtk(idiststream &ips, geo_basic< T, sequential > &omega)
Definition: geo_seq_get_vtk.cc:39
rheolef::field_basic::float_type
typename float_traits< T >::type float_type
Definition: field.h:245
rheolef::render_option::color
bool color
Definition: render_option.h:45
rheolef::render_option::fill
bool fill
Definition: render_option.h:44
rheolef::python
std::string python(const point_basic< T > &x, size_t d=3)
rheolef::visu_vtk_paraview
odiststream & visu_vtk_paraview(odiststream &, const field_basic< T, sequential > &)
Definition: field_seq_visu_vtk_paraview.cc:47
rheolef::render_option::elevation
bool elevation
Definition: render_option.h:44
rheolef::render_option::f_min
Float f_min
Definition: render_option.h:47
rheolef::odiststream::os
std::ostream & os()
Definition: diststream.h:236
rheolef::render_option::view_map
bool view_map
Definition: render_option.h:45
rheolef::render_option::xmin
point xmin
Definition: render_option.h:49
rheolef::norm
T norm(const vec< T, M > &x)
norm(x): see the expression page for the full documentation
Definition: vec.h:387
rheolef::render_option::gray
bool gray
Definition: render_option.h:45
rheolef::paraview_plane_cut
field_basic< T, sequential > paraview_plane_cut(const field_basic< T, sequential > &uh, const point_basic< T > &origin, const point_basic< T > &normal)
Definition: field_seq_visu_vtk_paraview.cc:180
rheolef::geo_basic< T, sequential >::set_nodes
void set_nodes(const disarray< node_type, sequential > &x)
rheolef::field_basic::get_geo
const geo_type & get_geo() const
Definition: field.h:301
rheolef::geo_basic< T, sequential >::set_dimension
void set_dimension(size_type dim)
rheolef::geo_basic< T, sequential >
Definition: geo.h:1108
rheolef::field_basic::set_u
vec< T, M > & set_u()
Definition: field.h:312
vtk
verbose clean transpose logscale grid shrink ball stereo iso volume skipvtk deformation fastfieldload lattice reader_on_stdin color format format format format format format format format format format format format format format format format vtk
Definition: iorheo-members.h:113
rheolef::render_option::n_isovalue
size_t n_isovalue
Definition: render_option.h:46
rheolef::field_basic::min
T min() const
Definition: field.h:683
rheolef::render_option::stereo
bool stereo
Definition: render_option.h:44
rheolef::interpolate
field_basic< T, M > interpolate(const space_basic< T, M > &V2h, const field_basic< T, M > &u1h)
see the interpolate page for the full documentation
Definition: interpolate.cc:233
rheolef::geo_basic< T, sequential >::set_name
void set_name(std::string name)
mkgeo_ball.clean
clean
Definition: mkgeo_ball.sh:335
rheolef::render_option::cut
bool cut
Definition: render_option.h:44
rheolef::render_option::mark
std::string mark
Definition: render_option.h:50
rheolef::field_basic::max
T max() const
Definition: field.h:699
rheolef::scatch
bool scatch(std::istream &in, const std::string &ch, bool full_match=true)
scatch: see the rheostream page for the full documentation
Definition: scatch.icc:52
rheolef::field_basic
Definition: field_expr_utilities.h:38
rheolef::render_option::scale
Float scale
Definition: render_option.h:47
rheolef::geo_basic< T, sequential >::get_nodes
const disarray< node_type, sequential > & get_nodes() const
Definition: geo.h:1177
rheolef::render_option::volume
bool volume
Definition: render_option.h:44
rheolef::render_option::high_order
bool high_order
Definition: render_option.h:45
rheolef::render_option::xmax
point xmax
Definition: render_option.h:49
rheolef::render_option::normal
point normal
Definition: render_option.h:49
mkgeo_couette.basename
basename
Definition: mkgeo_couette.sh:73
rheolef
This file is part of Rheolef.
Definition: compiler_eigen.h:37
error_macro
#define error_macro(message)
Definition: dis_macros.h:49
rheolef::render_option::label
std::string label
Definition: render_option.h:50
rheolef::render_option
Definition: render_option.h:38
rheolef::odiststream
odiststream: see the diststream page for the full documentation
Definition: diststream.h:126
rheolef::paraview_extract_isosurface
geo_basic< T, sequential > paraview_extract_isosurface(const field_basic< T, sequential > &uh)
Definition: field_seq_visu_vtk_paraview.cc:329
Float
see the Float page for the full documentation
point
see the point page for the full documentation
rheolef::disarray< node_type, sequential >
rheolef::render_option::isovalue
Float isovalue
Definition: render_option.h:47
mkgeo_ball.verbose
verbose
Definition: mkgeo_ball.sh:133
rheolef::render_option::resolution
point_basic< size_t > resolution
Definition: render_option.h:48
rheolef::geo_basic< T, sequential >::n_node
size_type n_node() const
Definition: geo.h:1172
mkgeo_ball.n
n
Definition: mkgeo_ball.sh:150
size_type
field::size_type size_type
Definition: branch.cc:425
rheolef::render_option::style
std::string style
Definition: render_option.h:50
_RHEOLEF_instanciation
#define _RHEOLEF_instanciation(T)
Definition: field_seq_visu_vtk_paraview.cc:413
_RHEOLEF_PKGDATADIR
#define _RHEOLEF_PKGDATADIR
Definition: config.h:240
mkgeo_ball.map_dim
map_dim
Definition: mkgeo_ball.sh:337
rheolef::render_option::iso
bool iso
Definition: render_option.h:44
rheolef::render_option::have_opacity_bug
bool have_opacity_bug
Definition: render_option.h:45
rheolef::itos
std::string itos(std::string::size_type i)
itos: see the rheostream page for the full documentation
mkgeo_ball.tmp
tmp
Definition: mkgeo_ball.sh:380
rheolef::space_basic< T, sequential >
Definition: space.h:361
mkgeo_ball.dim
dim
Definition: mkgeo_ball.sh:307
rheolef::render_option::showlabel
bool showlabel
Definition: render_option.h:44
rheolef::render_option::n_isovalue_negative
size_t n_isovalue_negative
Definition: render_option.h:46
rheolef::render_option::valued
std::string valued
Definition: render_option.h:50
rheolef::field_put_vtk
odiststream & field_put_vtk(odiststream &, const field_basic< T, sequential > &, std::string, bool)
Definition: field_seq_put_vtk.cc:154
rheolef::std
Definition: vec_expr_v2.h:391
mkgeo_contraction.status
status
Definition: mkgeo_contraction.sh:290
mkgeo_ball.command
command
Definition: mkgeo_ball.sh:136
rheolef::details::dot
rheolef::details::is_vec dot
rheolef::render_option::view_2d
bool view_2d
Definition: render_option.h:44
rheolef::vect
point_basic< T > vect(const point_basic< T > &v, const point_basic< T > &w)
Definition: point.h:265
T
Expr1::float_type T
Definition: field_expr.h:218
rheolef::render_option::format
std::string format
Definition: render_option.h:50