GNU Octave  4.2.1
A high-level interpreted language, primarily intended for numerical computations, mostly compatible with Matlab
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Pages
gl2ps-print.cc
Go to the documentation of this file.
1 /*
2 
3 Copyright (C) 2009-2017 Shai Ayal
4 
5 This file is part of Octave.
6 
7 Octave is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 Octave is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with Octave; see the file COPYING. If not, see
19 <http://www.gnu.org/licenses/>.
20 
21 */
22 
23 #if defined (HAVE_CONFIG_H)
24 # include "config.h"
25 #endif
26 
27 // Both header files are required outside of HAVE_GLP2S_H
28 #include "errwarn.h"
29 #include "gl2ps-print.h"
30 
31 #if defined (HAVE_GL2PS_H)
32 
33 #include <cstdio>
34 
35 #include <limits>
36 
37 #include <gl2ps.h>
38 
39 #include "lo-mappers.h"
40 #include "oct-locbuf.h"
41 #include "tmpfile-wrapper.h"
42 #include "unistd-wrappers.h"
43 #include "unwind-prot.h"
44 
45 #include "gl-render.h"
46 #include "oct-opengl.h"
47 #include "sighandlers.h"
48 #include "sysdep.h"
49 #include "text-renderer.h"
50 
51 namespace octave
52 {
53  class
55  gl2ps_renderer : public opengl_renderer
56  {
57  public:
58 
59  gl2ps_renderer (FILE *_fp, const std::string& _term)
60  : octave::opengl_renderer () , fp (_fp), term (_term), fontsize (),
61  fontname (), buffer_overflow (false)
62  { }
63 
64  ~gl2ps_renderer (void) { }
65 
66  // FIXME: should we import the functions from the base class and
67  // overload them here, or should we use a different name so we don't
68  // have to do this? Without the using declaration or a name change,
69  // the base class functions will be hidden. That may be OK, but it
70  // can also cause some confusion.
72 
73  void draw (const graphics_object& go, const std::string& print_cmd);
74 
75  protected:
76 
77  Matrix render_text (const std::string& txt,
78  double x, double y, double z,
79  int halign, int valign, double rotation = 0.0);
80 
81  void set_font (const base_properties& props);
82 
83  void draw_axes (const axes::properties& props)
84  {
85  // Initialize a sorting tree (viewport) in gl2ps for each axes
86  GLint vp[4];
87  glGetIntegerv (GL_VIEWPORT, vp);
88  gl2psBeginViewport (vp);
89 
90  // Draw and finish () or there may primitives missing in the gl2ps output.
92  finish ();
93 
94  // Finalize viewport
95  GLint state = gl2psEndViewport ();
96  if (state == GL2PS_NO_FEEDBACK)
97  warning ("gl2ps_renderer::draw_axes: empty feedback buffer and/or nothing else to print");
98  else if (state == GL2PS_ERROR)
99  error ("gl2ps_renderer::draw_axes: gl2psEndPage returned GL2PS_ERROR");
100 
101  buffer_overflow |= (state == GL2PS_OVERFLOW);
102 
103  // Don't draw background for subsequent viewports (legends, subplots, etc.)
104  GLint opts;
105  gl2psGetOptions (&opts);
106  opts &= ~GL2PS_DRAW_BACKGROUND;
107  gl2psSetOptions (opts);
108  }
109 
110  void draw_text (const text::properties& props);
111 
112  void draw_pixels (int w, int h, const float *data);
113  void draw_pixels (int w, int h, const uint8_t *data);
114  void draw_pixels (int w, int h, const uint16_t *data);
115 
116  void set_linestyle (const std::string& s, bool use_stipple = false,
117  double linewidth = 0.5)
118  {
119  octave::opengl_renderer::set_linestyle (s, use_stipple, linewidth);
120 
121  if (s == "-" && ! use_stipple)
122  gl2psDisable (GL2PS_LINE_STIPPLE);
123  else
124  gl2psEnable (GL2PS_LINE_STIPPLE);
125  }
126 
127  void set_polygon_offset (bool on, float offset = 0.0f)
128  {
129  if (on)
130  {
132  gl2psEnable (GL2PS_POLYGON_OFFSET_FILL);
133  }
134  else
135  {
136  gl2psDisable (GL2PS_POLYGON_OFFSET_FILL);
138  }
139  }
140 
141  void set_linewidth (float w)
142  {
143  gl2psLineWidth (w);
144  }
145 
146  private:
147 
148  // Use xform to compute the coordinates of the string list
149  // that have been parsed by freetype
150  void fix_strlist_position (double x, double y, double z,
151  Matrix box, double rotation,
152  std::list<octave::text_renderer::string>& lst);
153 
154  int alignment_to_mode (int ha, int va) const;
155  FILE *fp;
156  caseless_str term;
157  double fontsize;
158  std::string fontname;
159  bool buffer_overflow;
160  };
161 
162  void
163  gl2ps_renderer::draw (const graphics_object& go, const std::string& print_cmd)
164  {
165  static bool in_draw = false;
166  static std::string old_print_cmd;
167 
168  if (! in_draw)
169  {
171 
172  frame.protect_var (in_draw);
173 
174  in_draw = true;
175 
176  GLint gl2ps_term = GL2PS_PS;
177  if (term.find ("eps") != std::string::npos)
178  gl2ps_term = GL2PS_EPS;
179  else if (term.find ("pdf") != std::string::npos)
180  gl2ps_term = GL2PS_PDF;
181  else if (term.find ("ps") != std::string::npos)
182  gl2ps_term = GL2PS_PS;
183  else if (term.find ("svg") != std::string::npos)
184  gl2ps_term = GL2PS_SVG;
185  else if (term.find ("pgf") != std::string::npos)
186  gl2ps_term = GL2PS_PGF;
187  else if (term.find ("tex") != std::string::npos)
188  gl2ps_term = GL2PS_TEX;
189  else
190  warning ("gl2ps_renderer::draw: Unknown terminal %s, using 'ps'",
191  term.c_str ());
192 
193  GLint gl2ps_text = 0;
194  if (term.find ("notxt") != std::string::npos)
195  gl2ps_text = GL2PS_NO_TEXT;
196 
197  // Default sort order optimizes for 3D plots
198  GLint gl2ps_sort = GL2PS_BSP_SORT;
199 
200  // For 2D plots we can use a simpler Z-depth sorting algorithm
201  if (term.find ("is2D") != std::string::npos)
202  gl2ps_sort = GL2PS_SIMPLE_SORT;
203 
204  // Use a temporary file in case an overflow happens
205  FILE* tmpf = octave_tmpfile_wrapper ();
206 
207  if (! tmpf)
208  error ("gl2ps_renderer::draw: couldn't open temporary file for printing");
209 
210  GLint buffsize = 2*1024*1024;
211  buffer_overflow = true;
212 
213  while (buffer_overflow)
214  {
215  buffer_overflow = false;
216  buffsize *= 2;
217  std::fseek (tmpf, 0, SEEK_SET);
218  octave_ftruncate_wrapper (fileno (tmpf), 0);
219 
220  // For LaTeX output the fltk print process uses 2 drawnow() commands.
221  // The first one is for the pdf/ps/eps graph to be included. The
222  // print_cmd is saved as old_print_cmd. Then the second drawnow()
223  // outputs the tex-file and the graphic filename to be included is
224  // extracted from old_print_cmd.
225 
226  std::string include_graph;
227 
228  size_t found_redirect = old_print_cmd.find (">");
229 
230  if (found_redirect != std::string::npos)
231  include_graph = old_print_cmd.substr (found_redirect + 1);
232  else
233  include_graph = old_print_cmd;
234 
235  size_t n_begin = include_graph.find_first_not_of (" ");
236 
237  if (n_begin != std::string::npos)
238  {
239  size_t n_end = include_graph.find_last_not_of (" ");
240  include_graph = include_graph.substr (n_begin,
241  n_end - n_begin + 1);
242  }
243  else
244  include_graph = "foobar-inc";
245 
246  // GL2PS_SILENT was removed to allow gl2ps to print errors on stderr
247  GLint ret = gl2psBeginPage ("gl2ps_renderer figure", "Octave", 0,
248  gl2ps_term, gl2ps_sort,
249  (GL2PS_NO_BLENDING
250  | GL2PS_OCCLUSION_CULL
251  | GL2PS_BEST_ROOT
252  | gl2ps_text
253  | GL2PS_DRAW_BACKGROUND
254  | GL2PS_NO_PS3_SHADING
255  | GL2PS_USE_CURRENT_VIEWPORT),
256  GL_RGBA, 0, 0, 0, 0, 0,
257  buffsize, tmpf, include_graph.c_str ());
258  if (ret == GL2PS_ERROR)
259  {
260  old_print_cmd.clear ();
261  error ("gl2ps_renderer::draw: gl2psBeginPage returned GL2PS_ERROR");
262  }
263 
265 
266  if (! buffer_overflow)
267  old_print_cmd = print_cmd;
268 
269  // Don't check return value of gl2psEndPage, it is not meaningful.
270  // Errors and warnings are checked after gl2psEndViewport in
271  // gl2ps_renderer::draw_axes instead.
272  gl2psEndPage ();
273  }
274 
275  // Copy temporary file to pipe
276  std::fseek (tmpf, 0, SEEK_SET);
277  char str[256];
278  size_t nread, nwrite;
279  nread = 1;
280  while (! feof (tmpf) && nread)
281  {
282  nread = std::fread (str, 1, 256, tmpf);
283  if (nread)
284  {
285  nwrite = std::fwrite (str, 1, nread, fp);
286  if (nwrite != nread)
287  {
288  octave::signal_handler (); // Clear SIGPIPE signal
289  error ("gl2ps_renderer::draw: internal pipe error");
290  }
291  }
292  }
293  }
294  else
296  }
297 
298  int
299  gl2ps_renderer::alignment_to_mode (int ha, int va) const
300  {
301  int gl2psa = GL2PS_TEXT_BL;
302 
303  if (ha == 0)
304  {
305  if (va == 0 || va == 3)
306  gl2psa=GL2PS_TEXT_BL;
307  else if (va == 2)
308  gl2psa=GL2PS_TEXT_TL;
309  else if (va == 1)
310  gl2psa=GL2PS_TEXT_CL;
311  }
312  else if (ha == 2)
313  {
314  if (va == 0 || va == 3)
315  gl2psa=GL2PS_TEXT_BR;
316  else if (va == 2)
317  gl2psa=GL2PS_TEXT_TR;
318  else if (va == 1)
319  gl2psa=GL2PS_TEXT_CR;
320  }
321  else if (ha == 1)
322  {
323  if (va == 0 || va == 3)
324  gl2psa=GL2PS_TEXT_B;
325  else if (va == 2)
326  gl2psa=GL2PS_TEXT_T;
327  else if (va == 1)
328  gl2psa=GL2PS_TEXT_C;
329  }
330 
331  return gl2psa;
332  }
333 
334  void
335  gl2ps_renderer::fix_strlist_position (double x, double y, double z,
336  Matrix box, double rotation,
337  std::list<octave::text_renderer::string>& lst)
338  {
339  for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
340  p != lst.end (); p++)
341  {
342  // Get pixel coordinates
343  ColumnVector coord_pix = get_transform ().transform (x, y, z, false);
344 
345  // Translate and rotate
346  double rot = rotation * 4.0 * atan (1.0) / 180;
347  coord_pix(0) += ((*p).get_x () + box(0))*cos (rot)
348  - ((*p).get_y () + box(1))*sin (rot);
349  coord_pix(1) -= ((*p).get_y () + box(1))*cos (rot)
350  + ((*p).get_x () + box(0))*sin (rot);;
351 
352  // Turn coordinates back into current gl coordinates
353  ColumnVector coord =
354  get_transform ().untransform (coord_pix(0), coord_pix(1),
355  coord_pix(2), false);
356  (*p).set_x (coord(0));
357  (*p).set_y (coord(1));
358  (*p).set_z (coord(2));
359  }
360  }
361 }
362 
363 static std::string
364 code_to_symbol (uint32_t code)
365 {
367 
368  uint32_t idx = code - 945;
369  if (idx < 25)
370  {
371  std::string characters("abgdezhqiklmnxoprVstufcyw");
372  retval = characters[idx];
373  return retval;
374  }
375 
376  idx = code - 913;
377  if (idx < 25)
378  {
379  std::string characters("ABGDEZHQIKLMNXOPRVSTUFCYW");
380  retval = characters[idx];
381  }
382  else if (code == 978)
383  retval = std::string ("U");
384  else if (code == 215)
385  retval = std::string ("\xb4");
386  else if (code == 177)
387  retval = std::string ("\xb1");
388  else if (code == 8501)
389  retval = std::string ("\xc0");
390  else if (code == 8465)
391  retval = std::string ("\xc1");
392  else if (code == 8242)
393  retval = std::string ("\xa2");
394  else if (code == 8736)
395  retval = std::string ("\xd0");
396  else if (code == 172)
397  retval = std::string ("\xd8");
398  else if (code == 9829)
399  retval = std::string ("\xa9");
400  else if (code == 8472)
401  retval = std::string ("\xc3");
402  else if (code == 8706)
403  retval = std::string ("\xb6");
404  else if (code == 8704)
405  retval = std::string ("\x22");
406  else if (code == 9827)
407  retval = std::string ("\xa7");
408  else if (code == 9824)
409  retval = std::string ("\xaa");
410  else if (code == 8476)
411  retval = std::string ("\xc2");
412  else if (code == 8734)
413  retval = std::string ("\xa5");
414  else if (code == 8730)
415  retval = std::string ("\xd6");
416  else if (code == 8707)
417  retval = std::string ("\x24");
418  else if (code == 9830)
419  retval = std::string ("\xa8");
420  else if (code == 8747)
421  retval = std::string ("\xf2");
422  else if (code == 8727)
423  retval = std::string ("\x2a");
424  else if (code == 8744)
425  retval = std::string ("\xda");
426  else if (code == 8855)
427  retval = std::string ("\xc4");
428  else if (code == 8901)
429  retval = std::string ("\xd7");
430  else if (code == 8728)
431  retval = std::string ("\xb0");
432  else if (code == 8745)
433  retval = std::string ("\xc7");
434  else if (code == 8743)
435  retval = std::string ("\xd9");
436  else if (code == 8856)
437  retval = std::string ("\xc6");
438  else if (code == 8729)
439  retval = std::string ("\xb7");
440  else if (code == 8746)
441  retval = std::string ("\xc8");
442  else if (code == 8853)
443  retval = std::string ("\xc5");
444  else if (code == 8804)
445  retval = std::string ("\xa3");
446  else if (code == 8712)
447  retval = std::string ("\xce");
448  else if (code == 8839)
449  retval = std::string ("\xca");
450  else if (code == 8801)
451  retval = std::string ("\xba");
452  else if (code == 8773)
453  retval = std::string ("\x40");
454  else if (code == 8834)
455  retval = std::string ("\xcc");
456  else if (code == 8805)
457  retval = std::string ("\xb3");
458  else if (code == 8715)
459  retval = std::string ("\x27");
460  else if (code == 8764)
461  retval = std::string ("\x7e");
462  else if (code == 8733)
463  retval = std::string ("\xb5");
464  else if (code == 8838)
465  retval = std::string ("\xcd");
466  else if (code == 8835)
467  retval = std::string ("\xc9");
468  else if (code == 8739)
469  retval = std::string ("\xbd");
470  else if (code == 8776)
471  retval = std::string ("\xbb");
472  else if (code == 8869)
473  retval = std::string ("\x5e");
474  else if (code == 8656)
475  retval = std::string ("\xdc");
476  else if (code == 8592)
477  retval = std::string ("\xac");
478  else if (code == 8658)
479  retval = std::string ("\xde");
480  else if (code == 8594)
481  retval = std::string ("\xae");
482  else if (code == 8596)
483  retval = std::string ("\xab");
484  else if (code == 8593)
485  retval = std::string ("\xad");
486  else if (code == 8595)
487  retval = std::string ("\xaf");
488  else if (code == 8970)
489  retval = std::string ("\xeb");
490  else if (code == 8971)
491  retval = std::string ("\xfb");
492  else if (code == 10216)
493  retval = std::string ("\xe1");
494  else if (code == 10217)
495  retval = std::string ("\xf1");
496  else if (code == 8968)
497  retval = std::string ("\xe9");
498  else if (code == 8969)
499  retval = std::string ("\xf9");
500  else if (code == 8800)
501  retval = std::string ("\xb9");
502  else if (code == 8230)
503  retval = std::string ("\xbc");
504  else if (code == 176)
505  retval = std::string ("\xb0");
506  else if (code == 8709)
507  retval = std::string ("\xc6");
508  else if (code == 169)
509  retval = std::string ("\xd3");
510 
511  if (retval.empty ())
512  warning ("print: unhandled symbol %d", code);
513 
514  return retval;
515 }
516 
517 static std::string
518 select_font (caseless_str fn, bool isbold, bool isitalic)
519 {
520  std::transform (fn.begin (), fn.end (), fn.begin (), ::tolower);
521  std::string fontname;
522  if (fn == "times" || fn == "times-roman")
523  {
524  if (isitalic && isbold)
525  fontname = "Times-BoldItalic";
526  else if (isitalic)
527  fontname = "Times-Italic";
528  else if (isbold)
529  fontname = "Times-Bold";
530  else
531  fontname = "Times-Roman";
532  }
533  else if (fn == "courier")
534  {
535  if (isitalic && isbold)
536  fontname = "Courier-BoldOblique";
537  else if (isitalic)
538  fontname = "Courier-Oblique";
539  else if (isbold)
540  fontname = "Courier-Bold";
541  else
542  fontname = "Courier";
543  }
544  else if (fn == "symbol")
545  fontname = "Symbol";
546  else if (fn == "zapfdingbats")
547  fontname = "ZapfDingbats";
548  else
549  {
550  if (isitalic && isbold)
551  fontname = "Helvetica-BoldOblique";
552  else if (isitalic)
553  fontname = "Helvetica-Oblique";
554  else if (isbold)
555  fontname = "Helvetica-Bold";
556  else
557  fontname = "Helvetica";
558  }
559  return fontname;
560 }
561 
562 static void
563 escape_character (const std::string chr, std::string& str)
564 {
565  std::size_t idx = str.find (chr);
566  while (idx != std::string::npos)
567  {
568  str.insert (idx, "\\");
569  idx = str.find (chr, idx + 2);
570  }
571 }
572 
573 namespace octave
574 {
575  Matrix
576  gl2ps_renderer::render_text (const std::string& txt,
577  double x, double y, double z,
578  int ha, int va, double rotation)
579  {
580  std::string saved_font = fontname;
581 
582  if (txt.empty ())
583  return Matrix (1, 4, 0.0);
584 
585  // We have no way to get a bounding box from gl2ps, so we parse the raw
586  // string using freetype
587  Matrix bbox;
588  std::string str = txt;
589  std::list<octave::text_renderer::string> lst;
590 
591  text_to_strlist (str, lst, bbox, ha, va, rotation);
592 
593  // When using "tex" or when the string has only one line and no
594  // special characters, use gl2ps for alignment
595  if (lst.empty () || term.find ("tex") != std::string::npos
596  || (lst.size () == 1 && ! lst.front ().get_code ()))
597  {
598  std::string name = fontname;
599  int sz = fontsize;
600  if (! lst.empty () && term.find ("tex") == std::string::npos)
601  {
602  octave::text_renderer::string s = lst.front ();
603  name = select_font (s.get_name (), s.get_weight () == "bold",
604  s.get_angle () == "italic");
605  set_color (s.get_color ());
606  str = s.get_string ();
607  sz = s.get_size ();
608  }
609 
610  glRasterPos3d (x, y, z);
611 
612  // Escape parenthesis until gl2ps does it (see bug ##45301).
613  if (term.find ("svg") == std::string::npos
614  && term.find ("tex") == std::string::npos)
615  {
616  escape_character ("(", str);
617  escape_character (")", str);
618  }
619 
620  gl2psTextOpt (str.c_str (), name.c_str (), sz,
621  alignment_to_mode (ha, va), rotation);
622  return bbox;
623  }
624 
625  // Translate and rotate coordinates in order to use bottom-left alignment
626  fix_strlist_position (x, y, z, bbox, rotation, lst);
627 
628  for (std::list<octave::text_renderer::string>::iterator p = lst.begin ();
629  p != lst.end (); p++)
630  {
631  fontname = select_font ((*p).get_name (),
632  (*p).get_weight () == "bold",
633  (*p).get_angle () == "italic");
634  if ((*p).get_code ())
635  {
636  // This is only one character represented by a uint32 (utf8) code.
637  // We replace it by the corresponding character in the
638  // "Symbol" font except for svg which has built-in utf8 support.
639  if (term.find ("svg") == std::string::npos)
640  {
641  fontname = "Symbol";
642  str = code_to_symbol ((*p).get_code ());
643  }
644  else
645  {
646  std::stringstream ss;
647  ss << (*p).get_code ();
648  str = "&#" + ss.str () + ";";
649  }
650  }
651  else
652  {
653  str = (*p).get_string ();
654  // Escape parenthesis until gl2ps does it (see bug ##45301).
655  if (term.find ("svg") == std::string::npos)
656  {
657  escape_character ("(", str);
658  escape_character (")", str);
659  }
660  }
661 
662  set_color ((*p).get_color ());
663  glRasterPos3d ((*p).get_x (), (*p).get_y (), (*p).get_z ());
664  gl2psTextOpt (str.c_str (), fontname.c_str (), (*p).get_size (),
665  GL2PS_TEXT_BL, rotation);
666  }
667 
668  fontname = saved_font;
669  return bbox;
670  }
671 
672  void
673  gl2ps_renderer::set_font (const base_properties& props)
674  {
676 
677  // Set the interpreter so that text_to_pixels can parse strings properly
678  if (props.has_property ("interpreter"))
679  set_interpreter (props.get ("interpreter").string_value ());
680 
681  fontsize = props.get ("fontsize_points").double_value ();
682 
683  caseless_str fn = props.get ("fontname").xtolower ().string_value ();
684  bool isbold =
685  (props.get ("fontweight").xtolower ().string_value () == "bold");
686  bool isitalic =
687  (props.get ("fontangle").xtolower ().string_value () == "italic");
688 
689  fontname = select_font (fn, isbold, isitalic);
690  }
691 
692  void
693  gl2ps_renderer::draw_pixels (int w, int h, const float *data)
694  {
695  // Clip data between 0 and 1 for float values
696  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
697 
698  for (int i = 0; i < 3*h*w; i++)
699  tmp_data[i] = (data[i] < 0.0f ? 0.0f : (data[i] > 1.0f ? 1.0f : data[i]));
700 
701  gl2psDrawPixels (w, h, 0, 0, GL_RGB, GL_FLOAT, tmp_data);
702  }
703 
704  void
705  gl2ps_renderer::draw_pixels (int w, int h, const uint8_t *data)
706  {
707  // gl2psDrawPixels only supports the GL_FLOAT type.
708 
709  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
710 
711  static const float maxval = std::numeric_limits<float>::max ();
712 
713  for (int i = 0; i < 3*w*h; i++)
714  tmp_data[i] = data[i] / maxval;
715 
716  draw_pixels (w, h, tmp_data);
717  }
718 
719  void
720  gl2ps_renderer::draw_pixels (int w, int h, const uint16_t *data)
721  {
722  // gl2psDrawPixels only supports the GL_FLOAT type.
723 
724  OCTAVE_LOCAL_BUFFER (float, tmp_data, 3*w*h);
725 
726  static const float maxval = std::numeric_limits<float>::max ();
727 
728  for (int i = 0; i < 3*w*h; i++)
729  tmp_data[i] = data[i] / maxval;
730 
731  draw_pixels (w, h, tmp_data);
732  }
733 
734  void
735  gl2ps_renderer::draw_text (const text::properties& props)
736  {
737  if (props.get_string ().is_empty ())
738  return;
739 
740  // First set font properties: freetype will use them to compute
741  // coordinates and gl2ps will retrieve the color directly from the
742  // feedback buffer
743  set_font (props);
744  set_color (props.get_color_rgb ());
745 
746  std::string saved_font = fontname;
747 
748  // Alignment
749  int halign = 0;
750  int valign = 0;
751 
752  if (props.horizontalalignment_is ("center"))
753  halign = 1;
754  else if (props.horizontalalignment_is ("right"))
755  halign = 2;
756 
757  if (props.verticalalignment_is ("top"))
758  valign = 2;
759  else if (props.verticalalignment_is ("baseline"))
760  valign = 3;
761  else if (props.verticalalignment_is ("middle"))
762  valign = 1;
763 
764  // FIXME: handle margin and surrounding box
765  // Matrix bbox;
766 
767  const Matrix pos = get_transform ().scale (props.get_data_position ());
768  std::string str = props.get_string ().string_vector_value ().join ("\n");
769 
770  render_text (str, pos(0), pos(1), pos.numel () > 2 ? pos(2) : 0.0,
771  halign, valign, props.get_rotation ());
772  }
773 
774 }
775 
776 static void
777 safe_pclose (FILE *f)
778 {
779  if (f)
780  octave_pclose (f);
781 }
782 
783 static void
784 safe_fclose (FILE *f)
785 {
786  if (f)
787  std::fclose (f);
788 }
789 
790 #endif
791 
792 namespace octave
793 {
794 
795  // If the name of the stream begins with '|', open a pipe to the command
796  // named by the rest of the string. Otherwise, write to the named file.
797 
798  void
799  gl2ps_print (const graphics_object& fig, const std::string& stream,
800  const std::string& term)
801  {
802 #if defined (HAVE_GL2PS_H)
803 
804  // FIXME: should we have a way to create a file that begins with the
805  // character '|'?
806 
807  bool have_cmd = stream.length () > 1 && stream[0] == '|';
808 
809  FILE *fp = 0;
810 
812 
813  if (have_cmd)
814  {
815  // Create process and pipe gl2ps output to it.
816 
817  std::string cmd = stream.substr (1);
818 
819  fp = octave_popen (cmd.c_str (), "w");
820 
821  if (! fp)
822  error ("print: failed to open pipe \"%s\"", stream.c_str ());
823 
824  frame.add_fcn (safe_pclose, fp);
825  }
826  else
827  {
828  // Write gl2ps output directly to file.
829 
830  fp = std::fopen (stream.c_str (), "w");
831 
832  if (! fp)
833  error ("gl2ps_print: failed to create file \"%s\"", stream.c_str ());
834 
835  frame.add_fcn (safe_fclose, fp);
836  }
837 
838  gl2ps_renderer rend (fp, term);
839 
840  rend.draw (fig, stream);
841 
842  // Make sure buffered commands are finished!!!
843  rend.finish ();
844 
845 #else
846  err_disabled_feature ("gl2ps_print", "gl2ps");
847 #endif
848  }
849 }
Octave interface to the compression and uncompression libraries.
Definition: aepbalance.cc:47
Matrix get_color(void) const
FILE * octave_popen(const char *command, const char *mode)
Definition: sysdep.cc:510
Matrix get_data_position(void) const
Definition: graphics.cc:7981
int octave_pclose(FILE *f)
Definition: sysdep.cc:530
virtual void set_polygon_offset(bool on, float offset=0.0f)
Definition: gl-render.cc:3594
octave_idx_type numel(void) const
Number of elements in the array.
Definition: Array.h:363
int octave_ftruncate_wrapper(int fd, off_t sz)
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE const F77_DBLE * f
fclose(in)
virtual void draw(const graphics_object &go, bool toplevel=true)
Definition: gl-render.cc:652
std::string get_weight(void) const
void protect_var(T &var)
void error(const char *fmt,...)
Definition: error.cc:570
std::string get_string(void) const
s
Definition: file-io.cc:2682
bool verticalalignment_is(const std::string &v) const
Definition: graphics.h:8100
virtual void draw_axes(const axes::properties &props)
Definition: gl-render.cc:1914
double h
Definition: graphics.cc:11205
octave_value xtolower(void) const
Definition: ov.h:1408
OCTAVE_EXPORT octave_value_list any number nd example oindent prints the prompt xample Pick a any number!nd example oindent and waits for the user to enter a value The string entered by the user is evaluated as an so it may be a literal a variable name
Definition: input.cc:871
Complex atan(const Complex &x)
Definition: lo-mappers.cc:210
void add_fcn(void(*fcn)(void))
#define OCTINTERP_API
Definition: mexproto.h:69
std::string string_value(bool force=false) const
Definition: ov.h:908
std::string join(const std::string &sep="") const
Definition: str-vec.cc:134
std::complex< double > w(std::complex< double > z, double relerr=0)
void gl2ps_print(const graphics_object &fig, const std::string &stream, const std::string &term)
Definition: gl2ps-print.cc:799
std::string str
Definition: hash.cc:118
void signal_handler(void)
Definition: sighandlers.cc:321
is false
Definition: cellfun.cc:398
octave_value retval
Definition: data.cc:6294
FILE * octave_tmpfile_wrapper(void)
do not permute tem code
Definition: balance.cc:90
Definition: dMatrix.h:37
sz
Definition: data.cc:5342
string_vector string_vector_value(bool pad=false) const
Definition: ov.h:911
virtual void set_linestyle(const std::string &s, bool stipple=false, double linewidth=0.5)
Definition: gl-render.cc:3643
static uint32_t state[624]
Definition: randmtzig.cc:184
octave_value get_string(void) const
Definition: graphics.h:8095
void warning(const char *fmt,...)
Definition: error.cc:788
octave::unwind_protect frame
Definition: graphics.cc:11584
charNDArray max(char d, const charNDArray &m)
Definition: chNDArray.cc:228
bool is_empty(void) const
Definition: ov.h:542
virtual octave_value get(const caseless_str &pname) const
std::string get_angle(void) const
static octave_value box(JNIEnv *jni_env, void *jobj, void *jcls_arg=0)
Convert the Java object pointed to by jobj_arg with class jcls_arg to an Octave value.
Definition: ov-java.cc:1192
=val(i)}if ode{val(i)}occurs in table i
Definition: lookup.cc:239
p
Definition: lu.cc:138
the element is set to zero In other the statement xample y
Definition: data.cc:5342
#define SEEK_SET
#define OCTAVE_LOCAL_BUFFER(T, buf, size)
Definition: oct-locbuf.h:200
ColumnVector transform(const Matrix &m, double x, double y, double z)
Definition: graphics.cc:5118
std::string get_name(void) const
double double_value(bool frc_str_conv=false) const
Definition: ov.h:775
double get_size(void) const
virtual bool has_property(const caseless_str &) const
Definition: graphics.h:2472
virtual void set_font(const base_properties &props)
Definition: gl-render.cc:3585
void err_disabled_feature(const std::string &fcn, const std::string &feature, const std::string &pkg)
Definition: errwarn.cc:50
If this string is the system will ring the terminal sometimes it is useful to be able to print the original representation of the string
Definition: utils.cc:854
static void safe_fclose(FILE *f)
Definition: oct-parse.cc:8064
F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_REAL const F77_REAL F77_REAL &F77_RET_T const F77_DBLE const F77_DBLE F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T F77_DBLE &F77_RET_T F77_REAL &F77_RET_T F77_REAL &F77_RET_T F77_DBLE &F77_RET_T const F77_DBLE F77_DBLE &F77_RET_T const F77_REAL F77_REAL &F77_RET_T F77_REAL F77_REAL &F77_RET_T F77_DBLE F77_DBLE &F77_RET_T const F77_DBLE * x
Matrix get_color_rgb(void) const
Definition: graphics.h:8047
bool horizontalalignment_is(const std::string &v) const
Definition: graphics.h:8078