~ubuntu-branches/ubuntu/vivid/grass/vivid-proposed

« back to all changes in this revision

Viewing changes to display/d.linegraph/linegraph.c

  • Committer: Package Import Robot
  • Author(s): Bas Couwenberg
  • Date: 2015-02-20 23:12:08 UTC
  • mfrom: (8.2.6 experimental)
  • Revision ID: package-import@ubuntu.com-20150220231208-1u6qvqm84v430b10
Tags: 7.0.0-1~exp1
* New upstream release.
* Update python-ctypes-ternary.patch to use if/else instead of and/or.
* Drop check4dev patch, rely on upstream check.
* Add build dependency on libpq-dev to grass-dev for libpq-fe.h.
* Drop patches applied upstream, refresh remaining patches.
* Update symlinks for images switched from jpg to png.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
 
2
 
/****************************************************************************
3
 
 *
4
 
 * MODULE:       d.linegraph
5
 
 * AUTHOR(S):    Chris Rewerts, Agricultural Engineering, Purdue University (original contributor)
6
 
 *               Markus Neteler <neteler itc.it>
7
 
 *               Roberto Flor <flor itc.it>, Bernhard Reiter <bernhard intevation.de>, 
8
 
 *               Huidae Cho <grass4u gmail.com>, Glynn Clements <glynn gclements.plus.com>, 
9
 
 *               Hamish Bowman <hamish_b yahoo.com>
10
 
 * PURPOSE:      
11
 
 * COPYRIGHT:    (C) 1999-2007 by the GRASS Development Team
12
 
 *
13
 
 *               This program is free software under the GNU General Public
14
 
 *               License (>=v2). Read the file COPYING that comes with GRASS
15
 
 *               for details.
16
 
 *
17
 
 *****************************************************************************/
18
 
/* Chris Rewerts
19
 
   rewerts@ecn.purdue.edu
20
 
   Agricultural Engineering, Purdue University
21
 
   February 1992
22
 
   program: d.linegraph
23
 
 
24
 
   This program is based on Raghaven Srinivasan's modification  
25
 
   of the programs written by Dave Johnson for d.histogram. 
26
 
 
27
 
   Will read files containing a column of numbers and create line
28
 
   graphs. One file can be used for the X axis, up to 10 for the 
29
 
   Y axis. Each numerical x,y file should be a single column of
30
 
   numbers.    
31
 
 */
32
 
 
33
 
#include <stdlib.h>
34
 
#include <math.h>
35
 
#include <grass/gis.h>
36
 
#include <grass/raster.h>
37
 
#include <grass/display.h>
38
 
#include <grass/colors.h>
39
 
#include <grass/glocale.h>
40
 
#include "linegraph.h"
41
 
 
42
 
#define MAX(x,y) ((x) > (y) ? (x) : (y))
43
 
#define MIN(x,y) ((x) < (y) ? (x) : (y))
44
 
 
45
 
/* the default order of precedence of colors to use for Y lines */
46
 
int default_y_colors[] = {
47
 
    0,
48
 
    RED, GREEN, VIOLET, BLUE, ORANGE,
49
 
    GRAY, BROWN, MAGENTA, WHITE, INDIGO
50
 
};
51
 
 
52
 
int main(int argc, char **argv)
53
 
