1 /*!
2   \file lib/display/r_raster.c
3 
4   \brief Display Library - Raster graphics subroutines
5 
6   (C) 2001-2015 by the GRASS Development Team
7 
8   This program is free software under the GNU General Public License
9   (>=v2). Read the file COPYING that comes with GRASS for details.
10 
11   \author Original author CERL
12   \author Monitors support by Martin Landa <landa.martin gmail.com>
13 */
14 
15 #include <grass/config.h>
16 
17 #include <errno.h>
18 #include <signal.h>
19 #include <stdio.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <unistd.h>
23 
24 #include <grass/gis.h>
25 #include <grass/glocale.h>
26 #include <grass/display.h>
27 #include <grass/spawn.h>
28 
29 #include "driver.h"
30 
31 extern const struct driver *PNG_Driver(void);
32 extern const struct driver *PS_Driver(void);
33 extern const struct driver *HTML_Driver(void);
34 #ifdef USE_CAIRO
35 extern const struct driver *Cairo_Driver(void);
36 #endif
37 
38 static struct {
39     double t, b, l, r;
40 } screen, frame;
41 
init(void)42 static void init(void)
43 {
44     const char *fenc = getenv("GRASS_ENCODING");
45     const char *font = getenv("GRASS_FONT");
46     const char *line_width = getenv("GRASS_RENDER_LINE_WIDTH");
47     const char *text_size = getenv("GRASS_RENDER_TEXT_SIZE");
48     const char *frame_str = getenv("GRASS_RENDER_FRAME");
49 
50     D_font(font ? font : "romans");
51 
52     if (fenc)
53 	D_encoding(fenc);
54 
55     if (line_width)
56 	COM_Line_width(atof(line_width));
57 
58     if (text_size) {
59 	double s = atof(text_size);
60 	D_text_size(s, s);
61     }
62 
63     D_text_rotation(0);
64 
65     COM_Get_window(&screen.t, &screen.b, &screen.l, &screen.r);
66     if (frame_str) {
67 	sscanf(frame_str, "%lf,%lf,%lf,%lf", &frame.t, &frame.b, &frame.l, &frame.r);
68 	COM_Set_window(frame.t, frame.b, frame.l, frame.r);
69     }
70     else
71 	frame = screen;
72 }
73 
74 /*!
75   \brief Open display driver
76 
77   Default display driver is Cairo, if not available PNG is used.
78 
79   \return 0 on success
80 */
D_open_driver(void)81 int D_open_driver(void)
82 {
83     const char *p, *c, *m;
84     const struct driver *drv;
85 
86     G_debug(1, "D_open_driver():");
87     p = getenv("GRASS_RENDER_IMMEDIATE");
88     c = getenv("GRASS_RENDER_COMMAND");
89     m = G_getenv_nofatal("MONITOR");
90 
91     if (!p && (m || c)) {
92         char *cmd;
93         char progname[GPATH_MAX];
94 
95         cmd = G_recreate_command();
96 
97         if (c && m) {
98             G_warning(_("Both %s and %s are defined. "
99                         "%s will be ignored."),
100                       "GRASS_RENDER_COMMAND", "MONITOR",
101                       "MONITOR");
102             m = NULL;
103         }
104 
105         if (c)
106             sprintf(progname, "%s", c);
107         else { /* monitors managed by d.mon -> call default renderer */
108             char element[GPATH_MAX];
109 
110             G_temp_element(element);
111             strcat(element, "/");
112             strcat(element, "MONITORS");
113             strcat(element, "/");
114             strcat(element, m);
115             G_file_name(progname, element, "render.py", G_mapset());
116         }
117 
118         G_debug(1, "rendering redirected to %s", progname);
119         /* assuming Python script here (could be extended in the future) */
120         G_spawn_ex(getenv("GRASS_PYTHON"), getenv("GRASS_PYTHON"), progname,
121                    cmd, NULL);
122 
123         G_free(cmd);
124 
125         /* force exiting GRASS command, leave rendering on
126          * GRASS_RENDER_COMMAND program */
127         exit(0);
128     }
129 
130     if (!p)
131 	G_fatal_error(_("Neither %s (managed by d.mon command) nor %s "
132                         "(used for direct rendering) defined"),
133 		      "MONITOR", "GRASS_RENDER_IMMEDIATE");
134 
135     if (p && G_strcasecmp(p, "default") == 0)
136 	p = NULL;
137 
138     drv =
139 	(p && G_strcasecmp(p, "png")   == 0) ? PNG_Driver() :
140 	(p && G_strcasecmp(p, "ps")    == 0) ? PS_Driver() :
141 	(p && G_strcasecmp(p, "html")  == 0) ? HTML_Driver() :
142 #ifdef USE_CAIRO
143 	(p && G_strcasecmp(p, "cairo") == 0) ? Cairo_Driver() :
144 	Cairo_Driver();
145 #else
146 	PNG_Driver();
147 #endif
148 
149     if (p && G_strcasecmp(drv->name, p) != 0)
150 	G_warning(_("Unknown display driver <%s>"), p);
151     G_verbose_message(_("Using display driver <%s>..."), drv->name);
152     LIB_init(drv);
153 
154     init();
155 
156     return 0;
157 }
158 
159 /*!
160   \brief Close display driver
161 
162   If GRASS_NOTIFY is defined, run notifier.
163 */
D_close_driver(void)164 void D_close_driver(void)
165 {
166     const char *cmd = getenv("GRASS_NOTIFY");
167 
168     COM_Graph_close();
169 
170     if (cmd)
171 	system(cmd);
172 }
173 
174 /*!
175   \brief Append command to the cmd file (unused)
176 
177   \todo To be removed
178 */
D_save_command(const char * cmd)179 int D_save_command(const char *cmd)
180 {
181     return 0;
182 }
183 
184 /*!
185   \brief Erase display (internal use only)
186 */
D__erase(void)187 void D__erase(void)
188 {
189     COM_Erase();
190 }
191 
192 /*!
193   \brief Set text size (width and height)
194 
195   \param width text pixel width
196   \param height text pixel height
197 */
D_text_size(double width,double height)198 void D_text_size(double width, double height)
199 {
200     COM_Text_size(width, height);
201 }
202 
203 /*!
204   \brief Set text rotation
205 
206   \param rotation value
207 */
D_text_rotation(double rotation)208 void D_text_rotation(double rotation)
209 {
210     COM_Text_rotation(rotation);
211 }
212 
213 /*!
214   \brief Draw text
215 
216   Writes <em>text</em> in the current color and font, at the current text
217   width and height, starting at the current screen location.
218 
219   \param text text to be drawn
220 */
D_text(const char * text)221 void D_text(const char *text)
222 {
223     COM_Text(text);
224 }
225 
226 /*!
227   \brief Choose font
228 
229   Set current font to <em>font name</em>.
230 
231   \param name font name
232 */
D_font(const char * name)233 void D_font(const char *name)
234 {
235     COM_Set_font(name);
236 }
237 
238 /*!
239   \brief Set encoding
240 
241   \param name encoding name
242 */
D_encoding(const char * name)243 void D_encoding(const char *name)
244 {
245     COM_Set_encoding(name);
246 }
247 
248 /*!
249   \brief Get font list
250 
251   \param[out] list list of font names
252   \param[out] number of items in the list
253 */
D_font_list(char *** list,int * count)254 void D_font_list(char ***list, int *count)
255 {
256     COM_Font_list(list, count);
257 }
258 
259 /*!
260   \brief Get font info
261 
262   \param[out] list list of font info
263   \param[out] number of items in the list
264 */
D_font_info(char *** list,int * count)265 void D_font_info(char ***list, int *count)
266 {
267     COM_Font_info(list, count);
268 }
269 
270 /*!
271  * \brief get graphical clipping window
272  *
273  * Queries the graphical clipping window (origin is top right)
274  *
275  *  \param[out] t top edge of clip window
276  *  \param[out] b bottom edge of clip window
277  *  \param[out] l left edge of clip window
278  *  \param[out] r right edge of clip window
279  *  \return ~
280  */
281 
D_get_clip_window(double * t,double * b,double * l,double * r)282 void D_get_clip_window(double *t, double *b, double *l, double *r)
283 {
284     COM_Get_window(t, b, l, r);
285 }
286 
287 /*!
288  * \brief set graphical clipping window
289  *
290  * Sets the graphical clipping window to the specified rectangle
291  *  (origin is top right)
292  *
293  *  \param t top edge of clip window
294  *  \param b bottom edge of clip window
295  *  \param l left edge of clip window
296  *  \param r right edge of clip window
297  *  \return ~
298  */
299 
D_set_clip_window(double t,double b,double l,double r)300 void D_set_clip_window(double t, double b, double l, double r)
301 {
302     if (t < frame.t) t = frame.t;
303     if (b > frame.b) b = frame.b;
304     if (l < frame.l) l = frame.l;
305     if (r > frame.r) r = frame.r;
306 
307     COM_Set_window(t, b, l, r);
308 }
309 
310 /*!
311  * \brief get graphical window (frame)
312  *
313  * Queries the graphical frame (origin is top right)
314  *
315  *  \param[out] t top edge of frame
316  *  \param[out] b bottom edge of frame
317  *  \param[out] l left edge of frame
318  *  \param[out] r right edge of frame
319  *  \return ~
320  */
321 
D_get_frame(double * t,double * b,double * l,double * r)322 void D_get_frame(double *t, double *b, double *l, double *r)
323 {
324     *t = frame.t;
325     *b = frame.b;
326     *l = frame.l;
327     *r = frame.r;
328 }
329 
330 /*!
331  * \brief get screen bounds
332  *
333  * Queries the screen bounds (origin is top right)
334  *
335  *  \param[out] t top edge of screen
336  *  \param[out] b bottom edge of screen
337  *  \param[out] l left edge of screen
338  *  \param[out] r right edge of screen
339  *  \return ~
340  */
341 
D_get_screen(double * t,double * b,double * l,double * r)342 void D_get_screen(double *t, double *b, double *l, double *r)
343 {
344     *t = screen.t;
345     *b = screen.b;
346     *l = screen.l;
347     *r = screen.r;
348 }
349 
350 /*!
351  * \brief set graphical clipping window to map window
352  *
353  * Sets the graphical clipping window to the pixel window that corresponds
354  * to the current database region.
355  *
356  *  \param ~
357  *  \return ~
358  */
359 
D_set_clip_window_to_map_window(void)360 void D_set_clip_window_to_map_window(void)
361 {
362     D_set_clip_window(
363 	D_get_d_north(), D_get_d_south(),
364 	D_get_d_west(), D_get_d_east());
365 }
366 
367 /*!
368  * \brief set clipping window to screen window
369  *
370  * Sets the clipping window to the pixel window that corresponds to the
371  * full screen window. Off screen rendering is still clipped.
372  *
373  *  \param ~
374  *  \return ~
375  */
376 
D_set_clip_window_to_screen_window(void)377 void D_set_clip_window_to_screen_window(void)
378 {
379     COM_Set_window(frame.t, frame.b, frame.l, frame.r);
380 }
381 
382