GNU Octave  6.2.0
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
gl2ps-print.cc
Go to the documentation of this file.
1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2009-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING. If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 #if defined (HAVE_CONFIG_H)
27 # include "config.h"
28 #endif
29 
30 // Both header files are required outside of HAVE_GLP2S_H
31 #include "errwarn.h"
32 #include "gl2ps-print.h"
33 
34 #if defined (HAVE_GL2PS_H) && defined (HAVE_OPENGL)
35 
36 #include <cstdio>
37 
38 #include <limits>
39 
40 #include <gl2ps.h>
41 
42 #include "lo-mappers.h"
43 #include "oct-locbuf.h"
44 #include "tmpfile-wrapper.h"
45 #include "unistd-wrappers.h"
46 #include "unistr-wrappers.h"
47 #include "unwind-prot.h"
48 
49 #include "gl-render.h"
50 #include "interpreter-private.h"
51 #include "oct-opengl.h"
52 #include "sighandlers.h"
53 #include "sysdep.h"
54 #include "text-renderer.h"
55 
56 namespace octave
57 {
58  static void
59  safe_pclose (FILE *f)
60  {
61  if (f)
62  octave::pclose (f);
63  }
64 
65  static void
66  safe_fclose (FILE *f)
67  {
68  if (f)
69  std::fclose (f);
70  }
71 
72  class
73  OCTINTERP_API
74  gl2ps_renderer : public opengl_renderer
75  {
76  public:
77 
78  gl2ps_renderer (opengl_functions& glfcns, FILE *_fp,
79  const std::string& _term)
80  : opengl_renderer (glfcns), fp (_fp), term (_term),
81  fontsize (), fontname (), buffer_overflow (false)
82  { }
83 
84  ~gl2ps_renderer (void) = default;
85 
86  // FIXME: should we import the functions from the base class and
87  // overload them here, or should we use a different name so we don't
88  // have to do this? Without the using declaration or a name change,
89  // the base class functions will be hidden. That may be OK, but it
90  // can also cause some confusion.
92 
93  void draw (const graphics_object& go, const std::string& print_cmd);
94 
95  protected:
96 
97  Matrix render_text (const std::string& txt,
98  double x, double y, double z,
99  int halign, int valign, double rotation = 0.0);
100 
101  void set_font (const base_properties& props);
102 
103  static bool has_alpha (const graphics_handle& h)
104  {
105  bool retval = false;
106 
107  gh_manager& gh_mgr = __get_gh_manager__ ("gl2ps_renderer::has_alpha");
108 
109  graphics_object go = gh_mgr.get_object (h);
110 
111  if (! go.valid_object ())
112  return retval;
113 
114  if (go.isa ("axes") || go.isa ("hggroup"))
115  {
116  Matrix children = go.get ("children").matrix_value ();
117  for (octave_idx_type ii = 0; ii < children.numel (); ii++)
118  {
119  retval = has_alpha (graphics_handle (children(ii)));
120  if (retval)
121  break;
122  }
123  }
124  else if (go.isa ("patch") || go.isa ("surface"))
125  {
126  octave_value fa = go.get ("facealpha");
127  if (fa.is_scalar_type () && fa.is_double_type ()
128  && fa.double_value () < 1)
129  retval = true;
130  }
131 
132  return retval;
133  }
134 
135  void draw_axes (const axes::properties& props)
136  {
137  // Initialize a sorting tree (viewport) in gl2ps for each axes
138  GLint vp[4];
139  m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
140  gl2psBeginViewport (vp);
141 
142 
143  // Don't remove hidden primitives when some of them are transparent
144  GLint opts;
145  gl2psGetOptions (&opts);
146  if (has_alpha (props.get___myhandle__ ()))
147  {
148  opts &= ~GL2PS_OCCLUSION_CULL;
149  // FIXME: currently the GL2PS_BLEND (which is more an equivalent of
150  // GL_ALPHA_TEST than GL_BLEND) is not working on a per primitive
151  // basis. We thus set it once per viewport.
152  gl2psEnable (GL2PS_BLEND);
153  }
154  else
155  {
156  opts |= GL2PS_OCCLUSION_CULL;
157  gl2psDisable (GL2PS_BLEND);
158  }
159 
160  gl2psSetOptions (opts);
161 
162  // Draw and finish () or there may be primitives missing in the gl2ps
163  // output.
165  finish ();
166 
167  // Finalize viewport
168  GLint state = gl2psEndViewport ();
169  if (state == GL2PS_NO_FEEDBACK && props.is_visible ())
170  warning ("gl2ps_renderer::draw_axes: empty feedback buffer and/or nothing else to print");
171  else if (state == GL2PS_ERROR)
172  error ("gl2ps_renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR");
173 
174  buffer_overflow |= (state == GL2PS_OVERFLOW);
175 
176  // Don't draw background for subsequent viewports (legends, subplots,
177  // etc.)
178  gl2psGetOptions (&opts);
179  opts &= ~GL2PS_DRAW_BACKGROUND;
180  gl2psSetOptions (opts);
181  }
182 
183  void draw_text (const text::properties& props);
184 
185  void draw_image (const image::properties& props);
186  void draw_pixels (int w, int h, const float *data);
187  void draw_pixels (int w, int h, const uint8_t *data);
188  void draw_pixels (int w, int h, const uint16_t *data);
189 
190  void init_marker (const std::string& m, double size, float width)
191  {
192  opengl_renderer::init_marker (m, size, width);
193 
194  // FIXME: gl2ps can't handle closed contours so we set linecap/linejoin
195  // round to obtain a better looking result for some markers.
196  if (m == "o" || m == "v" || m == "^" || m == ">" || m == "<" || m == "h"
197  || m == "hexagram" || m == "p" || m == "pentagram")
198  {
199  set_linejoin ("round");
200  set_linecap ("round");
201  }
202  else
203  {
204  set_linejoin ("miter");
205  set_linecap ("square");
206  }
207  }
208 
209  void set_linestyle (const std::string& s, bool use_stipple = false,
210  double linewidth = 0.5)
211  {
212  opengl_renderer::set_linestyle (s, use_stipple, linewidth);
213 
214  if (s == "-" && ! use_stipple)
215  gl2psDisable (GL2PS_LINE_STIPPLE);
216  else
217  gl2psEnable (GL2PS_LINE_STIPPLE);
218  }
219 
220  void set_linecap (const std::string& s)
221  {
223 
224 #if defined (HAVE_GL2PSLINEJOIN)
225  if (s == "butt")
226  gl2psLineCap (GL2PS_LINE_CAP_BUTT);
227  else if (s == "square")
228  gl2psLineCap (GL2PS_LINE_CAP_SQUARE);
229  else if (s == "round")
230  gl2psLineCap (GL2PS_LINE_CAP_ROUND);
231 #endif
232  }
233 
234  void set_linejoin (const std::string& s)
235  {
237 
238 #if defined (HAVE_GL2PSLINEJOIN)
239  if (s == "round")
240  gl2psLineJoin (GL2PS_LINE_JOIN_ROUND);
241  else if (s == "miter")
242  gl2psLineJoin (GL2PS_LINE_JOIN_MITER);
243  else if (s == "chamfer")
244  gl2psLineJoin (GL2PS_LINE_JOIN_BEVEL);
245 #endif
246  }
247 
248  void set_polygon_offset (bool on, float offset = 0.0f)
249  {
250  if (on)
251  {
253  gl2psEnable (GL2PS_POLYGON_OFFSET_FILL);
254  }
255  else
256  {
257  gl2psDisable (GL2PS_POLYGON_OFFSET_FILL);
259  }
260  }
261 
262  void set_linewidth (float w)
263  {
264  gl2psLineWidth (w);
265  }
266 
267  private:
268 
269  // Use xform to compute the coordinates of the string list
270  // that have been parsed by freetype.
271  void fix_strlist_position (double x, double y, double z,
272  Matrix box, double rotation,
273  std::list<text_renderer::string>& lst);
274 
275  // Build an svg text element from a list of parsed strings.
276  std::string strlist_to_svg (double x, double y, double z, Matrix box,
277  double rotation,
278  std::list<text_renderer::string>& lst);
279 
280  // Build a list of postscript commands from a list of parsed strings.
281  std::string strlist_to_ps (double x, double y, double z, Matrix box,
282  double rotation,
283  std::list<text_renderer::string>& lst);
284 
285  int alignment_to_mode (int ha, int va) const;
286 
287  FILE *fp;
288  caseless_str term;
289  double fontsize;
290  std::string fontname;
291  bool buffer_overflow;
292  };
293 
294  static bool
295  has_2D_axes (const graphics_handle& h)
296  {
297  bool retval = true;
298 
299  gh_manager& gh_mgr = __get_gh_manager__ ("gl2ps_renderer::has_2D_axes");
300 
301  graphics_object go = gh_mgr.get_object (h);
302 
303  if (! go.valid_object ())
304  return retval;
305 
306  if (go.isa ("figure") || go.isa ("uipanel"))
307  {
308  Matrix children = go.get ("children").matrix_value ();
309  for (octave_idx_type ii = 0; ii < children.numel (); ii++)
310  {
311  retval = has_2D_axes (graphics_handle (children(ii)));
312  if (! retval)
313  break;
314  }
315  }
316  else if (go.isa ("axes"))
317  {
318  axes::properties& ap
319  = reinterpret_cast<axes::properties&> (go.get_properties ());
320  retval = ap.get_is2D (true);
321  }
322 
323  return retval;
324  }
325 
326  void
327  gl2ps_renderer::draw (const graphics_object& go, const std::string& print_cmd)
328  {
329  static bool in_draw = false;
330  static std::string old_print_cmd;
331  static GLint buffsize;
332 
333  if (! in_draw)
334  {
335  unwind_protect frame;
336 
337  frame.protect_var (in_draw);
338 
339  in_draw = true;
340 
341  GLint gl2ps_term = GL2PS_PS;
342  if (term.find ("eps") != std::string::npos)
343  gl2ps_term = GL2PS_EPS;
344  else if (term.find ("pdf") != std::string::npos)
345  gl2ps_term = GL2PS_PDF;
346  else if (term.find ("ps") != std::string::npos)
347  gl2ps_term = GL2PS_PS;
348  else if (term.find ("svg") != std::string::npos)
349  gl2ps_term = GL2PS_SVG;
350  else if (term.find ("pgf") != std::string::npos)
351  gl2ps_term = GL2PS_PGF;
352  else if (term.find ("tex") != std::string::npos)
353  gl2ps_term = GL2PS_TEX;
354  else
355  warning ("gl2ps_renderer::draw: Unknown terminal %s, using 'ps'",
356  term.c_str ());
357 
358  GLint gl2ps_text = 0;
359  if (term.find ("notxt") != std::string::npos)
360  gl2ps_text = GL2PS_NO_TEXT;
361 
362  // Default sort order optimizes for 3D plots
363  GLint gl2ps_sort = GL2PS_BSP_SORT;
364 
365  // FIXME: gl2ps does not provide a way to change the sorting algorithm
366  // on a viewport basis, we thus disable sorting only if all axes are 2D
367  if (has_2D_axes (go.get ("__myhandle__")))
368  gl2ps_sort = GL2PS_NO_SORT;
369 
370  // Use a temporary file in case an overflow happens
371  FILE *tmpf = octave_tmpfile_wrapper ();
372 
373  if (! tmpf)
374  error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
375 
376  frame.add_fcn (safe_fclose, tmpf);
377 
378  // Reset buffsize, unless this is 2nd pass of a texstandalone print.
379  if (term.find ("tex") == std::string::npos)
380  buffsize = 2*1024*1024;
381  else
382  buffsize /= 2;
383 
384  buffer_overflow = true;
385 
386  while (buffer_overflow)
387  {
388  buffer_overflow = false;
389  buffsize *= 2;
390 
391  std::fseek (tmpf, 0, SEEK_SET);
392  octave_ftruncate_wrapper (fileno (tmpf), 0);
393 
394  // For LaTeX output the print process uses 2 drawnow() commands.
395  // The first one is for the pdf/ps/eps graph to be included. The
396  // print_cmd is saved as old_print_cmd. Then the second drawnow()
397  // outputs the tex-file and the graphic filename to be included is
398  // extracted from old_print_cmd.
399 
400  std::string include_graph;
401 
402  size_t found_redirect = old_print_cmd.find ('>');
403 
404  if (found_redirect != std::string::npos)
405  include_graph = old_print_cmd.substr (found_redirect + 1);
406  else
407  include_graph = old_print_cmd;
408 
409  size_t n_begin = include_graph.find_first_not_of (" \"'");
410 
411  if (n_begin != std::string::npos)
412  {
413  size_t n_end = include_graph.find_last_not_of (" \"'");
414  include_graph = include_graph.substr (n_begin,
415  n_end - n_begin + 1);
416  }
417  else
418  include_graph = "foobar-inc";
419 
420  // FIXME: workaround gl2ps drawing 2 background planes, the first
421  // eventually being black and producing visual artifacts
422  const figure::properties& fprop
423  = dynamic_cast<const figure::properties&> (go.get_properties ());
424  Matrix c = fprop.get_color_rgb ();
425  m_glfcns.glClearColor (c(0), c(1), c(2), 1);
426 
427  // Allow figures to be printed at arbitrary resolution
428  set_device_pixel_ratio (fprop.get___device_pixel_ratio__ ());
429 
430  // GL2PS_SILENT was removed to allow gl2ps to print errors on stderr
431  GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave",
432  nullptr, gl2ps_term, gl2ps_sort,
433  (GL2PS_BEST_ROOT
434  | gl2ps_text
435  | GL2PS_DRAW_BACKGROUND
436  | GL2PS_NO_PS3_SHADING
437  | GL2PS_USE_CURRENT_VIEWPORT),
438  GL_RGBA, 0, nullptr, 0, 0, 0,
439  buffsize, tmpf, include_graph.c_str ());
440  if (ret == GL2PS_ERROR)
441  {
442  old_print_cmd.clear ();
443  error ("gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERROR");
444  }
445 
447 
448  if (buffer_overflow)
449  warning ("gl2ps_renderer::draw: retrying with buffer size: %.1E B\n", double (2*buffsize));
450 
451  if (! buffer_overflow)
452  old_print_cmd = print_cmd;
453 
454  // Don't check return value of gl2psEndPage, it is not meaningful.
455  // Errors and warnings are checked after gl2psEndViewport in
456  // gl2ps_renderer::draw_axes instead.
457  gl2psEndPage ();
458  }
459 
460  // Copy temporary file to pipe
461  std::fseek (tmpf, 0, SEEK_SET);
462  char str[8192]; // 8 kB is a common kernel buffersize
463  size_t nread, nwrite;
464  nread = 1;
465 
466  // In EPS terminal read the header line by line and insert a
467  // new procedure
468  const char* fcn = "/SRX { gsave FCT moveto rotate xshow grestore } BD\n";
469  bool header_found = ! (term.find ("eps") != std::string::npos
470  || term.find ("svg") != std::string::npos);
471 
472  while (! feof (tmpf) && nread)
473  {
474  if (! header_found && std::fgets (str, 8192, tmpf))
475  nread = strlen (str);
476  else
477  nread = std::fread (str, 1, 8192, tmpf);
478 
479  if (nread)
480  {
481  if (! header_found && std::strncmp (str, "/SBCR", 5) == 0)
482  {
483  header_found = true;
484  nwrite = std::fwrite (fcn, 1, strlen (fcn), fp);
485  if (nwrite != strlen (fcn))
486  {
487  // FIXME: is this the best thing to do here?
489  error ("gl2ps_renderer::draw: internal pipe error");
490  }
491  }
492  else if (! header_found
493  && term.find ("svg") != std::string::npos)
494  {
495  // FIXME: gl2ps uses pixel units for SVG format.
496  // Modify resulting svg to use points instead.
497  // Remove this "else if" block, and
498  // make header_found true for SVG if gl2ps is fixed.
499  std::string srchstr (str);
500  size_t pos = srchstr.find ("px");
501  if (pos != std::string::npos)
502  {
503  header_found = true;
504  srchstr[pos+1] = 't'; // "px" -> "pt"
505  // Assume the second occurrence is at the same line
506  pos = srchstr.find ("px", pos);
507  srchstr[pos+1] = 't'; // "px" -> "pt"
508  std::strcpy (str, srchstr.c_str ());
509  }
510  }
511 
512  nwrite = std::fwrite (str, 1, nread, fp);
513  if (nwrite != nread)
514  {
515  // FIXME: is this the best thing to do here?
516  respond_to_pending_signals (); // Clear SIGPIPE signal
517  error ("gl2ps_renderer::draw: internal pipe error");
518  }
519  }
520  }
521  }
522  else
524  }
525 
526  int
527  gl2ps_renderer::alignment_to_mode (int ha, int va) const
528  {
529  int gl2psa = GL2PS_TEXT_BL;
530 
531  if (ha == 0)
532  {
533  if (va == 0 || va == 3)
534  gl2psa=GL2PS_TEXT_BL;
535  else if (va == 2)
536  gl2psa=GL2PS_TEXT_TL;
537  else if (va == 1)
538  gl2psa=GL2PS_TEXT_CL;
539  }
540  else if (ha == 2)
541  {
542  if (va == 0 || va == 3)
543  gl2psa=GL2PS_TEXT_BR;
544  else if (va == 2)
545  gl2psa=GL2PS_TEXT_TR;
546  else if (va == 1)
547  gl2psa=GL2PS_TEXT_CR;
548  }
549  else if (ha == 1)
550  {
551  if (va == 0 || va == 3)
552  gl2psa=GL2PS_TEXT_B;
553  else if (va == 2)
554  gl2psa=GL2PS_TEXT_T;
555  else if (va == 1)
556  gl2psa=GL2PS_TEXT_C;
557  }
558 
559  return gl2psa;
560  }
561 
562  void
563  gl2ps_renderer::fix_strlist_position (double x, double y, double z,
564  Matrix box, double rotation,
565  std::list<text_renderer::string>& lst)
566  {
567  for (auto& txtobj : lst)
568  {
569  // Get pixel coordinates
570  ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
571 
572  // Translate and rotate
573  double rot = rotation * 4.0 * atan (1.0) / 180;
574  coord_pix(0) += (txtobj.get_x () + box(0))*cos (rot)
575  - (txtobj.get_y () + box(1))*sin (rot);
576  coord_pix(1) -= (txtobj.get_y () + box(1))*cos (rot)
577  + (txtobj.get_x () + box(0))*sin (rot);
578 
579  GLint vp[4];
580  m_glfcns.glGetIntegerv (GL_VIEWPORT, vp);
581 
582  txtobj.set_x (coord_pix(0));
583  txtobj.set_y (vp[3] - coord_pix(1));
584  txtobj.set_z (coord_pix(2));
585  }
586  }
587 
588  static std::string
589  code_to_symbol (uint32_t code)
590  {
591  std::string retval;
592 
593  uint32_t idx = code - 945;
594  if (idx < 25)
595  {
596  std::string characters ("abgdezhqiklmnxoprVstufcyw");
597  retval = characters[idx];
598  return retval;
599  }
600 
601  idx = code - 913;
602  if (idx < 25)
603  {
604  std::string characters ("ABGDEZHQIKLMNXOPRVSTUFCYW");
605  retval = characters[idx];
606  }
607  else if (code == 978)
608  retval = "U";
609  else if (code == 215)
610  retval = "\xb4";
611  else if (code == 177)
612  retval = "\xb1";
613  else if (code == 8501)
614  retval = "\xc0";
615  else if (code == 8465)
616  retval = "\xc1";
617  else if (code == 8242)
618  retval = "\xa2";
619  else if (code == 8736)
620  retval = "\xd0";
621  else if (code == 172)
622  retval = "\xd8";
623  else if (code == 9829)
624  retval = "\xa9";
625  else if (code == 8472)
626  retval = "\xc3";
627  else if (code == 8706)
628  retval = "\xb6";
629  else if (code == 8704)
630  retval = "\x22";
631  else if (code == 9827)
632  retval = "\xa7";
633  else if (code == 9824)
634  retval = "\xaa";
635  else if (code == 8476)
636  retval = "\xc2";
637  else if (code == 8734)
638  retval = "\xa5";
639  else if (code == 8730)
640  retval = "\xd6";
641  else if (code == 8707)
642  retval = "\x24";
643  else if (code == 9830)
644  retval = "\xa8";
645  else if (code == 8747)
646  retval = "\xf2";
647  else if (code == 8727)
648  retval = "\x2a";
649  else if (code == 8744)
650  retval = "\xda";
651  else if (code == 8855)
652  retval = "\xc4";
653  else if (code == 8901)
654  retval = "\xd7";
655  else if (code == 8728)
656  retval = "\xb0";
657  else if (code == 8745)
658  retval = "\xc7";
659  else if (code == 8743)
660  retval = "\xd9";
661  else if (code == 8856)
662  retval = "\xc6";
663  else if (code == 8729)
664  retval = "\xb7";
665  else if (code == 8746)
666  retval = "\xc8";
667  else if (code == 8853)
668  retval = "\xc5";
669  else if (code == 8804)
670  retval = "\xa3";
671  else if (code == 8712)
672  retval = "\xce";
673  else if (code == 8839)
674  retval = "\xca";
675  else if (code == 8801)
676  retval = "\xba";
677  else if (code == 8773)
678  retval = "\x40";
679  else if (code == 8834)
680  retval = "\xcc";
681  else if (code == 8805)
682  retval = "\xb3";
683  else if (code == 8715)
684  retval = "\x27";
685  else if (code == 8764)
686  retval = "\x7e";
687  else if (code == 8733)
688  retval = "\xb5";
689  else if (code == 8838)
690  retval = "\xcd";
691  else if (code == 8835)
692  retval = "\xc9";
693  else if (code == 8739)
694  retval = "\xbd";
695  else if (code == 8776)
696  retval = "\xbb";
697  else if (code == 8869)
698  retval = "\x5e";
699  else if (code == 8656)
700  retval = "\xdc";
701  else if (code == 8592)
702  retval = "\xac";
703  else if (code == 8658)
704  retval = "\xde";
705  else if (code == 8594)
706  retval = "\xae";
707  else if (code == 8596)
708  retval = "\xab";
709  else if (code == 8593)
710  retval = "\xad";
711  else if (code == 8595)
712  retval = "\xaf";
713  else if (code == 8970)
714  retval = "\xeb";
715  else if (code == 8971)
716  retval = "\xfb";
717  else if (code == 10216)
718  retval = "\xe1";
719  else if (code == 10217)
720  retval = "\xf1";
721  else if (code == 8968)
722  retval = "\xe9";
723  else if (code == 8969)
724  retval = "\xf9";
725  else if (code == 8800)
726  retval = "\xb9";
727  else if (code == 8230)
728  retval = "\xbc";
729  else if (code == 176)
730  retval = "\xb0";
731  else if (code == 8709)
732  retval = "\xc6";
733  else if (code == 169)
734  retval = "\xd3";
735 
736  if (retval.empty ())
737  warning ("print: unhandled symbol %d", code);
738 
739  return retval;
740  }
741 
742  static std::string
743  select_font (caseless_str fn, bool isbold, bool isitalic)
744  {
745  std::transform (fn.begin (), fn.end (), fn.begin (), ::tolower);
746  std::string fontname;
747  if (fn == "times" || fn == "times-roman")
748  {
749  if (isitalic && isbold)
750  fontname = "Times-BoldItalic";
751  else if (isitalic)
752  fontname = "Times-Italic";
753  else if (isbold)
754  fontname = "Times-Bold";
755  else
756  fontname = "Times-Roman";
757  }
758  else if (fn == "courier")
759  {
760  if (isitalic && isbold)
761  fontname = "Courier-BoldOblique";
762  else if (isitalic)
763  fontname = "Courier-Oblique";
764  else if (isbold)
765  fontname = "Courier-Bold";
766  else
767  fontname = "Courier";
768  }
769  else if (fn == "symbol")
770  fontname = "Symbol";
771  else if (fn == "zapfdingbats")
772  fontname = "ZapfDingbats";
773  else
774  {
775  if (isitalic && isbold)
776  fontname = "Helvetica-BoldOblique";
777  else if (isitalic)
778  fontname = "Helvetica-Oblique";
779  else if (isbold)
780  fontname = "Helvetica-Bold";
781  else
782  fontname = "Helvetica";
783  }
784  return fontname;
785  }
786 
787  static void
788  escape_character (const std::string chr, std::string& str)
789  {
790  std::size_t idx = str.find (chr);
791  while (idx != std::string::npos)
792  {
793  str.insert (idx, 1, '\\');
794  idx = str.find (chr, idx + 2);
795  }
796  }
797 
798  std::string
799  gl2ps_renderer::strlist_to_svg (double x, double y, double z,
800  Matrix box, double rotation,
801  std::list<text_renderer::string>& lst)
802  {
803  if (lst.empty ())
804  return "";
805 
806  //Use pixel coordinates to conform to gl2ps
807  ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
808 
809  std::ostringstream os;
810  os << "<text xml:space=\"preserve\" ";
811 
812  // Rotation and translation are applied to the whole text element
813  os << "transform=\""
814  << "translate(" << coord_pix(0) + box(0) << "," << coord_pix(1) - box(1)
815  << ") rotate(" << -rotation << "," << -box(0) << "," << box(1)
816  << ")\" ";
817 
818  // Use the first entry for the base text font
819  auto p = lst.begin ();
820  std::string name = p->get_family ();
821  std::string weight = p->get_weight ();
822  std::string angle = p->get_angle ();
823  double size = p->get_size ();
824 
825  os << "font-family=\"" << name << "\" "
826  << "font-weight=\"" << weight << "\" "
827  << "font-style=\"" << angle << "\" "
828  << "font-size=\"" << size << "\">";
829 
830 
831  // build a tspan for each element in the strlist
832  for (p = lst.begin (); p != lst.end (); p++)
833  {
834  os << "<tspan ";
835 
836  if (name.compare (p->get_family ()))
837  os << "font-family=\"" << p->get_family () << "\" ";
838 
839  if (weight.compare (p->get_weight ()))
840  os << "font-weight=\"" << p->get_weight () << "\" ";
841 
842  if (angle.compare (p->get_angle ()))
843  os << "font-style=\"" << p->get_angle () << "\" ";
844 
845  if (size != p->get_size ())
846  os << "font-size=\"" << p->get_size () << "\" ";
847 
848  os << "y=\"" << - p->get_y () << "\" ";
849 
850  Matrix col = p->get_color ();
851  os << "fill=\"rgb(" << col(0)*255 << ","
852  << col(1)*255 << "," << col(2)*255 << ")\" ";
853 
854  // provide an x coordinate for each character in the string
855  os << "x=\"";
856  std::vector<double> xdata = p->get_xdata ();
857  for (auto q = xdata.begin (); q != xdata.end (); q++)
858  os << (*q) << " ";
859  os << "\"";
860 
861  os << ">";
862 
863  // translate unicode and special xml characters
864  if (p->get_code ())
865  os << "&#" << p->get_code () << ";";
866  else
867  {
868  const std::string str = p->get_string ();
869  for (auto q = str.begin (); q != str.end (); q++)
870  {
871  std::stringstream chr;
872  chr << *q;
873  if (chr.str () == "\"")
874  os << "&quot;";
875  else if (chr.str () == "'")
876  os << "&apos;";
877  else if (chr.str () == "&")
878  os << "&amp;";
879  else if (chr.str () == "<")
880  os << "&lt;";
881  else if (chr.str () == ">")
882  os << "&gt;";
883  else
884  os << chr.str ();
885  }
886  }
887  os << "</tspan>";
888  }
889  os << "</text>";
890 
891  return os.str ();
892  }
893 
894  std::string
895  gl2ps_renderer::strlist_to_ps (double x, double y, double z,
896  Matrix box, double rotation,
897  std::list<text_renderer::string>& lst)
898  {
899  // Translate and rotate coordinates in order to use bottom-left alignment
900  fix_strlist_position (x, y, z, box, rotation, lst);
901  Matrix prev_color (1, 3, -1);
902 
903  std::ostringstream ss;
904  ss << "gsave\n";
905 
906  static bool warned = false;
907 
908  for (const auto& txtobj : lst)
909  {
910  // Color
911  if (txtobj.get_color () != prev_color)
912  {
913  prev_color = txtobj.get_color ();
914  for (int i = 0; i < 3; i++)
915  ss << prev_color(i) << " ";
916 
917  ss << "C\n";
918  }
919 
920  // String
921  std::string str;
922  if (txtobj.get_code ())
923  {
924  fontname = "Symbol";
925  str = code_to_symbol (txtobj.get_code ());
926  }
927  else
928  {
929  fontname = select_font (txtobj.get_name (),
930  txtobj.get_weight () == "bold",
931  txtobj.get_angle () == "italic");
932 
933  // Check that the string is composed of single byte characters
934  const std::string tmpstr = txtobj.get_string ();
935  const uint8_t *c
936  = reinterpret_cast<const uint8_t *> (tmpstr.c_str ());
937 
938  for (size_t i = 0; i < tmpstr.size ();)
939  {
940  int mblen = octave_u8_strmblen_wrapper (c + i);
941 
942  // Replace multibyte or non ascii characters by a question mark
943  if (mblen > 1)
944  {
945  str += "?";
946  if (! warned)
947  {
948  warning_with_id ("Octave:print:unsupported-multibyte",
949  "print: only ASCII characters are "
950  "supported for EPS and derived "
951  "formats.");
952  warned = true;
953  }
954  }
955  else if (mblen < 1)
956  {
957  mblen = 1;
958  str += "?";
959  if (! warned)
960  {
961  warning_with_id ("Octave:print:unhandled-character",
962  "print: only ASCII characters are "
963  "supported for EPS and derived "
964  "formats.");
965  warned = true;
966  }
967  }
968  else
969  str += tmpstr.at (i);
970 
971  i += mblen;
972  }
973  }
974 
975  escape_character ("\\", str);
976  escape_character ("(", str);
977  escape_character (")", str);
978 
979  ss << "(" << str << ") [";
980 
981  std::vector<double> xdata = txtobj.get_xdata ();
982  for (size_t i = 1; i < xdata.size (); i++)
983  ss << xdata[i] - xdata[i-1] << " ";
984 
985  ss << "10] " << rotation << " " << txtobj.get_x ()
986  << " " << txtobj.get_y () << " " << txtobj.get_size ()
987  << " /" << fontname << " SRX\n";
988  }
989 
990  ss << "grestore\n";
991 
992  return ss.str ();
993  }
994 
995  Matrix
996  gl2ps_renderer::render_text (const std::string& txt,
997  double x, double y, double z,
998  int ha, int va, double rotation)
999  {
1000  std::string saved_font = fontname;
1001 
1002  if (txt.empty ())
1003  return Matrix (1, 4, 0.0);
1004 
1005  Matrix bbox;
1006  std::string str = txt;
1007  std::list<text_renderer::string> lst;
1008 
1009  text_to_strlist (str, lst, bbox, ha, va, rotation);
1010  m_glfcns.glRasterPos3d (x, y, z);
1011 
1012  // For svg/eps directly dump a preformated text element into gl2ps output
1013  if (term.find ("svg") != std::string::npos)
1014  {
1015  std::string elt = strlist_to_svg (x, y, z, bbox, rotation, lst);
1016  if (! elt.empty ())
1017  gl2psSpecial (GL2PS_SVG, elt.c_str ());
1018  }
1019  else if (term.find ("eps") != std::string::npos)
1020  {
1021  std::string elt = strlist_to_ps (x, y, z, bbox, rotation, lst);
1022  if (! elt.empty ())
1023  gl2psSpecial (GL2PS_EPS, elt.c_str ());
1024 
1025  }
1026  else
1027  gl2psTextOpt (str.c_str (), fontname.c_str (), fontsize,
1028  alignment_to_mode (ha, va), rotation);
1029 
1030  fontname = saved_font;
1031 
1032  return bbox;
1033  }
1034 
1035  void
1036  gl2ps_renderer::set_font (const base_properties& props)
1037  {
1038  opengl_renderer::set_font (props);
1039 
1040  // Set the interpreter so that text_to_pixels can parse strings properly
1041  if (props.has_property ("interpreter"))
1042  set_interpreter (props.get ("interpreter").string_value ());
1043 
1044  fontsize = props.get ("__fontsize_points__").double_value ();
1045 
1046  caseless_str fn = props.get ("fontname").xtolower ().string_value ();
1047  bool isbold
1048  =(props.get ("fontweight").xtolower ().string_value () == "bold");
1049  bool isitalic
1050  = (props.get ("fontangle").xtolower ().string_value () == "italic");
1051 
1052  fontname = select_font (fn, isbold, isitalic);
1053  }
1054 
1055  void
1056  gl2ps_renderer::draw_image (const image::properties& props)
1057  {
1058  octave_value cdata = props.get_color_data ();
1059  dim_vector dv (cdata.dims ());
1060  int h = dv(0);
1061  int w = dv(1);
1062 
1063  Matrix x = props.get_xdata ().matrix_value ();
1064  Matrix y = props.get_ydata ().matrix_value ();
1065 
1066  // Someone wants us to draw an empty image? No way.
1067  if (x.isempty () || y.isempty ())
1068  return;
1069 
1070  // Sort x/ydata and mark flipped dimensions
1071  bool xflip = false;
1072  if (x(0) > x(1))
1073  {
1074  std::swap (x(0), x(1));
1075  xflip = true;
1076  }
1077  else if (w > 1 && x(1) == x(0))
1078  x(1) = x(1) + (w-1);
1079 
1080  bool yflip = false;
1081  if (y(0) > y(1))
1082  {
1083  std::swap (y(0), y(1));
1084  yflip = true;
1085  }
1086  else if (h > 1 && y(1) == y(0))
1087  y(1) = y(1) + (h-1);
1088 
1089 
1090  const ColumnVector p0 = xform.transform (x(0), y(0), 0);
1091  const ColumnVector p1 = xform.transform (x(1), y(1), 0);
1092 
1093  if (math::isnan (p0(0)) || math::isnan (p0(1))
1094  || math::isnan (p1(0)) || math::isnan (p1(1)))
1095  {
1096  warning ("opengl_renderer: image X,Y data too large to draw");
1097  return;
1098  }
1099 
1100  // image pixel size in screen pixel units
1101  float pix_dx, pix_dy;
1102  // image pixel size in normalized units
1103  float nor_dx, nor_dy;
1104 
1105  if (w > 1)
1106  {
1107  pix_dx = (p1(0) - p0(0)) / (w-1);
1108  nor_dx = (x(1) - x(0)) / (w-1);
1109  }
1110  else
1111  {
1112  const ColumnVector p1w = xform.transform (x(1) + 1, y(1), 0);
1113  pix_dx = p1w(0) - p0(0);
1114  nor_dx = 1;
1115  }
1116 
1117  if (h > 1)
1118  {
1119  pix_dy = (p1(1) - p0(1)) / (h-1);
1120  nor_dy = (y(1) - y(0)) / (h-1);
1121  }
1122  else
1123  {
1124  const ColumnVector p1h = xform.transform (x(1), y(1) + 1, 0);
1125  pix_dy = p1h(1) - p0(1);
1126  nor_dy = 1;
1127  }
1128 
1129  // OpenGL won't draw any of the image if its origin is outside the
1130  // viewport/clipping plane so we must do the clipping ourselves.
1131 
1132  int j0, j1, jj, i0, i1, ii;
1133  j0 = 0, j1 = w;
1134  i0 = 0, i1 = h;
1135 
1136  float im_xmin = x(0) - nor_dx/2;
1137  float im_xmax = x(1) + nor_dx/2;
1138  float im_ymin = y(0) - nor_dy/2;
1139  float im_ymax = y(1) + nor_dy/2;
1140 
1141  // Clip to axes or viewport
1142  bool do_clip = props.is_clipping ();
1143  Matrix vp = get_viewport_scaled ();
1144 
1145  ColumnVector vp_lim_min
1146  = xform.untransform (std::numeric_limits <float>::epsilon (),
1147  std::numeric_limits <float>::epsilon ());
1148  ColumnVector vp_lim_max = xform.untransform (vp(2), vp(3));
1149 
1150  if (vp_lim_min(0) > vp_lim_max(0))
1151  std::swap (vp_lim_min(0), vp_lim_max(0));
1152 
1153  if (vp_lim_min(1) > vp_lim_max(1))
1154  std::swap (vp_lim_min(1), vp_lim_max(1));
1155 
1156  float clip_xmin
1157  = do_clip ? (vp_lim_min(0) > xmin ? vp_lim_min(0) : xmin) : vp_lim_min(0);
1158 
1159  float clip_ymin
1160  = do_clip ? (vp_lim_min(1) > ymin ? vp_lim_min(1) : ymin) : vp_lim_min(1);
1161 
1162  float clip_xmax
1163  = do_clip ? (vp_lim_max(0) < xmax ? vp_lim_max(0) : xmax) : vp_lim_max(0);
1164 
1165  float clip_ymax
1166  = do_clip ? (vp_lim_max(1) < ymax ? vp_lim_max(1) : ymax) : vp_lim_max(1);
1167 
1168  if (im_xmin < clip_xmin)
1169  j0 += (clip_xmin - im_xmin)/nor_dx + 1;
1170 
1171  if (im_xmax > clip_xmax)
1172  j1 -= (im_xmax - clip_xmax)/nor_dx;
1173 
1174  if (im_ymin < clip_ymin)
1175  i0 += (clip_ymin - im_ymin)/nor_dy + 1;
1176 
1177  if (im_ymax > clip_ymax)
1178  i1 -= (im_ymax - clip_ymax)/nor_dy;
1179 
1180  if (i0 >= i1 || j0 >= j1)
1181  return;
1182 
1183  float zoom_x;
1184  m_glfcns.glGetFloatv (GL_ZOOM_X, &zoom_x);
1185  float zoom_y;
1186  m_glfcns.glGetFloatv (GL_ZOOM_Y, &zoom_y);
1187 
1188  m_glfcns.glPixelZoom (m_devpixratio * pix_dx, - m_devpixratio * pix_dy);
1189  m_glfcns.glRasterPos3d (im_xmin + nor_dx*j0, im_ymin + nor_dy*i0, 0);
1190 
1191  // Expect RGB data
1192  if (dv.ndims () == 3 && dv(2) == 3)
1193  {
1194  if (cdata.is_double_type ())
1195  {
1196  const NDArray xcdata = cdata.array_value ();
1197 
1198  OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
1199 
1200  for (int i = i0; i < i1; i++)
1201  {
1202  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
1203  {
1204  if (! yflip)
1205  ii = i;
1206  else
1207  ii = h - i - 1;
1208 
1209  if (! xflip)
1210  jj = j;
1211  else
1212  jj = w - j - 1;
1213 
1214  a[idx] = xcdata(ii,jj,0);
1215  a[idx+1] = xcdata(ii,jj,1);
1216  a[idx+2] = xcdata(ii,jj,2);
1217  }
1218  }
1219 
1220  draw_pixels (j1-j0, i1-i0, a);
1221 
1222  }
1223  else if (cdata.is_single_type ())
1224  {
1225  const FloatNDArray xcdata = cdata.float_array_value ();
1226 
1227  OCTAVE_LOCAL_BUFFER (GLfloat, a, 3*(j1-j0)*(i1-i0));
1228 
1229  for (int i = i0; i < i1; i++)
1230  {
1231  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
1232  {
1233  if (! yflip)
1234  ii = i;
1235  else
1236  ii = h - i - 1;
1237 
1238  if (! xflip)
1239  jj = j;
1240  else
1241  jj = w - j - 1;
1242 
1243  a[idx] = xcdata(ii,jj,0);
1244  a[idx+1] = xcdata(ii,jj,1);
1245  a[idx+2] = xcdata(ii,jj,2);
1246  }
1247  }
1248 
1249  draw_pixels (j1-j0, i1-i0, a);
1250 
1251  }
1252  else if (cdata.is_uint8_type ())
1253  {
1254  const uint8NDArray xcdata = cdata.uint8_array_value ();
1255 
1256  OCTAVE_LOCAL_BUFFER (GLubyte, a, 3*(j1-j0)*(i1-i0));
1257 
1258  for (int i = i0; i < i1; i++)
1259  {
1260  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
1261  {
1262  if (! yflip)
1263  ii = i;
1264  else
1265  ii = h - i - 1;
1266 
1267  if (! xflip)
1268  jj = j;
1269  else
1270  jj = w - j - 1;
1271 
1272  a[idx] = xcdata(ii,jj,0);
1273  a[idx+1] = xcdata(ii,jj,1);
1274  a[idx+2] = xcdata(ii,jj,2);
1275  }
1276  }
1277 
1278  draw_pixels (j1-j0, i1-i0, a);
1279 
1280  }
1281  else if (cdata.is_uint16_type ())
1282  {
1283  const uint16NDArray xcdata = cdata.uint16_array_value ();
1284 
1285  OCTAVE_LOCAL_BUFFER (GLushort, a, 3*(j1-j0)*(i1-i0));
1286 
1287  for (int i = i0; i < i1; i++)
1288  {
1289  for (int j = j0, idx = (i-i0)*(j1-j0)*3; j < j1; j++, idx += 3)
1290  {
1291  if (! yflip)
1292  ii = i;
1293  else
1294  ii = h - i - 1;
1295 
1296  if (! xflip)
1297  jj = j;
1298  else
1299  jj = w - j - 1;
1300 
1301  a[idx] = xcdata(ii,jj,0);
1302  a[idx+1] = xcdata(ii,jj,1);
1303  a[idx+2] = xcdata(ii,jj,2);
1304  }
1305  }
1306 
1307  draw_pixels (j1-j0, i1-i0, a);
1308 
1309  }
1310  else
1311  warning ("opengl_renderer: invalid image data type (expected double, single, uint8, or uint16)");
1312 
1313  m_glfcns.glPixelZoom (zoom_x, zoom_y);
1314 
1315  }
1316  }
1317 
1318  void
1319  gl2ps_renderer::draw_pixels (int w, int h, const float *data)
1320  {
1321  // Clip data between 0 and 1 for float values
1322  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
1323 
1324  for (int i = 0; i < 3*h*w; i++)
1325  tmp_data[i] = (data[i] < 0.0f ? 0.0f : (data[i] > 1.0f ? 1.0f : data[i]));
1326 
1327  gl2psDrawPixels (w, h, 0, 0, GL_RGB, GL_FLOAT, tmp_data);
1328  }
1329 
1330  void
1331  gl2ps_renderer::draw_pixels (int w, int h, const uint8_t *data)
1332  {
1333  // gl2psDrawPixels only supports the GL_FLOAT type.
1334 
1335  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
1336 
1337  static const float maxval = std::numeric_limits<uint8_t>::max ();
1338 
1339  for (int i = 0; i < 3*w*h; i++)
1340  tmp_data[i] = data[i] / maxval;
1341 
1342  draw_pixels (w, h, tmp_data);
1343  }
1344 
1345  void
1346  gl2ps_renderer::draw_pixels (int w, int h, const uint16_t *data)
1347  {
1348  // gl2psDrawPixels only supports the GL_FLOAT type.
1349 
1350  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
1351 
1352  static const float maxval = std::numeric_limits<uint16_t>::max ();
1353 
1354  for (int i = 0; i < 3*w*h; i++)
1355  tmp_data[i] = data[i] / maxval;
1356 
1357  draw_pixels (w, h, tmp_data);
1358  }
1359 
1360  void
1361  gl2ps_renderer::draw_text (const text::properties& props)
1362  {
1363  if (props.get_string ().isempty ())
1364  return;
1365 
1366  draw_text_background (props, true);
1367 
1368  // First set font properties: freetype will use them to compute
1369  // coordinates and gl2ps will retrieve the color directly from the
1370  // feedback buffer
1371  set_font (props);
1372  set_color (props.get_color_rgb ());
1373 
1374  std::string saved_font = fontname;
1375 
1376  // Alignment
1377  int halign = 0;
1378  int valign = 0;
1379 
1380  if (props.horizontalalignment_is ("center"))
1381  halign = 1;
1382  else if (props.horizontalalignment_is ("right"))
1383  halign = 2;
1384 
1385  if (props.verticalalignment_is ("top"))
1386  valign = 2;
1387  else if (props.verticalalignment_is ("baseline"))
1388  valign = 3;
1389  else if (props.verticalalignment_is ("middle"))
1390  valign = 1;
1391 
1392  // FIXME: handle margin and surrounding box
1393  // Matrix bbox;
1394 
1395  const Matrix pos = get_transform ().scale (props.get_data_position ());
1396  std::string str = props.get_string ().string_vector_value ().join ("\n");
1397 
1398  render_text (str, pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0,
1399  halign, valign, props.get_rotation ());
1400  }
1401 }
1402 
1403 #endif
1404 
1405 namespace octave
1406 {
1407  // If the name of the stream begins with '|', open a pipe to the command
1408  // named by the rest of the string. Otherwise, write to the named file.
1409 
1410  void
1412  const std::string& stream, const std::string& term)
1413  {
1414 #if defined (HAVE_GL2PS_H) && defined (HAVE_OPENGL)
1415 
1416  // FIXME: should we have a way to create a file that begins with the
1417  // character '|'?
1418 
1419  bool have_cmd = stream.length () > 1 && stream[0] == '|';
1420 
1421  FILE *fp = nullptr;
1422 
1423  unwind_protect frame;
1424 
1425  if (have_cmd)
1426  {
1427  // Create process and pipe gl2ps output to it.
1428 
1429  std::string cmd = stream.substr (1);
1430 
1431  fp = popen (cmd.c_str (), "w");
1432 
1433  if (! fp)
1434  error (R"(print: failed to open pipe "%s")", stream.c_str ());
1435 
1436  frame.add_fcn (safe_pclose, fp);
1437  }
1438  else
1439  {
1440  // Write gl2ps output directly to file.
1441 
1442  fp = sys::fopen (stream.c_str (), "w");
1443 
1444  if (! fp)
1445  error (R"(gl2ps_print: failed to create file "%s")", stream.c_str ());
1446 
1447  frame.add_fcn (safe_fclose, fp);
1448  }
1449 
1450  gl2ps_renderer rend (glfcns, fp, term);
1451 
1452  Matrix pos = fig.get ("position").matrix_value ();
1453  rend.set_viewport (pos(2), pos(3));
1454  rend.draw (fig, stream);
1455 
1456  // Make sure buffered commands are finished!!!
1457  rend.finish ();
1458 
1459 #else
1460 
1461  octave_unused_parameter (glfcns);
1462  octave_unused_parameter (fig);
1463  octave_unused_parameter (stream);
1464  octave_unused_parameter (term);
1465 
1466  err_disabled_feature ("gl2ps_print", "gl2ps");
1467 
1468 #endif
1469  }
1470 }
#define SEEK_SET
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:230
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:377
bool isempty(void) const
Size of the specified dimension.
Definition: Array.h:572
Definition: dMatrix.h:42
bool get_is2D(bool include_kids=false) const
Definition: graphics.in.h:3522
virtual bool has_property(const caseless_str &) const
Definition: graphics.in.h:2241
virtual octave_value get(const caseless_str &pname) const
Vector representing the dimensions (size) of an Array.
Definition: dim-vector.h:95
graphics_object get_object(double val) const
Definition: graphics.in.h:6260
octave_value get(bool all=false) const
Definition: graphics.in.h:2746
bool isa(const std::string &go_name) const
Definition: graphics.in.h:2827
base_properties & get_properties(void)
Definition: graphics.in.h:2829
bool valid_object(void) const
Definition: graphics.in.h:2847
octave_value get_color_data(void) const
Definition: graphics.cc:9567
void add_fcn(void(*fcn)(Params...), Args &&... args)
virtual void set_linejoin(const std::string &)
Definition: gl-render.h:110
virtual void draw_axes(const axes::properties &props)
Definition: gl-render.cc:2292
virtual void draw(const graphics_object &go, bool toplevel=true)
Definition: gl-render.cc:717
virtual void set_polygon_offset(bool on, float offset=0.0f)
Definition: gl-render.cc:4056
virtual void init_marker(const std::string &m, double size, float width)
Definition: gl-render.cc:4245
virtual void set_linestyle(const std::string &s, bool stipple=false, double linewidth=0.5)
Definition: gl-render.cc:4105
virtual void set_font(const base_properties &props)
Definition: gl-render.cc:4044
uint16NDArray uint16_array_value(void) const
Definition: ov.h:918
bool is_uint16_type(void) const
Definition: ov.h:674
bool is_scalar_type(void) const
Definition: ov.h:697
bool is_double_type(void) const
Definition: ov.h:648
uint8NDArray uint8_array_value(void) const
Definition: ov.h:915
std::string string_value(bool force=false) const
Definition: ov.h:927
NDArray array_value(bool frc_str_conv=false) const
Definition: ov.h:812
octave_value xtolower(void) const
Definition: ov.h:1431
bool is_single_type(void) const
Definition: ov.h:651
FloatNDArray float_array_value(bool frc_str_conv=false) const
Definition: ov.h:815
bool is_uint8_type(void) const
Definition: ov.h:671
Matrix matrix_value(bool frc_str_conv=false) const
Definition: ov.h:806
double double_value(bool frc_str_conv=false) const
Definition: ov.h:794
dim_vector dims(void) const
Definition: ov.h:500
void warning(const char *fmt,...)
Definition: error.cc:1050
void warning_with_id(const char *id, const char *fmt,...)
Definition: error.cc:1065
void error(const char *fmt,...)
Definition: error.cc:968
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:53
void xform(ColumnVector &v, const Matrix &m)
Definition: graphics.cc:5858
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5814
QString name
F77_RET_T const F77_DBLE * x
T octave_idx_type m
Definition: mx-inlines.cc:773
std::complex< double > w(std::complex< double > z, double relerr=0)
Complex atan(const Complex &x)
Definition: lo-mappers.h:71
bool isnan(bool)
Definition: lo-mappers.h:178
bool strncmp(const T &str_a, const T &str_b, const typename T::size_type n)
True if the first N characters are the same.
Definition: oct-string.cc:156
std::FILE * fopen(const std::string &filename, const std::string &mode)
Definition: lo-sysdep.cc:295
gh_manager & __get_gh_manager__(const std::string &who)
static uint32_t state[624]
Definition: randmtzig.cc:190
void respond_to_pending_signals(void)
Definition: sighandlers.cc:106
void gl2ps_print(opengl_functions &glfcns, const graphics_object &fig, const std::string &stream, const std::string &term)
static double f(double k, double l_nu, double c_pm)
Definition: randpoisson.cc:118
FILE * popen(const char *command, const char *mode)
Definition: sysdep.cc:619
int pclose(FILE *f)
Definition: sysdep.cc:643
octave_int< T > xmin(const octave_int< T > &x, const octave_int< T > &y)
octave_int< T > xmax(const octave_int< T > &x, const octave_int< T > &y)
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:44
T::size_type strlen(const typename T::value_type *str)
Definition: oct-string.cc:85
void draw(QDomElement &parent_elt, pdfpainter &painter)
static octave_value box(JNIEnv *jni_env, void *jobj, void *jcls_arg=nullptr)
octave_value::octave_value(const Array< char > &chm, char type) return retval
Definition: ov.cc:811
FILE * octave_tmpfile_wrapper(void)
int octave_ftruncate_wrapper(int fd, off_t sz)
int octave_u8_strmblen_wrapper(const uint8_t *src)