{
54
 
    int xoffset;                /* offset for x-axis */
55
 
    int yoffset;                /* offset for y-axis */
56
 
    int text_height;
57
 
    int text_width;
58
 
    int i;
59
 
    int j;
60
 
    int c;
61
 
    int tic_every;
62
 
    int max_tics;
63
 
    int title_color;
64
 
    int num_y_files;
65
 
    int tic_unit;
66
 
    int t, b, l, r;
67
 
    int tt, tb, tl, tr;
68
 
    int prev_x, prev_y[11];
69
 
    int new_x, new_y[11];
70
 
    int line;
71
 
    int x_line[3];
72
 
    int y_line[3];
73
 
    int err;
74
 
 
75
 
    struct in_file
76
 
    {
77
 
        int num_pnts;           /* number of lines in file  */
78
 
        int color;              /* color to use for y lines */
79
 
        float max;              /* maximum value in file    */
80
 
        float min;              /* minimum value in file    */
81
 
        float value;            /* current value read in    */
82
 
        char name[1024];        /* name of file      */
83
 
        char full_name[1024];   /* path/name of file    */
84
 
        FILE *fp;               /* pointer to file        */
85
 
    };
86
 
 
87
 
    struct in_file in[12];
88
 
    struct GModule *module;
89
 
 
90
 
    float max_y;
91
 
    float min_y;
92
 
    float height, width;
93
 
    float xscale;
94
 
    float yscale;
95
 
 
96
 
    char txt[1024], xlabel[512];
97
 
    char tic_name[1024];
98
 
    char *name;
99
 
    char color_name[20];
100
 
 
101
 
    FILE *fopen();
102
 
 
103
 
    struct Option *dir_opt, *x_opt, *y_opt;
104
 
    struct Option *y_color_opt;
105
 
    struct Option *title[3];
106
 
    struct Option *t_color_opt;
107
 
 
108
 
    /* Initialize the GIS calls */
109
 
    G_gisinit(argv[0]);
110
 
 
111
 
    /* Set description */
112
 
    module = G_define_module();
113
 
    module->keywords = _("display, cartography");
114
 
    module->description =
115
 
        _("Generates and displays simple line graphs in the active graphics monitor display frame.");
116
 
 
117
 
    x_opt = G_define_option();
118
 
    x_opt->key = "x_file";
119
 
    x_opt->description = _("Name of data file for X axis of graph");
120
 
    x_opt->type = TYPE_STRING;
121
 
    x_opt->required = YES;
122
 
 
123
 
    y_opt = G_define_option();
124
 
    y_opt->key = "y_file";
125
 
    y_opt->description = _("Name of data file(s) for Y axis of graph");
126
 
    y_opt->type = TYPE_STRING;
127
 
    y_opt->required = YES;
128
 
    y_opt->multiple = YES;
129
 
 
130
 
    dir_opt = G_define_option();
131
 
    dir_opt->key = "directory";
132
 
    dir_opt->description = _("Path to file location");
133
 
    dir_opt->type = TYPE_STRING;
134
 
    dir_opt->required = NO;
135
 
    dir_opt->answer = ".";
136
 
 
137
 
    y_color_opt = G_define_option();
138
 
    y_color_opt->key = "y_color";
139
 
    y_color_opt->description = _("Color for Y data");
140
 
    y_color_opt->type = TYPE_STRING;
141
 
    y_color_opt->required = NO;
142
 
    y_color_opt->multiple = YES;
143
 
    y_color_opt->answers = NULL;
144
 
    y_color_opt->options = D_COLOR_LIST;
145
 
 
146
 
    t_color_opt = G_define_option();
147
 
    t_color_opt->key = "title_color";
148
 
    t_color_opt->description = _("Color for axis, tics, numbers, and title");
149
 
    t_color_opt->type = TYPE_STRING;
150
 
    t_color_opt->required = NO;
151
 
    t_color_opt->answer = DEFAULT_FG_COLOR;
152
 
    t_color_opt->options = D_COLOR_LIST;
153
 
 
154
 
    title[0] = G_define_option();
155
 
    title[0]->key = "x_title";
156
 
    title[0]->description = _("Title for X data");
157
 
    title[0]->type = TYPE_STRING;
158
 
    title[0]->required = NO;
159
 
    title[0]->answer = "";
160
 
 
161
 
    title[1] = G_define_option();
162
 
    title[1]->key = "y_title";
163
 
    title[1]->description = _("Title for Y data");
164
 
    title[1]->type = TYPE_STRING;
165
 
    title[1]->required = NO;
166
 
    title[1]->answer = "";
167
 
 
168
 
    title[2] = G_define_option();
169
 
    title[2]->key = "title";
170
 
    title[2]->description = _("Title for Graph");
171
 
    title[2]->type = TYPE_STRING;
172
 
    title[2]->required = NO;
173
 
    title[2]->answer = "";
174
 
 
175
 
 
176
 
    if (G_parser(argc, argv))
177
 
        exit(EXIT_FAILURE);
178
 
 
179
 
    for (i = 0; i < 3; i++) {
180
 
        for (j = 0; j < strlen(title[i]->answer); j++)
181
 
            if (title[i]->answer[j] == '_')
182
 
                title[i]->answer[j] = ' ';
183
 
    }
184
 
 
185
 
    /* build path to X data file and open for reading
186
 
       notice that in[0] will be the X file, and in[1-10]
187
 
       will be the Y file(s) */
188
 
 
189
 
    sprintf(in[0].full_name, "%s/%s", dir_opt->answer, x_opt->answer);
190
 
    sprintf(in[0].name, "%s", x_opt->answer);
191
 
 
192
 
    if ((in[0].fp = fopen(in[0].full_name, "r")) == NULL)
193
 
        G_fatal_error(_("Unable to open input file <%s>"), in[0].full_name);
194
 
 
195
 
    num_y_files = 0;
196
 
 
197
 
    /* open all Y data files */
198
 
 
199
 
    for (i = 0, j = 1; (name = y_opt->answers[i]); i++, j++) {
200
 
        sprintf(in[j].full_name, "%s/%s", dir_opt->answer, name);
201
 
        sprintf(in[j].name, "%s", name);
202
 
 
203
 
        if ((in[j].fp = fopen(in[j].full_name, "r")) == NULL)
204
 
            G_fatal_error(_("Unable to open input file <%s>"),
205
 
                          in[j].full_name);
206
 
 
207
 
        num_y_files++;
208
 
        if (num_y_files > 10)
209
 
            G_fatal_error(_("Maximum of 10 Y data files exceeded"));
210
 
    }
211
 
 
212
 
    /* set colors  */
213
 
 
214
 
    title_color = D_translate_color(t_color_opt->answer);
215
 
 
216
 
    /* I had an argument with the parser, and couldn't get a neat list of
217
 
       the input colors as I thought I should. I did a quick hack to get
218
 
       my list from the answer var, which gives us the colors input
219
 
       separated by commas. at least we know that they have been checked against
220
 
       the list of possibles */
221
 
    c = 0;
222
 
    j = 1;
223
 
    if (y_color_opt->answer != NULL) {
224
 
        for (i = 0; i <= (strlen(y_color_opt->answer)); i++) {
225
 
            if ((y_color_opt->answer[i] == ',') ||
226
 
                (i == (strlen(y_color_opt->answer)))) {
227
 
                color_name[c] = '\0';
228
 
                in[j].color = D_translate_color(color_name);
229
 
                j++;
230
 
                c = 0;
231
 
            }
232
 
            else {
233
 
                color_name[c++] = y_color_opt->answer[i];
234
 
            }
235
 
        }
236
 
        /* this is lame. I could come up with a color or prompt for one or something */
237
 
        if (j < num_y_files)
238
 
            G_fatal_error(_("Only <%d> colors given for <%d> lines"), j,
239
 
                          num_y_files);
240
 
    }
241
 
    else
242
 
        /* no colors given on command line, use default list */
243
 
    {
244
 
        for (i = 1; i <= num_y_files; i++) {
245
 
            in[i].color = default_y_colors[i];
246
 
        }
247
 
    }
248
 
 
249
 
    /* get coordinates of current screen window, in pixels */
250
 
    if (R_open_driver() != 0)
251
 
        G_fatal_error(_("No graphics device selected"));
252
 
    D_get_screen_window(&t, &b, &l, &r);
253
 
    R_set_window(t, b, l, r);
254
 
 
255
 
    /* create axis lines, to be drawn later */
256
 
    height = b - t;
257
 
    width = r - l;
258
 
    x_line[0] = x_line[1] = l + (int)(ORIGIN_X * width);
259
 
    x_line[2] = l + (int)(XAXIS_END * width);
260
 
    y_line[0] = b - (int)(YAXIS_END * height);
261
 
    y_line[1] = y_line[2] = b - (int)(ORIGIN_Y * height);
262
 
    text_height = (int)(b - t) * TEXT_HEIGHT;
263
 
    text_width = (int)(r - l) * TEXT_WIDTH;
264
 
    R_text_size(text_width, text_height);
265
 
 
266
 
    /* read thru each data file in turn, find max and min values for
267
 
       each, count lines, find x min and max, find overall y min and
268
 
       max */
269
 
 
270
 
    max_y = -99999.9;
271
 
    min_y = 99999.9;
272
 
 
273
 
    for (i = 0; i <= num_y_files; i++) {
274
 
 
275
 
        in[i].min = 99999.9;
276
 
        in[i].max = -99999.9;
277
 
        in[i].value = 0.0;
278
 
        in[i].num_pnts = 0;
279
 
 
280
 
        while ((err = fscanf(in[i].fp, "%f", &in[i].value)) != EOF) {
281
 
            in[i].num_pnts++;
282
 
            in[i].max = MAX(in[i].max, in[i].value);
283
 
            in[i].min = MIN(in[i].min, in[i].value);
284
 
            if (i > 0) {        /* if we have a y file */
285
 
                min_y = MIN(min_y, in[i].value);
286
 
                max_y = MAX(max_y, in[i].value);
287
 
            }
288
 
        }
289
 
        if ((i > 0) && (in[0].num_pnts != in[i].num_pnts)) {
290
 
            G_warning(_("Y input file <%s> contains %s data points than the X input file"),
291
 
                      in[i].name,
292
 
                      ((in[i].num_pnts < in[0].num_pnts) ? "fewer" : "more"));
293
 
 
294
 
            if (in[i].num_pnts > in[0].num_pnts)
295
 
                G_message(_("The last %d point(s) will be ignored"),
296
 
                          (in[i].num_pnts - in[0].num_pnts));
297
 
        }
298
 
    }
299
 
 
300
 
    /* close all files */
301
 
 
302
 
    for (i = 0; i <= num_y_files; i++)
303
 
        fclose(in[i].fp);
304
 
 
305
 
    /* figure scaling factors and offsets */
306
 
 
307
 
    xscale = ((double)(x_line[2] - x_line[1]) / (double)(in[0].num_pnts));
308
 
    yscale = ((double)(y_line[1] - y_line[0]) / (max_y - min_y));
309
 
    yoffset = (double)(y_line[1]);
310
 
    xoffset = (double)(x_line[1]);
311
 
 
312
 
    /* figure tic_every and tic_units for the x-axis of the bar-chart.
313
 
       tic_every tells how often to place a tic-number.  tic_unit tells
314
 
       the unit to use in expressing tic-numbers. */
315
 
 
316
 
    if (xscale < XTIC_DIST) {
317
 
        max_tics = (x_line[2] - x_line[1]) / XTIC_DIST;
318
 
        i = 1;
319
 
        while (((in[0].max - in[0].min) / tics[i].every) > max_tics)
320
 
            i++;
321
 
        tic_every = tics[i].every;
322
 
        tic_unit = tics[i].unit;
323
 
        strcpy(tic_name, tics[i].name);
324
 
    }
325
 
    else {
326
 
        tic_every = 1;
327
 
        tic_unit = 1;
328
 
        strcpy(tic_name, "");
329
 
    }
330
 
 
331
 
 
332
 
    /* open all the data files again */
333
 
 
334
 
    for (i = 0; i <= num_y_files; i++) {
335
 
        if ((in[i].fp = fopen(in[i].full_name, "r")) == NULL) {
336
 
            sprintf(txt, "Could not open input file <%s>.", in[i].full_name);
337
 
            death(txt);
338
 
        }
339
 
    }
340
 
 
341
 
    /* loop through number of lines in x data file, 
342
 
       then loop thru for each y file, drawing a piece of each line and a
343
 
       legend bar on each iteration evenly divisible, a tic-mark
344
 
       on those evenly divisible by tic_unit, and a tic_mark
345
 
       number on those evenly divisible by tic_every   */
346
 
 
347
 
    /* read the info from the inputs */
348
 
 
349
 
    for (line = 0; line < in[0].num_pnts; line++) {
350
 
        /* scan in an X value */
351
 
        err = fscanf(in[0].fp, "%f", &in[0].value);
352
 
 
353
 
        /* didn't find a number or hit EOF before our time */
354
 
        if ((err != 1) || (err == EOF)) {
355
 
            sprintf(txt, _("Problem reading X data file at line %d"), line);
356
 
            death(txt);
357
 
        }
358
 
 
359
 
        /* for each Y data file, get a value and compute where to draw it */
360
 
        for (i = 1; i <= num_y_files; i++) {
361
 
            /* check to see that we do indeed have data for this point */
362
 
            if (line < in[i].num_pnts) {
363
 
                err = fscanf(in[i].fp, "%f", &in[i].value);
364
 
                if ((in[i].num_pnts >= line) && (err != 1)) {
365
 
                    sprintf(txt,
366
 
                            _("Problem reading <%s> data file at line %d"),
367
 
                            in[i].name, line);
368
 
                    death(txt);
369
 
                }
370
 
 
371
 
                /* in case the Y file has fewer lines than the X file, we will skip
372
 
                   trying to draw when we run out of data */
373
 
 
374
 
                /* draw increment of each Y file's data */
375
 
 
376
 
                R_standard_color(in[i].color);
377
 
 
378
 
                /* find out position of where Y should be drawn. */
379
 
                /* if our minimum value of y is not negative, this is easy */
380
 
 
381
 
                if (min_y >= 0)
382
 
                    new_y[i] =
383
 
                        (int)(yoffset - yscale * (in[i].value - min_y));
384
 
 
385
 
                /* if our minimum value of y is negative, then we have two
386
 
                   cases:  our current value to plot is pos or neg */
387
 
 
388
 
                else {
389
 
                    if (in[i].value < 0)
390
 
                        new_y[i] = (int)(yoffset - yscale * (-1 *
391
 
                                                             (min_y -
392
 
                                                              in[i].value)));
393
 
                    else
394
 
                        new_y[i] = (int)(yoffset - yscale * (in[i].value +
395
 
                                                             (min_y * -1)));
396
 
                }
397
 
 
398
 
                new_x = xoffset + (line * xscale);
399
 
                if (line == 0) {
400
 
                    prev_x = xoffset;
401
 
                    prev_y[i] = yoffset;
402
 
                }
403
 
                R_move_abs(prev_x, prev_y[i]);
404
 
                R_cont_abs(new_x, new_y[i]);
405
 
                prev_y[i] = new_y[i];
406
 
            }
407
 
        }
408
 
        prev_x = new_x;
409
 
 
410
 
        /* draw x-axis tic-marks and numbers */
411
 
 
412
 
        if (rem((long int)in[0].value, tic_every) == (float)0) {
413
 
 
414
 
            /* draw a numbered tic-mark */
415
 
 
416
 
            R_standard_color(title_color);
417
 
            R_move_abs((int)(xoffset + line * xscale),
418
 
                       (int)(b - ORIGIN_Y * (b - t)));
419
 
            R_cont_rel((int)0, (int)(BIG_TIC * (b - t)));
420
 
            if ((in[0].value >= 1) || (in[0].value <= -1) ||
421
 
                (in[0].value == 0))
422
 
                sprintf(txt, "%.0f", (in[0].value / tic_unit));
423
 
            else
424
 
                sprintf(txt, "%.2f", (in[0].value));
425
 
            text_height = (b - t) * TEXT_HEIGHT;
426
 
            text_width = (r - l) * TEXT_WIDTH;
427
 
            R_text_size(text_width, text_height);
428
 
            R_get_text_box(txt, &tt, &tb, &tl, &tr);
429
 
            while ((tr - tl) > XTIC_DIST) {
430
 
                text_width *= 0.75;
431
 
                text_height *= 0.75;
432
 
                R_text_size(text_width, text_height);
433
 
                R_get_text_box(txt, &tt, &tb, &tl, &tr);
434
 
            }
435
 
            R_move_abs((int)(xoffset + (line * xscale - (tr - tl) / 2)),
436
 
                       (int)(b - XNUMS_Y * (b - t)));
437
 
            R_text(txt);
438
 
        }
439
 
        else if (rem(line, tic_unit) == (float)0) {
440
 
 
441
 
            /* draw a tic-mark */
442
 
 
443
 
            R_standard_color(title_color);
444
 
            R_move_abs((int)(xoffset + line * xscale),
445
 
                       (int)(b - ORIGIN_Y * (b - t)));
446
 
            R_cont_rel((int)0, (int)(SMALL_TIC * (b - t)));
447
 
        }
448
 
    }
449
 
 
450
 
    /* close all input files */
451
 
    for (i = 0; i <= num_y_files; i++) {
452
 
        fclose(in[i].fp);
453
 
    }
454
 
 
455
 
    /* draw the x-axis label */
456
 
    if ((strcmp(title[0]->answer, "") == 0) && (strcmp(tic_name, "") == 0))
457
 
        *xlabel = '\0';
458
 
    else
459
 
        sprintf(xlabel, "X: %s %s", title[0]->answer, tic_name);
460
 
    text_height = (b - t) * TEXT_HEIGHT;
461
 
    text_width = (r - l) * TEXT_WIDTH * 1.5;
462
 
    R_text_size(text_width, text_height);
463
 
    R_get_text_box(xlabel, &tt, &tb, &tl, &tr);
464
 
    R_move_abs((int)(l + (r - l) / 2 - (tr - tl) / 2),
465
 
               (int)(b - LABEL_1 * (b - t)));
466
 
    R_standard_color(title_color);
467
 
    R_text(xlabel);
468
 
 
469
 
    /* DRAW Y-AXIS TIC-MARKS AND NUMBERS
470
 
       first, figure tic_every and tic_units for the x-axis of the bar-chart.
471
 
       tic_every tells how often to place a tic-number.  tic_unit tells
472
 
       the unit to use in expressing tic-numbers. */
473
 
 
474
 
    if (yscale < YTIC_DIST) {
475
 
        max_tics = (y_line[1] - y_line[0]) / YTIC_DIST;
476
 
        i = 1;
477
 
        while (((max_y - min_y) / tics[i].every) > max_tics)
478
 
            i++;
479
 
        tic_every = tics[i].every;
480
 
        tic_unit = tics[i].unit;
481
 
        strcpy(tic_name, tics[i].name);
482
 
    }
483
 
    else {
484
 
        tic_every = 1;
485
 
        tic_unit = 1;
486
 
        strcpy(tic_name, "");
487
 
    }
488
 
 
489
 
    /* Y-AXIS LOOP */
490
 
 
491
 
    for (i = (int)min_y; i <= (int)max_y; i += tic_unit) {
492
 
        if (rem(i, tic_every) == (float)0) {
493
 
            /* draw a tic-mark */
494
 
 
495
 
            R_move_abs((int)x_line[0], (int)(yoffset - yscale * (i - min_y)));
496
 
            R_cont_rel((int)(-(r - l) * BIG_TIC), (int)0);
497
 
 
498
 
            /* draw a tic-mark number */
499
 
 
500
 
            sprintf(txt, "%d", (i / tic_unit));
501
 
            text_height = (b - t) * TEXT_HEIGHT;
502
 
            text_width = (r - l) * TEXT_WIDTH;
503
 
            R_text_size(text_width, text_height);
504
 
            R_get_text_box(txt, &tt, &tb, &tl, &tr);
505
 
            while ((tt - tb) > YTIC_DIST) {
506
 
                text_width *= 0.75;
507
 
                text_height *= 0.75;
508
 
                R_text_size(text_width, text_height);
509
 
                R_get_text_box(txt, &tt, &tb, &tl, &tr);
510
 
            }
511
 
            R_move_abs((int)(l + (r - l) * YNUMS_X - (tr - tl) / 2),
512
 
                       (int)(yoffset -
513
 
                             (yscale * (i - min_y) + 0.5 * (tt - tb))));
514
 
            R_text(txt);
515
 
        }
516
 
        else if (rem(i, tic_unit) == (float)0) {
517
 
            /* draw a tic-mark */
518
 
 
519
 
            R_move_abs((int)x_line[0], (int)(yoffset - yscale * (i - min_y)));
520
 
            R_cont_rel((int)(-(r - l) * SMALL_TIC), (int)0);
521
 
        }
522
 
    }
523
 
 
524
 
    /* draw the y-axis label */
525
 
    if ((strcmp(title[1]->answer, "") == 0) && (strcmp(tic_name, "") == 0))
526
 
        *xlabel = '\0';
527
 
    else
528
 
        sprintf(xlabel, "Y: %s %s", title[1]->answer, tic_name);
529
 
    text_height = (b - t) * TEXT_HEIGHT;
530
 
    text_width = (r - l) * TEXT_WIDTH * 1.5;
531
 
    R_text_size(text_width, text_height);
532
 
    R_get_text_box(xlabel, &tt, &tb, &tl, &tr);
533
 
    R_move_abs((int)(l + (r - l) / 2 - (tr - tl) / 2),
534
 
               (int)(b - LABEL_2 * (b - t)));
535
 
    R_standard_color(title_color);
536
 
    R_text(xlabel);
537
 
 
538
 
    /* top label */
539
 
    sprintf(xlabel, "%s", title[2]->answer);
540
 
    text_height = (b - t) * TEXT_HEIGHT;
541
 
    text_width = (r - l) * TEXT_WIDTH * 2.0;
542
 
    R_text_size(text_width, text_height);
543
 
    R_get_text_box(xlabel, &tt, &tb, &tl, &tr);
544
 
    /*
545
 
       R_move_abs((int)(((r-l)/2)-(tr-tl)/2),
546
 
       (int) (t+ (b-t)*.07) );
547
 
     */
548
 
    R_move_abs((int)(l + (r - l) / 2 - (tr - tl) / 2),
549
 
               (int)(t + (b - t) * .07));
550
 
    R_standard_color(title_color);
551
 
    R_text(xlabel);
552
 
 
553
 
    /* draw x and y axis lines */
554
 
    R_standard_color(title_color);
555
 
    R_polyline_abs(x_line, y_line, 3);
556
 
 
557
 
    R_flush();
558
 
    R_close_driver();
559
 
    exit(EXIT_SUCCESS);
560
 
}
561
 
 
562
 
float rem(long int x, long int y)
563
 
{
564
 
    long int d = x / y;
565
 
 
566
 
    return ((float)(x - y * d));
567
 
}
568
 
 
569
 
 
570
 
/* a function for making an exit after the R_driver is open */
571
 
int death(char *gasp)
572
 
{
573
 
    R_flush();
574
 
    R_close_driver();
575
 
    G_fatal_error("%s", gasp);
576
 
}